[
  {
    "path": ".gitattributes",
    "content": "Tools/BCnCompressglTF/DirectXTex/Shaders/Compiled/* linguist-vendored\nTools/BCnCompressglTF/DirectXTex/** linguist-vendored\nTools/BCnCompressglTF/TexConv/** linguist-vendored\nExternal/** linguist-vendored\nAssets/** linguist-vendored"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: build-and-test\n\non:\n  push:\n    branches:\n      - master\n    paths:\n      - 'Source/**'\n      - 'Tests/**'\n      - 'CMake/**'\n      - 'Tools/**'\n      - '!Tools/Natvis/**'\n  pull_request:\n    branches:\n      - master\n    paths:\n      - 'Source/**'\n      - 'Tests/**'\n      - 'CMake/**'\n      - 'Tools/**'\n      - '!Tools/Natvis/**'\n\njobs:\n  build:\n    name: ${{ matrix.compiler }}-${{ matrix.config }}\n    runs-on: windows-latest\n\n    strategy:\n      matrix:\n        compiler: [msvc, clang]\n        config: [Debug, Release]\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v4\n\n      - name: Configure CMake\n        run: |\n          mkdir build\n          cmake -S . -B build -G \"Visual Studio 17 2022\" -T ${{ matrix.compiler == 'msvc' && 'host=x64' || 'ClangCL' }} -DBUILD_TESTS=on\n\n      - name: Build\n        run: cmake --build build --config ${{ matrix.config }}\n\n      - name: Test\n        shell: bash\n        run: |\n          if [ \"${{ matrix.config }}\" == \"Debug\" ]; then\n            \"bin/Testsd.exe\"\n          else\n            \"bin/Tests.exe\"\n          fi"
  },
  {
    "path": ".gitignore",
    "content": "# build files\n/.vs\n/.vscode\nbuild/\nbin/\n\n# assets\nAssets/*\n!Assets/CornellBox\n!Assets/Font\n!Assets/LUT\n!Assets/Samplers\n!Assets/Images\n\n# external libs\nExternal/*\n!External/concurrentqueue\n!External/FastDelegate\n!External/FSR2\n!External/stb\n!External/ImGui\nExternal/ImGui/imgui_*\nExternal/ImGui/imnodes*\nExternal/ImGui/implot*\nExternal/ImGui/imstb*\nExternal/ImGui/imgui.h\nExternal/ImGui/imgui.cpp\n\n# misc\ndocs/\nTools/dxc\ntemp/"
  },
  {
    "path": "Assets/CornellBox/cornell.gltf",
    "content": "{\n  \"accessors\": [\n    {\n      \"bufferView\": 0,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 54,\n      \"min\": [-1, -1, -1],\n      \"max\": [1, 1, 1]\n    },\n    {\n      \"bufferView\": 1,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 54\n    },\n    {\n      \"bufferView\": 2,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 54\n    },\n    {\n      \"bufferView\": 3,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 54\n    },\n    {\n      \"bufferView\": 4,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 60\n    },\n    {\n      \"bufferView\": 5,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [1, -0.964481771, -0.964481771],\n      \"max\": [1, 0.964481771, 1]\n    },\n    {\n      \"bufferView\": 6,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 7,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 8,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 9,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 6\n    },\n    {\n      \"bufferView\": 10,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [-1, -0.964481771, -0.964481771],\n      \"max\": [-1, 0.964481771, 1]\n    },\n    {\n      \"bufferView\": 11,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 12,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 13,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 14,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 6\n    },\n    {\n      \"bufferView\": 15,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [-0.964481771, -0.964481771, -1],\n      \"max\": [0.964481771, 0.964481771, -1]\n    },\n    {\n      \"bufferView\": 16,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 17,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 18,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 19,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [-0.964481771, 1, -0.964481771],\n      \"max\": [0.964481771, 1, 1]\n    },\n    {\n      \"bufferView\": 20,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 21,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 22,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 23,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 6\n    },\n    {\n      \"bufferView\": 24,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [-0.964481771, -1, -0.964481771],\n      \"max\": [0.964481771, -1, 1]\n    },\n    {\n      \"bufferView\": 25,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 26,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 27,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 28,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 6\n    },\n    {\n      \"bufferView\": 29,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [-1, 0, -1],\n      \"max\": [1, 0, 1]\n    },\n    {\n      \"bufferView\": 30,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 31,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 32,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 33,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [-1, 0, -1],\n      \"max\": [1, 0, 1]\n    },\n    {\n      \"bufferView\": 34,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 35,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 36,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 37,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 6\n    },\n    {\n      \"bufferView\": 38,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 24,\n      \"min\": [-1, -1, -1],\n      \"max\": [1, 1, 1]\n    },\n    {\n      \"bufferView\": 39,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 24\n    },\n    {\n      \"bufferView\": 40,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 24\n    },\n    {\n      \"bufferView\": 41,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 24\n    },\n    {\n      \"bufferView\": 42,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 36\n    },\n    {\n      \"bufferView\": 43,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 24,\n      \"min\": [-1, -1, -1],\n      \"max\": [1, 1, 1]\n    },\n    {\n      \"bufferView\": 44,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 24\n    },\n    {\n      \"bufferView\": 45,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 24\n    },\n    {\n      \"bufferView\": 46,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 24\n    }\n  ],\n  \"asset\": {\n    \"generator\": \"Khronos glTF Blender I/O v3.6.28\",\n    \"version\": \"2.0\"\n  },\n  \"bufferViews\": [\n    {\n      \"buffer\": 0,\n      \"byteLength\": 648\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 648,\n      \"byteOffset\": 648\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 432,\n      \"byteOffset\": 1296\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 864,\n      \"byteOffset\": 1728\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 120,\n      \"byteOffset\": 2592\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 2712\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 2760\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 2808\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 2840\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 12,\n      \"byteOffset\": 2904\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 2916\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 2964\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 3012\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 3044\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 12,\n      \"byteOffset\": 3108\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3120\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3168\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 3216\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 3248\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3312\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3360\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 3408\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 3440\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 12,\n      \"byteOffset\": 3504\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3516\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3564\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 3612\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 3644\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 12,\n      \"byteOffset\": 3708\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3720\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3768\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 3816\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 3848\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3912\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3960\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 4008\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 4040\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 12,\n      \"byteOffset\": 4104\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 288,\n      \"byteOffset\": 4116\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 288,\n      \"byteOffset\": 4404\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 192,\n      \"byteOffset\": 4692\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 384,\n      \"byteOffset\": 4884\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 72,\n      \"byteOffset\": 5268\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 288,\n      \"byteOffset\": 5340\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 288,\n      \"byteOffset\": 5628\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 192,\n      \"byteOffset\": 5916\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 384,\n      \"byteOffset\": 6108\n    }\n  ],\n  \"buffers\": [\n    {\n      \"uri\": \"cornell.bin\",\n      \"byteLength\": 6492\n    }\n  ],\n  \"images\": [\n    {\n      \"name\": \"checkerboard\",\n      \"uri\": \"compressed/checkerboard.dds\",\n      \"mimeType\": \"image/png\"\n    }\n  ],\n  \"meshes\": [\n    {\n      \"name\": \"CubeMesh\",\n      \"primitives\": [\n        {\n          \"indices\": 4,\n          \"material\": 0,\n          \"attributes\": {\n            \"POSITION\": 0,\n            \"NORMAL\": 1,\n            \"TEXCOORD_0\": 2,\n            \"TANGENT\": 3\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"RightWallMesh\",\n      \"primitives\": [\n        {\n          \"indices\": 9,\n          \"material\": 1,\n          \"attributes\": {\n            \"POSITION\": 5,\n            \"NORMAL\": 6,\n            \"TEXCOORD_0\": 7,\n            \"TANGENT\": 8\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"LeftWallMesh\",\n      \"primitives\": [\n        {\n          \"indices\": 14,\n          \"material\": 2,\n          \"attributes\": {\n            \"POSITION\": 10,\n            \"NORMAL\": 11,\n            \"TEXCOORD_0\": 12,\n            \"TANGENT\": 13\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"BackWallMesh\",\n      \"primitives\": [\n        {\n          \"indices\": 14,\n          \"material\": 3,\n          \"attributes\": {\n            \"POSITION\": 15,\n            \"NORMAL\": 16,\n            \"TEXCOORD_0\": 17,\n            \"TANGENT\": 18\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"RoofMesh\",\n      \"primitives\": [\n        {\n          \"indices\": 23,\n          \"material\": 4,\n          \"attributes\": {\n            \"POSITION\": 19,\n            \"NORMAL\": 20,\n            \"TEXCOORD_0\": 21,\n            \"TANGENT\": 22\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"FloorMesh\",\n      \"primitives\": [\n        {\n          \"indices\": 28,\n          \"material\": 0,\n          \"attributes\": {\n            \"POSITION\": 24,\n            \"NORMAL\": 25,\n            \"TEXCOORD_0\": 26,\n            \"TANGENT\": 27\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"Plane\",\n      \"primitives\": [\n        {\n          \"indices\": 14,\n          \"material\": 5,\n          \"attributes\": {\n            \"POSITION\": 29,\n            \"NORMAL\": 30,\n            \"TEXCOORD_0\": 31,\n            \"TANGENT\": 32\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"Plane.001\",\n      \"primitives\": [\n        {\n          \"indices\": 37,\n          \"material\": 6,\n          \"attributes\": {\n            \"POSITION\": 33,\n            \"NORMAL\": 34,\n            \"TEXCOORD_0\": 35,\n            \"TANGENT\": 36\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"Cube.001\",\n      \"primitives\": [\n        {\n          \"indices\": 42,\n          \"material\": 7,\n          \"attributes\": {\n            \"POSITION\": 38,\n            \"NORMAL\": 39,\n            \"TEXCOORD_0\": 40,\n            \"TANGENT\": 41\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"Cube.002\",\n      \"primitives\": [\n        {\n          \"indices\": 42,\n          \"material\": 8,\n          \"attributes\": {\n            \"POSITION\": 43,\n            \"NORMAL\": 44,\n            \"TEXCOORD_0\": 45,\n            \"TANGENT\": 46\n          }\n        }\n      ]\n    }\n  ],\n  \"materials\": [\n    {\n      \"name\": \"floor\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.725000024, 0.709999979, 0.680000007, 1]\n      }\n    },\n    {\n      \"name\": \"rightWall\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.140000001, 0.449999988, 0.0909999982, 1]\n      }\n    },\n    {\n      \"name\": \"leftWall.001\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.629999995, 0.0649999976, 0.0500000007, 1]\n      }\n    },\n    {\n      \"name\": \"backWall\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.725000024, 0.709999979, 0.680000007, 1]\n      }\n    },\n    {\n      \"name\": \"ceiling\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.725000024, 0.709999979, 0.680000007, 1]\n      }\n    },\n    {\n      \"name\": \"light\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.779999971, 0.779999971, 0.779999971, 1]\n      }\n    },\n    {\n      \"name\": \"ground\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"baseColorTexture\": {\n          \"index\": 0\n        },\n        \"metallicFactor\": 0\n      }\n    },\n    {\n      \"name\": \"shortBox\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.725000024, 0.709999979, 0.680000007, 1]\n      }\n    },\n    {\n      \"name\": \"tallBox\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.725000024, 0.709999979, 0.680000007, 1]\n      }\n    }\n  ],\n  \"nodes\": [\n    {\n      \"mesh\": 0,\n      \"name\": \"Cube\",\n      \"translation\": [0, 1.02813554, 0]\n    },\n    {\n      \"mesh\": 1,\n      \"name\": \"RightWall\",\n      \"translation\": [0, 1.02813554, 0]\n    },\n    {\n      \"mesh\": 2,\n      \"name\": \"LeftWall\",\n      \"translation\": [0, 1.02813554, 0]\n    },\n    {\n      \"mesh\": 3,\n      \"name\": \"BackWall\",\n      \"translation\": [0, 1.02813554, 0]\n    },\n    {\n      \"mesh\": 4,\n      \"name\": \"Roof\",\n      \"translation\": [0, 1.02813554, 0]\n    },\n    {\n      \"mesh\": 5,\n      \"name\": \"Floor\",\n      \"translation\": [0, 1.02813554, 0]\n    },\n    {\n      \"mesh\": 6,\n      \"name\": \"Plane\",\n      \"translation\": [-0.00379260769, 2.02274299, -0.0408690274],\n      \"scale\": [0.235878631, 0.235878631, 0.194536671]\n    },\n    {\n      \"mesh\": 7,\n      \"name\": \"Plane.001\",\n      \"scale\": [50, 50, 50]\n    },\n    {\n      \"mesh\": 8,\n      \"name\": \"Cube.003\",\n      \"translation\": [0.325628012, 0.329526007, 0.373807997],\n      \"rotation\": [0, -0.144368067, 0, 0.989524126],\n      \"scale\": [0.297057986, 0.297057986, 0.297057986]\n    },\n    {\n      \"mesh\": 9,\n      \"name\": \"Cube.004\",\n      \"translation\": [-0.327136993, 0.609180987, -0.291770011],\n      \"rotation\": [0, 0.157149047, 0, 0.987574995],\n      \"scale\": [0.290537, 0.581031978, 0.290537]\n    }\n  ],\n  \"samplers\": [\n    {\n      \"magFilter\": 9729,\n      \"minFilter\": 9987\n    }\n  ],\n  \"scene\": 0,\n  \"scenes\": [\n    {\n      \"name\": \"Scene\",\n      \"nodes\": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]\n    }\n  ],\n  \"textures\": [\n    {\n      \"source\": 0,\n      \"sampler\": 0\n    }\n  ]\n}\n"
  },
  {
    "path": "Assets/CornellBox/cornell_emissive.gltf",
    "content": "{\n  \"accessors\": [\n    {\n      \"bufferView\": 0,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 54,\n      \"min\": [-1, -1, -1],\n      \"max\": [1, 1, 1]\n    },\n    {\n      \"bufferView\": 1,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 54\n    },\n    {\n      \"bufferView\": 2,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 54\n    },\n    {\n      \"bufferView\": 3,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 54\n    },\n    {\n      \"bufferView\": 4,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 60\n    },\n    {\n      \"bufferView\": 5,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [1, -0.964481771, -0.964481771],\n      \"max\": [1, 0.964481771, 1]\n    },\n    {\n      \"bufferView\": 6,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 7,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 8,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 9,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 6\n    },\n    {\n      \"bufferView\": 10,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [-1, -0.964481771, -0.964481771],\n      \"max\": [-1, 0.964481771, 1]\n    },\n    {\n      \"bufferView\": 11,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 12,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 13,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 14,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 6\n    },\n    {\n      \"bufferView\": 15,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [-0.964481771, -0.964481771, -1],\n      \"max\": [0.964481771, 0.964481771, -1]\n    },\n    {\n      \"bufferView\": 16,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 17,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 18,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 19,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [-0.964481771, 1, -0.964481771],\n      \"max\": [0.964481771, 1, 1]\n    },\n    {\n      \"bufferView\": 20,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 21,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 22,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 23,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 6\n    },\n    {\n      \"bufferView\": 24,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [-0.964481771, -1, -0.964481771],\n      \"max\": [0.964481771, -1, 1]\n    },\n    {\n      \"bufferView\": 25,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 26,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 27,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 28,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 6\n    },\n    {\n      \"bufferView\": 29,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [-1, 0, -1],\n      \"max\": [1, 0, 1]\n    },\n    {\n      \"bufferView\": 30,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 31,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 32,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 33,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4,\n      \"min\": [-1, 0, -1],\n      \"max\": [1, 0, 1]\n    },\n    {\n      \"bufferView\": 34,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 35,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 36,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 4\n    },\n    {\n      \"bufferView\": 37,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 6\n    },\n    {\n      \"bufferView\": 38,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 24,\n      \"min\": [-1, -1, -1],\n      \"max\": [1, 1, 1]\n    },\n    {\n      \"bufferView\": 39,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 24\n    },\n    {\n      \"bufferView\": 40,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 24\n    },\n    {\n      \"bufferView\": 41,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 24\n    },\n    {\n      \"bufferView\": 42,\n      \"componentType\": 5123,\n      \"type\": \"SCALAR\",\n      \"count\": 36\n    },\n    {\n      \"bufferView\": 43,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 24,\n      \"min\": [-1, -1, -1],\n      \"max\": [1, 1, 1]\n    },\n    {\n      \"bufferView\": 44,\n      \"componentType\": 5126,\n      \"type\": \"VEC3\",\n      \"count\": 24\n    },\n    {\n      \"bufferView\": 45,\n      \"componentType\": 5126,\n      \"type\": \"VEC2\",\n      \"count\": 24\n    },\n    {\n      \"bufferView\": 46,\n      \"componentType\": 5126,\n      \"type\": \"VEC4\",\n      \"count\": 24\n    }\n  ],\n  \"asset\": {\n    \"generator\": \"Khronos glTF Blender I/O v3.6.28\",\n    \"version\": \"2.0\"\n  },\n  \"bufferViews\": [\n    {\n      \"buffer\": 0,\n      \"byteLength\": 648\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 648,\n      \"byteOffset\": 648\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 432,\n      \"byteOffset\": 1296\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 864,\n      \"byteOffset\": 1728\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 120,\n      \"byteOffset\": 2592\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 2712\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 2760\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 2808\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 2840\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 12,\n      \"byteOffset\": 2904\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 2916\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 2964\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 3012\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 3044\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 12,\n      \"byteOffset\": 3108\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3120\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3168\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 3216\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 3248\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3312\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3360\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 3408\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 3440\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 12,\n      \"byteOffset\": 3504\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3516\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3564\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 3612\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 3644\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 12,\n      \"byteOffset\": 3708\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3720\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3768\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 3816\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 3848\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3912\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 48,\n      \"byteOffset\": 3960\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 32,\n      \"byteOffset\": 4008\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 64,\n      \"byteOffset\": 4040\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 12,\n      \"byteOffset\": 4104\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 288,\n      \"byteOffset\": 4116\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 288,\n      \"byteOffset\": 4404\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 192,\n      \"byteOffset\": 4692\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 384,\n      \"byteOffset\": 4884\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 72,\n      \"byteOffset\": 5268\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 288,\n      \"byteOffset\": 5340\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 288,\n      \"byteOffset\": 5628\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 192,\n      \"byteOffset\": 5916\n    },\n    {\n      \"buffer\": 0,\n      \"byteLength\": 384,\n      \"byteOffset\": 6108\n    }\n  ],\n  \"buffers\": [\n    {\n      \"uri\": \"cornell.bin\",\n      \"byteLength\": 6492\n    }\n  ],\n  \"images\": [\n    {\n      \"name\": \"checkerboard\",\n      \"uri\": \"compressed/checkerboard.dds\",\n      \"mimeType\": \"image/png\"\n    }\n  ],\n  \"meshes\": [\n    {\n      \"name\": \"CubeMesh\",\n      \"primitives\": [\n        {\n          \"indices\": 4,\n          \"material\": 0,\n          \"attributes\": {\n            \"POSITION\": 0,\n            \"NORMAL\": 1,\n            \"TEXCOORD_0\": 2,\n            \"TANGENT\": 3\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"RightWallMesh\",\n      \"primitives\": [\n        {\n          \"indices\": 9,\n          \"material\": 1,\n          \"attributes\": {\n            \"POSITION\": 5,\n            \"NORMAL\": 6,\n            \"TEXCOORD_0\": 7,\n            \"TANGENT\": 8\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"LeftWallMesh\",\n      \"primitives\": [\n        {\n          \"indices\": 14,\n          \"material\": 2,\n          \"attributes\": {\n            \"POSITION\": 10,\n            \"NORMAL\": 11,\n            \"TEXCOORD_0\": 12,\n            \"TANGENT\": 13\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"BackWallMesh\",\n      \"primitives\": [\n        {\n          \"indices\": 14,\n          \"material\": 3,\n          \"attributes\": {\n            \"POSITION\": 15,\n            \"NORMAL\": 16,\n            \"TEXCOORD_0\": 17,\n            \"TANGENT\": 18\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"RoofMesh\",\n      \"primitives\": [\n        {\n          \"indices\": 23,\n          \"material\": 4,\n          \"attributes\": {\n            \"POSITION\": 19,\n            \"NORMAL\": 20,\n            \"TEXCOORD_0\": 21,\n            \"TANGENT\": 22\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"FloorMesh\",\n      \"primitives\": [\n        {\n          \"indices\": 28,\n          \"material\": 0,\n          \"attributes\": {\n            \"POSITION\": 24,\n            \"NORMAL\": 25,\n            \"TEXCOORD_0\": 26,\n            \"TANGENT\": 27\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"Plane\",\n      \"primitives\": [\n        {\n          \"indices\": 14,\n          \"material\": 5,\n          \"attributes\": {\n            \"POSITION\": 29,\n            \"NORMAL\": 30,\n            \"TEXCOORD_0\": 31,\n            \"TANGENT\": 32\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"Plane.001\",\n      \"primitives\": [\n        {\n          \"indices\": 37,\n          \"material\": 6,\n          \"attributes\": {\n            \"POSITION\": 33,\n            \"NORMAL\": 34,\n            \"TEXCOORD_0\": 35,\n            \"TANGENT\": 36\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"Cube.001\",\n      \"primitives\": [\n        {\n          \"indices\": 42,\n          \"material\": 7,\n          \"attributes\": {\n            \"POSITION\": 38,\n            \"NORMAL\": 39,\n            \"TEXCOORD_0\": 40,\n            \"TANGENT\": 41\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"Cube.002\",\n      \"primitives\": [\n        {\n          \"indices\": 42,\n          \"material\": 8,\n          \"attributes\": {\n            \"POSITION\": 43,\n            \"NORMAL\": 44,\n            \"TEXCOORD_0\": 45,\n            \"TANGENT\": 46\n          }\n        }\n      ]\n    }\n  ],\n  \"materials\": [\n    {\n      \"name\": \"floor\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.725000024, 0.709999979, 0.680000007, 1]\n      }\n    },\n    {\n      \"name\": \"rightWall\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.140000001, 0.449999988, 0.0909999982, 1]\n      }\n    },\n    {\n      \"name\": \"leftWall.001\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.629999995, 0.0649999976, 0.0500000007, 1]\n      }\n    },\n    {\n      \"name\": \"backWall\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.725000024, 0.709999979, 0.680000007, 1]\n      }\n    },\n    {\n      \"name\": \"ceiling\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.725000024, 0.709999979, 0.680000007, 1]\n      }\n    },\n    {\n      \"name\": \"light\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.779999971, 0.779999971, 0.779999971, 1]\n      },\n      \"extensions\": {\n        \"KHR_materials_emissive_strength\": {\n          \"emissiveStrength\": 20\n        }\n      },\n      \"emissiveFactor\": [1, 0.775918424, 0.616738319]\n    },\n    {\n      \"name\": \"ground\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"baseColorTexture\": {\n          \"index\": 0\n        },\n        \"metallicFactor\": 0\n      }\n    },\n    {\n      \"name\": \"shortBox\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.725000024, 0.709999979, 0.680000007, 1]\n      }\n    },\n    {\n      \"name\": \"tallBox\",\n      \"doubleSided\": true,\n      \"pbrMetallicRoughness\": {\n        \"metallicFactor\": 0,\n        \"baseColorFactor\": [0.725000024, 0.709999979, 0.680000007, 1]\n      }\n    }\n  ],\n  \"nodes\": [\n    {\n      \"mesh\": 0,\n      \"name\": \"Cube\",\n      \"translation\": [0, 1.02813554, 0]\n    },\n    {\n      \"mesh\": 1,\n      \"name\": \"RightWall\",\n      \"translation\": [0, 1.02813554, 0]\n    },\n    {\n      \"mesh\": 2,\n      \"name\": \"LeftWall\",\n      \"translation\": [0, 1.02813554, 0]\n    },\n    {\n      \"mesh\": 3,\n      \"name\": \"BackWall\",\n      \"translation\": [0, 1.02813554, 0]\n    },\n    {\n      \"mesh\": 4,\n      \"name\": \"Roof\",\n      \"translation\": [0, 1.02813554, 0]\n    },\n    {\n      \"mesh\": 5,\n      \"name\": \"Floor\",\n      \"translation\": [0, 1.02813554, 0]\n    },\n    {\n      \"mesh\": 6,\n      \"name\": \"Plane\",\n      \"translation\": [-0.00379260769, 2.02274299, -0.0408690274],\n      \"scale\": [0.235878631, 0.235878631, 0.194536671]\n    },\n    {\n      \"mesh\": 7,\n      \"name\": \"Plane.001\",\n      \"scale\": [50, 50, 50]\n    },\n    {\n      \"mesh\": 8,\n      \"name\": \"Cube.003\",\n      \"translation\": [0.325628012, 0.329526007, 0.373807997],\n      \"rotation\": [0, -0.144368097, 0, 0.989524126],\n      \"scale\": [0.297057986, 0.297057986, 0.297057986]\n    },\n    {\n      \"mesh\": 9,\n      \"name\": \"Cube.004\",\n      \"translation\": [-0.327136993, 0.609180987, -0.291770011],\n      \"rotation\": [0, 0.157149047, 0, 0.987574995],\n      \"scale\": [0.290537, 0.581031978, 0.290537]\n    }\n  ],\n  \"samplers\": [\n    {\n      \"magFilter\": 9729,\n      \"minFilter\": 9987\n    }\n  ],\n  \"scene\": 0,\n  \"scenes\": [\n    {\n      \"name\": \"Scene\",\n      \"nodes\": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]\n    }\n  ],\n  \"textures\": [\n    {\n      \"source\": 0,\n      \"sampler\": 0\n    }\n  ],\n  \"extensionsUsed\": [\n    \"KHR_materials_emissive_strength\"\n  ]\n}\n"
  },
  {
    "path": "Assets/CornellBox/license.txt",
    "content": "Model Information:\n* title:\tCornell Box- Original\n* source:\thttps://sketchfab.com/3d-models/cornell-box-original-0d18de8d108c4c9cab1a4405698cc6b6\n* author:\tt-ly (https://sketchfab.com/t-ly)\n\nModel License:\n* license type:\tCC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)\n* requirements:\tAuthor must be credited. Commercial use is allowed.\n\nIf you use this 3D model in your project be sure to copy paste this credit wherever you share it:\nThis work is based on \"Cornell Box- Original\" (https://sketchfab.com/3d-models/cornell-box-original-0d18de8d108c4c9cab1a4405698cc6b6) by t-ly (https://sketchfab.com/t-ly) licensed under CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)"
  },
  {
    "path": "Assets/Font/Font.h",
    "content": "#pragma once\n\n#if defined(__cplusplus)\nextern \"C\" {\n#endif\n\nstruct FontSpan\n{\n    const void* Data;\n    size_t N;\n};\n\nenum FONT_TYPE\n{\n    ROBOTO_REGULAR,\n    FONT_AWESOME_6,\n    BFONT,\n    COUNT\n};\n\n__declspec(dllexport) FontSpan GetFont(FONT_TYPE f);\n\n#if defined(__cplusplus)\n}\n#endif"
  },
  {
    "path": "Assets/Font/IconsFontAwesome6.h",
    "content": "// Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py for languages C and C++\n// from https://github.com/FortAwesome/Font-Awesome/raw/6.x/metadata/icons.yml\n// for use with https://github.com/FortAwesome/Font-Awesome/blob/6.x/webfonts/fa-solid-900.ttf\n#pragma once\n\n#define FONT_ICON_FILE_NAME_FAS \"fa-solid-900.ttf\"\n\n#define ICON_MIN_FA 0xe005\n#define ICON_MAX_16_FA 0xf8ff\n#define ICON_MAX_FA 0xf8ff\n#define ICON_FA_0 \"0\"\t// U+0030\n#define ICON_FA_1 \"1\"\t// U+0031\n#define ICON_FA_2 \"2\"\t// U+0032\n#define ICON_FA_3 \"3\"\t// U+0033\n#define ICON_FA_4 \"4\"\t// U+0034\n#define ICON_FA_5 \"5\"\t// U+0035\n#define ICON_FA_6 \"6\"\t// U+0036\n#define ICON_FA_7 \"7\"\t// U+0037\n#define ICON_FA_8 \"8\"\t// U+0038\n#define ICON_FA_9 \"9\"\t// U+0039\n#define ICON_FA_A \"A\"\t// U+0041\n#define ICON_FA_ADDRESS_BOOK \"\\xef\\x8a\\xb9\"\t// U+f2b9\n#define ICON_FA_ADDRESS_CARD \"\\xef\\x8a\\xbb\"\t// U+f2bb\n#define ICON_FA_ALIGN_CENTER \"\\xef\\x80\\xb7\"\t// U+f037\n#define ICON_FA_ALIGN_JUSTIFY \"\\xef\\x80\\xb9\"\t// U+f039\n#define ICON_FA_ALIGN_LEFT \"\\xef\\x80\\xb6\"\t// U+f036\n#define ICON_FA_ALIGN_RIGHT \"\\xef\\x80\\xb8\"\t// U+f038\n#define ICON_FA_ANCHOR \"\\xef\\x84\\xbd\"\t// U+f13d\n#define ICON_FA_ANCHOR_CIRCLE_CHECK \"\\xee\\x92\\xaa\"\t// U+e4aa\n#define ICON_FA_ANCHOR_CIRCLE_EXCLAMATION \"\\xee\\x92\\xab\"\t// U+e4ab\n#define ICON_FA_ANCHOR_CIRCLE_XMARK \"\\xee\\x92\\xac\"\t// U+e4ac\n#define ICON_FA_ANCHOR_LOCK \"\\xee\\x92\\xad\"\t// U+e4ad\n#define ICON_FA_ANGLE_DOWN \"\\xef\\x84\\x87\"\t// U+f107\n#define ICON_FA_ANGLE_LEFT \"\\xef\\x84\\x84\"\t// U+f104\n#define ICON_FA_ANGLE_RIGHT \"\\xef\\x84\\x85\"\t// U+f105\n#define ICON_FA_ANGLE_UP \"\\xef\\x84\\x86\"\t// U+f106\n#define ICON_FA_ANGLES_DOWN \"\\xef\\x84\\x83\"\t// U+f103\n#define ICON_FA_ANGLES_LEFT \"\\xef\\x84\\x80\"\t// U+f100\n#define ICON_FA_ANGLES_RIGHT \"\\xef\\x84\\x81\"\t// U+f101\n#define ICON_FA_ANGLES_UP \"\\xef\\x84\\x82\"\t// U+f102\n#define ICON_FA_ANKH \"\\xef\\x99\\x84\"\t// U+f644\n#define ICON_FA_APPLE_WHOLE \"\\xef\\x97\\x91\"\t// U+f5d1\n#define ICON_FA_ARCHWAY \"\\xef\\x95\\x97\"\t// U+f557\n#define ICON_FA_ARROW_DOWN \"\\xef\\x81\\xa3\"\t// U+f063\n#define ICON_FA_ARROW_DOWN_1_9 \"\\xef\\x85\\xa2\"\t// U+f162\n#define ICON_FA_ARROW_DOWN_9_1 \"\\xef\\xa2\\x86\"\t// U+f886\n#define ICON_FA_ARROW_DOWN_A_Z \"\\xef\\x85\\x9d\"\t// U+f15d\n#define ICON_FA_ARROW_DOWN_LONG \"\\xef\\x85\\xb5\"\t// U+f175\n#define ICON_FA_ARROW_DOWN_SHORT_WIDE \"\\xef\\xa2\\x84\"\t// U+f884\n#define ICON_FA_ARROW_DOWN_UP_ACROSS_LINE \"\\xee\\x92\\xaf\"\t// U+e4af\n#define ICON_FA_ARROW_DOWN_UP_LOCK \"\\xee\\x92\\xb0\"\t// U+e4b0\n#define ICON_FA_ARROW_DOWN_WIDE_SHORT \"\\xef\\x85\\xa0\"\t// U+f160\n#define ICON_FA_ARROW_DOWN_Z_A \"\\xef\\xa2\\x81\"\t// U+f881\n#define ICON_FA_ARROW_LEFT \"\\xef\\x81\\xa0\"\t// U+f060\n#define ICON_FA_ARROW_LEFT_LONG \"\\xef\\x85\\xb7\"\t// U+f177\n#define ICON_FA_ARROW_POINTER \"\\xef\\x89\\x85\"\t// U+f245\n#define ICON_FA_ARROW_RIGHT \"\\xef\\x81\\xa1\"\t// U+f061\n#define ICON_FA_ARROW_RIGHT_ARROW_LEFT \"\\xef\\x83\\xac\"\t// U+f0ec\n#define ICON_FA_ARROW_RIGHT_FROM_BRACKET \"\\xef\\x82\\x8b\"\t// U+f08b\n#define ICON_FA_ARROW_RIGHT_LONG \"\\xef\\x85\\xb8\"\t// U+f178\n#define ICON_FA_ARROW_RIGHT_TO_BRACKET \"\\xef\\x82\\x90\"\t// U+f090\n#define ICON_FA_ARROW_RIGHT_TO_CITY \"\\xee\\x92\\xb3\"\t// U+e4b3\n#define ICON_FA_ARROW_ROTATE_LEFT \"\\xef\\x83\\xa2\"\t// U+f0e2\n#define ICON_FA_ARROW_ROTATE_RIGHT \"\\xef\\x80\\x9e\"\t// U+f01e\n#define ICON_FA_ARROW_TREND_DOWN \"\\xee\\x82\\x97\"\t// U+e097\n#define ICON_FA_ARROW_TREND_UP \"\\xee\\x82\\x98\"\t// U+e098\n#define ICON_FA_ARROW_TURN_DOWN \"\\xef\\x85\\x89\"\t// U+f149\n#define ICON_FA_ARROW_TURN_UP \"\\xef\\x85\\x88\"\t// U+f148\n#define ICON_FA_ARROW_UP \"\\xef\\x81\\xa2\"\t// U+f062\n#define ICON_FA_ARROW_UP_1_9 \"\\xef\\x85\\xa3\"\t// U+f163\n#define ICON_FA_ARROW_UP_9_1 \"\\xef\\xa2\\x87\"\t// U+f887\n#define ICON_FA_ARROW_UP_A_Z \"\\xef\\x85\\x9e\"\t// U+f15e\n#define ICON_FA_ARROW_UP_FROM_BRACKET \"\\xee\\x82\\x9a\"\t// U+e09a\n#define ICON_FA_ARROW_UP_FROM_GROUND_WATER \"\\xee\\x92\\xb5\"\t// U+e4b5\n#define ICON_FA_ARROW_UP_FROM_WATER_PUMP \"\\xee\\x92\\xb6\"\t// U+e4b6\n#define ICON_FA_ARROW_UP_LONG \"\\xef\\x85\\xb6\"\t// U+f176\n#define ICON_FA_ARROW_UP_RIGHT_DOTS \"\\xee\\x92\\xb7\"\t// U+e4b7\n#define ICON_FA_ARROW_UP_RIGHT_FROM_SQUARE \"\\xef\\x82\\x8e\"\t// U+f08e\n#define ICON_FA_ARROW_UP_SHORT_WIDE \"\\xef\\xa2\\x85\"\t// U+f885\n#define ICON_FA_ARROW_UP_WIDE_SHORT \"\\xef\\x85\\xa1\"\t// U+f161\n#define ICON_FA_ARROW_UP_Z_A \"\\xef\\xa2\\x82\"\t// U+f882\n#define ICON_FA_ARROWS_DOWN_TO_LINE \"\\xee\\x92\\xb8\"\t// U+e4b8\n#define ICON_FA_ARROWS_DOWN_TO_PEOPLE \"\\xee\\x92\\xb9\"\t// U+e4b9\n#define ICON_FA_ARROWS_LEFT_RIGHT \"\\xef\\x81\\xbe\"\t// U+f07e\n#define ICON_FA_ARROWS_LEFT_RIGHT_TO_LINE \"\\xee\\x92\\xba\"\t// U+e4ba\n#define ICON_FA_ARROWS_ROTATE \"\\xef\\x80\\xa1\"\t// U+f021\n#define ICON_FA_ARROWS_SPIN \"\\xee\\x92\\xbb\"\t// U+e4bb\n#define ICON_FA_ARROWS_SPLIT_UP_AND_LEFT \"\\xee\\x92\\xbc\"\t// U+e4bc\n#define ICON_FA_ARROWS_TO_CIRCLE \"\\xee\\x92\\xbd\"\t// U+e4bd\n#define ICON_FA_ARROWS_TO_DOT \"\\xee\\x92\\xbe\"\t// U+e4be\n#define ICON_FA_ARROWS_TO_EYE \"\\xee\\x92\\xbf\"\t// U+e4bf\n#define ICON_FA_ARROWS_TURN_RIGHT \"\\xee\\x93\\x80\"\t// U+e4c0\n#define ICON_FA_ARROWS_TURN_TO_DOTS \"\\xee\\x93\\x81\"\t// U+e4c1\n#define ICON_FA_ARROWS_UP_DOWN \"\\xef\\x81\\xbd\"\t// U+f07d\n#define ICON_FA_ARROWS_UP_DOWN_LEFT_RIGHT \"\\xef\\x81\\x87\"\t// U+f047\n#define ICON_FA_ARROWS_UP_TO_LINE \"\\xee\\x93\\x82\"\t// U+e4c2\n#define ICON_FA_ASTERISK \"*\"\t// U+002a\n#define ICON_FA_AT \"@\"\t// U+0040\n#define ICON_FA_ATOM \"\\xef\\x97\\x92\"\t// U+f5d2\n#define ICON_FA_AUDIO_DESCRIPTION \"\\xef\\x8a\\x9e\"\t// U+f29e\n#define ICON_FA_AUSTRAL_SIGN \"\\xee\\x82\\xa9\"\t// U+e0a9\n#define ICON_FA_AWARD \"\\xef\\x95\\x99\"\t// U+f559\n#define ICON_FA_B \"B\"\t// U+0042\n#define ICON_FA_BABY \"\\xef\\x9d\\xbc\"\t// U+f77c\n#define ICON_FA_BABY_CARRIAGE \"\\xef\\x9d\\xbd\"\t// U+f77d\n#define ICON_FA_BACKWARD \"\\xef\\x81\\x8a\"\t// U+f04a\n#define ICON_FA_BACKWARD_FAST \"\\xef\\x81\\x89\"\t// U+f049\n#define ICON_FA_BACKWARD_STEP \"\\xef\\x81\\x88\"\t// U+f048\n#define ICON_FA_BACON \"\\xef\\x9f\\xa5\"\t// U+f7e5\n#define ICON_FA_BACTERIA \"\\xee\\x81\\x99\"\t// U+e059\n#define ICON_FA_BACTERIUM \"\\xee\\x81\\x9a\"\t// U+e05a\n#define ICON_FA_BAG_SHOPPING \"\\xef\\x8a\\x90\"\t// U+f290\n#define ICON_FA_BAHAI \"\\xef\\x99\\xa6\"\t// U+f666\n#define ICON_FA_BAHT_SIGN \"\\xee\\x82\\xac\"\t// U+e0ac\n#define ICON_FA_BAN \"\\xef\\x81\\x9e\"\t// U+f05e\n#define ICON_FA_BAN_SMOKING \"\\xef\\x95\\x8d\"\t// U+f54d\n#define ICON_FA_BANDAGE \"\\xef\\x91\\xa2\"\t// U+f462\n#define ICON_FA_BANGLADESHI_TAKA_SIGN \"\\xee\\x8b\\xa6\"\t// U+e2e6\n#define ICON_FA_BARCODE \"\\xef\\x80\\xaa\"\t// U+f02a\n#define ICON_FA_BARS \"\\xef\\x83\\x89\"\t// U+f0c9\n#define ICON_FA_BARS_PROGRESS \"\\xef\\xa0\\xa8\"\t// U+f828\n#define ICON_FA_BARS_STAGGERED \"\\xef\\x95\\x90\"\t// U+f550\n#define ICON_FA_BASEBALL \"\\xef\\x90\\xb3\"\t// U+f433\n#define ICON_FA_BASEBALL_BAT_BALL \"\\xef\\x90\\xb2\"\t// U+f432\n#define ICON_FA_BASKET_SHOPPING \"\\xef\\x8a\\x91\"\t// U+f291\n#define ICON_FA_BASKETBALL \"\\xef\\x90\\xb4\"\t// U+f434\n#define ICON_FA_BATH \"\\xef\\x8b\\x8d\"\t// U+f2cd\n#define ICON_FA_BATTERY_EMPTY \"\\xef\\x89\\x84\"\t// U+f244\n#define ICON_FA_BATTERY_FULL \"\\xef\\x89\\x80\"\t// U+f240\n#define ICON_FA_BATTERY_HALF \"\\xef\\x89\\x82\"\t// U+f242\n#define ICON_FA_BATTERY_QUARTER \"\\xef\\x89\\x83\"\t// U+f243\n#define ICON_FA_BATTERY_THREE_QUARTERS \"\\xef\\x89\\x81\"\t// U+f241\n#define ICON_FA_BED \"\\xef\\x88\\xb6\"\t// U+f236\n#define ICON_FA_BED_PULSE \"\\xef\\x92\\x87\"\t// U+f487\n#define ICON_FA_BEER_MUG_EMPTY \"\\xef\\x83\\xbc\"\t// U+f0fc\n#define ICON_FA_BELL \"\\xef\\x83\\xb3\"\t// U+f0f3\n#define ICON_FA_BELL_CONCIERGE \"\\xef\\x95\\xa2\"\t// U+f562\n#define ICON_FA_BELL_SLASH \"\\xef\\x87\\xb6\"\t// U+f1f6\n#define ICON_FA_BEZIER_CURVE \"\\xef\\x95\\x9b\"\t// U+f55b\n#define ICON_FA_BICYCLE \"\\xef\\x88\\x86\"\t// U+f206\n#define ICON_FA_BINOCULARS \"\\xef\\x87\\xa5\"\t// U+f1e5\n#define ICON_FA_BIOHAZARD \"\\xef\\x9e\\x80\"\t// U+f780\n#define ICON_FA_BITCOIN_SIGN \"\\xee\\x82\\xb4\"\t// U+e0b4\n#define ICON_FA_BLENDER \"\\xef\\x94\\x97\"\t// U+f517\n#define ICON_FA_BLENDER_PHONE \"\\xef\\x9a\\xb6\"\t// U+f6b6\n#define ICON_FA_BLOG \"\\xef\\x9e\\x81\"\t// U+f781\n#define ICON_FA_BOLD \"\\xef\\x80\\xb2\"\t// U+f032\n#define ICON_FA_BOLT \"\\xef\\x83\\xa7\"\t// U+f0e7\n#define ICON_FA_BOLT_LIGHTNING \"\\xee\\x82\\xb7\"\t// U+e0b7\n#define ICON_FA_BOMB \"\\xef\\x87\\xa2\"\t// U+f1e2\n#define ICON_FA_BONE \"\\xef\\x97\\x97\"\t// U+f5d7\n#define ICON_FA_BONG \"\\xef\\x95\\x9c\"\t// U+f55c\n#define ICON_FA_BOOK \"\\xef\\x80\\xad\"\t// U+f02d\n#define ICON_FA_BOOK_ATLAS \"\\xef\\x95\\x98\"\t// U+f558\n#define ICON_FA_BOOK_BIBLE \"\\xef\\x99\\x87\"\t// U+f647\n#define ICON_FA_BOOK_BOOKMARK \"\\xee\\x82\\xbb\"\t// U+e0bb\n#define ICON_FA_BOOK_JOURNAL_WHILLS \"\\xef\\x99\\xaa\"\t// U+f66a\n#define ICON_FA_BOOK_MEDICAL \"\\xef\\x9f\\xa6\"\t// U+f7e6\n#define ICON_FA_BOOK_OPEN \"\\xef\\x94\\x98\"\t// U+f518\n#define ICON_FA_BOOK_OPEN_READER \"\\xef\\x97\\x9a\"\t// U+f5da\n#define ICON_FA_BOOK_QURAN \"\\xef\\x9a\\x87\"\t// U+f687\n#define ICON_FA_BOOK_SKULL \"\\xef\\x9a\\xb7\"\t// U+f6b7\n#define ICON_FA_BOOK_TANAKH \"\\xef\\xa0\\xa7\"\t// U+f827\n#define ICON_FA_BOOKMARK \"\\xef\\x80\\xae\"\t// U+f02e\n#define ICON_FA_BORDER_ALL \"\\xef\\xa1\\x8c\"\t// U+f84c\n#define ICON_FA_BORDER_NONE \"\\xef\\xa1\\x90\"\t// U+f850\n#define ICON_FA_BORDER_TOP_LEFT \"\\xef\\xa1\\x93\"\t// U+f853\n#define ICON_FA_BORE_HOLE \"\\xee\\x93\\x83\"\t// U+e4c3\n#define ICON_FA_BOTTLE_DROPLET \"\\xee\\x93\\x84\"\t// U+e4c4\n#define ICON_FA_BOTTLE_WATER \"\\xee\\x93\\x85\"\t// U+e4c5\n#define ICON_FA_BOWL_FOOD \"\\xee\\x93\\x86\"\t// U+e4c6\n#define ICON_FA_BOWL_RICE \"\\xee\\x8b\\xab\"\t// U+e2eb\n#define ICON_FA_BOWLING_BALL \"\\xef\\x90\\xb6\"\t// U+f436\n#define ICON_FA_BOX \"\\xef\\x91\\xa6\"\t// U+f466\n#define ICON_FA_BOX_ARCHIVE \"\\xef\\x86\\x87\"\t// U+f187\n#define ICON_FA_BOX_OPEN \"\\xef\\x92\\x9e\"\t// U+f49e\n#define ICON_FA_BOX_TISSUE \"\\xee\\x81\\x9b\"\t// U+e05b\n#define ICON_FA_BOXES_PACKING \"\\xee\\x93\\x87\"\t// U+e4c7\n#define ICON_FA_BOXES_STACKED \"\\xef\\x91\\xa8\"\t// U+f468\n#define ICON_FA_BRAILLE \"\\xef\\x8a\\xa1\"\t// U+f2a1\n#define ICON_FA_BRAIN \"\\xef\\x97\\x9c\"\t// U+f5dc\n#define ICON_FA_BRAZILIAN_REAL_SIGN \"\\xee\\x91\\xac\"\t// U+e46c\n#define ICON_FA_BREAD_SLICE \"\\xef\\x9f\\xac\"\t// U+f7ec\n#define ICON_FA_BRIDGE \"\\xee\\x93\\x88\"\t// U+e4c8\n#define ICON_FA_BRIDGE_CIRCLE_CHECK \"\\xee\\x93\\x89\"\t// U+e4c9\n#define ICON_FA_BRIDGE_CIRCLE_EXCLAMATION \"\\xee\\x93\\x8a\"\t// U+e4ca\n#define ICON_FA_BRIDGE_CIRCLE_XMARK \"\\xee\\x93\\x8b\"\t// U+e4cb\n#define ICON_FA_BRIDGE_LOCK \"\\xee\\x93\\x8c\"\t// U+e4cc\n#define ICON_FA_BRIDGE_WATER \"\\xee\\x93\\x8e\"\t// U+e4ce\n#define ICON_FA_BRIEFCASE \"\\xef\\x82\\xb1\"\t// U+f0b1\n#define ICON_FA_BRIEFCASE_MEDICAL \"\\xef\\x91\\xa9\"\t// U+f469\n#define ICON_FA_BROOM \"\\xef\\x94\\x9a\"\t// U+f51a\n#define ICON_FA_BROOM_BALL \"\\xef\\x91\\x98\"\t// U+f458\n#define ICON_FA_BRUSH \"\\xef\\x95\\x9d\"\t// U+f55d\n#define ICON_FA_BUCKET \"\\xee\\x93\\x8f\"\t// U+e4cf\n#define ICON_FA_BUG \"\\xef\\x86\\x88\"\t// U+f188\n#define ICON_FA_BUG_SLASH \"\\xee\\x92\\x90\"\t// U+e490\n#define ICON_FA_BUGS \"\\xee\\x93\\x90\"\t// U+e4d0\n#define ICON_FA_BUILDING \"\\xef\\x86\\xad\"\t// U+f1ad\n#define ICON_FA_BUILDING_CIRCLE_ARROW_RIGHT \"\\xee\\x93\\x91\"\t// U+e4d1\n#define ICON_FA_BUILDING_CIRCLE_CHECK \"\\xee\\x93\\x92\"\t// U+e4d2\n#define ICON_FA_BUILDING_CIRCLE_EXCLAMATION \"\\xee\\x93\\x93\"\t// U+e4d3\n#define ICON_FA_BUILDING_CIRCLE_XMARK \"\\xee\\x93\\x94\"\t// U+e4d4\n#define ICON_FA_BUILDING_COLUMNS \"\\xef\\x86\\x9c\"\t// U+f19c\n#define ICON_FA_BUILDING_FLAG \"\\xee\\x93\\x95\"\t// U+e4d5\n#define ICON_FA_BUILDING_LOCK \"\\xee\\x93\\x96\"\t// U+e4d6\n#define ICON_FA_BUILDING_NGO \"\\xee\\x93\\x97\"\t// U+e4d7\n#define ICON_FA_BUILDING_SHIELD \"\\xee\\x93\\x98\"\t// U+e4d8\n#define ICON_FA_BUILDING_UN \"\\xee\\x93\\x99\"\t// U+e4d9\n#define ICON_FA_BUILDING_USER \"\\xee\\x93\\x9a\"\t// U+e4da\n#define ICON_FA_BUILDING_WHEAT \"\\xee\\x93\\x9b\"\t// U+e4db\n#define ICON_FA_BULLHORN \"\\xef\\x82\\xa1\"\t// U+f0a1\n#define ICON_FA_BULLSEYE \"\\xef\\x85\\x80\"\t// U+f140\n#define ICON_FA_BURGER \"\\xef\\xa0\\x85\"\t// U+f805\n#define ICON_FA_BURST \"\\xee\\x93\\x9c\"\t// U+e4dc\n#define ICON_FA_BUS \"\\xef\\x88\\x87\"\t// U+f207\n#define ICON_FA_BUS_SIMPLE \"\\xef\\x95\\x9e\"\t// U+f55e\n#define ICON_FA_BUSINESS_TIME \"\\xef\\x99\\x8a\"\t// U+f64a\n#define ICON_FA_C \"C\"\t// U+0043\n#define ICON_FA_CABLE_CAR \"\\xef\\x9f\\x9a\"\t// U+f7da\n#define ICON_FA_CAKE_CANDLES \"\\xef\\x87\\xbd\"\t// U+f1fd\n#define ICON_FA_CALCULATOR \"\\xef\\x87\\xac\"\t// U+f1ec\n#define ICON_FA_CALENDAR \"\\xef\\x84\\xb3\"\t// U+f133\n#define ICON_FA_CALENDAR_CHECK \"\\xef\\x89\\xb4\"\t// U+f274\n#define ICON_FA_CALENDAR_DAY \"\\xef\\x9e\\x83\"\t// U+f783\n#define ICON_FA_CALENDAR_DAYS \"\\xef\\x81\\xb3\"\t// U+f073\n#define ICON_FA_CALENDAR_MINUS \"\\xef\\x89\\xb2\"\t// U+f272\n#define ICON_FA_CALENDAR_PLUS \"\\xef\\x89\\xb1\"\t// U+f271\n#define ICON_FA_CALENDAR_WEEK \"\\xef\\x9e\\x84\"\t// U+f784\n#define ICON_FA_CALENDAR_XMARK \"\\xef\\x89\\xb3\"\t// U+f273\n#define ICON_FA_CAMERA \"\\xef\\x80\\xb0\"\t// U+f030\n#define ICON_FA_CAMERA_RETRO \"\\xef\\x82\\x83\"\t// U+f083\n#define ICON_FA_CAMERA_ROTATE \"\\xee\\x83\\x98\"\t// U+e0d8\n#define ICON_FA_CAMPGROUND \"\\xef\\x9a\\xbb\"\t// U+f6bb\n#define ICON_FA_CANDY_CANE \"\\xef\\x9e\\x86\"\t// U+f786\n#define ICON_FA_CANNABIS \"\\xef\\x95\\x9f\"\t// U+f55f\n#define ICON_FA_CAPSULES \"\\xef\\x91\\xab\"\t// U+f46b\n#define ICON_FA_CAR \"\\xef\\x86\\xb9\"\t// U+f1b9\n#define ICON_FA_CAR_BATTERY \"\\xef\\x97\\x9f\"\t// U+f5df\n#define ICON_FA_CAR_BURST \"\\xef\\x97\\xa1\"\t// U+f5e1\n#define ICON_FA_CAR_ON \"\\xee\\x93\\x9d\"\t// U+e4dd\n#define ICON_FA_CAR_REAR \"\\xef\\x97\\x9e\"\t// U+f5de\n#define ICON_FA_CAR_SIDE \"\\xef\\x97\\xa4\"\t// U+f5e4\n#define ICON_FA_CAR_TUNNEL \"\\xee\\x93\\x9e\"\t// U+e4de\n#define ICON_FA_CARAVAN \"\\xef\\xa3\\xbf\"\t// U+f8ff\n#define ICON_FA_CARET_DOWN \"\\xef\\x83\\x97\"\t// U+f0d7\n#define ICON_FA_CARET_LEFT \"\\xef\\x83\\x99\"\t// U+f0d9\n#define ICON_FA_CARET_RIGHT \"\\xef\\x83\\x9a\"\t// U+f0da\n#define ICON_FA_CARET_UP \"\\xef\\x83\\x98\"\t// U+f0d8\n#define ICON_FA_CARROT \"\\xef\\x9e\\x87\"\t// U+f787\n#define ICON_FA_CART_ARROW_DOWN \"\\xef\\x88\\x98\"\t// U+f218\n#define ICON_FA_CART_FLATBED \"\\xef\\x91\\xb4\"\t// U+f474\n#define ICON_FA_CART_FLATBED_SUITCASE \"\\xef\\x96\\x9d\"\t// U+f59d\n#define ICON_FA_CART_PLUS \"\\xef\\x88\\x97\"\t// U+f217\n#define ICON_FA_CART_SHOPPING \"\\xef\\x81\\xba\"\t// U+f07a\n#define ICON_FA_CASH_REGISTER \"\\xef\\x9e\\x88\"\t// U+f788\n#define ICON_FA_CAT \"\\xef\\x9a\\xbe\"\t// U+f6be\n#define ICON_FA_CEDI_SIGN \"\\xee\\x83\\x9f\"\t// U+e0df\n#define ICON_FA_CENT_SIGN \"\\xee\\x8f\\xb5\"\t// U+e3f5\n#define ICON_FA_CERTIFICATE \"\\xef\\x82\\xa3\"\t// U+f0a3\n#define ICON_FA_CHAIR \"\\xef\\x9b\\x80\"\t// U+f6c0\n#define ICON_FA_CHALKBOARD \"\\xef\\x94\\x9b\"\t// U+f51b\n#define ICON_FA_CHALKBOARD_USER \"\\xef\\x94\\x9c\"\t// U+f51c\n#define ICON_FA_CHAMPAGNE_GLASSES \"\\xef\\x9e\\x9f\"\t// U+f79f\n#define ICON_FA_CHARGING_STATION \"\\xef\\x97\\xa7\"\t// U+f5e7\n#define ICON_FA_CHART_AREA \"\\xef\\x87\\xbe\"\t// U+f1fe\n#define ICON_FA_CHART_BAR \"\\xef\\x82\\x80\"\t// U+f080\n#define ICON_FA_CHART_COLUMN \"\\xee\\x83\\xa3\"\t// U+e0e3\n#define ICON_FA_CHART_GANTT \"\\xee\\x83\\xa4\"\t// U+e0e4\n#define ICON_FA_CHART_LINE \"\\xef\\x88\\x81\"\t// U+f201\n#define ICON_FA_CHART_PIE \"\\xef\\x88\\x80\"\t// U+f200\n#define ICON_FA_CHART_SIMPLE \"\\xee\\x91\\xb3\"\t// U+e473\n#define ICON_FA_CHECK \"\\xef\\x80\\x8c\"\t// U+f00c\n#define ICON_FA_CHECK_DOUBLE \"\\xef\\x95\\xa0\"\t// U+f560\n#define ICON_FA_CHECK_TO_SLOT \"\\xef\\x9d\\xb2\"\t// U+f772\n#define ICON_FA_CHEESE \"\\xef\\x9f\\xaf\"\t// U+f7ef\n#define ICON_FA_CHESS \"\\xef\\x90\\xb9\"\t// U+f439\n#define ICON_FA_CHESS_BISHOP \"\\xef\\x90\\xba\"\t// U+f43a\n#define ICON_FA_CHESS_BOARD \"\\xef\\x90\\xbc\"\t// U+f43c\n#define ICON_FA_CHESS_KING \"\\xef\\x90\\xbf\"\t// U+f43f\n#define ICON_FA_CHESS_KNIGHT \"\\xef\\x91\\x81\"\t// U+f441\n#define ICON_FA_CHESS_PAWN \"\\xef\\x91\\x83\"\t// U+f443\n#define ICON_FA_CHESS_QUEEN \"\\xef\\x91\\x85\"\t// U+f445\n#define ICON_FA_CHESS_ROOK \"\\xef\\x91\\x87\"\t// U+f447\n#define ICON_FA_CHEVRON_DOWN \"\\xef\\x81\\xb8\"\t// U+f078\n#define ICON_FA_CHEVRON_LEFT \"\\xef\\x81\\x93\"\t// U+f053\n#define ICON_FA_CHEVRON_RIGHT \"\\xef\\x81\\x94\"\t// U+f054\n#define ICON_FA_CHEVRON_UP \"\\xef\\x81\\xb7\"\t// U+f077\n#define ICON_FA_CHILD \"\\xef\\x86\\xae\"\t// U+f1ae\n#define ICON_FA_CHILD_COMBATANT \"\\xee\\x93\\xa0\"\t// U+e4e0\n#define ICON_FA_CHILD_DRESS \"\\xee\\x96\\x9c\"\t// U+e59c\n#define ICON_FA_CHILD_REACHING \"\\xee\\x96\\x9d\"\t// U+e59d\n#define ICON_FA_CHILDREN \"\\xee\\x93\\xa1\"\t// U+e4e1\n#define ICON_FA_CHURCH \"\\xef\\x94\\x9d\"\t// U+f51d\n#define ICON_FA_CIRCLE \"\\xef\\x84\\x91\"\t// U+f111\n#define ICON_FA_CIRCLE_ARROW_DOWN \"\\xef\\x82\\xab\"\t// U+f0ab\n#define ICON_FA_CIRCLE_ARROW_LEFT \"\\xef\\x82\\xa8\"\t// U+f0a8\n#define ICON_FA_CIRCLE_ARROW_RIGHT \"\\xef\\x82\\xa9\"\t// U+f0a9\n#define ICON_FA_CIRCLE_ARROW_UP \"\\xef\\x82\\xaa\"\t// U+f0aa\n#define ICON_FA_CIRCLE_CHECK \"\\xef\\x81\\x98\"\t// U+f058\n#define ICON_FA_CIRCLE_CHEVRON_DOWN \"\\xef\\x84\\xba\"\t// U+f13a\n#define ICON_FA_CIRCLE_CHEVRON_LEFT \"\\xef\\x84\\xb7\"\t// U+f137\n#define ICON_FA_CIRCLE_CHEVRON_RIGHT \"\\xef\\x84\\xb8\"\t// U+f138\n#define ICON_FA_CIRCLE_CHEVRON_UP \"\\xef\\x84\\xb9\"\t// U+f139\n#define ICON_FA_CIRCLE_DOLLAR_TO_SLOT \"\\xef\\x92\\xb9\"\t// U+f4b9\n#define ICON_FA_CIRCLE_DOT \"\\xef\\x86\\x92\"\t// U+f192\n#define ICON_FA_CIRCLE_DOWN \"\\xef\\x8d\\x98\"\t// U+f358\n#define ICON_FA_CIRCLE_EXCLAMATION \"\\xef\\x81\\xaa\"\t// U+f06a\n#define ICON_FA_CIRCLE_H \"\\xef\\x91\\xbe\"\t// U+f47e\n#define ICON_FA_CIRCLE_HALF_STROKE \"\\xef\\x81\\x82\"\t// U+f042\n#define ICON_FA_CIRCLE_INFO \"\\xef\\x81\\x9a\"\t// U+f05a\n#define ICON_FA_CIRCLE_LEFT \"\\xef\\x8d\\x99\"\t// U+f359\n#define ICON_FA_CIRCLE_MINUS \"\\xef\\x81\\x96\"\t// U+f056\n#define ICON_FA_CIRCLE_NODES \"\\xee\\x93\\xa2\"\t// U+e4e2\n#define ICON_FA_CIRCLE_NOTCH \"\\xef\\x87\\x8e\"\t// U+f1ce\n#define ICON_FA_CIRCLE_PAUSE \"\\xef\\x8a\\x8b\"\t// U+f28b\n#define ICON_FA_CIRCLE_PLAY \"\\xef\\x85\\x84\"\t// U+f144\n#define ICON_FA_CIRCLE_PLUS \"\\xef\\x81\\x95\"\t// U+f055\n#define ICON_FA_CIRCLE_QUESTION \"\\xef\\x81\\x99\"\t// U+f059\n#define ICON_FA_CIRCLE_RADIATION \"\\xef\\x9e\\xba\"\t// U+f7ba\n#define ICON_FA_CIRCLE_RIGHT \"\\xef\\x8d\\x9a\"\t// U+f35a\n#define ICON_FA_CIRCLE_STOP \"\\xef\\x8a\\x8d\"\t// U+f28d\n#define ICON_FA_CIRCLE_UP \"\\xef\\x8d\\x9b\"\t// U+f35b\n#define ICON_FA_CIRCLE_USER \"\\xef\\x8a\\xbd\"\t// U+f2bd\n#define ICON_FA_CIRCLE_XMARK \"\\xef\\x81\\x97\"\t// U+f057\n#define ICON_FA_CITY \"\\xef\\x99\\x8f\"\t// U+f64f\n#define ICON_FA_CLAPPERBOARD \"\\xee\\x84\\xb1\"\t// U+e131\n#define ICON_FA_CLIPBOARD \"\\xef\\x8c\\xa8\"\t// U+f328\n#define ICON_FA_CLIPBOARD_CHECK \"\\xef\\x91\\xac\"\t// U+f46c\n#define ICON_FA_CLIPBOARD_LIST \"\\xef\\x91\\xad\"\t// U+f46d\n#define ICON_FA_CLIPBOARD_QUESTION \"\\xee\\x93\\xa3\"\t// U+e4e3\n#define ICON_FA_CLIPBOARD_USER \"\\xef\\x9f\\xb3\"\t// U+f7f3\n#define ICON_FA_CLOCK \"\\xef\\x80\\x97\"\t// U+f017\n#define ICON_FA_CLOCK_ROTATE_LEFT \"\\xef\\x87\\x9a\"\t// U+f1da\n#define ICON_FA_CLONE \"\\xef\\x89\\x8d\"\t// U+f24d\n#define ICON_FA_CLOSED_CAPTIONING \"\\xef\\x88\\x8a\"\t// U+f20a\n#define ICON_FA_CLOUD \"\\xef\\x83\\x82\"\t// U+f0c2\n#define ICON_FA_CLOUD_ARROW_DOWN \"\\xef\\x83\\xad\"\t// U+f0ed\n#define ICON_FA_CLOUD_ARROW_UP \"\\xef\\x83\\xae\"\t// U+f0ee\n#define ICON_FA_CLOUD_BOLT \"\\xef\\x9d\\xac\"\t// U+f76c\n#define ICON_FA_CLOUD_MEATBALL \"\\xef\\x9c\\xbb\"\t// U+f73b\n#define ICON_FA_CLOUD_MOON \"\\xef\\x9b\\x83\"\t// U+f6c3\n#define ICON_FA_CLOUD_MOON_RAIN \"\\xef\\x9c\\xbc\"\t// U+f73c\n#define ICON_FA_CLOUD_RAIN \"\\xef\\x9c\\xbd\"\t// U+f73d\n#define ICON_FA_CLOUD_SHOWERS_HEAVY \"\\xef\\x9d\\x80\"\t// U+f740\n#define ICON_FA_CLOUD_SHOWERS_WATER \"\\xee\\x93\\xa4\"\t// U+e4e4\n#define ICON_FA_CLOUD_SUN \"\\xef\\x9b\\x84\"\t// U+f6c4\n#define ICON_FA_CLOUD_SUN_RAIN \"\\xef\\x9d\\x83\"\t// U+f743\n#define ICON_FA_CLOVER \"\\xee\\x84\\xb9\"\t// U+e139\n#define ICON_FA_CODE \"\\xef\\x84\\xa1\"\t// U+f121\n#define ICON_FA_CODE_BRANCH \"\\xef\\x84\\xa6\"\t// U+f126\n#define ICON_FA_CODE_COMMIT \"\\xef\\x8e\\x86\"\t// U+f386\n#define ICON_FA_CODE_COMPARE \"\\xee\\x84\\xba\"\t// U+e13a\n#define ICON_FA_CODE_FORK \"\\xee\\x84\\xbb\"\t// U+e13b\n#define ICON_FA_CODE_MERGE \"\\xef\\x8e\\x87\"\t// U+f387\n#define ICON_FA_CODE_PULL_REQUEST \"\\xee\\x84\\xbc\"\t// U+e13c\n#define ICON_FA_COINS \"\\xef\\x94\\x9e\"\t// U+f51e\n#define ICON_FA_COLON_SIGN \"\\xee\\x85\\x80\"\t// U+e140\n#define ICON_FA_COMMENT \"\\xef\\x81\\xb5\"\t// U+f075\n#define ICON_FA_COMMENT_DOLLAR \"\\xef\\x99\\x91\"\t// U+f651\n#define ICON_FA_COMMENT_DOTS \"\\xef\\x92\\xad\"\t// U+f4ad\n#define ICON_FA_COMMENT_MEDICAL \"\\xef\\x9f\\xb5\"\t// U+f7f5\n#define ICON_FA_COMMENT_SLASH \"\\xef\\x92\\xb3\"\t// U+f4b3\n#define ICON_FA_COMMENT_SMS \"\\xef\\x9f\\x8d\"\t// U+f7cd\n#define ICON_FA_COMMENTS \"\\xef\\x82\\x86\"\t// U+f086\n#define ICON_FA_COMMENTS_DOLLAR \"\\xef\\x99\\x93\"\t// U+f653\n#define ICON_FA_COMPACT_DISC \"\\xef\\x94\\x9f\"\t// U+f51f\n#define ICON_FA_COMPASS \"\\xef\\x85\\x8e\"\t// U+f14e\n#define ICON_FA_COMPASS_DRAFTING \"\\xef\\x95\\xa8\"\t// U+f568\n#define ICON_FA_COMPRESS \"\\xef\\x81\\xa6\"\t// U+f066\n#define ICON_FA_COMPUTER \"\\xee\\x93\\xa5\"\t// U+e4e5\n#define ICON_FA_COMPUTER_MOUSE \"\\xef\\xa3\\x8c\"\t// U+f8cc\n#define ICON_FA_COOKIE \"\\xef\\x95\\xa3\"\t// U+f563\n#define ICON_FA_COOKIE_BITE \"\\xef\\x95\\xa4\"\t// U+f564\n#define ICON_FA_COPY \"\\xef\\x83\\x85\"\t// U+f0c5\n#define ICON_FA_COPYRIGHT \"\\xef\\x87\\xb9\"\t// U+f1f9\n#define ICON_FA_COUCH \"\\xef\\x92\\xb8\"\t// U+f4b8\n#define ICON_FA_COW \"\\xef\\x9b\\x88\"\t// U+f6c8\n#define ICON_FA_CREDIT_CARD \"\\xef\\x82\\x9d\"\t// U+f09d\n#define ICON_FA_CROP \"\\xef\\x84\\xa5\"\t// U+f125\n#define ICON_FA_CROP_SIMPLE \"\\xef\\x95\\xa5\"\t// U+f565\n#define ICON_FA_CROSS \"\\xef\\x99\\x94\"\t// U+f654\n#define ICON_FA_CROSSHAIRS \"\\xef\\x81\\x9b\"\t// U+f05b\n#define ICON_FA_CROW \"\\xef\\x94\\xa0\"\t// U+f520\n#define ICON_FA_CROWN \"\\xef\\x94\\xa1\"\t// U+f521\n#define ICON_FA_CRUTCH \"\\xef\\x9f\\xb7\"\t// U+f7f7\n#define ICON_FA_CRUZEIRO_SIGN \"\\xee\\x85\\x92\"\t// U+e152\n#define ICON_FA_CUBE \"\\xef\\x86\\xb2\"\t// U+f1b2\n#define ICON_FA_CUBES \"\\xef\\x86\\xb3\"\t// U+f1b3\n#define ICON_FA_CUBES_STACKED \"\\xee\\x93\\xa6\"\t// U+e4e6\n#define ICON_FA_D \"D\"\t// U+0044\n#define ICON_FA_DATABASE \"\\xef\\x87\\x80\"\t// U+f1c0\n#define ICON_FA_DELETE_LEFT \"\\xef\\x95\\x9a\"\t// U+f55a\n#define ICON_FA_DEMOCRAT \"\\xef\\x9d\\x87\"\t// U+f747\n#define ICON_FA_DESKTOP \"\\xef\\x8e\\x90\"\t// U+f390\n#define ICON_FA_DHARMACHAKRA \"\\xef\\x99\\x95\"\t// U+f655\n#define ICON_FA_DIAGRAM_NEXT \"\\xee\\x91\\xb6\"\t// U+e476\n#define ICON_FA_DIAGRAM_PREDECESSOR \"\\xee\\x91\\xb7\"\t// U+e477\n#define ICON_FA_DIAGRAM_PROJECT \"\\xef\\x95\\x82\"\t// U+f542\n#define ICON_FA_DIAGRAM_SUCCESSOR \"\\xee\\x91\\xba\"\t// U+e47a\n#define ICON_FA_DIAMOND \"\\xef\\x88\\x99\"\t// U+f219\n#define ICON_FA_DIAMOND_TURN_RIGHT \"\\xef\\x97\\xab\"\t// U+f5eb\n#define ICON_FA_DICE \"\\xef\\x94\\xa2\"\t// U+f522\n#define ICON_FA_DICE_D20 \"\\xef\\x9b\\x8f\"\t// U+f6cf\n#define ICON_FA_DICE_D6 \"\\xef\\x9b\\x91\"\t// U+f6d1\n#define ICON_FA_DICE_FIVE \"\\xef\\x94\\xa3\"\t// U+f523\n#define ICON_FA_DICE_FOUR \"\\xef\\x94\\xa4\"\t// U+f524\n#define ICON_FA_DICE_ONE \"\\xef\\x94\\xa5\"\t// U+f525\n#define ICON_FA_DICE_SIX \"\\xef\\x94\\xa6\"\t// U+f526\n#define ICON_FA_DICE_THREE \"\\xef\\x94\\xa7\"\t// U+f527\n#define ICON_FA_DICE_TWO \"\\xef\\x94\\xa8\"\t// U+f528\n#define ICON_FA_DISEASE \"\\xef\\x9f\\xba\"\t// U+f7fa\n#define ICON_FA_DISPLAY \"\\xee\\x85\\xa3\"\t// U+e163\n#define ICON_FA_DIVIDE \"\\xef\\x94\\xa9\"\t// U+f529\n#define ICON_FA_DNA \"\\xef\\x91\\xb1\"\t// U+f471\n#define ICON_FA_DOG \"\\xef\\x9b\\x93\"\t// U+f6d3\n#define ICON_FA_DOLLAR_SIGN \"$\"\t// U+0024\n#define ICON_FA_DOLLY \"\\xef\\x91\\xb2\"\t// U+f472\n#define ICON_FA_DONG_SIGN \"\\xee\\x85\\xa9\"\t// U+e169\n#define ICON_FA_DOOR_CLOSED \"\\xef\\x94\\xaa\"\t// U+f52a\n#define ICON_FA_DOOR_OPEN \"\\xef\\x94\\xab\"\t// U+f52b\n#define ICON_FA_DOVE \"\\xef\\x92\\xba\"\t// U+f4ba\n#define ICON_FA_DOWN_LEFT_AND_UP_RIGHT_TO_CENTER \"\\xef\\x90\\xa2\"\t// U+f422\n#define ICON_FA_DOWN_LONG \"\\xef\\x8c\\x89\"\t// U+f309\n#define ICON_FA_DOWNLOAD \"\\xef\\x80\\x99\"\t// U+f019\n#define ICON_FA_DRAGON \"\\xef\\x9b\\x95\"\t// U+f6d5\n#define ICON_FA_DRAW_POLYGON \"\\xef\\x97\\xae\"\t// U+f5ee\n#define ICON_FA_DROPLET \"\\xef\\x81\\x83\"\t// U+f043\n#define ICON_FA_DROPLET_SLASH \"\\xef\\x97\\x87\"\t// U+f5c7\n#define ICON_FA_DRUM \"\\xef\\x95\\xa9\"\t// U+f569\n#define ICON_FA_DRUM_STEELPAN \"\\xef\\x95\\xaa\"\t// U+f56a\n#define ICON_FA_DRUMSTICK_BITE \"\\xef\\x9b\\x97\"\t// U+f6d7\n#define ICON_FA_DUMBBELL \"\\xef\\x91\\x8b\"\t// U+f44b\n#define ICON_FA_DUMPSTER \"\\xef\\x9e\\x93\"\t// U+f793\n#define ICON_FA_DUMPSTER_FIRE \"\\xef\\x9e\\x94\"\t// U+f794\n#define ICON_FA_DUNGEON \"\\xef\\x9b\\x99\"\t// U+f6d9\n#define ICON_FA_E \"E\"\t// U+0045\n#define ICON_FA_EAR_DEAF \"\\xef\\x8a\\xa4\"\t// U+f2a4\n#define ICON_FA_EAR_LISTEN \"\\xef\\x8a\\xa2\"\t// U+f2a2\n#define ICON_FA_EARTH_AFRICA \"\\xef\\x95\\xbc\"\t// U+f57c\n#define ICON_FA_EARTH_AMERICAS \"\\xef\\x95\\xbd\"\t// U+f57d\n#define ICON_FA_EARTH_ASIA \"\\xef\\x95\\xbe\"\t// U+f57e\n#define ICON_FA_EARTH_EUROPE \"\\xef\\x9e\\xa2\"\t// U+f7a2\n#define ICON_FA_EARTH_OCEANIA \"\\xee\\x91\\xbb\"\t// U+e47b\n#define ICON_FA_EGG \"\\xef\\x9f\\xbb\"\t// U+f7fb\n#define ICON_FA_EJECT \"\\xef\\x81\\x92\"\t// U+f052\n#define ICON_FA_ELEVATOR \"\\xee\\x85\\xad\"\t// U+e16d\n#define ICON_FA_ELLIPSIS \"\\xef\\x85\\x81\"\t// U+f141\n#define ICON_FA_ELLIPSIS_VERTICAL \"\\xef\\x85\\x82\"\t// U+f142\n#define ICON_FA_ENVELOPE \"\\xef\\x83\\xa0\"\t// U+f0e0\n#define ICON_FA_ENVELOPE_CIRCLE_CHECK \"\\xee\\x93\\xa8\"\t// U+e4e8\n#define ICON_FA_ENVELOPE_OPEN \"\\xef\\x8a\\xb6\"\t// U+f2b6\n#define ICON_FA_ENVELOPE_OPEN_TEXT \"\\xef\\x99\\x98\"\t// U+f658\n#define ICON_FA_ENVELOPES_BULK \"\\xef\\x99\\xb4\"\t// U+f674\n#define ICON_FA_EQUALS \"=\"\t// U+003d\n#define ICON_FA_ERASER \"\\xef\\x84\\xad\"\t// U+f12d\n#define ICON_FA_ETHERNET \"\\xef\\x9e\\x96\"\t// U+f796\n#define ICON_FA_EURO_SIGN \"\\xef\\x85\\x93\"\t// U+f153\n#define ICON_FA_EXCLAMATION \"!\"\t// U+0021\n#define ICON_FA_EXPAND \"\\xef\\x81\\xa5\"\t// U+f065\n#define ICON_FA_EXPLOSION \"\\xee\\x93\\xa9\"\t// U+e4e9\n#define ICON_FA_EYE \"\\xef\\x81\\xae\"\t// U+f06e\n#define ICON_FA_EYE_DROPPER \"\\xef\\x87\\xbb\"\t// U+f1fb\n#define ICON_FA_EYE_LOW_VISION \"\\xef\\x8a\\xa8\"\t// U+f2a8\n#define ICON_FA_EYE_SLASH \"\\xef\\x81\\xb0\"\t// U+f070\n#define ICON_FA_F \"F\"\t// U+0046\n#define ICON_FA_FACE_ANGRY \"\\xef\\x95\\x96\"\t// U+f556\n#define ICON_FA_FACE_DIZZY \"\\xef\\x95\\xa7\"\t// U+f567\n#define ICON_FA_FACE_FLUSHED \"\\xef\\x95\\xb9\"\t// U+f579\n#define ICON_FA_FACE_FROWN \"\\xef\\x84\\x99\"\t// U+f119\n#define ICON_FA_FACE_FROWN_OPEN \"\\xef\\x95\\xba\"\t// U+f57a\n#define ICON_FA_FACE_GRIMACE \"\\xef\\x95\\xbf\"\t// U+f57f\n#define ICON_FA_FACE_GRIN \"\\xef\\x96\\x80\"\t// U+f580\n#define ICON_FA_FACE_GRIN_BEAM \"\\xef\\x96\\x82\"\t// U+f582\n#define ICON_FA_FACE_GRIN_BEAM_SWEAT \"\\xef\\x96\\x83\"\t// U+f583\n#define ICON_FA_FACE_GRIN_HEARTS \"\\xef\\x96\\x84\"\t// U+f584\n#define ICON_FA_FACE_GRIN_SQUINT \"\\xef\\x96\\x85\"\t// U+f585\n#define ICON_FA_FACE_GRIN_SQUINT_TEARS \"\\xef\\x96\\x86\"\t// U+f586\n#define ICON_FA_FACE_GRIN_STARS \"\\xef\\x96\\x87\"\t// U+f587\n#define ICON_FA_FACE_GRIN_TEARS \"\\xef\\x96\\x88\"\t// U+f588\n#define ICON_FA_FACE_GRIN_TONGUE \"\\xef\\x96\\x89\"\t// U+f589\n#define ICON_FA_FACE_GRIN_TONGUE_SQUINT \"\\xef\\x96\\x8a\"\t// U+f58a\n#define ICON_FA_FACE_GRIN_TONGUE_WINK \"\\xef\\x96\\x8b\"\t// U+f58b\n#define ICON_FA_FACE_GRIN_WIDE \"\\xef\\x96\\x81\"\t// U+f581\n#define ICON_FA_FACE_GRIN_WINK \"\\xef\\x96\\x8c\"\t// U+f58c\n#define ICON_FA_FACE_KISS \"\\xef\\x96\\x96\"\t// U+f596\n#define ICON_FA_FACE_KISS_BEAM \"\\xef\\x96\\x97\"\t// U+f597\n#define ICON_FA_FACE_KISS_WINK_HEART \"\\xef\\x96\\x98\"\t// U+f598\n#define ICON_FA_FACE_LAUGH \"\\xef\\x96\\x99\"\t// U+f599\n#define ICON_FA_FACE_LAUGH_BEAM \"\\xef\\x96\\x9a\"\t// U+f59a\n#define ICON_FA_FACE_LAUGH_SQUINT \"\\xef\\x96\\x9b\"\t// U+f59b\n#define ICON_FA_FACE_LAUGH_WINK \"\\xef\\x96\\x9c\"\t// U+f59c\n#define ICON_FA_FACE_MEH \"\\xef\\x84\\x9a\"\t// U+f11a\n#define ICON_FA_FACE_MEH_BLANK \"\\xef\\x96\\xa4\"\t// U+f5a4\n#define ICON_FA_FACE_ROLLING_EYES \"\\xef\\x96\\xa5\"\t// U+f5a5\n#define ICON_FA_FACE_SAD_CRY \"\\xef\\x96\\xb3\"\t// U+f5b3\n#define ICON_FA_FACE_SAD_TEAR \"\\xef\\x96\\xb4\"\t// U+f5b4\n#define ICON_FA_FACE_SMILE \"\\xef\\x84\\x98\"\t// U+f118\n#define ICON_FA_FACE_SMILE_BEAM \"\\xef\\x96\\xb8\"\t// U+f5b8\n#define ICON_FA_FACE_SMILE_WINK \"\\xef\\x93\\x9a\"\t// U+f4da\n#define ICON_FA_FACE_SURPRISE \"\\xef\\x97\\x82\"\t// U+f5c2\n#define ICON_FA_FACE_TIRED \"\\xef\\x97\\x88\"\t// U+f5c8\n#define ICON_FA_FAN \"\\xef\\xa1\\xa3\"\t// U+f863\n#define ICON_FA_FAUCET \"\\xee\\x80\\x85\"\t// U+e005\n#define ICON_FA_FAUCET_DRIP \"\\xee\\x80\\x86\"\t// U+e006\n#define ICON_FA_FAX \"\\xef\\x86\\xac\"\t// U+f1ac\n#define ICON_FA_FEATHER \"\\xef\\x94\\xad\"\t// U+f52d\n#define ICON_FA_FEATHER_POINTED \"\\xef\\x95\\xab\"\t// U+f56b\n#define ICON_FA_FERRY \"\\xee\\x93\\xaa\"\t// U+e4ea\n#define ICON_FA_FILE \"\\xef\\x85\\x9b\"\t// U+f15b\n#define ICON_FA_FILE_ARROW_DOWN \"\\xef\\x95\\xad\"\t// U+f56d\n#define ICON_FA_FILE_ARROW_UP \"\\xef\\x95\\xb4\"\t// U+f574\n#define ICON_FA_FILE_AUDIO \"\\xef\\x87\\x87\"\t// U+f1c7\n#define ICON_FA_FILE_CIRCLE_CHECK \"\\xee\\x96\\xa0\"\t// U+e5a0\n#define ICON_FA_FILE_CIRCLE_EXCLAMATION \"\\xee\\x93\\xab\"\t// U+e4eb\n#define ICON_FA_FILE_CIRCLE_MINUS \"\\xee\\x93\\xad\"\t// U+e4ed\n#define ICON_FA_FILE_CIRCLE_PLUS \"\\xee\\x92\\x94\"\t// U+e494\n#define ICON_FA_FILE_CIRCLE_QUESTION \"\\xee\\x93\\xaf\"\t// U+e4ef\n#define ICON_FA_FILE_CIRCLE_XMARK \"\\xee\\x96\\xa1\"\t// U+e5a1\n#define ICON_FA_FILE_CODE \"\\xef\\x87\\x89\"\t// U+f1c9\n#define ICON_FA_FILE_CONTRACT \"\\xef\\x95\\xac\"\t// U+f56c\n#define ICON_FA_FILE_CSV \"\\xef\\x9b\\x9d\"\t// U+f6dd\n#define ICON_FA_FILE_EXCEL \"\\xef\\x87\\x83\"\t// U+f1c3\n#define ICON_FA_FILE_EXPORT \"\\xef\\x95\\xae\"\t// U+f56e\n#define ICON_FA_FILE_IMAGE \"\\xef\\x87\\x85\"\t// U+f1c5\n#define ICON_FA_FILE_IMPORT \"\\xef\\x95\\xaf\"\t// U+f56f\n#define ICON_FA_FILE_INVOICE \"\\xef\\x95\\xb0\"\t// U+f570\n#define ICON_FA_FILE_INVOICE_DOLLAR \"\\xef\\x95\\xb1\"\t// U+f571\n#define ICON_FA_FILE_LINES \"\\xef\\x85\\x9c\"\t// U+f15c\n#define ICON_FA_FILE_MEDICAL \"\\xef\\x91\\xb7\"\t// U+f477\n#define ICON_FA_FILE_PDF \"\\xef\\x87\\x81\"\t// U+f1c1\n#define ICON_FA_FILE_PEN \"\\xef\\x8c\\x9c\"\t// U+f31c\n#define ICON_FA_FILE_POWERPOINT \"\\xef\\x87\\x84\"\t// U+f1c4\n#define ICON_FA_FILE_PRESCRIPTION \"\\xef\\x95\\xb2\"\t// U+f572\n#define ICON_FA_FILE_SHIELD \"\\xee\\x93\\xb0\"\t// U+e4f0\n#define ICON_FA_FILE_SIGNATURE \"\\xef\\x95\\xb3\"\t// U+f573\n#define ICON_FA_FILE_VIDEO \"\\xef\\x87\\x88\"\t// U+f1c8\n#define ICON_FA_FILE_WAVEFORM \"\\xef\\x91\\xb8\"\t// U+f478\n#define ICON_FA_FILE_WORD \"\\xef\\x87\\x82\"\t// U+f1c2\n#define ICON_FA_FILE_ZIPPER \"\\xef\\x87\\x86\"\t// U+f1c6\n#define ICON_FA_FILL \"\\xef\\x95\\xb5\"\t// U+f575\n#define ICON_FA_FILL_DRIP \"\\xef\\x95\\xb6\"\t// U+f576\n#define ICON_FA_FILM \"\\xef\\x80\\x88\"\t// U+f008\n#define ICON_FA_FILTER \"\\xef\\x82\\xb0\"\t// U+f0b0\n#define ICON_FA_FILTER_CIRCLE_DOLLAR \"\\xef\\x99\\xa2\"\t// U+f662\n#define ICON_FA_FILTER_CIRCLE_XMARK \"\\xee\\x85\\xbb\"\t// U+e17b\n#define ICON_FA_FINGERPRINT \"\\xef\\x95\\xb7\"\t// U+f577\n#define ICON_FA_FIRE \"\\xef\\x81\\xad\"\t// U+f06d\n#define ICON_FA_FIRE_BURNER \"\\xee\\x93\\xb1\"\t// U+e4f1\n#define ICON_FA_FIRE_EXTINGUISHER \"\\xef\\x84\\xb4\"\t// U+f134\n#define ICON_FA_FIRE_FLAME_CURVED \"\\xef\\x9f\\xa4\"\t// U+f7e4\n#define ICON_FA_FIRE_FLAME_SIMPLE \"\\xef\\x91\\xaa\"\t// U+f46a\n#define ICON_FA_FISH \"\\xef\\x95\\xb8\"\t// U+f578\n#define ICON_FA_FISH_FINS \"\\xee\\x93\\xb2\"\t// U+e4f2\n#define ICON_FA_FLAG \"\\xef\\x80\\xa4\"\t// U+f024\n#define ICON_FA_FLAG_CHECKERED \"\\xef\\x84\\x9e\"\t// U+f11e\n#define ICON_FA_FLAG_USA \"\\xef\\x9d\\x8d\"\t// U+f74d\n#define ICON_FA_FLASK \"\\xef\\x83\\x83\"\t// U+f0c3\n#define ICON_FA_FLASK_VIAL \"\\xee\\x93\\xb3\"\t// U+e4f3\n#define ICON_FA_FLOPPY_DISK \"\\xef\\x83\\x87\"\t// U+f0c7\n#define ICON_FA_FLORIN_SIGN \"\\xee\\x86\\x84\"\t// U+e184\n#define ICON_FA_FOLDER \"\\xef\\x81\\xbb\"\t// U+f07b\n#define ICON_FA_FOLDER_CLOSED \"\\xee\\x86\\x85\"\t// U+e185\n#define ICON_FA_FOLDER_MINUS \"\\xef\\x99\\x9d\"\t// U+f65d\n#define ICON_FA_FOLDER_OPEN \"\\xef\\x81\\xbc\"\t// U+f07c\n#define ICON_FA_FOLDER_PLUS \"\\xef\\x99\\x9e\"\t// U+f65e\n#define ICON_FA_FOLDER_TREE \"\\xef\\xa0\\x82\"\t// U+f802\n#define ICON_FA_FONT \"\\xef\\x80\\xb1\"\t// U+f031\n#define ICON_FA_FONT_AWESOME \"\\xef\\x8a\\xb4\"\t// U+f2b4\n#define ICON_FA_FOOTBALL \"\\xef\\x91\\x8e\"\t// U+f44e\n#define ICON_FA_FORWARD \"\\xef\\x81\\x8e\"\t// U+f04e\n#define ICON_FA_FORWARD_FAST \"\\xef\\x81\\x90\"\t// U+f050\n#define ICON_FA_FORWARD_STEP \"\\xef\\x81\\x91\"\t// U+f051\n#define ICON_FA_FRANC_SIGN \"\\xee\\x86\\x8f\"\t// U+e18f\n#define ICON_FA_FROG \"\\xef\\x94\\xae\"\t// U+f52e\n#define ICON_FA_FUTBOL \"\\xef\\x87\\xa3\"\t// U+f1e3\n#define ICON_FA_G \"G\"\t// U+0047\n#define ICON_FA_GAMEPAD \"\\xef\\x84\\x9b\"\t// U+f11b\n#define ICON_FA_GAS_PUMP \"\\xef\\x94\\xaf\"\t// U+f52f\n#define ICON_FA_GAUGE \"\\xef\\x98\\xa4\"\t// U+f624\n#define ICON_FA_GAUGE_HIGH \"\\xef\\x98\\xa5\"\t// U+f625\n#define ICON_FA_GAUGE_SIMPLE \"\\xef\\x98\\xa9\"\t// U+f629\n#define ICON_FA_GAUGE_SIMPLE_HIGH \"\\xef\\x98\\xaa\"\t// U+f62a\n#define ICON_FA_GAVEL \"\\xef\\x83\\xa3\"\t// U+f0e3\n#define ICON_FA_GEAR \"\\xef\\x80\\x93\"\t// U+f013\n#define ICON_FA_GEARS \"\\xef\\x82\\x85\"\t// U+f085\n#define ICON_FA_GEM \"\\xef\\x8e\\xa5\"\t// U+f3a5\n#define ICON_FA_GENDERLESS \"\\xef\\x88\\xad\"\t// U+f22d\n#define ICON_FA_GHOST \"\\xef\\x9b\\xa2\"\t// U+f6e2\n#define ICON_FA_GIFT \"\\xef\\x81\\xab\"\t// U+f06b\n#define ICON_FA_GIFTS \"\\xef\\x9e\\x9c\"\t// U+f79c\n#define ICON_FA_GLASS_WATER \"\\xee\\x93\\xb4\"\t// U+e4f4\n#define ICON_FA_GLASS_WATER_DROPLET \"\\xee\\x93\\xb5\"\t// U+e4f5\n#define ICON_FA_GLASSES \"\\xef\\x94\\xb0\"\t// U+f530\n#define ICON_FA_GLOBE \"\\xef\\x82\\xac\"\t// U+f0ac\n#define ICON_FA_GOLF_BALL_TEE \"\\xef\\x91\\x90\"\t// U+f450\n#define ICON_FA_GOPURAM \"\\xef\\x99\\xa4\"\t// U+f664\n#define ICON_FA_GRADUATION_CAP \"\\xef\\x86\\x9d\"\t// U+f19d\n#define ICON_FA_GREATER_THAN \">\"\t// U+003e\n#define ICON_FA_GREATER_THAN_EQUAL \"\\xef\\x94\\xb2\"\t// U+f532\n#define ICON_FA_GRIP \"\\xef\\x96\\x8d\"\t// U+f58d\n#define ICON_FA_GRIP_LINES \"\\xef\\x9e\\xa4\"\t// U+f7a4\n#define ICON_FA_GRIP_LINES_VERTICAL \"\\xef\\x9e\\xa5\"\t// U+f7a5\n#define ICON_FA_GRIP_VERTICAL \"\\xef\\x96\\x8e\"\t// U+f58e\n#define ICON_FA_GROUP_ARROWS_ROTATE \"\\xee\\x93\\xb6\"\t// U+e4f6\n#define ICON_FA_GUARANI_SIGN \"\\xee\\x86\\x9a\"\t// U+e19a\n#define ICON_FA_GUITAR \"\\xef\\x9e\\xa6\"\t// U+f7a6\n#define ICON_FA_GUN \"\\xee\\x86\\x9b\"\t// U+e19b\n#define ICON_FA_H \"H\"\t// U+0048\n#define ICON_FA_HAMMER \"\\xef\\x9b\\xa3\"\t// U+f6e3\n#define ICON_FA_HAMSA \"\\xef\\x99\\xa5\"\t// U+f665\n#define ICON_FA_HAND \"\\xef\\x89\\x96\"\t// U+f256\n#define ICON_FA_HAND_BACK_FIST \"\\xef\\x89\\x95\"\t// U+f255\n#define ICON_FA_HAND_DOTS \"\\xef\\x91\\xa1\"\t// U+f461\n#define ICON_FA_HAND_FIST \"\\xef\\x9b\\x9e\"\t// U+f6de\n#define ICON_FA_HAND_HOLDING \"\\xef\\x92\\xbd\"\t// U+f4bd\n#define ICON_FA_HAND_HOLDING_DOLLAR \"\\xef\\x93\\x80\"\t// U+f4c0\n#define ICON_FA_HAND_HOLDING_DROPLET \"\\xef\\x93\\x81\"\t// U+f4c1\n#define ICON_FA_HAND_HOLDING_HAND \"\\xee\\x93\\xb7\"\t// U+e4f7\n#define ICON_FA_HAND_HOLDING_HEART \"\\xef\\x92\\xbe\"\t// U+f4be\n#define ICON_FA_HAND_HOLDING_MEDICAL \"\\xee\\x81\\x9c\"\t// U+e05c\n#define ICON_FA_HAND_LIZARD \"\\xef\\x89\\x98\"\t// U+f258\n#define ICON_FA_HAND_MIDDLE_FINGER \"\\xef\\xa0\\x86\"\t// U+f806\n#define ICON_FA_HAND_PEACE \"\\xef\\x89\\x9b\"\t// U+f25b\n#define ICON_FA_HAND_POINT_DOWN \"\\xef\\x82\\xa7\"\t// U+f0a7\n#define ICON_FA_HAND_POINT_LEFT \"\\xef\\x82\\xa5\"\t// U+f0a5\n#define ICON_FA_HAND_POINT_RIGHT \"\\xef\\x82\\xa4\"\t// U+f0a4\n#define ICON_FA_HAND_POINT_UP \"\\xef\\x82\\xa6\"\t// U+f0a6\n#define ICON_FA_HAND_POINTER \"\\xef\\x89\\x9a\"\t// U+f25a\n#define ICON_FA_HAND_SCISSORS \"\\xef\\x89\\x97\"\t// U+f257\n#define ICON_FA_HAND_SPARKLES \"\\xee\\x81\\x9d\"\t// U+e05d\n#define ICON_FA_HAND_SPOCK \"\\xef\\x89\\x99\"\t// U+f259\n#define ICON_FA_HANDCUFFS \"\\xee\\x93\\xb8\"\t// U+e4f8\n#define ICON_FA_HANDS \"\\xef\\x8a\\xa7\"\t// U+f2a7\n#define ICON_FA_HANDS_ASL_INTERPRETING \"\\xef\\x8a\\xa3\"\t// U+f2a3\n#define ICON_FA_HANDS_BOUND \"\\xee\\x93\\xb9\"\t// U+e4f9\n#define ICON_FA_HANDS_BUBBLES \"\\xee\\x81\\x9e\"\t// U+e05e\n#define ICON_FA_HANDS_CLAPPING \"\\xee\\x86\\xa8\"\t// U+e1a8\n#define ICON_FA_HANDS_HOLDING \"\\xef\\x93\\x82\"\t// U+f4c2\n#define ICON_FA_HANDS_HOLDING_CHILD \"\\xee\\x93\\xba\"\t// U+e4fa\n#define ICON_FA_HANDS_HOLDING_CIRCLE \"\\xee\\x93\\xbb\"\t// U+e4fb\n#define ICON_FA_HANDS_PRAYING \"\\xef\\x9a\\x84\"\t// U+f684\n#define ICON_FA_HANDSHAKE \"\\xef\\x8a\\xb5\"\t// U+f2b5\n#define ICON_FA_HANDSHAKE_ANGLE \"\\xef\\x93\\x84\"\t// U+f4c4\n#define ICON_FA_HANDSHAKE_SIMPLE \"\\xef\\x93\\x86\"\t// U+f4c6\n#define ICON_FA_HANDSHAKE_SIMPLE_SLASH \"\\xee\\x81\\x9f\"\t// U+e05f\n#define ICON_FA_HANDSHAKE_SLASH \"\\xee\\x81\\xa0\"\t// U+e060\n#define ICON_FA_HANUKIAH \"\\xef\\x9b\\xa6\"\t// U+f6e6\n#define ICON_FA_HARD_DRIVE \"\\xef\\x82\\xa0\"\t// U+f0a0\n#define ICON_FA_HASHTAG \"#\"\t// U+0023\n#define ICON_FA_HAT_COWBOY \"\\xef\\xa3\\x80\"\t// U+f8c0\n#define ICON_FA_HAT_COWBOY_SIDE \"\\xef\\xa3\\x81\"\t// U+f8c1\n#define ICON_FA_HAT_WIZARD \"\\xef\\x9b\\xa8\"\t// U+f6e8\n#define ICON_FA_HEAD_SIDE_COUGH \"\\xee\\x81\\xa1\"\t// U+e061\n#define ICON_FA_HEAD_SIDE_COUGH_SLASH \"\\xee\\x81\\xa2\"\t// U+e062\n#define ICON_FA_HEAD_SIDE_MASK \"\\xee\\x81\\xa3\"\t// U+e063\n#define ICON_FA_HEAD_SIDE_VIRUS \"\\xee\\x81\\xa4\"\t// U+e064\n#define ICON_FA_HEADING \"\\xef\\x87\\x9c\"\t// U+f1dc\n#define ICON_FA_HEADPHONES \"\\xef\\x80\\xa5\"\t// U+f025\n#define ICON_FA_HEADPHONES_SIMPLE \"\\xef\\x96\\x8f\"\t// U+f58f\n#define ICON_FA_HEADSET \"\\xef\\x96\\x90\"\t// U+f590\n#define ICON_FA_HEART \"\\xef\\x80\\x84\"\t// U+f004\n#define ICON_FA_HEART_CIRCLE_BOLT \"\\xee\\x93\\xbc\"\t// U+e4fc\n#define ICON_FA_HEART_CIRCLE_CHECK \"\\xee\\x93\\xbd\"\t// U+e4fd\n#define ICON_FA_HEART_CIRCLE_EXCLAMATION \"\\xee\\x93\\xbe\"\t// U+e4fe\n#define ICON_FA_HEART_CIRCLE_MINUS \"\\xee\\x93\\xbf\"\t// U+e4ff\n#define ICON_FA_HEART_CIRCLE_PLUS \"\\xee\\x94\\x80\"\t// U+e500\n#define ICON_FA_HEART_CIRCLE_XMARK \"\\xee\\x94\\x81\"\t// U+e501\n#define ICON_FA_HEART_CRACK \"\\xef\\x9e\\xa9\"\t// U+f7a9\n#define ICON_FA_HEART_PULSE \"\\xef\\x88\\x9e\"\t// U+f21e\n#define ICON_FA_HELICOPTER \"\\xef\\x94\\xb3\"\t// U+f533\n#define ICON_FA_HELICOPTER_SYMBOL \"\\xee\\x94\\x82\"\t// U+e502\n#define ICON_FA_HELMET_SAFETY \"\\xef\\xa0\\x87\"\t// U+f807\n#define ICON_FA_HELMET_UN \"\\xee\\x94\\x83\"\t// U+e503\n#define ICON_FA_HIGHLIGHTER \"\\xef\\x96\\x91\"\t// U+f591\n#define ICON_FA_HILL_AVALANCHE \"\\xee\\x94\\x87\"\t// U+e507\n#define ICON_FA_HILL_ROCKSLIDE \"\\xee\\x94\\x88\"\t// U+e508\n#define ICON_FA_HIPPO \"\\xef\\x9b\\xad\"\t// U+f6ed\n#define ICON_FA_HOCKEY_PUCK \"\\xef\\x91\\x93\"\t// U+f453\n#define ICON_FA_HOLLY_BERRY \"\\xef\\x9e\\xaa\"\t// U+f7aa\n#define ICON_FA_HORSE \"\\xef\\x9b\\xb0\"\t// U+f6f0\n#define ICON_FA_HORSE_HEAD \"\\xef\\x9e\\xab\"\t// U+f7ab\n#define ICON_FA_HOSPITAL \"\\xef\\x83\\xb8\"\t// U+f0f8\n#define ICON_FA_HOSPITAL_USER \"\\xef\\xa0\\x8d\"\t// U+f80d\n#define ICON_FA_HOT_TUB_PERSON \"\\xef\\x96\\x93\"\t// U+f593\n#define ICON_FA_HOTDOG \"\\xef\\xa0\\x8f\"\t// U+f80f\n#define ICON_FA_HOTEL \"\\xef\\x96\\x94\"\t// U+f594\n#define ICON_FA_HOURGLASS \"\\xef\\x89\\x94\"\t// U+f254\n#define ICON_FA_HOURGLASS_END \"\\xef\\x89\\x93\"\t// U+f253\n#define ICON_FA_HOURGLASS_HALF \"\\xef\\x89\\x92\"\t// U+f252\n#define ICON_FA_HOURGLASS_START \"\\xef\\x89\\x91\"\t// U+f251\n#define ICON_FA_HOUSE \"\\xef\\x80\\x95\"\t// U+f015\n#define ICON_FA_HOUSE_CHIMNEY \"\\xee\\x8e\\xaf\"\t// U+e3af\n#define ICON_FA_HOUSE_CHIMNEY_CRACK \"\\xef\\x9b\\xb1\"\t// U+f6f1\n#define ICON_FA_HOUSE_CHIMNEY_MEDICAL \"\\xef\\x9f\\xb2\"\t// U+f7f2\n#define ICON_FA_HOUSE_CHIMNEY_USER \"\\xee\\x81\\xa5\"\t// U+e065\n#define ICON_FA_HOUSE_CHIMNEY_WINDOW \"\\xee\\x80\\x8d\"\t// U+e00d\n#define ICON_FA_HOUSE_CIRCLE_CHECK \"\\xee\\x94\\x89\"\t// U+e509\n#define ICON_FA_HOUSE_CIRCLE_EXCLAMATION \"\\xee\\x94\\x8a\"\t// U+e50a\n#define ICON_FA_HOUSE_CIRCLE_XMARK \"\\xee\\x94\\x8b\"\t// U+e50b\n#define ICON_FA_HOUSE_CRACK \"\\xee\\x8e\\xb1\"\t// U+e3b1\n#define ICON_FA_HOUSE_FIRE \"\\xee\\x94\\x8c\"\t// U+e50c\n#define ICON_FA_HOUSE_FLAG \"\\xee\\x94\\x8d\"\t// U+e50d\n#define ICON_FA_HOUSE_FLOOD_WATER \"\\xee\\x94\\x8e\"\t// U+e50e\n#define ICON_FA_HOUSE_FLOOD_WATER_CIRCLE_ARROW_RIGHT \"\\xee\\x94\\x8f\"\t// U+e50f\n#define ICON_FA_HOUSE_LAPTOP \"\\xee\\x81\\xa6\"\t// U+e066\n#define ICON_FA_HOUSE_LOCK \"\\xee\\x94\\x90\"\t// U+e510\n#define ICON_FA_HOUSE_MEDICAL \"\\xee\\x8e\\xb2\"\t// U+e3b2\n#define ICON_FA_HOUSE_MEDICAL_CIRCLE_CHECK \"\\xee\\x94\\x91\"\t// U+e511\n#define ICON_FA_HOUSE_MEDICAL_CIRCLE_EXCLAMATION \"\\xee\\x94\\x92\"\t// U+e512\n#define ICON_FA_HOUSE_MEDICAL_CIRCLE_XMARK \"\\xee\\x94\\x93\"\t// U+e513\n#define ICON_FA_HOUSE_MEDICAL_FLAG \"\\xee\\x94\\x94\"\t// U+e514\n#define ICON_FA_HOUSE_SIGNAL \"\\xee\\x80\\x92\"\t// U+e012\n#define ICON_FA_HOUSE_TSUNAMI \"\\xee\\x94\\x95\"\t// U+e515\n#define ICON_FA_HOUSE_USER \"\\xee\\x86\\xb0\"\t// U+e1b0\n#define ICON_FA_HRYVNIA_SIGN \"\\xef\\x9b\\xb2\"\t// U+f6f2\n#define ICON_FA_HURRICANE \"\\xef\\x9d\\x91\"\t// U+f751\n#define ICON_FA_I \"I\"\t// U+0049\n#define ICON_FA_I_CURSOR \"\\xef\\x89\\x86\"\t// U+f246\n#define ICON_FA_ICE_CREAM \"\\xef\\xa0\\x90\"\t// U+f810\n#define ICON_FA_ICICLES \"\\xef\\x9e\\xad\"\t// U+f7ad\n#define ICON_FA_ICONS \"\\xef\\xa1\\xad\"\t// U+f86d\n#define ICON_FA_ID_BADGE \"\\xef\\x8b\\x81\"\t// U+f2c1\n#define ICON_FA_ID_CARD \"\\xef\\x8b\\x82\"\t// U+f2c2\n#define ICON_FA_ID_CARD_CLIP \"\\xef\\x91\\xbf\"\t// U+f47f\n#define ICON_FA_IGLOO \"\\xef\\x9e\\xae\"\t// U+f7ae\n#define ICON_FA_IMAGE \"\\xef\\x80\\xbe\"\t// U+f03e\n#define ICON_FA_IMAGE_PORTRAIT \"\\xef\\x8f\\xa0\"\t// U+f3e0\n#define ICON_FA_IMAGES \"\\xef\\x8c\\x82\"\t// U+f302\n#define ICON_FA_INBOX \"\\xef\\x80\\x9c\"\t// U+f01c\n#define ICON_FA_INDENT \"\\xef\\x80\\xbc\"\t// U+f03c\n#define ICON_FA_INDIAN_RUPEE_SIGN \"\\xee\\x86\\xbc\"\t// U+e1bc\n#define ICON_FA_INDUSTRY \"\\xef\\x89\\xb5\"\t// U+f275\n#define ICON_FA_INFINITY \"\\xef\\x94\\xb4\"\t// U+f534\n#define ICON_FA_INFO \"\\xef\\x84\\xa9\"\t// U+f129\n#define ICON_FA_ITALIC \"\\xef\\x80\\xb3\"\t// U+f033\n#define ICON_FA_J \"J\"\t// U+004a\n#define ICON_FA_JAR \"\\xee\\x94\\x96\"\t// U+e516\n#define ICON_FA_JAR_WHEAT \"\\xee\\x94\\x97\"\t// U+e517\n#define ICON_FA_JEDI \"\\xef\\x99\\xa9\"\t// U+f669\n#define ICON_FA_JET_FIGHTER \"\\xef\\x83\\xbb\"\t// U+f0fb\n#define ICON_FA_JET_FIGHTER_UP \"\\xee\\x94\\x98\"\t// U+e518\n#define ICON_FA_JOINT \"\\xef\\x96\\x95\"\t// U+f595\n#define ICON_FA_JUG_DETERGENT \"\\xee\\x94\\x99\"\t// U+e519\n#define ICON_FA_K \"K\"\t// U+004b\n#define ICON_FA_KAABA \"\\xef\\x99\\xab\"\t// U+f66b\n#define ICON_FA_KEY \"\\xef\\x82\\x84\"\t// U+f084\n#define ICON_FA_KEYBOARD \"\\xef\\x84\\x9c\"\t// U+f11c\n#define ICON_FA_KHANDA \"\\xef\\x99\\xad\"\t// U+f66d\n#define ICON_FA_KIP_SIGN \"\\xee\\x87\\x84\"\t// U+e1c4\n#define ICON_FA_KIT_MEDICAL \"\\xef\\x91\\xb9\"\t// U+f479\n#define ICON_FA_KITCHEN_SET \"\\xee\\x94\\x9a\"\t// U+e51a\n#define ICON_FA_KIWI_BIRD \"\\xef\\x94\\xb5\"\t// U+f535\n#define ICON_FA_L \"L\"\t// U+004c\n#define ICON_FA_LAND_MINE_ON \"\\xee\\x94\\x9b\"\t// U+e51b\n#define ICON_FA_LANDMARK \"\\xef\\x99\\xaf\"\t// U+f66f\n#define ICON_FA_LANDMARK_DOME \"\\xef\\x9d\\x92\"\t// U+f752\n#define ICON_FA_LANDMARK_FLAG \"\\xee\\x94\\x9c\"\t// U+e51c\n#define ICON_FA_LANGUAGE \"\\xef\\x86\\xab\"\t// U+f1ab\n#define ICON_FA_LAPTOP \"\\xef\\x84\\x89\"\t// U+f109\n#define ICON_FA_LAPTOP_CODE \"\\xef\\x97\\xbc\"\t// U+f5fc\n#define ICON_FA_LAPTOP_FILE \"\\xee\\x94\\x9d\"\t// U+e51d\n#define ICON_FA_LAPTOP_MEDICAL \"\\xef\\xa0\\x92\"\t// U+f812\n#define ICON_FA_LARI_SIGN \"\\xee\\x87\\x88\"\t// U+e1c8\n#define ICON_FA_LAYER_GROUP \"\\xef\\x97\\xbd\"\t// U+f5fd\n#define ICON_FA_LEAF \"\\xef\\x81\\xac\"\t// U+f06c\n#define ICON_FA_LEFT_LONG \"\\xef\\x8c\\x8a\"\t// U+f30a\n#define ICON_FA_LEFT_RIGHT \"\\xef\\x8c\\xb7\"\t// U+f337\n#define ICON_FA_LEMON \"\\xef\\x82\\x94\"\t// U+f094\n#define ICON_FA_LESS_THAN \"<\"\t// U+003c\n#define ICON_FA_LESS_THAN_EQUAL \"\\xef\\x94\\xb7\"\t// U+f537\n#define ICON_FA_LIFE_RING \"\\xef\\x87\\x8d\"\t// U+f1cd\n#define ICON_FA_LIGHTBULB \"\\xef\\x83\\xab\"\t// U+f0eb\n#define ICON_FA_LINES_LEANING \"\\xee\\x94\\x9e\"\t// U+e51e\n#define ICON_FA_LINK \"\\xef\\x83\\x81\"\t// U+f0c1\n#define ICON_FA_LINK_SLASH \"\\xef\\x84\\xa7\"\t// U+f127\n#define ICON_FA_LIRA_SIGN \"\\xef\\x86\\x95\"\t// U+f195\n#define ICON_FA_LIST \"\\xef\\x80\\xba\"\t// U+f03a\n#define ICON_FA_LIST_CHECK \"\\xef\\x82\\xae\"\t// U+f0ae\n#define ICON_FA_LIST_OL \"\\xef\\x83\\x8b\"\t// U+f0cb\n#define ICON_FA_LIST_UL \"\\xef\\x83\\x8a\"\t// U+f0ca\n#define ICON_FA_LITECOIN_SIGN \"\\xee\\x87\\x93\"\t// U+e1d3\n#define ICON_FA_LOCATION_ARROW \"\\xef\\x84\\xa4\"\t// U+f124\n#define ICON_FA_LOCATION_CROSSHAIRS \"\\xef\\x98\\x81\"\t// U+f601\n#define ICON_FA_LOCATION_DOT \"\\xef\\x8f\\x85\"\t// U+f3c5\n#define ICON_FA_LOCATION_PIN \"\\xef\\x81\\x81\"\t// U+f041\n#define ICON_FA_LOCATION_PIN_LOCK \"\\xee\\x94\\x9f\"\t// U+e51f\n#define ICON_FA_LOCK \"\\xef\\x80\\xa3\"\t// U+f023\n#define ICON_FA_LOCK_OPEN \"\\xef\\x8f\\x81\"\t// U+f3c1\n#define ICON_FA_LOCUST \"\\xee\\x94\\xa0\"\t// U+e520\n#define ICON_FA_LUNGS \"\\xef\\x98\\x84\"\t// U+f604\n#define ICON_FA_LUNGS_VIRUS \"\\xee\\x81\\xa7\"\t// U+e067\n#define ICON_FA_M \"M\"\t// U+004d\n#define ICON_FA_MAGNET \"\\xef\\x81\\xb6\"\t// U+f076\n#define ICON_FA_MAGNIFYING_GLASS \"\\xef\\x80\\x82\"\t// U+f002\n#define ICON_FA_MAGNIFYING_GLASS_ARROW_RIGHT \"\\xee\\x94\\xa1\"\t// U+e521\n#define ICON_FA_MAGNIFYING_GLASS_CHART \"\\xee\\x94\\xa2\"\t// U+e522\n#define ICON_FA_MAGNIFYING_GLASS_DOLLAR \"\\xef\\x9a\\x88\"\t// U+f688\n#define ICON_FA_MAGNIFYING_GLASS_LOCATION \"\\xef\\x9a\\x89\"\t// U+f689\n#define ICON_FA_MAGNIFYING_GLASS_MINUS \"\\xef\\x80\\x90\"\t// U+f010\n#define ICON_FA_MAGNIFYING_GLASS_PLUS \"\\xef\\x80\\x8e\"\t// U+f00e\n#define ICON_FA_MANAT_SIGN \"\\xee\\x87\\x95\"\t// U+e1d5\n#define ICON_FA_MAP \"\\xef\\x89\\xb9\"\t// U+f279\n#define ICON_FA_MAP_LOCATION \"\\xef\\x96\\x9f\"\t// U+f59f\n#define ICON_FA_MAP_LOCATION_DOT \"\\xef\\x96\\xa0\"\t// U+f5a0\n#define ICON_FA_MAP_PIN \"\\xef\\x89\\xb6\"\t// U+f276\n#define ICON_FA_MARKER \"\\xef\\x96\\xa1\"\t// U+f5a1\n#define ICON_FA_MARS \"\\xef\\x88\\xa2\"\t// U+f222\n#define ICON_FA_MARS_AND_VENUS \"\\xef\\x88\\xa4\"\t// U+f224\n#define ICON_FA_MARS_AND_VENUS_BURST \"\\xee\\x94\\xa3\"\t// U+e523\n#define ICON_FA_MARS_DOUBLE \"\\xef\\x88\\xa7\"\t// U+f227\n#define ICON_FA_MARS_STROKE \"\\xef\\x88\\xa9\"\t// U+f229\n#define ICON_FA_MARS_STROKE_RIGHT \"\\xef\\x88\\xab\"\t// U+f22b\n#define ICON_FA_MARS_STROKE_UP \"\\xef\\x88\\xaa\"\t// U+f22a\n#define ICON_FA_MARTINI_GLASS \"\\xef\\x95\\xbb\"\t// U+f57b\n#define ICON_FA_MARTINI_GLASS_CITRUS \"\\xef\\x95\\xa1\"\t// U+f561\n#define ICON_FA_MARTINI_GLASS_EMPTY \"\\xef\\x80\\x80\"\t// U+f000\n#define ICON_FA_MASK \"\\xef\\x9b\\xba\"\t// U+f6fa\n#define ICON_FA_MASK_FACE \"\\xee\\x87\\x97\"\t// U+e1d7\n#define ICON_FA_MASK_VENTILATOR \"\\xee\\x94\\xa4\"\t// U+e524\n#define ICON_FA_MASKS_THEATER \"\\xef\\x98\\xb0\"\t// U+f630\n#define ICON_FA_MATTRESS_PILLOW \"\\xee\\x94\\xa5\"\t// U+e525\n#define ICON_FA_MAXIMIZE \"\\xef\\x8c\\x9e\"\t// U+f31e\n#define ICON_FA_MEDAL \"\\xef\\x96\\xa2\"\t// U+f5a2\n#define ICON_FA_MEMORY \"\\xef\\x94\\xb8\"\t// U+f538\n#define ICON_FA_MENORAH \"\\xef\\x99\\xb6\"\t// U+f676\n#define ICON_FA_MERCURY \"\\xef\\x88\\xa3\"\t// U+f223\n#define ICON_FA_MESSAGE \"\\xef\\x89\\xba\"\t// U+f27a\n#define ICON_FA_METEOR \"\\xef\\x9d\\x93\"\t// U+f753\n#define ICON_FA_MICROCHIP \"\\xef\\x8b\\x9b\"\t// U+f2db\n#define ICON_FA_MICROPHONE \"\\xef\\x84\\xb0\"\t// U+f130\n#define ICON_FA_MICROPHONE_LINES \"\\xef\\x8f\\x89\"\t// U+f3c9\n#define ICON_FA_MICROPHONE_LINES_SLASH \"\\xef\\x94\\xb9\"\t// U+f539\n#define ICON_FA_MICROPHONE_SLASH \"\\xef\\x84\\xb1\"\t// U+f131\n#define ICON_FA_MICROSCOPE \"\\xef\\x98\\x90\"\t// U+f610\n#define ICON_FA_MILL_SIGN \"\\xee\\x87\\xad\"\t// U+e1ed\n#define ICON_FA_MINIMIZE \"\\xef\\x9e\\x8c\"\t// U+f78c\n#define ICON_FA_MINUS \"\\xef\\x81\\xa8\"\t// U+f068\n#define ICON_FA_MITTEN \"\\xef\\x9e\\xb5\"\t// U+f7b5\n#define ICON_FA_MOBILE \"\\xef\\x8f\\x8e\"\t// U+f3ce\n#define ICON_FA_MOBILE_BUTTON \"\\xef\\x84\\x8b\"\t// U+f10b\n#define ICON_FA_MOBILE_RETRO \"\\xee\\x94\\xa7\"\t// U+e527\n#define ICON_FA_MOBILE_SCREEN \"\\xef\\x8f\\x8f\"\t// U+f3cf\n#define ICON_FA_MOBILE_SCREEN_BUTTON \"\\xef\\x8f\\x8d\"\t// U+f3cd\n#define ICON_FA_MONEY_BILL \"\\xef\\x83\\x96\"\t// U+f0d6\n#define ICON_FA_MONEY_BILL_1 \"\\xef\\x8f\\x91\"\t// U+f3d1\n#define ICON_FA_MONEY_BILL_1_WAVE \"\\xef\\x94\\xbb\"\t// U+f53b\n#define ICON_FA_MONEY_BILL_TRANSFER \"\\xee\\x94\\xa8\"\t// U+e528\n#define ICON_FA_MONEY_BILL_TREND_UP \"\\xee\\x94\\xa9\"\t// U+e529\n#define ICON_FA_MONEY_BILL_WAVE \"\\xef\\x94\\xba\"\t// U+f53a\n#define ICON_FA_MONEY_BILL_WHEAT \"\\xee\\x94\\xaa\"\t// U+e52a\n#define ICON_FA_MONEY_BILLS \"\\xee\\x87\\xb3\"\t// U+e1f3\n#define ICON_FA_MONEY_CHECK \"\\xef\\x94\\xbc\"\t// U+f53c\n#define ICON_FA_MONEY_CHECK_DOLLAR \"\\xef\\x94\\xbd\"\t// U+f53d\n#define ICON_FA_MONUMENT \"\\xef\\x96\\xa6\"\t// U+f5a6\n#define ICON_FA_MOON \"\\xef\\x86\\x86\"\t// U+f186\n#define ICON_FA_MORTAR_PESTLE \"\\xef\\x96\\xa7\"\t// U+f5a7\n#define ICON_FA_MOSQUE \"\\xef\\x99\\xb8\"\t// U+f678\n#define ICON_FA_MOSQUITO \"\\xee\\x94\\xab\"\t// U+e52b\n#define ICON_FA_MOSQUITO_NET \"\\xee\\x94\\xac\"\t// U+e52c\n#define ICON_FA_MOTORCYCLE \"\\xef\\x88\\x9c\"\t// U+f21c\n#define ICON_FA_MOUND \"\\xee\\x94\\xad\"\t// U+e52d\n#define ICON_FA_MOUNTAIN \"\\xef\\x9b\\xbc\"\t// U+f6fc\n#define ICON_FA_MOUNTAIN_CITY \"\\xee\\x94\\xae\"\t// U+e52e\n#define ICON_FA_MOUNTAIN_SUN \"\\xee\\x94\\xaf\"\t// U+e52f\n#define ICON_FA_MUG_HOT \"\\xef\\x9e\\xb6\"\t// U+f7b6\n#define ICON_FA_MUG_SAUCER \"\\xef\\x83\\xb4\"\t// U+f0f4\n#define ICON_FA_MUSIC \"\\xef\\x80\\x81\"\t// U+f001\n#define ICON_FA_N \"N\"\t// U+004e\n#define ICON_FA_NAIRA_SIGN \"\\xee\\x87\\xb6\"\t// U+e1f6\n#define ICON_FA_NETWORK_WIRED \"\\xef\\x9b\\xbf\"\t// U+f6ff\n#define ICON_FA_NEUTER \"\\xef\\x88\\xac\"\t// U+f22c\n#define ICON_FA_NEWSPAPER \"\\xef\\x87\\xaa\"\t// U+f1ea\n#define ICON_FA_NOT_EQUAL \"\\xef\\x94\\xbe\"\t// U+f53e\n#define ICON_FA_NOTDEF \"\\xee\\x87\\xbe\"\t// U+e1fe\n#define ICON_FA_NOTE_STICKY \"\\xef\\x89\\x89\"\t// U+f249\n#define ICON_FA_NOTES_MEDICAL \"\\xef\\x92\\x81\"\t// U+f481\n#define ICON_FA_O \"O\"\t// U+004f\n#define ICON_FA_OBJECT_GROUP \"\\xef\\x89\\x87\"\t// U+f247\n#define ICON_FA_OBJECT_UNGROUP \"\\xef\\x89\\x88\"\t// U+f248\n#define ICON_FA_OIL_CAN \"\\xef\\x98\\x93\"\t// U+f613\n#define ICON_FA_OIL_WELL \"\\xee\\x94\\xb2\"\t// U+e532\n#define ICON_FA_OM \"\\xef\\x99\\xb9\"\t// U+f679\n#define ICON_FA_OTTER \"\\xef\\x9c\\x80\"\t// U+f700\n#define ICON_FA_OUTDENT \"\\xef\\x80\\xbb\"\t// U+f03b\n#define ICON_FA_P \"P\"\t// U+0050\n#define ICON_FA_PAGER \"\\xef\\xa0\\x95\"\t// U+f815\n#define ICON_FA_PAINT_ROLLER \"\\xef\\x96\\xaa\"\t// U+f5aa\n#define ICON_FA_PAINTBRUSH \"\\xef\\x87\\xbc\"\t// U+f1fc\n#define ICON_FA_PALETTE \"\\xef\\x94\\xbf\"\t// U+f53f\n#define ICON_FA_PALLET \"\\xef\\x92\\x82\"\t// U+f482\n#define ICON_FA_PANORAMA \"\\xee\\x88\\x89\"\t// U+e209\n#define ICON_FA_PAPER_PLANE \"\\xef\\x87\\x98\"\t// U+f1d8\n#define ICON_FA_PAPERCLIP \"\\xef\\x83\\x86\"\t// U+f0c6\n#define ICON_FA_PARACHUTE_BOX \"\\xef\\x93\\x8d\"\t// U+f4cd\n#define ICON_FA_PARAGRAPH \"\\xef\\x87\\x9d\"\t// U+f1dd\n#define ICON_FA_PASSPORT \"\\xef\\x96\\xab\"\t// U+f5ab\n#define ICON_FA_PASTE \"\\xef\\x83\\xaa\"\t// U+f0ea\n#define ICON_FA_PAUSE \"\\xef\\x81\\x8c\"\t// U+f04c\n#define ICON_FA_PAW \"\\xef\\x86\\xb0\"\t// U+f1b0\n#define ICON_FA_PEACE \"\\xef\\x99\\xbc\"\t// U+f67c\n#define ICON_FA_PEN \"\\xef\\x8c\\x84\"\t// U+f304\n#define ICON_FA_PEN_CLIP \"\\xef\\x8c\\x85\"\t// U+f305\n#define ICON_FA_PEN_FANCY \"\\xef\\x96\\xac\"\t// U+f5ac\n#define ICON_FA_PEN_NIB \"\\xef\\x96\\xad\"\t// U+f5ad\n#define ICON_FA_PEN_RULER \"\\xef\\x96\\xae\"\t// U+f5ae\n#define ICON_FA_PEN_TO_SQUARE \"\\xef\\x81\\x84\"\t// U+f044\n#define ICON_FA_PENCIL \"\\xef\\x8c\\x83\"\t// U+f303\n#define ICON_FA_PEOPLE_ARROWS \"\\xee\\x81\\xa8\"\t// U+e068\n#define ICON_FA_PEOPLE_CARRY_BOX \"\\xef\\x93\\x8e\"\t// U+f4ce\n#define ICON_FA_PEOPLE_GROUP \"\\xee\\x94\\xb3\"\t// U+e533\n#define ICON_FA_PEOPLE_LINE \"\\xee\\x94\\xb4\"\t// U+e534\n#define ICON_FA_PEOPLE_PULLING \"\\xee\\x94\\xb5\"\t// U+e535\n#define ICON_FA_PEOPLE_ROBBERY \"\\xee\\x94\\xb6\"\t// U+e536\n#define ICON_FA_PEOPLE_ROOF \"\\xee\\x94\\xb7\"\t// U+e537\n#define ICON_FA_PEPPER_HOT \"\\xef\\xa0\\x96\"\t// U+f816\n#define ICON_FA_PERCENT \"%\"\t// U+0025\n#define ICON_FA_PERSON \"\\xef\\x86\\x83\"\t// U+f183\n#define ICON_FA_PERSON_ARROW_DOWN_TO_LINE \"\\xee\\x94\\xb8\"\t// U+e538\n#define ICON_FA_PERSON_ARROW_UP_FROM_LINE \"\\xee\\x94\\xb9\"\t// U+e539\n#define ICON_FA_PERSON_BIKING \"\\xef\\xa1\\x8a\"\t// U+f84a\n#define ICON_FA_PERSON_BOOTH \"\\xef\\x9d\\x96\"\t// U+f756\n#define ICON_FA_PERSON_BREASTFEEDING \"\\xee\\x94\\xba\"\t// U+e53a\n#define ICON_FA_PERSON_BURST \"\\xee\\x94\\xbb\"\t// U+e53b\n#define ICON_FA_PERSON_CANE \"\\xee\\x94\\xbc\"\t// U+e53c\n#define ICON_FA_PERSON_CHALKBOARD \"\\xee\\x94\\xbd\"\t// U+e53d\n#define ICON_FA_PERSON_CIRCLE_CHECK \"\\xee\\x94\\xbe\"\t// U+e53e\n#define ICON_FA_PERSON_CIRCLE_EXCLAMATION \"\\xee\\x94\\xbf\"\t// U+e53f\n#define ICON_FA_PERSON_CIRCLE_MINUS \"\\xee\\x95\\x80\"\t// U+e540\n#define ICON_FA_PERSON_CIRCLE_PLUS \"\\xee\\x95\\x81\"\t// U+e541\n#define ICON_FA_PERSON_CIRCLE_QUESTION \"\\xee\\x95\\x82\"\t// U+e542\n#define ICON_FA_PERSON_CIRCLE_XMARK \"\\xee\\x95\\x83\"\t// U+e543\n#define ICON_FA_PERSON_DIGGING \"\\xef\\xa1\\x9e\"\t// U+f85e\n#define ICON_FA_PERSON_DOTS_FROM_LINE \"\\xef\\x91\\xb0\"\t// U+f470\n#define ICON_FA_PERSON_DRESS \"\\xef\\x86\\x82\"\t// U+f182\n#define ICON_FA_PERSON_DRESS_BURST \"\\xee\\x95\\x84\"\t// U+e544\n#define ICON_FA_PERSON_DROWNING \"\\xee\\x95\\x85\"\t// U+e545\n#define ICON_FA_PERSON_FALLING \"\\xee\\x95\\x86\"\t// U+e546\n#define ICON_FA_PERSON_FALLING_BURST \"\\xee\\x95\\x87\"\t// U+e547\n#define ICON_FA_PERSON_HALF_DRESS \"\\xee\\x95\\x88\"\t// U+e548\n#define ICON_FA_PERSON_HARASSING \"\\xee\\x95\\x89\"\t// U+e549\n#define ICON_FA_PERSON_HIKING \"\\xef\\x9b\\xac\"\t// U+f6ec\n#define ICON_FA_PERSON_MILITARY_POINTING \"\\xee\\x95\\x8a\"\t// U+e54a\n#define ICON_FA_PERSON_MILITARY_RIFLE \"\\xee\\x95\\x8b\"\t// U+e54b\n#define ICON_FA_PERSON_MILITARY_TO_PERSON \"\\xee\\x95\\x8c\"\t// U+e54c\n#define ICON_FA_PERSON_PRAYING \"\\xef\\x9a\\x83\"\t// U+f683\n#define ICON_FA_PERSON_PREGNANT \"\\xee\\x8c\\x9e\"\t// U+e31e\n#define ICON_FA_PERSON_RAYS \"\\xee\\x95\\x8d\"\t// U+e54d\n#define ICON_FA_PERSON_RIFLE \"\\xee\\x95\\x8e\"\t// U+e54e\n#define ICON_FA_PERSON_RUNNING \"\\xef\\x9c\\x8c\"\t// U+f70c\n#define ICON_FA_PERSON_SHELTER \"\\xee\\x95\\x8f\"\t// U+e54f\n#define ICON_FA_PERSON_SKATING \"\\xef\\x9f\\x85\"\t// U+f7c5\n#define ICON_FA_PERSON_SKIING \"\\xef\\x9f\\x89\"\t// U+f7c9\n#define ICON_FA_PERSON_SKIING_NORDIC \"\\xef\\x9f\\x8a\"\t// U+f7ca\n#define ICON_FA_PERSON_SNOWBOARDING \"\\xef\\x9f\\x8e\"\t// U+f7ce\n#define ICON_FA_PERSON_SWIMMING \"\\xef\\x97\\x84\"\t// U+f5c4\n#define ICON_FA_PERSON_THROUGH_WINDOW \"\\xee\\x96\\xa9\"\t// U+e5a9\n#define ICON_FA_PERSON_WALKING \"\\xef\\x95\\x94\"\t// U+f554\n#define ICON_FA_PERSON_WALKING_ARROW_LOOP_LEFT \"\\xee\\x95\\x91\"\t// U+e551\n#define ICON_FA_PERSON_WALKING_ARROW_RIGHT \"\\xee\\x95\\x92\"\t// U+e552\n#define ICON_FA_PERSON_WALKING_DASHED_LINE_ARROW_RIGHT \"\\xee\\x95\\x93\"\t// U+e553\n#define ICON_FA_PERSON_WALKING_LUGGAGE \"\\xee\\x95\\x94\"\t// U+e554\n#define ICON_FA_PERSON_WALKING_WITH_CANE \"\\xef\\x8a\\x9d\"\t// U+f29d\n#define ICON_FA_PESETA_SIGN \"\\xee\\x88\\xa1\"\t// U+e221\n#define ICON_FA_PESO_SIGN \"\\xee\\x88\\xa2\"\t// U+e222\n#define ICON_FA_PHONE \"\\xef\\x82\\x95\"\t// U+f095\n#define ICON_FA_PHONE_FLIP \"\\xef\\xa1\\xb9\"\t// U+f879\n#define ICON_FA_PHONE_SLASH \"\\xef\\x8f\\x9d\"\t// U+f3dd\n#define ICON_FA_PHONE_VOLUME \"\\xef\\x8a\\xa0\"\t// U+f2a0\n#define ICON_FA_PHOTO_FILM \"\\xef\\xa1\\xbc\"\t// U+f87c\n#define ICON_FA_PIGGY_BANK \"\\xef\\x93\\x93\"\t// U+f4d3\n#define ICON_FA_PILLS \"\\xef\\x92\\x84\"\t// U+f484\n#define ICON_FA_PIZZA_SLICE \"\\xef\\xa0\\x98\"\t// U+f818\n#define ICON_FA_PLACE_OF_WORSHIP \"\\xef\\x99\\xbf\"\t// U+f67f\n#define ICON_FA_PLANE \"\\xef\\x81\\xb2\"\t// U+f072\n#define ICON_FA_PLANE_ARRIVAL \"\\xef\\x96\\xaf\"\t// U+f5af\n#define ICON_FA_PLANE_CIRCLE_CHECK \"\\xee\\x95\\x95\"\t// U+e555\n#define ICON_FA_PLANE_CIRCLE_EXCLAMATION \"\\xee\\x95\\x96\"\t// U+e556\n#define ICON_FA_PLANE_CIRCLE_XMARK \"\\xee\\x95\\x97\"\t// U+e557\n#define ICON_FA_PLANE_DEPARTURE \"\\xef\\x96\\xb0\"\t// U+f5b0\n#define ICON_FA_PLANE_LOCK \"\\xee\\x95\\x98\"\t// U+e558\n#define ICON_FA_PLANE_SLASH \"\\xee\\x81\\xa9\"\t// U+e069\n#define ICON_FA_PLANE_UP \"\\xee\\x88\\xad\"\t// U+e22d\n#define ICON_FA_PLANT_WILT \"\\xee\\x96\\xaa\"\t// U+e5aa\n#define ICON_FA_PLATE_WHEAT \"\\xee\\x95\\x9a\"\t// U+e55a\n#define ICON_FA_PLAY \"\\xef\\x81\\x8b\"\t// U+f04b\n#define ICON_FA_PLUG \"\\xef\\x87\\xa6\"\t// U+f1e6\n#define ICON_FA_PLUG_CIRCLE_BOLT \"\\xee\\x95\\x9b\"\t// U+e55b\n#define ICON_FA_PLUG_CIRCLE_CHECK \"\\xee\\x95\\x9c\"\t// U+e55c\n#define ICON_FA_PLUG_CIRCLE_EXCLAMATION \"\\xee\\x95\\x9d\"\t// U+e55d\n#define ICON_FA_PLUG_CIRCLE_MINUS \"\\xee\\x95\\x9e\"\t// U+e55e\n#define ICON_FA_PLUG_CIRCLE_PLUS \"\\xee\\x95\\x9f\"\t// U+e55f\n#define ICON_FA_PLUG_CIRCLE_XMARK \"\\xee\\x95\\xa0\"\t// U+e560\n#define ICON_FA_PLUS \"+\"\t// U+002b\n#define ICON_FA_PLUS_MINUS \"\\xee\\x90\\xbc\"\t// U+e43c\n#define ICON_FA_PODCAST \"\\xef\\x8b\\x8e\"\t// U+f2ce\n#define ICON_FA_POO \"\\xef\\x8b\\xbe\"\t// U+f2fe\n#define ICON_FA_POO_STORM \"\\xef\\x9d\\x9a\"\t// U+f75a\n#define ICON_FA_POOP \"\\xef\\x98\\x99\"\t// U+f619\n#define ICON_FA_POWER_OFF \"\\xef\\x80\\x91\"\t// U+f011\n#define ICON_FA_PRESCRIPTION \"\\xef\\x96\\xb1\"\t// U+f5b1\n#define ICON_FA_PRESCRIPTION_BOTTLE \"\\xef\\x92\\x85\"\t// U+f485\n#define ICON_FA_PRESCRIPTION_BOTTLE_MEDICAL \"\\xef\\x92\\x86\"\t// U+f486\n#define ICON_FA_PRINT \"\\xef\\x80\\xaf\"\t// U+f02f\n#define ICON_FA_PUMP_MEDICAL \"\\xee\\x81\\xaa\"\t// U+e06a\n#define ICON_FA_PUMP_SOAP \"\\xee\\x81\\xab\"\t// U+e06b\n#define ICON_FA_PUZZLE_PIECE \"\\xef\\x84\\xae\"\t// U+f12e\n#define ICON_FA_Q \"Q\"\t// U+0051\n#define ICON_FA_QRCODE \"\\xef\\x80\\xa9\"\t// U+f029\n#define ICON_FA_QUESTION \"?\"\t// U+003f\n#define ICON_FA_QUOTE_LEFT \"\\xef\\x84\\x8d\"\t// U+f10d\n#define ICON_FA_QUOTE_RIGHT \"\\xef\\x84\\x8e\"\t// U+f10e\n#define ICON_FA_R \"R\"\t// U+0052\n#define ICON_FA_RADIATION \"\\xef\\x9e\\xb9\"\t// U+f7b9\n#define ICON_FA_RADIO \"\\xef\\xa3\\x97\"\t// U+f8d7\n#define ICON_FA_RAINBOW \"\\xef\\x9d\\x9b\"\t// U+f75b\n#define ICON_FA_RANKING_STAR \"\\xee\\x95\\xa1\"\t// U+e561\n#define ICON_FA_RECEIPT \"\\xef\\x95\\x83\"\t// U+f543\n#define ICON_FA_RECORD_VINYL \"\\xef\\xa3\\x99\"\t// U+f8d9\n#define ICON_FA_RECTANGLE_AD \"\\xef\\x99\\x81\"\t// U+f641\n#define ICON_FA_RECTANGLE_LIST \"\\xef\\x80\\xa2\"\t// U+f022\n#define ICON_FA_RECTANGLE_XMARK \"\\xef\\x90\\x90\"\t// U+f410\n#define ICON_FA_RECYCLE \"\\xef\\x86\\xb8\"\t// U+f1b8\n#define ICON_FA_REGISTERED \"\\xef\\x89\\x9d\"\t// U+f25d\n#define ICON_FA_REPEAT \"\\xef\\x8d\\xa3\"\t// U+f363\n#define ICON_FA_REPLY \"\\xef\\x8f\\xa5\"\t// U+f3e5\n#define ICON_FA_REPLY_ALL \"\\xef\\x84\\xa2\"\t// U+f122\n#define ICON_FA_REPUBLICAN \"\\xef\\x9d\\x9e\"\t// U+f75e\n#define ICON_FA_RESTROOM \"\\xef\\x9e\\xbd\"\t// U+f7bd\n#define ICON_FA_RETWEET \"\\xef\\x81\\xb9\"\t// U+f079\n#define ICON_FA_RIBBON \"\\xef\\x93\\x96\"\t// U+f4d6\n#define ICON_FA_RIGHT_FROM_BRACKET \"\\xef\\x8b\\xb5\"\t// U+f2f5\n#define ICON_FA_RIGHT_LEFT \"\\xef\\x8d\\xa2\"\t// U+f362\n#define ICON_FA_RIGHT_LONG \"\\xef\\x8c\\x8b\"\t// U+f30b\n#define ICON_FA_RIGHT_TO_BRACKET \"\\xef\\x8b\\xb6\"\t// U+f2f6\n#define ICON_FA_RING \"\\xef\\x9c\\x8b\"\t// U+f70b\n#define ICON_FA_ROAD \"\\xef\\x80\\x98\"\t// U+f018\n#define ICON_FA_ROAD_BARRIER \"\\xee\\x95\\xa2\"\t// U+e562\n#define ICON_FA_ROAD_BRIDGE \"\\xee\\x95\\xa3\"\t// U+e563\n#define ICON_FA_ROAD_CIRCLE_CHECK \"\\xee\\x95\\xa4\"\t// U+e564\n#define ICON_FA_ROAD_CIRCLE_EXCLAMATION \"\\xee\\x95\\xa5\"\t// U+e565\n#define ICON_FA_ROAD_CIRCLE_XMARK \"\\xee\\x95\\xa6\"\t// U+e566\n#define ICON_FA_ROAD_LOCK \"\\xee\\x95\\xa7\"\t// U+e567\n#define ICON_FA_ROAD_SPIKES \"\\xee\\x95\\xa8\"\t// U+e568\n#define ICON_FA_ROBOT \"\\xef\\x95\\x84\"\t// U+f544\n#define ICON_FA_ROCKET \"\\xef\\x84\\xb5\"\t// U+f135\n#define ICON_FA_ROTATE \"\\xef\\x8b\\xb1\"\t// U+f2f1\n#define ICON_FA_ROTATE_LEFT \"\\xef\\x8b\\xaa\"\t// U+f2ea\n#define ICON_FA_ROTATE_RIGHT \"\\xef\\x8b\\xb9\"\t// U+f2f9\n#define ICON_FA_ROUTE \"\\xef\\x93\\x97\"\t// U+f4d7\n#define ICON_FA_RSS \"\\xef\\x82\\x9e\"\t// U+f09e\n#define ICON_FA_RUBLE_SIGN \"\\xef\\x85\\x98\"\t// U+f158\n#define ICON_FA_RUG \"\\xee\\x95\\xa9\"\t// U+e569\n#define ICON_FA_RULER \"\\xef\\x95\\x85\"\t// U+f545\n#define ICON_FA_RULER_COMBINED \"\\xef\\x95\\x86\"\t// U+f546\n#define ICON_FA_RULER_HORIZONTAL \"\\xef\\x95\\x87\"\t// U+f547\n#define ICON_FA_RULER_VERTICAL \"\\xef\\x95\\x88\"\t// U+f548\n#define ICON_FA_RUPEE_SIGN \"\\xef\\x85\\x96\"\t// U+f156\n#define ICON_FA_RUPIAH_SIGN \"\\xee\\x88\\xbd\"\t// U+e23d\n#define ICON_FA_S \"S\"\t// U+0053\n#define ICON_FA_SACK_DOLLAR \"\\xef\\xa0\\x9d\"\t// U+f81d\n#define ICON_FA_SACK_XMARK \"\\xee\\x95\\xaa\"\t// U+e56a\n#define ICON_FA_SAILBOAT \"\\xee\\x91\\x85\"\t// U+e445\n#define ICON_FA_SATELLITE \"\\xef\\x9e\\xbf\"\t// U+f7bf\n#define ICON_FA_SATELLITE_DISH \"\\xef\\x9f\\x80\"\t// U+f7c0\n#define ICON_FA_SCALE_BALANCED \"\\xef\\x89\\x8e\"\t// U+f24e\n#define ICON_FA_SCALE_UNBALANCED \"\\xef\\x94\\x95\"\t// U+f515\n#define ICON_FA_SCALE_UNBALANCED_FLIP \"\\xef\\x94\\x96\"\t// U+f516\n#define ICON_FA_SCHOOL \"\\xef\\x95\\x89\"\t// U+f549\n#define ICON_FA_SCHOOL_CIRCLE_CHECK \"\\xee\\x95\\xab\"\t// U+e56b\n#define ICON_FA_SCHOOL_CIRCLE_EXCLAMATION \"\\xee\\x95\\xac\"\t// U+e56c\n#define ICON_FA_SCHOOL_CIRCLE_XMARK \"\\xee\\x95\\xad\"\t// U+e56d\n#define ICON_FA_SCHOOL_FLAG \"\\xee\\x95\\xae\"\t// U+e56e\n#define ICON_FA_SCHOOL_LOCK \"\\xee\\x95\\xaf\"\t// U+e56f\n#define ICON_FA_SCISSORS \"\\xef\\x83\\x84\"\t// U+f0c4\n#define ICON_FA_SCREWDRIVER \"\\xef\\x95\\x8a\"\t// U+f54a\n#define ICON_FA_SCREWDRIVER_WRENCH \"\\xef\\x9f\\x99\"\t// U+f7d9\n#define ICON_FA_SCROLL \"\\xef\\x9c\\x8e\"\t// U+f70e\n#define ICON_FA_SCROLL_TORAH \"\\xef\\x9a\\xa0\"\t// U+f6a0\n#define ICON_FA_SD_CARD \"\\xef\\x9f\\x82\"\t// U+f7c2\n#define ICON_FA_SECTION \"\\xee\\x91\\x87\"\t// U+e447\n#define ICON_FA_SEEDLING \"\\xef\\x93\\x98\"\t// U+f4d8\n#define ICON_FA_SERVER \"\\xef\\x88\\xb3\"\t// U+f233\n#define ICON_FA_SHAPES \"\\xef\\x98\\x9f\"\t// U+f61f\n#define ICON_FA_SHARE \"\\xef\\x81\\xa4\"\t// U+f064\n#define ICON_FA_SHARE_FROM_SQUARE \"\\xef\\x85\\x8d\"\t// U+f14d\n#define ICON_FA_SHARE_NODES \"\\xef\\x87\\xa0\"\t// U+f1e0\n#define ICON_FA_SHEET_PLASTIC \"\\xee\\x95\\xb1\"\t// U+e571\n#define ICON_FA_SHEKEL_SIGN \"\\xef\\x88\\x8b\"\t// U+f20b\n#define ICON_FA_SHIELD \"\\xef\\x84\\xb2\"\t// U+f132\n#define ICON_FA_SHIELD_CAT \"\\xee\\x95\\xb2\"\t// U+e572\n#define ICON_FA_SHIELD_DOG \"\\xee\\x95\\xb3\"\t// U+e573\n#define ICON_FA_SHIELD_HALVED \"\\xef\\x8f\\xad\"\t// U+f3ed\n#define ICON_FA_SHIELD_HEART \"\\xee\\x95\\xb4\"\t// U+e574\n#define ICON_FA_SHIELD_VIRUS \"\\xee\\x81\\xac\"\t// U+e06c\n#define ICON_FA_SHIP \"\\xef\\x88\\x9a\"\t// U+f21a\n#define ICON_FA_SHIRT \"\\xef\\x95\\x93\"\t// U+f553\n#define ICON_FA_SHOE_PRINTS \"\\xef\\x95\\x8b\"\t// U+f54b\n#define ICON_FA_SHOP \"\\xef\\x95\\x8f\"\t// U+f54f\n#define ICON_FA_SHOP_LOCK \"\\xee\\x92\\xa5\"\t// U+e4a5\n#define ICON_FA_SHOP_SLASH \"\\xee\\x81\\xb0\"\t// U+e070\n#define ICON_FA_SHOWER \"\\xef\\x8b\\x8c\"\t// U+f2cc\n#define ICON_FA_SHRIMP \"\\xee\\x91\\x88\"\t// U+e448\n#define ICON_FA_SHUFFLE \"\\xef\\x81\\xb4\"\t// U+f074\n#define ICON_FA_SHUTTLE_SPACE \"\\xef\\x86\\x97\"\t// U+f197\n#define ICON_FA_SIGN_HANGING \"\\xef\\x93\\x99\"\t// U+f4d9\n#define ICON_FA_SIGNAL \"\\xef\\x80\\x92\"\t// U+f012\n#define ICON_FA_SIGNATURE \"\\xef\\x96\\xb7\"\t// U+f5b7\n#define ICON_FA_SIGNS_POST \"\\xef\\x89\\xb7\"\t// U+f277\n#define ICON_FA_SIM_CARD \"\\xef\\x9f\\x84\"\t// U+f7c4\n#define ICON_FA_SINK \"\\xee\\x81\\xad\"\t// U+e06d\n#define ICON_FA_SITEMAP \"\\xef\\x83\\xa8\"\t// U+f0e8\n#define ICON_FA_SKULL \"\\xef\\x95\\x8c\"\t// U+f54c\n#define ICON_FA_SKULL_CROSSBONES \"\\xef\\x9c\\x94\"\t// U+f714\n#define ICON_FA_SLASH \"\\xef\\x9c\\x95\"\t// U+f715\n#define ICON_FA_SLEIGH \"\\xef\\x9f\\x8c\"\t// U+f7cc\n#define ICON_FA_SLIDERS \"\\xef\\x87\\x9e\"\t// U+f1de\n#define ICON_FA_SMOG \"\\xef\\x9d\\x9f\"\t// U+f75f\n#define ICON_FA_SMOKING \"\\xef\\x92\\x8d\"\t// U+f48d\n#define ICON_FA_SNOWFLAKE \"\\xef\\x8b\\x9c\"\t// U+f2dc\n#define ICON_FA_SNOWMAN \"\\xef\\x9f\\x90\"\t// U+f7d0\n#define ICON_FA_SNOWPLOW \"\\xef\\x9f\\x92\"\t// U+f7d2\n#define ICON_FA_SOAP \"\\xee\\x81\\xae\"\t// U+e06e\n#define ICON_FA_SOCKS \"\\xef\\x9a\\x96\"\t// U+f696\n#define ICON_FA_SOLAR_PANEL \"\\xef\\x96\\xba\"\t// U+f5ba\n#define ICON_FA_SORT \"\\xef\\x83\\x9c\"\t// U+f0dc\n#define ICON_FA_SORT_DOWN \"\\xef\\x83\\x9d\"\t// U+f0dd\n#define ICON_FA_SORT_UP \"\\xef\\x83\\x9e\"\t// U+f0de\n#define ICON_FA_SPA \"\\xef\\x96\\xbb\"\t// U+f5bb\n#define ICON_FA_SPAGHETTI_MONSTER_FLYING \"\\xef\\x99\\xbb\"\t// U+f67b\n#define ICON_FA_SPELL_CHECK \"\\xef\\xa2\\x91\"\t// U+f891\n#define ICON_FA_SPIDER \"\\xef\\x9c\\x97\"\t// U+f717\n#define ICON_FA_SPINNER \"\\xef\\x84\\x90\"\t// U+f110\n#define ICON_FA_SPLOTCH \"\\xef\\x96\\xbc\"\t// U+f5bc\n#define ICON_FA_SPOON \"\\xef\\x8b\\xa5\"\t// U+f2e5\n#define ICON_FA_SPRAY_CAN \"\\xef\\x96\\xbd\"\t// U+f5bd\n#define ICON_FA_SPRAY_CAN_SPARKLES \"\\xef\\x97\\x90\"\t// U+f5d0\n#define ICON_FA_SQUARE \"\\xef\\x83\\x88\"\t// U+f0c8\n#define ICON_FA_SQUARE_ARROW_UP_RIGHT \"\\xef\\x85\\x8c\"\t// U+f14c\n#define ICON_FA_SQUARE_CARET_DOWN \"\\xef\\x85\\x90\"\t// U+f150\n#define ICON_FA_SQUARE_CARET_LEFT \"\\xef\\x86\\x91\"\t// U+f191\n#define ICON_FA_SQUARE_CARET_RIGHT \"\\xef\\x85\\x92\"\t// U+f152\n#define ICON_FA_SQUARE_CARET_UP \"\\xef\\x85\\x91\"\t// U+f151\n#define ICON_FA_SQUARE_CHECK \"\\xef\\x85\\x8a\"\t// U+f14a\n#define ICON_FA_SQUARE_ENVELOPE \"\\xef\\x86\\x99\"\t// U+f199\n#define ICON_FA_SQUARE_FULL \"\\xef\\x91\\x9c\"\t// U+f45c\n#define ICON_FA_SQUARE_H \"\\xef\\x83\\xbd\"\t// U+f0fd\n#define ICON_FA_SQUARE_MINUS \"\\xef\\x85\\x86\"\t// U+f146\n#define ICON_FA_SQUARE_NFI \"\\xee\\x95\\xb6\"\t// U+e576\n#define ICON_FA_SQUARE_PARKING \"\\xef\\x95\\x80\"\t// U+f540\n#define ICON_FA_SQUARE_PEN \"\\xef\\x85\\x8b\"\t// U+f14b\n#define ICON_FA_SQUARE_PERSON_CONFINED \"\\xee\\x95\\xb7\"\t// U+e577\n#define ICON_FA_SQUARE_PHONE \"\\xef\\x82\\x98\"\t// U+f098\n#define ICON_FA_SQUARE_PHONE_FLIP \"\\xef\\xa1\\xbb\"\t// U+f87b\n#define ICON_FA_SQUARE_PLUS \"\\xef\\x83\\xbe\"\t// U+f0fe\n#define ICON_FA_SQUARE_POLL_HORIZONTAL \"\\xef\\x9a\\x82\"\t// U+f682\n#define ICON_FA_SQUARE_POLL_VERTICAL \"\\xef\\x9a\\x81\"\t// U+f681\n#define ICON_FA_SQUARE_ROOT_VARIABLE \"\\xef\\x9a\\x98\"\t// U+f698\n#define ICON_FA_SQUARE_RSS \"\\xef\\x85\\x83\"\t// U+f143\n#define ICON_FA_SQUARE_SHARE_NODES \"\\xef\\x87\\xa1\"\t// U+f1e1\n#define ICON_FA_SQUARE_UP_RIGHT \"\\xef\\x8d\\xa0\"\t// U+f360\n#define ICON_FA_SQUARE_VIRUS \"\\xee\\x95\\xb8\"\t// U+e578\n#define ICON_FA_SQUARE_XMARK \"\\xef\\x8b\\x93\"\t// U+f2d3\n#define ICON_FA_STAFF_SNAKE \"\\xee\\x95\\xb9\"\t// U+e579\n#define ICON_FA_STAIRS \"\\xee\\x8a\\x89\"\t// U+e289\n#define ICON_FA_STAMP \"\\xef\\x96\\xbf\"\t// U+f5bf\n#define ICON_FA_STAPLER \"\\xee\\x96\\xaf\"\t// U+e5af\n#define ICON_FA_STAR \"\\xef\\x80\\x85\"\t// U+f005\n#define ICON_FA_STAR_AND_CRESCENT \"\\xef\\x9a\\x99\"\t// U+f699\n#define ICON_FA_STAR_HALF \"\\xef\\x82\\x89\"\t// U+f089\n#define ICON_FA_STAR_HALF_STROKE \"\\xef\\x97\\x80\"\t// U+f5c0\n#define ICON_FA_STAR_OF_DAVID \"\\xef\\x9a\\x9a\"\t// U+f69a\n#define ICON_FA_STAR_OF_LIFE \"\\xef\\x98\\xa1\"\t// U+f621\n#define ICON_FA_STERLING_SIGN \"\\xef\\x85\\x94\"\t// U+f154\n#define ICON_FA_STETHOSCOPE \"\\xef\\x83\\xb1\"\t// U+f0f1\n#define ICON_FA_STOP \"\\xef\\x81\\x8d\"\t// U+f04d\n#define ICON_FA_STOPWATCH \"\\xef\\x8b\\xb2\"\t// U+f2f2\n#define ICON_FA_STOPWATCH_20 \"\\xee\\x81\\xaf\"\t// U+e06f\n#define ICON_FA_STORE \"\\xef\\x95\\x8e\"\t// U+f54e\n#define ICON_FA_STORE_SLASH \"\\xee\\x81\\xb1\"\t// U+e071\n#define ICON_FA_STREET_VIEW \"\\xef\\x88\\x9d\"\t// U+f21d\n#define ICON_FA_STRIKETHROUGH \"\\xef\\x83\\x8c\"\t// U+f0cc\n#define ICON_FA_STROOPWAFEL \"\\xef\\x95\\x91\"\t// U+f551\n#define ICON_FA_SUBSCRIPT \"\\xef\\x84\\xac\"\t// U+f12c\n#define ICON_FA_SUITCASE \"\\xef\\x83\\xb2\"\t// U+f0f2\n#define ICON_FA_SUITCASE_MEDICAL \"\\xef\\x83\\xba\"\t// U+f0fa\n#define ICON_FA_SUITCASE_ROLLING \"\\xef\\x97\\x81\"\t// U+f5c1\n#define ICON_FA_SUN \"\\xef\\x86\\x85\"\t// U+f185\n#define ICON_FA_SUN_PLANT_WILT \"\\xee\\x95\\xba\"\t// U+e57a\n#define ICON_FA_SUPERSCRIPT \"\\xef\\x84\\xab\"\t// U+f12b\n#define ICON_FA_SWATCHBOOK \"\\xef\\x97\\x83\"\t// U+f5c3\n#define ICON_FA_SYNAGOGUE \"\\xef\\x9a\\x9b\"\t// U+f69b\n#define ICON_FA_SYRINGE \"\\xef\\x92\\x8e\"\t// U+f48e\n#define ICON_FA_T \"T\"\t// U+0054\n#define ICON_FA_TABLE \"\\xef\\x83\\x8e\"\t// U+f0ce\n#define ICON_FA_TABLE_CELLS \"\\xef\\x80\\x8a\"\t// U+f00a\n#define ICON_FA_TABLE_CELLS_LARGE \"\\xef\\x80\\x89\"\t// U+f009\n#define ICON_FA_TABLE_COLUMNS \"\\xef\\x83\\x9b\"\t// U+f0db\n#define ICON_FA_TABLE_LIST \"\\xef\\x80\\x8b\"\t// U+f00b\n#define ICON_FA_TABLE_TENNIS_PADDLE_BALL \"\\xef\\x91\\x9d\"\t// U+f45d\n#define ICON_FA_TABLET \"\\xef\\x8f\\xbb\"\t// U+f3fb\n#define ICON_FA_TABLET_BUTTON \"\\xef\\x84\\x8a\"\t// U+f10a\n#define ICON_FA_TABLET_SCREEN_BUTTON \"\\xef\\x8f\\xba\"\t// U+f3fa\n#define ICON_FA_TABLETS \"\\xef\\x92\\x90\"\t// U+f490\n#define ICON_FA_TACHOGRAPH_DIGITAL \"\\xef\\x95\\xa6\"\t// U+f566\n#define ICON_FA_TAG \"\\xef\\x80\\xab\"\t// U+f02b\n#define ICON_FA_TAGS \"\\xef\\x80\\xac\"\t// U+f02c\n#define ICON_FA_TAPE \"\\xef\\x93\\x9b\"\t// U+f4db\n#define ICON_FA_TARP \"\\xee\\x95\\xbb\"\t// U+e57b\n#define ICON_FA_TARP_DROPLET \"\\xee\\x95\\xbc\"\t// U+e57c\n#define ICON_FA_TAXI \"\\xef\\x86\\xba\"\t// U+f1ba\n#define ICON_FA_TEETH \"\\xef\\x98\\xae\"\t// U+f62e\n#define ICON_FA_TEETH_OPEN \"\\xef\\x98\\xaf\"\t// U+f62f\n#define ICON_FA_TEMPERATURE_ARROW_DOWN \"\\xee\\x80\\xbf\"\t// U+e03f\n#define ICON_FA_TEMPERATURE_ARROW_UP \"\\xee\\x81\\x80\"\t// U+e040\n#define ICON_FA_TEMPERATURE_EMPTY \"\\xef\\x8b\\x8b\"\t// U+f2cb\n#define ICON_FA_TEMPERATURE_FULL \"\\xef\\x8b\\x87\"\t// U+f2c7\n#define ICON_FA_TEMPERATURE_HALF \"\\xef\\x8b\\x89\"\t// U+f2c9\n#define ICON_FA_TEMPERATURE_HIGH \"\\xef\\x9d\\xa9\"\t// U+f769\n#define ICON_FA_TEMPERATURE_LOW \"\\xef\\x9d\\xab\"\t// U+f76b\n#define ICON_FA_TEMPERATURE_QUARTER \"\\xef\\x8b\\x8a\"\t// U+f2ca\n#define ICON_FA_TEMPERATURE_THREE_QUARTERS \"\\xef\\x8b\\x88\"\t// U+f2c8\n#define ICON_FA_TENGE_SIGN \"\\xef\\x9f\\x97\"\t// U+f7d7\n#define ICON_FA_TENT \"\\xee\\x95\\xbd\"\t// U+e57d\n#define ICON_FA_TENT_ARROW_DOWN_TO_LINE \"\\xee\\x95\\xbe\"\t// U+e57e\n#define ICON_FA_TENT_ARROW_LEFT_RIGHT \"\\xee\\x95\\xbf\"\t// U+e57f\n#define ICON_FA_TENT_ARROW_TURN_LEFT \"\\xee\\x96\\x80\"\t// U+e580\n#define ICON_FA_TENT_ARROWS_DOWN \"\\xee\\x96\\x81\"\t// U+e581\n#define ICON_FA_TENTS \"\\xee\\x96\\x82\"\t// U+e582\n#define ICON_FA_TERMINAL \"\\xef\\x84\\xa0\"\t// U+f120\n#define ICON_FA_TEXT_HEIGHT \"\\xef\\x80\\xb4\"\t// U+f034\n#define ICON_FA_TEXT_SLASH \"\\xef\\xa1\\xbd\"\t// U+f87d\n#define ICON_FA_TEXT_WIDTH \"\\xef\\x80\\xb5\"\t// U+f035\n#define ICON_FA_THERMOMETER \"\\xef\\x92\\x91\"\t// U+f491\n#define ICON_FA_THUMBS_DOWN \"\\xef\\x85\\xa5\"\t// U+f165\n#define ICON_FA_THUMBS_UP \"\\xef\\x85\\xa4\"\t// U+f164\n#define ICON_FA_THUMBTACK \"\\xef\\x82\\x8d\"\t// U+f08d\n#define ICON_FA_TICKET \"\\xef\\x85\\x85\"\t// U+f145\n#define ICON_FA_TICKET_SIMPLE \"\\xef\\x8f\\xbf\"\t// U+f3ff\n#define ICON_FA_TIMELINE \"\\xee\\x8a\\x9c\"\t// U+e29c\n#define ICON_FA_TOGGLE_OFF \"\\xef\\x88\\x84\"\t// U+f204\n#define ICON_FA_TOGGLE_ON \"\\xef\\x88\\x85\"\t// U+f205\n#define ICON_FA_TOILET \"\\xef\\x9f\\x98\"\t// U+f7d8\n#define ICON_FA_TOILET_PAPER \"\\xef\\x9c\\x9e\"\t// U+f71e\n#define ICON_FA_TOILET_PAPER_SLASH \"\\xee\\x81\\xb2\"\t// U+e072\n#define ICON_FA_TOILET_PORTABLE \"\\xee\\x96\\x83\"\t// U+e583\n#define ICON_FA_TOILETS_PORTABLE \"\\xee\\x96\\x84\"\t// U+e584\n#define ICON_FA_TOOLBOX \"\\xef\\x95\\x92\"\t// U+f552\n#define ICON_FA_TOOTH \"\\xef\\x97\\x89\"\t// U+f5c9\n#define ICON_FA_TORII_GATE \"\\xef\\x9a\\xa1\"\t// U+f6a1\n#define ICON_FA_TORNADO \"\\xef\\x9d\\xaf\"\t// U+f76f\n#define ICON_FA_TOWER_BROADCAST \"\\xef\\x94\\x99\"\t// U+f519\n#define ICON_FA_TOWER_CELL \"\\xee\\x96\\x85\"\t// U+e585\n#define ICON_FA_TOWER_OBSERVATION \"\\xee\\x96\\x86\"\t// U+e586\n#define ICON_FA_TRACTOR \"\\xef\\x9c\\xa2\"\t// U+f722\n#define ICON_FA_TRADEMARK \"\\xef\\x89\\x9c\"\t// U+f25c\n#define ICON_FA_TRAFFIC_LIGHT \"\\xef\\x98\\xb7\"\t// U+f637\n#define ICON_FA_TRAILER \"\\xee\\x81\\x81\"\t// U+e041\n#define ICON_FA_TRAIN \"\\xef\\x88\\xb8\"\t// U+f238\n#define ICON_FA_TRAIN_SUBWAY \"\\xef\\x88\\xb9\"\t// U+f239\n#define ICON_FA_TRAIN_TRAM \"\\xee\\x96\\xb4\"\t// U+e5b4\n#define ICON_FA_TRANSGENDER \"\\xef\\x88\\xa5\"\t// U+f225\n#define ICON_FA_TRASH \"\\xef\\x87\\xb8\"\t// U+f1f8\n#define ICON_FA_TRASH_ARROW_UP \"\\xef\\xa0\\xa9\"\t// U+f829\n#define ICON_FA_TRASH_CAN \"\\xef\\x8b\\xad\"\t// U+f2ed\n#define ICON_FA_TRASH_CAN_ARROW_UP \"\\xef\\xa0\\xaa\"\t// U+f82a\n#define ICON_FA_TREE \"\\xef\\x86\\xbb\"\t// U+f1bb\n#define ICON_FA_TREE_CITY \"\\xee\\x96\\x87\"\t// U+e587\n#define ICON_FA_TRIANGLE_EXCLAMATION \"\\xef\\x81\\xb1\"\t// U+f071\n#define ICON_FA_TROPHY \"\\xef\\x82\\x91\"\t// U+f091\n#define ICON_FA_TROWEL \"\\xee\\x96\\x89\"\t// U+e589\n#define ICON_FA_TROWEL_BRICKS \"\\xee\\x96\\x8a\"\t// U+e58a\n#define ICON_FA_TRUCK \"\\xef\\x83\\x91\"\t// U+f0d1\n#define ICON_FA_TRUCK_ARROW_RIGHT \"\\xee\\x96\\x8b\"\t// U+e58b\n#define ICON_FA_TRUCK_DROPLET \"\\xee\\x96\\x8c\"\t// U+e58c\n#define ICON_FA_TRUCK_FAST \"\\xef\\x92\\x8b\"\t// U+f48b\n#define ICON_FA_TRUCK_FIELD \"\\xee\\x96\\x8d\"\t// U+e58d\n#define ICON_FA_TRUCK_FIELD_UN \"\\xee\\x96\\x8e\"\t// U+e58e\n#define ICON_FA_TRUCK_FRONT \"\\xee\\x8a\\xb7\"\t// U+e2b7\n#define ICON_FA_TRUCK_MEDICAL \"\\xef\\x83\\xb9\"\t// U+f0f9\n#define ICON_FA_TRUCK_MONSTER \"\\xef\\x98\\xbb\"\t// U+f63b\n#define ICON_FA_TRUCK_MOVING \"\\xef\\x93\\x9f\"\t// U+f4df\n#define ICON_FA_TRUCK_PICKUP \"\\xef\\x98\\xbc\"\t// U+f63c\n#define ICON_FA_TRUCK_PLANE \"\\xee\\x96\\x8f\"\t// U+e58f\n#define ICON_FA_TRUCK_RAMP_BOX \"\\xef\\x93\\x9e\"\t// U+f4de\n#define ICON_FA_TTY \"\\xef\\x87\\xa4\"\t// U+f1e4\n#define ICON_FA_TURKISH_LIRA_SIGN \"\\xee\\x8a\\xbb\"\t// U+e2bb\n#define ICON_FA_TURN_DOWN \"\\xef\\x8e\\xbe\"\t// U+f3be\n#define ICON_FA_TURN_UP \"\\xef\\x8e\\xbf\"\t// U+f3bf\n#define ICON_FA_TV \"\\xef\\x89\\xac\"\t// U+f26c\n#define ICON_FA_U \"U\"\t// U+0055\n#define ICON_FA_UMBRELLA \"\\xef\\x83\\xa9\"\t// U+f0e9\n#define ICON_FA_UMBRELLA_BEACH \"\\xef\\x97\\x8a\"\t// U+f5ca\n#define ICON_FA_UNDERLINE \"\\xef\\x83\\x8d\"\t// U+f0cd\n#define ICON_FA_UNIVERSAL_ACCESS \"\\xef\\x8a\\x9a\"\t// U+f29a\n#define ICON_FA_UNLOCK \"\\xef\\x82\\x9c\"\t// U+f09c\n#define ICON_FA_UNLOCK_KEYHOLE \"\\xef\\x84\\xbe\"\t// U+f13e\n#define ICON_FA_UP_DOWN \"\\xef\\x8c\\xb8\"\t// U+f338\n#define ICON_FA_UP_DOWN_LEFT_RIGHT \"\\xef\\x82\\xb2\"\t// U+f0b2\n#define ICON_FA_UP_LONG \"\\xef\\x8c\\x8c\"\t// U+f30c\n#define ICON_FA_UP_RIGHT_AND_DOWN_LEFT_FROM_CENTER \"\\xef\\x90\\xa4\"\t// U+f424\n#define ICON_FA_UP_RIGHT_FROM_SQUARE \"\\xef\\x8d\\x9d\"\t// U+f35d\n#define ICON_FA_UPLOAD \"\\xef\\x82\\x93\"\t// U+f093\n#define ICON_FA_USER \"\\xef\\x80\\x87\"\t// U+f007\n#define ICON_FA_USER_ASTRONAUT \"\\xef\\x93\\xbb\"\t// U+f4fb\n#define ICON_FA_USER_CHECK \"\\xef\\x93\\xbc\"\t// U+f4fc\n#define ICON_FA_USER_CLOCK \"\\xef\\x93\\xbd\"\t// U+f4fd\n#define ICON_FA_USER_DOCTOR \"\\xef\\x83\\xb0\"\t// U+f0f0\n#define ICON_FA_USER_GEAR \"\\xef\\x93\\xbe\"\t// U+f4fe\n#define ICON_FA_USER_GRADUATE \"\\xef\\x94\\x81\"\t// U+f501\n#define ICON_FA_USER_GROUP \"\\xef\\x94\\x80\"\t// U+f500\n#define ICON_FA_USER_INJURED \"\\xef\\x9c\\xa8\"\t// U+f728\n#define ICON_FA_USER_LARGE \"\\xef\\x90\\x86\"\t// U+f406\n#define ICON_FA_USER_LARGE_SLASH \"\\xef\\x93\\xba\"\t// U+f4fa\n#define ICON_FA_USER_LOCK \"\\xef\\x94\\x82\"\t// U+f502\n#define ICON_FA_USER_MINUS \"\\xef\\x94\\x83\"\t// U+f503\n#define ICON_FA_USER_NINJA \"\\xef\\x94\\x84\"\t// U+f504\n#define ICON_FA_USER_NURSE \"\\xef\\xa0\\xaf\"\t// U+f82f\n#define ICON_FA_USER_PEN \"\\xef\\x93\\xbf\"\t// U+f4ff\n#define ICON_FA_USER_PLUS \"\\xef\\x88\\xb4\"\t// U+f234\n#define ICON_FA_USER_SECRET \"\\xef\\x88\\x9b\"\t// U+f21b\n#define ICON_FA_USER_SHIELD \"\\xef\\x94\\x85\"\t// U+f505\n#define ICON_FA_USER_SLASH \"\\xef\\x94\\x86\"\t// U+f506\n#define ICON_FA_USER_TAG \"\\xef\\x94\\x87\"\t// U+f507\n#define ICON_FA_USER_TIE \"\\xef\\x94\\x88\"\t// U+f508\n#define ICON_FA_USER_XMARK \"\\xef\\x88\\xb5\"\t// U+f235\n#define ICON_FA_USERS \"\\xef\\x83\\x80\"\t// U+f0c0\n#define ICON_FA_USERS_BETWEEN_LINES \"\\xee\\x96\\x91\"\t// U+e591\n#define ICON_FA_USERS_GEAR \"\\xef\\x94\\x89\"\t// U+f509\n#define ICON_FA_USERS_LINE \"\\xee\\x96\\x92\"\t// U+e592\n#define ICON_FA_USERS_RAYS \"\\xee\\x96\\x93\"\t// U+e593\n#define ICON_FA_USERS_RECTANGLE \"\\xee\\x96\\x94\"\t// U+e594\n#define ICON_FA_USERS_SLASH \"\\xee\\x81\\xb3\"\t// U+e073\n#define ICON_FA_USERS_VIEWFINDER \"\\xee\\x96\\x95\"\t// U+e595\n#define ICON_FA_UTENSILS \"\\xef\\x8b\\xa7\"\t// U+f2e7\n#define ICON_FA_V \"V\"\t// U+0056\n#define ICON_FA_VAN_SHUTTLE \"\\xef\\x96\\xb6\"\t// U+f5b6\n#define ICON_FA_VAULT \"\\xee\\x8b\\x85\"\t// U+e2c5\n#define ICON_FA_VECTOR_SQUARE \"\\xef\\x97\\x8b\"\t// U+f5cb\n#define ICON_FA_VENUS \"\\xef\\x88\\xa1\"\t// U+f221\n#define ICON_FA_VENUS_DOUBLE \"\\xef\\x88\\xa6\"\t// U+f226\n#define ICON_FA_VENUS_MARS \"\\xef\\x88\\xa8\"\t// U+f228\n#define ICON_FA_VEST \"\\xee\\x82\\x85\"\t// U+e085\n#define ICON_FA_VEST_PATCHES \"\\xee\\x82\\x86\"\t// U+e086\n#define ICON_FA_VIAL \"\\xef\\x92\\x92\"\t// U+f492\n#define ICON_FA_VIAL_CIRCLE_CHECK \"\\xee\\x96\\x96\"\t// U+e596\n#define ICON_FA_VIAL_VIRUS \"\\xee\\x96\\x97\"\t// U+e597\n#define ICON_FA_VIALS \"\\xef\\x92\\x93\"\t// U+f493\n#define ICON_FA_VIDEO \"\\xef\\x80\\xbd\"\t// U+f03d\n#define ICON_FA_VIDEO_SLASH \"\\xef\\x93\\xa2\"\t// U+f4e2\n#define ICON_FA_VIHARA \"\\xef\\x9a\\xa7\"\t// U+f6a7\n#define ICON_FA_VIRUS \"\\xee\\x81\\xb4\"\t// U+e074\n#define ICON_FA_VIRUS_COVID \"\\xee\\x92\\xa8\"\t// U+e4a8\n#define ICON_FA_VIRUS_COVID_SLASH \"\\xee\\x92\\xa9\"\t// U+e4a9\n#define ICON_FA_VIRUS_SLASH \"\\xee\\x81\\xb5\"\t// U+e075\n#define ICON_FA_VIRUSES \"\\xee\\x81\\xb6\"\t// U+e076\n#define ICON_FA_VOICEMAIL \"\\xef\\xa2\\x97\"\t// U+f897\n#define ICON_FA_VOLCANO \"\\xef\\x9d\\xb0\"\t// U+f770\n#define ICON_FA_VOLLEYBALL \"\\xef\\x91\\x9f\"\t// U+f45f\n#define ICON_FA_VOLUME_HIGH \"\\xef\\x80\\xa8\"\t// U+f028\n#define ICON_FA_VOLUME_LOW \"\\xef\\x80\\xa7\"\t// U+f027\n#define ICON_FA_VOLUME_OFF \"\\xef\\x80\\xa6\"\t// U+f026\n#define ICON_FA_VOLUME_XMARK \"\\xef\\x9a\\xa9\"\t// U+f6a9\n#define ICON_FA_VR_CARDBOARD \"\\xef\\x9c\\xa9\"\t// U+f729\n#define ICON_FA_W \"W\"\t// U+0057\n#define ICON_FA_WALKIE_TALKIE \"\\xef\\xa3\\xaf\"\t// U+f8ef\n#define ICON_FA_WALLET \"\\xef\\x95\\x95\"\t// U+f555\n#define ICON_FA_WAND_MAGIC \"\\xef\\x83\\x90\"\t// U+f0d0\n#define ICON_FA_WAND_MAGIC_SPARKLES \"\\xee\\x8b\\x8a\"\t// U+e2ca\n#define ICON_FA_WAND_SPARKLES \"\\xef\\x9c\\xab\"\t// U+f72b\n#define ICON_FA_WAREHOUSE \"\\xef\\x92\\x94\"\t// U+f494\n#define ICON_FA_WATER \"\\xef\\x9d\\xb3\"\t// U+f773\n#define ICON_FA_WATER_LADDER \"\\xef\\x97\\x85\"\t// U+f5c5\n#define ICON_FA_WAVE_SQUARE \"\\xef\\xa0\\xbe\"\t// U+f83e\n#define ICON_FA_WEIGHT_HANGING \"\\xef\\x97\\x8d\"\t// U+f5cd\n#define ICON_FA_WEIGHT_SCALE \"\\xef\\x92\\x96\"\t// U+f496\n#define ICON_FA_WHEAT_AWN \"\\xee\\x8b\\x8d\"\t// U+e2cd\n#define ICON_FA_WHEAT_AWN_CIRCLE_EXCLAMATION \"\\xee\\x96\\x98\"\t// U+e598\n#define ICON_FA_WHEELCHAIR \"\\xef\\x86\\x93\"\t// U+f193\n#define ICON_FA_WHEELCHAIR_MOVE \"\\xee\\x8b\\x8e\"\t// U+e2ce\n#define ICON_FA_WHISKEY_GLASS \"\\xef\\x9e\\xa0\"\t// U+f7a0\n#define ICON_FA_WIFI \"\\xef\\x87\\xab\"\t// U+f1eb\n#define ICON_FA_WIND \"\\xef\\x9c\\xae\"\t// U+f72e\n#define ICON_FA_WINDOW_MAXIMIZE \"\\xef\\x8b\\x90\"\t// U+f2d0\n#define ICON_FA_WINDOW_MINIMIZE \"\\xef\\x8b\\x91\"\t// U+f2d1\n#define ICON_FA_WINDOW_RESTORE \"\\xef\\x8b\\x92\"\t// U+f2d2\n#define ICON_FA_WINE_BOTTLE \"\\xef\\x9c\\xaf\"\t// U+f72f\n#define ICON_FA_WINE_GLASS \"\\xef\\x93\\xa3\"\t// U+f4e3\n#define ICON_FA_WINE_GLASS_EMPTY \"\\xef\\x97\\x8e\"\t// U+f5ce\n#define ICON_FA_WON_SIGN \"\\xef\\x85\\x99\"\t// U+f159\n#define ICON_FA_WORM \"\\xee\\x96\\x99\"\t// U+e599\n#define ICON_FA_WRENCH \"\\xef\\x82\\xad\"\t// U+f0ad\n#define ICON_FA_X \"X\"\t// U+0058\n#define ICON_FA_X_RAY \"\\xef\\x92\\x97\"\t// U+f497\n#define ICON_FA_XMARK \"\\xef\\x80\\x8d\"\t// U+f00d\n#define ICON_FA_XMARKS_LINES \"\\xee\\x96\\x9a\"\t// U+e59a\n#define ICON_FA_Y \"Y\"\t// U+0059\n#define ICON_FA_YEN_SIGN \"\\xef\\x85\\x97\"\t// U+f157\n#define ICON_FA_YIN_YANG \"\\xef\\x9a\\xad\"\t// U+f6ad\n#define ICON_FA_Z \"Z\"\t// U+005a\n"
  },
  {
    "path": "Assets/Font/LICENSE-bfont.ttf.txt",
    "content": "Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. Glyphs imported from Arev fonts are (c) Tavmjung Bah (see below)\n\n'DeJaVu-Lite' changes (removing characters for lighter file size) are in public domain. Source file is accompanied in this directory, BZip2 compressed, DeJaVuSans-Lite.sfd.bz2 .\n\n\nBitstream Vera Fonts Copyright\n------------------------------\n\nCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is\na trademark of Bitstream, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof the fonts accompanying this license (\"Fonts\") and associated\ndocumentation files (the \"Font Software\"), to reproduce and distribute the\nFont Software, including without limitation the rights to use, copy, merge,\npublish, distribute, and/or sell copies of the Font Software, and to permit\npersons to whom the Font Software is furnished to do so, subject to the\nfollowing conditions:\n\nThe above copyright and trademark notices and this permission notice shall\nbe included in all copies of one or more of the Font Software typefaces.\n\nThe Font Software may be modified, altered, or added to, and in particular\nthe designs of glyphs or characters in the Fonts may be modified and\nadditional glyphs or characters may be added to the Fonts, only if the fonts\nare renamed to names not containing either the words \"Bitstream\" or the word\n\"Vera\".\n\nThis License becomes null and void to the extent applicable to Fonts or Font\nSoftware that has been modified and is distributed under the \"Bitstream\nVera\" names.\n\nThe Font Software may be sold as part of a larger software package but no\ncopy of one or more of the Font Software typefaces may be sold by itself.\n\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,\nTRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME\nFOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING\nANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF\nTHE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE\nFONT SOFTWARE.\n\nExcept as contained in this notice, the names of Gnome, the Gnome\nFoundation, and Bitstream Inc., shall not be used in advertising or\notherwise to promote the sale, use or other dealings in this Font Software\nwithout prior written authorization from the Gnome Foundation or Bitstream\nInc., respectively. For further information, contact: fonts at gnome dot\norg. \n\nArev Fonts Copyright\n------------------------------\n\nCopyright (c) 2006 by Tavmjong Bah. All Rights Reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of the fonts accompanying this license (\"Fonts\") and\nassociated documentation files (the \"Font Software\"), to reproduce\nand distribute the modifications to the Bitstream Vera Font Software,\nincluding without limitation the rights to use, copy, merge, publish,\ndistribute, and/or sell copies of the Font Software, and to permit\npersons to whom the Font Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright and trademark notices and this permission notice\nshall be included in all copies of one or more of the Font Software\ntypefaces.\n\nThe Font Software may be modified, altered, or added to, and in\nparticular the designs of glyphs or characters in the Fonts may be\nmodified and additional glyphs or characters may be added to the\nFonts, only if the fonts are renamed to names not containing either\nthe words \"Tavmjong Bah\" or the word \"Arev\".\n\nThis License becomes null and void to the extent applicable to Fonts\nor Font Software that has been modified and is distributed under the \n\"Tavmjong Bah Arev\" names.\n\nThe Font Software may be sold as part of a larger software package but\nno copy of one or more of the Font Software typefaces may be sold by\nitself.\n\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL\nTAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\nOTHER DEALINGS IN THE FONT SOFTWARE.\n\nExcept as contained in this notice, the name of Tavmjong Bah shall not\nbe used in advertising or otherwise to promote the sale, use or other\ndealings in this Font Software without prior written authorization\nfrom Tavmjong Bah. For further information, contact: tavmjong @ free\n. fr.\n\n"
  },
  {
    "path": "Assets/LUT/LICENSE-MIT",
    "content": "Copyright (c) 2023 Tomasz Stachowiak\n\nPermission is hereby granted, free of charge, to any\nperson obtaining a copy of this software and associated\ndocumentation files (the \"Software\"), to deal in the\nSoftware without restriction, including without\nlimitation the rights to use, copy, modify, merge,\npublish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software\nis furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice\nshall be included in all copies or substantial portions\nof the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF\nANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\nTO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\nSHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\nIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "CMake/CompileHLSL.cmake",
    "content": "# Returns a list of included paths (if any)\nfunction(ParseIncludes DATA DIR RET)\n    string(REGEX MATCHALL \"#include[ \\t]*[\\\"]([^\\\"]+)[\\\"]\" ALL_MATCHES \"${DATA}\")\n    set(INCLUDES \"\")\n\n    foreach(INCLUDE_LINE ${ALL_MATCHES})\n        string(REGEX REPLACE \"#include[ \\t]*[\\\"]([^\\\"]+)[\\\"]\" \"\\\\1\" INCLUDED_FILE \"${INCLUDE_LINE}\")\n\n        # Skip if extension is not .hlsli, .hlsl or .h\n        get_filename_component(EX \"${INCLUDED_FILE}\" LAST_EXT)\n        if(NOT \"${EX}\" STREQUAL \".hlsli\" AND NOT \"${EX}\" STREQUAL \".hlsl\" AND NOT \"${EX}\" STREQUAL \".h\")\n            continue()\n        endif()\n\n        set(CURR_PATH \"${DIR}/${INCLUDED_FILE}\")\n\n        # Necessary in order to detect duplicate paths\n        get_filename_component(CURR_PATH_ABS \"${CURR_PATH}\" ABSOLUTE)\n\n        set(INCLUDES ${INCLUDES} \"${CURR_PATH_ABS}\")\n    endforeach()\n\n    set(${RET} ${INCLUDES} PARENT_SCOPE)\nendfunction()\n\n# DFS search to recursively find all included paths\nfunction(DFS FILE_PATH FILE_CONTENTS RET)\n    get_filename_component(CURR_DIR \"${FILE_PATH}\" DIRECTORY)\n    ParseIncludes(\"${FILE_CONTENTS}\" \"${CURR_DIR}\" INCLUDES)\n    set(ALL ${INCLUDES})\n\n    foreach(INCLUDE ${INCLUDES})\n        # Skip searching cpp headers that are not in render pass directory\n        get_filename_component(FILE_NAME \"${INCLUDE}\" LAST_EXT)\n        string(SUBSTRING \"${INCLUDE}\" 0 ${ZETA_RENDER_PASS_DIR_LEN} TEMP)\n\n        if(\"${FILE_NAME}\" STREQUAL \".h\" AND NOT \"${TEMP}\" STREQUAL \"${ZETA_RENDER_PASS_DIR}\")\n            continue()\n        endif()\n\n        file(STRINGS \"${INCLUDE}\" NEXT_FILE_CONTENTS NEWLINE_CONSUME)\n        DFS(\"${INCLUDE}\" \"${NEXT_FILE_CONTENTS}\" NEXT_INCLUDES)\n        set(ALL ${ALL} ${NEXT_INCLUDES})\n    endforeach()\n\n    # Remove duplicate paths\n    list(REMOVE_DUPLICATES ALL)\n\n    set(${RET} ${ALL} PARENT_SCOPE)\nendfunction()\n\nfunction(CompileHLSL HLSL_PATH RET)\n    # DXC compiler\n    find_program(DXC dxc PATHS \"${DXC_BIN_DIR}\" REQUIRED NO_DEFAULT_PATH)\n\n    get_filename_component(FILE_NAME_WO_EXT ${HLSL_PATH} NAME_WLE)\n    file(STRINGS \"${HLSL_PATH}\" DATA NEWLINE_CONSUME)\n    DFS(\"${HLSL_PATH}\" ${DATA} ALL_INCLUDES)\n\n    # Figure out if shader is a compute shader, DXIL lib, etc\n\n    if(COMPILE_SHADERS_WITH_DEBUG_INFO)\n        set(COMMON_ARGS \"-Qembed_debug\" \"-Qstrip_reflect\" \"-nologo\" \"-Zi\" \"-all_resources_bound\" \"-enable-16bit-types\" \"-WX\" \"-HV 202x\" \"-Wdouble-promotion\")\n    else()\n        set(COMMON_ARGS \"-Qstrip_reflect\" \"-nologo\" \"-all_resources_bound\" \"-enable-16bit-types\" \"-WX\" \"-HV 202x\" \"-Wdouble-promotion\")\n    endif()\n    \n    # Compute shader\n    set(RE_CS \"\\\\[numthreads.*\\\\][ \\t\\r\\n]*void[ \\t\\r\\n]+([a-zA-Z][A-Za-z0-9_]*)\")\n    string(REGEX MATCH ${RE_CS} MATCH ${DATA})\n\n    if(${CMAKE_MATCH_COUNT} GREATER 0)\n        set(MAIN_FUNC ${CMAKE_MATCH_1})\n        set(CSO_PATH \"${CSO_DIR}/${FILE_NAME_WO_EXT}_cs.cso\")\n\n        add_custom_command(\n            OUTPUT ${CSO_PATH}\n            COMMAND ${DXC} ${COMMON_ARGS} -T cs_6_7 -E ${MAIN_FUNC} -Fo ${CSO_PATH} ${HLSL_PATH}\n            DEPENDS ${ALL_INCLUDES} \"${HLSL_PATH}\"\n            COMMENT \"Compiling HLSL source file ${FILE_NAME_WO_EXT}.hlsl...\"\n            VERBATIM)\n\n        set(CSOS ${CSO_PATH})\n    else()\n        # RT lib\n        set(RE_DXIL \"\\\\[shader(.*)\\\\][ \\t\\r\\n]\")\n        string(REGEX MATCH ${RE_DXIL} MATCH ${DATA})\n        \n        if(${CMAKE_MATCH_COUNT} GREATER 0)\n            set(CSO_PATH \"${CSO_DIR}/${FILE_NAME_WO_EXT}_lib.cso\")\n            \n            add_custom_command(\n                OUTPUT ${CSO_PATH}\n                COMMAND ${DXC} ${COMMON_ARGS} -T lib_6_7 -Fo ${CSO_PATH} ${HLSL_PATH}\n                DEPENDS ${ALL_INCLUDES} \"${HLSL_PATH}\"\n                COMMENT \"Compiling DXIL library ${FILE_NAME_WO_EXT}.hlsl...\"\n                VERBATIM)\n\n            set(CSOS ${CSO_PATH})\n        else()\n            # Compute shader that includes another .hlsl. Further assumes included hlsl has a \"main\" entry point.\n            set(RE_INCLUDE_HLSL \"#include[ \\t]*[\\\"<]([^\\\">]+)\\\\.hlsl[\\\">]\")\n            string(REGEX MATCH ${RE_INCLUDE_HLSL} MATCH ${DATA})\n                    \n            if(${CMAKE_MATCH_COUNT} GREATER 0)\n                set(CSO_PATH \"${CSO_DIR}/${FILE_NAME_WO_EXT}_cs.cso\")\n\n                add_custom_command(\n                    OUTPUT ${CSO_PATH}\n                    COMMAND ${DXC} ${COMMON_ARGS} -T cs_6_7 -E main -Fo ${CSO_PATH} ${HLSL_PATH}\n                    DEPENDS ${ALL_INCLUDES} \"${HLSL_PATH}\"\n                    COMMENT \"Compiling HLSL source file ${FILE_NAME_WO_EXT}.hlsl...\"\n                    VERBATIM)\n        \n                set(CSOS ${CSO_PATH})\n            # VS-PS\n            else()\n                # Vertex shader\n                set(CSO_PATH_VS ${CSO_DIR}/${FILE_NAME_WO_EXT}_vs.cso)\n                # Pixel shader\n                set(CSO_PATH_PS ${CSO_DIR}/${FILE_NAME_WO_EXT}_ps.cso)\n                \n                add_custom_command(\n                    OUTPUT ${CSO_PATH_VS} ${CSO_PATH_PS}\n                    COMMAND ${DXC} ${COMMON_ARGS} -T vs_6_7 -E mainVS -Fo ${CSO_PATH_VS} ${HLSL_PATH}\n                    COMMAND ${DXC} ${COMMON_ARGS} -T ps_6_7 -E mainPS -Fo ${CSO_PATH_PS} ${HLSL_PATH}\n                    DEPENDS ${ALL_INCLUDES} \"${HLSL_PATH}\"\n                    COMMENT \"Compiling HLSL source file ${FILE_NAME_WO_EXT}.hlsl...\"\n                    VERBATIM)\n\n                set(CSOS ${CSO_PATH_VS} ${CSO_PATH_PS})\n            endif()\n        endif()\n    endif()\n\n    set(${RET} ${CSOS} PARENT_SCOPE)\nendfunction()"
  },
  {
    "path": "CMake/Copy.cmake",
    "content": "function(Copy FILES DEST TARGET_NAME)\n    foreach(FULL_FILENAME ${FILES})\n        get_filename_component(FILE ${FULL_FILENAME} NAME)\n        add_custom_command(\n            OUTPUT ${DEST}/${FILE}\n            COMMAND ${CMAKE_COMMAND} -E make_directory ${DEST}\n            COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FULL_FILENAME} ${DEST}\n            MAIN_DEPENDENCY ${FULL_FILENAME}\n            COMMENT \"Copying ${FILE} into ${DEST}...\" )\n        list(APPEND ALL_DESTS ${DEST}/${FILE})\n    endforeach()\n\n    add_custom_target(${TARGET_NAME} DEPENDS \"${ALL_DESTS}\")\n    set_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"CopyTargets\")\nendfunction()"
  },
  {
    "path": "CMake/SetBuildConfigurations.cmake",
    "content": "get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)\nif(isMultiConfig)\n    set(CMAKE_CONFIGURATION_TYPES \"Debug;Release;\" CACHE STRING \"\" FORCE) \nendif()"
  },
  {
    "path": "CMake/SetupAgilitySDK.cmake",
    "content": "function(SetupAgilitySDK SDK_VERSION)\n    set(VER \"1.615.0\")\n    set(SDK_DIR \"${EXTERNAL_DIR}/D3D12/${VER}\")\n\n    file(GLOB_RECURSE CORE_DLL_PATH \"${SDK_DIR}/*D3D12Core.dll\")\n    \n    if(CORE_DLL_PATH STREQUAL \"\")\n        file(MAKE_DIRECTORY ${SDK_DIR})\n\n        # download from nuget\n        set(URL \"https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/${VER}\")\n        message(STATUS \"Downloading Agility SDK from ${URL}...\")\n        set(ARCHIVE_PATH \"${SDK_DIR}/temp/agility.zip\")\n        file(DOWNLOAD \"${URL}\" \"${ARCHIVE_PATH}\" TIMEOUT 120)       \n        file(ARCHIVE_EXTRACT INPUT \"${ARCHIVE_PATH}\" DESTINATION \"${SDK_DIR}/temp\")\n        \n        # remove d3dx12\n        file(REMOVE_RECURSE \"${SDK_DIR}/temp/build/native/include/d3dx12\")\n        # copy headers\n        file(GLOB_RECURSE SDK_HEADERS \"${SDK_DIR}/temp/build/native/include/*.h\")\n        file(COPY ${SDK_HEADERS} DESTINATION ${SDK_DIR})\n        \n        if(SDK_HEADERS STREQUAL \"\")\n            message(FATAL_ERROR \"Setting up Agility SDK failed.\")\n        endif()\n\n        # copy binaries\n        set(DLLS\n            \"${SDK_DIR}/temp/build/native/bin/x64/D3D12Core.dll\"\n            \"${SDK_DIR}/temp/build/native/bin/x64/d3d12SDKLayers.dll\")\n        \n        file(COPY ${DLLS} DESTINATION ${SDK_DIR})\n\n        # cleanup\n        file(REMOVE_RECURSE \"${SDK_DIR}/temp\")\n    endif()\n\n    set(${SDK_VERSION} ${VER} PARENT_SCOPE)\nendfunction()"
  },
  {
    "path": "CMake/SetupDXC.cmake",
    "content": "function(SetupDXC DXC_BIN_DIR)\n    set(DXC_DIR \"${TOOLS_DIR}/dxc\")\n    file(GLOB_RECURSE DXC_BIN_PATH \"${DXC_DIR}/*dxc.exe\")\n\n    # if(NOT EXISTS \"${DXC_BIN_DIR}\")\n    if(DXC_BIN_PATH STREQUAL \"\")\n        set(URL \"https://github.com/microsoft/DirectXShaderCompiler/releases/download/v1.8.2405/dxc_2024_05_24_clang_cl.zip\")\n        message(STATUS \"Downloading DXC from ${URL}...\")\n        set(ARCHIVE_PATH \"${TOOLS_DIR}/dxc.zip\")\n        file(DOWNLOAD \"${URL}\" \"${ARCHIVE_PATH}\" TIMEOUT 120)\n\n        file(ARCHIVE_EXTRACT INPUT \"${ARCHIVE_PATH}\" DESTINATION \"${DXC_DIR}\")\n        file(REMOVE_RECURSE \"${DXC_DIR}/bin/arm64\")\n        file(REMOVE_RECURSE \"${DXC_DIR}/bin/x86\")\n        file(REMOVE_RECURSE \"${DXC_DIR}/lib\")\n        file(REMOVE_RECURSE \"${DXC_DIR}/inc\")\n        file(REMOVE \"${ARCHIVE_PATH}\")\n\n        file(GLOB_RECURSE DXC_BIN_PATH \"${DXC_DIR}/*dxc.exe\")\n\n        if(DXC_BIN_PATH STREQUAL \"\")\n            message(FATAL_ERROR \"Setting up DXC failed.\")\n        endif()\n    endif()\n\n    get_filename_component(PARENT_DIR ${DXC_BIN_PATH} DIRECTORY)\n    set(${DXC_BIN_DIR} ${PARENT_DIR} PARENT_SCOPE)\nendfunction()"
  },
  {
    "path": "CMake/SetupDoctest.cmake",
    "content": "function(SetupDoctest)\n    set(DOCTEST_DIR \"${EXTERNAL_DIR}/doctest\")\n    file(GLOB_RECURSE HEADER_PATH \"${DOCTEST_DIR}/doctest.h\")\n\n    if(HEADER_PATH STREQUAL \"\")\n        file(MAKE_DIRECTORY ${DOCTEST_DIR})\n        set(URL \"https://github.com/doctest/doctest/releases/download/v2.4.11/doctest.h\")\n        message(STATUS \"Downloading doctest 2.4.11 from ${URL}...\")\n        file(DOWNLOAD \"${URL}\" \"${DOCTEST_DIR}/doctest.h\" TIMEOUT 60)\n    endif()   \nendfunction()"
  },
  {
    "path": "CMake/SetupImGui.cmake",
    "content": "function(SetupImGui)\n    set(IMGUI_VER \"1.91.6\")\n    set(IMPLOT_COMMIT \"47522f47054d33178e7defa780042bd2a06b09f9\")\n    set(IMNODES_COMMIT \"8563e1655bd9bb1f249e6552cc6274d506ee788b\")\n    set(IMGUI_DIR \"${EXTERNAL_DIR}/ImGui\")\n    file(GLOB_RECURSE IMGUI_HEADER_PATH \"${IMGUI_DIR}/*imgui.h\")\n    file(GLOB_RECURSE IMPLOT_HEADER_PATH \"${IMGUI_DIR}/*implot.h\")\n    file(GLOB_RECURSE IMNODES_HEADER_PATH \"${IMGUI_DIR}/*imnodes.h\")\n\n    if(IMGUI_HEADER_PATH STREQUAL \"\")\n        # download ImGui source code\n        set(URL \"https://github.com/ocornut/imgui/archive/refs/tags/v${IMGUI_VER}.zip\")\n        message(STATUS \"Downloading ImGui ${IMGUI_VER} from ${URL}...\")\n        set(ARCHIVE_PATH \"${IMGUI_DIR}/temp/imgui.zip\")\n        file(DOWNLOAD \"${URL}\" \"${ARCHIVE_PATH}\" TIMEOUT 120)       \n        file(ARCHIVE_EXTRACT INPUT \"${ARCHIVE_PATH}\" DESTINATION \"${IMGUI_DIR}/temp\")\n\n        # copy to ImGui directory\n        set(FILES \n            \"${IMGUI_DIR}/temp/imgui-${IMGUI_VER}/imgui_draw.cpp\"\n            \"${IMGUI_DIR}/temp/imgui-${IMGUI_VER}/imgui_internal.h\"\n            \"${IMGUI_DIR}/temp/imgui-${IMGUI_VER}/imgui_tables.cpp\"\n            \"${IMGUI_DIR}/temp/imgui-${IMGUI_VER}/imgui_widgets.cpp\"\n            \"${IMGUI_DIR}/temp/imgui-${IMGUI_VER}/imgui.cpp\"\n            \"${IMGUI_DIR}/temp/imgui-${IMGUI_VER}/imgui.h\"\n            \"${IMGUI_DIR}/temp/imgui-${IMGUI_VER}/imstb_rectpack.h\"\n            \"${IMGUI_DIR}/temp/imgui-${IMGUI_VER}/imstb_textedit.h\"\n            \"${IMGUI_DIR}/temp/imgui-${IMGUI_VER}/imstb_truetype.h\")\n\n        file(COPY ${FILES} DESTINATION ${IMGUI_DIR})\n\n        # cleanup\n        file(REMOVE_RECURSE \"${IMGUI_DIR}/temp\")\n    endif()\n\n    if(IMPLOT_HEADER_PATH STREQUAL \"\")\n        # download ImPlot source code\n        set(URL \"https://github.com/epezent/implot/archive/${IMPLOT_COMMIT}.zip\")\n        message(STATUS \"Downloading ImPlot from ${URL}...\")\n        set(ARCHIVE_PATH \"${IMGUI_DIR}/temp/implot.zip\")\n        file(DOWNLOAD \"${URL}\" \"${ARCHIVE_PATH}\" TIMEOUT 120)       \n        file(ARCHIVE_EXTRACT INPUT \"${ARCHIVE_PATH}\" DESTINATION \"${IMGUI_DIR}/temp\")\n\n        # copy to ImGui directory\n        set(FILES \n            \"${IMGUI_DIR}/temp/implot-${IMPLOT_COMMIT}/implot_internal.h\"\n            \"${IMGUI_DIR}/temp/implot-${IMPLOT_COMMIT}/implot_items.cpp\"\n            \"${IMGUI_DIR}/temp/implot-${IMPLOT_COMMIT}/implot.cpp\"\n            \"${IMGUI_DIR}/temp/implot-${IMPLOT_COMMIT}/implot.h\")\n\n        file(COPY ${FILES} DESTINATION ${IMGUI_DIR})\n\n        # cleanup\n        file(REMOVE_RECURSE \"${IMGUI_DIR}/temp\")\n    endif()\n\n    if(IMNODES_HEADER_PATH STREQUAL \"\")\n        # download imnodes source code\n        set(URL \"https://github.com/Nelarius/imnodes/archive/${IMNODES_COMMIT}.zip\")\n        message(STATUS \"Downloading imnodes from ${URL}...\")\n        set(ARCHIVE_PATH \"${IMGUI_DIR}/temp/imnodes.zip\")\n        file(DOWNLOAD \"${URL}\" \"${ARCHIVE_PATH}\" TIMEOUT 120)       \n        file(ARCHIVE_EXTRACT INPUT \"${ARCHIVE_PATH}\" DESTINATION \"${IMGUI_DIR}/temp\")\n\n        # copy to ImGui directory\n        set(FILES \n            \"${IMGUI_DIR}/temp/imnodes-${IMNODES_COMMIT}/imnodes_internal.h\"\n            \"${IMGUI_DIR}/temp/imnodes-${IMNODES_COMMIT}/imnodes.cpp\"\n            \"${IMGUI_DIR}/temp/imnodes-${IMNODES_COMMIT}/imnodes.h\")\n\n        file(COPY ${FILES} DESTINATION ${IMGUI_DIR})\n\n        # cleanup\n        file(REMOVE_RECURSE \"${IMGUI_DIR}/temp\")\n    endif()   \nendfunction()"
  },
  {
    "path": "CMake/SetupWinPIX.cmake",
    "content": "function(SetupWinPIX)\n    set(PIX_DIR \"${EXTERNAL_DIR}/WinPixEventRuntime\")\n    file(GLOB_RECURSE DLL_PATH \"${PIX_DIR}/*WinPixEventRuntime.dll\")\n\n    if(DLL_PATH STREQUAL \"\")\n        file(MAKE_DIRECTORY ${PIX_DIR})\n\n        # download from nuget\n        set(URL \"https://www.nuget.org/api/v2/package/WinPixEventRuntime/1.0.231030001\")\n        message(STATUS \"Downloading WinPixEventRuntime from ${URL}...\")\n        set(ARCHIVE_PATH \"${PIX_DIR}/temp/pix.zip\")\n        file(DOWNLOAD \"${URL}\" \"${ARCHIVE_PATH}\" TIMEOUT 120)        \n        file(ARCHIVE_EXTRACT INPUT \"${ARCHIVE_PATH}\" DESTINATION \"${PIX_DIR}/temp\")\n\n        # copy headers\n        file(GLOB_RECURSE PIX_HEADERS \"${PIX_DIR}/temp/include/*.h\")\n        file(COPY ${PIX_HEADERS} DESTINATION ${PIX_DIR})\n        \n        if(PIX_HEADERS STREQUAL \"\")\n            message(FATAL_ERROR \"Setting up WinPixEventRuntime failed.\")\n        endif()\n\n        # copy binaries\n        set(BINS\n            \"${PIX_DIR}/temp/bin/x64/WinPixEventRuntime.dll\"\n            \"${PIX_DIR}/temp/bin/x64/WinPixEventRuntime.lib\")\n\n        file(COPY ${BINS} DESTINATION ${PIX_DIR})\n\n        # cleanup\n        file(REMOVE_RECURSE \"${PIX_DIR}/temp\")\n    endif()\nendfunction()"
  },
  {
    "path": "CMake/Setupcgltf.cmake",
    "content": "function(Setupcgltf)\n    set(CGLTF_DIR \"${EXTERNAL_DIR}/cgltf\")\n    file(GLOB_RECURSE HEADER_PATH \"${CGLTF_DIR}/cgltf.h\")\n    file(GLOB_RECURSE HEADER_PATH_WRITE \"${CGLTF_DIR}/cgltf_write.h\")\n    set(CGLTF_VER \"1.14\")\n\n    if(HEADER_PATH STREQUAL \"\" OR HEADER_PATH_WRITE STREQUAL \"\")\n        file(MAKE_DIRECTORY ${CGLTF_DIR})\n\n        # download\n        set(URL \"https://github.com/jkuhlmann/cgltf/archive/refs/tags/v${CGLTF_VER}.zip\")\n        message(STATUS \"Downloading cgltf ${CGLTF_VER} from ${URL}...\")\n        set(ARCHIVE_PATH \"${CGLTF_DIR}/temp/cgltf.zip\")\n        file(DOWNLOAD \"${URL}\" \"${ARCHIVE_PATH}\" TIMEOUT 120)\n        file(ARCHIVE_EXTRACT INPUT \"${ARCHIVE_PATH}\" DESTINATION \"${CGLTF_DIR}/temp\")\n\n        # copy headers\n        file(GLOB_RECURSE HEADER \"${CGLTF_DIR}/temp/*cgltf*.h\")\n        file(COPY ${HEADER} DESTINATION ${CGLTF_DIR})\n            \n        if(HEADER STREQUAL \"\")\n            message(FATAL_ERROR \"Setting up cgltf failed.\")\n        endif()\n\n        # cleanup\n        file(REMOVE_RECURSE \"${CGLTF_DIR}/temp\")\n    endif()   \nendfunction()"
  },
  {
    "path": "CMake/SetupxxHash.cmake",
    "content": "function(SetupxxHash)\n    set(XXHASH_DIR \"${EXTERNAL_DIR}/xxHash\")\n    file(GLOB_RECURSE HEADER_PATH \"${XXHASH_DIR}/xxHash.h\")\n\n    if(HEADER_PATH STREQUAL \"\")\n        file(MAKE_DIRECTORY ${XXHASH_DIR})\n\n        # download\n        set(URL \"https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.1.zip\")\n        message(STATUS \"Downloading xxHash 0.8.1 from ${URL}...\")\n        set(ARCHIVE_PATH \"${XXHASH_DIR}/temp/xxhash.zip\")\n        file(DOWNLOAD \"${URL}\" \"${ARCHIVE_PATH}\" TIMEOUT 120)        \n        file(ARCHIVE_EXTRACT INPUT \"${ARCHIVE_PATH}\" DESTINATION \"${XXHASH_DIR}/temp\")\n\n        # copy header\n        file(GLOB_RECURSE HEADER \"${XXHASH_DIR}/temp/*xxhash.h\")\n        file(COPY ${HEADER} DESTINATION ${XXHASH_DIR})\n\n        if(HEADER STREQUAL \"\")\n            message(FATAL_ERROR \"Setting up xxHash failed.\")\n        endif()\n\n        # cleanup\n        file(REMOVE_RECURSE \"${XXHASH_DIR}/temp\")\n    endif()   \nendfunction()"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.21)\n\n# Enable building custom commands by Visual Studio in parallel. Introduced in CMake 3.27.\nif(${CMAKE_VERSION} VERSION_GREATER_EQUAL \"3.27\")\n    cmake_policy(SET CMP0147 NEW)\nendif()\n\nset(CMAKE_INCLUDE_DIR \"${CMAKE_SOURCE_DIR}/CMake\")\ninclude(\"${CMAKE_INCLUDE_DIR}/SetBuildConfigurations.cmake\")\ninclude(\"${CMAKE_INCLUDE_DIR}/SetupDXC.cmake\")\n\nproject(ZetaRay\n    LANGUAGES CXX\n    DESCRIPTION \"Real-time Direct3D 12 path tracer\")\n\noption(BUILD_TESTS \"Build unit tests\" OFF)\noption(BUILD_TOOLS \"Build tools\" ON)\noption(COMPILE_SHADERS_WITH_DEBUG_INFO \"Compile shaders with debug information (-Zi in dxc)\" OFF)\n\n# set output directories\nset(CMAKE_SUPPRESS_REGENERATION true)\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"${CMAKE_SOURCE_DIR}/bin\")\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\nset(CMAKE_LIBRARY_OUTPUT_DIRECTORY \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\nset(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\nset(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\nset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\nset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\nset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\n# append 'd' to debug targets\nset(CMAKE_DEBUG_POSTFIX \"d\")\n\n# enable folders for code organization\nset_property(GLOBAL PROPERTY USE_FOLDERS ON)\n\n# if(MSVC)\n#     # generate pdb files for the release build (off by default)\n#     add_compile_options(\"$<$<CONFIG:RELEASE>:/Zi>\")\n#     add_link_options(\"$<$<CONFIG:RELEASE>:/DEBUG>\")\n# endif()\n\n# \n# compiler options\n# \nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\nset(CMAKE_COMPILE_WARNING_AS_ERROR ON)\n\nif(MSVC)\n    if(MSVC_TOOLSET_VERSION VERSION_LESS 142)\n        message(FATAL_ERROR \"MSVC toolset version 142 or greater is required.\")\n    endif()\n\n    # disable exceptions\n    string(REPLACE \"/EHsc\" \"\" NEW_CXX_FLAGS ${CMAKE_CXX_FLAGS})\n    set(CMAKE_CXX_FLAGS ${NEW_CXX_FLAGS} CACHE STRING \"\" FORCE) \n    # disable runtime checks\n    string(REPLACE \"/RTC1\" \"\" NEW_CXX_DBG_FLAGS ${CMAKE_CXX_FLAGS_DEBUG})\n    set(CMAKE_CXX_FLAGS_DEBUG ${NEW_CXX_DBG_FLAGS} CACHE STRING \"\" FORCE)\n    # multi-processor compilation\n    add_compile_options(/MP)\n    # warning level\n    add_compile_options(/W4)\n    # enable intrinsic functions\n    add_compile_options(/Oi)\n    add_compile_options(\"$<$<CONFIG:DEBUG>:/Ob1>\")\n    # disable RTTI\n    add_compile_options(/GR-)\n    # precise floating point\n    add_compile_options(/fp:precise)\n    # standards conformance\n    add_compile_options(/permissive-)\n    add_compile_options(/arch:AVX2)\n\n    # disable a few MSVC warnings\n    if (NOT CMAKE_CXX_COMPILER_ID STREQUAL \"Clang\")\n        # _CRT_SECURE_NO_WARNINGS\n        add_compile_options(/wd4996)\n        # unreferenced local variable\n        add_compile_options(/wd4101)\n        # unreferenced formal parameter\n        add_compile_options(/wd4100)\n        # local variable is initialized but not referenced\n        add_compile_options(/wd4189)\n        # structure was padded due to alignment specifier\n        add_compile_options(/wd4324)\n    endif()\n\n    add_compile_definitions(\"ZETA_HAS_NO_UNIQUE_ADDRESS\")\nendif()\n\nif (CMAKE_CXX_COMPILER_ID STREQUAL \"Clang\")\n    add_compile_options(-Wno-unused-parameter)\n    add_compile_options(-Wno-deprecated-declarations)\n    add_compile_options(-Wno-reorder-ctor)\n    add_compile_options(-Wno-unused-variable)\n    add_compile_options(-Wno-unused-but-set-variable)\n    add_compile_options(-Wno-sign-compare)\n    add_compile_options(-Wno-missing-braces)\n    add_compile_options(-Wno-unused-local-typedef)\n    add_compile_options(-Wno-unused-function)\n    add_compile_options(-Wno-unused-private-field)\n\n    if (${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER_EQUAL 18)\n        add_compile_options(-Wno-nan-infinity-disabled)\n        add_compile_definitions(\"ZETA_HAS_NO_UNIQUE_ADDRESS\")\n    endif()\n\n    # Echo the currently compiled filename\n    if (${CMAKE_CXX_SIMULATE_ID} STREQUAL MSVC)\n        set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /showFilenames\")\n    endif()\nendif()\n\n# \n# common paths\n# \nset(EXTERNAL_DIR \"${CMAKE_SOURCE_DIR}/External\")\nset(TOOLS_DIR \"${CMAKE_SOURCE_DIR}/Tools\")\nset(ZETA_CORE_DIR \"${CMAKE_SOURCE_DIR}/Source/ZetaCore\")\nset(ZETA_RENDER_PASS_DIR \"${CMAKE_SOURCE_DIR}/Source/ZetaRenderPass\")\nstring(LENGTH \"${ZETA_RENDER_PASS_DIR}\" ZETA_RENDER_PASS_DIR_LEN)\nset(ZETA_RENDERER_DIR \"${CMAKE_SOURCE_DIR}/Source/ZetaRenderer\")\nset(ASSET_DIR \"${CMAKE_SOURCE_DIR}/Assets\")\nset(CSO_DIR \"${ASSET_DIR}/CSO\")\n\n# \n# setup DXC\n# \nSetupDXC(DXC_BIN_DIR)\n\nadd_subdirectory(Source)\n\nif(BUILD_TESTS)\n    add_subdirectory(Tests)\nendif()\n\nif(BUILD_TOOLS)\n    add_subdirectory(Tools)\nendif()"
  },
  {
    "path": "External/FSR2/Include/dx12/shaders/ffx_fsr2_shaders_dx12.h",
    "content": "// This file is part of the FidelityFX SDK.\n//\n// Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n#pragma once\n\n#include <stdint.h>\n#include \"../../ffx_fsr2_interface.h\"\n\n#if defined(__cplusplus)\nextern \"C\" {\n#endif // #if defined(__cplusplus)\n\n// A single shader blob and a description of its resources.\ntypedef struct Fsr2ShaderBlobDX12 {\n\n    const uint8_t*  data;               // A pointer to the blob \n    uint32_t        size;               // Size in bytes.\n    uint32_t        uavCount;           // Number of UAV.\n    uint32_t        srvCount;           // Number of SRV.\n    uint32_t        cbvCount;           // Number of CBs.\n    const char**    boundUAVResourceNames;\n    const uint32_t* boundUAVResources;  // Pointer to an array of bound UAV resources.\n    const char**    boundSRVResourceNames;\n    const uint32_t* boundSRVResources;  // Pointer to an array of bound SRV resources.\n    const char**    boundCBVResourceNames;\n    const uint32_t* boundCBVResources;   // Pointer to an array of bound ConstantBuffers.\n} Fsr2ShaderBlobDX12;\n\n// The different options which contribute to permutations.\ntypedef enum Fs2ShaderPermutationOptionsDX12 {\n\n    FSR2_SHADER_PERMUTATION_USE_LANCZOS_TYPE        = (1<<0),    // FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE. Off means reference, On means LUT\n    FSR2_SHADER_PERMUTATION_HDR_COLOR_INPUT         = (1<<1),    // FFX_FSR2_OPTION_HDR_COLOR_INPUT\n    FSR2_SHADER_PERMUTATION_LOW_RES_MOTION_VECTORS  = (1<<2),    // FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS\n    FSR2_SHADER_PERMUTATION_JITTER_MOTION_VECTORS   = (1<<3),    // FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS\n    FSR2_SHADER_PERMUTATION_DEPTH_INVERTED          = (1<<4),    // FFX_FSR2_OPTION_INVERTED_DEPTH\n    FSR2_SHADER_PERMUTATION_ENABLE_SHARPENING       = (1<<5),    // FFX_FSR2_OPTION_APPLY_SHARPENING\n    FSR2_SHADER_PERMUTATION_FORCE_WAVE64            = (1<<6),    // doesn't map to a define, selects different table\n    FSR2_SHADER_PERMUTATION_ALLOW_FP16              = (1<<7),    // FFX_USE_16BIT\n} Fs2ShaderPermutationOptionsDX12;\n\n// Get a DX12 shader blob for the specified pass and permutation index.\nFFX_API Fsr2ShaderBlobDX12 fsr2GetPermutationBlobByIndexDX12(FfxFsr2Pass passId, uint32_t permutationOptions);\n\n#if defined(__cplusplus)\n}\n#endif // #if defined(__cplusplus)\n"
  },
  {
    "path": "External/FSR2/Include/ffx_assert.h",
    "content": "// This file is part of the FidelityFX SDK.\n//\n// Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n#pragma once\n\n#include \"ffx_types.h\"\n#include \"ffx_util.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // #ifdef __cplusplus\n\n#ifdef _DEBUG\n#ifdef _WIN32\n\n#ifdef DISABLE_FFX_DEBUG_BREAK\n#define FFX_DEBUG_BREAK \\\n    {                   \\\n    }\n#else\n/// Macro to force the debugger to break at this point in the code.\n#define FFX_DEBUG_BREAK __debugbreak();\n#endif\n#else\n#define FFX_DEBUG_BREAK \\\n    {                   \\\n    }\n#endif\n#else\n// don't allow debug break in release builds.\n#define FFX_DEBUG_BREAK\n#endif\n\n/// A typedef for the callback function for assert printing.\n///\n/// This can be used to re-route printing of assert messages from the FFX backend\n/// to another destination. For example instead of the default behaviour of printing\n/// the assert messages to the debugger's TTY the message can be re-routed to a\n/// MessageBox in a GUI application.\n///\n/// @param [in] message                 The message generated by the assert.\n///\ntypedef void (*FfxAssertCallback)(const char* message);\n\n/// Function to report an assert.\n///\n/// @param [in] file                    The name of the file as a string.\n/// @param [in] line                    The index of the line in the file.\n/// @param [in] condition               The boolean condition that was tested.\n/// @param [in] msg                     The optional message to print.\n///\n/// @returns\n/// Always returns true.\n///\nFFX_API bool ffxAssertReport(const char* file, int32_t line, const char* condition, const char* msg);\n\n/// Provides the ability to set a callback for assert messages.\n///\n/// @param [in] callback                The callback function that will receive assert messages.\n///\nFFX_API void ffxAssertSetPrintingCallback(FfxAssertCallback callback);\n\n#ifdef _DEBUG\n/// Standard assert macro.\n#define FFX_ASSERT(condition)                                                      \\\n    do                                                                             \\\n    {                                                                              \\\n        if (!(condition) && ffxAssertReport(__FILE__, __LINE__, #condition, NULL)) \\\n            FFX_DEBUG_BREAK                                                        \\\n    } while (0)\n\n/// Assert macro with message.\n#define FFX_ASSERT_MESSAGE(condition, msg)                                        \\\n    do                                                                            \\\n    {                                                                             \\\n        if (!(condition) && ffxAssertReport(__FILE__, __LINE__, #condition, msg)) \\\n            FFX_DEBUG_BREAK                                                       \\\n    } while (0)\n\n/// Assert macro that always fails.\n#define FFX_ASSERT_FAIL(message)                            \\\n    do                                                      \\\n    {                                                       \\\n        ffxAssertReport(__FILE__, __LINE__, NULL, message); \\\n        FFX_DEBUG_BREAK                                     \\\n    } while (0)\n#else\n// asserts disabled\n#define FFX_ASSERT(condition)  \\\n    do                         \\\n    {                          \\\n        FFX_UNUSED(condition); \\\n    } while (0)\n\n#define FFX_ASSERT_MESSAGE(condition, message) \\\n    do                                         \\\n    {                                          \\\n        FFX_UNUSED(condition);                 \\\n        FFX_UNUSED(message);                   \\\n    } while (0)\n\n#define FFX_ASSERT_FAIL(message) \\\n    do                           \\\n    {                            \\\n        FFX_UNUSED(message);     \\\n    } while (0)\n#endif  // #if _DEBUG\n\n/// Simple static assert.\n#define FFX_STATIC_ASSERT(condition) static_assert(condition, #condition)\n\n#ifdef __cplusplus\n}\n#endif  // #ifdef __cplusplus\n"
  },
  {
    "path": "External/FSR2/Include/ffx_error.h",
    "content": "// This file is part of the FidelityFX SDK.\n//\n// Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n#pragma once\n\n#include \"ffx_types.h\"\n\n/// Typedef for error codes returned from functions in the FidelityFX SDK.\ntypedef int32_t FfxErrorCode;\n\nstatic const FfxErrorCode FFX_OK                            = 0;           ///< The operation completed successfully.\nstatic const FfxErrorCode FFX_ERROR_INVALID_POINTER         = 0x80000000;  ///< The operation failed due to an invalid pointer.\nstatic const FfxErrorCode FFX_ERROR_INVALID_ALIGNMENT       = 0x80000001;  ///< The operation failed due to an invalid alignment.\nstatic const FfxErrorCode FFX_ERROR_INVALID_SIZE            = 0x80000002;  ///< The operation failed due to an invalid size.\nstatic const FfxErrorCode FFX_EOF                           = 0x80000003;  ///< The end of the file was encountered.\nstatic const FfxErrorCode FFX_ERROR_INVALID_PATH            = 0x80000004;  ///< The operation failed because the specified path was invalid.\nstatic const FfxErrorCode FFX_ERROR_EOF                     = 0x80000005;  ///< The operation failed because end of file was reached.\nstatic const FfxErrorCode FFX_ERROR_MALFORMED_DATA          = 0x80000006;  ///< The operation failed because of some malformed data.\nstatic const FfxErrorCode FFX_ERROR_OUT_OF_MEMORY           = 0x80000007;  ///< The operation failed because it ran out memory.\nstatic const FfxErrorCode FFX_ERROR_INCOMPLETE_INTERFACE    = 0x80000008;  ///< The operation failed because the interface was not fully configured.\nstatic const FfxErrorCode FFX_ERROR_INVALID_ENUM            = 0x80000009;  ///< The operation failed because of an invalid enumeration value.\nstatic const FfxErrorCode FFX_ERROR_INVALID_ARGUMENT        = 0x8000000a;  ///< The operation failed because an argument was invalid.\nstatic const FfxErrorCode FFX_ERROR_OUT_OF_RANGE            = 0x8000000b;  ///< The operation failed because a value was out of range.\nstatic const FfxErrorCode FFX_ERROR_NULL_DEVICE             = 0x8000000c;  ///< The operation failed because a device was null.\nstatic const FfxErrorCode FFX_ERROR_BACKEND_API_ERROR       = 0x8000000d;  ///< The operation failed because the backend API returned an error code.\nstatic const FfxErrorCode FFX_ERROR_INSUFFICIENT_MEMORY     = 0x8000000e;  ///< The operation failed because there was not enough memory.\n\n/// Helper macro to return error code y from a function when a specific condition, x, is not met.\n#define FFX_RETURN_ON_ERROR(x, y)                   \\\n    if (!(x))                                       \\\n    {                                               \\\n        return (y);                                 \\\n    }\n\n/// Helper macro to return error code x from a function when it is not FFX_OK.\n#define FFX_VALIDATE(x)                             \\\n    {                                               \\\n        FfxErrorCode ret = x;                       \\\n        FFX_RETURN_ON_ERROR(ret == FFX_OK, ret);    \\\n    }\n\n"
  },
  {
    "path": "External/FSR2/Include/ffx_fsr2.h",
    "content": "// This file is part of the FidelityFX SDK.\n//\n// Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n\n// @defgroup FSR2\n\n#pragma once\n\n// Include the interface for the backend of the FSR2 API.\n#include \"ffx_fsr2_interface.h\"\n\n/// FidelityFX Super Resolution 2 major version.\n///\n/// @ingroup FSR2\n#define FFX_FSR2_VERSION_MAJOR      (2)\n\n/// FidelityFX Super Resolution 2 minor version.\n///\n/// @ingroup FSR2\n#define FFX_FSR2_VERSION_MINOR      (2)\n\n/// FidelityFX Super Resolution 2 patch version.\n///\n/// @ingroup FSR2\n#define FFX_FSR2_VERSION_PATCH      (0)\n\n/// The size of the context specified in 32bit values.\n///\n/// @ingroup FSR2\n#define FFX_FSR2_CONTEXT_SIZE       (16536)\n\n#if defined(__cplusplus)\nextern \"C\" {\n#endif // #if defined(__cplusplus)\n\n/// An enumeration of all the quality modes supported by FidelityFX Super\n/// Resolution 2 upscaling.\n///\n/// In order to provide a consistent user experience across multiple\n/// applications which implement FSR2. It is strongly recommended that the\n/// following preset scaling factors are made available through your\n/// application's user interface.\n///\n/// If your application does not expose the notion of preset scaling factors\n/// for upscaling algorithms (perhaps instead implementing a fixed ratio which\n/// is immutable) or implementing a more dynamic scaling scheme (such as\n/// dynamic resolution scaling), then there is no need to use these presets.\n///\n/// Please note that <c><i>FFX_FSR2_QUALITY_MODE_ULTRA_PERFORMANCE</i></c> is\n/// an optional mode which may introduce significant quality degradation in the\n/// final image. As such it is recommended that you evaluate the final results\n/// of using this scaling mode before deciding if you should include it in your\n/// application.\n///\n/// @ingroup FSR2\ntypedef enum FfxFsr2QualityMode {\n\n    FFX_FSR2_QUALITY_MODE_QUALITY                       = 1,        ///< Perform upscaling with a per-dimension upscaling ratio of 1.5x.\n    FFX_FSR2_QUALITY_MODE_BALANCED                      = 2,        ///< Perform upscaling with a per-dimension upscaling ratio of 1.7x.\n    FFX_FSR2_QUALITY_MODE_PERFORMANCE                   = 3,        ///< Perform upscaling with a per-dimension upscaling ratio of 2.0x.\n    FFX_FSR2_QUALITY_MODE_ULTRA_PERFORMANCE             = 4         ///< Perform upscaling with a per-dimension upscaling ratio of 3.0x.\n} FfxFsr2QualityMode;\n\n/// An enumeration of bit flags used when creating a\n/// <c><i>FfxFsr2Context</i></c>. See <c><i>FfxFsr2ContextDescription</i></c>.\n///\n/// @ingroup FSR2\ntypedef enum FfxFsr2InitializationFlagBits {\n\n    FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE                  = (1<<0),   ///< A bit indicating if the input color data provided is using a high-dynamic range.\n    FFX_FSR2_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS   = (1<<1),   ///< A bit indicating if the motion vectors are rendered at display resolution.\n    FFX_FSR2_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION  = (1<<2),   ///< A bit indicating that the motion vectors have the jittering pattern applied to them.\n    FFX_FSR2_ENABLE_DEPTH_INVERTED                      = (1<<3),   ///< A bit indicating that the input depth buffer data provided is inverted [1..0].\n    FFX_FSR2_ENABLE_DEPTH_INFINITE                      = (1<<4),   ///< A bit indicating that the input depth buffer data provided is using an infinite far plane.\n    FFX_FSR2_ENABLE_AUTO_EXPOSURE                       = (1<<5),   ///< A bit indicating if automatic exposure should be applied to input color data.\n    FFX_FSR2_ENABLE_DYNAMIC_RESOLUTION                  = (1<<6),   ///< A bit indicating that the application uses dynamic resolution scaling.\n    FFX_FSR2_ENABLE_TEXTURE1D_USAGE                     = (1<<7),   ///< A bit indicating that the backend should use 1D textures.\n    FFX_FSR2_ENABLE_DEBUG_CHECKING                      = (1<<8),   ///< A bit indicating that the runtime should check some API values and report issues.\n} FfxFsr2InitializationFlagBits;\n\n/// A structure encapsulating the parameters required to initialize FidelityFX\n/// Super Resolution 2 upscaling.\n///\n/// @ingroup FSR2\ntypedef struct FfxFsr2ContextDescription {\n\n    uint32_t                    flags;                              ///< A collection of <c><i>FfxFsr2InitializationFlagBits</i></c>.\n    FfxDimensions2D             maxRenderSize;                      ///< The maximum size that rendering will be performed at.\n    FfxDimensions2D             displaySize;                        ///< The size of the presentation resolution targeted by the upscaling process.\n    FfxFsr2Interface            callbacks;                          ///< A set of pointers to the backend implementation for FSR 2.0.\n    FfxDevice                   device;                             ///< The abstracted device which is passed to some callback functions.\n\n    FfxFsr2Message              fpMessage;                          ///< A pointer to a function that can recieve messages from the runtime.\n} FfxFsr2ContextDescription;\n\n/// A structure encapsulating the parameters for dispatching the various passes\n/// of FidelityFX Super Resolution 2.\n///\n/// @ingroup FSR2\ntypedef struct FfxFsr2DispatchDescription {\n\n    FfxCommandList              commandList;                        ///< The <c><i>FfxCommandList</i></c> to record FSR2 rendering commands into.\n    FfxResource                 color;                              ///< A <c><i>FfxResource</i></c> containing the color buffer for the current frame (at render resolution).\n    FfxResource                 depth;                              ///< A <c><i>FfxResource</i></c> containing 32bit depth values for the current frame (at render resolution).\n    FfxResource                 motionVectors;                      ///< A <c><i>FfxResource</i></c> containing 2-dimensional motion vectors (at render resolution if <c><i>FFX_FSR2_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS</i></c> is not set).\n    FfxResource                 exposure;                           ///< A optional <c><i>FfxResource</i></c> containing a 1x1 exposure value.\n    FfxResource                 reactive;                           ///< A optional <c><i>FfxResource</i></c> containing alpha value of reactive objects in the scene.\n    FfxResource                 transparencyAndComposition;         ///< A optional <c><i>FfxResource</i></c> containing alpha value of special objects in the scene.\n    FfxResource                 output;                             ///< A <c><i>FfxResource</i></c> containing the output color buffer for the current frame (at presentation resolution).\n    FfxFloatCoords2D            jitterOffset;                       ///< The subpixel jitter offset applied to the camera.\n    FfxFloatCoords2D            motionVectorScale;                  ///< The scale factor to apply to motion vectors.\n    FfxDimensions2D             renderSize;                         ///< The resolution that was used for rendering the input resources.\n    bool                        enableSharpening;                   ///< Enable an additional sharpening pass.\n    float                       sharpness;                          ///< The sharpness value between 0 and 1, where 0 is no additional sharpness and 1 is maximum additional sharpness.\n    float                       frameTimeDelta;                     ///< The time elapsed since the last frame (expressed in milliseconds).\n    float                       preExposure;                        ///< The pre exposure value (must be > 0.0f)\n    bool                        reset;                              ///< A boolean value which when set to true, indicates the camera has moved discontinuously.\n    float                       cameraNear;                         ///< The distance to the near plane of the camera.\n    float                       cameraFar;                          ///< The distance to the far plane of the camera. This is used only used in case of non infinite depth.\n    float                       cameraFovAngleVertical;             ///< The camera angle field of view in the vertical direction (expressed in radians).\n    float                       viewSpaceToMetersFactor;            ///< The scale factor to convert view space units to meters\n\n    // EXPERIMENTAL reactive mask generation parameters\n    bool                        enableAutoReactive;                 ///< A boolean value to indicate internal reactive autogeneration should be used\n    FfxResource                 colorOpaqueOnly;                    ///< A <c><i>FfxResource</i></c> containing the opaque only color buffer for the current frame (at render resolution).\n    float                       autoTcThreshold;                    ///< Cutoff value for TC\n    float                       autoTcScale;                        ///< A value to scale the transparency and composition mask\n    float                       autoReactiveScale;                  ///< A value to scale the reactive mask\n    float                       autoReactiveMax;                    ///< A value to clamp the reactive mask\n\n} FfxFsr2DispatchDescription;\n\n/// A structure encapsulating the parameters for automatic generation of a reactive mask\n///\n/// @ingroup FSR2\ntypedef struct FfxFsr2GenerateReactiveDescription {\n\n    FfxCommandList              commandList;                        ///< The <c><i>FfxCommandList</i></c> to record FSR2 rendering commands into.\n    FfxResource                 colorOpaqueOnly;                    ///< A <c><i>FfxResource</i></c> containing the opaque only color buffer for the current frame (at render resolution).\n    FfxResource                 colorPreUpscale;                    ///< A <c><i>FfxResource</i></c> containing the opaque+translucent color buffer for the current frame (at render resolution).\n    FfxResource                 outReactive;                        ///< A <c><i>FfxResource</i></c> containing the surface to generate the reactive mask into.\n    FfxDimensions2D             renderSize;                         ///< The resolution that was used for rendering the input resources.\n    float                       scale;                              ///< A value to scale the output\n    float                       cutoffThreshold;                    ///< A threshold value to generate a binary reactive mask\n    float                       binaryValue;                        ///< A value to set for the binary reactive mask\n    uint32_t                    flags;                              ///< Flags to determine how to generate the reactive mask\n} FfxFsr2GenerateReactiveDescription;\n\n/// A structure encapsulating the FidelityFX Super Resolution 2 context.\n///\n/// This sets up an object which contains all persistent internal data and\n/// resources that are required by FSR2.\n///\n/// The <c><i>FfxFsr2Context</i></c> object should have a lifetime matching\n/// your use of FSR2. Before destroying the FSR2 context care should be taken\n/// to ensure the GPU is not accessing the resources created or used by FSR2.\n/// It is therefore recommended that the GPU is idle before destroying the\n/// FSR2 context.\n///\n/// @ingroup FSR2\ntypedef struct FfxFsr2Context {\n\n    uint32_t                    data[FFX_FSR2_CONTEXT_SIZE];        ///< An opaque set of <c>uint32_t</c> which contain the data for the context.\n} FfxFsr2Context;\n\n/// Create a FidelityFX Super Resolution 2 context from the parameters\n/// programmed to the <c><i>FfxFsr2CreateParams</i></c> structure.\n///\n/// The context structure is the main object used to interact with the FSR2\n/// API, and is responsible for the management of the internal resources used\n/// by the FSR2 algorithm. When this API is called, multiple calls will be\n/// made via the pointers contained in the <c><i>callbacks</i></c> structure.\n/// These callbacks will attempt to retreive the device capabilities, and\n/// create the internal resources, and pipelines required by FSR2's\n/// frame-to-frame function. Depending on the precise configuration used when\n/// creating the <c><i>FfxFsr2Context</i></c> a different set of resources and\n/// pipelines might be requested via the callback functions.\n///\n/// The flags included in the <c><i>flags</i></c> field of\n/// <c><i>FfxFsr2Context</i></c> how match the configuration of your\n/// application as well as the intended use of FSR2. It is important that these\n/// flags are set correctly (as well as a correct programmed\n/// <c><i>FfxFsr2DispatchDescription</i></c>) to ensure correct operation. It is\n/// recommended to consult the overview documentation for further details on\n/// how FSR2 should be integerated into an application.\n///\n/// When the <c><i>FfxFsr2Context</i></c> is created, you should use the\n/// <c><i>ffxFsr2ContextDispatch</i></c> function each frame where FSR2\n/// upscaling should be applied. See the documentation of\n/// <c><i>ffxFsr2ContextDispatch</i></c> for more details.\n///\n/// The <c><i>FfxFsr2Context</i></c> should be destroyed when use of it is\n/// completed, typically when an application is unloaded or FSR2 upscaling is\n/// disabled by a user. To destroy the FSR2 context you should call\n/// <c><i>ffxFsr2ContextDestroy</i></c>.\n///\n/// @param [out] context                A pointer to a <c><i>FfxFsr2Context</i></c> structure to populate.\n/// @param [in]  contextDescription     A pointer to a <c><i>FfxFsr2ContextDescription</i></c> structure.\n///\n/// @retval\n/// FFX_OK                              The operation completed successfully.\n/// @retval\n/// FFX_ERROR_CODE_NULL_POINTER         The operation failed because either <c><i>context</i></c> or <c><i>contextDescription</i></c> was <c><i>NULL</i></c>.\n/// @retval\n/// FFX_ERROR_INCOMPLETE_INTERFACE      The operation failed because the <c><i>FfxFsr2ContextDescription.callbacks</i></c>  was not fully specified.\n/// @retval\n/// FFX_ERROR_BACKEND_API_ERROR         The operation failed because of an error returned from the backend.\n///\n/// @ingroup FSR2\nFFX_API FfxErrorCode ffxFsr2ContextCreate(FfxFsr2Context* context, const FfxFsr2ContextDescription* contextDescription);\n\n/// Dispatch the various passes that constitute FidelityFX Super Resolution 2.\n///\n/// FSR2 is a composite effect, meaning that it is compromised of multiple\n/// constituent passes (implemented as one or more clears, copies and compute\n/// dispatches). The <c><i>ffxFsr2ContextDispatch</i></c> function is the\n/// function which (via the use of the functions contained in the\n/// <c><i>callbacks</i></c> field of the <c><i>FfxFsr2Context</i></c>\n/// structure) utlimately generates the sequence of graphics API calls required\n/// each frame.\n///\n/// As with the creation of the <c><i>FfxFsr2Context</i></c> correctly\n/// programming the <c><i>FfxFsr2DispatchDescription</i></c> is key to ensuring\n/// the correct operation of FSR2. It is particularly important to ensure that\n/// camera jitter is correctly applied to your application's projection matrix\n/// (or camera origin for raytraced applications). FSR2 provides the\n/// <c><i>ffxFsr2GetJitterPhaseCount</i></c> and\n/// <c><i>ffxFsr2GetJitterOffset</i></c> entry points to help applications\n/// correctly compute the camera jitter. Whatever jitter pattern is used by the\n/// application it should be correctly programmed to the\n/// <c><i>jitterOffset</i></c> field of the <c><i>dispatchDescription</i></c>\n/// structure. For more guidance on camera jitter please consult the\n/// documentation for <c><i>ffxFsr2GetJitterOffset</i></c> as well as the\n/// accompanying overview documentation for FSR2.\n///\n/// @param [in] context                 A pointer to a <c><i>FfxFsr2Context</i></c> structure.\n/// @param [in] dispatchDescription     A pointer to a <c><i>FfxFsr2DispatchDescription</i></c> structure.\n///\n/// @retval\n/// FFX_OK                              The operation completed successfully.\n/// @retval\n/// FFX_ERROR_CODE_NULL_POINTER         The operation failed because either <c><i>context</i></c> or <c><i>dispatchDescription</i></c> was <c><i>NULL</i></c>.\n/// @retval\n/// FFX_ERROR_OUT_OF_RANGE              The operation failed because <c><i>dispatchDescription.renderSize</i></c> was larger than the maximum render resolution.\n/// @retval\n/// FFX_ERROR_NULL_DEVICE               The operation failed because the device inside the context was <c><i>NULL</i></c>.\n/// @retval\n/// FFX_ERROR_BACKEND_API_ERROR         The operation failed because of an error returned from the backend.\n///\n/// @ingroup FSR2\nFFX_API FfxErrorCode ffxFsr2ContextDispatch(FfxFsr2Context* context, const FfxFsr2DispatchDescription* dispatchDescription);\n\n/// A helper function generate a Reactive mask from an opaque only texure and one containing translucent objects.\n///\n/// @param [in] context                 A pointer to a <c><i>FfxFsr2Context</i></c> structure.\n/// @param [in] params                  A pointer to a <c><i>FfxFsr2GenerateReactiveDescription</i></c> structure\n///\n/// @retval\n/// FFX_OK                              The operation completed successfully.\n///\n/// @ingroup FSR2\nFFX_API FfxErrorCode ffxFsr2ContextGenerateReactiveMask(FfxFsr2Context* context, const FfxFsr2GenerateReactiveDescription* params);\n\n/// Destroy the FidelityFX Super Resolution context.\n///\n/// @param [out] context                A pointer to a <c><i>FfxFsr2Context</i></c> structure to destroy.\n///\n/// @retval\n/// FFX_OK                              The operation completed successfully.\n/// @retval\n/// FFX_ERROR_CODE_NULL_POINTER         The operation failed because either <c><i>context</i></c> was <c><i>NULL</i></c>.\n///\n/// @ingroup FSR2\nFFX_API FfxErrorCode ffxFsr2ContextDestroy(FfxFsr2Context* context);\n\n/// Get the upscale ratio from the quality mode.\n///\n/// The following table enumerates the mapping of the quality modes to\n/// per-dimension scaling ratios.\n///\n/// Quality preset                                        | Scale factor\n/// ----------------------------------------------------- | -------------\n/// <c><i>FFX_FSR2_QUALITY_MODE_QUALITY</i></c>           | 1.5x\n/// <c><i>FFX_FSR2_QUALITY_MODE_BALANCED</i></c>          | 1.7x\n/// <c><i>FFX_FSR2_QUALITY_MODE_PERFORMANCE</i></c>       | 2.0x\n/// <c><i>FFX_FSR2_QUALITY_MODE_ULTRA_PERFORMANCE</i></c> | 3.0x\n///\n/// Passing an invalid <c><i>qualityMode</i></c> will return 0.0f.\n///\n/// @param [in] qualityMode             The quality mode preset.\n///\n/// @returns\n/// The upscaling the per-dimension upscaling ratio for\n/// <c><i>qualityMode</i></c> according to the table above.\n///\n/// @ingroup FSR2\nFFX_API float ffxFsr2GetUpscaleRatioFromQualityMode(FfxFsr2QualityMode qualityMode);\n\n/// A helper function to calculate the rendering resolution from a target\n/// resolution and desired quality level.\n///\n/// This function applies the scaling factor returned by\n/// <c><i>ffxFsr2GetUpscaleRatioFromQualityMode</i></c> to each dimension.\n///\n/// @param [out] renderWidth            A pointer to a <c>uint32_t</c> which will hold the calculated render resolution width.\n/// @param [out] renderHeight           A pointer to a <c>uint32_t</c> which will hold the calculated render resolution height.\n/// @param [in] displayWidth            The target display resolution width.\n/// @param [in] displayHeight           The target display resolution height.\n/// @param [in] qualityMode             The desired quality mode for FSR 2 upscaling.\n///\n/// @retval\n/// FFX_OK                              The operation completed successfully.\n/// @retval\n/// FFX_ERROR_INVALID_POINTER           Either <c><i>renderWidth</i></c> or <c><i>renderHeight</i></c> was <c>NULL</c>.\n/// @retval\n/// FFX_ERROR_INVALID_ENUM              An invalid quality mode was specified.\n///\n/// @ingroup FSR2\nFFX_API FfxErrorCode ffxFsr2GetRenderResolutionFromQualityMode(\n    uint32_t* renderWidth,\n    uint32_t* renderHeight,\n    uint32_t displayWidth,\n    uint32_t displayHeight,\n    FfxFsr2QualityMode qualityMode);\n\n/// A helper function to calculate the jitter phase count from display\n/// resolution.\n///\n/// For more detailed information about the application of camera jitter to\n/// your application's rendering please refer to the\n/// <c><i>ffxFsr2GetJitterOffset</i></c> function.\n/// \n/// The table below shows the jitter phase count which this function\n/// would return for each of the quality presets.\n///\n/// Quality preset                                        | Scale factor  | Phase count\n/// ----------------------------------------------------- | ------------- | ---------------\n/// <c><i>FFX_FSR2_QUALITY_MODE_QUALITY</i></c>           | 1.5x          | 18\n/// <c><i>FFX_FSR2_QUALITY_MODE_BALANCED</i></c>          | 1.7x          | 23\n/// <c><i>FFX_FSR2_QUALITY_MODE_PERFORMANCE</i></c>       | 2.0x          | 32\n/// <c><i>FFX_FSR2_QUALITY_MODE_ULTRA_PERFORMANCE</i></c> | 3.0x          | 72\n/// Custom                                                | [1..n]x       | ceil(8*n^2)\n///\n/// @param [in] renderWidth             The render resolution width.\n/// @param [in] displayWidth            The display resolution width.\n///\n/// @returns\n/// The jitter phase count for the scaling factor between <c><i>renderWidth</i></c> and <c><i>displayWidth</i></c>.\n///\n/// @ingroup FSR2\nFFX_API int32_t ffxFsr2GetJitterPhaseCount(int32_t renderWidth, int32_t displayWidth);\n\n/// A helper function to calculate the subpixel jitter offset.\n///\n/// FSR2 relies on the application to apply sub-pixel jittering while rendering.\n/// This is typically included in the projection matrix of the camera. To make\n/// the application of camera jitter simple, the FSR2 API provides a small set\n/// of utility function which computes the sub-pixel jitter offset for a\n/// particular frame within a sequence of separate jitter offsets. To begin, the\n/// index within the jitter phase must be computed. To calculate the\n/// sequence's length, you can call the <c><i>ffxFsr2GetJitterPhaseCount</i></c>\n/// function. The index should be a value which is incremented each frame modulo\n/// the length of the sequence computed by <c><i>ffxFsr2GetJitterPhaseCount</i></c>.\n/// The index within the jitter phase  is passed to\n/// <c><i>ffxFsr2GetJitterOffset</i></c> via the <c><i>index</i></c> parameter.\n///\n/// This function uses a Halton(2,3) sequence to compute the jitter offset.\n/// The ultimate index used for the sequence is <c><i>index</i></c> %\n/// <c><i>phaseCount</i></c>.\n///\n/// It is important to understand that the values returned from the\n/// <c><i>ffxFsr2GetJitterOffset</i></c> function are in unit pixel space, and\n/// in order to composite this correctly into a projection matrix we must\n/// convert them into projection offsets. This is done as per the pseudo code\n/// listing which is shown below.\n///\n///     const int32_t jitterPhaseCount = ffxFsr2GetJitterPhaseCount(renderWidth, displayWidth);\n///\n///     float jitterX = 0;\n///     float jitterY = 0;\n///     ffxFsr2GetJitterOffset(&jitterX, &jitterY, index, jitterPhaseCount);\n/// \n///     const float jitterX = 2.0f * jitterX / (float)renderWidth;\n///     const float jitterY = -2.0f * jitterY / (float)renderHeight;\n///     const Matrix4 jitterTranslationMatrix = translateMatrix(Matrix3::identity, Vector3(jitterX, jitterY, 0));\n///     const Matrix4 jitteredProjectionMatrix = jitterTranslationMatrix * projectionMatrix;\n/// \n/// Jitter should be applied to all rendering. This includes opaque, alpha\n/// transparent, and raytraced objects. For rasterized objects, the sub-pixel\n/// jittering values calculated by the <c><i>iffxFsr2GetJitterOffset</i></c>\n/// function can be applied to the camera projection matrix which is ultimately\n/// used to perform transformations during vertex shading. For raytraced\n/// rendering, the sub-pixel jitter should be applied to the ray's origin,\n/// often the camera's position.\n/// \n/// Whether you elect to use the <c><i>ffxFsr2GetJitterOffset</i></c> function\n/// or your own sequence generator, you must program the\n/// <c><i>jitterOffset</i></c> field of the\n/// <c><i>FfxFsr2DispatchParameters</i></c> structure in order to inform FSR2\n/// of the jitter offset that has been applied in order to render each frame.\n/// \n/// If not using the recommended <c><i>ffxFsr2GetJitterOffset</i></c> function,\n/// care should be taken that your jitter sequence never generates a null vector;\n/// that is value of 0 in both the X and Y dimensions.\n///\n/// @param [out] outX                   A pointer to a <c>float</c> which will contain the subpixel jitter offset for the x dimension.\n/// @param [out] outY                   A pointer to a <c>float</c> which will contain the subpixel jitter offset for the y dimension.\n/// @param [in] index                   The index within the jitter sequence.\n/// @param [in] phaseCount              The length of jitter phase. See <c><i>ffxFsr2GetJitterPhaseCount</i></c>.\n/// \n/// @retval\n/// FFX_OK                              The operation completed successfully.\n/// @retval\n/// FFX_ERROR_INVALID_POINTER           Either <c><i>outX</i></c> or <c><i>outY</i></c> was <c>NULL</c>.\n/// @retval\n/// FFX_ERROR_INVALID_ARGUMENT          Argument <c><i>phaseCount</i></c> must be greater than 0.\n/// \n/// @ingroup FSR2\nFFX_API FfxErrorCode ffxFsr2GetJitterOffset(float* outX, float* outY, int32_t index, int32_t phaseCount);\n\n/// A helper function to check if a resource is\n/// <c><i>FFX_FSR2_RESOURCE_IDENTIFIER_NULL</i></c>.\n///\n/// @param [in] resource                A <c><i>FfxResource</i></c>.\n///\n/// @returns\n/// true                                The <c><i>resource</i></c> was not <c><i>FFX_FSR2_RESOURCE_IDENTIFIER_NULL</i></c>.\n/// @returns\n/// false                               The <c><i>resource</i></c> was <c><i>FFX_FSR2_RESOURCE_IDENTIFIER_NULL</i></c>.\n///\n/// @ingroup FSR2\nFFX_API bool ffxFsr2ResourceIsNull(FfxResource resource);\n\n#if defined(__cplusplus)\n}\n#endif // #if defined(__cplusplus)\n"
  },
  {
    "path": "External/FSR2/Include/ffx_fsr2_interface.h",
    "content": "// This file is part of the FidelityFX SDK.\n//\n// Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n#pragma once\n\n#include \"ffx_assert.h\"\n#include \"ffx_types.h\"\n#include \"ffx_error.h\"\n\n// Include the FSR2 resources defined in the HLSL code. This shared here to avoid getting out of sync.\n#define FFX_CPU\n#include \"shaders/ffx_fsr2_resources.h\"\n#include \"shaders/ffx_fsr2_common.h\"\n\n#if defined(__cplusplus)\nextern \"C\" {\n#endif // #if defined(__cplusplus)\n\nFFX_FORWARD_DECLARE(FfxFsr2Interface);\n\n/// An enumeration of all the passes which constitute the FSR2 algorithm.\n///\n/// FSR2 is implemented as a composite of several compute passes each\n/// computing a key part of the final result. Each call to the \n/// <c><i>FfxFsr2ScheduleGpuJobFunc</i></c> callback function will\n/// correspond to a single pass included in <c><i>FfxFsr2Pass</i></c>. For a\n/// more comprehensive description of each pass, please refer to the FSR2\n/// reference documentation.\n///\n/// Please note in some cases e.g.: <c><i>FFX_FSR2_PASS_ACCUMULATE</i></c>\n/// and <c><i>FFX_FSR2_PASS_ACCUMULATE_SHARPEN</i></c> either one pass or the\n/// other will be used (they are mutually exclusive). The choice of which will\n/// depend on the way the <c><i>FfxFsr2Context</i></c> is created and the\n/// precise contents of <c><i>FfxFsr2DispatchParamters</i></c> each time a call\n/// is made to <c><i>ffxFsr2ContextDispatch</i></c>.\n/// \n/// @ingroup FSR2\ntypedef enum FfxFsr2Pass {\n\n    FFX_FSR2_PASS_DEPTH_CLIP = 0,                                       ///< A pass which performs depth clipping.\n    FFX_FSR2_PASS_RECONSTRUCT_PREVIOUS_DEPTH = 1,                       ///< A pass which performs reconstruction of previous frame's depth.\n    FFX_FSR2_PASS_LOCK = 2,                                             ///< A pass which calculates pixel locks.\n    FFX_FSR2_PASS_ACCUMULATE = 3,                                       ///< A pass which performs upscaling.\n    FFX_FSR2_PASS_ACCUMULATE_SHARPEN = 4,                               ///< A pass which performs upscaling when sharpening is used.\n    FFX_FSR2_PASS_RCAS = 5,                                             ///< A pass which performs sharpening.\n    FFX_FSR2_PASS_COMPUTE_LUMINANCE_PYRAMID = 6,                        ///< A pass which generates the luminance mipmap chain for the current frame.\n    FFX_FSR2_PASS_GENERATE_REACTIVE = 7,                                ///< An optional pass to generate a reactive mask\n    FFX_FSR2_PASS_TCR_AUTOGENERATE = 8,                                 ///< An optional pass to generate a texture-and-composition and reactive masks\n\n    FFX_FSR2_PASS_COUNT                                                 ///< The number of passes performed by FSR2.\n} FfxFsr2Pass;\n\ntypedef enum FfxFsr2MsgType {\n    FFX_FSR2_MESSAGE_TYPE_ERROR = 0,\n    FFX_FSR2_MESSAGE_TYPE_WARNING = 1,\n    FFX_FSR2_MESSAGE_TYPE_COUNT\n} FfxFsr2MsgType;\n\n/// Create and initialize the backend context.\n///\n/// The callback function sets up the backend context for rendering.\n/// It will create or reference the device and create required internal data structures.\n///\n/// @param [in] backendInterface                    A pointer to the backend interface.\n/// @param [in] device                              The FfxDevice obtained by ffxGetDevice(DX12/VK/...).\n///\n/// @retval\n/// FFX_OK                                          The operation completed successfully.\n/// @retval\n/// Anything else                                   The operation failed.\n///\n/// @ingroup FSR2\ntypedef FfxErrorCode (*FfxFsr2CreateBackendContextFunc)(\n    FfxFsr2Interface* backendInterface,\n    FfxDevice device);\n\n/// Get a list of capabilities of the device.\n///\n/// When creating an <c><i>FfxFsr2Context</i></c> it is desirable for the FSR2\n/// core implementation to be aware of certain characteristics of the platform\n/// that is being targetted. This is because some optimizations which FSR2\n/// attempts to perform are more effective on certain classes of hardware than\n/// others, or are not supported by older hardware. In order to avoid cases\n/// where optimizations actually have the effect of decreasing performance, or\n/// reduce the breadth of support provided by FSR2, FSR2 queries the\n/// capabilities of the device to make such decisions.\n///\n/// For target platforms with fixed hardware support you need not implement\n/// this callback function by querying the device, but instead may hardcore\n/// what features are available on the platform.\n///\n/// @param [in] backendInterface                    A pointer to the backend interface.\n/// @param [out] outDeviceCapabilities              The device capabilities structure to fill out.\n/// @param [in] device                              The device to query for capabilities.\n///\n/// @retval\n/// FFX_OK                                          The operation completed successfully.\n/// @retval\n/// Anything else                                   The operation failed.\n/// \n/// @ingroup FSR2\ntypedef FfxErrorCode(*FfxFsr2GetDeviceCapabilitiesFunc)(\n    FfxFsr2Interface* backendInterface,\n    FfxDeviceCapabilities* outDeviceCapabilities,\n    FfxDevice device);\n\n/// Destroy the backend context and dereference the device.\n///\n/// This function is called when the <c><i>FfxFsr2Context</i></c> is destroyed.\n///\n/// @param [in] backendInterface                    A pointer to the backend interface.\n///\n/// @retval\n/// FFX_OK                                          The operation completed successfully.\n/// @retval\n/// Anything else                                   The operation failed.\n///\n/// @ingroup FSR2\ntypedef FfxErrorCode(*FfxFsr2DestroyBackendContextFunc)(\n    FfxFsr2Interface* backendInterface);\n\n/// Create a resource.\n///\n/// This callback is intended for the backend to create internal resources.\n///\n/// Please note: It is also possible that the creation of resources might\n/// itself cause additional resources to be created by simply calling the\n/// <c><i>FfxFsr2CreateResourceFunc</i></c> function pointer again. This is\n/// useful when handling the initial creation of resources which must be\n/// initialized. The flow in such a case would be an initial call to create the\n/// CPU-side resource, another to create the GPU-side resource, and then a call\n/// to schedule a copy render job to move the data between the two. Typically\n/// this type of function call flow is only seen during the creation of an\n/// <c><i>FfxFsr2Context</i></c>.\n///\n/// @param [in] backendInterface                    A pointer to the backend interface.\n/// @param [in] createResourceDescription           A pointer to a <c><i>FfxCreateResourceDescription</i></c>.\n/// @param [out] outResource                        A pointer to a <c><i>FfxResource</i></c> object.\n///\n/// @retval\n/// FFX_OK                                          The operation completed successfully.\n/// @retval\n/// Anything else                                   The operation failed.\n/// \n/// @ingroup FSR2\ntypedef FfxErrorCode (*FfxFsr2CreateResourceFunc)(\n    FfxFsr2Interface* backendInterface,\n    const FfxCreateResourceDescription* createResourceDescription,\n    FfxResourceInternal* outResource);\n\n/// Register a resource in the backend for the current frame.\n///\n/// Since FSR2 and the backend are not aware how many different\n/// resources will get passed to FSR2 over time, it's not safe \n/// to register all resources simultaneously in the backend.\n/// Also passed resources may not be valid after the dispatch call.\n/// As a result it's safest to register them as FfxResourceInternal \n/// and clear them at the end of the dispatch call.\n///\n/// @param [in] backendInterface                    A pointer to the backend interface.\n/// @param [in] inResource                          A pointer to a <c><i>FfxResource</i></c>.\n/// @param [out] outResource                        A pointer to a <c><i>FfxResourceInternal</i></c> object.\n///\n/// @retval\n/// FFX_OK                                          The operation completed successfully.\n/// @retval\n/// Anything else                                   The operation failed.\n/// \n/// @ingroup FSR2\ntypedef FfxErrorCode(*FfxFsr2RegisterResourceFunc)(\n    FfxFsr2Interface* backendInterface,\n    const FfxResource* inResource,\n    FfxResourceInternal* outResource);\n\n/// Unregister all temporary FfxResourceInternal from the backend.\n///\n/// Unregister FfxResourceInternal referencing resources passed to \n/// a function as a parameter.\n///\n/// @param [in] backendInterface                    A pointer to the backend interface.\n///\n/// @retval\n/// FFX_OK                                          The operation completed successfully.\n/// @retval\n/// Anything else                                   The operation failed.\n/// \n/// @ingroup FSR2\ntypedef FfxErrorCode(*FfxFsr2UnregisterResourcesFunc)(\n    FfxFsr2Interface* backendInterface);\n\n/// Retrieve a <c><i>FfxResourceDescription</i></c> matching a\n/// <c><i>FfxResource</i></c> structure. \n///\n/// @param [in] backendInterface                    A pointer to the backend interface.\n/// @param [in] resource                            A pointer to a <c><i>FfxResource</i></c> object.\n///\n/// @returns\n/// A description of the resource.\n///\n/// @ingroup FSR2\ntypedef FfxResourceDescription (*FfxFsr2GetResourceDescriptionFunc)(\n    FfxFsr2Interface* backendInterface,\n    FfxResourceInternal resource);\n\n/// Destroy a resource\n///\n/// This callback is intended for the backend to release an internal resource.\n///\n/// @param [in] backendInterface                    A pointer to the backend interface.\n/// @param [in] resource                            A pointer to a <c><i>FfxResource</i></c> object.\n/// \n/// @retval\n/// FFX_OK                                          The operation completed successfully.\n/// @retval\n/// Anything else                                   The operation failed.\n/// \n/// @ingroup FSR2\ntypedef FfxErrorCode (*FfxFsr2DestroyResourceFunc)(\n    FfxFsr2Interface* backendInterface,\n    FfxResourceInternal resource);\n\n/// Create a render pipeline.\n///\n/// A rendering pipeline contains the shader as well as resource bindpoints\n/// and samplers.\n/// \n/// @param [in] backendInterface                    A pointer to the backend interface.\n/// @param [in] pass                                The identifier for the pass.\n/// @param [in] pipelineDescription                 A pointer to a <c><i>FfxPipelineDescription</i></c> describing the pipeline to be created.\n/// @param [out] outPipeline                        A pointer to a <c><i>FfxPipelineState</i></c> structure which should be populated.\n/// \n/// @retval\n/// FFX_OK                                          The operation completed successfully.\n/// @retval\n/// Anything else                                   The operation failed.\n/// \n/// @ingroup FSR2\ntypedef FfxErrorCode (*FfxFsr2CreatePipelineFunc)(\n    FfxFsr2Interface* backendInterface,\n    FfxFsr2Pass pass,\n    const FfxPipelineDescription* pipelineDescription,\n    FfxPipelineState* outPipeline);\n\n/// Destroy a render pipeline.\n///\n/// @param [in] backendInterface                    A pointer to the backend interface.\n/// @param [out] pipeline                           A pointer to a <c><i>FfxPipelineState</i></c> structure which should be released.\n/// \n/// @retval\n/// FFX_OK                                          The operation completed successfully.\n/// @retval\n/// Anything else                                   The operation failed.\n/// \n/// @ingroup FSR2\ntypedef FfxErrorCode (*FfxFsr2DestroyPipelineFunc)(\n    FfxFsr2Interface* backendInterface,\n    FfxPipelineState* pipeline);\n\n/// Schedule a render job to be executed on the next call of\n/// <c><i>FfxFsr2ExecuteGpuJobsFunc</i></c>.\n///\n/// Render jobs can perform one of three different tasks: clear, copy or\n/// compute dispatches.\n///\n/// @param [in] backendInterface                    A pointer to the backend interface.\n/// @param [in] job                                 A pointer to a <c><i>FfxGpuJobDescription</i></c> structure.\n/// \n/// @retval\n/// FFX_OK                                          The operation completed successfully.\n/// @retval\n/// Anything else                                   The operation failed.\n/// \n/// @ingroup FSR2\ntypedef FfxErrorCode (*FfxFsr2ScheduleGpuJobFunc)(\n    FfxFsr2Interface* backendInterface,\n    const FfxGpuJobDescription* job);\n\n/// Execute scheduled render jobs on the <c><i>comandList</i></c> provided.\n/// \n/// The recording of the graphics API commands should take place in this\n/// callback function, the render jobs which were previously enqueued (via\n/// callbacks made to <c><i>FfxFsr2ScheduleGpuJobFunc</i></c>) should be\n/// processed in the order they were received. Advanced users might choose to\n/// reorder the rendering jobs, but should do so with care to respect the\n/// resource dependencies.\n/// \n/// Depending on the precise contents of <c><i>FfxFsr2DispatchDescription</i></c> a\n/// different number of render jobs might have previously been enqueued (for\n/// example if sharpening is toggled on and off).\n/// \n/// @param [in] backendInterface                    A pointer to the backend interface.\n/// @param [in] commandList                         A pointer to a <c><i>FfxCommandList</i></c> structure.\n/// \n/// @retval\n/// FFX_OK                                          The operation completed successfully.\n/// @retval\n/// Anything else                                   The operation failed.\n/// \n/// @ingroup FSR2\ntypedef FfxErrorCode (*FfxFsr2ExecuteGpuJobsFunc)(\n    FfxFsr2Interface* backendInterface,\n    FfxCommandList commandList);\n\n/// Pass a string message\n///\n/// Used for debug messages.\n///\n/// @param [in] type                       The type of message.\n/// @param [in] message                    A string message to pass.\n///\n///\n/// @ingroup FSR2\ntypedef void(*FfxFsr2Message)(\n    FfxFsr2MsgType type,\n    const wchar_t* message);\n\n/// A structure encapsulating the interface between the core implentation of\n/// the FSR2 algorithm and any graphics API that it should ultimately call.\n/// \n/// This set of functions serves as an abstraction layer between FSR2 and the\n/// API used to implement it. While FSR2 ships with backends for DirectX12 and\n/// Vulkan, it is possible to implement your own backend for other platforms or\n/// which sits ontop of your engine's own abstraction layer. For details on the\n/// expectations of what each function should do you should refer the\n/// description of the following function pointer types:\n/// \n///     <c><i>FfxFsr2CreateDeviceFunc</i></c>\n///     <c><i>FfxFsr2GetDeviceCapabilitiesFunc</i></c>\n///     <c><i>FfxFsr2DestroyDeviceFunc</i></c>\n///     <c><i>FfxFsr2CreateResourceFunc</i></c>\n///     <c><i>FfxFsr2GetResourceDescriptionFunc</i></c>\n///     <c><i>FfxFsr2DestroyResourceFunc</i></c>\n///     <c><i>FfxFsr2CreatePipelineFunc</i></c>\n///     <c><i>FfxFsr2DestroyPipelineFunc</i></c>\n///     <c><i>FfxFsr2ScheduleGpuJobFunc</i></c>\n///     <c><i>FfxFsr2ExecuteGpuJobsFunc</i></c>\n///\n/// Depending on the graphics API that is abstracted by the backend, it may be\n/// required that the backend is to some extent stateful. To ensure that\n/// applications retain full control to manage the memory used by FSR2, the\n/// <c><i>scratchBuffer</i></c> and <c><i>scratchBufferSize</i></c> fields are\n/// provided. A backend should provide a means of specifying how much scratch\n/// memory is required for its internal implementation (e.g: via a function\n/// or constant value). The application is that responsible for allocating that\n/// memory and providing it when setting up the FSR2 backend. Backends provided\n/// with FSR2 do not perform dynamic memory allocations, and instead\n/// suballocate all memory from the scratch buffers provided.\n///\n/// The <c><i>scratchBuffer</i></c> and <c><i>scratchBufferSize</i></c> fields\n/// should be populated according to the requirements of each backend. For\n/// example, if using the DirectX 12 backend you should call the \n/// <c><i>ffxFsr2GetScratchMemorySizeDX12</i></c> function. It is not required\n/// that custom backend implementations use a scratch buffer.\n///\n/// @ingroup FSR2\ntypedef struct FfxFsr2Interface {\n\n    FfxFsr2CreateBackendContextFunc         fpCreateBackendContext;         ///< A callback function to create and initialize the backend context.\n    FfxFsr2GetDeviceCapabilitiesFunc        fpGetDeviceCapabilities;        ///< A callback function to query device capabilites.\n    FfxFsr2DestroyBackendContextFunc        fpDestroyBackendContext;        ///< A callback function to destroy the backendcontext. This also dereferences the device.\n    FfxFsr2CreateResourceFunc               fpCreateResource;               ///< A callback function to create a resource.\n    FfxFsr2RegisterResourceFunc             fpRegisterResource;             ///< A callback function to register an external resource.\n    FfxFsr2UnregisterResourcesFunc          fpUnregisterResources;          ///< A callback function to unregister external resource.\n    FfxFsr2GetResourceDescriptionFunc       fpGetResourceDescription;       ///< A callback function to retrieve a resource description.\n    FfxFsr2DestroyResourceFunc              fpDestroyResource;              ///< A callback function to destroy a resource.\n    FfxFsr2CreatePipelineFunc               fpCreatePipeline;               ///< A callback function to create a render or compute pipeline.\n    FfxFsr2DestroyPipelineFunc              fpDestroyPipeline;              ///< A callback function to destroy a render or compute pipeline.\n    FfxFsr2ScheduleGpuJobFunc               fpScheduleGpuJob;               ///< A callback function to schedule a render job.\n    FfxFsr2ExecuteGpuJobsFunc               fpExecuteGpuJobs;               ///< A callback function to execute all queued render jobs.\n\n    void*                                   scratchBuffer;                  ///< A preallocated buffer for memory utilized internally by the backend.\n    size_t                                  scratchBufferSize;              ///< Size of the buffer pointed to by <c><i>scratchBuffer</i></c>.\n} FfxFsr2Interface;\n\n#if defined(__cplusplus)\n}\n#endif // #if defined(__cplusplus)\n"
  },
  {
    "path": "External/FSR2/Include/ffx_types.h",
    "content": "// This file is part of the FidelityFX SDK.\n//\n// Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n#pragma once\n\n#include <stdint.h>\n\n#if defined (FFX_GCC)\n/// FidelityFX exported functions\n#define FFX_API\n#else\n/// FidelityFX exported functions\n#define FFX_API __declspec(dllexport)\n#endif // #if defined (FFX_GCC)\n\n/// Maximum supported number of simultaneously bound SRVs.\n#define FFX_MAX_NUM_SRVS            16\n\n/// Maximum supported number of simultaneously bound UAVs.\n#define FFX_MAX_NUM_UAVS            8\n\n/// Maximum number of constant buffers bound.\n#define FFX_MAX_NUM_CONST_BUFFERS   2\n\n/// Maximum size of bound constant buffers.\n#define FFX_MAX_CONST_SIZE          64\n\n/// Off by default warnings\n#if defined(_MSC_VER)\n#pragma warning(disable : 4365 4710 4820 5039)\n#elif defined(__clang__)\n#pragma clang diagnostic ignored \"-Wunused-parameter\"\n#pragma clang diagnostic ignored \"-Wmissing-field-initializers\"\n#pragma clang diagnostic ignored \"-Wsign-compare\"\n#pragma clang diagnostic ignored \"-Wunused-function\"\n#pragma clang diagnostic ignored \"-Wignored-qualifiers\"\n#elif defined(__GNUC__)\n#pragma GCC diagnostic ignored \"-Wunused-function\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif  // #ifdef __cplusplus\n\n/// An enumeration of surface formats.\ntypedef enum FfxSurfaceFormat {\n\n    FFX_SURFACE_FORMAT_UNKNOWN,                     ///< Unknown format\n    FFX_SURFACE_FORMAT_R32G32B32A32_TYPELESS,       ///< 32 bit per channel, 4 channel typeless format\n    FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT,          ///< 32 bit per channel, 4 channel float format\n    FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT,          ///< 16 bit per channel, 4 channel float format\n    FFX_SURFACE_FORMAT_R16G16B16A16_UNORM,          ///< 16 bit per channel, 4 channel unsigned normalized format\n    FFX_SURFACE_FORMAT_R32G32_FLOAT,                ///< 32 bit per channel, 2 channel float format\n    FFX_SURFACE_FORMAT_R32_UINT,                    ///< 32 bit per channel, 1 channel float format\n    FFX_SURFACE_FORMAT_R8G8B8A8_TYPELESS,           ///<  8 bit per channel, 4 channel float format\n    FFX_SURFACE_FORMAT_R8G8B8A8_UNORM,              ///<  8 bit per channel, 4 channel unsigned normalized format\n    FFX_SURFACE_FORMAT_R11G11B10_FLOAT,             ///< 32 bit 3 channel float format\n    FFX_SURFACE_FORMAT_R16G16_FLOAT,                ///< 16 bit per channel, 2 channel float format\n    FFX_SURFACE_FORMAT_R16G16_UINT,                 ///< 16 bit per channel, 2 channel unsigned int format\n    FFX_SURFACE_FORMAT_R16_FLOAT,                   ///< 16 bit per channel, 1 channel float format\n    FFX_SURFACE_FORMAT_R16_UINT,                    ///< 16 bit per channel, 1 channel unsigned int format\n    FFX_SURFACE_FORMAT_R16_UNORM,                   ///< 16 bit per channel, 1 channel unsigned normalized format\n    FFX_SURFACE_FORMAT_R16_SNORM,                   ///< 16 bit per channel, 1 channel signed normalized format\n    FFX_SURFACE_FORMAT_R8_UNORM,                    ///<  8 bit per channel, 1 channel unsigned normalized format\n    FFX_SURFACE_FORMAT_R8_UINT,                     ///<  8 bit per channel, 1 channel unsigned int format\n    FFX_SURFACE_FORMAT_R8G8_UNORM,                  ///<  8 bit per channel, 2 channel unsigned normalized format\n    FFX_SURFACE_FORMAT_R32_FLOAT                    ///< 32 bit per channel, 1 channel float format\n} FfxSurfaceFormat;\n\n/// An enumeration of resource usage.\ntypedef enum FfxResourceUsage {\n\n    FFX_RESOURCE_USAGE_READ_ONLY = 0,               ///< No usage flags indicate a resource is read only.\n    FFX_RESOURCE_USAGE_RENDERTARGET = (1<<0),       ///< Indicates a resource will be used as render target.\n    FFX_RESOURCE_USAGE_UAV = (1<<1),                ///< Indicates a resource will be used as UAV.\n} FfxResourceUsage;\n\n/// An enumeration of resource states.\ntypedef enum FfxResourceStates {\n\n    FFX_RESOURCE_STATE_UNORDERED_ACCESS = (1<<0),   ///< Indicates a resource is in the state to be used as UAV.\n    FFX_RESOURCE_STATE_COMPUTE_READ = (1 << 1),     ///< Indicates a resource is in the state to be read by compute shaders.\n    FFX_RESOURCE_STATE_COPY_SRC = (1 << 2),         ///< Indicates a resource is in the state to be used as source in a copy command.\n    FFX_RESOURCE_STATE_COPY_DEST = (1 << 3),        ///< Indicates a resource is in the state to be used as destination in a copy command.\n    FFX_RESOURCE_STATE_GENERIC_READ = (FFX_RESOURCE_STATE_COPY_SRC | FFX_RESOURCE_STATE_COMPUTE_READ),  ///< Indicates a resource is in generic (slow) read state.\n} FfxResourceStates;\n\n/// An enumeration of surface dimensions.\ntypedef enum FfxResourceDimension {\n\n    FFX_RESOURCE_DIMENSION_TEXTURE_1D,              ///< A resource with a single dimension.\n    FFX_RESOURCE_DIMENSION_TEXTURE_2D,              ///< A resource with two dimensions.\n} FfxResourceDimension;\n\n/// An enumeration of surface dimensions.\ntypedef enum FfxResourceFlags {\n\n    FFX_RESOURCE_FLAGS_NONE         = 0,            ///< No flags.\n    FFX_RESOURCE_FLAGS_ALIASABLE    = (1<<0),       ///< A bit indicating a resource does not need to persist across frames.\n} FfxResourceFlags;\n\n/// An enumeration of all resource view types.\ntypedef enum FfxResourceViewType {\n\n    FFX_RESOURCE_VIEW_UNORDERED_ACCESS,             ///< The resource view is an unordered access view (UAV).\n    FFX_RESOURCE_VIEW_SHADER_READ,                  ///< The resource view is a shader resource view (SRV).\n} FfxResourceViewType;\n\n/// The type of filtering to perform when reading a texture.\ntypedef enum FfxFilterType {\n\n    FFX_FILTER_TYPE_POINT,                          ///< Point sampling.\n    FFX_FILTER_TYPE_LINEAR                          ///< Sampling with interpolation.\n} FfxFilterType;\n\n/// An enumeration of all supported shader models.\ntypedef enum FfxShaderModel {\n\n    FFX_SHADER_MODEL_5_1,                           ///< Shader model 5.1.\n    FFX_SHADER_MODEL_6_0,                           ///< Shader model 6.0.\n    FFX_SHADER_MODEL_6_1,                           ///< Shader model 6.1.\n    FFX_SHADER_MODEL_6_2,                           ///< Shader model 6.2.\n    FFX_SHADER_MODEL_6_3,                           ///< Shader model 6.3.\n    FFX_SHADER_MODEL_6_4,                           ///< Shader model 6.4.\n    FFX_SHADER_MODEL_6_5,                           ///< Shader model 6.5.\n    FFX_SHADER_MODEL_6_6,                           ///< Shader model 6.6.\n    FFX_SHADER_MODEL_6_7,                           ///< Shader model 6.7.\n} FfxShaderModel;\n\n// An enumeration for different resource types\ntypedef enum FfxResourceType {\n\n    FFX_RESOURCE_TYPE_BUFFER,                       ///< The resource is a buffer.\n    FFX_RESOURCE_TYPE_TEXTURE1D,                    ///< The resource is a 1-dimensional texture.\n    FFX_RESOURCE_TYPE_TEXTURE2D,                    ///< The resource is a 2-dimensional texture.\n    FFX_RESOURCE_TYPE_TEXTURE3D,                    ///< The resource is a 3-dimensional texture.\n} FfxResourceType;\n\n/// An enumeration for different heap types\ntypedef enum FfxHeapType {\n\n    FFX_HEAP_TYPE_DEFAULT = 0,                      ///< Local memory.\n    FFX_HEAP_TYPE_UPLOAD                            ///< Heap used for uploading resources.\n} FfxHeapType;\n\n/// An enumberation for different render job types\ntypedef enum FfxGpuJobType {\n\n    FFX_GPU_JOB_CLEAR_FLOAT = 0,                 ///< The GPU job is performing a floating-point clear.\n    FFX_GPU_JOB_COPY = 1,                        ///< The GPU job is performing a copy.\n    FFX_GPU_JOB_COMPUTE = 2,                     ///< The GPU job is performing a compute dispatch.\n} FfxGpuJobType;\n\n/// A typedef representing the graphics device.\ntypedef void* FfxDevice;\n\n/// A typedef representing a command list or command buffer.\ntypedef void* FfxCommandList;\n\n/// A typedef for a root signature.\ntypedef void* FfxRootSignature;\n\n/// A typedef for a pipeline state object.\ntypedef void* FfxPipeline;\n\n/// A structure encapasulating a collection of device capabilities.\ntypedef struct FfxDeviceCapabilities {\n\n    FfxShaderModel                  minimumSupportedShaderModel;            ///< The minimum shader model supported by the device.\n    uint32_t                        waveLaneCountMin;                       ///< The minimum supported wavefront width.\n    uint32_t                        waveLaneCountMax;                       ///< The maximum supported wavefront width.\n    bool                            fp16Supported;                          ///< The device supports FP16 in hardware.\n    bool                            raytracingSupported;                    ///< The device supports raytracing.\n} FfxDeviceCapabilities;\n\n/// A structure encapsulating a 2-dimensional point, using 32bit unsigned integers.\ntypedef struct FfxDimensions2D {\n\n    uint32_t                        width;                                  ///< The width of a 2-dimensional range.\n    uint32_t                        height;                                 ///< The height of a 2-dimensional range.\n} FfxDimensions2D;\n\n/// A structure encapsulating a 2-dimensional point,\ntypedef struct FfxIntCoords2D {\n\n    int32_t                         x;                                      ///< The x coordinate of a 2-dimensional point.\n    int32_t                         y;                                      ///< The y coordinate of a 2-dimensional point.\n} FfxIntCoords2D;\n\n/// A structure encapsulating a 2-dimensional set of floating point coordinates.\ntypedef struct FfxFloatCoords2D {\n\n    float                           x;                                      ///< The x coordinate of a 2-dimensional point.\n    float                           y;                                      ///< The y coordinate of a 2-dimensional point.\n} FfxFloatCoords2D;\n\n/// A structure describing a resource.\ntypedef struct FfxResourceDescription {\n\n    FfxResourceType                 type;                                   ///< The type of the resource.\n    FfxSurfaceFormat                format;                                 ///< The surface format.\n    uint32_t                        width;                                  ///< The width of the resource.\n    uint32_t                        height;                                 ///< The height of the resource.\n    uint32_t                        depth;                                  ///< The depth of the resource.\n    uint32_t                        mipCount;                               ///< Number of mips (or 0 for full mipchain).\n    FfxResourceFlags                flags;                                  ///< A set of <c><i>FfxResourceFlags</i></c> flags.\n} FfxResourceDescription;\n\n/// An outward facing structure containing a resource\ntypedef struct FfxResource {\n    void*                           resource;                               ///< pointer to the resource.\n    wchar_t                         name[64];\n    FfxResourceDescription          description;\n    FfxResourceStates               state;\n    bool                            isDepth;\n    uint64_t                        descriptorData;\n} FfxResource;\n\n/// An internal structure containing a handle to a resource and resource views\ntypedef struct FfxResourceInternal {\n    int32_t                         internalIndex;                          ///< The index of the resource.\n} FfxResourceInternal;\n\n\n/// A structure defining a resource bind point\ntypedef struct FfxResourceBinding\n{\n    uint32_t    slotIndex;\n    uint32_t    resourceIdentifier;\n    wchar_t     name[64];\n}FfxResourceBinding;\n\n/// A structure encapsulating a single pass of an algorithm.\ntypedef struct FfxPipelineState {\n\n    FfxRootSignature                rootSignature;                                  ///< The pipelines rootSignature\n    FfxPipeline                     pipeline;                                       ///< The pipeline object\n    uint32_t                        uavCount;                                       ///< Count of UAVs used in this pipeline\n    uint32_t                        srvCount;                                       ///< Count of SRVs used in this pipeline\n    uint32_t                        constCount;                                     ///< Count of constant buffers used in this pipeline\n\n    FfxResourceBinding              uavResourceBindings[FFX_MAX_NUM_UAVS];          ///< Array of ResourceIdentifiers bound as UAVs\n    FfxResourceBinding              srvResourceBindings[FFX_MAX_NUM_SRVS];          ///< Array of ResourceIdentifiers bound as SRVs\n    FfxResourceBinding              cbResourceBindings[FFX_MAX_NUM_CONST_BUFFERS];  ///< Array of ResourceIdentifiers bound as CBs\n} FfxPipelineState;\n\n/// A structure containing the data required to create a resource.\ntypedef struct FfxCreateResourceDescription {\n    \n    FfxHeapType                     heapType;                               ///< The heap type to hold the resource, typically <c><i>FFX_HEAP_TYPE_DEFAULT</i></c>.\n    FfxResourceDescription          resourceDescription;                    ///< A resource description.\n    FfxResourceStates               initalState;                            ///< The initial resource state.\n    uint32_t                        initDataSize;                           ///< Size of initial data buffer.\n    void*                           initData;                               ///< Buffer containing data to fill the resource.\n    const wchar_t*                  name;                                   ///< Name of the resource.\n    FfxResourceUsage                usage;                                  ///< Resource usage flags.\n    uint32_t                        id;                                     ///< Internal resource ID.\n} FfxCreateResourceDescription;\n\n/// A structure containing the description used to create a\n/// <c><i>FfxPipeline</i></c> structure.\n///\n/// A pipeline is the name given to a shader and the collection of state that\n/// is required to dispatch it. In the context of FSR2 and its architecture\n/// this means that a <c><i>FfxPipelineDescription</i></c> will map to either a\n/// monolithic object in an explicit API (such as a\n/// <c><i>PipelineStateObject</i></c> in DirectX 12). Or a shader and some\n/// ancillary API objects (in something like DirectX 11).\n///\n/// The <c><i>contextFlags</i></c> field contains a copy of the flags passed\n/// to <c><i>ffxFsr2ContextCreate</i></c> via the <c><i>flags</i></c> field of\n/// the <c><i>FfxFsr2InitializationParams</i></c> structure. These flags are\n/// used to determine which permutation of a pipeline for a specific\n/// <c><i>FfxFsr2Pass</i></c> should be used to implement the features required\n/// by each application, as well as to acheive the best performance on specific\n/// target hardware configurations.\n/// \n/// When using one of the provided backends for FSR2 (such as DirectX 12 or\n/// Vulkan) the data required to create a pipeline is compiled offline and\n/// included into the backend library that you are using. For cases where the\n/// backend interface is overriden by providing custom callback function\n/// implementations care should be taken to respect the contents of the\n/// <c><i>contextFlags</i></c> field in order to correctly support the options\n/// provided by FSR2, and acheive best performance.\n///\n/// @ingroup FSR2\ntypedef struct FfxPipelineDescription {\n\n    uint32_t                            contextFlags;                   ///< A collection of <c><i>FfxFsr2InitializationFlagBits</i></c> which were passed to the context.\n    FfxFilterType*                      samplers;                       ///< Array of static samplers.\n    size_t                              samplerCount;                   ///< The number of samples contained inside <c><i>samplers</i></c>.\n    const uint32_t*                     rootConstantBufferSizes;        ///< Array containing the sizes of the root constant buffers (count of 32 bit elements).\n    uint32_t                            rootConstantBufferCount;        ///< The number of root constants contained within <c><i>rootConstantBufferSizes</i></c>.\n} FfxPipelineDescription;\n\n/// A structure containing a constant buffer.\ntypedef struct FfxConstantBuffer {\n\n    uint32_t                        uint32Size;                             ///< Size of 32 bit chunks used in the constant buffer\n    uint32_t                        data[FFX_MAX_CONST_SIZE];               ///< Constant buffer data\n}FfxConstantBuffer;\n\n/// A structure describing a clear render job.\ntypedef struct FfxClearFloatJobDescription {\n\n    float                           color[4];                               ///< The clear color of the resource.\n    FfxResourceInternal             target;                                 ///< The resource to be cleared.\n} FfxClearFloatJobDescription;\n\n/// A structure describing a compute render job.\ntypedef struct FfxComputeJobDescription {\n\n    FfxPipelineState                pipeline;                               ///< Compute pipeline for the render job.\n    uint32_t                        dimensions[3];                          ///< Dispatch dimensions.\n    FfxResourceInternal             srvs[FFX_MAX_NUM_SRVS];                 ///< SRV resources to be bound in the compute job.\n    wchar_t                         srvNames[FFX_MAX_NUM_SRVS][64];\n    FfxResourceInternal             uavs[FFX_MAX_NUM_UAVS];                 ///< UAV resources to be bound in the compute job.\n    uint32_t                        uavMip[FFX_MAX_NUM_UAVS];               ///< Mip level of UAV resources to be bound in the compute job.\n    wchar_t                         uavNames[FFX_MAX_NUM_UAVS][64];\n    FfxConstantBuffer               cbs[FFX_MAX_NUM_CONST_BUFFERS];         ///< Constant buffers to be bound in the compute job.\n    wchar_t                         cbNames[FFX_MAX_NUM_CONST_BUFFERS][64];\n    uint32_t                        cbSlotIndex[FFX_MAX_NUM_CONST_BUFFERS]; ///< Slot index in the descriptor table\n} FfxComputeJobDescription;\n\n/// A structure describing a copy render job.\ntypedef struct FfxCopyJobDescription\n{\n    FfxResourceInternal                     src;                                    ///< Source resource for the copy.\n    FfxResourceInternal                     dst;                                    ///< Destination resource for the copy.\n} FfxCopyJobDescription;\n\n/// A structure describing a single render job.\ntypedef struct FfxGpuJobDescription{\n\n    FfxGpuJobType                jobType;                                    ///< Type of the job.\n\n    union {\n        FfxClearFloatJobDescription clearJobDescriptor;                     ///< Clear job descriptor. Valid when <c><i>jobType</i></c> is <c><i>FFX_RENDER_JOB_CLEAR_FLOAT</i></c>.\n        FfxCopyJobDescription       copyJobDescriptor;                      ///< Copy job descriptor. Valid when <c><i>jobType</i></c> is <c><i>FFX_RENDER_JOB_COPY</i></c>.\n        FfxComputeJobDescription    computeJobDescriptor;                   ///< Compute job descriptor. Valid when <c><i>jobType</i></c> is <c><i>FFX_RENDER_JOB_COMPUTE</i></c>.\n    };\n} FfxGpuJobDescription;\n\n#ifdef __cplusplus\n}\n#endif  // #ifdef __cplusplus\n"
  },
  {
    "path": "External/FSR2/Include/ffx_util.h",
    "content": "// This file is part of the FidelityFX SDK.\n//\n// Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n#pragma once\n\n#include \"ffx_types.h\"\n\n/// The value of Pi.\nconst float FFX_PI = 3.141592653589793f;\n\n/// An epsilon value for floating point numbers.\nconst float FFX_EPSILON = 1e-06f;\n\n/// Helper macro to create the version number.\n#define FFX_MAKE_VERSION(major, minor, patch) ((major << 22) | (minor << 12) | patch)\n\n///< Use this to specify no version.\n#define FFX_UNSPECIFIED_VERSION     0xFFFFAD00\n\n/// Helper macro to avoid warnings about unused variables.\n#define FFX_UNUSED(x)               ((void)(x))\n\n/// Helper macro to align an integer to the specified power of 2 boundary\n#define FFX_ALIGN_UP(x, y)          (((x) + ((y)-1)) & ~((y)-1))\n\n/// Helper macro to check if a value is aligned.\n#define FFX_IS_ALIGNED(x)           (((x) != 0) && ((x) & ((x)-1)))\n\n/// Helper macro to stringify a value.\n#define FFX_STR(s)                  FFX_XSTR(s)\n#define FFX_XSTR(s)                 #s\n\n/// Helper macro to forward declare a structure.\n#define FFX_FORWARD_DECLARE(x)      typedef struct x x\n\n/// Helper macro to return the maximum of two values.\n#define FFX_MAXIMUM(x, y)           (((x) > (y)) ? (x) : (y))\n\n/// Helper macro to return the minimum of two values.\n#define FFX_MINIMUM(x, y)           (((x) < (y)) ? (x) : (y))\n\n/// Helper macro to do safe free on a pointer.\n#define FFX_SAFE_FREE(x) \\\n    if (x)               \\\n    free(x)\n\n/// Helper macro to return the abs of an integer value.\n#define FFX_ABSOLUTE(x)                 (((x) < 0) ? (-(x)) : (x))\n\n/// Helper macro to return sign of a value.\n#define FFX_SIGN(x)                     (((x) < 0) ? -1 : 1)\n\n/// Helper macro to work out the number of elements in an array.\n#define FFX_ARRAY_ELEMENTS(x)           (int32_t)((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x])))))\n\n/// The maximum length of a path that can be specified to the FidelityFX API.\n#define FFX_MAXIMUM_PATH                (260)\n\n/// Helper macro to check if the specified key is set in a bitfield.\n#define FFX_CONTAINS_FLAG(options, key) ((options & key) == key)\n"
  },
  {
    "path": "External/FSR2/Include/shaders/ffx_fsr2_common.h",
    "content": "// This file is part of the FidelityFX SDK.\n//\n// Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n#if !defined(FFX_FSR2_COMMON_H)\n#define FFX_FSR2_COMMON_H\n\n#if defined(FFX_CPU) || defined(FFX_GPU)\n//Locks\n#define LOCK_LIFETIME_REMAINING 0\n#define LOCK_TEMPORAL_LUMA 1\n#endif // #if defined(FFX_CPU) || defined(FFX_GPU)\n\n#if defined(FFX_GPU)\nFFX_STATIC const FfxFloat32 FSR2_FP16_MIN = 6.10e-05f;\nFFX_STATIC const FfxFloat32 FSR2_FP16_MAX = 65504.0f;\nFFX_STATIC const FfxFloat32 FSR2_EPSILON = 1e-03f;\nFFX_STATIC const FfxFloat32 FSR2_TONEMAP_EPSILON = 1.0f / FSR2_FP16_MAX;\nFFX_STATIC const FfxFloat32 FSR2_FLT_MAX = 3.402823466e+38f;\nFFX_STATIC const FfxFloat32 FSR2_FLT_MIN = 1.175494351e-38f;\n\n// treat vector truncation warnings as errors\n#pragma warning(error: 3206)\n\n// suppress warnings\n#pragma warning(disable: 3205)  // conversion from larger type to smaller\n#pragma warning(disable: 3571)  // in ffxPow(f, e), f could be negative\n\n// Reconstructed depth usage\nFFX_STATIC const FfxFloat32 fReconstructedDepthBilinearWeightThreshold = 0.01f;\n\n// Accumulation\nFFX_STATIC const FfxFloat32 fUpsampleLanczosWeightScale = 1.0f / 12.0f;\nFFX_STATIC const FfxFloat32 fMaxAccumulationLanczosWeight = 1.0f;\nFFX_STATIC const FfxFloat32 fAverageLanczosWeightPerFrame = 0.74f * fUpsampleLanczosWeightScale; // Average lanczos weight for jitter accumulated samples\nFFX_STATIC const FfxFloat32 fAccumulationMaxOnMotion = 3.0f * fUpsampleLanczosWeightScale;\n\n// Auto exposure\nFFX_STATIC const FfxFloat32 resetAutoExposureAverageSmoothing = 1e8f;\n\nstruct AccumulationPassCommonParams\n{\n    FfxInt32x2 iPxHrPos;\n    FfxFloat32x2 fHrUv;\n    FfxFloat32x2 fLrUv_HwSampler;\n    FfxFloat32x2 fMotionVector;\n    FfxFloat32x2 fReprojectedHrUv;\n    FfxFloat32 fHrVelocity;\n    FfxFloat32 fDepthClipFactor;\n    FfxFloat32 fDilatedReactiveFactor;\n    FfxFloat32 fAccumulationMask;\n\n    FfxBoolean bIsResetFrame;\n    FfxBoolean bIsExistingSample;\n    FfxBoolean bIsNewSample;\n};\n\nstruct LockState\n{\n    FfxBoolean NewLock; //Set for both unique new and re-locked new\n    FfxBoolean WasLockedPrevFrame; //Set to identify if the pixel was already locked (relock)\n};\n\nvoid InitializeNewLockSample(FFX_PARAMETER_OUT FfxFloat32x2 fLockStatus)\n{\n    fLockStatus = FfxFloat32x2(0, 0);\n}\n\n#if FFX_HALF\nvoid InitializeNewLockSample(FFX_PARAMETER_OUT FFX_MIN16_F2 fLockStatus)\n{\n    fLockStatus = FFX_MIN16_F2(0, 0);\n}\n#endif\n\n\nvoid KillLock(FFX_PARAMETER_INOUT FfxFloat32x2 fLockStatus)\n{\n    fLockStatus[LOCK_LIFETIME_REMAINING] = 0;\n}\n\n#if FFX_HALF\nvoid KillLock(FFX_PARAMETER_INOUT FFX_MIN16_F2 fLockStatus)\n{\n    fLockStatus[LOCK_LIFETIME_REMAINING] = FFX_MIN16_F(0);\n}\n#endif\n\nstruct RectificationBox\n{\n    FfxFloat32x3 boxCenter;\n    FfxFloat32x3 boxVec;\n    FfxFloat32x3 aabbMin;\n    FfxFloat32x3 aabbMax;\n    FfxFloat32 fBoxCenterWeight;\n};\n#if FFX_HALF\nstruct RectificationBoxMin16\n{\n    FFX_MIN16_F3 boxCenter;\n    FFX_MIN16_F3 boxVec;\n    FFX_MIN16_F3 aabbMin;\n    FFX_MIN16_F3 aabbMax;\n    FFX_MIN16_F fBoxCenterWeight;\n};\n#endif\n\nvoid RectificationBoxReset(FFX_PARAMETER_INOUT RectificationBox rectificationBox)\n{\n    rectificationBox.fBoxCenterWeight = FfxFloat32(0);\n\n    rectificationBox.boxCenter = FfxFloat32x3(0, 0, 0);\n    rectificationBox.boxVec = FfxFloat32x3(0, 0, 0);\n    rectificationBox.aabbMin = FfxFloat32x3(FSR2_FLT_MAX, FSR2_FLT_MAX, FSR2_FLT_MAX);\n    rectificationBox.aabbMax = -FfxFloat32x3(FSR2_FLT_MAX, FSR2_FLT_MAX, FSR2_FLT_MAX);\n}\n#if FFX_HALF\nvoid RectificationBoxReset(FFX_PARAMETER_INOUT RectificationBoxMin16 rectificationBox)\n{\n    rectificationBox.fBoxCenterWeight = FFX_MIN16_F(0);\n\n    rectificationBox.boxCenter = FFX_MIN16_F3(0, 0, 0);\n    rectificationBox.boxVec = FFX_MIN16_F3(0, 0, 0);\n    rectificationBox.aabbMin = FFX_MIN16_F3(FSR2_FP16_MAX, FSR2_FP16_MAX, FSR2_FP16_MAX);\n    rectificationBox.aabbMax = -FFX_MIN16_F3(FSR2_FP16_MAX, FSR2_FP16_MAX, FSR2_FP16_MAX);\n}\n#endif\n\nvoid RectificationBoxAddInitialSample(FFX_PARAMETER_INOUT RectificationBox rectificationBox, const FfxFloat32x3 colorSample, const FfxFloat32 fSampleWeight)\n{\n    rectificationBox.aabbMin = colorSample;\n    rectificationBox.aabbMax = colorSample;\n\n    FfxFloat32x3 weightedSample = colorSample * fSampleWeight;\n    rectificationBox.boxCenter = weightedSample;\n    rectificationBox.boxVec = colorSample * weightedSample;\n    rectificationBox.fBoxCenterWeight = fSampleWeight;\n}\n\nvoid RectificationBoxAddSample(FfxBoolean bInitialSample, FFX_PARAMETER_INOUT RectificationBox rectificationBox, const FfxFloat32x3 colorSample, const FfxFloat32 fSampleWeight)\n{\n    if (bInitialSample) {\n        RectificationBoxAddInitialSample(rectificationBox, colorSample, fSampleWeight);\n    } else {\n        rectificationBox.aabbMin = ffxMin(rectificationBox.aabbMin, colorSample);\n        rectificationBox.aabbMax = ffxMax(rectificationBox.aabbMax, colorSample);\n\n        FfxFloat32x3 weightedSample = colorSample * fSampleWeight;\n        rectificationBox.boxCenter += weightedSample;\n        rectificationBox.boxVec += colorSample * weightedSample;\n        rectificationBox.fBoxCenterWeight += fSampleWeight;\n    }\n}\n#if FFX_HALF\nvoid RectificationBoxAddInitialSample(FFX_PARAMETER_INOUT RectificationBoxMin16 rectificationBox, const FFX_MIN16_F3 colorSample, const FFX_MIN16_F fSampleWeight)\n{\n    rectificationBox.aabbMin = colorSample;\n    rectificationBox.aabbMax = colorSample;\n\n    FFX_MIN16_F3 weightedSample = colorSample * fSampleWeight;\n    rectificationBox.boxCenter = weightedSample;\n    rectificationBox.boxVec = colorSample * weightedSample;\n    rectificationBox.fBoxCenterWeight = fSampleWeight;\n}\n\nvoid RectificationBoxAddSample(FfxBoolean bInitialSample, FFX_PARAMETER_INOUT RectificationBoxMin16 rectificationBox, const FFX_MIN16_F3 colorSample, const FFX_MIN16_F fSampleWeight)\n{\n    if (bInitialSample) {\n        RectificationBoxAddInitialSample(rectificationBox, colorSample, fSampleWeight);\n    } else {\n        rectificationBox.aabbMin = ffxMin(rectificationBox.aabbMin, colorSample);\n        rectificationBox.aabbMax = ffxMax(rectificationBox.aabbMax, colorSample);\n\n        FFX_MIN16_F3 weightedSample = colorSample * fSampleWeight;\n        rectificationBox.boxCenter += weightedSample;\n        rectificationBox.boxVec += colorSample * weightedSample;\n        rectificationBox.fBoxCenterWeight += fSampleWeight;\n    }\n}\n#endif\n\nvoid RectificationBoxComputeVarianceBoxData(FFX_PARAMETER_INOUT RectificationBox rectificationBox)\n{\n    rectificationBox.fBoxCenterWeight = (abs(rectificationBox.fBoxCenterWeight) > FfxFloat32(FSR2_EPSILON) ? rectificationBox.fBoxCenterWeight : FfxFloat32(1.f));\n    rectificationBox.boxCenter /= rectificationBox.fBoxCenterWeight;\n    rectificationBox.boxVec /= rectificationBox.fBoxCenterWeight;\n    FfxFloat32x3 stdDev = sqrt(abs(rectificationBox.boxVec - rectificationBox.boxCenter * rectificationBox.boxCenter));\n    rectificationBox.boxVec = stdDev;\n}\n#if FFX_HALF\nvoid RectificationBoxComputeVarianceBoxData(FFX_PARAMETER_INOUT RectificationBoxMin16 rectificationBox)\n{\n    rectificationBox.fBoxCenterWeight = (abs(rectificationBox.fBoxCenterWeight) > FFX_MIN16_F(FSR2_EPSILON) ? rectificationBox.fBoxCenterWeight : FFX_MIN16_F(1.f));\n    rectificationBox.boxCenter /= rectificationBox.fBoxCenterWeight;\n    rectificationBox.boxVec /= rectificationBox.fBoxCenterWeight;\n    FFX_MIN16_F3 stdDev = sqrt(abs(rectificationBox.boxVec - rectificationBox.boxCenter * rectificationBox.boxCenter));\n    rectificationBox.boxVec = stdDev;\n}\n#endif\n\nFfxFloat32x3 SafeRcp3(FfxFloat32x3 v)\n{\n    return (all(FFX_NOT_EQUAL(v, FfxFloat32x3(0, 0, 0)))) ? (FfxFloat32x3(1, 1, 1) / v) : FfxFloat32x3(0, 0, 0);\n}\n#if FFX_HALF\nFFX_MIN16_F3 SafeRcp3(FFX_MIN16_F3 v)\n{\n    return (all(FFX_NOT_EQUAL(v, FFX_MIN16_F3(0, 0, 0)))) ? (FFX_MIN16_F3(1, 1, 1) / v) : FFX_MIN16_F3(0, 0, 0);\n}\n#endif\n\nFfxFloat32 MinDividedByMax(const FfxFloat32 v0, const FfxFloat32 v1)\n{\n    const FfxFloat32 m = ffxMax(v0, v1);\n    return m != 0 ? ffxMin(v0, v1) / m : 0;\n}\n\n#if FFX_HALF\nFFX_MIN16_F MinDividedByMax(const FFX_MIN16_F v0, const FFX_MIN16_F v1)\n{\n    const FFX_MIN16_F m = ffxMax(v0, v1);\n    return m != FFX_MIN16_F(0) ? ffxMin(v0, v1) / m : FFX_MIN16_F(0);\n}\n#endif\n\nFfxFloat32x3 YCoCgToRGB(FfxFloat32x3 fYCoCg)\n{\n    FfxFloat32x3 fRgb;\n\n    fRgb = FfxFloat32x3(\n        fYCoCg.x + fYCoCg.y - fYCoCg.z,\n        fYCoCg.x + fYCoCg.z,\n        fYCoCg.x - fYCoCg.y - fYCoCg.z);\n\n    return fRgb;\n}\n#if FFX_HALF\nFFX_MIN16_F3 YCoCgToRGB(FFX_MIN16_F3 fYCoCg)\n{\n    FFX_MIN16_F3 fRgb;\n\n    fRgb = FFX_MIN16_F3(\n        fYCoCg.x + fYCoCg.y - fYCoCg.z,\n        fYCoCg.x + fYCoCg.z,\n        fYCoCg.x - fYCoCg.y - fYCoCg.z);\n\n    return fRgb;\n}\n#endif\n\nFfxFloat32x3 RGBToYCoCg(FfxFloat32x3 fRgb)\n{\n    FfxFloat32x3 fYCoCg;\n\n    fYCoCg = FfxFloat32x3(\n        0.25f * fRgb.r + 0.5f * fRgb.g + 0.25f * fRgb.b,\n        0.5f * fRgb.r - 0.5f * fRgb.b,\n        -0.25f * fRgb.r + 0.5f * fRgb.g - 0.25f * fRgb.b);\n\n    return fYCoCg;\n}\n#if FFX_HALF\nFFX_MIN16_F3 RGBToYCoCg(FFX_MIN16_F3 fRgb)\n{\n    FFX_MIN16_F3 fYCoCg;\n\n    fYCoCg = FFX_MIN16_F3(\n        0.25 * fRgb.r + 0.5 * fRgb.g + 0.25 * fRgb.b,\n        0.5 * fRgb.r - 0.5 * fRgb.b,\n        -0.25 * fRgb.r + 0.5 * fRgb.g - 0.25 * fRgb.b);\n\n    return fYCoCg;\n}\n#endif\n\nFfxFloat32 RGBToLuma(FfxFloat32x3 fLinearRgb)\n{\n    return dot(fLinearRgb, FfxFloat32x3(0.2126f, 0.7152f, 0.0722f));\n}\n#if FFX_HALF\nFFX_MIN16_F RGBToLuma(FFX_MIN16_F3 fLinearRgb)\n{\n    return dot(fLinearRgb, FFX_MIN16_F3(0.2126f, 0.7152f, 0.0722f));\n}\n#endif\n\nFfxFloat32 RGBToPerceivedLuma(FfxFloat32x3 fLinearRgb)\n{\n    FfxFloat32 fLuminance = RGBToLuma(fLinearRgb);\n\n    FfxFloat32 fPercievedLuminance = 0;\n    if (fLuminance <= 216.0f / 24389.0f) {\n        fPercievedLuminance = fLuminance * (24389.0f / 27.0f);\n    }\n    else {\n        fPercievedLuminance = ffxPow(fLuminance, 1.0f / 3.0f) * 116.0f - 16.0f;\n    }\n\n    return fPercievedLuminance * 0.01f;\n}\n#if FFX_HALF\nFFX_MIN16_F RGBToPerceivedLuma(FFX_MIN16_F3 fLinearRgb)\n{\n    FFX_MIN16_F fLuminance = RGBToLuma(fLinearRgb);\n\n    FFX_MIN16_F fPercievedLuminance = FFX_MIN16_F(0);\n    if (fLuminance <= FFX_MIN16_F(216.0f / 24389.0f)) {\n        fPercievedLuminance = fLuminance * FFX_MIN16_F(24389.0f / 27.0f);\n    }\n    else {\n        fPercievedLuminance = ffxPow(fLuminance, FFX_MIN16_F(1.0f / 3.0f)) * FFX_MIN16_F(116.0f) - FFX_MIN16_F(16.0f);\n    }\n\n    return fPercievedLuminance * FFX_MIN16_F(0.01f);\n}\n#endif\n\nFfxFloat32x3 Tonemap(FfxFloat32x3 fRgb)\n{\n    return fRgb / (ffxMax(ffxMax(0.f, fRgb.r), ffxMax(fRgb.g, fRgb.b)) + 1.f).xxx;\n}\n\nFfxFloat32x3 InverseTonemap(FfxFloat32x3 fRgb)\n{\n    return fRgb / ffxMax(FSR2_TONEMAP_EPSILON, 1.f - ffxMax(fRgb.r, ffxMax(fRgb.g, fRgb.b))).xxx;\n}\n\n#if FFX_HALF\nFFX_MIN16_F3 Tonemap(FFX_MIN16_F3 fRgb)\n{\n    return fRgb / (ffxMax(ffxMax(FFX_MIN16_F(0.f), fRgb.r), ffxMax(fRgb.g, fRgb.b)) + FFX_MIN16_F(1.f)).xxx;\n}\n\nFFX_MIN16_F3 InverseTonemap(FFX_MIN16_F3 fRgb)\n{\n    return fRgb / ffxMax(FFX_MIN16_F(FSR2_TONEMAP_EPSILON), FFX_MIN16_F(1.f) - ffxMax(fRgb.r, ffxMax(fRgb.g, fRgb.b))).xxx;\n}\n#endif\n\nFfxInt32x2 ClampLoad(FfxInt32x2 iPxSample, FfxInt32x2 iPxOffset, FfxInt32x2 iTextureSize)\n{\n    FfxInt32x2 result = iPxSample + iPxOffset;\n    result.x = (iPxOffset.x < 0) ? ffxMax(result.x, 0) : result.x;\n    result.x = (iPxOffset.x > 0) ? ffxMin(result.x, iTextureSize.x - 1) : result.x;\n    result.y = (iPxOffset.y < 0) ? ffxMax(result.y, 0) : result.y;\n    result.y = (iPxOffset.y > 0) ? ffxMin(result.y, iTextureSize.y - 1) : result.y;\n    return result;\n\n    // return ffxMed3(iPxSample + iPxOffset, FfxInt32x2(0, 0), iTextureSize - FfxInt32x2(1, 1));\n}\n#if FFX_HALF\nFFX_MIN16_I2 ClampLoad(FFX_MIN16_I2 iPxSample, FFX_MIN16_I2 iPxOffset, FFX_MIN16_I2 iTextureSize)\n{\n    FFX_MIN16_I2 result = iPxSample + iPxOffset;\n    result.x = (iPxOffset.x < 0) ? ffxMax(result.x, FFX_MIN16_I(0)) : result.x;\n    result.x = (iPxOffset.x > 0) ? ffxMin(result.x, iTextureSize.x - FFX_MIN16_I(1)) : result.x;\n    result.y = (iPxOffset.y < 0) ? ffxMax(result.y, FFX_MIN16_I(0)) : result.y;\n    result.y = (iPxOffset.y > 0) ? ffxMin(result.y, iTextureSize.y - FFX_MIN16_I(1)) : result.y;\n    return result;\n\n    // return ffxMed3Half(iPxSample + iPxOffset, FFX_MIN16_I2(0, 0), iTextureSize - FFX_MIN16_I2(1, 1));\n}\n#endif\n\nFfxFloat32x2 ClampUv(FfxFloat32x2 fUv, FfxInt32x2 iTextureSize, FfxInt32x2 iResourceSize)\n{\n    const FfxFloat32x2 fSampleLocation = fUv * iTextureSize;\n    const FfxFloat32x2 fClampedLocation = ffxMax(FfxFloat32x2(0.5f, 0.5f), ffxMin(fSampleLocation, FfxFloat32x2(iTextureSize) - FfxFloat32x2(0.5f, 0.5f)));\n    const FfxFloat32x2 fClampedUv = fClampedLocation / FfxFloat32x2(iResourceSize);\n\n    return fClampedUv;\n}\n\nFfxBoolean IsOnScreen(FfxInt32x2 pos, FfxInt32x2 size)\n{\n    return all(FFX_LESS_THAN(FfxUInt32x2(pos), FfxUInt32x2(size)));\n}\n#if FFX_HALF\nFfxBoolean IsOnScreen(FFX_MIN16_I2 pos, FFX_MIN16_I2 size)\n{\n    return all(FFX_LESS_THAN(FFX_MIN16_U2(pos), FFX_MIN16_U2(size)));\n}\n#endif\n\nFfxFloat32 ComputeAutoExposureFromLavg(FfxFloat32 Lavg)\n{\n    Lavg = exp(Lavg);\n\n    const FfxFloat32 S = 100.0f; //ISO arithmetic speed\n    const FfxFloat32 K = 12.5f;\n    FfxFloat32 ExposureISO100 = log2((Lavg * S) / K);\n\n    const FfxFloat32 q = 0.65f;\n    FfxFloat32 Lmax = (78.0f / (q * S)) * ffxPow(2.0f, ExposureISO100);\n\n    return 1 / Lmax;\n}\n#if FFX_HALF\nFFX_MIN16_F ComputeAutoExposureFromLavg(FFX_MIN16_F Lavg)\n{\n    Lavg = exp(Lavg);\n\n    const FFX_MIN16_F S = FFX_MIN16_F(100.0f); //ISO arithmetic speed\n    const FFX_MIN16_F K = FFX_MIN16_F(12.5f);\n    const FFX_MIN16_F ExposureISO100 = log2((Lavg * S) / K);\n\n    const FFX_MIN16_F q = FFX_MIN16_F(0.65f);\n    const FFX_MIN16_F Lmax = (FFX_MIN16_F(78.0f) / (q * S)) * ffxPow(FFX_MIN16_F(2.0f), ExposureISO100);\n\n    return FFX_MIN16_F(1) / Lmax;\n}\n#endif\n\nFfxInt32x2 ComputeHrPosFromLrPos(FfxInt32x2 iPxLrPos)\n{\n    FfxFloat32x2 fSrcJitteredPos = FfxFloat32x2(iPxLrPos) + 0.5f - Jitter();\n    FfxFloat32x2 fLrPosInHr = (fSrcJitteredPos / RenderSize()) * DisplaySize();\n    FfxInt32x2 iPxHrPos = FfxInt32x2(floor(fLrPosInHr));\n    return iPxHrPos;\n}\n#if FFX_HALF\nFFX_MIN16_I2 ComputeHrPosFromLrPos(FFX_MIN16_I2 iPxLrPos)\n{\n    FFX_MIN16_F2 fSrcJitteredPos = FFX_MIN16_F2(iPxLrPos) + FFX_MIN16_F(0.5f) - FFX_MIN16_F2(Jitter());\n    FFX_MIN16_F2 fLrPosInHr = (fSrcJitteredPos / FFX_MIN16_F2(RenderSize())) * FFX_MIN16_F2(DisplaySize());\n    FFX_MIN16_I2 iPxHrPos = FFX_MIN16_I2(floor(fLrPosInHr));\n    return iPxHrPos;\n}\n#endif\n\nFfxFloat32x2 ComputeNdc(FfxFloat32x2 fPxPos, FfxInt32x2 iSize)\n{\n    return fPxPos / FfxFloat32x2(iSize) * FfxFloat32x2(2.0f, -2.0f) + FfxFloat32x2(-1.0f, 1.0f);\n}\n\nFfxFloat32 GetViewSpaceDepth(FfxFloat32 fDeviceDepth)\n{\n    const FfxFloat32x4 fDeviceToViewDepth = DeviceToViewSpaceTransformFactors();\n\n    // fDeviceToViewDepth details found in ffx_fsr2.cpp\n    return (fDeviceToViewDepth[1] / (fDeviceDepth - fDeviceToViewDepth[0]));\n}\n\nFfxFloat32 GetViewSpaceDepthInMeters(FfxFloat32 fDeviceDepth)\n{\n    return GetViewSpaceDepth(fDeviceDepth) * ViewSpaceToMetersFactor();\n}\n\nFfxFloat32x3 GetViewSpacePosition(FfxInt32x2 iViewportPos, FfxInt32x2 iViewportSize, FfxFloat32 fDeviceDepth)\n{\n    const FfxFloat32x4 fDeviceToViewDepth = DeviceToViewSpaceTransformFactors();\n\n    const FfxFloat32 Z = GetViewSpaceDepth(fDeviceDepth);\n\n    const FfxFloat32x2 fNdcPos = ComputeNdc(iViewportPos, iViewportSize);\n    const FfxFloat32 X = fDeviceToViewDepth[2] * fNdcPos.x * Z;\n    const FfxFloat32 Y = fDeviceToViewDepth[3] * fNdcPos.y * Z;\n\n    return FfxFloat32x3(X, Y, Z);\n}\n\nFfxFloat32x3 GetViewSpacePositionInMeters(FfxInt32x2 iViewportPos, FfxInt32x2 iViewportSize, FfxFloat32 fDeviceDepth)\n{\n    return GetViewSpacePosition(iViewportPos, iViewportSize, fDeviceDepth) * ViewSpaceToMetersFactor();\n}\n\nFfxFloat32 GetMaxDistanceInMeters()\n{\n#if FFX_FSR2_OPTION_INVERTED_DEPTH\n    return GetViewSpaceDepth(0.0f) * ViewSpaceToMetersFactor();\n#else\n    return GetViewSpaceDepth(1.0f) * ViewSpaceToMetersFactor();\n#endif\n}\n\nFfxFloat32x3 PrepareRgb(FfxFloat32x3 fRgb, FfxFloat32 fExposure, FfxFloat32 fPreExposure)\n{\n    fRgb /= fPreExposure;\n    fRgb *= fExposure;\n\n    fRgb = clamp(fRgb, 0.0f, FSR2_FP16_MAX);\n\n    return fRgb;\n}\n\nFfxFloat32x3 UnprepareRgb(FfxFloat32x3 fRgb, FfxFloat32 fExposure)\n{\n    fRgb /= fExposure;\n    fRgb *= PreExposure();\n\n    return fRgb;\n}\n\n\nstruct BilinearSamplingData\n{\n    FfxInt32x2 iOffsets[4];\n    FfxFloat32 fWeights[4];\n    FfxInt32x2 iBasePos;\n};\n\nBilinearSamplingData GetBilinearSamplingData(FfxFloat32x2 fUv, FfxInt32x2 iSize)\n{\n    BilinearSamplingData data;\n\n    FfxFloat32x2 fPxSample = (fUv * iSize) - FfxFloat32x2(0.5f, 0.5f);\n    data.iBasePos = FfxInt32x2(floor(fPxSample));\n    FfxFloat32x2 fPxFrac = ffxFract(fPxSample);\n\n    data.iOffsets[0] = FfxInt32x2(0, 0);\n    data.iOffsets[1] = FfxInt32x2(1, 0);\n    data.iOffsets[2] = FfxInt32x2(0, 1);\n    data.iOffsets[3] = FfxInt32x2(1, 1);\n\n    data.fWeights[0] = (1 - fPxFrac.x) * (1 - fPxFrac.y);\n    data.fWeights[1] = (fPxFrac.x) * (1 - fPxFrac.y);\n    data.fWeights[2] = (1 - fPxFrac.x) * (fPxFrac.y);\n    data.fWeights[3] = (fPxFrac.x) * (fPxFrac.y);\n\n    return data;\n}\n\nstruct PlaneData\n{\n    FfxFloat32x3 fNormal;\n    FfxFloat32 fDistanceFromOrigin;\n};\n\nPlaneData GetPlaneFromPoints(FfxFloat32x3 fP0, FfxFloat32x3 fP1, FfxFloat32x3 fP2)\n{\n    PlaneData plane;\n\n    FfxFloat32x3 v0 = fP0 - fP1;\n    FfxFloat32x3 v1 = fP0 - fP2;\n    plane.fNormal = normalize(cross(v0, v1));\n    plane.fDistanceFromOrigin = -dot(fP0, plane.fNormal);\n\n    return plane;\n}\n\nFfxFloat32 PointToPlaneDistance(PlaneData plane, FfxFloat32x3 fPoint)\n{\n    return abs(dot(plane.fNormal, fPoint) + plane.fDistanceFromOrigin);\n}\n\n#endif // #if defined(FFX_GPU)\n\n#endif //!defined(FFX_FSR2_COMMON_H)\n"
  },
  {
    "path": "External/FSR2/Include/shaders/ffx_fsr2_resources.h",
    "content": "// This file is part of the FidelityFX SDK.\n//\n// Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n#ifndef FFX_FSR2_RESOURCES_H\n#define FFX_FSR2_RESOURCES_H\n\n#if defined(FFX_CPU) || defined(FFX_GPU)\n#define FFX_FSR2_RESOURCE_IDENTIFIER_NULL                                           0\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_OPAQUE_ONLY                              1\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_COLOR                                    2\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS                           3\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_DEPTH                                    4\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_EXPOSURE                                 5\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_REACTIVE_MASK                            6\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_TRANSPARENCY_AND_COMPOSITION_MASK        7\n#define FFX_FSR2_RESOURCE_IDENTIFIER_RECONSTRUCTED_PREVIOUS_NEAREST_DEPTH           8\n#define FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_MOTION_VECTORS                         9\n#define FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_DEPTH                                  10\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR                        11\n#define FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS                                    12\n#define FFX_FSR2_RESOURCE_IDENTIFIER_NEW_LOCKS                                      13\n#define FFX_FSR2_RESOURCE_IDENTIFIER_PREPARED_INPUT_COLOR                           14\n#define FFX_FSR2_RESOURCE_IDENTIFIER_LUMA_HISTORY                                   15\n#define FFX_FSR2_RESOURCE_IDENTIFIER_DEBUG_OUTPUT                                   16\n#define FFX_FSR2_RESOURCE_IDENTIFIER_LANCZOS_LUT                                    17\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SPD_ATOMIC_COUNT                               18\n#define FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT                                19\n#define FFX_FSR2_RESOURCE_IDENTIFIER_RCAS_INPUT                                     20\n#define FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS_1                                  21\n#define FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS_2                                  22\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR_1                      23\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR_2                      24\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DEFAULT_REACTIVITY                    25\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DEFAULT_TRANSPARENCY_AND_COMPOSITION  26\n#define FFX_FSR2_RESOURCE_IDENTITIER_UPSAMPLE_MAXIMUM_BIAS_LUT                      27\n#define FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_REACTIVE_MASKS                         28\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE                                29 // same as FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_0\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_0                       29\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_1                       30\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_2                       31\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_3                       32\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_4                       33\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_5                       34\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_6                       35\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_7                       36\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_8                       37\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_9                       38\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_10                      39\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_11                      40\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_12                      41\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DEFAULT_EXPOSURE                      42\n#define FFX_FSR2_RESOURCE_IDENTIFIER_AUTO_EXPOSURE                                  43\n#define FFX_FSR2_RESOURCE_IDENTIFIER_AUTOREACTIVE                                   44\n#define FFX_FSR2_RESOURCE_IDENTIFIER_AUTOCOMPOSITION                                45\n\n#define FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR                           46\n#define FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR                          47\n#define FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR_1                         48\n#define FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR_1                        49\n#define FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR_2                         50\n#define FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR_2                        51\n#define FFX_FSR2_RESOURCE_IDENTIFIER_PREVIOUS_DILATED_MOTION_VECTORS                52\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DILATED_MOTION_VECTORS_1              53\n#define FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DILATED_MOTION_VECTORS_2              54\n#define FFX_FSR2_RESOURCE_IDENTIFIER_LUMA_HISTORY_1                                 55\n#define FFX_FSR2_RESOURCE_IDENTIFIER_LUMA_HISTORY_2                                 56\n#define FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_INPUT_LUMA                                57\n\n// Shading change detection mip level setting, value must be in the range [FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_0, FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_12]\n#define FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_SHADING_CHANGE          FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_4\n#define FFX_FSR2_SHADING_CHANGE_MIP_LEVEL                                           (FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_SHADING_CHANGE - FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE)\n\n#define FFX_FSR2_RESOURCE_IDENTIFIER_COUNT                                          58\n\n#define FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_FSR2                                     0\n#define FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_SPD                                      1\n#define FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_RCAS                                     2\n#define FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_GENREACTIVE                              3\n\n#define FFX_FSR2_AUTOREACTIVEFLAGS_APPLY_TONEMAP                                    1\n#define FFX_FSR2_AUTOREACTIVEFLAGS_APPLY_INVERSETONEMAP                             2\n#define FFX_FSR2_AUTOREACTIVEFLAGS_APPLY_THRESHOLD                                  4\n#define FFX_FSR2_AUTOREACTIVEFLAGS_USE_COMPONENTS_MAX                               8\n\n#endif // #if defined(FFX_CPU) || defined(FFX_GPU)\n\n#endif //!defined( FFX_FSR2_RESOURCES_H )\n"
  },
  {
    "path": "External/FastDelegate/FastDelegate.h",
    "content": "//\t\t\t\t\t\tFastDelegate.h \n//\tEfficient delegates in C++ that generate only two lines of asm code!\n//  Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp\n//\n//\t\t\t\t\t\t- Don Clugston, Mar 2004.\n//\t\tMajor contributions were made by Jody Hagins.\n// History:\n// 24-Apr-04 1.0  * Submitted to CodeProject. \n// 28-Apr-04 1.1  * Prevent most unsafe uses of evil static function hack.\n//\t\t\t\t  * Improved syntax for horrible_cast (thanks Paul Bludov).\n//\t\t\t\t  * Tested on Metrowerks MWCC and Intel ICL (IA32)\n//\t\t\t\t  * Compiled, but not run, on Comeau C++ and Intel Itanium ICL.\n//\t27-Jun-04 1.2 * Now works on Borland C++ Builder 5.5\n//\t\t\t\t  * Now works on /clr \"managed C++\" code on VC7, VC7.1\n//\t\t\t\t  * Comeau C++ now compiles without warnings.\n//\t\t\t\t  * Prevent the virtual inheritance case from being used on \n//\t\t\t\t\t  VC6 and earlier, which generate incorrect code.\n//\t\t\t\t  * Improved warning and error messages. Non-standard hacks\n//\t\t\t\t\t now have compile-time checks to make them safer.\n//\t\t\t\t  * implicit_cast used instead of static_cast in many cases.\n//\t\t\t\t  * If calling a const member function, a const class pointer can be used.\n//\t\t\t\t  * MakeDelegate() global helper function added to simplify pass-by-value.\n//\t\t\t\t  * Added fastdelegate.clear()\n// 16-Jul-04 1.2.1* Workaround for gcc bug (const member function pointers in templates)\n// 30-Oct-04 1.3  * Support for (non-void) return values.\n//\t\t\t\t  * No more workarounds in client code!\n//\t\t\t\t\t MSVC and Intel now use a clever hack invented by John Dlugosz:\n//\t\t\t\t     - The FASTDELEGATEDECLARE workaround is no longer necessary.\n//\t\t\t\t\t - No more warning messages for VC6\n//\t\t\t\t  * Less use of macros. Error messages should be more comprehensible.\n//\t\t\t\t  * Added include guards\n//\t\t\t\t  * Added FastDelegate::empty() to test if invocation is safe (Thanks Neville Franks).\n//\t\t\t\t  * Now tested on VS 2005 Express Beta, PGI C++\n// 24-Dec-04 1.4  * Added DelegateMemento, to allow collections of disparate delegates.\n//                * <,>,<=,>= comparison operators to allow storage in ordered containers.\n//\t\t\t\t  * Substantial reduction of code size, especially the 'Closure' class.\n//\t\t\t\t  * Standardised all the compiler-specific workarounds.\n//                * MFP conversion now works for CodePlay (but not yet supported in the full code).\n//                * Now compiles without warnings on _any_ supported compiler, including BCC 5.5.1\n//\t\t\t\t  * New syntax: FastDelegate< int (char *, double) >. \n// 14-Feb-05 1.4.1* Now treats =0 as equivalent to .clear(), ==0 as equivalent to .empty(). (Thanks elfric).\n//\t\t\t\t  * Now tested on Intel ICL for AMD64, VS2005 Beta for AMD64 and Itanium.\n// 30-Mar-05 1.5  * Safebool idiom: \"if (dg)\" is now equivalent to \"if (!dg.empty())\"\n//\t\t\t\t  * Fully supported by CodePlay VectorC\n//                * Bugfix for Metrowerks: empty() was buggy because a valid MFP can be 0 on MWCC!\n//                * More optimal assignment,== and != operators for static function pointers.\n\n#ifndef FASTDELEGATE_H\n#define FASTDELEGATE_H\n#if _MSC_VER > 1000\n#pragma once\n#endif // _MSC_VER > 1000\n\n#include <memory.h> // to allow <,> comparisons\n\n////////////////////////////////////////////////////////////////////////////////\n//\t\t\t\t\t\tConfiguration options\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// Uncomment the following #define for optimally-sized delegates.\n// In this case, the generated asm code is almost identical to the code you'd get\n// if the compiler had native support for delegates.\n// It will not work on systems where sizeof(dataptr) < sizeof(codeptr). \n// Thus, it will not work for DOS compilers using the medium model.\n// It will also probably fail on some DSP systems.\n#define FASTDELEGATE_USESTATICFUNCTIONHACK\n\n// Uncomment the next line to allow function declarator syntax.\n// It is automatically enabled for those compilers where it is known to work.\n//#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n\n////////////////////////////////////////////////////////////////////////////////\n//\t\t\t\t\t\tCompiler identification for workarounds\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// Compiler identification. It's not easy to identify Visual C++ because\n// many vendors fraudulently define Microsoft's identifiers.\n#if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__VECTOR_C) && !defined(__ICL) && !defined(__BORLANDC__)\n#define FASTDLGT_ISMSVC\n\n#if (_MSC_VER <1300) // Many workarounds are required for VC6.\n#define FASTDLGT_VC6\n#pragma warning(disable:4786) // disable this ridiculous warning\n#endif\n\n#endif\n\n// Does the compiler uses Microsoft's member function pointer structure?\n// If so, it needs special treatment.\n// Metrowerks CodeWarrior, Intel, and CodePlay fraudulently define Microsoft's \n// identifier, _MSC_VER. We need to filter Metrowerks out.\n#if defined(_MSC_VER) && !defined(__MWERKS__)\n#define FASTDLGT_MICROSOFT_MFP\n\n#if !defined(__VECTOR_C)\n// CodePlay doesn't have the __single/multi/virtual_inheritance keywords\n#define FASTDLGT_HASINHERITANCE_KEYWORDS\n#endif\n#endif\n\n// Does it allow function declarator syntax? The following compilers are known to work:\n#if defined(FASTDLGT_ISMSVC) && (_MSC_VER >=1310) // VC 7.1\n#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n#endif\n\n// Gcc(2.95+), and versions of Digital Mars, Intel and Comeau in common use.\n#if defined (__DMC__) || defined(__GNUC__) || defined(__ICL) || defined(__COMO__)\n#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n#endif\n\n// It works on Metrowerks MWCC 3.2.2. From boost.Config it should work on earlier ones too.\n#if defined (__MWERKS__)\n#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n#endif\n\n#ifdef __GNUC__ // Workaround GCC bug #8271 \n\t// At present, GCC doesn't recognize constness of MFPs in templates\n#define FASTDELEGATE_GCC_BUG_8271\n#endif\n\n\n\n////////////////////////////////////////////////////////////////////////////////\n//\t\t\t\t\t\tGeneral tricks used in this code\n//\n// (a) Error messages are generated by typdefing an array of negative size to\n//     generate compile-time errors.\n// (b) Warning messages on MSVC are generated by declaring unused variables, and\n//\t    enabling the \"variable XXX is never used\" warning.\n// (c) Unions are used in a few compiler-specific cases to perform illegal casts.\n// (d) For Microsoft and Intel, when adjusting the 'this' pointer, it's cast to\n//     (char *) first to ensure that the correct number of *bytes* are added.\n//\n////////////////////////////////////////////////////////////////////////////////\n//\t\t\t\t\t\tHelper templates\n//\n////////////////////////////////////////////////////////////////////////////////\n\n\nnamespace fastdelegate {\nnamespace detail {\t// we'll hide the implementation details in a nested namespace.\n\n//\t\timplicit_cast< >\n// I believe this was originally going to be in the C++ standard but \n// was left out by accident. It's even milder than static_cast.\n// I use it instead of static_cast<> to emphasize that I'm not doing\n// anything nasty. \n// Usage is identical to static_cast<>\ntemplate <class OutputClass, class InputClass>\ninline OutputClass implicit_cast(InputClass input){\n\treturn input;\n}\n\n//\t\thorrible_cast< >\n// This is truly evil. It completely subverts C++'s type system, allowing you \n// to cast from any class to any other class. Technically, using a union \n// to perform the cast is undefined behaviour (even in C). But we can see if\n// it is OK by checking that the union is the same size as each of its members.\n// horrible_cast<> should only be used for compiler-specific workarounds. \n// Usage is identical to reinterpret_cast<>.\n\n// This union is declared outside the horrible_cast because BCC 5.5.1\n// can't inline a function with a nested class, and gives a warning.\ntemplate <class OutputClass, class InputClass>\nunion horrible_union{\n\tOutputClass out;\n\tInputClass in;\n};\n\ntemplate <class OutputClass, class InputClass>\ninline OutputClass horrible_cast(const InputClass input){\n\thorrible_union<OutputClass, InputClass> u;\n\t// Cause a compile-time error if in, out and u are not the same size.\n\t// If the compile fails here, it means the compiler has peculiar\n\t// unions which would prevent the cast from working.\n\ttypedef int ERROR_CantUseHorrible_cast[sizeof(InputClass)==sizeof(u) \n\t\t&& sizeof(InputClass)==sizeof(OutputClass) ? 1 : -1];\n\tu.in = input;\n\treturn u.out;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//\t\t\t\t\t\tWorkarounds\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// Backwards compatibility: This macro used to be necessary in the virtual inheritance\n// case for Intel and Microsoft. Now it just forward-declares the class.\n#define FASTDELEGATEDECLARE(CLASSNAME)\tclass CLASSNAME;\n\n// Prevent use of the static function hack with the DOS medium model.\n#ifdef __MEDIUM__\n#undef FASTDELEGATE_USESTATICFUNCTIONHACK\n#endif\n\n//\t\t\tDefaultVoid - a workaround for 'void' templates in VC6.\n//\n//  (1) VC6 and earlier do not allow 'void' as a default template argument.\n//  (2) They also doesn't allow you to return 'void' from a function.\n//\n// Workaround for (1): Declare a dummy type 'DefaultVoid' which we use\n//   when we'd like to use 'void'. We convert it into 'void' and back\n//   using the templates DefaultVoidToVoid<> and VoidToDefaultVoid<>.\n// Workaround for (2): On VC6, the code for calling a void function is\n//   identical to the code for calling a non-void function in which the\n//   return value is never used, provided the return value is returned\n//   in the EAX register, rather than on the stack. \n//   This is true for most fundamental types such as int, enum, void *.\n//   Const void * is the safest option since it doesn't participate \n//   in any automatic conversions. But on a 16-bit compiler it might\n//   cause extra code to be generated, so we disable it for all compilers\n//   except for VC6 (and VC5).\n#ifdef FASTDLGT_VC6\n// VC6 workaround\ntypedef const void * DefaultVoid;\n#else\n// On any other compiler, just use a normal void.\ntypedef void DefaultVoid;\n#endif\n\n// Translate from 'DefaultVoid' to 'void'.\n// Everything else is unchanged\ntemplate <class T>\nstruct DefaultVoidToVoid { typedef T type; };\n\ntemplate <>\nstruct DefaultVoidToVoid<DefaultVoid> {\ttypedef void type; };\n\n// Translate from 'void' into 'DefaultVoid'\n// Everything else is unchanged\ntemplate <class T>\nstruct VoidToDefaultVoid { typedef T type; };\n\ntemplate <>\nstruct VoidToDefaultVoid<void> { typedef DefaultVoid type; };\n\n\n\n////////////////////////////////////////////////////////////////////////////////\n//\t\t\t\t\t\tFast Delegates, part 1:\n//\n//\t\tConversion of member function pointer to a standard form\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// GenericClass is a fake class, ONLY used to provide a type.\n// It is vitally important that it is never defined, so that the compiler doesn't\n// think it can optimize the invocation. For example, Borland generates simpler\n// code if it knows the class only uses single inheritance.\n\n// Compilers using Microsoft's structure need to be treated as a special case.\n#ifdef  FASTDLGT_MICROSOFT_MFP\n\n#ifdef FASTDLGT_HASINHERITANCE_KEYWORDS\n\t// For Microsoft and Intel, we want to ensure that it's the most efficient type of MFP \n\t// (4 bytes), even when the /vmg option is used. Declaring an empty class \n\t// would give 16 byte pointers in this case....\n\tclass __single_inheritance GenericClass;\n#endif\n\t// ...but for Codeplay, an empty class *always* gives 4 byte pointers.\n\t// If compiled with the /clr option (\"managed C++\"), the JIT compiler thinks\n\t// it needs to load GenericClass before it can call any of its functions,\n\t// (compiles OK but crashes at runtime!), so we need to declare an \n\t// empty class to make it happy.\n\t// Codeplay and VC4 can't cope with the unknown_inheritance case either.\n\tclass GenericClass {};\n#else\n\tclass GenericClass;\n#endif\n\n// The size of a single inheritance member function pointer.\nconst int SINGLE_MEMFUNCPTR_SIZE = sizeof(void (GenericClass::*)());\n\n//\t\t\t\t\t\tSimplifyMemFunc< >::Convert()\n//\n//\tA template function that converts an arbitrary member function pointer into the \n//\tsimplest possible form of member function pointer, using a supplied 'this' pointer.\n//  According to the standard, this can be done legally with reinterpret_cast<>.\n//\tFor (non-standard) compilers which use member function pointers which vary in size \n//  depending on the class, we need to use\tknowledge of the internal structure of a \n//  member function pointer, as used by the compiler. Template specialization is used\n//  to distinguish between the sizes. Because some compilers don't support partial \n//\ttemplate specialisation, I use full specialisation of a wrapper struct.\n\n// general case -- don't know how to convert it. Force a compile failure\ntemplate <int N>\nstruct SimplifyMemFunc {\n\ttemplate <class X, class XFuncType, class GenericMemFuncType>\n\tinline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, \n\t\tGenericMemFuncType &bound_func) { \n\t\t// Unsupported member function type -- force a compile failure.\n\t    // (it's illegal to have a array with negative size).\n\t\ttypedef char ERROR_Unsupported_member_function_pointer_on_this_compiler[N-100];\n\t\treturn 0; \n\t}\n};\n\n// For compilers where all member func ptrs are the same size, everything goes here.\n// For non-standard compilers, only single_inheritance classes go here.\ntemplate <>\nstruct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE>  {\t\n\ttemplate <class X, class XFuncType, class GenericMemFuncType>\n\tinline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, \n\t\t\tGenericMemFuncType &bound_func) {\n#if defined __DMC__  \n\t\t// Digital Mars doesn't allow you to cast between abitrary PMF's, \n\t\t// even though the standard says you can. The 32-bit compiler lets you\n\t\t// static_cast through an int, but the DOS compiler doesn't.\n\t\tbound_func = horrible_cast<GenericMemFuncType>(function_to_bind);\n#else \n        bound_func = reinterpret_cast<GenericMemFuncType>(function_to_bind);\n#endif\n        return reinterpret_cast<GenericClass *>(pthis);\n\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////\n//\t\t\t\t\t\tFast Delegates, part 1b:\n//\n//\t\t\t\t\tWorkarounds for Microsoft and Intel\n//\n////////////////////////////////////////////////////////////////////////////////\n\n\n// Compilers with member function pointers which violate the standard (MSVC, Intel, Codeplay),\n// need to be treated as a special case.\n#ifdef FASTDLGT_MICROSOFT_MFP\n\n// We use unions to perform horrible_casts. I would like to use #pragma pack(push, 1)\n// at the start of each function for extra safety, but VC6 seems to ICE\n// intermittently if you do this inside a template.\n\n// __multiple_inheritance classes go here\n// Nasty hack for Microsoft and Intel (IA32 and Itanium)\ntemplate<>\nstruct SimplifyMemFunc< SINGLE_MEMFUNCPTR_SIZE + sizeof(int) >  {\n\ttemplate <class X, class XFuncType, class GenericMemFuncType>\n\tinline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, \n\t\tGenericMemFuncType &bound_func) { \n\t\t// We need to use a horrible_cast to do this conversion.\n\t\t// In MSVC, a multiple inheritance member pointer is internally defined as:\n        union {\n\t\t\tXFuncType func;\n\t\t\tstruct {\t \n\t\t\t\tGenericMemFuncType funcaddress; // points to the actual member function\n\t\t\t\tint delta;\t     // #BYTES to be added to the 'this' pointer\n\t\t\t}s;\n        } u;\n\t\t// Check that the horrible_cast will work\n\t\ttypedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)? 1 : -1];\n        u.func = function_to_bind;\n\t\tbound_func = u.s.funcaddress;\n\t\treturn reinterpret_cast<GenericClass *>(reinterpret_cast<char *>(pthis) + u.s.delta); \n\t}\n};\n\n// virtual inheritance is a real nuisance. It's inefficient and complicated.\n// On MSVC and Intel, there isn't enough information in the pointer itself to\n// enable conversion to a closure pointer. Earlier versions of this code didn't\n// work for all cases, and generated a compile-time error instead.\n// But a very clever hack invented by John M. Dlugosz solves this problem.\n// My code is somewhat different to his: I have no asm code, and I make no \n// assumptions about the calling convention that is used.\n\n// In VC++ and ICL, a virtual_inheritance member pointer \n// is internally defined as:\nstruct MicrosoftVirtualMFP {\n\tvoid (GenericClass::*codeptr)(); // points to the actual member function\n\tint delta;\t\t// #bytes to be added to the 'this' pointer\n\tint vtable_index; // or 0 if no virtual inheritance\n};\n// The CRUCIAL feature of Microsoft/Intel MFPs which we exploit is that the\n// m_codeptr member is *always* called, regardless of the values of the other\n// members. (This is *not* true for other compilers, eg GCC, which obtain the\n// function address from the vtable if a virtual function is being called).\n// Dlugosz's trick is to make the codeptr point to a probe function which\n// returns the 'this' pointer that was used.\n\n// Define a generic class that uses virtual inheritance.\n// It has a trival member function that returns the value of the 'this' pointer.\nstruct GenericVirtualClass : virtual public GenericClass\n{\n\ttypedef GenericVirtualClass * (GenericVirtualClass::*ProbePtrType)();\n\tGenericVirtualClass * GetThis() { return this; }\n};\n\n// __virtual_inheritance classes go here\ntemplate <>\nstruct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 2*sizeof(int) >\n{\n\n\ttemplate <class X, class XFuncType, class GenericMemFuncType>\n\tinline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, \n\t\tGenericMemFuncType &bound_func) {\n\t\tunion {\n\t\t\tXFuncType func;\n\t\t\tGenericClass* (X::*ProbeFunc)();\n\t\t\tMicrosoftVirtualMFP s;\n\t\t} u;\n\t\tu.func = function_to_bind;\n\t\tbound_func = reinterpret_cast<GenericMemFuncType>(u.s.codeptr);\n\t\tunion {\n\t\t\tGenericVirtualClass::ProbePtrType virtfunc;\n\t\t\tMicrosoftVirtualMFP s;\n\t\t} u2;\n\t\t// Check that the horrible_cast<>s will work\n\t\ttypedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind)==sizeof(u.s)\n\t\t\t&& sizeof(function_to_bind)==sizeof(u.ProbeFunc)\n\t\t\t&& sizeof(u2.virtfunc)==sizeof(u2.s) ? 1 : -1];\n   // Unfortunately, taking the address of a MF prevents it from being inlined, so \n   // this next line can't be completely optimised away by the compiler.\n\t\tu2.virtfunc = &GenericVirtualClass::GetThis;\n\t\tu.s.codeptr = u2.s.codeptr;\n\t\treturn (pthis->*u.ProbeFunc)();\n\t}\n};\n\n#if (_MSC_VER <1300)\n\n// Nasty hack for Microsoft Visual C++ 6.0\n// unknown_inheritance classes go here\n// There is a compiler bug in MSVC6 which generates incorrect code in this case!!\ntemplate <>\nstruct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >\n{\n\ttemplate <class X, class XFuncType, class GenericMemFuncType>\n\tinline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, \n\t\tGenericMemFuncType &bound_func) {\n\t\t// There is an apalling but obscure compiler bug in MSVC6 and earlier:\n\t\t// vtable_index and 'vtordisp' are always set to 0 in the \n\t\t// unknown_inheritance case!\n\t\t// This means that an incorrect function could be called!!!\n\t\t// Compiling with the /vmg option leads to potentially incorrect code.\n\t\t// This is probably the reason that the IDE has a user interface for specifying\n\t\t// the /vmg option, but it is disabled -  you can only specify /vmg on \n\t\t// the command line. In VC1.5 and earlier, the compiler would ICE if it ever\n\t\t// encountered this situation.\n\t\t// It is OK to use the /vmg option if /vmm or /vms is specified.\n\n\t\t// Fortunately, the wrong function is only called in very obscure cases.\n\t\t// It only occurs when a derived class overrides a virtual function declared \n\t\t// in a virtual base class, and the member function \n\t\t// points to the *Derived* version of that function. The problem can be\n\t\t// completely averted in 100% of cases by using the *Base class* for the \n\t\t// member fpointer. Ie, if you use the base class as an interface, you'll\n\t\t// stay out of trouble.\n\t\t// Occasionally, you might want to point directly to a derived class function\n\t\t// that isn't an override of a base class. In this case, both vtable_index \n\t\t// and 'vtordisp' are zero, but a virtual_inheritance pointer will be generated.\n\t\t// We can generate correct code in this case. To prevent an incorrect call from\n\t\t// ever being made, on MSVC6 we generate a warning, and call a function to \n\t\t// make the program crash instantly. \n\t\ttypedef char ERROR_VC6CompilerBug[-100];\n\t\treturn 0; \n\t}\n};\n\n\n#else \n\n// Nasty hack for Microsoft and Intel (IA32 and Itanium)\n// unknown_inheritance classes go here \n// This is probably the ugliest bit of code I've ever written. Look at the casts!\n// There is a compiler bug in MSVC6 which prevents it from using this code.\ntemplate <>\nstruct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3*sizeof(int) >\n{\n\ttemplate <class X, class XFuncType, class GenericMemFuncType>\n\tinline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, \n\t\t\tGenericMemFuncType &bound_func) {\n\t\t// The member function pointer is 16 bytes long. We can't use a normal cast, but\n\t\t// we can use a union to do the conversion.\n\t\tunion {\n\t\t\tXFuncType func;\n\t\t\t// In VC++ and ICL, an unknown_inheritance member pointer \n\t\t\t// is internally defined as:\n\t\t\tstruct {\n\t\t\t\tGenericMemFuncType m_funcaddress; // points to the actual member function\n\t\t\t\tint delta;\t\t// #bytes to be added to the 'this' pointer\n\t\t\t\tint vtordisp;\t\t// #bytes to add to 'this' to find the vtable\n\t\t\t\tint vtable_index; // or 0 if no virtual inheritance\n\t\t\t} s;\n\t\t} u;\n\t\t// Check that the horrible_cast will work\n\t\ttypedef int ERROR_CantUsehorrible_cast[sizeof(XFuncType)==sizeof(u.s)? 1 : -1];\n\t\tu.func = function_to_bind;\n\t\tbound_func = u.s.funcaddress;\n\t\tint virtual_delta = 0;\n\t\tif (u.s.vtable_index) { // Virtual inheritance is used\n\t\t\t// First, get to the vtable. \n\t\t\t// It is 'vtordisp' bytes from the start of the class.\n\t\t\tconst int * vtable = *reinterpret_cast<const int *const*>(\n\t\t\t\treinterpret_cast<const char *>(pthis) + u.s.vtordisp );\n\n\t\t\t// 'vtable_index' tells us where in the table we should be looking.\n\t\t\tvirtual_delta = u.s.vtordisp + *reinterpret_cast<const int *>( \n\t\t\t\treinterpret_cast<const char *>(vtable) + u.s.vtable_index);\n\t\t}\n\t\t// The int at 'virtual_delta' gives us the amount to add to 'this'.\n        // Finally we can add the three components together. Phew!\n        return reinterpret_cast<GenericClass *>(\n\t\t\treinterpret_cast<char *>(pthis) + u.s.delta + virtual_delta);\n\t};\n};\n#endif // MSVC 7 and greater\n\n#endif // MS/Intel hacks\n\n}  // namespace detail\n\n////////////////////////////////////////////////////////////////////////////////\n//\t\t\t\t\t\tFast Delegates, part 2:\n//\n//\tDefine the delegate storage, and cope with static functions\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// DelegateMemento -- an opaque structure which can hold an arbitary delegate.\n// It knows nothing about the calling convention or number of arguments used by\n// the function pointed to.\n// It supplies comparison operators so that it can be stored in STL collections.\n// It cannot be set to anything other than null, nor invoked directly: \n//   it must be converted to a specific delegate.\n\n// Implementation:\n// There are two possible implementations: the Safe method and the Evil method.\n//\t\t\t\tDelegateMemento - Safe version\n//\n// This implementation is standard-compliant, but a bit tricky.\n// A static function pointer is stored inside the class. \n// Here are the valid values:\n// +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+\n// |   0\t\t\t\t|  0       |   0        | Empty          |\n// |   !=0              |(dontcare)|  Invoker   | Static function|\n// |   0                |  !=0     |  !=0*      | Method call    |\n// +--------------------+----------+------------+----------------+\n//  * For Metrowerks, this can be 0. (first virtual function in a \n//       single_inheritance class).\n// When stored stored inside a specific delegate, the 'dontcare' entries are replaced\n// with a reference to the delegate itself. This complicates the = and == operators\n// for the delegate class.\n\n//\t\t\t\tDelegateMemento - Evil version\n//\n// For compilers where data pointers are at least as big as code pointers, it is \n// possible to store the function pointer in the this pointer, using another \n// horrible_cast. In this case the DelegateMemento implementation is simple:\n// +--pThis --+-- pMemFunc-+-- Meaning---------------------+\n// |    0     |  0         | Empty                         |\n// |  !=0     |  !=0*      | Static function or method call|\n// +----------+------------+-------------------------------+\n//  * For Metrowerks, this can be 0. (first virtual function in a \n//       single_inheritance class).\n// Note that the Sun C++ and MSVC documentation explicitly state that they \n// support static_cast between void * and function pointers.\n\nclass DelegateMemento {\nprotected: \n\t// the data is protected, not private, because many\n\t// compilers have problems with template friends.\n\ttypedef void (detail::GenericClass::*GenericMemFuncType)(); // arbitrary MFP.\n\tdetail::GenericClass *m_pthis;\n\tGenericMemFuncType m_pFunction;\n\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n\ttypedef void (*GenericFuncPtr)(); // arbitrary code pointer\n\tGenericFuncPtr m_pStaticFunction;\n#endif\n\npublic:\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n\tDelegateMemento() : m_pthis(0), m_pFunction(0), m_pStaticFunction(0) {};\n\tvoid clear() {\n\t\tm_pthis=0; m_pFunction=0; m_pStaticFunction=0;\n\t}\n#else\n\tDelegateMemento() : m_pthis(0), m_pFunction(0) {};\n\tvoid clear() {\tm_pthis=0; m_pFunction=0;\t}\n#endif\npublic:\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n\tinline bool IsEqual (const DelegateMemento &x) const{\n\t    // We have to cope with the static function pointers as a special case\n\t\tif (m_pFunction!=x.m_pFunction) return false;\n\t\t// the static function ptrs must either both be equal, or both be 0.\n\t\tif (m_pStaticFunction!=x.m_pStaticFunction) return false;\n\t\tif (m_pStaticFunction!=0) return m_pthis==x.m_pthis;\n\t\telse return true;\n\t}\n#else // Evil Method\n\tinline bool IsEqual (const DelegateMemento &x) const{\n\t\treturn m_pthis==x.m_pthis && m_pFunction==x.m_pFunction;\n\t}\n#endif\n\t// Provide a strict weak ordering for DelegateMementos.\n\tinline bool IsLess(const DelegateMemento &right) const {\n\t\t// deal with static function pointers first\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n\t\tif (m_pStaticFunction !=0 || right.m_pStaticFunction!=0) \n\t\t\t\treturn m_pStaticFunction < right.m_pStaticFunction;\n#endif\n\t\tif (m_pthis !=right.m_pthis) return m_pthis < right.m_pthis;\n\t// There are no ordering operators for member function pointers, \n\t// but we can fake one by comparing each byte. The resulting ordering is\n\t// arbitrary (and compiler-dependent), but it permits storage in ordered STL containers.\n\t\treturn memcmp(&m_pFunction, &right.m_pFunction, sizeof(m_pFunction)) < 0;\n\n\t}\n\t// BUGFIX (Mar 2005):\n\t// We can't just compare m_pFunction because on Metrowerks,\n\t// m_pFunction can be zero even if the delegate is not empty!\n\tinline bool operator ! () const\t\t// Is it bound to anything?\n\t{ return m_pthis==0 && m_pFunction==0; }\n\tinline bool empty() const\t\t// Is it bound to anything?\n\t{ return m_pthis==0 && m_pFunction==0; }\npublic:\n\tDelegateMemento & operator = (const DelegateMemento &right)  {\n\t\tSetMementoFrom(right); \n\t\treturn *this;\n\t}\n\tinline bool operator <(const DelegateMemento &right) {\n\t\treturn IsLess(right);\n\t}\n\tinline bool operator >(const DelegateMemento &right) {\n\t\treturn right.IsLess(*this);\n\t}\n\tDelegateMemento (const DelegateMemento &right)  : \n\t\tm_pFunction(right.m_pFunction), m_pthis(right.m_pthis)\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n\t\t, m_pStaticFunction (right.m_pStaticFunction)\n#endif\n\t\t{}\nprotected:\n\tvoid SetMementoFrom(const DelegateMemento &right)  {\n\t\tm_pFunction = right.m_pFunction;\n\t\tm_pthis = right.m_pthis;\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n\t\tm_pStaticFunction = right.m_pStaticFunction;\n#endif\n\t}\n};\n\n\n//\t\t\t\t\t\tClosurePtr<>\n//\n// A private wrapper class that adds function signatures to DelegateMemento.\n// It's the class that does most of the actual work.\n// The signatures are specified by:\n// GenericMemFunc: must be a type of GenericClass member function pointer. \n// StaticFuncPtr:  must be a type of function pointer with the same signature \n//                 as GenericMemFunc.\n// UnvoidStaticFuncPtr: is the same as StaticFuncPtr, except on VC6\n//                 where it never returns void (returns DefaultVoid instead).\n\n// An outer class, FastDelegateN<>, handles the invoking and creates the\n// necessary typedefs.\n// This class does everything else.\n\nnamespace detail {\n\ntemplate < class GenericMemFunc, class StaticFuncPtr, class UnvoidStaticFuncPtr>\nclass ClosurePtr : public DelegateMemento {\npublic:\n\t// These functions are for setting the delegate to a member function.\n\n\t// Here's the clever bit: we convert an arbitrary member function into a \n\t// standard form. XMemFunc should be a member function of class X, but I can't \n\t// enforce that here. It needs to be enforced by the wrapper class.\n\ttemplate < class X, class XMemFunc >\n\tinline void bindmemfunc(X *pthis, XMemFunc function_to_bind ) {\n\t\tm_pthis = SimplifyMemFunc< sizeof(function_to_bind) >\n\t\t\t::Convert(pthis, function_to_bind, m_pFunction);\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n\t\tm_pStaticFunction = 0;\n#endif\n\t}\n\t// For const member functions, we only need a const class pointer.\n\t// Since we know that the member function is const, it's safe to \n\t// remove the const qualifier from the 'this' pointer with a const_cast.\n\t// VC6 has problems if we just overload 'bindmemfunc', so we give it a different name.\n\ttemplate < class X, class XMemFunc>\n\tinline void bindconstmemfunc(const X *pthis, XMemFunc function_to_bind) {\n\t\tm_pthis= SimplifyMemFunc< sizeof(function_to_bind) >\n\t\t\t::Convert(const_cast<X*>(pthis), function_to_bind, m_pFunction);\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n\t\tm_pStaticFunction = 0;\n#endif\n\t}\n#ifdef FASTDELEGATE_GCC_BUG_8271\t// At present, GCC doesn't recognize constness of MFPs in templates\n\ttemplate < class X, class XMemFunc>\n\tinline void bindmemfunc(const X *pthis, XMemFunc function_to_bind) {\n\t\tbindconstmemfunc(pthis, function_to_bind);\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n\t\tm_pStaticFunction = 0;\n#endif\n\t}\n#endif\n\t// These functions are required for invoking the stored function\n\tinline GenericClass *GetClosureThis() const { return m_pthis; }\n\tinline GenericMemFunc GetClosureMemPtr() const { return reinterpret_cast<GenericMemFunc>(m_pFunction); }\n\n// There are a few ways of dealing with static function pointers.\n// There's a standard-compliant, but tricky method.\n// There's also a straightforward hack, that won't work on DOS compilers using the\n// medium memory model. It's so evil that I can't recommend it, but I've\n// implemented it anyway because it produces very nice asm code.\n\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n\n//\t\t\t\tClosurePtr<> - Safe version\n//\n// This implementation is standard-compliant, but a bit tricky.\n// I store the function pointer inside the class, and the delegate then\n// points to itself. Whenever the delegate is copied, these self-references\n// must be transformed, and this complicates the = and == operators.\npublic:\n\t// The next two functions are for operator ==, =, and the copy constructor.\n\t// We may need to convert the m_pthis pointers, so that\n\t// they remain as self-references.\n\ttemplate< class DerivedClass >\n\tinline void CopyFrom (DerivedClass *pParent, const DelegateMemento &x) {\n\t\tSetMementoFrom(x);\n\t\tif (m_pStaticFunction!=0) {\n\t\t\t// transform self references...\n\t\t\tm_pthis=reinterpret_cast<GenericClass *>(pParent);\n\t\t}\n\t}\n\t// For static functions, the 'static_function_invoker' class in the parent \n\t// will be called. The parent then needs to call GetStaticFunction() to find out \n\t// the actual function to invoke.\n\ttemplate < class DerivedClass, class ParentInvokerSig >\n\tinline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, \n\t\t\t\tStaticFuncPtr function_to_bind ) {\n\t\tif (function_to_bind==0) { // cope with assignment to 0\n\t\t\tm_pFunction=0;\n\t\t} else { \n\t\t\tbindmemfunc(pParent, static_function_invoker);\n        }\n\t\tm_pStaticFunction=reinterpret_cast<GenericFuncPtr>(function_to_bind);\n\t}\n\tinline UnvoidStaticFuncPtr GetStaticFunction() const { \n\t\treturn reinterpret_cast<UnvoidStaticFuncPtr>(m_pStaticFunction); \n\t}\n#else\n\n//\t\t\t\tClosurePtr<> - Evil version\n//\n// For compilers where data pointers are at least as big as code pointers, it is \n// possible to store the function pointer in the this pointer, using another \n// horrible_cast. Invocation isn't any faster, but it saves 4 bytes, and\n// speeds up comparison and assignment. If C++ provided direct language support\n// for delegates, they would produce asm code that was almost identical to this.\n// Note that the Sun C++ and MSVC documentation explicitly state that they \n// support static_cast between void * and function pointers.\n\n\ttemplate< class DerivedClass >\n\tinline void CopyFrom (DerivedClass *pParent, const DelegateMemento &right) {\n\t\tSetMementoFrom(right);\n\t}\n\t// For static functions, the 'static_function_invoker' class in the parent \n\t// will be called. The parent then needs to call GetStaticFunction() to find out \n\t// the actual function to invoke.\n\t// ******** EVIL, EVIL CODE! *******\n\ttemplate < \tclass DerivedClass, class ParentInvokerSig>\n\tinline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, \n\t\t\t\tStaticFuncPtr function_to_bind) {\n\t\tif (function_to_bind==0) { // cope with assignment to 0\n\t\t\tm_pFunction=0;\n\t\t} else { \n\t\t   // We'll be ignoring the 'this' pointer, but we need to make sure we pass\n\t\t   // a valid value to bindmemfunc().\n\t\t\tbindmemfunc(pParent, static_function_invoker);\n        }\n\n\t\t// WARNING! Evil hack. We store the function in the 'this' pointer!\n\t\t// Ensure that there's a compilation failure if function pointers \n\t\t// and data pointers have different sizes.\n\t\t// If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK.\n\t\ttypedef int ERROR_CantUseEvilMethod[sizeof(GenericClass *)==sizeof(function_to_bind) ? 1 : -1];\n\t\tm_pthis = horrible_cast<GenericClass *>(function_to_bind);\n\t\t// MSVC, SunC++ and DMC accept the following (non-standard) code:\n//\t\tm_pthis = static_cast<GenericClass *>(static_cast<void *>(function_to_bind));\n\t\t// BCC32, Comeau and DMC accept this method. MSVC7.1 needs __int64 instead of long\n//\t\tm_pthis = reinterpret_cast<GenericClass *>(reinterpret_cast<long>(function_to_bind));\n\t}\n\t// ******** EVIL, EVIL CODE! *******\n\t// This function will be called with an invalid 'this' pointer!!\n\t// We're just returning the 'this' pointer, converted into\n\t// a function pointer!\n\tinline UnvoidStaticFuncPtr GetStaticFunction() const {\n\t\t// Ensure that there's a compilation failure if function pointers \n\t\t// and data pointers have different sizes.\n\t\t// If you get this error, you need to #undef FASTDELEGATE_USESTATICFUNCTIONHACK.\n\t\ttypedef int ERROR_CantUseEvilMethod[sizeof(UnvoidStaticFuncPtr)==sizeof(this) ? 1 : -1];\n\t\treturn horrible_cast<UnvoidStaticFuncPtr>(this);\n\t}\n#endif // !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n\n\t// Does the closure contain this static function?\n\tinline bool IsEqualToStaticFuncPtr(StaticFuncPtr funcptr){\n\t\tif (funcptr==0) return empty(); \n\t// For the Evil method, if it doesn't actually contain a static function, this will return an arbitrary\n\t// value that is not equal to any valid function pointer.\n\t\telse return funcptr==reinterpret_cast<StaticFuncPtr>(GetStaticFunction());\n\t}\n};\n\n\n} // namespace detail\n\n////////////////////////////////////////////////////////////////////////////////\n//\t\t\t\t\t\tFast Delegates, part 3:\n//\n//\t\t\t\tWrapper classes to ensure type safety\n//\n////////////////////////////////////////////////////////////////////////////////\n\n\n// Once we have the member function conversion templates, it's easy to make the\n// wrapper classes. So that they will work with as many compilers as possible, \n// the classes are of the form\n//   FastDelegate3<int, char *, double>\n// They can cope with any combination of parameters. The max number of parameters\n// allowed is 8, but it is trivial to increase this limit.\n// Note that we need to treat const member functions seperately.\n// All this class does is to enforce type safety, and invoke the delegate with\n// the correct list of parameters.\n\n// Because of the weird rule about the class of derived member function pointers,\n// you sometimes need to apply a downcast to the 'this' pointer.\n// This is the reason for the use of \"implicit_cast<X*>(pthis)\" in the code below. \n// If CDerivedClass is derived from CBaseClass, but doesn't override SimpleVirtualFunction,\n// without this trick you'd need to write:\n//\t\tMyDelegate(static_cast<CBaseClass *>(&d), &CDerivedClass::SimpleVirtualFunction);\n// but with the trick you can write\n//\t\tMyDelegate(&d, &CDerivedClass::SimpleVirtualFunction);\n\n// RetType is the type the compiler uses in compiling the template. For VC6,\n// it cannot be void. DesiredRetType is the real type which is returned from\n// all of the functions. It can be void.\n\n// Implicit conversion to \"bool\" is achieved using the safe_bool idiom,\n// using member data pointers (MDP). This allows \"if (dg)...\" syntax\n// Because some compilers (eg codeplay) don't have a unique value for a zero\n// MDP, an extra padding member is added to the SafeBool struct.\n// Some compilers (eg VC6) won't implicitly convert from 0 to an MDP, so\n// in that case the static function constructor is not made explicit; this\n// allows \"if (dg==0) ...\" to compile.\n\n//N=0\ntemplate<class RetType=detail::DefaultVoid>\nclass FastDelegate0 {\nprivate:\n\ttypedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n\ttypedef DesiredRetType (*StaticFunctionPtr)();\n\ttypedef RetType (*UnvoidStaticFunctionPtr)();\n\ttypedef RetType (detail::GenericClass::*GenericMemFn)();\n\ttypedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;\n\tClosureType m_Closure;\npublic:\n\t// Typedefs to aid generic programming\n\ttypedef FastDelegate0 type;\n\n\t// Construction and comparison functions\n\tFastDelegate0() { clear(); }\n\tFastDelegate0(const FastDelegate0 &x) {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tvoid operator = (const FastDelegate0 &x)  {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tbool operator ==(const FastDelegate0 &x) const {\n\t\treturn m_Closure.IsEqual(x.m_Closure);\t}\n\tbool operator !=(const FastDelegate0 &x) const {\n\t\treturn !m_Closure.IsEqual(x.m_Closure); }\n\tbool operator <(const FastDelegate0 &x) const {\n\t\treturn m_Closure.IsLess(x.m_Closure);\t}\n\tbool operator >(const FastDelegate0 &x) const {\n\t\treturn x.m_Closure.IsLess(m_Closure);\t}\n\t// Binding to non-const member functions\n\ttemplate < class X, class Y >\n\tFastDelegate0(Y *pthis, DesiredRetType (X::* function_to_bind)() ) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }\n\ttemplate < class X, class Y >\n\tinline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)()) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);\t}\n\t// Binding to const member functions.\n\ttemplate < class X, class Y >\n\tFastDelegate0(const Y *pthis, DesiredRetType (X::* function_to_bind)() const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);\t}\n\ttemplate < class X, class Y >\n\tinline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)() const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);\t}\n\t// Static functions. We convert them into a member function call.\n\t// This constructor also provides implicit conversion\n\tFastDelegate0(DesiredRetType (*function_to_bind)() ) {\n\t\tbind(function_to_bind);\t}\n\t// for efficiency, prevent creation of a temporary\n\tvoid operator = (DesiredRetType (*function_to_bind)() ) {\n\t\tbind(function_to_bind);\t}\n\tinline void bind(DesiredRetType (*function_to_bind)()) {\n\t\tm_Closure.bindstaticfunc(this, &FastDelegate0::InvokeStaticFunction, \n\t\t\tfunction_to_bind); }\n\t// Invoke the delegate\n\tRetType operator() () const {\n\treturn (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(); }\n\t// Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n\ttypedef struct SafeBoolStruct {\n\t\tint a_data_pointer_to_this_is_0_on_buggy_compilers;\n\t\tStaticFunctionPtr m_nonzero;\n\t} UselessTypedef;\n    typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\npublic:\n\toperator unspecified_bool_type() const {\n        return empty()? 0: &SafeBoolStruct::m_nonzero;\n    }\n\t// necessary to allow ==0 to work despite the safe_bool idiom\n\tinline bool operator==(StaticFunctionPtr funcptr) {\n\t\treturn m_Closure.IsEqualToStaticFuncPtr(funcptr);\t}\n\tinline bool operator!=(StaticFunctionPtr funcptr) { \n\t\treturn !m_Closure.IsEqualToStaticFuncPtr(funcptr);    }\n\tinline bool operator ! () const\t{\t// Is it bound to anything?\n\t\t\treturn !m_Closure; }\n\tinline bool empty() const\t{\n\t\t\treturn !m_Closure; }\n\tvoid clear() { m_Closure.clear();}\n\t// Conversion to and from the DelegateMemento storage class\n\tconst DelegateMemento & GetMemento() { return m_Closure; }\n\tvoid SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate:\t// Invoker for static functions\n\tRetType InvokeStaticFunction() const {\n\treturn (*(m_Closure.GetStaticFunction()))(); }\n};\n\n//N=1\ntemplate<class Param1, class RetType=detail::DefaultVoid>\nclass FastDelegate1 {\nprivate:\n\ttypedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n\ttypedef DesiredRetType (*StaticFunctionPtr)(Param1 p1);\n\ttypedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1);\n\ttypedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1);\n\ttypedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;\n\tClosureType m_Closure;\npublic:\n\t// Typedefs to aid generic programming\n\ttypedef FastDelegate1 type;\n\n\t// Construction and comparison functions\n\tFastDelegate1() { clear(); }\n\tFastDelegate1(const FastDelegate1 &x) {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tvoid operator = (const FastDelegate1 &x)  {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tbool operator ==(const FastDelegate1 &x) const {\n\t\treturn m_Closure.IsEqual(x.m_Closure);\t}\n\tbool operator !=(const FastDelegate1 &x) const {\n\t\treturn !m_Closure.IsEqual(x.m_Closure); }\n\tbool operator <(const FastDelegate1 &x) const {\n\t\treturn m_Closure.IsLess(x.m_Closure);\t}\n\tbool operator >(const FastDelegate1 &x) const {\n\t\treturn x.m_Closure.IsLess(m_Closure);\t}\n\t// Binding to non-const member functions\n\ttemplate < class X, class Y >\n\tFastDelegate1(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) ) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }\n\ttemplate < class X, class Y >\n\tinline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1)) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);\t}\n\t// Binding to const member functions.\n\ttemplate < class X, class Y >\n\tFastDelegate1(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);\t}\n\ttemplate < class X, class Y >\n\tinline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);\t}\n\t// Static functions. We convert them into a member function call.\n\t// This constructor also provides implicit conversion\n\tFastDelegate1(DesiredRetType (*function_to_bind)(Param1 p1) ) {\n\t\tbind(function_to_bind);\t}\n\t// for efficiency, prevent creation of a temporary\n\tvoid operator = (DesiredRetType (*function_to_bind)(Param1 p1) ) {\n\t\tbind(function_to_bind);\t}\n\tinline void bind(DesiredRetType (*function_to_bind)(Param1 p1)) {\n\t\tm_Closure.bindstaticfunc(this, &FastDelegate1::InvokeStaticFunction, \n\t\t\tfunction_to_bind); }\n\t// Invoke the delegate\n\tRetType operator() (Param1 p1) const {\n\treturn (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1); }\n\t// Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n\ttypedef struct SafeBoolStruct {\n\t\tint a_data_pointer_to_this_is_0_on_buggy_compilers;\n\t\tStaticFunctionPtr m_nonzero;\n\t} UselessTypedef;\n    typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\npublic:\n\toperator unspecified_bool_type() const {\n        return empty()? 0: &SafeBoolStruct::m_nonzero;\n    }\n\t// necessary to allow ==0 to work despite the safe_bool idiom\n\tinline bool operator==(StaticFunctionPtr funcptr) {\n\t\treturn m_Closure.IsEqualToStaticFuncPtr(funcptr);\t}\n\tinline bool operator!=(StaticFunctionPtr funcptr) { \n\t\treturn !m_Closure.IsEqualToStaticFuncPtr(funcptr);    }\n\tinline bool operator ! () const\t{\t// Is it bound to anything?\n\t\t\treturn !m_Closure; }\n\tinline bool empty() const\t{\n\t\t\treturn !m_Closure; }\n\tvoid clear() { m_Closure.clear();}\n\t// Conversion to and from the DelegateMemento storage class\n\tconst DelegateMemento & GetMemento() { return m_Closure; }\n\tvoid SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate:\t// Invoker for static functions\n\tRetType InvokeStaticFunction(Param1 p1) const {\n\treturn (*(m_Closure.GetStaticFunction()))(p1); }\n};\n\n//N=2\ntemplate<class Param1, class Param2, class RetType=detail::DefaultVoid>\nclass FastDelegate2 {\nprivate:\n\ttypedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n\ttypedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2);\n\ttypedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2);\n\ttypedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2);\n\ttypedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;\n\tClosureType m_Closure;\npublic:\n\t// Typedefs to aid generic programming\n\ttypedef FastDelegate2 type;\n\n\t// Construction and comparison functions\n\tFastDelegate2() { clear(); }\n\tFastDelegate2(const FastDelegate2 &x) {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tvoid operator = (const FastDelegate2 &x)  {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tbool operator ==(const FastDelegate2 &x) const {\n\t\treturn m_Closure.IsEqual(x.m_Closure);\t}\n\tbool operator !=(const FastDelegate2 &x) const {\n\t\treturn !m_Closure.IsEqual(x.m_Closure); }\n\tbool operator <(const FastDelegate2 &x) const {\n\t\treturn m_Closure.IsLess(x.m_Closure);\t}\n\tbool operator >(const FastDelegate2 &x) const {\n\t\treturn x.m_Closure.IsLess(m_Closure);\t}\n\t// Binding to non-const member functions\n\ttemplate < class X, class Y >\n\tFastDelegate2(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) ) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }\n\ttemplate < class X, class Y >\n\tinline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2)) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);\t}\n\t// Binding to const member functions.\n\ttemplate < class X, class Y >\n\tFastDelegate2(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);\t}\n\ttemplate < class X, class Y >\n\tinline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);\t}\n\t// Static functions. We convert them into a member function call.\n\t// This constructor also provides implicit conversion\n\tFastDelegate2(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2) ) {\n\t\tbind(function_to_bind);\t}\n\t// for efficiency, prevent creation of a temporary\n\tvoid operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2) ) {\n\t\tbind(function_to_bind);\t}\n\tinline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2)) {\n\t\tm_Closure.bindstaticfunc(this, &FastDelegate2::InvokeStaticFunction, \n\t\t\tfunction_to_bind); }\n\t// Invoke the delegate\n\tRetType operator() (Param1 p1, Param2 p2) const {\n\treturn (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2); }\n\t// Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n\ttypedef struct SafeBoolStruct {\n\t\tint a_data_pointer_to_this_is_0_on_buggy_compilers;\n\t\tStaticFunctionPtr m_nonzero;\n\t} UselessTypedef;\n    typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\npublic:\n\toperator unspecified_bool_type() const {\n        return empty()? 0: &SafeBoolStruct::m_nonzero;\n    }\n\t// necessary to allow ==0 to work despite the safe_bool idiom\n\tinline bool operator==(StaticFunctionPtr funcptr) {\n\t\treturn m_Closure.IsEqualToStaticFuncPtr(funcptr);\t}\n\tinline bool operator!=(StaticFunctionPtr funcptr) { \n\t\treturn !m_Closure.IsEqualToStaticFuncPtr(funcptr);    }\n\tinline bool operator ! () const\t{\t// Is it bound to anything?\n\t\t\treturn !m_Closure; }\n\tinline bool empty() const\t{\n\t\t\treturn !m_Closure; }\n\tvoid clear() { m_Closure.clear();}\n\t// Conversion to and from the DelegateMemento storage class\n\tconst DelegateMemento & GetMemento() { return m_Closure; }\n\tvoid SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate:\t// Invoker for static functions\n\tRetType InvokeStaticFunction(Param1 p1, Param2 p2) const {\n\treturn (*(m_Closure.GetStaticFunction()))(p1, p2); }\n};\n\n//N=3\ntemplate<class Param1, class Param2, class Param3, class RetType=detail::DefaultVoid>\nclass FastDelegate3 {\nprivate:\n\ttypedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n\ttypedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3);\n\ttypedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3);\n\ttypedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3);\n\ttypedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;\n\tClosureType m_Closure;\npublic:\n\t// Typedefs to aid generic programming\n\ttypedef FastDelegate3 type;\n\n\t// Construction and comparison functions\n\tFastDelegate3() { clear(); }\n\tFastDelegate3(const FastDelegate3 &x) {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tvoid operator = (const FastDelegate3 &x)  {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tbool operator ==(const FastDelegate3 &x) const {\n\t\treturn m_Closure.IsEqual(x.m_Closure);\t}\n\tbool operator !=(const FastDelegate3 &x) const {\n\t\treturn !m_Closure.IsEqual(x.m_Closure); }\n\tbool operator <(const FastDelegate3 &x) const {\n\t\treturn m_Closure.IsLess(x.m_Closure);\t}\n\tbool operator >(const FastDelegate3 &x) const {\n\t\treturn x.m_Closure.IsLess(m_Closure);\t}\n\t// Binding to non-const member functions\n\ttemplate < class X, class Y >\n\tFastDelegate3(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) ) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }\n\ttemplate < class X, class Y >\n\tinline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);\t}\n\t// Binding to const member functions.\n\ttemplate < class X, class Y >\n\tFastDelegate3(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);\t}\n\ttemplate < class X, class Y >\n\tinline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);\t}\n\t// Static functions. We convert them into a member function call.\n\t// This constructor also provides implicit conversion\n\tFastDelegate3(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) ) {\n\t\tbind(function_to_bind);\t}\n\t// for efficiency, prevent creation of a temporary\n\tvoid operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) ) {\n\t\tbind(function_to_bind);\t}\n\tinline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) {\n\t\tm_Closure.bindstaticfunc(this, &FastDelegate3::InvokeStaticFunction, \n\t\t\tfunction_to_bind); }\n\t// Invoke the delegate\n\tRetType operator() (Param1 p1, Param2 p2, Param3 p3) const {\n\treturn (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3); }\n\t// Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n\ttypedef struct SafeBoolStruct {\n\t\tint a_data_pointer_to_this_is_0_on_buggy_compilers;\n\t\tStaticFunctionPtr m_nonzero;\n\t} UselessTypedef;\n    typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\npublic:\n\toperator unspecified_bool_type() const {\n        return empty()? 0: &SafeBoolStruct::m_nonzero;\n    }\n\t// necessary to allow ==0 to work despite the safe_bool idiom\n\tinline bool operator==(StaticFunctionPtr funcptr) {\n\t\treturn m_Closure.IsEqualToStaticFuncPtr(funcptr);\t}\n\tinline bool operator!=(StaticFunctionPtr funcptr) { \n\t\treturn !m_Closure.IsEqualToStaticFuncPtr(funcptr);    }\n\tinline bool operator ! () const\t{\t// Is it bound to anything?\n\t\t\treturn !m_Closure; }\n\tinline bool empty() const\t{\n\t\t\treturn !m_Closure; }\n\tvoid clear() { m_Closure.clear();}\n\t// Conversion to and from the DelegateMemento storage class\n\tconst DelegateMemento & GetMemento() { return m_Closure; }\n\tvoid SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate:\t// Invoker for static functions\n\tRetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3) const {\n\treturn (*(m_Closure.GetStaticFunction()))(p1, p2, p3); }\n};\n\n//N=4\ntemplate<class Param1, class Param2, class Param3, class Param4, class RetType=detail::DefaultVoid>\nclass FastDelegate4 {\nprivate:\n\ttypedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n\ttypedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4);\n\ttypedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4);\n\ttypedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4);\n\ttypedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;\n\tClosureType m_Closure;\npublic:\n\t// Typedefs to aid generic programming\n\ttypedef FastDelegate4 type;\n\n\t// Construction and comparison functions\n\tFastDelegate4() { clear(); }\n\tFastDelegate4(const FastDelegate4 &x) {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tvoid operator = (const FastDelegate4 &x)  {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tbool operator ==(const FastDelegate4 &x) const {\n\t\treturn m_Closure.IsEqual(x.m_Closure);\t}\n\tbool operator !=(const FastDelegate4 &x) const {\n\t\treturn !m_Closure.IsEqual(x.m_Closure); }\n\tbool operator <(const FastDelegate4 &x) const {\n\t\treturn m_Closure.IsLess(x.m_Closure);\t}\n\tbool operator >(const FastDelegate4 &x) const {\n\t\treturn x.m_Closure.IsLess(m_Closure);\t}\n\t// Binding to non-const member functions\n\ttemplate < class X, class Y >\n\tFastDelegate4(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) ) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }\n\ttemplate < class X, class Y >\n\tinline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);\t}\n\t// Binding to const member functions.\n\ttemplate < class X, class Y >\n\tFastDelegate4(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);\t}\n\ttemplate < class X, class Y >\n\tinline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);\t}\n\t// Static functions. We convert them into a member function call.\n\t// This constructor also provides implicit conversion\n\tFastDelegate4(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) ) {\n\t\tbind(function_to_bind);\t}\n\t// for efficiency, prevent creation of a temporary\n\tvoid operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) ) {\n\t\tbind(function_to_bind);\t}\n\tinline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) {\n\t\tm_Closure.bindstaticfunc(this, &FastDelegate4::InvokeStaticFunction, \n\t\t\tfunction_to_bind); }\n\t// Invoke the delegate\n\tRetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4) const {\n\treturn (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4); }\n\t// Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n\ttypedef struct SafeBoolStruct {\n\t\tint a_data_pointer_to_this_is_0_on_buggy_compilers;\n\t\tStaticFunctionPtr m_nonzero;\n\t} UselessTypedef;\n    typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\npublic:\n\toperator unspecified_bool_type() const {\n        return empty()? 0: &SafeBoolStruct::m_nonzero;\n    }\n\t// necessary to allow ==0 to work despite the safe_bool idiom\n\tinline bool operator==(StaticFunctionPtr funcptr) {\n\t\treturn m_Closure.IsEqualToStaticFuncPtr(funcptr);\t}\n\tinline bool operator!=(StaticFunctionPtr funcptr) { \n\t\treturn !m_Closure.IsEqualToStaticFuncPtr(funcptr);    }\n\tinline bool operator ! () const\t{\t// Is it bound to anything?\n\t\t\treturn !m_Closure; }\n\tinline bool empty() const\t{\n\t\t\treturn !m_Closure; }\n\tvoid clear() { m_Closure.clear();}\n\t// Conversion to and from the DelegateMemento storage class\n\tconst DelegateMemento & GetMemento() { return m_Closure; }\n\tvoid SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate:\t// Invoker for static functions\n\tRetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const {\n\treturn (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4); }\n};\n\n//N=5\ntemplate<class Param1, class Param2, class Param3, class Param4, class Param5, class RetType=detail::DefaultVoid>\nclass FastDelegate5 {\nprivate:\n\ttypedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n\ttypedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5);\n\ttypedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5);\n\ttypedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5);\n\ttypedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;\n\tClosureType m_Closure;\npublic:\n\t// Typedefs to aid generic programming\n\ttypedef FastDelegate5 type;\n\n\t// Construction and comparison functions\n\tFastDelegate5() { clear(); }\n\tFastDelegate5(const FastDelegate5 &x) {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tvoid operator = (const FastDelegate5 &x)  {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tbool operator ==(const FastDelegate5 &x) const {\n\t\treturn m_Closure.IsEqual(x.m_Closure);\t}\n\tbool operator !=(const FastDelegate5 &x) const {\n\t\treturn !m_Closure.IsEqual(x.m_Closure); }\n\tbool operator <(const FastDelegate5 &x) const {\n\t\treturn m_Closure.IsLess(x.m_Closure);\t}\n\tbool operator >(const FastDelegate5 &x) const {\n\t\treturn x.m_Closure.IsLess(m_Closure);\t}\n\t// Binding to non-const member functions\n\ttemplate < class X, class Y >\n\tFastDelegate5(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) ) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }\n\ttemplate < class X, class Y >\n\tinline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);\t}\n\t// Binding to const member functions.\n\ttemplate < class X, class Y >\n\tFastDelegate5(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);\t}\n\ttemplate < class X, class Y >\n\tinline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);\t}\n\t// Static functions. We convert them into a member function call.\n\t// This constructor also provides implicit conversion\n\tFastDelegate5(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) ) {\n\t\tbind(function_to_bind);\t}\n\t// for efficiency, prevent creation of a temporary\n\tvoid operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) ) {\n\t\tbind(function_to_bind);\t}\n\tinline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) {\n\t\tm_Closure.bindstaticfunc(this, &FastDelegate5::InvokeStaticFunction, \n\t\t\tfunction_to_bind); }\n\t// Invoke the delegate\n\tRetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const {\n\treturn (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5); }\n\t// Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n\ttypedef struct SafeBoolStruct {\n\t\tint a_data_pointer_to_this_is_0_on_buggy_compilers;\n\t\tStaticFunctionPtr m_nonzero;\n\t} UselessTypedef;\n    typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\npublic:\n\toperator unspecified_bool_type() const {\n        return empty()? 0: &SafeBoolStruct::m_nonzero;\n    }\n\t// necessary to allow ==0 to work despite the safe_bool idiom\n\tinline bool operator==(StaticFunctionPtr funcptr) {\n\t\treturn m_Closure.IsEqualToStaticFuncPtr(funcptr);\t}\n\tinline bool operator!=(StaticFunctionPtr funcptr) { \n\t\treturn !m_Closure.IsEqualToStaticFuncPtr(funcptr);    }\n\tinline bool operator ! () const\t{\t// Is it bound to anything?\n\t\t\treturn !m_Closure; }\n\tinline bool empty() const\t{\n\t\t\treturn !m_Closure; }\n\tvoid clear() { m_Closure.clear();}\n\t// Conversion to and from the DelegateMemento storage class\n\tconst DelegateMemento & GetMemento() { return m_Closure; }\n\tvoid SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate:\t// Invoker for static functions\n\tRetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const {\n\treturn (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5); }\n};\n\n//N=6\ntemplate<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class RetType=detail::DefaultVoid>\nclass FastDelegate6 {\nprivate:\n\ttypedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n\ttypedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6);\n\ttypedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6);\n\ttypedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6);\n\ttypedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;\n\tClosureType m_Closure;\npublic:\n\t// Typedefs to aid generic programming\n\ttypedef FastDelegate6 type;\n\n\t// Construction and comparison functions\n\tFastDelegate6() { clear(); }\n\tFastDelegate6(const FastDelegate6 &x) {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tvoid operator = (const FastDelegate6 &x)  {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tbool operator ==(const FastDelegate6 &x) const {\n\t\treturn m_Closure.IsEqual(x.m_Closure);\t}\n\tbool operator !=(const FastDelegate6 &x) const {\n\t\treturn !m_Closure.IsEqual(x.m_Closure); }\n\tbool operator <(const FastDelegate6 &x) const {\n\t\treturn m_Closure.IsLess(x.m_Closure);\t}\n\tbool operator >(const FastDelegate6 &x) const {\n\t\treturn x.m_Closure.IsLess(m_Closure);\t}\n\t// Binding to non-const member functions\n\ttemplate < class X, class Y >\n\tFastDelegate6(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) ) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }\n\ttemplate < class X, class Y >\n\tinline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);\t}\n\t// Binding to const member functions.\n\ttemplate < class X, class Y >\n\tFastDelegate6(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);\t}\n\ttemplate < class X, class Y >\n\tinline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);\t}\n\t// Static functions. We convert them into a member function call.\n\t// This constructor also provides implicit conversion\n\tFastDelegate6(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) ) {\n\t\tbind(function_to_bind);\t}\n\t// for efficiency, prevent creation of a temporary\n\tvoid operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) ) {\n\t\tbind(function_to_bind);\t}\n\tinline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) {\n\t\tm_Closure.bindstaticfunc(this, &FastDelegate6::InvokeStaticFunction, \n\t\t\tfunction_to_bind); }\n\t// Invoke the delegate\n\tRetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const {\n\treturn (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6); }\n\t// Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n\ttypedef struct SafeBoolStruct {\n\t\tint a_data_pointer_to_this_is_0_on_buggy_compilers;\n\t\tStaticFunctionPtr m_nonzero;\n\t} UselessTypedef;\n    typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\npublic:\n\toperator unspecified_bool_type() const {\n        return empty()? 0: &SafeBoolStruct::m_nonzero;\n    }\n\t// necessary to allow ==0 to work despite the safe_bool idiom\n\tinline bool operator==(StaticFunctionPtr funcptr) {\n\t\treturn m_Closure.IsEqualToStaticFuncPtr(funcptr);\t}\n\tinline bool operator!=(StaticFunctionPtr funcptr) { \n\t\treturn !m_Closure.IsEqualToStaticFuncPtr(funcptr);    }\n\tinline bool operator ! () const\t{\t// Is it bound to anything?\n\t\t\treturn !m_Closure; }\n\tinline bool empty() const\t{\n\t\t\treturn !m_Closure; }\n\tvoid clear() { m_Closure.clear();}\n\t// Conversion to and from the DelegateMemento storage class\n\tconst DelegateMemento & GetMemento() { return m_Closure; }\n\tvoid SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate:\t// Invoker for static functions\n\tRetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const {\n\treturn (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6); }\n};\n\n//N=7\ntemplate<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class RetType=detail::DefaultVoid>\nclass FastDelegate7 {\nprivate:\n\ttypedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n\ttypedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7);\n\ttypedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7);\n\ttypedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7);\n\ttypedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;\n\tClosureType m_Closure;\npublic:\n\t// Typedefs to aid generic programming\n\ttypedef FastDelegate7 type;\n\n\t// Construction and comparison functions\n\tFastDelegate7() { clear(); }\n\tFastDelegate7(const FastDelegate7 &x) {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tvoid operator = (const FastDelegate7 &x)  {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tbool operator ==(const FastDelegate7 &x) const {\n\t\treturn m_Closure.IsEqual(x.m_Closure);\t}\n\tbool operator !=(const FastDelegate7 &x) const {\n\t\treturn !m_Closure.IsEqual(x.m_Closure); }\n\tbool operator <(const FastDelegate7 &x) const {\n\t\treturn m_Closure.IsLess(x.m_Closure);\t}\n\tbool operator >(const FastDelegate7 &x) const {\n\t\treturn x.m_Closure.IsLess(m_Closure);\t}\n\t// Binding to non-const member functions\n\ttemplate < class X, class Y >\n\tFastDelegate7(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) ) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }\n\ttemplate < class X, class Y >\n\tinline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);\t}\n\t// Binding to const member functions.\n\ttemplate < class X, class Y >\n\tFastDelegate7(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);\t}\n\ttemplate < class X, class Y >\n\tinline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);\t}\n\t// Static functions. We convert them into a member function call.\n\t// This constructor also provides implicit conversion\n\tFastDelegate7(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) ) {\n\t\tbind(function_to_bind);\t}\n\t// for efficiency, prevent creation of a temporary\n\tvoid operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) ) {\n\t\tbind(function_to_bind);\t}\n\tinline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) {\n\t\tm_Closure.bindstaticfunc(this, &FastDelegate7::InvokeStaticFunction, \n\t\t\tfunction_to_bind); }\n\t// Invoke the delegate\n\tRetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const {\n\treturn (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6, p7); }\n\t// Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n\ttypedef struct SafeBoolStruct {\n\t\tint a_data_pointer_to_this_is_0_on_buggy_compilers;\n\t\tStaticFunctionPtr m_nonzero;\n\t} UselessTypedef;\n    typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\npublic:\n\toperator unspecified_bool_type() const {\n        return empty()? 0: &SafeBoolStruct::m_nonzero;\n    }\n\t// necessary to allow ==0 to work despite the safe_bool idiom\n\tinline bool operator==(StaticFunctionPtr funcptr) {\n\t\treturn m_Closure.IsEqualToStaticFuncPtr(funcptr);\t}\n\tinline bool operator!=(StaticFunctionPtr funcptr) { \n\t\treturn !m_Closure.IsEqualToStaticFuncPtr(funcptr);    }\n\tinline bool operator ! () const\t{\t// Is it bound to anything?\n\t\t\treturn !m_Closure; }\n\tinline bool empty() const\t{\n\t\t\treturn !m_Closure; }\n\tvoid clear() { m_Closure.clear();}\n\t// Conversion to and from the DelegateMemento storage class\n\tconst DelegateMemento & GetMemento() { return m_Closure; }\n\tvoid SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate:\t// Invoker for static functions\n\tRetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const {\n\treturn (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7); }\n};\n\n//N=8\ntemplate<class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class RetType=detail::DefaultVoid>\nclass FastDelegate8 {\nprivate:\n\ttypedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n\ttypedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8);\n\ttypedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8);\n\ttypedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8);\n\ttypedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr, UnvoidStaticFunctionPtr> ClosureType;\n\tClosureType m_Closure;\npublic:\n\t// Typedefs to aid generic programming\n\ttypedef FastDelegate8 type;\n\n\t// Construction and comparison functions\n\tFastDelegate8() { clear(); }\n\tFastDelegate8(const FastDelegate8 &x) {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tvoid operator = (const FastDelegate8 &x)  {\n\t\tm_Closure.CopyFrom(this, x.m_Closure); }\n\tbool operator ==(const FastDelegate8 &x) const {\n\t\treturn m_Closure.IsEqual(x.m_Closure);\t}\n\tbool operator !=(const FastDelegate8 &x) const {\n\t\treturn !m_Closure.IsEqual(x.m_Closure); }\n\tbool operator <(const FastDelegate8 &x) const {\n\t\treturn m_Closure.IsLess(x.m_Closure);\t}\n\tbool operator >(const FastDelegate8 &x) const {\n\t\treturn x.m_Closure.IsLess(m_Closure);\t}\n\t// Binding to non-const member functions\n\ttemplate < class X, class Y >\n\tFastDelegate8(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) ) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind); }\n\ttemplate < class X, class Y >\n\tinline void bind(Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) {\n\t\tm_Closure.bindmemfunc(detail::implicit_cast<X*>(pthis), function_to_bind);\t}\n\t// Binding to const member functions.\n\ttemplate < class X, class Y >\n\tFastDelegate8(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X*>(pthis), function_to_bind);\t}\n\ttemplate < class X, class Y >\n\tinline void bind(const Y *pthis, DesiredRetType (X::* function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) {\n\t\tm_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis), function_to_bind);\t}\n\t// Static functions. We convert them into a member function call.\n\t// This constructor also provides implicit conversion\n\tFastDelegate8(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) ) {\n\t\tbind(function_to_bind);\t}\n\t// for efficiency, prevent creation of a temporary\n\tvoid operator = (DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) ) {\n\t\tbind(function_to_bind);\t}\n\tinline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) {\n\t\tm_Closure.bindstaticfunc(this, &FastDelegate8::InvokeStaticFunction, \n\t\t\tfunction_to_bind); }\n\t// Invoke the delegate\n\tRetType operator() (Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const {\n\treturn (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3, p4, p5, p6, p7, p8); }\n\t// Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n\ttypedef struct SafeBoolStruct {\n\t\tint a_data_pointer_to_this_is_0_on_buggy_compilers;\n\t\tStaticFunctionPtr m_nonzero;\n\t} UselessTypedef;\n    typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\npublic:\n\toperator unspecified_bool_type() const {\n        return empty()? 0: &SafeBoolStruct::m_nonzero;\n    }\n\t// necessary to allow ==0 to work despite the safe_bool idiom\n\tinline bool operator==(StaticFunctionPtr funcptr) {\n\t\treturn m_Closure.IsEqualToStaticFuncPtr(funcptr);\t}\n\tinline bool operator!=(StaticFunctionPtr funcptr) { \n\t\treturn !m_Closure.IsEqualToStaticFuncPtr(funcptr);    }\n\tinline bool operator ! () const\t{\t// Is it bound to anything?\n\t\t\treturn !m_Closure; }\n\tinline bool empty() const\t{\n\t\t\treturn !m_Closure; }\n\tvoid clear() { m_Closure.clear();}\n\t// Conversion to and from the DelegateMemento storage class\n\tconst DelegateMemento & GetMemento() { return m_Closure; }\n\tvoid SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate:\t// Invoker for static functions\n\tRetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const {\n\treturn (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7, p8); }\n};\n\n\n////////////////////////////////////////////////////////////////////////////////\n//\t\t\t\t\t\tFast Delegates, part 4:\n// \n//\t\t\t\tFastDelegate<> class (Original author: Jody Hagins)\n//\tAllows boost::function style syntax like:\n//\t\t\tFastDelegate< double (int, long) >\n// instead of:\n//\t\t\tFastDelegate2< int, long, double >\n//\n////////////////////////////////////////////////////////////////////////////////\n\n#ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n\n// Declare FastDelegate as a class template.  It will be specialized\n// later for all number of arguments.\ntemplate <typename Signature>\nclass FastDelegate;\n\n//N=0\n// Specialization to allow use of\n// FastDelegate< R (  ) >\n// instead of \n// FastDelegate0 < R >\ntemplate<typename R>\nclass FastDelegate< R (  ) >\n  // Inherit from FastDelegate0 so that it can be treated just like a FastDelegate0\n  : public FastDelegate0 < R >\n{\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate0 < R > BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() { }\n\n  template < class X, class Y >\n  FastDelegate(Y * pthis, \n    R (X::* function_to_bind)(  ))\n    : BaseType(pthis, function_to_bind)  { }\n\n  template < class X, class Y >\n  FastDelegate(const Y *pthis,\n      R (X::* function_to_bind)(  ) const)\n    : BaseType(pthis, function_to_bind)\n  {  }\n\n  FastDelegate(R (*function_to_bind)(  ))\n    : BaseType(function_to_bind)  { }\n  void operator = (const BaseType &x)  {\t  \n\t\t*static_cast<BaseType*>(this) = x; }\n};\n\n//N=1\n// Specialization to allow use of\n// FastDelegate< R ( Param1 ) >\n// instead of \n// FastDelegate1 < Param1, R >\ntemplate<typename R, class Param1>\nclass FastDelegate< R ( Param1 ) >\n  // Inherit from FastDelegate1 so that it can be treated just like a FastDelegate1\n  : public FastDelegate1 < Param1, R >\n{\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate1 < Param1, R > BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() { }\n\n  template < class X, class Y >\n  FastDelegate(Y * pthis, \n    R (X::* function_to_bind)( Param1 p1 ))\n    : BaseType(pthis, function_to_bind)  { }\n\n  template < class X, class Y >\n  FastDelegate(const Y *pthis,\n      R (X::* function_to_bind)( Param1 p1 ) const)\n    : BaseType(pthis, function_to_bind)\n  {  }\n\n  FastDelegate(R (*function_to_bind)( Param1 p1 ))\n    : BaseType(function_to_bind)  { }\n  void operator = (const BaseType &x)  {\t  \n\t\t*static_cast<BaseType*>(this) = x; }\n};\n\n//N=2\n// Specialization to allow use of\n// FastDelegate< R ( Param1, Param2 ) >\n// instead of \n// FastDelegate2 < Param1, Param2, R >\ntemplate<typename R, class Param1, class Param2>\nclass FastDelegate< R ( Param1, Param2 ) >\n  // Inherit from FastDelegate2 so that it can be treated just like a FastDelegate2\n  : public FastDelegate2 < Param1, Param2, R >\n{\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate2 < Param1, Param2, R > BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() { }\n\n  template < class X, class Y >\n  FastDelegate(Y * pthis, \n    R (X::* function_to_bind)( Param1 p1, Param2 p2 ))\n    : BaseType(pthis, function_to_bind)  { }\n\n  template < class X, class Y >\n  FastDelegate(const Y *pthis,\n      R (X::* function_to_bind)( Param1 p1, Param2 p2 ) const)\n    : BaseType(pthis, function_to_bind)\n  {  }\n\n  FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2 ))\n    : BaseType(function_to_bind)  { }\n  void operator = (const BaseType &x)  {\t  \n\t\t*static_cast<BaseType*>(this) = x; }\n};\n\n//N=3\n// Specialization to allow use of\n// FastDelegate< R ( Param1, Param2, Param3 ) >\n// instead of \n// FastDelegate3 < Param1, Param2, Param3, R >\ntemplate<typename R, class Param1, class Param2, class Param3>\nclass FastDelegate< R ( Param1, Param2, Param3 ) >\n  // Inherit from FastDelegate3 so that it can be treated just like a FastDelegate3\n  : public FastDelegate3 < Param1, Param2, Param3, R >\n{\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate3 < Param1, Param2, Param3, R > BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() { }\n\n  template < class X, class Y >\n  FastDelegate(Y * pthis, \n    R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3 ))\n    : BaseType(pthis, function_to_bind)  { }\n\n  template < class X, class Y >\n  FastDelegate(const Y *pthis,\n      R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3 ) const)\n    : BaseType(pthis, function_to_bind)\n  {  }\n\n  FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3 ))\n    : BaseType(function_to_bind)  { }\n  void operator = (const BaseType &x)  {\t  \n\t\t*static_cast<BaseType*>(this) = x; }\n};\n\n//N=4\n// Specialization to allow use of\n// FastDelegate< R ( Param1, Param2, Param3, Param4 ) >\n// instead of \n// FastDelegate4 < Param1, Param2, Param3, Param4, R >\ntemplate<typename R, class Param1, class Param2, class Param3, class Param4>\nclass FastDelegate< R ( Param1, Param2, Param3, Param4 ) >\n  // Inherit from FastDelegate4 so that it can be treated just like a FastDelegate4\n  : public FastDelegate4 < Param1, Param2, Param3, Param4, R >\n{\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate4 < Param1, Param2, Param3, Param4, R > BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() { }\n\n  template < class X, class Y >\n  FastDelegate(Y * pthis, \n    R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ))\n    : BaseType(pthis, function_to_bind)  { }\n\n  template < class X, class Y >\n  FastDelegate(const Y *pthis,\n      R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) const)\n    : BaseType(pthis, function_to_bind)\n  {  }\n\n  FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ))\n    : BaseType(function_to_bind)  { }\n  void operator = (const BaseType &x)  {\t  \n\t\t*static_cast<BaseType*>(this) = x; }\n};\n\n//N=5\n// Specialization to allow use of\n// FastDelegate< R ( Param1, Param2, Param3, Param4, Param5 ) >\n// instead of \n// FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R >\ntemplate<typename R, class Param1, class Param2, class Param3, class Param4, class Param5>\nclass FastDelegate< R ( Param1, Param2, Param3, Param4, Param5 ) >\n  // Inherit from FastDelegate5 so that it can be treated just like a FastDelegate5\n  : public FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R >\n{\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R > BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() { }\n\n  template < class X, class Y >\n  FastDelegate(Y * pthis, \n    R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ))\n    : BaseType(pthis, function_to_bind)  { }\n\n  template < class X, class Y >\n  FastDelegate(const Y *pthis,\n      R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) const)\n    : BaseType(pthis, function_to_bind)\n  {  }\n\n  FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ))\n    : BaseType(function_to_bind)  { }\n  void operator = (const BaseType &x)  {\t  \n\t\t*static_cast<BaseType*>(this) = x; }\n};\n\n//N=6\n// Specialization to allow use of\n// FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6 ) >\n// instead of \n// FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R >\ntemplate<typename R, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>\nclass FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6 ) >\n  // Inherit from FastDelegate6 so that it can be treated just like a FastDelegate6\n  : public FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R >\n{\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R > BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() { }\n\n  template < class X, class Y >\n  FastDelegate(Y * pthis, \n    R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ))\n    : BaseType(pthis, function_to_bind)  { }\n\n  template < class X, class Y >\n  FastDelegate(const Y *pthis,\n      R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) const)\n    : BaseType(pthis, function_to_bind)\n  {  }\n\n  FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ))\n    : BaseType(function_to_bind)  { }\n  void operator = (const BaseType &x)  {\t  \n\t\t*static_cast<BaseType*>(this) = x; }\n};\n\n//N=7\n// Specialization to allow use of\n// FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) >\n// instead of \n// FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R >\ntemplate<typename R, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>\nclass FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) >\n  // Inherit from FastDelegate7 so that it can be treated just like a FastDelegate7\n  : public FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R >\n{\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R > BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() { }\n\n  template < class X, class Y >\n  FastDelegate(Y * pthis, \n    R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ))\n    : BaseType(pthis, function_to_bind)  { }\n\n  template < class X, class Y >\n  FastDelegate(const Y *pthis,\n      R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) const)\n    : BaseType(pthis, function_to_bind)\n  {  }\n\n  FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ))\n    : BaseType(function_to_bind)  { }\n  void operator = (const BaseType &x)  {\t  \n\t\t*static_cast<BaseType*>(this) = x; }\n};\n\n//N=8\n// Specialization to allow use of\n// FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) >\n// instead of \n// FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R >\ntemplate<typename R, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>\nclass FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8 ) >\n  // Inherit from FastDelegate8 so that it can be treated just like a FastDelegate8\n  : public FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R >\n{\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate8 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, R > BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() { }\n\n  template < class X, class Y >\n  FastDelegate(Y * pthis, \n    R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ))\n    : BaseType(pthis, function_to_bind)  { }\n\n  template < class X, class Y >\n  FastDelegate(const Y *pthis,\n      R (X::* function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) const)\n    : BaseType(pthis, function_to_bind)\n  {  }\n\n  FastDelegate(R (*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ))\n    : BaseType(function_to_bind)  { }\n  void operator = (const BaseType &x)  {\t  \n\t\t*static_cast<BaseType*>(this) = x; }\n};\n\n\n#endif //FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n\n////////////////////////////////////////////////////////////////////////////////\n//\t\t\t\t\t\tFast Delegates, part 5:\n//\n//\t\t\t\tMakeDelegate() helper function\n//\n//\t\t\tMakeDelegate(&x, &X::func) returns a fastdelegate of the type\n//\t\t\tnecessary for calling x.func() with the correct number of arguments.\n//\t\t\tThis makes it possible to eliminate many typedefs from user code.\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// Also declare overloads of a MakeDelegate() global function to \n// reduce the need for typedefs.\n// We need seperate overloads for const and non-const member functions.\n// Also, because of the weird rule about the class of derived member function pointers,\n// implicit downcasts may need to be applied later to the 'this' pointer.\n// That's why two classes (X and Y) appear in the definitions. Y must be implicitly\n// castable to X.\n\n// Workaround for VC6. VC6 needs void return types converted into DefaultVoid.\n// GCC 3.2 and later won't compile this unless it's preceded by 'typename',\n// but VC6 doesn't allow 'typename' in this context.\n// So, I have to use a macro.\n\n#ifdef FASTDLGT_VC6\n#define FASTDLGT_RETTYPE detail::VoidToDefaultVoid<RetType>::type\n#else \n#define FASTDLGT_RETTYPE RetType\n#endif\n\n//N=0\ntemplate <class X, class Y, class RetType>\nFastDelegate0<FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)()) { \n\treturn FastDelegate0<FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class RetType>\nFastDelegate0<FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)() const) { \n\treturn FastDelegate0<FASTDLGT_RETTYPE>(x, func);\n}\n\n//N=1\ntemplate <class X, class Y, class Param1, class RetType>\nFastDelegate1<Param1, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1)) { \n\treturn FastDelegate1<Param1, FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class RetType>\nFastDelegate1<Param1, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1) const) { \n\treturn FastDelegate1<Param1, FASTDLGT_RETTYPE>(x, func);\n}\n\n//N=2\ntemplate <class X, class Y, class Param1, class Param2, class RetType>\nFastDelegate2<Param1, Param2, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2)) { \n\treturn FastDelegate2<Param1, Param2, FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class RetType>\nFastDelegate2<Param1, Param2, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2) const) { \n\treturn FastDelegate2<Param1, Param2, FASTDLGT_RETTYPE>(x, func);\n}\n\n//N=3\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class RetType>\nFastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3)) { \n\treturn FastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class RetType>\nFastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3) const) { \n\treturn FastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE>(x, func);\n}\n\n//N=4\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class Param4, class RetType>\nFastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) { \n\treturn FastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class Param4, class RetType>\nFastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) { \n\treturn FastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE>(x, func);\n}\n\n//N=5\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class RetType>\nFastDelegate5<Param1, Param2, Param3, Param4, Param5, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) { \n\treturn FastDelegate5<Param1, Param2, Param3, Param4, Param5, FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class RetType>\nFastDelegate5<Param1, Param2, Param3, Param4, Param5, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) { \n\treturn FastDelegate5<Param1, Param2, Param3, Param4, Param5, FASTDLGT_RETTYPE>(x, func);\n}\n\n//N=6\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class RetType>\nFastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) { \n\treturn FastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6, FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class RetType>\nFastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) { \n\treturn FastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6, FASTDLGT_RETTYPE>(x, func);\n}\n\n//N=7\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class RetType>\nFastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6, Param7, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) { \n\treturn FastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6, Param7, FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class RetType>\nFastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6, Param7, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) { \n\treturn FastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6, Param7, FASTDLGT_RETTYPE>(x, func);\n}\n\n//N=8\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class RetType>\nFastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) { \n\treturn FastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8, class RetType>\nFastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, FASTDLGT_RETTYPE> MakeDelegate(Y* x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) { \n\treturn FastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, FASTDLGT_RETTYPE>(x, func);\n}\n\n\n // clean up after ourselves...\n#undef FASTDLGT_RETTYPE\n\n} // namespace fastdelegate\n\n#endif // !defined(FASTDELEGATE_H)\n\n"
  },
  {
    "path": "External/FastDelegate/FastDelegateBind.h",
    "content": "//\t\t\t\t\t\tFastDelegateBind.h \n//  Helper file for FastDelegates. Provides bind() function, enabling\n//  FastDelegates to be rapidly compared to programs using boost::function and boost::bind.\n//\n//  Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp\n//\n//\t\tOriginal author: Jody Hagins.\n//\t\t Minor changes by Don Clugston.\n//\n// Warning: The arguments to 'bind' are ignored! No actual binding is performed.\n// The behaviour is equivalent to boost::bind only when the basic placeholder \n// arguments _1, _2, _3, etc are used in order.\n//\n// HISTORY:\n//\t1.4 Dec 2004. Initial release as part of FastDelegate 1.4.\n\n\n#ifndef FASTDELEGATEBIND_H\n#define FASTDELEGATEBIND_H\n#if _MSC_VER > 1000\n#pragma once\n#endif // _MSC_VER > 1000\n\n////////////////////////////////////////////////////////////////////////////////\n//\t\t\t\t\t\tFastDelegate bind()\n//\n//\t\t\t\tbind() helper function for boost compatibility.\n//\t\t\t\t(Original author: Jody Hagins).\n//\n// Add another helper, so FastDelegate can be a dropin replacement\n// for boost::bind (in a fair number of cases).\n// Note the elipses, because boost::bind() takes place holders\n// but FastDelegate does not care about them.  Getting the place holder\n// mechanism to work, and play well with boost is a bit tricky, so\n// we do the \"easy\" thing...\n// Assume we have the following code...\n//      using boost::bind;\n//      bind(&Foo:func, &foo, _1, _2);\n// we should be able to replace the \"using\" with...\n//      using fastdelegate::bind;\n// and everything should work fine...\n////////////////////////////////////////////////////////////////////////////////\n\n#ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n\nnamespace fastdelegate {\n\n//N=0\ntemplate <class X, class Y, class RetType>\nFastDelegate< RetType (  ) >\nbind(\n    RetType (X::*func)(  ),\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType (  ) >(y, func);\n}\n\ntemplate <class X, class Y, class RetType>\nFastDelegate< RetType (  ) >\nbind(\n    RetType (X::*func)(  ) const,\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType (  ) >(y, func);\n}\n\n//N=1\ntemplate <class X, class Y, class RetType, class Param1>\nFastDelegate< RetType ( Param1 p1 ) >\nbind(\n    RetType (X::*func)( Param1 p1 ),\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1 ) >(y, func);\n}\n\ntemplate <class X, class Y, class RetType, class Param1>\nFastDelegate< RetType ( Param1 p1 ) >\nbind(\n    RetType (X::*func)( Param1 p1 ) const,\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1 ) >(y, func);\n}\n\n//N=2\ntemplate <class X, class Y, class RetType, class Param1, class Param2>\nFastDelegate< RetType ( Param1 p1, Param2 p2 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2 ),\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2 ) >(y, func);\n}\n\ntemplate <class X, class Y, class RetType, class Param1, class Param2>\nFastDelegate< RetType ( Param1 p1, Param2 p2 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2 ) const,\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2 ) >(y, func);\n}\n\n//N=3\ntemplate <class X, class Y, class RetType, class Param1, class Param2, class Param3>\nFastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3 ),\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) >(y, func);\n}\n\ntemplate <class X, class Y, class RetType, class Param1, class Param2, class Param3>\nFastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3 ) const,\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3 ) >(y, func);\n}\n\n//N=4\ntemplate <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4>\nFastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ),\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) >(y, func);\n}\n\ntemplate <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4>\nFastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) const,\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4 ) >(y, func);\n}\n\n//N=5\ntemplate <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>\nFastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ),\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) >(y, func);\n}\n\ntemplate <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5>\nFastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) const,\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5 ) >(y, func);\n}\n\n//N=6\ntemplate <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>\nFastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ),\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) >(y, func);\n}\n\ntemplate <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6>\nFastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) const,\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6 ) >(y, func);\n}\n\n//N=7\ntemplate <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>\nFastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ),\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) >(y, func);\n}\n\ntemplate <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7>\nFastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) const,\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7 ) >(y, func);\n}\n\n//N=8\ntemplate <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>\nFastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ),\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) >(y, func);\n}\n\ntemplate <class X, class Y, class RetType, class Param1, class Param2, class Param3, class Param4, class Param5, class Param6, class Param7, class Param8>\nFastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) >\nbind(\n    RetType (X::*func)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) const,\n    Y * y,\n    ...)\n{ \n  return FastDelegate< RetType ( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8 ) >(y, func);\n}\n\n\n#endif //FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n\n} // namespace fastdelegate\n\n#endif // !defined(FASTDELEGATEBIND_H)\n\n"
  },
  {
    "path": "External/ImGui/ImGuizmo.cpp",
    "content": "// https://github.com/CedricGuillemet/ImGuizmo\n// v1.91.3 WIP\n//\n// The MIT License(MIT)\n//\n// Copyright(c) 2021 Cedric Guillemet\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files(the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions :\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n//\n\n#include \"../ZetaCore/App/App.h\"\n#include \"../ZetaCore/Math/MatrixFuncs.h\"\n#include \"../ZetaCore/Core/RendererCore.h\"\n#include \"../ZetaCore/Scene/Camera.h\"\n\n#ifndef IMGUI_DEFINE_MATH_OPERATORS\n#define IMGUI_DEFINE_MATH_OPERATORS\n#endif\n#include \"imgui.h\"\n#include \"imgui_internal.h\"\n#include \"ImGuizmo.h\"\n\n#if defined(_MSC_VER) || defined(__MINGW32__)\n#include <malloc.h>\n#endif\n#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)\n#define _malloca(x) alloca(x)\n#define _freea(x)\n#endif\n\n// includes patches for multiview from\n// https://github.com/CedricGuillemet/ImGuizmo/issues/15\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Math;\n\nnamespace IMGUIZMO_NAMESPACE\n{\n   static const float ZPI = 3.14159265358979323846f;\n   static const float RAD2DEG = (180.f / ZPI);\n   static const float DEG2RAD = (ZPI / 180.f);\n   const float screenRotateSize = 0.06f;\n   // scale a bit so translate axis do not touch when in universal\n   const float rotationDisplayFactor = 1.2f;\n   static constexpr ImGuiID INVALID_ID = ImGuiID(-1);\n\n   static OPERATION operator&(OPERATION lhs, OPERATION rhs)\n   {\n     return static_cast<OPERATION>(static_cast<int>(lhs) & static_cast<int>(rhs));\n   }\n\n   static bool operator!=(OPERATION lhs, int rhs)\n   {\n     return static_cast<int>(lhs) != rhs;\n   }\n\n   static bool Intersects(OPERATION lhs, OPERATION rhs)\n   {\n     return (lhs & rhs) != 0;\n   }\n\n   // True if lhs contains rhs\n   static bool Contains(OPERATION lhs, OPERATION rhs)\n   {\n     return (lhs & rhs) == rhs;\n   }\n\n   ////////////////////////////////////////////////////////////////////////////////\n\n   void FPU_MatrixF_x_MatrixF(const float* a, const float* b, float* r)\n   {\n      r[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12];\n      r[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13];\n      r[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14];\n      r[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15];\n\n      r[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12];\n      r[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13];\n      r[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14];\n      r[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15];\n\n      r[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12];\n      r[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13];\n      r[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14];\n      r[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15];\n\n      r[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12];\n      r[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13];\n      r[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14];\n      r[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15];\n   }\n\n   void Frustum(float left, float right, float bottom, float top, float znear, float zfar, float* m16)\n   {\n      float temp, temp2, temp3, temp4;\n      temp = 2.0f * znear;\n      temp2 = right - left;\n      temp3 = top - bottom;\n      temp4 = zfar - znear;\n      m16[0] = temp / temp2;\n      m16[1] = 0.0;\n      m16[2] = 0.0;\n      m16[3] = 0.0;\n      m16[4] = 0.0;\n      m16[5] = temp / temp3;\n      m16[6] = 0.0;\n      m16[7] = 0.0;\n      m16[8] = (right + left) / temp2;\n      m16[9] = (top + bottom) / temp3;\n      m16[10] = (-zfar - znear) / temp4;\n      m16[11] = -1.0f;\n      m16[12] = 0.0;\n      m16[13] = 0.0;\n      m16[14] = (-temp * zfar) / temp4;\n      m16[15] = 0.0;\n   }\n\n   void Perspective(float fovyInDegrees, float aspectRatio, float znear, float zfar, float* m16)\n   {\n      float ymax, xmax;\n      ymax = znear * tanf(fovyInDegrees * DEG2RAD);\n      xmax = ymax * aspectRatio;\n      Frustum(-xmax, xmax, -ymax, ymax, znear, zfar, m16);\n   }\n\n   void Cross(const float* a, const float* b, float* r)\n   {\n      r[0] = a[1] * b[2] - a[2] * b[1];\n      r[1] = a[2] * b[0] - a[0] * b[2];\n      r[2] = a[0] * b[1] - a[1] * b[0];\n   }\n\n   float Dot(const float* a, const float* b)\n   {\n      return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n   }\n\n   void Normalize(const float* a, float* r)\n   {\n      float il = 1.f / (sqrtf(Dot(a, a)) + FLT_EPSILON);\n      r[0] = a[0] * il;\n      r[1] = a[1] * il;\n      r[2] = a[2] * il;\n   }\n\n   void LookAt(const float* eye, const float* at, const float* up, float* m16)\n   {\n      float X[3], Y[3], Z[3], tmp[3];\n\n      tmp[0] = eye[0] - at[0];\n      tmp[1] = eye[1] - at[1];\n      tmp[2] = eye[2] - at[2];\n      Normalize(tmp, Z);\n      Normalize(up, Y);\n      Cross(Y, Z, tmp);\n      Normalize(tmp, X);\n      Cross(Z, X, tmp);\n      Normalize(tmp, Y);\n\n      m16[0] = X[0];\n      m16[1] = Y[0];\n      m16[2] = Z[0];\n      m16[3] = 0.0f;\n      m16[4] = X[1];\n      m16[5] = Y[1];\n      m16[6] = Z[1];\n      m16[7] = 0.0f;\n      m16[8] = X[2];\n      m16[9] = Y[2];\n      m16[10] = Z[2];\n      m16[11] = 0.0f;\n      m16[12] = -Dot(X, eye);\n      m16[13] = -Dot(Y, eye);\n      m16[14] = -Dot(Z, eye);\n      m16[15] = 1.0f;\n   }\n\n   template <typename T> T Clamp(T x, T y, T z) { return ((x < y) ? y : ((x > z) ? z : x)); }\n   template <typename T> T max(T x, T y) { return (x > y) ? x : y; }\n   template <typename T> T min(T x, T y) { return (x < y) ? x : y; }\n   template <typename T> bool IsWithin(T x, T y, T z) { return (x >= y) && (x <= z); }\n\n   struct matrix_t;\n   struct vec_t\n   {\n   public:\n      float x, y, z, w;\n\n      vec_t() = default;\n      vec_t(float v0, float v1, float v2, float v3)\n          : x(v0),\n          y(v1),\n          z(v2),\n          w(v3)\n      {}\n      vec_t(const float3& v)\n          : x(v.x),\n          y(v.y),\n          z(v.z),\n          w(0)\n      {}\n      vec_t(const float4& v)\n          : x(v.x),\n          y(v.y),\n          z(v.z),\n          w(v.w)\n      {}\n\n      void Lerp(const vec_t& v, float t)\n      {\n         x += (v.x - x) * t;\n         y += (v.y - y) * t;\n         z += (v.z - z) * t;\n         w += (v.w - w) * t;\n      }\n\n      void Set(float v) { x = y = z = w = v; }\n      void Set(float _x, float _y, float _z = 0.f, float _w = 0.f) { x = _x; y = _y; z = _z; w = _w; }\n\n      vec_t& operator -= (const vec_t& v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; }\n      vec_t& operator += (const vec_t& v) { x += v.x; y += v.y; z += v.z; w += v.w; return *this; }\n      vec_t& operator *= (const vec_t& v) { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; }\n      vec_t& operator *= (float v) { x *= v;    y *= v;    z *= v;    w *= v;    return *this; }\n\n      vec_t operator * (float f) const;\n      vec_t operator - () const;\n      vec_t operator - (const vec_t& v) const;\n      vec_t operator + (const vec_t& v) const;\n      vec_t operator * (const vec_t& v) const;\n\n      const vec_t& operator + () const { return (*this); }\n      float Length() const { return sqrtf(x * x + y * y + z * z); };\n      float LengthSq() const { return (x * x + y * y + z * z); };\n      vec_t Normalize() { (*this) *= (1.f / ( Length() > FLT_EPSILON ? Length() : FLT_EPSILON ) ); return (*this); }\n      vec_t Normalize(const vec_t& v) { this->Set(v.x, v.y, v.z, v.w); this->Normalize(); return (*this); }\n      vec_t Abs() const;\n\n      void Cross(const vec_t& v)\n      {\n         vec_t res;\n         res.x = y * v.z - z * v.y;\n         res.y = z * v.x - x * v.z;\n         res.z = x * v.y - y * v.x;\n\n         x = res.x;\n         y = res.y;\n         z = res.z;\n         w = 0.f;\n      }\n\n      void Cross(const vec_t& v1, const vec_t& v2)\n      {\n         x = v1.y * v2.z - v1.z * v2.y;\n         y = v1.z * v2.x - v1.x * v2.z;\n         z = v1.x * v2.y - v1.y * v2.x;\n         w = 0.f;\n      }\n\n      float Dot(const vec_t& v) const\n      {\n         return (x * v.x) + (y * v.y) + (z * v.z) + (w * v.w);\n      }\n\n      float Dot3(const vec_t& v) const\n      {\n         return (x * v.x) + (y * v.y) + (z * v.z);\n      }\n\n      void Transform(const matrix_t& matrix);\n      void Transform(const vec_t& s, const matrix_t& matrix);\n\n      void TransformVector(const matrix_t& matrix);\n      void TransformPoint(const matrix_t& matrix);\n      void TransformVector(const vec_t& v, const matrix_t& matrix) { (*this) = v; this->TransformVector(matrix); }\n      void TransformPoint(const vec_t& v, const matrix_t& matrix) { (*this) = v; this->TransformPoint(matrix); }\n\n      float& operator [] (size_t index) { return ((float*)&x)[index]; }\n      const float& operator [] (size_t index) const { return ((float*)&x)[index]; }\n      bool operator!=(const vec_t& other) const { return memcmp(this, &other, sizeof(vec_t)) != 0; }\n   };\n\n   vec_t makeVect(float _x, float _y, float _z = 0.f, float _w = 0.f) { vec_t res; res.x = _x; res.y = _y; res.z = _z; res.w = _w; return res; }\n   vec_t makeVect(ImVec2 v) { vec_t res; res.x = v.x; res.y = v.y; res.z = 0.f; res.w = 0.f; return res; }\n   vec_t vec_t::operator * (float f) const { return makeVect(x * f, y * f, z * f, w * f); }\n   vec_t vec_t::operator - () const { return makeVect(-x, -y, -z, -w); }\n   vec_t vec_t::operator - (const vec_t& v) const { return makeVect(x - v.x, y - v.y, z - v.z, w - v.w); }\n   vec_t vec_t::operator + (const vec_t& v) const { return makeVect(x + v.x, y + v.y, z + v.z, w + v.w); }\n   vec_t vec_t::operator * (const vec_t& v) const { return makeVect(x * v.x, y * v.y, z * v.z, w * v.w); }\n   vec_t vec_t::Abs() const { return makeVect(fabsf(x), fabsf(y), fabsf(z)); }\n\n   vec_t Normalized(const vec_t& v) { vec_t res; res = v; res.Normalize(); return res; }\n   vec_t Cross(const vec_t& v1, const vec_t& v2)\n   {\n      vec_t res;\n      res.x = v1.y * v2.z - v1.z * v2.y;\n      res.y = v1.z * v2.x - v1.x * v2.z;\n      res.z = v1.x * v2.y - v1.y * v2.x;\n      res.w = 0.f;\n      return res;\n   }\n\n   float Dot(const vec_t& v1, const vec_t& v2)\n   {\n      return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);\n   }\n\n   vec_t BuildPlane(const vec_t& p_point1, const vec_t& p_normal)\n   {\n      vec_t normal, res;\n      normal.Normalize(p_normal);\n      res.w = normal.Dot(p_point1);\n      res.x = normal.x;\n      res.y = normal.y;\n      res.z = normal.z;\n      return res;\n   }\n\n   struct matrix_t\n   {\n   public:\n\n      union\n      {\n         float m[4][4];\n         float m16[16];\n         struct\n         {\n            vec_t right, up, dir, position;\n         } v;\n         vec_t component[4];\n      };\n\n      operator float* () { return m16; }\n      operator const float* () const { return m16; }\n      void Translation(float _x, float _y, float _z) { this->Translation(makeVect(_x, _y, _z)); }\n\n      void Translation(const vec_t& vt)\n      {\n         v.right.Set(1.f, 0.f, 0.f, 0.f);\n         v.up.Set(0.f, 1.f, 0.f, 0.f);\n         v.dir.Set(0.f, 0.f, 1.f, 0.f);\n         v.position.Set(vt.x, vt.y, vt.z, 1.f);\n      }\n\n      void Scale(float _x, float _y, float _z)\n      {\n         v.right.Set(_x, 0.f, 0.f, 0.f);\n         v.up.Set(0.f, _y, 0.f, 0.f);\n         v.dir.Set(0.f, 0.f, _z, 0.f);\n         v.position.Set(0.f, 0.f, 0.f, 1.f);\n      }\n      void Scale(const vec_t& s) { Scale(s.x, s.y, s.z); }\n\n      matrix_t& operator *= (const matrix_t& mat)\n      {\n         matrix_t tmpMat;\n         tmpMat = *this;\n         tmpMat.Multiply(mat);\n         *this = tmpMat;\n         return *this;\n      }\n      matrix_t operator * (const matrix_t& mat) const\n      {\n         matrix_t matT;\n         matT.Multiply(*this, mat);\n         return matT;\n      }\n\n      void Multiply(const matrix_t& matrix)\n      {\n         matrix_t tmp;\n         tmp = *this;\n\n         FPU_MatrixF_x_MatrixF((float*)&tmp, (float*)&matrix, (float*)this);\n      }\n\n      void Multiply(const matrix_t& m1, const matrix_t& m2)\n      {\n         FPU_MatrixF_x_MatrixF((float*)&m1, (float*)&m2, (float*)this);\n      }\n\n      float GetDeterminant() const\n      {\n         return m[0][0] * m[1][1] * m[2][2] + m[0][1] * m[1][2] * m[2][0] + m[0][2] * m[1][0] * m[2][1] -\n            m[0][2] * m[1][1] * m[2][0] - m[0][1] * m[1][0] * m[2][2] - m[0][0] * m[1][2] * m[2][1];\n      }\n\n      float Inverse(const matrix_t& srcMatrix, bool affine = false);\n      void SetToIdentity()\n      {\n         v.right.Set(1.f, 0.f, 0.f, 0.f);\n         v.up.Set(0.f, 1.f, 0.f, 0.f);\n         v.dir.Set(0.f, 0.f, 1.f, 0.f);\n         v.position.Set(0.f, 0.f, 0.f, 1.f);\n      }\n      void Transpose()\n      {\n         matrix_t tmpm;\n         for (int l = 0; l < 4; l++)\n         {\n            for (int c = 0; c < 4; c++)\n            {\n               tmpm.m[l][c] = m[c][l];\n            }\n         }\n         (*this) = tmpm;\n      }\n\n      void RotationAxis(const vec_t& axis, float angle);\n\n      void OrthoNormalize()\n      {\n         v.right.Normalize();\n         v.up.Normalize();\n         v.dir.Normalize();\n      }\n   };\n\n   void vec_t::Transform(const matrix_t& matrix)\n   {\n      vec_t out;\n\n      out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + w * matrix.m[3][0];\n      out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + w * matrix.m[3][1];\n      out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + w * matrix.m[3][2];\n      out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + w * matrix.m[3][3];\n\n      x = out.x;\n      y = out.y;\n      z = out.z;\n      w = out.w;\n   }\n\n   void vec_t::Transform(const vec_t& s, const matrix_t& matrix)\n   {\n      *this = s;\n      Transform(matrix);\n   }\n\n   void vec_t::TransformPoint(const matrix_t& matrix)\n   {\n      vec_t out;\n\n      out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0] + matrix.m[3][0];\n      out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1] + matrix.m[3][1];\n      out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2] + matrix.m[3][2];\n      out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3] + matrix.m[3][3];\n\n      x = out.x;\n      y = out.y;\n      z = out.z;\n      w = out.w;\n   }\n\n   void vec_t::TransformVector(const matrix_t& matrix)\n   {\n      vec_t out;\n\n      out.x = x * matrix.m[0][0] + y * matrix.m[1][0] + z * matrix.m[2][0];\n      out.y = x * matrix.m[0][1] + y * matrix.m[1][1] + z * matrix.m[2][1];\n      out.z = x * matrix.m[0][2] + y * matrix.m[1][2] + z * matrix.m[2][2];\n      out.w = x * matrix.m[0][3] + y * matrix.m[1][3] + z * matrix.m[2][3];\n\n      x = out.x;\n      y = out.y;\n      z = out.z;\n      w = out.w;\n   }\n\n   float matrix_t::Inverse(const matrix_t& srcMatrix, bool affine)\n   {\n      float det = 0;\n\n      if (affine)\n      {\n         det = GetDeterminant();\n         float s = 1 / det;\n         m[0][0] = (srcMatrix.m[1][1] * srcMatrix.m[2][2] - srcMatrix.m[1][2] * srcMatrix.m[2][1]) * s;\n         m[0][1] = (srcMatrix.m[2][1] * srcMatrix.m[0][2] - srcMatrix.m[2][2] * srcMatrix.m[0][1]) * s;\n         m[0][2] = (srcMatrix.m[0][1] * srcMatrix.m[1][2] - srcMatrix.m[0][2] * srcMatrix.m[1][1]) * s;\n         m[1][0] = (srcMatrix.m[1][2] * srcMatrix.m[2][0] - srcMatrix.m[1][0] * srcMatrix.m[2][2]) * s;\n         m[1][1] = (srcMatrix.m[2][2] * srcMatrix.m[0][0] - srcMatrix.m[2][0] * srcMatrix.m[0][2]) * s;\n         m[1][2] = (srcMatrix.m[0][2] * srcMatrix.m[1][0] - srcMatrix.m[0][0] * srcMatrix.m[1][2]) * s;\n         m[2][0] = (srcMatrix.m[1][0] * srcMatrix.m[2][1] - srcMatrix.m[1][1] * srcMatrix.m[2][0]) * s;\n         m[2][1] = (srcMatrix.m[2][0] * srcMatrix.m[0][1] - srcMatrix.m[2][1] * srcMatrix.m[0][0]) * s;\n         m[2][2] = (srcMatrix.m[0][0] * srcMatrix.m[1][1] - srcMatrix.m[0][1] * srcMatrix.m[1][0]) * s;\n         m[3][0] = -(m[0][0] * srcMatrix.m[3][0] + m[1][0] * srcMatrix.m[3][1] + m[2][0] * srcMatrix.m[3][2]);\n         m[3][1] = -(m[0][1] * srcMatrix.m[3][0] + m[1][1] * srcMatrix.m[3][1] + m[2][1] * srcMatrix.m[3][2]);\n         m[3][2] = -(m[0][2] * srcMatrix.m[3][0] + m[1][2] * srcMatrix.m[3][1] + m[2][2] * srcMatrix.m[3][2]);\n      }\n      else\n      {\n         // transpose matrix\n         float src[16];\n         for (int i = 0; i < 4; ++i)\n         {\n            src[i] = srcMatrix.m16[i * 4];\n            src[i + 4] = srcMatrix.m16[i * 4 + 1];\n            src[i + 8] = srcMatrix.m16[i * 4 + 2];\n            src[i + 12] = srcMatrix.m16[i * 4 + 3];\n         }\n\n         // calculate pairs for first 8 elements (cofactors)\n         float tmp[12]; // temp array for pairs\n         tmp[0] = src[10] * src[15];\n         tmp[1] = src[11] * src[14];\n         tmp[2] = src[9] * src[15];\n         tmp[3] = src[11] * src[13];\n         tmp[4] = src[9] * src[14];\n         tmp[5] = src[10] * src[13];\n         tmp[6] = src[8] * src[15];\n         tmp[7] = src[11] * src[12];\n         tmp[8] = src[8] * src[14];\n         tmp[9] = src[10] * src[12];\n         tmp[10] = src[8] * src[13];\n         tmp[11] = src[9] * src[12];\n\n         // calculate first 8 elements (cofactors)\n         m16[0] = (tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7]) - (tmp[1] * src[5] + tmp[2] * src[6] + tmp[5] * src[7]);\n         m16[1] = (tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7]) - (tmp[0] * src[4] + tmp[7] * src[6] + tmp[8] * src[7]);\n         m16[2] = (tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7]) - (tmp[3] * src[4] + tmp[6] * src[5] + tmp[11] * src[7]);\n         m16[3] = (tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6]) - (tmp[4] * src[4] + tmp[9] * src[5] + tmp[10] * src[6]);\n         m16[4] = (tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3]) - (tmp[0] * src[1] + tmp[3] * src[2] + tmp[4] * src[3]);\n         m16[5] = (tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3]) - (tmp[1] * src[0] + tmp[6] * src[2] + tmp[9] * src[3]);\n         m16[6] = (tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3]) - (tmp[2] * src[0] + tmp[7] * src[1] + tmp[10] * src[3]);\n         m16[7] = (tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2]) - (tmp[5] * src[0] + tmp[8] * src[1] + tmp[11] * src[2]);\n\n         // calculate pairs for second 8 elements (cofactors)\n         tmp[0] = src[2] * src[7];\n         tmp[1] = src[3] * src[6];\n         tmp[2] = src[1] * src[7];\n         tmp[3] = src[3] * src[5];\n         tmp[4] = src[1] * src[6];\n         tmp[5] = src[2] * src[5];\n         tmp[6] = src[0] * src[7];\n         tmp[7] = src[3] * src[4];\n         tmp[8] = src[0] * src[6];\n         tmp[9] = src[2] * src[4];\n         tmp[10] = src[0] * src[5];\n         tmp[11] = src[1] * src[4];\n\n         // calculate second 8 elements (cofactors)\n         m16[8] = (tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15]) - (tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15]);\n         m16[9] = (tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15]) - (tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15]);\n         m16[10] = (tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15]) - (tmp[3] * src[12] + tmp[6] * src[13] + tmp[11] * src[15]);\n         m16[11] = (tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14]) - (tmp[4] * src[12] + tmp[9] * src[13] + tmp[10] * src[14]);\n         m16[12] = (tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9]) - (tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10]);\n         m16[13] = (tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10]) - (tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8]);\n         m16[14] = (tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8]) - (tmp[10] * src[11] + tmp[2] * src[8] + tmp[7] * src[9]);\n         m16[15] = (tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9]) - (tmp[8] * src[9] + tmp[11] * src[10] + tmp[5] * src[8]);\n\n         // calculate determinant\n         det = src[0] * m16[0] + src[1] * m16[1] + src[2] * m16[2] + src[3] * m16[3];\n\n         // calculate matrix inverse\n         float invdet = 1 / det;\n         for (int j = 0; j < 16; ++j)\n         {\n            m16[j] *= invdet;\n         }\n      }\n\n      return det;\n   }\n\n   void matrix_t::RotationAxis(const vec_t& axis, float angle)\n   {\n      float length2 = axis.LengthSq();\n      if (length2 < FLT_EPSILON)\n      {\n         SetToIdentity();\n         return;\n      }\n\n      vec_t n = axis * (1.f / sqrtf(length2));\n      float s = sinf(angle);\n      float c = cosf(angle);\n      float k = 1.f - c;\n\n      float xx = n.x * n.x * k + c;\n      float yy = n.y * n.y * k + c;\n      float zz = n.z * n.z * k + c;\n      float xy = n.x * n.y * k;\n      float yz = n.y * n.z * k;\n      float zx = n.z * n.x * k;\n      float xs = n.x * s;\n      float ys = n.y * s;\n      float zs = n.z * s;\n\n      m[0][0] = xx;\n      m[0][1] = xy + zs;\n      m[0][2] = zx - ys;\n      m[0][3] = 0.f;\n      m[1][0] = xy - zs;\n      m[1][1] = yy;\n      m[1][2] = yz + xs;\n      m[1][3] = 0.f;\n      m[2][0] = zx + ys;\n      m[2][1] = yz - xs;\n      m[2][2] = zz;\n      m[2][3] = 0.f;\n      m[3][0] = 0.f;\n      m[3][1] = 0.f;\n      m[3][2] = 0.f;\n      m[3][3] = 1.f;\n   }\n\n   /////////////////////////////////////////////////////////////////////////////////////////\n\n   enum MOVETYPE\n   {\n      MT_NONE,\n      MT_MOVE_X,\n      MT_MOVE_Y,\n      MT_MOVE_Z,\n      MT_MOVE_YZ,\n      MT_MOVE_ZX,\n      MT_MOVE_XY,\n      MT_MOVE_SCREEN,\n      MT_ROTATE_X,\n      MT_ROTATE_Y,\n      MT_ROTATE_Z,\n      MT_ROTATE_SCREEN,\n      MT_SCALE_X,\n      MT_SCALE_Y,\n      MT_SCALE_Z,\n      MT_SCALE_XYZ\n   };\n\n   static bool IsTranslateType(int type)\n   {\n     return type >= MT_MOVE_X && type <= MT_MOVE_SCREEN;\n   }\n\n   static bool IsRotateType(int type)\n   {\n     return type >= MT_ROTATE_X && type <= MT_ROTATE_SCREEN;\n   }\n\n   static bool IsScaleType(int type)\n   {\n     return type >= MT_SCALE_X && type <= MT_SCALE_XYZ;\n   }\n\n   // Matches MT_MOVE_AB order\n   static const OPERATION TRANSLATE_PLANS[3] = { TRANSLATE_Y | TRANSLATE_Z, TRANSLATE_X | TRANSLATE_Z, TRANSLATE_X | TRANSLATE_Y };\n\n   Style::Style()\n   {\n      // default values\n      TranslationLineThickness        = 2.0f;\n      TranslationLineThicknessHovered = 3.0f;\n      TranslationLineArrowSize        = 6.0f;\n      RotationLineThickness           = 2.0f;\n      RotationLineThicknessHovered    = 3.0f;\n      RotationOuterLineThickness      = 3.0f;\n      ScaleLineThickness              = 2.0f;\n      ScaleLineThicknessHovered       = 3.0f;\n      ScaleLineCircleSize             = 6.0f;\n      HatchedAxisLineThickness        = 6.0f;\n      CenterCircleSize                = 6.0f;\n\n      // initialize default colors\n      Colors[DIRECTION_X]           = ImVec4(0.92158204f, 0.036889445f, 0.084376216f, 1.0f);\n      Colors[DIRECTION_Y]           = ImVec4(0.16202940f, 0.371237785f, 0.011612245f, 1.0f);\n      Colors[DIRECTION_Z]           = ImVec4(0.02842604f, 0.230740070f, 0.768151283f, 1.0f);\n      Colors[PLANE_X]               = ImVec4(0.92158204f, 0.036889445f, 0.084376216f, 0.380f);\n      Colors[PLANE_Y]               = ImVec4(0.16202940f, 0.371237785f, 0.011612245f, 0.380f);\n      Colors[PLANE_Z]               = ImVec4(0.02842604f, 0.230740070f, 0.768151283f, 0.380f);\n      Colors[SELECTION]             = ImVec4(1.000f, 0.500f, 0.062f, 0.541f);\n      Colors[SELECTION_X]           = ImVec4(1.0f, 0.03688944f, 0.08650046f, 1.0f);\n      Colors[SELECTION_Y]           = ImVec4(0.25415218f, 0.70837593f, 0.0f, 1.0f);\n      Colors[SELECTION_Z]           = ImVec4(0.02518686f, 0.27467736f, 1.0f, 1.0f);\n      Colors[INACTIVE]              = ImVec4(0.600f, 0.600f, 0.600f, 0.600f);\n      Colors[TRANSLATION_LINE]      = ImVec4(0.666f, 0.666f, 0.666f, 0.666f);\n      Colors[SCALE_LINE]            = ImVec4(0.250f, 0.250f, 0.250f, 1.000f);\n      Colors[ROTATION_USING_BORDER] = ImVec4(1.000f, 0.500f, 0.062f, 1.000f);\n      Colors[ROTATION_USING_FILL]   = ImVec4(1.000f, 0.500f, 0.062f, 0.500f);\n      Colors[HATCHED_AXIS_LINES]    = ImVec4(0.000f, 0.000f, 0.000f, 0.500f);\n      Colors[TEXT]                  = ImVec4(1.000f, 1.000f, 1.000f, 1.000f);\n      Colors[TEXT_SHADOW]           = ImVec4(0.000f, 0.000f, 0.000f, 1.000f);\n   }\n\n   struct Context\n   {\n      Context() : mbUsing(false), mbUsingViewManipulate(false), mbEnable(true), mbUsingBounds(false)\n      {\n          mIDStack.push_back(INVALID_ID);\n      }\n\n      ImDrawList* mDrawList;\n      Style mStyle;\n\n      MODE mMode;\n      matrix_t mModel;\n      matrix_t mModelLocal; // orthonormalized model\n      matrix_t mModelInverse;\n      matrix_t mModelSource;\n      //matrix_t mModelSourceInverse;\n      matrix_t mMVP;\n      matrix_t mMVPLocal; // MVP with full model matrix whereas mMVP's model matrix might only be translation in case of World space edition\n      matrix_t mViewProjection;\n\n      vec_t mModelScaleOrigin;\n      vec_t mRayOrigin;\n      vec_t mRayVector;\n\n      float  mRadiusSquareCenter;\n      ImVec2 mScreenSquareCenter;\n      ImVec2 mScreenSquareMin;\n      ImVec2 mScreenSquareMax;\n\n      float mScreenFactor;\n      vec_t mRelativeOrigin;\n\n      bool mbUsing;\n      bool mbUsingViewManipulate;\n      bool mbEnable;\n      bool mbMouseOver;\n      bool mReversed; // reversed projection matrix\n\n      // translation\n      vec_t mTranslationPlan;\n      vec_t mTranslationPlanOrigin;\n      vec_t mMatrixOrigin;\n      vec_t mTranslationLastDelta;\n\n      // rotation\n      vec_t mRotationVectorSource;\n      float mRotationAngle;\n      float mRotationAngleOrigin;\n      //vec_t mWorldToLocalAxis;\n\n      // scale\n      vec_t mScale;\n      vec_t mScaleValueOrigin;\n      vec_t mScaleLast;\n      float mSaveMousePosx;\n\n      // save axis factor when using gizmo\n      bool mBelowAxisLimit[3];\n      int mAxisMask = 0;\n      bool mBelowPlaneLimit[3];\n      float mAxisFactor[3];\n\n      float mAxisLimit=0.0025f;\n      float mPlaneLimit=0.02f;\n\n      // bounds stretching\n      vec_t mBoundsPivot;\n      vec_t mBoundsAnchor;\n      vec_t mBoundsPlan;\n      vec_t mBoundsLocalPivot;\n      int mBoundsBestAxis;\n      int mBoundsAxis[2];\n      bool mbUsingBounds;\n      matrix_t mBoundsMatrix;\n\n      //\n      int mCurrentOperation;\n\n      float mX = 0.f;\n      float mY = 0.f;\n      float mWidth = 0.f;\n      float mHeight = 0.f;\n      float mXMax = 0.f;\n      float mYMax = 0.f;\n      float mDisplayRatio = 1.f;\n\n      // check to not have multiple gizmo highlighted at the same time\n      bool mbOverGizmoHotspot = false;\n\n      ImGuiWindow* mAlternativeWindow = nullptr;\n      ImVector<ImGuiID> mIDStack;\n      ImGuiID mEditingID = INVALID_ID;\n      OPERATION mOperation = OPERATION(-1);\n\n      bool mAllowAxisFlip = true;\n      float mGizmoSizeClipSpace = 0.1f;\n\n      inline ImGuiID GetCurrentID() {return mIDStack.back();}\n   };\n\n   static Context gContext;\n\n   static const vec_t directionUnary[3] = { makeVect(1.f, 0.f, 0.f), makeVect(0.f, 1.f, 0.f), makeVect(0.f, 0.f, 1.f) };\n   static const char* translationInfoMask[] = { \"X : %5.3f\", \"Y : %5.3f\", \"Z : %5.3f\",\n      \"Y : %5.3f Z : %5.3f\", \"X : %5.3f Z : %5.3f\", \"X : %5.3f Y : %5.3f\",\n      \"X : %5.3f Y : %5.3f Z : %5.3f\" };\n   static const char* scaleInfoMask[] = { \"X : %5.2f\", \"Y : %5.2f\", \"Z : %5.2f\", \"XYZ : %5.2f\" };\n   static const char* rotationInfoMask[] = { \"X : %5.2f deg (%5.2f rad)\", \"Y : %5.2f deg (%5.2f rad)\", \"Z : %5.2f deg (%5.2f rad)\", \"Screen : %5.2f deg (%5.2f rad)\" };\n   static const int translationInfoIndex[] = { 0,0,0, 1,0,0, 2,0,0, 1,2,0, 0,2,0, 0,1,0, 0,1,2 };\n   static const float quadMin = 0.5f;\n   static const float quadMax = 0.8f;\n   static const float quadUV[8] = { quadMin, quadMin, quadMin, quadMax, quadMax, quadMax, quadMax, quadMin };\n   static const int halfCircleSegmentCount = 64;\n   static const float snapTension = 0.5f;\n\n   /////////////////////////////////////////////////////////////////////////////////////////\n\n   static int GetMoveType(OPERATION op, vec_t* gizmoHitProportion);\n   static int GetRotateType(OPERATION op);\n   static int GetScaleType(OPERATION op);\n\n   Style& GetStyle()\n   {\n      return gContext.mStyle;\n   }\n\n   static ImU32 GetColorU32(int idx)\n   {\n      IM_ASSERT(idx < COLOR::COUNT);\n      return ImGui::ColorConvertFloat4ToU32(gContext.mStyle.Colors[idx]);\n   }\n\n   static ImVec2 worldToPos(const vec_t& worldPos, const matrix_t& mat, \n       ImVec2 position = ImVec2(gContext.mX, gContext.mY), \n       ImVec2 size = ImVec2(gContext.mWidth, gContext.mHeight))\n   {\n      vec_t trans;\n      trans.TransformPoint(worldPos, mat);\n      trans *= 0.5f / trans.w;\n      trans += makeVect(0.5f, 0.5f);\n      trans.y = 1.f - trans.y;\n      trans.x *= size.x;\n      trans.y *= size.y;\n      trans.x += position.x;\n      trans.y += position.y;\n      return ImVec2(trans.x, trans.y);\n   }\n\n   static void ComputeCameraRay(vec_t& rayOrigin, vec_t& rayDir, \n       ImVec2 position = ImVec2(gContext.mX, gContext.mY), \n       ImVec2 size = ImVec2(gContext.mWidth, gContext.mHeight))\n   {\n       ImGuiIO& io = ImGui::GetIO();\n       const auto& camera = App::GetCamera();\n\n       float2 pixel(io.MousePos.x, io.MousePos.y);\n       float2 renderDim = float2(App::GetRenderer().GetDisplayWidth(),\n           App::GetRenderer().GetDisplayHeight());\n       float aspectRatio = camera.GetAspectRatio();\n       float tanHalfFOV = camera.GetTanHalfFOV();\n       float3 viewBasisX = camera.GetBasisX();\n       float3 viewBasisY = camera.GetBasisY();\n       float3 viewBasisZ = camera.GetBasisZ();\n\n       float2 uv = (pixel + 0.5f) / renderDim;\n       float2 ndc = uv * 2.0f - 1.0f;\n       ndc.y = -ndc.y;\n       float3 dirV = float3(ndc.x * aspectRatio * tanHalfFOV, ndc.y * tanHalfFOV, 1);\n       float3 dirW = dirV.x * viewBasisX + dirV.y * viewBasisY + dirV.z * viewBasisZ;\n       dirW.normalize();\n       rayDir = dirW;\n\n       rayOrigin = camera.GetPos();\n   }\n\n   static float GetSegmentLengthClipSpace(const vec_t& start, const vec_t& end, \n       const bool localCoordinates = false)\n   {\n      vec_t startOfSegment = start;\n      const matrix_t& mvp = localCoordinates ? gContext.mMVPLocal : gContext.mMVP;\n      startOfSegment.TransformPoint(mvp);\n      if (fabsf(startOfSegment.w) > FLT_EPSILON) // check for axis aligned with camera direction\n         startOfSegment *= 1.f / startOfSegment.w;\n\n      vec_t endOfSegment = end;\n      endOfSegment.TransformPoint(mvp);\n      if (fabsf(endOfSegment.w) > FLT_EPSILON) // check for axis aligned with camera direction\n         endOfSegment *= 1.f / endOfSegment.w;\n\n      vec_t clipSpaceAxis = endOfSegment - startOfSegment;\n      if (gContext.mDisplayRatio < 1.0)\n         clipSpaceAxis.x *= gContext.mDisplayRatio;\n      else\n         clipSpaceAxis.y /= gContext.mDisplayRatio;\n      float segmentLengthInClipSpace = sqrtf(clipSpaceAxis.x * clipSpaceAxis.x + \n          clipSpaceAxis.y * clipSpaceAxis.y);\n      return segmentLengthInClipSpace;\n   }\n\n   static float GetParallelogram(const vec_t& ptO, const vec_t& ptA, const vec_t& ptB)\n   {\n      vec_t pts[] = { ptO, ptA, ptB };\n      for (unsigned int i = 0; i < 3; i++)\n      {\n         pts[i].TransformPoint(gContext.mMVP);\n         if (fabsf(pts[i].w) > FLT_EPSILON) // check for axis aligned with camera direction\n            pts[i] *= 1.f / pts[i].w;\n      }\n      vec_t segA = pts[1] - pts[0];\n      vec_t segB = pts[2] - pts[0];\n      segA.y /= gContext.mDisplayRatio;\n      segB.y /= gContext.mDisplayRatio;\n      vec_t segAOrtho = makeVect(-segA.y, segA.x);\n      segAOrtho.Normalize();\n      float dt = segAOrtho.Dot3(segB);\n      float surface = sqrtf(segA.x * segA.x + segA.y * segA.y) * fabsf(dt);\n      return surface;\n   }\n\n   inline vec_t PointOnSegment(const vec_t& point, const vec_t& vertPos1, const vec_t& vertPos2)\n   {\n      vec_t c = point - vertPos1;\n      vec_t V;\n\n      V.Normalize(vertPos2 - vertPos1);\n      float d = (vertPos2 - vertPos1).Length();\n      float t = V.Dot3(c);\n\n      if (t < 0.f)\n         return vertPos1;\n\n      if (t > d)\n         return vertPos2;\n\n      return vertPos1 + V * t;\n   }\n\n   static float IntersectRayPlane(const vec_t& rOrigin, const vec_t& rVector, const vec_t& plan)\n   {\n      const float numer = plan.Dot3(rOrigin) - plan.w;\n      const float denom = plan.Dot3(rVector);\n\n      if (fabsf(denom) < FLT_EPSILON)  // normal is orthogonal to vector, cant intersect\n         return -1.0f;\n\n      return -(numer / denom);\n   }\n\n   static bool IsInContextRect(ImVec2 p)\n   {\n      return IsWithin(p.x, gContext.mX, gContext.mXMax) && IsWithin(p.y, gContext.mY, gContext.mYMax);\n   }\n\n   static bool IsHoveringWindow()\n   {\n      ImGuiContext& g = *ImGui::GetCurrentContext();\n      ImGuiWindow* window = ImGui::FindWindowByName(gContext.mDrawList->_OwnerName);\n      if (g.HoveredWindow == window)   // Mouse hovering drawlist window\n         return true;\n      if (gContext.mAlternativeWindow != nullptr && g.HoveredWindow == gContext.mAlternativeWindow)\n         return true;\n      if (g.HoveredWindow != NULL)     // Any other window is hovered\n         return false;\n      if (ImGui::IsMouseHoveringRect(window->InnerRect.Min, window->InnerRect.Max, false))   // Hovering drawlist window rect, while no other window is hovered (for _NoInputs windows)\n         return true;\n      return false;\n   }\n\n   void SetRect(float x, float y, float width, float height)\n   {\n      gContext.mX = x;\n      gContext.mY = y;\n      gContext.mWidth = width;\n      gContext.mHeight = height;\n      gContext.mXMax = gContext.mX + gContext.mWidth;\n      gContext.mYMax = gContext.mY + gContext.mXMax;\n      gContext.mDisplayRatio = width / height;\n   }\n\n   void SetDrawlist(ImDrawList* drawlist)\n   {\n      gContext.mDrawList = drawlist ? drawlist : ImGui::GetWindowDrawList();\n   }\n\n   void SetImGuiContext(ImGuiContext* ctx)\n   {\n      ImGui::SetCurrentContext(ctx);\n   }\n\n   void BeginFrame()\n   {\n      const ImU32 flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | \n          ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | \n          ImGuiWindowFlags_NoBringToFrontOnFocus;\n\n#ifdef IMGUI_HAS_VIEWPORT\n      ImGui::SetNextWindowSize(ImGui::GetMainViewport()->Size);\n      ImGui::SetNextWindowPos(ImGui::GetMainViewport()->Pos);\n#else\n      ImGuiIO& io = ImGui::GetIO();\n      ImGui::SetNextWindowSize(io.DisplaySize);\n      ImGui::SetNextWindowPos(ImVec2(0, 0));\n#endif\n\n      ImGui::PushStyleColor(ImGuiCol_WindowBg, 0);\n      ImGui::PushStyleColor(ImGuiCol_Border, 0);\n      ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);\n\n      ImGui::Begin(\"gizmo\", NULL, flags);\n      gContext.mDrawList = ImGui::GetWindowDrawList();\n      gContext.mbOverGizmoHotspot = false;\n      ImGui::End();\n      ImGui::PopStyleVar();\n      ImGui::PopStyleColor(2);\n   }\n\n   bool IsUsing()\n   {\n      return (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID)) || gContext.mbUsingBounds;\n   }\n\n   bool IsUsingViewManipulate()\n   {\n      return gContext.mbUsingViewManipulate;\n   }\n\n   bool IsUsingAny()\n   {\n      return gContext.mbUsing || gContext.mbUsingBounds;\n   }\n\n   bool IsOver()\n   {\n      return (Intersects(gContext.mOperation, TRANSLATE) && GetMoveType(gContext.mOperation, NULL) != MT_NONE) ||\n         (Intersects(gContext.mOperation, ROTATE) && GetRotateType(gContext.mOperation) != MT_NONE) ||\n         (Intersects(gContext.mOperation, SCALE) && GetScaleType(gContext.mOperation) != MT_NONE) || IsUsing();\n   }\n\n   bool IsOver(OPERATION op)\n   {\n      if(IsUsing())\n         return true;\n      if(Intersects(op, SCALE) && GetScaleType(op) != MT_NONE)\n         return true;\n      if(Intersects(op, ROTATE) && GetRotateType(op) != MT_NONE)\n         return true;\n      if(Intersects(op, TRANSLATE) && GetMoveType(op, NULL) != MT_NONE)\n         return true;\n      return false;\n   }\n\n   void Enable(bool enable)\n   {\n      gContext.mbEnable = enable;\n      if (!enable)\n      {\n         gContext.mbUsing = false;\n         gContext.mbUsingBounds = false;\n      }\n   }\n\n   static void ComputeContext(float4x4a& matrix, MODE mode)\n   {\n        const auto& camera = App::GetCamera();\n        auto V = camera.GetCurrView();\n        // ImGuizmo doesn't appear to work with infinite far plane\n        auto P = camera.GetProjNonInfiniteFarZ();\n        v_float4x4 vCurrV = load4x4(const_cast<float4x4a&>(camera.GetCurrView()));\n        v_float4x4 vP = load4x4(const_cast<float4x4a&>(camera.GetProj()));\n        v_float4x4 vVP = mul(vCurrV, vP);\n        auto VP = store(vVP);\n\n        gContext.mMode = mode;\n        gContext.mbMouseOver = IsHoveringWindow();\n\n        memcpy(gContext.mModelLocal, &matrix, sizeof(float) * 16);\n        gContext.mModelLocal.OrthoNormalize();\n\n        if (mode == LOCAL)\n        {\n            gContext.mModel = gContext.mModelLocal;\n            gContext.mModelInverse.Inverse(gContext.mModel);\n        }\n        else\n        {\n            float4x4a M(store(identity()));\n            M.m[3] = matrix.m[3];\n            memcpy(gContext.mModel, &M, sizeof(float) * 16);\n\n            M.m[3] = float4(-matrix.m[3].x, -matrix.m[3].y, -matrix.m[3].z, 1);\n            memcpy(gContext.mModelInverse, &M, sizeof(float) * 16);\n        }\n\n        memcpy(gContext.mModelSource, &matrix, sizeof(float) * 16);\n        gContext.mModelScaleOrigin.Set(gContext.mModelSource.v.right.Length(), \n            gContext.mModelSource.v.up.Length(), \n            gContext.mModelSource.v.dir.Length());\n\n        memcpy(gContext.mViewProjection, &VP, sizeof(float) * 16);\n        gContext.mMVP = gContext.mModel * gContext.mViewProjection;\n        gContext.mMVPLocal = gContext.mModelLocal * gContext.mViewProjection;\n\n        gContext.mReversed = true;\n\n        // compute scale from the size of camera right vector projected on screen at the matrix position\n        vec_t pointRight = App::GetCamera().GetBasisX();\n        pointRight.TransformPoint(gContext.mViewProjection);\n        gContext.mScreenFactor = gContext.mGizmoSizeClipSpace / \n            (pointRight.x / pointRight.w - gContext.mMVP.v.position.x / gContext.mMVP.v.position.w);\n\n        vec_t rightViewInverse = App::GetCamera().GetBasisX();\n        rightViewInverse.TransformVector(gContext.mModelInverse);\n        float rightLength = GetSegmentLengthClipSpace(makeVect(0.f, 0.f), rightViewInverse);\n        gContext.mScreenFactor = gContext.mGizmoSizeClipSpace / rightLength;\n\n        ImVec2 centerSSpace = worldToPos(makeVect(0.f, 0.f), gContext.mMVP);\n        gContext.mScreenSquareCenter = centerSSpace;\n        gContext.mScreenSquareMin = ImVec2(centerSSpace.x - 10.f, centerSSpace.y - 10.f);\n        gContext.mScreenSquareMax = ImVec2(centerSSpace.x + 10.f, centerSSpace.y + 10.f);\n\n        ComputeCameraRay(gContext.mRayOrigin, gContext.mRayVector);\n   }\n\n   static void ComputeColors(ImU32* colors, int type, OPERATION operation)\n   {\n      if (gContext.mbEnable)\n      {\n         ImU32 selectionColor = GetColorU32(SELECTION);\n\n         switch (operation)\n         {\n         case TRANSLATE:\n            colors[0] = (type == MT_MOVE_SCREEN) ? selectionColor : IM_COL32_WHITE;\n            for (int i = 0; i < 3; i++)\n            {\n               colors[i + 1] = (type == (int)(MT_MOVE_X + i)) ? GetColorU32(SELECTION_X + i) : GetColorU32(DIRECTION_X + i);\n               colors[i + 4] = (type == (int)(MT_MOVE_YZ + i)) ? selectionColor : GetColorU32(PLANE_X + i);\n               colors[i + 4] = (type == MT_MOVE_SCREEN) ? selectionColor : colors[i + 4];\n            }\n            break;\n         case ROTATE:\n            colors[0] = (type == MT_ROTATE_SCREEN) ? selectionColor : IM_COL32_WHITE;\n            for (int i = 0; i < 3; i++)\n               colors[i + 1] = (type == (int)(MT_ROTATE_X + i)) ? GetColorU32(SELECTION_X + i) : GetColorU32(DIRECTION_X + i);\n            break;\n         case SCALEU:\n         case SCALE:\n            colors[0] = (type == MT_SCALE_XYZ) ? selectionColor : IM_COL32_WHITE;\n            for (int i = 0; i < 3; i++)\n               colors[i + 1] = (type == (int)(MT_SCALE_X + i)) ? GetColorU32(SELECTION_X + i) : GetColorU32(DIRECTION_X + i);\n            break;\n         // note: this internal function is only called with three possible values for operation\n         default:\n            break;\n         }\n      }\n      else\n      {\n         ImU32 inactiveColor = GetColorU32(INACTIVE);\n         for (int i = 0; i < 7; i++)\n            colors[i] = inactiveColor;\n      }\n   }\n\n   static void ComputeTripodAxisAndVisibility(const int axisIndex, vec_t& dirAxis, vec_t& dirPlaneX, \n       vec_t& dirPlaneY, bool& belowAxisLimit, bool& belowPlaneLimit, const bool localCoordinates = false)\n   {\n      dirAxis = directionUnary[axisIndex];\n      dirPlaneX = directionUnary[(axisIndex + 1) % 3];\n      dirPlaneY = directionUnary[(axisIndex + 2) % 3];\n\n      if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID))\n      {\n         // when using, use stored factors so the gizmo doesn't flip when we translate\n\n         // Apply axis mask to axes and planes\n         belowAxisLimit = gContext.mBelowAxisLimit[axisIndex] && ((1<<axisIndex) & gContext.mAxisMask);\n         belowPlaneLimit = gContext.mBelowPlaneLimit[axisIndex] && ((((1<<axisIndex) & gContext.mAxisMask) && \n             !(gContext.mAxisMask & (gContext.mAxisMask - 1))) || !gContext.mAxisMask);\n\n         dirAxis *= gContext.mAxisFactor[axisIndex];\n         dirPlaneX *= gContext.mAxisFactor[(axisIndex + 1) % 3];\n         dirPlaneY *= gContext.mAxisFactor[(axisIndex + 2) % 3];\n      }\n      else\n      {\n         // new method\n         float lenDir = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirAxis, \n             localCoordinates);\n         float lenDirMinus = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), -dirAxis, \n             localCoordinates);\n\n         float lenDirPlaneX = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), dirPlaneX, \n             localCoordinates);\n         float lenDirMinusPlaneX = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), \n             -dirPlaneX, localCoordinates);\n\n         float lenDirPlaneY = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), \n             dirPlaneY, localCoordinates);\n         float lenDirMinusPlaneY = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), \n             -dirPlaneY, localCoordinates);\n\n         // For readability\n         bool & allowFlip = gContext.mAllowAxisFlip;\n         float mulAxis = (allowFlip && lenDir < lenDirMinus && \n             fabsf(lenDir - lenDirMinus) > FLT_EPSILON) ? -1.f : 1.f;\n         float mulAxisX = (allowFlip && lenDirPlaneX < lenDirMinusPlaneX && \n             fabsf(lenDirPlaneX - lenDirMinusPlaneX) > FLT_EPSILON) ? -1.f : 1.f;\n         float mulAxisY = (allowFlip && lenDirPlaneY < lenDirMinusPlaneY && \n             fabsf(lenDirPlaneY - lenDirMinusPlaneY) > FLT_EPSILON) ? -1.f : 1.f;\n         dirAxis *= mulAxis;\n         dirPlaneX *= mulAxisX;\n         dirPlaneY *= mulAxisY;\n\n         // for axis\n         float axisLengthInClipSpace = GetSegmentLengthClipSpace(makeVect(0.f, 0.f, 0.f), \n             dirAxis * gContext.mScreenFactor, localCoordinates);\n\n         float paraSurf = GetParallelogram(makeVect(0.f, 0.f, 0.f), dirPlaneX * gContext.mScreenFactor, \n             dirPlaneY * gContext.mScreenFactor);\n         // Apply axis mask to axes and planes\n         belowPlaneLimit = (paraSurf > gContext.mAxisLimit) && ((((1<<axisIndex)&gContext.mAxisMask) && \n             !(gContext.mAxisMask & (gContext.mAxisMask - 1))) || !gContext.mAxisMask);\n         belowAxisLimit = (axisLengthInClipSpace > gContext.mPlaneLimit) && !((1<<axisIndex)&gContext.mAxisMask);\n\n         // and store values\n         gContext.mAxisFactor[axisIndex] = mulAxis;\n         gContext.mAxisFactor[(axisIndex + 1) % 3] = mulAxisX;\n         gContext.mAxisFactor[(axisIndex + 2) % 3] = mulAxisY;\n         gContext.mBelowAxisLimit[axisIndex] = belowAxisLimit;\n         gContext.mBelowPlaneLimit[axisIndex] = belowPlaneLimit;\n      }\n   }\n\n   static void ComputeSnap(float* value, float snap)\n   {\n      if (snap <= FLT_EPSILON)\n         return;\n\n      float modulo = fmodf(*value, snap);\n      float moduloRatio = fabsf(modulo) / snap;\n      if (moduloRatio < snapTension)\n         *value -= modulo;\n      else if (moduloRatio > (1.f - snapTension))\n         *value = *value - modulo + snap * ((*value < 0.f) ? -1.f : 1.f);\n   }\n   static void ComputeSnap(vec_t& value, const float* snap)\n   {\n      for (int i = 0; i < 3; i++)\n         ComputeSnap(&value[i], snap[i]);\n   }\n\n   static float ComputeAngleOnPlan()\n   {\n      const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, \n          gContext.mTranslationPlan);\n      vec_t localPos = Normalized(gContext.mRayOrigin + gContext.mRayVector * len - \n          gContext.mModel.v.position);\n\n      vec_t perpendicularVector;\n      perpendicularVector.Cross(gContext.mRotationVectorSource, gContext.mTranslationPlan);\n      perpendicularVector.Normalize();\n      float acosAngle = Clamp(Dot(localPos, gContext.mRotationVectorSource), -1.f, 1.f);\n      float angle = acosf(acosAngle);\n      angle *= (Dot(localPos, perpendicularVector) < 0.f) ? 1.f : -1.f;\n      return angle;\n   }\n\n   static void DrawRotationGizmo(OPERATION op, int type)\n   {\n      if(!Intersects(op, ROTATE))\n         return;\n      ImDrawList* drawList = gContext.mDrawList;\n\n      bool isMultipleAxesMasked = gContext.mAxisMask & (gContext.mAxisMask - 1);\n      bool isNoAxesMasked = !gContext.mAxisMask;\n\n      // colors\n      ImU32 colors[7];\n      ComputeColors(colors, type, ROTATE);\n\n      vec_t cameraToModelNormalized = Normalized(gContext.mModel.v.position - App::GetCamera().GetPos());\n      cameraToModelNormalized.TransformVector(gContext.mModelInverse);\n\n      gContext.mRadiusSquareCenter = screenRotateSize * gContext.mHeight;\n\n      bool hasRSC = Intersects(op, ROTATE_SCREEN);\n      for (int axis = 0; axis < 3; axis++)\n      {\n         if(!Intersects(op, static_cast<OPERATION>(ROTATE_Z >> axis)))\n            continue;\n\n         bool isAxisMasked = (1 << (2 - axis)) & gContext.mAxisMask;\n\n         if ((!isAxisMasked || isMultipleAxesMasked) && !isNoAxesMasked)\n            continue;\n         const bool usingAxis = (gContext.mbUsing && type == MT_ROTATE_Z - axis);\n         const int circleMul = (hasRSC && !usingAxis) ? 1 : 2;\n\n         //ImVec2* circlePos = (ImVec2*)alloca(sizeof(ImVec2) * (circleMul * halfCircleSegmentCount + 1));\n         SmallVector<ImVec2, App::FrameAllocator> circlePosVec;\n         circlePosVec.resize(circleMul * halfCircleSegmentCount + 1);\n         ImVec2* circlePos = circlePosVec.data();\n\n         float angleStart = atan2f(cameraToModelNormalized[(4 - axis) % 3], \n             cameraToModelNormalized[(3 - axis) % 3]) + ZPI * 0.5f;\n\n         for (int i = 0; i < circleMul * halfCircleSegmentCount + 1; i++)\n         {\n            float ng = angleStart + (float)circleMul * ZPI * ((float)i / (float)(circleMul * halfCircleSegmentCount));\n            vec_t axisPos = makeVect(cosf(ng), sinf(ng), 0.f);\n            vec_t pos = makeVect(axisPos[axis], axisPos[(axis + 1) % 3], \n                axisPos[(axis + 2) % 3]) * gContext.mScreenFactor * rotationDisplayFactor;\n            circlePos[i] = worldToPos(pos, gContext.mMVP);\n         }\n\n         if (!gContext.mbUsing || usingAxis)\n         {\n             const float thickness = type == (int)MT_ROTATE_Z - axis ?\n                 gContext.mStyle.RotationLineThicknessHovered :\n                 gContext.mStyle.RotationLineThickness;\n\n             drawList->AddPolyline(circlePos, circleMul* halfCircleSegmentCount + 1,\n                colors[3 - axis], false, thickness);\n         }\n\n         float radiusAxis = sqrtf((ImLengthSqr(worldToPos(gContext.mModel.v.position, \n             gContext.mViewProjection) - circlePos[0])));\n         if (radiusAxis > gContext.mRadiusSquareCenter)\n            gContext.mRadiusSquareCenter = radiusAxis;\n      }\n      if (hasRSC && (!gContext.mbUsing || type == MT_ROTATE_SCREEN) && (!isMultipleAxesMasked && isNoAxesMasked))\n      {\n         drawList->AddCircle(worldToPos(gContext.mModel.v.position, gContext.mViewProjection), \n             gContext.mRadiusSquareCenter, colors[0], 64, gContext.mStyle.RotationOuterLineThickness);\n      }\n\n      if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID) && IsRotateType(type))\n      {\n         ImVec2 circlePos[halfCircleSegmentCount + 1];\n\n         circlePos[0] = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);\n         for (unsigned int i = 1; i < halfCircleSegmentCount + 1; i++)\n         {\n            float ng = gContext.mRotationAngle * ((float)(i - 1) / (float)(halfCircleSegmentCount - 1));\n            matrix_t rotateVectorMatrix;\n            rotateVectorMatrix.RotationAxis(gContext.mTranslationPlan, ng);\n            vec_t pos;\n            pos.TransformPoint(gContext.mRotationVectorSource, rotateVectorMatrix);\n            pos *= gContext.mScreenFactor * rotationDisplayFactor;\n            circlePos[i] = worldToPos(pos + gContext.mModel.v.position, gContext.mViewProjection);\n         }\n\n         const COLOR colorBorder = type == (int)MT_ROTATE_X ? SELECTION_X :\n             (type == (int)MT_ROTATE_Y ? SELECTION_Y : SELECTION_Z);\n         drawList->AddConvexPolyFilled(circlePos, halfCircleSegmentCount + 1, \n             GetColorU32(ROTATION_USING_FILL));\n         drawList->AddPolyline(circlePos, halfCircleSegmentCount + 1, GetColorU32(colorBorder),\n             true, gContext.mStyle.RotationLineThickness);\n\n         ImVec2 destinationPosOnScreen = circlePos[1];\n         char tmps[512];\n         ImFormatString(tmps, sizeof(tmps), rotationInfoMask[type - MT_ROTATE_X], \n             (gContext.mRotationAngle / ZPI) * 180.f, gContext.mRotationAngle);\n         drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), \n             GetColorU32(TEXT_SHADOW), tmps);\n         drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), \n             GetColorU32(TEXT), tmps);\n      }\n   }\n\n   static void DrawHatchedAxis(const vec_t& axis)\n   {\n      if (gContext.mStyle.HatchedAxisLineThickness <= 0.0f)\n         return;\n\n      for (int j = 1; j < 10; j++)\n      {\n         ImVec2 baseSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2) * gContext.mScreenFactor, \n             gContext.mMVP);\n         ImVec2 worldDirSSpace2 = worldToPos(axis * 0.05f * (float)(j * 2 + 1) * gContext.mScreenFactor, \n             gContext.mMVP);\n         gContext.mDrawList->AddLine(baseSSpace2, worldDirSSpace2, GetColorU32(HATCHED_AXIS_LINES), \n             gContext.mStyle.HatchedAxisLineThickness);\n      }\n   }\n\n   static void DrawScaleGizmo(OPERATION op, int type)\n   {\n      ImDrawList* drawList = gContext.mDrawList;\n\n      if(!Intersects(op, SCALE))\n        return;\n\n      // colors\n      ImU32 colors[7];\n      ComputeColors(colors, type, SCALE);\n\n      // draw\n      vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f };\n\n      if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID))\n         scaleDisplay = gContext.mScale;\n\n      for (int i = 0; i < 3; i++)\n      {\n         if(!Intersects(op, static_cast<OPERATION>(SCALE_X << i)))\n            continue;\n         const bool usingAxis = (gContext.mbUsing && type == MT_SCALE_X + i);\n         if (!gContext.mbUsing || usingAxis)\n         {\n            vec_t dirPlaneX, dirPlaneY, dirAxis;\n            bool belowAxisLimit, belowPlaneLimit;\n            ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, \n                belowAxisLimit, belowPlaneLimit, true);\n\n            // draw axis\n            if (belowAxisLimit)\n            {\n               bool hasTranslateOnAxis = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i));\n               float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f;\n               ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, \n                   gContext.mMVP);\n               ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, \n                   gContext.mMVP);\n               ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale * scaleDisplay[i]) * gContext.mScreenFactor, \n                   gContext.mMVP);\n\n               if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID))\n               {\n                  ImU32 scaleLineColor = GetColorU32(SCALE_LINE);\n                  drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, scaleLineColor, \n                      gContext.mStyle.ScaleLineThickness);\n                  drawList->AddCircleFilled(worldDirSSpaceNoScale, gContext.mStyle.ScaleLineCircleSize, \n                      scaleLineColor);\n               }\n\n               if (!hasTranslateOnAxis || gContext.mbUsing)\n               {\n                    const float thickness = type == (int)MT_SCALE_X + i ?\n                        gContext.mStyle.ScaleLineThicknessHovered :\n                        gContext.mStyle.ScaleLineThickness;\n\n                    drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], \n                        thickness);\n               }\n               drawList->AddCircleFilled(worldDirSSpace, gContext.mStyle.ScaleLineCircleSize, \n                   colors[i + 1]);\n\n               if (gContext.mAxisFactor[i] < 0.f)\n                  DrawHatchedAxis(dirAxis * scaleDisplay[i]);\n            }\n         }\n      }\n\n      // draw screen cirle\n      drawList->AddCircleFilled(gContext.mScreenSquareCenter, gContext.mStyle.CenterCircleSize, \n          colors[0], 32);\n\n      if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID) && IsScaleType(type))\n      {\n         //ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);\n         ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);\n         char tmps[512];\n         //vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;\n         int componentInfoIndex = (type - MT_SCALE_X) * 3;\n         ImFormatString(tmps, sizeof(tmps), scaleInfoMask[type - MT_SCALE_X], \n             scaleDisplay[translationInfoIndex[componentInfoIndex]]);\n         drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), \n             GetColorU32(TEXT_SHADOW), tmps);\n         drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), \n             GetColorU32(TEXT), tmps);\n      }\n   }\n\n   static void DrawScaleUniveralGizmo(OPERATION op, int type)\n   {\n      ImDrawList* drawList = gContext.mDrawList;\n\n      if (!Intersects(op, SCALEU))\n         return;\n\n      // colors\n      ImU32 colors[7];\n      ComputeColors(colors, type, SCALEU);\n\n      // draw\n      vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f };\n\n      if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID))\n         scaleDisplay = gContext.mScale;\n\n      for (int i = 0; i < 3; i++)\n      {\n         if (!Intersects(op, static_cast<OPERATION>(SCALE_XU << i)))\n            continue;\n\n         const bool usingAxis = (gContext.mbUsing && type == MT_SCALE_X + i);\n         if (!gContext.mbUsing || usingAxis)\n         {\n            vec_t dirPlaneX, dirPlaneY, dirAxis;\n            bool belowAxisLimit, belowPlaneLimit;\n            ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, \n                belowPlaneLimit, true);\n\n            // draw axis\n            if (belowAxisLimit)\n            {\n               bool hasTranslateOnAxis = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i));\n               float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f;\n               //ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal);\n               //ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP);\n               ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale * scaleDisplay[i]) * \n                   gContext.mScreenFactor, gContext.mMVPLocal);\n\n               drawList->AddCircleFilled(worldDirSSpace, 12.f, colors[i + 1]);\n            }\n         }\n      }\n\n      // draw screen cirle\n      drawList->AddCircle(gContext.mScreenSquareCenter, 20.f, colors[0], 32, \n          gContext.mStyle.CenterCircleSize);\n\n      if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID) && IsScaleType(type))\n      {\n         //ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);\n         ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);\n\n         char tmps[512];\n         //vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;\n         int componentInfoIndex = (type - MT_SCALE_X) * 3;\n         ImFormatString(tmps, sizeof(tmps), scaleInfoMask[type - MT_SCALE_X], \n             scaleDisplay[translationInfoIndex[componentInfoIndex]]);\n         drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), \n             GetColorU32(TEXT_SHADOW), tmps);\n         drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), \n             GetColorU32(TEXT), tmps);\n      }\n   }\n\n   static void DrawTranslationGizmo(OPERATION op, int type)\n   {\n      ImDrawList* drawList = gContext.mDrawList;\n      if (!drawList)\n         return;\n\n      if(!Intersects(op, TRANSLATE))\n         return;\n\n      // colors\n      ImU32 colors[7];\n      ComputeColors(colors, type, TRANSLATE);\n\n      const ImVec2 origin = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);\n\n      // draw\n      bool belowAxisLimit = false;\n      bool belowPlaneLimit = false;\n      for (int i = 0; i < 3; ++i)\n      {\n         vec_t dirPlaneX, dirPlaneY, dirAxis;\n         ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, \n             belowAxisLimit, belowPlaneLimit);\n\n         if (!gContext.mbUsing || (gContext.mbUsing && type == MT_MOVE_X + i))\n         {\n             const float thickness = type == (int)MT_MOVE_X + i ?\n                 gContext.mStyle.TranslationLineThicknessHovered :\n                 gContext.mStyle.TranslationLineThickness;\n\n            // draw axis\n            if (belowAxisLimit && Intersects(op, static_cast<OPERATION>(TRANSLATE_X << i)))\n            {\n               ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVP);\n               ImVec2 worldDirSSpace = worldToPos(dirAxis * gContext.mScreenFactor, gContext.mMVP);\n\n               drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], thickness);\n\n               // Arrow head begin\n               ImVec2 dir(origin - worldDirSSpace);\n\n               float d = sqrtf(ImLengthSqr(dir));\n               dir /= d; // Normalize\n               dir *= gContext.mStyle.TranslationLineArrowSize;\n\n               ImVec2 ortogonalDir(dir.y, -dir.x); // Perpendicular vector\n               ImVec2 a(worldDirSSpace + dir);\n               drawList->AddTriangleFilled(worldDirSSpace - dir, a + ortogonalDir, \n                   a - ortogonalDir, colors[i + 1]);\n               // Arrow head end\n\n               if (gContext.mAxisFactor[i] < 0.f)\n                  DrawHatchedAxis(dirAxis);\n            }\n         }\n         // draw plane\n         if (!gContext.mbUsing || (gContext.mbUsing && type == MT_MOVE_YZ + i))\n         {\n            if (belowPlaneLimit && Contains(op, TRANSLATE_PLANS[i]))\n            {\n               ImVec2 screenQuadPts[4];\n               for (int j = 0; j < 4; ++j)\n               {\n                  vec_t cornerWorldPos = (dirPlaneX * quadUV[j * 2] + dirPlaneY * \n                      quadUV[j * 2 + 1]) * gContext.mScreenFactor;\n                  screenQuadPts[j] = worldToPos(cornerWorldPos, gContext.mMVP);\n               }\n               drawList->AddPolyline(screenQuadPts, 4, GetColorU32(DIRECTION_X + i), true, 1.0f);\n               drawList->AddConvexPolyFilled(screenQuadPts, 4, colors[i + 4]);\n            }\n         }\n      }\n\n      drawList->AddCircleFilled(gContext.mScreenSquareCenter, gContext.mStyle.CenterCircleSize, \n          colors[0], 32);\n\n      if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID) && \n          IsTranslateType(type))\n      {\n         ImU32 translationLineColor = GetColorU32(TRANSLATION_LINE);\n\n         ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);\n         ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);\n         vec_t dif = { destinationPosOnScreen.x - sourcePosOnScreen.x, \n             destinationPosOnScreen.y - sourcePosOnScreen.y, 0.f, 0.f };\n         dif.Normalize();\n         dif *= 5.f;\n         drawList->AddCircle(sourcePosOnScreen, 6.f, translationLineColor);\n         drawList->AddCircle(destinationPosOnScreen, 6.f, translationLineColor);\n         drawList->AddLine(ImVec2(sourcePosOnScreen.x + dif.x, sourcePosOnScreen.y + dif.y), \n             ImVec2(destinationPosOnScreen.x - dif.x, destinationPosOnScreen.y - dif.y), \n             translationLineColor, 2.f);\n\n         char tmps[512];\n         vec_t deltaInfo = gContext.mModel.v.position - gContext.mMatrixOrigin;\n         int componentInfoIndex = (type - MT_MOVE_X) * 3;\n         ImFormatString(tmps, sizeof(tmps), translationInfoMask[type - MT_MOVE_X], \n             deltaInfo[translationInfoIndex[componentInfoIndex]], \n             deltaInfo[translationInfoIndex[componentInfoIndex + 1]], \n             deltaInfo[translationInfoIndex[componentInfoIndex + 2]]);\n         drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), \n             GetColorU32(TEXT_SHADOW), tmps);\n         drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), \n             GetColorU32(TEXT), tmps);\n      }\n   }\n\n   static bool CanActivate()\n   {\n      if (ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered() && !ImGui::IsAnyItemActive())\n         return true;\n      return false;\n   }\n\n   ///////////////////////////////////////////////////////////////////////////////////////\n\n   static int GetScaleType(OPERATION op)\n   {\n      if (gContext.mbUsing)\n         return MT_NONE;\n\n      ImGuiIO& io = ImGui::GetIO();\n      int type = MT_NONE;\n\n      // screen\n      if (io.MousePos.x >= gContext.mScreenSquareMin.x && io.MousePos.x <= gContext.mScreenSquareMax.x &&\n         io.MousePos.y >= gContext.mScreenSquareMin.y && io.MousePos.y <= gContext.mScreenSquareMax.y &&\n         Contains(op, SCALE))\n      {\n         type = MT_SCALE_XYZ;\n      }\n\n      // compute\n      for (int i = 0; i < 3 && type == MT_NONE; i++)\n      {\n         if(!Intersects(op, static_cast<OPERATION>(SCALE_X << i)))\n            continue;\n\n         bool isAxisMasked = (1 << i) & gContext.mAxisMask;\n\n         vec_t dirPlaneX, dirPlaneY, dirAxis;\n         bool belowAxisLimit, belowPlaneLimit;\n         ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit, true);\n         dirAxis.TransformVector(gContext.mModelLocal);\n         dirPlaneX.TransformVector(gContext.mModelLocal);\n         dirPlaneY.TransformVector(gContext.mModelLocal);\n\n         const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, \n             BuildPlane(gContext.mModelLocal.v.position, dirAxis));\n         vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len;\n\n         const float startOffset = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i)) ? 1.0f : 0.1f;\n         const float endOffset = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i)) ? 1.4f : 1.0f;\n         const ImVec2 posOnPlanScreen = worldToPos(posOnPlan, gContext.mViewProjection);\n         const ImVec2 axisStartOnScreen = worldToPos(gContext.mModelLocal.v.position + \n             dirAxis * gContext.mScreenFactor * startOffset, gContext.mViewProjection);\n         const ImVec2 axisEndOnScreen = worldToPos(gContext.mModelLocal.v.position + \n             dirAxis * gContext.mScreenFactor * endOffset, gContext.mViewProjection);\n\n         vec_t closestPointOnAxis = PointOnSegment(makeVect(posOnPlanScreen), \n             makeVect(axisStartOnScreen), makeVect(axisEndOnScreen));\n\n         if ((closestPointOnAxis - makeVect(posOnPlanScreen)).Length() < 12.f) // pixel size\n         {\n            if (!isAxisMasked)\n               type = MT_SCALE_X + i;\n         }\n      }\n\n      // universal\n\n      vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x,\n          io.MousePos.y - gContext.mScreenSquareCenter.y, 0.f, 0.f };\n      float dist = deltaScreen.Length();\n      if (Contains(op, SCALEU) && dist >= 17.0f && dist < 23.0f)\n         type = MT_SCALE_XYZ;\n\n      for (int i = 0; i < 3 && type == MT_NONE; i++)\n      {\n         if (!Intersects(op, static_cast<OPERATION>(SCALE_XU << i)))\n            continue;\n\n         vec_t dirPlaneX, dirPlaneY, dirAxis;\n         bool belowAxisLimit, belowPlaneLimit;\n         ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, \n             belowPlaneLimit, true);\n\n         // draw axis\n         if (belowAxisLimit)\n         {\n            bool hasTranslateOnAxis = Contains(op, static_cast<OPERATION>(TRANSLATE_X << i));\n            float markerScale = hasTranslateOnAxis ? 1.4f : 1.0f;\n            //ImVec2 baseSSpace = worldToPos(dirAxis * 0.1f * gContext.mScreenFactor, gContext.mMVPLocal);\n            //ImVec2 worldDirSSpaceNoScale = worldToPos(dirAxis * markerScale * gContext.mScreenFactor, gContext.mMVP);\n            ImVec2 worldDirSSpace = worldToPos((dirAxis * markerScale) * gContext.mScreenFactor, gContext.mMVPLocal);\n\n            float distance = sqrtf(ImLengthSqr(worldDirSSpace - io.MousePos));\n            if (distance < 12.f)\n               type = MT_SCALE_X + i;\n         }\n      }\n      return type;\n   }\n\n   static int GetRotateType(OPERATION op)\n   {\n      if (gContext.mbUsing)\n         return MT_NONE;\n\n      bool isNoAxesMasked = !gContext.mAxisMask;\n      bool isMultipleAxesMasked = gContext.mAxisMask & (gContext.mAxisMask - 1);\n\n      ImGuiIO& io = ImGui::GetIO();\n      int type = MT_NONE;\n\n      vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x, \n          io.MousePos.y - gContext.mScreenSquareCenter.y, 0.f, 0.f };\n      float dist = deltaScreen.Length();\n      if (Intersects(op, ROTATE_SCREEN) && dist >= (gContext.mRadiusSquareCenter - 4.0f) && \n          dist < (gContext.mRadiusSquareCenter + 4.0f))\n      {\n         if (!isNoAxesMasked)\n            return MT_NONE;\n         type = MT_ROTATE_SCREEN;\n      }\n\n      const vec_t planNormals[] = { gContext.mModel.v.right, gContext.mModel.v.up, \n          gContext.mModel.v.dir };\n\n      auto V = App::GetCamera().GetCurrView();\n         matrix_t viewMat;\n         memcpy(&viewMat, &V, sizeof(float) * 16);\n\n      vec_t modelViewPos;\n      modelViewPos.TransformPoint(gContext.mModel.v.position, viewMat);\n\n      for (int i = 0; i < 3 && type == MT_NONE; i++)\n      {\n         if(!Intersects(op, static_cast<OPERATION>(ROTATE_X << i)))\n            continue;\n         bool isAxisMasked = (1 << i) & gContext.mAxisMask;\n         // pickup plan\n         vec_t pickupPlan = BuildPlane(gContext.mModel.v.position, planNormals[i]);\n\n         const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, pickupPlan);\n         const vec_t intersectWorldPos = gContext.mRayOrigin + gContext.mRayVector * len;\n         vec_t intersectViewPos;\n         intersectViewPos.TransformPoint(intersectWorldPos, viewMat);\n\n         if (ImAbs(modelViewPos.z) - ImAbs(intersectViewPos.z) < -FLT_EPSILON)\n            continue;\n\n         const vec_t localPos = intersectWorldPos - gContext.mModel.v.position;\n         vec_t idealPosOnCircle = Normalized(localPos);\n         idealPosOnCircle.TransformVector(gContext.mModelInverse);\n         const ImVec2 idealPosOnCircleScreen = worldToPos(idealPosOnCircle * rotationDisplayFactor * \n             gContext.mScreenFactor, gContext.mMVP);\n\n         //gContext.mDrawList->AddCircle(idealPosOnCircleScreen, 5.f, IM_COL32_WHITE);\n         const ImVec2 distanceOnScreen = idealPosOnCircleScreen - io.MousePos;\n\n         const float distance = makeVect(distanceOnScreen).Length();\n         if (distance < 8.f) // pixel size\n         {\n            if ((!isAxisMasked || isMultipleAxesMasked) && !isNoAxesMasked)\n               break;\n            type = MT_ROTATE_X + i;\n         }\n      }\n\n      return type;\n   }\n\n   static int GetMoveType(OPERATION op, vec_t* gizmoHitProportion)\n   {\n      if(!Intersects(op, TRANSLATE) || gContext.mbUsing || !gContext.mbMouseOver)\n        return MT_NONE;\n\n      bool isNoAxesMasked = !gContext.mAxisMask;\n      bool isMultipleAxesMasked = gContext.mAxisMask & (gContext.mAxisMask - 1);\n\n      ImGuiIO& io = ImGui::GetIO();\n      int type = MT_NONE;\n\n      // screen\n      if (io.MousePos.x >= gContext.mScreenSquareMin.x && io.MousePos.x <= gContext.mScreenSquareMax.x &&\n         io.MousePos.y >= gContext.mScreenSquareMin.y && io.MousePos.y <= gContext.mScreenSquareMax.y &&\n         Contains(op, TRANSLATE))\n      {\n         type = MT_MOVE_SCREEN;\n      }\n\n      const vec_t screenCoord = makeVect(io.MousePos - ImVec2(gContext.mX, gContext.mY));\n\n      // compute\n      for (int i = 0; i < 3 && type == MT_NONE; i++)\n      {\n         bool isAxisMasked = (1 << i) & gContext.mAxisMask;\n         vec_t dirPlaneX, dirPlaneY, dirAxis;\n         bool belowAxisLimit, belowPlaneLimit;\n         ComputeTripodAxisAndVisibility(i, dirAxis, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit);\n         dirAxis.TransformVector(gContext.mModel);\n         dirPlaneX.TransformVector(gContext.mModel);\n         dirPlaneY.TransformVector(gContext.mModel);\n\n         const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, \n             BuildPlane(gContext.mModel.v.position, dirAxis));\n         vec_t posOnPlan = gContext.mRayOrigin + gContext.mRayVector * len;\n\n         const ImVec2 axisStartOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * \n             gContext.mScreenFactor * 0.1f, gContext.mViewProjection) - ImVec2(gContext.mX, gContext.mY);\n         const ImVec2 axisEndOnScreen = worldToPos(gContext.mModel.v.position + dirAxis * \n             gContext.mScreenFactor, gContext.mViewProjection) - ImVec2(gContext.mX, gContext.mY);\n\n         vec_t closestPointOnAxis = PointOnSegment(screenCoord, makeVect(axisStartOnScreen), \n             makeVect(axisEndOnScreen));\n         if ((closestPointOnAxis - screenCoord).Length() < 12.f && \n             Intersects(op, static_cast<OPERATION>(TRANSLATE_X << i))) // pixel size\n         {\n            if (isAxisMasked)\n               break;\n            type = MT_MOVE_X + i;\n         }\n\n         const float dx = dirPlaneX.Dot3((posOnPlan - gContext.mModel.v.position) * \n             (1.f / gContext.mScreenFactor));\n         const float dy = dirPlaneY.Dot3((posOnPlan - gContext.mModel.v.position) * \n             (1.f / gContext.mScreenFactor));\n         if (belowPlaneLimit && dx >= quadUV[0] && dx <= quadUV[4] && dy >= quadUV[1] && dy <= quadUV[3] && \n             Contains(op, TRANSLATE_PLANS[i]))\n         {\n            if ((!isAxisMasked || isMultipleAxesMasked) && !isNoAxesMasked)\n               break;\n            type = MT_MOVE_YZ + i;\n         }\n\n         if (gizmoHitProportion)\n            *gizmoHitProportion = makeVect(dx, dy, 0.f);\n      }\n      return type;\n   }\n\n   static bool HandleTranslation(float* matrix, float3& dt, OPERATION op, int& type, \n       const float* snap)\n   {\n      if(!Intersects(op, TRANSLATE) || type != MT_NONE)\n        return false;\n\n      const ImGuiIO& io = ImGui::GetIO();\n      const bool applyRotationLocaly = gContext.mMode == LOCAL || type == MT_MOVE_SCREEN;\n      bool modified = false;\n\n      // move\n      if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID) && \n          IsTranslateType(gContext.mCurrentOperation))\n      {\n         ImGui::SetNextFrameWantCaptureMouse(true);\n\n         const float signedLength = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, \n             gContext.mTranslationPlan);\n         const float len = fabsf(signedLength); // near plane\n         const vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;\n\n         // compute delta\n         const vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;\n         vec_t delta = newOrigin - gContext.mModel.v.position;\n\n         // 1 axis constraint\n         if (gContext.mCurrentOperation >= MT_MOVE_X && gContext.mCurrentOperation <= MT_MOVE_Z)\n         {\n            const int axisIndex = gContext.mCurrentOperation - MT_MOVE_X;\n            const vec_t& axisValue = *(vec_t*)&gContext.mModel.m[axisIndex];\n            const float lengthOnAxis = Dot(axisValue, delta);\n            delta = axisValue * lengthOnAxis;\n         }\n\n         // snap\n         if (snap)\n         {\n            vec_t cumulativeDelta = gContext.mModel.v.position + delta - gContext.mMatrixOrigin;\n            if (applyRotationLocaly)\n            {\n               matrix_t modelSourceNormalized = gContext.mModelSource;\n               modelSourceNormalized.OrthoNormalize();\n               matrix_t modelSourceNormalizedInverse;\n               modelSourceNormalizedInverse.Inverse(modelSourceNormalized);\n               cumulativeDelta.TransformVector(modelSourceNormalizedInverse);\n               ComputeSnap(cumulativeDelta, snap);\n               cumulativeDelta.TransformVector(modelSourceNormalized);\n            }\n            else\n               ComputeSnap(cumulativeDelta, snap);\n\n            delta = gContext.mMatrixOrigin + cumulativeDelta - gContext.mModel.v.position;\n         }\n\n         if (delta != gContext.mTranslationLastDelta)\n            modified = true;\n\n         gContext.mTranslationLastDelta = delta;\n\n         // compute matrix & delta\n         matrix_t deltaMatrixTranslation;\n         deltaMatrixTranslation.Translation(delta);\n         dt = float3(delta.x, delta.y, delta.z);\n\n         const matrix_t res = gContext.mModelSource * deltaMatrixTranslation;\n         *(matrix_t*)matrix = res;\n\n         if (!io.MouseDown[0])\n            gContext.mbUsing = false;\n\n         type = gContext.mCurrentOperation;\n      }\n      else\n      {\n         // find new possible way to move\n         vec_t gizmoHitProportion;\n         type = gContext.mbOverGizmoHotspot ? MT_NONE : GetMoveType(op, &gizmoHitProportion);\n         gContext.mbOverGizmoHotspot |= type != MT_NONE;\n         if (type != MT_NONE)\n            ImGui::SetNextFrameWantCaptureMouse(true);\n\n         if (CanActivate() && type != MT_NONE)\n         {\n            gContext.mbUsing = true;\n            gContext.mEditingID = gContext.GetCurrentID();\n            gContext.mCurrentOperation = type;\n            vec_t movePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir,\n               gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir,\n               -App::GetCamera().GetBasisZ() };\n\n            vec_t cameraToModelNormalized = Normalized(gContext.mModel.v.position - vec_t(App::GetCamera().GetPos()));\n            for (unsigned int i = 0; i < 3; i++)\n            {\n               vec_t orthoVector = Cross(movePlanNormal[i], cameraToModelNormalized);\n               movePlanNormal[i].Cross(orthoVector);\n               movePlanNormal[i].Normalize();\n            }\n            // pickup plan\n            gContext.mTranslationPlan = BuildPlane(gContext.mModel.v.position, movePlanNormal[type - MT_MOVE_X]);\n            const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, \n                gContext.mTranslationPlan);\n            gContext.mTranslationPlanOrigin = gContext.mRayOrigin + gContext.mRayVector * len;\n            gContext.mMatrixOrigin = gContext.mModel.v.position;\n\n            gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModel.v.position) * \n                (1.f / gContext.mScreenFactor);\n         }\n      }\n      return modified;\n   }\n\n   static bool HandleScale(float* matrix, float3& ds, OPERATION op, int& type, \n       const float* snap)\n   {\n      if((!Intersects(op, SCALE) && !Intersects(op, SCALEU)) || type != MT_NONE || !gContext.mbMouseOver)\n         return false;\n\n      ImGuiIO& io = ImGui::GetIO();\n      bool modified = false;\n\n      if (!gContext.mbUsing)\n      {\n         // find new possible way to scale\n         type = gContext.mbOverGizmoHotspot ? MT_NONE : GetScaleType(op);\n         gContext.mbOverGizmoHotspot |= type != MT_NONE;\n\n         if (type != MT_NONE)\n            ImGui::SetNextFrameWantCaptureMouse(true);\n\n         if (CanActivate() && type != MT_NONE)\n         {\n            gContext.mbUsing = true;\n            gContext.mEditingID = gContext.GetCurrentID();\n            gContext.mCurrentOperation = type;\n            const vec_t movePlanNormal[] = { gContext.mModelLocal.v.up, gContext.mModelLocal.v.dir, \n                gContext.mModelLocal.v.right, gContext.mModelLocal.v.dir, gContext.mModelLocal.v.up, \n                gContext.mModelLocal.v.right, -App::GetCamera().GetBasisZ()};\n            // pickup plan\n\n            gContext.mTranslationPlan = BuildPlane(gContext.mModelLocal.v.position, \n                movePlanNormal[type - MT_SCALE_X]);\n            const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, \n                gContext.mTranslationPlan);\n            gContext.mTranslationPlanOrigin = gContext.mRayOrigin + gContext.mRayVector * len;\n            gContext.mMatrixOrigin = gContext.mModelLocal.v.position;\n            gContext.mScale.Set(1.f, 1.f, 1.f);\n            gContext.mRelativeOrigin = (gContext.mTranslationPlanOrigin - gContext.mModelLocal.v.position) * \n                (1.f / gContext.mScreenFactor);\n            gContext.mScaleValueOrigin = makeVect(gContext.mModelSource.v.right.Length(), \n                gContext.mModelSource.v.up.Length(), gContext.mModelSource.v.dir.Length());\n            gContext.mSaveMousePosx = io.MousePos.x;\n         }\n      }\n      // scale\n      if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID) && \n          IsScaleType(gContext.mCurrentOperation))\n      {\n         ImGui::SetNextFrameWantCaptureMouse(true);\n\n         const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, \n             gContext.mTranslationPlan);\n         vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;\n         vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;\n         vec_t delta = newOrigin - gContext.mModelLocal.v.position;\n\n         // 1 axis constraint\n         if (gContext.mCurrentOperation >= MT_SCALE_X && gContext.mCurrentOperation <= MT_SCALE_Z)\n         {\n            int axisIndex = gContext.mCurrentOperation - MT_SCALE_X;\n            const vec_t& axisValue = *(vec_t*)&gContext.mModelLocal.m[axisIndex];\n            float lengthOnAxis = Dot(axisValue, delta);\n            delta = axisValue * lengthOnAxis;\n\n            vec_t baseVector = gContext.mTranslationPlanOrigin - gContext.mModelLocal.v.position;\n            float ratio = Dot(axisValue, baseVector + delta) / Dot(axisValue, baseVector);\n\n            gContext.mScale[axisIndex] = max(ratio, 0.001f);\n         }\n         else\n         {\n            float scaleDelta = (io.MousePos.x - gContext.mSaveMousePosx) * 0.01f;\n            gContext.mScale.Set(max(1.f + scaleDelta, 0.001f));\n         }\n\n         // snap\n         if (snap)\n         {\n            float scaleSnap[] = { snap[0], snap[0], snap[0] };\n            ComputeSnap(gContext.mScale, scaleSnap);\n         }\n\n         // no 0 allowed\n         for (int i = 0; i < 3; i++)\n            gContext.mScale[i] = max(gContext.mScale[i], 0.001f);\n\n         if (gContext.mScaleLast != gContext.mScale)\n            modified = true;\n         gContext.mScaleLast = gContext.mScale;\n\n         // compute matrix & delta\n         matrix_t deltaMatrixScale;\n         deltaMatrixScale.Scale(gContext.mScale * gContext.mScaleValueOrigin);\n\n         matrix_t res = deltaMatrixScale * gContext.mModelLocal;\n         *(matrix_t*)matrix = res;\n\n         {\n            vec_t deltaScale = gContext.mScale * gContext.mScaleValueOrigin;\n\n            vec_t originalScaleDivider;\n            originalScaleDivider.x = 1 / gContext.mModelScaleOrigin.x;\n            originalScaleDivider.y = 1 / gContext.mModelScaleOrigin.y;\n            originalScaleDivider.z = 1 / gContext.mModelScaleOrigin.z;\n\n            deltaScale = deltaScale * originalScaleDivider;\n\n            //deltaMatrixScale.Scale(deltaScale);\n            //memcpy(&ds, deltaMatrixScale.m16, sizeof(float) * 16);\n            //ds = float3(deltaMatrixScale.m[0][0], deltaMatrixScale.m[1][1], deltaMatrixScale.m[2][2]);\n            ds = float3(deltaScale.x, deltaScale.y, deltaScale.z);\n         }\n\n         if (!io.MouseDown[0])\n         {\n            gContext.mbUsing = false;\n            gContext.mScale.Set(1.f, 1.f, 1.f);\n         }\n\n         type = gContext.mCurrentOperation;\n      }\n      return modified;\n   }\n\n   static bool HandleRotation(float* matrix, float4x4a& dr, OPERATION op, int& type, \n       const float* snap)\n   {\n      if(!Intersects(op, ROTATE) || type != MT_NONE || !gContext.mbMouseOver)\n        return false;\n\n      ImGuiIO& io = ImGui::GetIO();\n      bool applyRotationLocaly = gContext.mMode == LOCAL;\n      bool modified = false;\n\n      if (!gContext.mbUsing)\n      {\n         type = gContext.mbOverGizmoHotspot ? MT_NONE : GetRotateType(op);\n         gContext.mbOverGizmoHotspot |= type != MT_NONE;\n\n         if (type != MT_NONE)\n            ImGui::SetNextFrameWantCaptureMouse(true);\n\n         if (type == MT_ROTATE_SCREEN)\n            applyRotationLocaly = true;\n\n         if (CanActivate() && type != MT_NONE)\n         {\n            gContext.mbUsing = true;\n            gContext.mEditingID = gContext.GetCurrentID();\n            gContext.mCurrentOperation = type;\n            const vec_t rotatePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, \n                gContext.mModel.v.dir, -App::GetCamera().GetBasisZ() };\n            // pickup plan\n            if (applyRotationLocaly)\n            {\n               gContext.mTranslationPlan = BuildPlane(gContext.mModel.v.position, \n                   rotatePlanNormal[type - MT_ROTATE_X]);\n            }\n            else\n            {\n               gContext.mTranslationPlan = BuildPlane(gContext.mModelSource.v.position, \n                   directionUnary[type - MT_ROTATE_X]);\n            }\n\n            const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);\n            vec_t localPos = gContext.mRayOrigin + gContext.mRayVector * len - gContext.mModel.v.position;\n            gContext.mRotationVectorSource = Normalized(localPos);\n            gContext.mRotationAngleOrigin = ComputeAngleOnPlan();\n         }\n      }\n\n      // rotation\n      if (gContext.mbUsing && (gContext.GetCurrentID() == gContext.mEditingID) && \n          IsRotateType(gContext.mCurrentOperation))\n      {\n         ImGui::SetNextFrameWantCaptureMouse(true);\n\n         gContext.mRotationAngle = ComputeAngleOnPlan();\n         if (snap)\n         {\n            float snapInRadian = snap[0] * DEG2RAD;\n            ComputeSnap(&gContext.mRotationAngle, snapInRadian);\n         }\n         vec_t rotationAxisLocalSpace;\n\n         rotationAxisLocalSpace.TransformVector(makeVect(gContext.mTranslationPlan.x, \n             gContext.mTranslationPlan.y, gContext.mTranslationPlan.z, 0.f), gContext.mModelInverse);\n         rotationAxisLocalSpace.Normalize();\n\n         matrix_t deltaRotation;\n         deltaRotation.RotationAxis(rotationAxisLocalSpace, gContext.mRotationAngle - \n             gContext.mRotationAngleOrigin);\n         if (gContext.mRotationAngle != gContext.mRotationAngleOrigin)\n            modified = true;\n         gContext.mRotationAngleOrigin = gContext.mRotationAngle;\n\n         matrix_t scaleOrigin;\n         scaleOrigin.Scale(gContext.mModelScaleOrigin);\n\n         if (applyRotationLocaly)\n            *(matrix_t*)matrix = scaleOrigin * deltaRotation * gContext.mModelLocal;\n         else\n         {\n            matrix_t res = gContext.mModelSource;\n            res.v.position.Set(0.f);\n\n            *(matrix_t*)matrix = res * deltaRotation;\n            ((matrix_t*)matrix)->v.position = gContext.mModelSource.v.position;\n         }\n\n         //matrix_t deltaMatrix = gContext.mModelInverse * deltaRotation * gContext.mModel;\n         //memcpy(&dr, &deltaMatrix, 16 * sizeof(float));\n         memcpy(&dr, &deltaRotation, 16 * sizeof(float));\n\n         if (!io.MouseDown[0])\n         {\n            gContext.mbUsing = false;\n            gContext.mEditingID = ImGuiID(-1);\n         }\n         type = gContext.mCurrentOperation;\n      }\n      return modified;\n   }\n\n   void SetAlternativeWindow(ImGuiWindow* window)\n   {\n      gContext.mAlternativeWindow = window;\n   }\n\n   void SetID(int id)\n   {\n      gContext.mIDStack.back() = id;\n   }\n\n   ImGuiID GetID(const char* str, const char* str_end)\n   {\n      ImGuiID seed = gContext.mIDStack.back();\n      ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);\n      return id;\n   }\n\n   ImGuiID GetID(const char* str)\n   {\n      return GetID(str, nullptr);\n   }\n\n   ImGuiID GetID(const void* ptr)\n   {\n      ImGuiID seed = gContext.mIDStack.back();\n      ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);\n      return id;\n   }\n\n   ImGuiID GetID(int n)\n   {\n      ImGuiID seed = gContext.mIDStack.back();\n      ImGuiID id = ImHashData(&n, sizeof(n), seed);\n      return id;\n   }\n\n   void PushID(const char* str_id)\n   {\n      ImGuiID id = GetID(str_id);\n      gContext.mIDStack.push_back(id);\n   }\n\n   void PushID(const char* str_id_begin, const char* str_id_end)\n   {\n      ImGuiID id = GetID(str_id_begin, str_id_end);\n      gContext.mIDStack.push_back(id);\n   }\n\n   void PushID(const void* ptr_id)\n   {\n      ImGuiID id = GetID(ptr_id);\n      gContext.mIDStack.push_back(id);\n   }\n\n   void PushID(int int_id)\n   {\n      ImGuiID id = GetID(int_id);\n      gContext.mIDStack.push_back(id);\n   }\n\n   void PopID()\n   {\n      IM_ASSERT(gContext.mIDStack.Size > 1); // Too many PopID(), or could be popping in a wrong/different window?\n      gContext.mIDStack.pop_back();\n   }\n\n   void AllowAxisFlip(bool value)\n   {\n     gContext.mAllowAxisFlip = value;\n   }\n\n   void SetAxisLimit(float value)\n   {\n     gContext.mAxisLimit=value;\n   }\n\n   void SetAxisMask(bool x, bool y, bool z)\n   {\n      gContext.mAxisMask = (x ? 1 : 0) + (y ? 2 : 0) + (z ? 4 : 0);\n   }\n\n   void SetPlaneLimit(float value)\n   {\n     gContext.mPlaneLimit = value;\n   }\n\n   bool IsOver(float* position, float pixelRadius)\n   {\n      const ImGuiIO& io = ImGui::GetIO();\n\n      float radius = sqrtf((ImLengthSqr(worldToPos({ position[0], position[1], position[2], 0 }, \n          gContext.mViewProjection) - io.MousePos)));\n      return radius < pixelRadius;\n   }\n\n   bool Manipulate(OPERATION operation, MODE mode, float4x4a& world, float3& dt, float4x4a& dr, \n       float3& ds, const float* snap, const float* localBounds, const float* boundsSnap)\n   {\n      gContext.mDrawList->PushClipRect (ImVec2(gContext.mX, gContext.mY), \n          ImVec2(gContext.mX + gContext.mWidth, gContext.mY + gContext.mHeight), false);\n\n      // Scale is always local or matrix will be skewed when applying world scale or oriented matrix\n      ComputeContext(world, (operation & SCALE) ? LOCAL : mode);\n\n      // behind camera\n      //vec_t camSpacePosition;\n      //camSpacePosition.TransformPoint(makeVect(0.f, 0.f, 0.f), gContext.mMVP);\n      //if (!gContext.mIsOrthographic && camSpacePosition.z < 0.001f && !gContext.mbUsing)\n      //   return;\n\n      // --\n      int type = MT_NONE;\n      float* matrix = reinterpret_cast<float*>(&world);\n      bool modified = false;\n\n      // Init to identify transformations\n      dt = float3(0);\n      dr = store(identity());\n      ds = float3(1);\n\n      if (gContext.mbEnable)\n      {\n         if (!gContext.mbUsingBounds)\n         {\n             modified = HandleTranslation(matrix, dt, operation, type, snap) ||\n                HandleScale(matrix, ds, operation, type, snap) ||\n                HandleRotation(matrix, dr, operation, type, snap);\n         }\n      }\n\n      gContext.mOperation = operation;\n      if (!gContext.mbUsingBounds)\n      {\n         DrawRotationGizmo(operation, type);\n         DrawTranslationGizmo(operation, type);\n         DrawScaleGizmo(operation, type);\n         DrawScaleUniveralGizmo(operation, type);\n      }\n\n      gContext.mDrawList->PopClipRect ();\n      return modified;\n   }\n\n   void SetGizmoSizeClipSpace(float value)\n   {\n      gContext.mGizmoSizeClipSpace = value;\n   }\n};\n"
  },
  {
    "path": "External/ImGui/ImGuizmo.h",
    "content": "// https://github.com/CedricGuillemet/ImGuizmo\n// v1.91.3 WIP\n//\n// The MIT License(MIT)\n//\n// Copyright(c) 2021 Cedric Guillemet\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files(the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions :\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n//\n// -------------------------------------------------------------------------------------------\n// History :\n// 2019/11/03 View gizmo\n// 2016/09/11 Behind camera culling. Scaling Delta matrix not multiplied by source matrix scales. local/world rotation and translation fixed. Display message is incorrect (X: ... Y:...) in local mode.\n// 2016/09/09 Hatched negative axis. Snapping. Documentation update.\n// 2016/09/04 Axis switch and translation plan autohiding. Scale transform stability improved\n// 2016/09/01 Mogwai changed to Manipulate. Draw debug cube. Fixed inverted scale. Mixing scale and translation/rotation gives bad results.\n// 2016/08/31 First version\n//\n// -------------------------------------------------------------------------------------------\n// Future (no order):\n//\n// - Multi view\n// - display rotation/translation/scale infos in local/world space and not only local\n// - finish local/world matrix application\n// - OPERATION as bitmask\n// \n// -------------------------------------------------------------------------------------------\n// Example \n#if 0\nvoid EditTransform(const Camera& camera, matrix_t& matrix)\n{\n   static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::ROTATE);\n   static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::WORLD);\n   if (ImGui::IsKeyPressed(90))\n      mCurrentGizmoOperation = ImGuizmo::TRANSLATE;\n   if (ImGui::IsKeyPressed(69))\n      mCurrentGizmoOperation = ImGuizmo::ROTATE;\n   if (ImGui::IsKeyPressed(82)) // r Key\n      mCurrentGizmoOperation = ImGuizmo::SCALE;\n   if (ImGui::RadioButton(\"Translate\", mCurrentGizmoOperation == ImGuizmo::TRANSLATE))\n      mCurrentGizmoOperation = ImGuizmo::TRANSLATE;\n   ImGui::SameLine();\n   if (ImGui::RadioButton(\"Rotate\", mCurrentGizmoOperation == ImGuizmo::ROTATE))\n      mCurrentGizmoOperation = ImGuizmo::ROTATE;\n   ImGui::SameLine();\n   if (ImGui::RadioButton(\"Scale\", mCurrentGizmoOperation == ImGuizmo::SCALE))\n      mCurrentGizmoOperation = ImGuizmo::SCALE;\n   float matrixTranslation[3], matrixRotation[3], matrixScale[3];\n   ImGuizmo::DecomposeMatrixToComponents(matrix.m16, matrixTranslation, matrixRotation, matrixScale);\n   ImGui::InputFloat3(\"Tr\", matrixTranslation, 3);\n   ImGui::InputFloat3(\"Rt\", matrixRotation, 3);\n   ImGui::InputFloat3(\"Sc\", matrixScale, 3);\n   ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, matrix.m16);\n\n   if (mCurrentGizmoOperation != ImGuizmo::SCALE)\n   {\n      if (ImGui::RadioButton(\"Local\", mCurrentGizmoMode == ImGuizmo::LOCAL))\n         mCurrentGizmoMode = ImGuizmo::LOCAL;\n      ImGui::SameLine();\n      if (ImGui::RadioButton(\"World\", mCurrentGizmoMode == ImGuizmo::WORLD))\n         mCurrentGizmoMode = ImGuizmo::WORLD;\n   }\n   static bool useSnap(false);\n   if (ImGui::IsKeyPressed(83))\n      useSnap = !useSnap;\n   ImGui::Checkbox(\"\", &useSnap);\n   ImGui::SameLine();\n   vec_t snap;\n   switch (mCurrentGizmoOperation)\n   {\n   case ImGuizmo::TRANSLATE:\n      snap = config.mSnapTranslation;\n      ImGui::InputFloat3(\"Snap\", &snap.x);\n      break;\n   case ImGuizmo::ROTATE:\n      snap = config.mSnapRotation;\n      ImGui::InputFloat(\"Angle Snap\", &snap.x);\n      break;\n   case ImGuizmo::SCALE:\n      snap = config.mSnapScale;\n      ImGui::InputFloat(\"Scale Snap\", &snap.x);\n      break;\n   }\n   ImGuiIO& io = ImGui::GetIO();\n   ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);\n   ImGuizmo::Manipulate(camera.mView.m16, camera.mProjection.m16, mCurrentGizmoOperation, \n       mCurrentGizmoMode, matrix.m16, NULL, useSnap ? &snap.x : NULL);\n}\n#endif\n#pragma once\n\n#ifdef USE_IMGUI_API\n#include \"imconfig.h\"\n#endif\n#ifndef IMGUI_API\n#define IMGUI_API\n#endif\n\n#ifndef IMGUIZMO_NAMESPACE\n#define IMGUIZMO_NAMESPACE ImGuizmo\n#endif\n\nstruct ImGuiWindow;\nstruct ImDrawList;\nstruct ImGuiContext;\n\nnamespace ZetaRay::Math\n{\n    struct float3;\n    struct alignas(16) float4x4a;\n}\n\nnamespace IMGUIZMO_NAMESPACE\n{\n   // call inside your own window and before Manipulate() in order to draw gizmo to that window.\n   // Or pass a specific ImDrawList to draw to (e.g. ImGui::GetForegroundDrawList()).\n   IMGUI_API void SetDrawlist(ImDrawList* drawlist = nullptr);\n\n   // call BeginFrame right after ImGui_XXXX_NewFrame();\n   IMGUI_API void BeginFrame();\n\n   // this is necessary because when imguizmo is compiled into a dll, and imgui into another\n   // globals are not shared between them.\n   // More details at https://stackoverflow.com/questions/19373061/what-happens-to-global-and-static-variables-in-a-shared-library-when-it-is-dynam\n   // expose method to set imgui context\n   IMGUI_API void SetImGuiContext(ImGuiContext* ctx);\n\n   // return true if mouse cursor is over any gizmo control (axis, plan or screen component)\n   IMGUI_API bool IsOver();\n\n   // return true if mouse IsOver or if the gizmo is in moving state\n   IMGUI_API bool IsUsing();\n\n   // return true if the view gizmo is in moving state\n   IMGUI_API bool IsUsingViewManipulate();\n\n   // return true if any gizmo is in moving state\n   IMGUI_API bool IsUsingAny();\n\n   // enable/disable the gizmo. Stay in the state until next call to Enable.\n   // gizmo is rendered with gray half transparent color when disabled\n   IMGUI_API void Enable(bool enable);\n\n   IMGUI_API void SetRect(float x, float y, float width, float height);\n\n   // call it when you want a gizmo\n   // Needs view and projection matrices. \n   // matrix parameter is the source matrix (where will be gizmo be drawn) and might be \n   // transformed by the function. Return deltaMatrix is optiona translation is applied \n   // in world space\n   enum OPERATION\n   {\n      TRANSLATE_X      = (1u << 0),\n      TRANSLATE_Y      = (1u << 1),\n      TRANSLATE_Z      = (1u << 2),\n      ROTATE_X         = (1u << 3),\n      ROTATE_Y         = (1u << 4),\n      ROTATE_Z         = (1u << 5),\n      ROTATE_SCREEN    = (1u << 6),\n      SCALE_X          = (1u << 7),\n      SCALE_Y          = (1u << 8),\n      SCALE_Z          = (1u << 9),\n      BOUNDS           = (1u << 10),\n      SCALE_XU         = (1u << 11),\n      SCALE_YU         = (1u << 12),\n      SCALE_ZU         = (1u << 13),\n\n      TRANSLATE = TRANSLATE_X | TRANSLATE_Y | TRANSLATE_Z,\n      ROTATE = ROTATE_X | ROTATE_Y | ROTATE_Z | ROTATE_SCREEN,\n      SCALE = SCALE_X | SCALE_Y | SCALE_Z,\n      SCALEU = SCALE_XU | SCALE_YU | SCALE_ZU, // universal\n      UNIVERSAL = TRANSLATE | ROTATE | SCALEU\n   };\n\n   inline OPERATION operator|(OPERATION lhs, OPERATION rhs)\n   {\n     return static_cast<OPERATION>(static_cast<int>(lhs) | static_cast<int>(rhs));\n   }\n\n   enum MODE\n   {\n      LOCAL,\n      WORLD\n   };\n\n   IMGUI_API bool Manipulate(OPERATION operation, MODE mode, ZetaRay::Math::float4x4a& matrix,\n       ZetaRay::Math::float3& dt, ZetaRay::Math::float4x4a& dr, ZetaRay::Math::float3& ds, \n       const float* snap = nullptr, const float* localBounds = nullptr, \n       const float* boundsSnap = nullptr);\n\n   IMGUI_API void SetAlternativeWindow(ImGuiWindow* window);\n  \n   [[deprecated(\"Use PushID/PopID instead.\")]]\n   IMGUI_API void SetID(int id);\n\n\t// ID stack/scopes\n\t// Read the FAQ (docs/FAQ.md or http://dearimgui.org/faq) for more details about how ID are handled in dear imgui.\n\t// - Those questions are answered and impacted by understanding of the ID stack system:\n\t//   - \"Q: Why is my widget not reacting when I click on it?\"\n\t//   - \"Q: How can I have widgets with an empty label?\"\n\t//   - \"Q: How can I have multiple widgets with the same label?\"\n\t// - Short version: ID are hashes of the entire ID stack. If you are creating widgets in a loop you most likely\n\t//   want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them.\n\t// - You can also use the \"Label##foobar\" syntax within widget label to distinguish them from each others.\n\t// - In this header file we use the \"label\"/\"name\" terminology to denote a string that will be displayed + used as an ID,\n\t//   whereas \"str_id\" denote a string that is only used as an ID and not normally displayed.\n\tIMGUI_API void          PushID(const char* str_id);                                     // push string into the ID stack (will hash string).\n\tIMGUI_API void          PushID(const char* str_id_begin, const char* str_id_end);       // push string into the ID stack (will hash string).\n\tIMGUI_API void          PushID(const void* ptr_id);                                     // push pointer into the ID stack (will hash pointer).\n\tIMGUI_API void          PushID(int int_id);                                             // push integer into the ID stack (will hash integer).\n\tIMGUI_API void          PopID();                                                        // pop from the ID stack.\n\tIMGUI_API ImGuiID       GetID(const char* str_id);                                      // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself\n\tIMGUI_API ImGuiID       GetID(const char* str_id_begin, const char* str_id_end);\n\tIMGUI_API ImGuiID       GetID(const void* ptr_id);\n\n   // return true if the cursor is over the operation's gizmo\n   IMGUI_API bool IsOver(OPERATION op);\n   IMGUI_API void SetGizmoSizeClipSpace(float value);\n\n   // Allow axis to flip\n   // When true (default), the guizmo axis flip for better visibility\n   // When false, they always stay along the positive world/local axis\n   IMGUI_API void AllowAxisFlip(bool value);\n\n   // Configure the limit where axis are hidden\n   IMGUI_API void SetAxisLimit(float value);\n   // Set an axis mask to permanently hide a given axis (true -> hidden, false -> shown)\n   IMGUI_API void SetAxisMask(bool x, bool y, bool z);\n   // Configure the limit where planes are hiden\n   IMGUI_API void SetPlaneLimit(float value);\n   // from a x,y,z point in space and using Manipulation view/projection matrix, check if\n   // mouse is in pixel radius distance of that projected point\n   IMGUI_API bool IsOver(float* position, float pixelRadius);\n\n   enum COLOR\n   {\n      DIRECTION_X,      // directionColor[0]\n      DIRECTION_Y,      // directionColor[1]\n      DIRECTION_Z,      // directionColor[2]\n      PLANE_X,          // planeColor[0]\n      PLANE_Y,          // planeColor[1]\n      PLANE_Z,          // planeColor[2]\n      SELECTION,        // selectionColor\n      SELECTION_X,      // selectionColor (x axis)\n      SELECTION_Y,      // selectionColor (y axis) \n      SELECTION_Z,      // selectionColor (z axis)\n      INACTIVE,         // inactiveColor\n      TRANSLATION_LINE, // translationLineColor\n      SCALE_LINE,\n      ROTATION_USING_BORDER,\n      ROTATION_USING_FILL,\n      HATCHED_AXIS_LINES,\n      TEXT,\n      TEXT_SHADOW,\n      COUNT\n   };\n\n   struct Style\n   {\n      IMGUI_API Style();\n\n      float TranslationLineThickness;        // Thickness of lines for translation gizmo\n      float TranslationLineThicknessHovered; // Thickness of lines for translation gizmo when hovered\n      float TranslationLineArrowSize;        // Size of arrow at the end of lines for translation gizmo\n      float RotationLineThickness;           // Thickness of lines for rotation gizmo\n      float RotationLineThicknessHovered;    // Thickness of lines for rotation gizmo when hovered\n      float RotationOuterLineThickness;      // Thickness of line surrounding the rotation gizmo\n      float ScaleLineThickness;              // Thickness of lines for scale gizmo\n      float ScaleLineThicknessHovered;       // Thickness of lines for scale gizmo\n      float ScaleLineCircleSize;             // Size of circle at the end of lines for scale gizmo\n      float HatchedAxisLineThickness;        // Thickness of hatched axis lines\n      float CenterCircleSize;                // Size of circle at the center of the translate/scale gizmo\n\n      ImVec4 Colors[COLOR::COUNT];\n   };\n\n   IMGUI_API Style& GetStyle();\n}\n"
  },
  {
    "path": "External/ImGui/imconfig.h",
    "content": "//-----------------------------------------------------------------------------\n// DEAR IMGUI COMPILE-TIME OPTIONS\n// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.\n// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.\n//-----------------------------------------------------------------------------\n// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)\n// B) or '#define IMGUI_USER_CONFIG \"my_imgui_config.h\"' in your project and then add directives in your own file without touching this template.\n//-----------------------------------------------------------------------------\n// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp\n// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.\n// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.\n// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.\n//-----------------------------------------------------------------------------\n\n#pragma once\n\n//---- Define assertion handler. Defaults to calling assert().\n// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.\n//#define IM_ASSERT(_EXPR)  MyAssert(_EXPR)\n//#define IM_ASSERT(_EXPR)  ((void)(_EXPR))     // Disable asserts\n\n//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows\n// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.\n// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()\n//   for each static/DLL boundary you are calling from. Read \"Context and Memory Allocators\" section of imgui.cpp for more details.\n//#define IMGUI_API __declspec(dllexport)                   // MSVC Windows: DLL export\n//#define IMGUI_API __declspec(dllimport)                   // MSVC Windows: DLL import\n//#define IMGUI_API __attribute__((visibility(\"default\")))  // GCC/Clang: override visibility when set is hidden\n\n//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.\n#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS\n\n//---- Disable all of Dear ImGui or don't implement standard windows/tools.\n// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.\n//#define IMGUI_DISABLE                                     // Disable everything: all headers and source files will be empty.\n//#define IMGUI_DISABLE_DEMO_WINDOWS                        // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.\n//#define IMGUI_DISABLE_DEBUG_TOOLS                         // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.\n\n//---- Don't implement some functions to reduce linkage requirements.\n//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS   // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)\n//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS          // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)\n//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS         // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)\n//#define IMGUI_DISABLE_WIN32_FUNCTIONS                     // [Win32] Won't use and link with any Win32 function (clipboard, IME).\n//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS      // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).\n//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS             // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system(\"\")).\n//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS            // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)\n//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS              // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.\n//#define IMGUI_DISABLE_FILE_FUNCTIONS                      // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)\n//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS              // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.\n//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS                  // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().\n#define IMGUI_DISABLE_DEFAULT_FONT                        // Disable default embedded font (ProggyClean.ttf), remove ~9.5 KB from output binary. AddFontDefault() will assert.\n//#define IMGUI_DISABLE_SSE                                 // Disable use of SSE intrinsics even if available\n\n//---- Enable Test Engine / Automation features.\n//#define IMGUI_ENABLE_TEST_ENGINE                          // Enable imgui_test_engine hooks. Generally set automatically by include \"imgui_te_config.h\", see Test Engine for details.\n\n//---- Include imgui_user.h at the end of imgui.h as a convenience\n// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.\n//#define IMGUI_INCLUDE_IMGUI_USER_H\n//#define IMGUI_USER_H_FILENAME         \"my_folder/my_imgui_user.h\"\n\n//---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support.\n//#define IMGUI_USE_BGRA_PACKED_COLOR\n\n//---- Use legacy CRC32-adler tables (used before 1.91.6), in order to preserve old .ini data that you cannot afford to invalidate.\n//#define IMGUI_USE_LEGACY_CRC32_ADLER\n\n//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)\n//#define IMGUI_USE_WCHAR32\n\n//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version\n// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.\n//#define IMGUI_STB_TRUETYPE_FILENAME   \"my_folder/stb_truetype.h\"\n//#define IMGUI_STB_RECT_PACK_FILENAME  \"my_folder/stb_rect_pack.h\"\n#define IMGUI_STB_SPRINTF_FILENAME    \"../stb/stb_sprintf.h\"    // only used if IMGUI_USE_STB_SPRINTF is defined.\n//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION\n//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION\n#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION                   // only disabled if IMGUI_USE_STB_SPRINTF is defined.\n\n//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)\n// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.\n#define IMGUI_USE_STB_SPRINTF\n\n//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)\n// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).\n// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.\n//#define IMGUI_ENABLE_FREETYPE\n\n//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)\n// Only works in combination with IMGUI_ENABLE_FREETYPE.\n// - lunasvg is currently easier to acquire/install, as e.g. it is part of vcpkg.\n// - plutosvg will support more fonts and may load them faster. It currently requires to be built manually but it is fairly easy. See misc/freetype/README for instructions.\n// - Both require headers to be available in the include path + program to be linked with the library code (not provided).\n// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)\n//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG\n//#define IMGUI_ENABLE_FREETYPE_LUNASVG\n\n//---- Use stb_truetype to build and rasterize the font atlas (default)\n// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.\n//#define IMGUI_ENABLE_STB_TRUETYPE\n\n//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.\n// This will be inlined as part of ImVec2 and ImVec4 class declarations.\n/*\n#define IM_VEC2_CLASS_EXTRA                                                     \\\n        constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {}                   \\\n        operator MyVec2() const { return MyVec2(x,y); }\n\n#define IM_VEC4_CLASS_EXTRA                                                     \\\n        constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {}   \\\n        operator MyVec4() const { return MyVec4(x,y,z,w); }\n*/\n//---- ...Or use Dear ImGui's own very basic math operators.\n#define IMGUI_DEFINE_MATH_OPERATORS\n\n//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.\n// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).\n// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.\n// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.\n//#define ImDrawIdx unsigned int\n\n//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)\n//struct ImDrawList;\n//struct ImDrawCmd;\n//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);\n//#define ImDrawCallback MyImDrawCallback\n\n//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)\n// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)\n//#define IM_DEBUG_BREAK  IM_ASSERT(0)\n//#define IM_DEBUG_BREAK  __debugbreak()\n\n//---- Debug Tools: Enable slower asserts\n//#define IMGUI_DEBUG_PARANOID\n\n//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)\n/*\nnamespace ImGui\n{\n    void MyFunction(const char* name, MyMatrix44* mtx);\n}\n*/\n\n//\n// Manual tracking of obsolete stuff\n//"
  },
  {
    "path": "External/concurrentqueue/blockingconcurrentqueue.h",
    "content": "// Provides an efficient blocking version of moodycamel::ConcurrentQueue.\n// ©2015-2020 Cameron Desrochers. Distributed under the terms of the simplified\n// BSD license, available at the top of concurrentqueue.h.\n// Also dual-licensed under the Boost Software License (see LICENSE.md)\n// Uses Jeff Preshing's semaphore implementation (under the terms of its\n// separate zlib license, see lightweightsemaphore.h).\n\n#pragma once\n\n#include \"concurrentqueue.h\"\n#include \"lightweightsemaphore.h\"\n\n#include <type_traits>\n#include <cerrno>\n#include <memory>\n#include <chrono>\n#include <ctime>\n\nnamespace moodycamel\n{\n// This is a blocking version of the queue. It has an almost identical interface to\n// the normal non-blocking version, with the addition of various wait_dequeue() methods\n// and the removal of producer-specific dequeue methods.\ntemplate<typename T, typename Traits = ConcurrentQueueDefaultTraits>\nclass BlockingConcurrentQueue\n{\nprivate:\n\ttypedef ::moodycamel::ConcurrentQueue<T, Traits> ConcurrentQueue;\n\ttypedef ::moodycamel::LightweightSemaphore LightweightSemaphore;\n\npublic:\n\ttypedef typename ConcurrentQueue::producer_token_t producer_token_t;\n\ttypedef typename ConcurrentQueue::consumer_token_t consumer_token_t;\n\t\n\ttypedef typename ConcurrentQueue::index_t index_t;\n\ttypedef typename ConcurrentQueue::size_t size_t;\n\ttypedef typename std::make_signed<size_t>::type ssize_t;\n\t\n\tstatic const size_t BLOCK_SIZE = ConcurrentQueue::BLOCK_SIZE;\n\tstatic const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = ConcurrentQueue::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD;\n\tstatic const size_t EXPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::EXPLICIT_INITIAL_INDEX_SIZE;\n\tstatic const size_t IMPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::IMPLICIT_INITIAL_INDEX_SIZE;\n\tstatic const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = ConcurrentQueue::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE;\n\tstatic const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = ConcurrentQueue::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE;\n\tstatic const size_t MAX_SUBQUEUE_SIZE = ConcurrentQueue::MAX_SUBQUEUE_SIZE;\n\t\npublic:\n\t// Creates a queue with at least `capacity` element slots; note that the\n\t// actual number of elements that can be inserted without additional memory\n\t// allocation depends on the number of producers and the block size (e.g. if\n\t// the block size is equal to `capacity`, only a single block will be allocated\n\t// up-front, which means only a single producer will be able to enqueue elements\n\t// without an extra allocation -- blocks aren't shared between producers).\n\t// This method is not thread safe -- it is up to the user to ensure that the\n\t// queue is fully constructed before it starts being used by other threads (this\n\t// includes making the memory effects of construction visible, possibly with a\n\t// memory barrier).\n\texplicit BlockingConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE)\n\t\t: inner(capacity), sema(create<LightweightSemaphore, ssize_t, int>(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy<LightweightSemaphore>)\n\t{\n\t\tassert(reinterpret_cast<ConcurrentQueue*>((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && \"BlockingConcurrentQueue must have ConcurrentQueue as its first member\");\n\t\tif (!sema) {\n\t\t\tMOODYCAMEL_THROW(std::bad_alloc());\n\t\t}\n\t}\n\t\n\tBlockingConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers)\n\t\t: inner(minCapacity, maxExplicitProducers, maxImplicitProducers), sema(create<LightweightSemaphore, ssize_t, int>(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy<LightweightSemaphore>)\n\t{\n\t\tassert(reinterpret_cast<ConcurrentQueue*>((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && \"BlockingConcurrentQueue must have ConcurrentQueue as its first member\");\n\t\tif (!sema) {\n\t\t\tMOODYCAMEL_THROW(std::bad_alloc());\n\t\t}\n\t}\n\t\n\t// Disable copying and copy assignment\n\tBlockingConcurrentQueue(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION;\n\tBlockingConcurrentQueue& operator=(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION;\n\t\n\t// Moving is supported, but note that it is *not* a thread-safe operation.\n\t// Nobody can use the queue while it's being moved, and the memory effects\n\t// of that move must be propagated to other threads before they can use it.\n\t// Note: When a queue is moved, its tokens are still valid but can only be\n\t// used with the destination queue (i.e. semantically they are moved along\n\t// with the queue itself).\n\tBlockingConcurrentQueue(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT\n\t\t: inner(std::move(other.inner)), sema(std::move(other.sema))\n\t{ }\n\t\n\tinline BlockingConcurrentQueue& operator=(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT\n\t{\n\t\treturn swap_internal(other);\n\t}\n\t\n\t// Swaps this queue's state with the other's. Not thread-safe.\n\t// Swapping two queues does not invalidate their tokens, however\n\t// the tokens that were created for one queue must be used with\n\t// only the swapped queue (i.e. the tokens are tied to the\n\t// queue's movable state, not the object itself).\n\tinline void swap(BlockingConcurrentQueue& other) MOODYCAMEL_NOEXCEPT\n\t{\n\t\tswap_internal(other);\n\t}\n\t\nprivate:\n\tBlockingConcurrentQueue& swap_internal(BlockingConcurrentQueue& other)\n\t{\n\t\tif (this == &other) {\n\t\t\treturn *this;\n\t\t}\n\t\t\n\t\tinner.swap(other.inner);\n\t\tsema.swap(other.sema);\n\t\treturn *this;\n\t}\n\t\npublic:\n\t// Enqueues a single item (by copying it).\n\t// Allocates memory if required. Only fails if memory allocation fails (or implicit\n\t// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0,\n\t// or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).\n\t// Thread-safe.\n\tinline bool enqueue(T const& item)\n\t{\n\t\tif ((details::likely)(inner.enqueue(item))) {\n\t\t\tsema->signal();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Enqueues a single item (by moving it, if possible).\n\t// Allocates memory if required. Only fails if memory allocation fails (or implicit\n\t// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0,\n\t// or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).\n\t// Thread-safe.\n\tinline bool enqueue(T&& item)\n\t{\n\t\tif ((details::likely)(inner.enqueue(std::move(item)))) {\n\t\t\tsema->signal();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Enqueues a single item (by copying it) using an explicit producer token.\n\t// Allocates memory if required. Only fails if memory allocation fails (or\n\t// Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).\n\t// Thread-safe.\n\tinline bool enqueue(producer_token_t const& token, T const& item)\n\t{\n\t\tif ((details::likely)(inner.enqueue(token, item))) {\n\t\t\tsema->signal();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Enqueues a single item (by moving it, if possible) using an explicit producer token.\n\t// Allocates memory if required. Only fails if memory allocation fails (or\n\t// Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).\n\t// Thread-safe.\n\tinline bool enqueue(producer_token_t const& token, T&& item)\n\t{\n\t\tif ((details::likely)(inner.enqueue(token, std::move(item)))) {\n\t\t\tsema->signal();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Enqueues several items.\n\t// Allocates memory if required. Only fails if memory allocation fails (or\n\t// implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE\n\t// is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).\n\t// Note: Use std::make_move_iterator if the elements should be moved instead of copied.\n\t// Thread-safe.\n\ttemplate<typename It>\n\tinline bool enqueue_bulk(It itemFirst, size_t count)\n\t{\n\t\tif ((details::likely)(inner.enqueue_bulk(std::forward<It>(itemFirst), count))) {\n\t\t\tsema->signal((LightweightSemaphore::ssize_t)(ssize_t)count);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Enqueues several items using an explicit producer token.\n\t// Allocates memory if required. Only fails if memory allocation fails\n\t// (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).\n\t// Note: Use std::make_move_iterator if the elements should be moved\n\t// instead of copied.\n\t// Thread-safe.\n\ttemplate<typename It>\n\tinline bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)\n\t{\n\t\tif ((details::likely)(inner.enqueue_bulk(token, std::forward<It>(itemFirst), count))) {\n\t\t\tsema->signal((LightweightSemaphore::ssize_t)(ssize_t)count);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Enqueues a single item (by copying it).\n\t// Does not allocate memory. Fails if not enough room to enqueue (or implicit\n\t// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE\n\t// is 0).\n\t// Thread-safe.\n\tinline bool try_enqueue(T const& item)\n\t{\n\t\tif (inner.try_enqueue(item)) {\n\t\t\tsema->signal();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Enqueues a single item (by moving it, if possible).\n\t// Does not allocate memory (except for one-time implicit producer).\n\t// Fails if not enough room to enqueue (or implicit production is\n\t// disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0).\n\t// Thread-safe.\n\tinline bool try_enqueue(T&& item)\n\t{\n\t\tif (inner.try_enqueue(std::move(item))) {\n\t\t\tsema->signal();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Enqueues a single item (by copying it) using an explicit producer token.\n\t// Does not allocate memory. Fails if not enough room to enqueue.\n\t// Thread-safe.\n\tinline bool try_enqueue(producer_token_t const& token, T const& item)\n\t{\n\t\tif (inner.try_enqueue(token, item)) {\n\t\t\tsema->signal();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Enqueues a single item (by moving it, if possible) using an explicit producer token.\n\t// Does not allocate memory. Fails if not enough room to enqueue.\n\t// Thread-safe.\n\tinline bool try_enqueue(producer_token_t const& token, T&& item)\n\t{\n\t\tif (inner.try_enqueue(token, std::move(item))) {\n\t\t\tsema->signal();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Enqueues several items.\n\t// Does not allocate memory (except for one-time implicit producer).\n\t// Fails if not enough room to enqueue (or implicit production is\n\t// disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0).\n\t// Note: Use std::make_move_iterator if the elements should be moved\n\t// instead of copied.\n\t// Thread-safe.\n\ttemplate<typename It>\n\tinline bool try_enqueue_bulk(It itemFirst, size_t count)\n\t{\n\t\tif (inner.try_enqueue_bulk(std::forward<It>(itemFirst), count)) {\n\t\t\tsema->signal((LightweightSemaphore::ssize_t)(ssize_t)count);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Enqueues several items using an explicit producer token.\n\t// Does not allocate memory. Fails if not enough room to enqueue.\n\t// Note: Use std::make_move_iterator if the elements should be moved\n\t// instead of copied.\n\t// Thread-safe.\n\ttemplate<typename It>\n\tinline bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)\n\t{\n\t\tif (inner.try_enqueue_bulk(token, std::forward<It>(itemFirst), count)) {\n\t\t\tsema->signal((LightweightSemaphore::ssize_t)(ssize_t)count);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t\n\t// Attempts to dequeue from the queue.\n\t// Returns false if all producer streams appeared empty at the time they\n\t// were checked (so, the queue is likely but not guaranteed to be empty).\n\t// Never allocates. Thread-safe.\n\ttemplate<typename U>\n\tinline bool try_dequeue(U& item)\n\t{\n\t\tif (sema->tryWait()) {\n\t\t\twhile (!inner.try_dequeue(item)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Attempts to dequeue from the queue using an explicit consumer token.\n\t// Returns false if all producer streams appeared empty at the time they\n\t// were checked (so, the queue is likely but not guaranteed to be empty).\n\t// Never allocates. Thread-safe.\n\ttemplate<typename U>\n\tinline bool try_dequeue(consumer_token_t& token, U& item)\n\t{\n\t\tif (sema->tryWait()) {\n\t\t\twhile (!inner.try_dequeue(token, item)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Attempts to dequeue several elements from the queue.\n\t// Returns the number of items actually dequeued.\n\t// Returns 0 if all producer streams appeared empty at the time they\n\t// were checked (so, the queue is likely but not guaranteed to be empty).\n\t// Never allocates. Thread-safe.\n\ttemplate<typename It>\n\tinline size_t try_dequeue_bulk(It itemFirst, size_t max)\n\t{\n\t\tsize_t count = 0;\n\t\tmax = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max);\n\t\twhile (count != max) {\n\t\t\tcount += inner.template try_dequeue_bulk<It&>(itemFirst, max - count);\n\t\t}\n\t\treturn count;\n\t}\n\t\n\t// Attempts to dequeue several elements from the queue using an explicit consumer token.\n\t// Returns the number of items actually dequeued.\n\t// Returns 0 if all producer streams appeared empty at the time they\n\t// were checked (so, the queue is likely but not guaranteed to be empty).\n\t// Never allocates. Thread-safe.\n\ttemplate<typename It>\n\tinline size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max)\n\t{\n\t\tsize_t count = 0;\n\t\tmax = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max);\n\t\twhile (count != max) {\n\t\t\tcount += inner.template try_dequeue_bulk<It&>(token, itemFirst, max - count);\n\t\t}\n\t\treturn count;\n\t}\n\t\n\t\n\t\n\t// Blocks the current thread until there's something to dequeue, then\n\t// dequeues it.\n\t// Never allocates. Thread-safe.\n\ttemplate<typename U>\n\tinline void wait_dequeue(U& item)\n\t{\n\t\twhile (!sema->wait()) {\n\t\t\tcontinue;\n\t\t}\n\t\twhile (!inner.try_dequeue(item)) {\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\t// Blocks the current thread until either there's something to dequeue\n\t// or the timeout (specified in microseconds) expires. Returns false\n\t// without setting `item` if the timeout expires, otherwise assigns\n\t// to `item` and returns true.\n\t// Using a negative timeout indicates an indefinite timeout,\n\t// and is thus functionally equivalent to calling wait_dequeue.\n\t// Never allocates. Thread-safe.\n\ttemplate<typename U>\n\tinline bool wait_dequeue_timed(U& item, std::int64_t timeout_usecs)\n\t{\n\t\tif (!sema->wait(timeout_usecs)) {\n\t\t\treturn false;\n\t\t}\n\t\twhile (!inner.try_dequeue(item)) {\n\t\t\tcontinue;\n\t\t}\n\t\treturn true;\n\t}\n    \n    // Blocks the current thread until either there's something to dequeue\n\t// or the timeout expires. Returns false without setting `item` if the\n    // timeout expires, otherwise assigns to `item` and returns true.\n\t// Never allocates. Thread-safe.\n\ttemplate<typename U, typename Rep, typename Period>\n\tinline bool wait_dequeue_timed(U& item, std::chrono::duration<Rep, Period> const& timeout)\n    {\n        return wait_dequeue_timed(item, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());\n    }\n\t\n\t// Blocks the current thread until there's something to dequeue, then\n\t// dequeues it using an explicit consumer token.\n\t// Never allocates. Thread-safe.\n\ttemplate<typename U>\n\tinline void wait_dequeue(consumer_token_t& token, U& item)\n\t{\n\t\twhile (!sema->wait()) {\n\t\t\tcontinue;\n\t\t}\n\t\twhile (!inner.try_dequeue(token, item)) {\n\t\t\tcontinue;\n\t\t}\n\t}\n\t\n\t// Blocks the current thread until either there's something to dequeue\n\t// or the timeout (specified in microseconds) expires. Returns false\n\t// without setting `item` if the timeout expires, otherwise assigns\n\t// to `item` and returns true.\n\t// Using a negative timeout indicates an indefinite timeout,\n\t// and is thus functionally equivalent to calling wait_dequeue.\n\t// Never allocates. Thread-safe.\n\ttemplate<typename U>\n\tinline bool wait_dequeue_timed(consumer_token_t& token, U& item, std::int64_t timeout_usecs)\n\t{\n\t\tif (!sema->wait(timeout_usecs)) {\n\t\t\treturn false;\n\t\t}\n\t\twhile (!inner.try_dequeue(token, item)) {\n\t\t\tcontinue;\n\t\t}\n\t\treturn true;\n\t}\n    \n    // Blocks the current thread until either there's something to dequeue\n\t// or the timeout expires. Returns false without setting `item` if the\n    // timeout expires, otherwise assigns to `item` and returns true.\n\t// Never allocates. Thread-safe.\n\ttemplate<typename U, typename Rep, typename Period>\n\tinline bool wait_dequeue_timed(consumer_token_t& token, U& item, std::chrono::duration<Rep, Period> const& timeout)\n    {\n        return wait_dequeue_timed(token, item, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());\n    }\n\t\n\t// Attempts to dequeue several elements from the queue.\n\t// Returns the number of items actually dequeued, which will\n\t// always be at least one (this method blocks until the queue\n\t// is non-empty) and at most max.\n\t// Never allocates. Thread-safe.\n\ttemplate<typename It>\n\tinline size_t wait_dequeue_bulk(It itemFirst, size_t max)\n\t{\n\t\tsize_t count = 0;\n\t\tmax = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max);\n\t\twhile (count != max) {\n\t\t\tcount += inner.template try_dequeue_bulk<It&>(itemFirst, max - count);\n\t\t}\n\t\treturn count;\n\t}\n\t\n\t// Attempts to dequeue several elements from the queue.\n\t// Returns the number of items actually dequeued, which can\n\t// be 0 if the timeout expires while waiting for elements,\n\t// and at most max.\n\t// Using a negative timeout indicates an indefinite timeout,\n\t// and is thus functionally equivalent to calling wait_dequeue_bulk.\n\t// Never allocates. Thread-safe.\n\ttemplate<typename It>\n\tinline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::int64_t timeout_usecs)\n\t{\n\t\tsize_t count = 0;\n\t\tmax = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs);\n\t\twhile (count != max) {\n\t\t\tcount += inner.template try_dequeue_bulk<It&>(itemFirst, max - count);\n\t\t}\n\t\treturn count;\n\t}\n    \n    // Attempts to dequeue several elements from the queue.\n\t// Returns the number of items actually dequeued, which can\n\t// be 0 if the timeout expires while waiting for elements,\n\t// and at most max.\n\t// Never allocates. Thread-safe.\n\ttemplate<typename It, typename Rep, typename Period>\n\tinline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::chrono::duration<Rep, Period> const& timeout)\n    {\n        return wait_dequeue_bulk_timed<It&>(itemFirst, max, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());\n    }\n\t\n\t// Attempts to dequeue several elements from the queue using an explicit consumer token.\n\t// Returns the number of items actually dequeued, which will\n\t// always be at least one (this method blocks until the queue\n\t// is non-empty) and at most max.\n\t// Never allocates. Thread-safe.\n\ttemplate<typename It>\n\tinline size_t wait_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max)\n\t{\n\t\tsize_t count = 0;\n\t\tmax = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max);\n\t\twhile (count != max) {\n\t\t\tcount += inner.template try_dequeue_bulk<It&>(token, itemFirst, max - count);\n\t\t}\n\t\treturn count;\n\t}\n\t\n\t// Attempts to dequeue several elements from the queue using an explicit consumer token.\n\t// Returns the number of items actually dequeued, which can\n\t// be 0 if the timeout expires while waiting for elements,\n\t// and at most max.\n\t// Using a negative timeout indicates an indefinite timeout,\n\t// and is thus functionally equivalent to calling wait_dequeue_bulk.\n\t// Never allocates. Thread-safe.\n\ttemplate<typename It>\n\tinline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::int64_t timeout_usecs)\n\t{\n\t\tsize_t count = 0;\n\t\tmax = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs);\n\t\twhile (count != max) {\n\t\t\tcount += inner.template try_dequeue_bulk<It&>(token, itemFirst, max - count);\n\t\t}\n\t\treturn count;\n\t}\n\t\n\t// Attempts to dequeue several elements from the queue using an explicit consumer token.\n\t// Returns the number of items actually dequeued, which can\n\t// be 0 if the timeout expires while waiting for elements,\n\t// and at most max.\n\t// Never allocates. Thread-safe.\n\ttemplate<typename It, typename Rep, typename Period>\n\tinline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::chrono::duration<Rep, Period> const& timeout)\n    {\n        return wait_dequeue_bulk_timed<It&>(token, itemFirst, max, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());\n    }\n\t\n\t\n\t// Returns an estimate of the total number of elements currently in the queue. This\n\t// estimate is only accurate if the queue has completely stabilized before it is called\n\t// (i.e. all enqueue and dequeue operations have completed and their memory effects are\n\t// visible on the calling thread, and no further operations start while this method is\n\t// being called).\n\t// Thread-safe.\n\tinline size_t size_approx() const\n\t{\n\t\treturn (size_t)sema->availableApprox();\n\t}\n\t\n\t\n\t// Returns true if the underlying atomic variables used by\n\t// the queue are lock-free (they should be on most platforms).\n\t// Thread-safe.\n\tstatic constexpr bool is_lock_free()\n\t{\n\t\treturn ConcurrentQueue::is_lock_free();\n\t}\n\t\n\nprivate:\n\ttemplate<typename U, typename A1, typename A2>\n\tstatic inline U* create(A1&& a1, A2&& a2)\n\t{\n\t\tvoid* p = (Traits::malloc)(sizeof(U));\n\t\treturn p != nullptr ? new (p) U(std::forward<A1>(a1), std::forward<A2>(a2)) : nullptr;\n\t}\n\t\n\ttemplate<typename U>\n\tstatic inline void destroy(U* p)\n\t{\n\t\tif (p != nullptr) {\n\t\t\tp->~U();\n\t\t}\n\t\t(Traits::free)(p);\n\t}\n\t\nprivate:\n\tConcurrentQueue inner;\n\tstd::unique_ptr<LightweightSemaphore, void (*)(LightweightSemaphore*)> sema;\n};\n\n\ntemplate<typename T, typename Traits>\ninline void swap(BlockingConcurrentQueue<T, Traits>& a, BlockingConcurrentQueue<T, Traits>& b) MOODYCAMEL_NOEXCEPT\n{\n\ta.swap(b);\n}\n\n}\t// end namespace moodycamel\n"
  },
  {
    "path": "External/concurrentqueue/concurrentqueue.h",
    "content": "// Provides a C++11 implementation of a multi-producer, multi-consumer lock-free queue.\n// An overview, including benchmark results, is provided here:\n//     http://moodycamel.com/blog/2014/a-fast-general-purpose-lock-free-queue-for-c++\n// The full design is also described in excruciating detail at:\n//    http://moodycamel.com/blog/2014/detailed-design-of-a-lock-free-queue\n\n// Simplified BSD license:\n// Copyright (c) 2013-2020, Cameron Desrochers.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without modification,\n// are permitted provided that the following conditions are met:\n//\n// - Redistributions of source code must retain the above copyright notice, this list of\n// conditions and the following disclaimer.\n// - Redistributions in binary form must reproduce the above copyright notice, this list of\n// conditions and the following disclaimer in the documentation and/or other materials\n// provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\n// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL\n// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR\n// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n// Also dual-licensed under the Boost Software License (see LICENSE.md)\n\n#pragma once\n\n#if defined(__GNUC__) && !defined(__INTEL_COMPILER)\n// Disable -Wconversion warnings (spuriously triggered when Traits::size_t and\n// Traits::index_t are set to < 32 bits, causing integer promotion, causing warnings\n// upon assigning any computed values)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n\n#ifdef MCDBGQ_USE_RELACY\n#pragma GCC diagnostic ignored \"-Wint-to-pointer-cast\"\n#endif\n#endif\n\n#if defined(_MSC_VER) && (!defined(_HAS_CXX17) || !_HAS_CXX17)\n// VS2019 with /W4 warns about constant conditional expressions but unless /std=c++17 or higher\n// does not support `if constexpr`, so we have no choice but to simply disable the warning\n#pragma warning(push)\n#pragma warning(disable: 4127)  // conditional expression is constant\n#endif\n\n#if defined(__APPLE__)\n#include \"TargetConditionals.h\"\n#endif\n\n#ifdef MCDBGQ_USE_RELACY\n#include \"relacy/relacy_std.hpp\"\n#include \"relacy_shims.h\"\n// We only use malloc/free anyway, and the delete macro messes up `= delete` method declarations.\n// We'll override the default trait malloc ourselves without a macro.\n#undef new\n#undef delete\n#undef malloc\n#undef free\n#else\n#include <atomic>\t\t// Requires C++11. Sorry VS2010.\n#include <cassert>\n#endif\n#include <cstddef>              // for max_align_t\n#include <cstdint>\n#include <cstdlib>\n#include <type_traits>\n#include <algorithm>\n#include <utility>\n#include <limits>\n#include <climits>\t\t// for CHAR_BIT\n#include <array>\n#include <thread>\t\t// partly for __WINPTHREADS_VERSION if on MinGW-w64 w/ POSIX threading\n#include <mutex>        // used for thread exit synchronization\n\n// Platform-specific definitions of a numeric thread ID type and an invalid value\nnamespace moodycamel { namespace details {\n\ttemplate<typename thread_id_t> struct thread_id_converter {\n\t\ttypedef thread_id_t thread_id_numeric_size_t;\n\t\ttypedef thread_id_t thread_id_hash_t;\n\t\tstatic thread_id_hash_t prehash(thread_id_t const& x) { return x; }\n\t};\n} }\n#if defined(MCDBGQ_USE_RELACY)\nnamespace moodycamel { namespace details {\n\ttypedef std::uint32_t thread_id_t;\n\tstatic const thread_id_t invalid_thread_id  = 0xFFFFFFFFU;\n\tstatic const thread_id_t invalid_thread_id2 = 0xFFFFFFFEU;\n\tstatic inline thread_id_t thread_id() { return rl::thread_index(); }\n} }\n#elif defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__)\n// No sense pulling in windows.h in a header, we'll manually declare the function\n// we use and rely on backwards-compatibility for this not to break\nextern \"C\" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(void);\nnamespace moodycamel { namespace details {\n\tstatic_assert(sizeof(unsigned long) == sizeof(std::uint32_t), \"Expected size of unsigned long to be 32 bits on Windows\");\n\ttypedef std::uint32_t thread_id_t;\n\tstatic const thread_id_t invalid_thread_id  = 0;\t\t\t// See http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx\n\tstatic const thread_id_t invalid_thread_id2 = 0xFFFFFFFFU;\t// Not technically guaranteed to be invalid, but is never used in practice. Note that all Win32 thread IDs are presently multiples of 4.\n\tstatic inline thread_id_t thread_id() { return static_cast<thread_id_t>(::GetCurrentThreadId()); }\n} }\n#elif defined(__arm__) || defined(_M_ARM) || defined(__aarch64__) || (defined(__APPLE__) && TARGET_OS_IPHONE) || defined(MOODYCAMEL_NO_THREAD_LOCAL)\nnamespace moodycamel { namespace details {\n\tstatic_assert(sizeof(std::thread::id) == 4 || sizeof(std::thread::id) == 8, \"std::thread::id is expected to be either 4 or 8 bytes\");\n\t\n\ttypedef std::thread::id thread_id_t;\n\tstatic const thread_id_t invalid_thread_id;         // Default ctor creates invalid ID\n\n\t// Note we don't define a invalid_thread_id2 since std::thread::id doesn't have one; it's\n\t// only used if MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is defined anyway, which it won't\n\t// be.\n\tstatic inline thread_id_t thread_id() { return std::this_thread::get_id(); }\n\n\ttemplate<std::size_t> struct thread_id_size { };\n\ttemplate<> struct thread_id_size<4> { typedef std::uint32_t numeric_t; };\n\ttemplate<> struct thread_id_size<8> { typedef std::uint64_t numeric_t; };\n\n\ttemplate<> struct thread_id_converter<thread_id_t> {\n\t\ttypedef thread_id_size<sizeof(thread_id_t)>::numeric_t thread_id_numeric_size_t;\n#ifndef __APPLE__\n\t\ttypedef std::size_t thread_id_hash_t;\n#else\n\t\ttypedef thread_id_numeric_size_t thread_id_hash_t;\n#endif\n\n\t\tstatic thread_id_hash_t prehash(thread_id_t const& x)\n\t\t{\n#ifndef __APPLE__\n\t\t\treturn std::hash<std::thread::id>()(x);\n#else\n\t\t\treturn *reinterpret_cast<thread_id_hash_t const*>(&x);\n#endif\n\t\t}\n\t};\n} }\n#else\n// Use a nice trick from this answer: http://stackoverflow.com/a/8438730/21475\n// In order to get a numeric thread ID in a platform-independent way, we use a thread-local\n// static variable's address as a thread identifier :-)\n#if defined(__GNUC__) || defined(__INTEL_COMPILER)\n#define MOODYCAMEL_THREADLOCAL __thread\n#elif defined(_MSC_VER)\n#define MOODYCAMEL_THREADLOCAL __declspec(thread)\n#else\n// Assume C++11 compliant compiler\n#define MOODYCAMEL_THREADLOCAL thread_local\n#endif\nnamespace moodycamel { namespace details {\n\ttypedef std::uintptr_t thread_id_t;\n\tstatic const thread_id_t invalid_thread_id  = 0;\t\t// Address can't be nullptr\n\tstatic const thread_id_t invalid_thread_id2 = 1;\t\t// Member accesses off a null pointer are also generally invalid. Plus it's not aligned.\n\tinline thread_id_t thread_id() { static MOODYCAMEL_THREADLOCAL int x; return reinterpret_cast<thread_id_t>(&x); }\n} }\n#endif\n\n// Constexpr if\n#ifndef MOODYCAMEL_CONSTEXPR_IF\n#if (defined(_MSC_VER) && defined(_HAS_CXX17) && _HAS_CXX17) || __cplusplus > 201402L\n#define MOODYCAMEL_CONSTEXPR_IF if constexpr\n#define MOODYCAMEL_MAYBE_UNUSED [[maybe_unused]]\n#else\n#define MOODYCAMEL_CONSTEXPR_IF if\n#define MOODYCAMEL_MAYBE_UNUSED\n#endif\n#endif\n\n// Exceptions\n#ifndef MOODYCAMEL_EXCEPTIONS_ENABLED\n#if (defined(_MSC_VER) && defined(_CPPUNWIND)) || (defined(__GNUC__) && defined(__EXCEPTIONS)) || (!defined(_MSC_VER) && !defined(__GNUC__))\n#define MOODYCAMEL_EXCEPTIONS_ENABLED\n#endif\n#endif\n#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED\n#define MOODYCAMEL_TRY try\n#define MOODYCAMEL_CATCH(...) catch(__VA_ARGS__)\n#define MOODYCAMEL_RETHROW throw\n#define MOODYCAMEL_THROW(expr) throw (expr)\n#else\n#define MOODYCAMEL_TRY MOODYCAMEL_CONSTEXPR_IF (true)\n#define MOODYCAMEL_CATCH(...) else MOODYCAMEL_CONSTEXPR_IF (false)\n#define MOODYCAMEL_RETHROW\n#define MOODYCAMEL_THROW(expr)\n#endif\n\n#ifndef MOODYCAMEL_NOEXCEPT\n#if !defined(MOODYCAMEL_EXCEPTIONS_ENABLED)\n#define MOODYCAMEL_NOEXCEPT\n#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) true\n#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) true\n#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1800\n// VS2012's std::is_nothrow_[move_]constructible is broken and returns true when it shouldn't :-(\n// We have to assume *all* non-trivial constructors may throw on VS2012!\n#define MOODYCAMEL_NOEXCEPT _NOEXCEPT\n#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference<valueType>::value && std::is_move_constructible<type>::value ? std::is_trivially_move_constructible<type>::value : std::is_trivially_copy_constructible<type>::value)\n#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference<valueType>::value && std::is_move_assignable<type>::value ? std::is_trivially_move_assignable<type>::value || std::is_nothrow_move_assignable<type>::value : std::is_trivially_copy_assignable<type>::value || std::is_nothrow_copy_assignable<type>::value) && MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr))\n#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1900\n#define MOODYCAMEL_NOEXCEPT _NOEXCEPT\n#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference<valueType>::value && std::is_move_constructible<type>::value ? std::is_trivially_move_constructible<type>::value || std::is_nothrow_move_constructible<type>::value : std::is_trivially_copy_constructible<type>::value || std::is_nothrow_copy_constructible<type>::value)\n#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference<valueType>::value && std::is_move_assignable<type>::value ? std::is_trivially_move_assignable<type>::value || std::is_nothrow_move_assignable<type>::value : std::is_trivially_copy_assignable<type>::value || std::is_nothrow_copy_assignable<type>::value) && MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr))\n#else\n#define MOODYCAMEL_NOEXCEPT noexcept\n#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) noexcept(expr)\n#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) noexcept(expr)\n#endif\n#endif\n\n#ifndef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED\n#ifdef MCDBGQ_USE_RELACY\n#define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED\n#else\n// VS2013 doesn't support `thread_local`, and MinGW-w64 w/ POSIX threading has a crippling bug: http://sourceforge.net/p/mingw-w64/bugs/445\n// g++ <=4.7 doesn't support thread_local either.\n// Finally, iOS/ARM doesn't have support for it either, and g++/ARM allows it to compile but it's unconfirmed to actually work\n#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && (!defined(__MINGW32__) && !defined(__MINGW64__) || !defined(__WINPTHREADS_VERSION)) && (!defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) && (!defined(__APPLE__) || !TARGET_OS_IPHONE) && !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__)\n// Assume `thread_local` is fully supported in all other C++11 compilers/platforms\n#define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED    // tentatively enabled for now; years ago several users report having problems with it on\n#endif\n#endif\n#endif\n\n// VS2012 doesn't support deleted functions. \n// In this case, we declare the function normally but don't define it. A link error will be generated if the function is called.\n#ifndef MOODYCAMEL_DELETE_FUNCTION\n#if defined(_MSC_VER) && _MSC_VER < 1800\n#define MOODYCAMEL_DELETE_FUNCTION\n#else\n#define MOODYCAMEL_DELETE_FUNCTION = delete\n#endif\n#endif\n\nnamespace moodycamel { namespace details {\n#ifndef MOODYCAMEL_ALIGNAS\n// VS2013 doesn't support alignas or alignof, and align() requires a constant literal\n#if defined(_MSC_VER) && _MSC_VER <= 1800\n#define MOODYCAMEL_ALIGNAS(alignment) __declspec(align(alignment))\n#define MOODYCAMEL_ALIGNOF(obj) __alignof(obj)\n#define MOODYCAMEL_ALIGNED_TYPE_LIKE(T, obj) typename details::Vs2013Aligned<std::alignment_of<obj>::value, T>::type\n\ttemplate<int Align, typename T> struct Vs2013Aligned { };  // default, unsupported alignment\n\ttemplate<typename T> struct Vs2013Aligned<1, T> { typedef __declspec(align(1)) T type; };\n\ttemplate<typename T> struct Vs2013Aligned<2, T> { typedef __declspec(align(2)) T type; };\n\ttemplate<typename T> struct Vs2013Aligned<4, T> { typedef __declspec(align(4)) T type; };\n\ttemplate<typename T> struct Vs2013Aligned<8, T> { typedef __declspec(align(8)) T type; };\n\ttemplate<typename T> struct Vs2013Aligned<16, T> { typedef __declspec(align(16)) T type; };\n\ttemplate<typename T> struct Vs2013Aligned<32, T> { typedef __declspec(align(32)) T type; };\n\ttemplate<typename T> struct Vs2013Aligned<64, T> { typedef __declspec(align(64)) T type; };\n\ttemplate<typename T> struct Vs2013Aligned<128, T> { typedef __declspec(align(128)) T type; };\n\ttemplate<typename T> struct Vs2013Aligned<256, T> { typedef __declspec(align(256)) T type; };\n#else\n\ttemplate<typename T> struct identity { typedef T type; };\n#define MOODYCAMEL_ALIGNAS(alignment) alignas(alignment)\n#define MOODYCAMEL_ALIGNOF(obj) alignof(obj)\n#define MOODYCAMEL_ALIGNED_TYPE_LIKE(T, obj) alignas(alignof(obj)) typename details::identity<T>::type\n#endif\n#endif\n} }\n\n\n// TSAN can false report races in lock-free code.  To enable TSAN to be used from projects that use this one,\n// we can apply per-function compile-time suppression.\n// See https://clang.llvm.org/docs/ThreadSanitizer.html#has-feature-thread-sanitizer\n#define MOODYCAMEL_NO_TSAN\n#if defined(__has_feature)\n #if __has_feature(thread_sanitizer)\n  #undef MOODYCAMEL_NO_TSAN\n  #define MOODYCAMEL_NO_TSAN __attribute__((no_sanitize(\"thread\")))\n #endif // TSAN\n#endif // TSAN\n\n// Compiler-specific likely/unlikely hints\nnamespace moodycamel { namespace details {\n#if defined(__GNUC__)\n\tstatic inline bool (likely)(bool x) { return __builtin_expect((x), true); }\n\tstatic inline bool (unlikely)(bool x) { return __builtin_expect((x), false); }\n#else\n\tstatic inline bool (likely)(bool x) { return x; }\n\tstatic inline bool (unlikely)(bool x) { return x; }\n#endif\n} }\n\n#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG\n#include \"internal/concurrentqueue_internal_debug.h\"\n#endif\n\nnamespace moodycamel {\nnamespace details {\n\ttemplate<typename T>\n\tstruct const_numeric_max {\n\t\tstatic_assert(std::is_integral<T>::value, \"const_numeric_max can only be used with integers\");\n\t\tstatic const T value = std::numeric_limits<T>::is_signed\n\t\t\t? (static_cast<T>(1) << (sizeof(T) * CHAR_BIT - 1)) - static_cast<T>(1)\n\t\t\t: static_cast<T>(-1);\n\t};\n\n#if defined(__GLIBCXX__)\n\ttypedef ::max_align_t std_max_align_t;      // libstdc++ forgot to add it to std:: for a while\n#else\n\ttypedef std::max_align_t std_max_align_t;   // Others (e.g. MSVC) insist it can *only* be accessed via std::\n#endif\n\n\t// Some platforms have incorrectly set max_align_t to a type with <8 bytes alignment even while supporting\n\t// 8-byte aligned scalar values (*cough* 32-bit iOS). Work around this with our own union. See issue #64.\n\ttypedef union {\n\t\tstd_max_align_t x;\n\t\tlong long y;\n\t\tvoid* z;\n\t} max_align_t;\n}\n\n// Default traits for the ConcurrentQueue. To change some of the\n// traits without re-implementing all of them, inherit from this\n// struct and shadow the declarations you wish to be different;\n// since the traits are used as a template type parameter, the\n// shadowed declarations will be used where defined, and the defaults\n// otherwise.\nstruct ConcurrentQueueDefaultTraits\n{\n\t// General-purpose size type. std::size_t is strongly recommended.\n\ttypedef std::size_t size_t;\n\t\n\t// The type used for the enqueue and dequeue indices. Must be at least as\n\t// large as size_t. Should be significantly larger than the number of elements\n\t// you expect to hold at once, especially if you have a high turnover rate;\n\t// for example, on 32-bit x86, if you expect to have over a hundred million\n\t// elements or pump several million elements through your queue in a very\n\t// short space of time, using a 32-bit type *may* trigger a race condition.\n\t// A 64-bit int type is recommended in that case, and in practice will\n\t// prevent a race condition no matter the usage of the queue. Note that\n\t// whether the queue is lock-free with a 64-int type depends on the whether\n\t// std::atomic<std::uint64_t> is lock-free, which is platform-specific.\n\ttypedef std::size_t index_t;\n\t\n\t// Internally, all elements are enqueued and dequeued from multi-element\n\t// blocks; this is the smallest controllable unit. If you expect few elements\n\t// but many producers, a smaller block size should be favoured. For few producers\n\t// and/or many elements, a larger block size is preferred. A sane default\n\t// is provided. Must be a power of 2.\n\tstatic const size_t BLOCK_SIZE = 32;\n\t\n\t// For explicit producers (i.e. when using a producer token), the block is\n\t// checked for being empty by iterating through a list of flags, one per element.\n\t// For large block sizes, this is too inefficient, and switching to an atomic\n\t// counter-based approach is faster. The switch is made for block sizes strictly\n\t// larger than this threshold.\n\tstatic const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = 32;\n\t\n\t// How many full blocks can be expected for a single explicit producer? This should\n\t// reflect that number's maximum for optimal performance. Must be a power of 2.\n\tstatic const size_t EXPLICIT_INITIAL_INDEX_SIZE = 32;\n\t\n\t// How many full blocks can be expected for a single implicit producer? This should\n\t// reflect that number's maximum for optimal performance. Must be a power of 2.\n\tstatic const size_t IMPLICIT_INITIAL_INDEX_SIZE = 32;\n\t\n\t// The initial size of the hash table mapping thread IDs to implicit producers.\n\t// Note that the hash is resized every time it becomes half full.\n\t// Must be a power of two, and either 0 or at least 1. If 0, implicit production\n\t// (using the enqueue methods without an explicit producer token) is disabled.\n\tstatic const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = 32;\n\t\n\t// Controls the number of items that an explicit consumer (i.e. one with a token)\n\t// must consume before it causes all consumers to rotate and move on to the next\n\t// internal queue.\n\tstatic const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = 256;\n\t\n\t// The maximum number of elements (inclusive) that can be enqueued to a sub-queue.\n\t// Enqueue operations that would cause this limit to be surpassed will fail. Note\n\t// that this limit is enforced at the block level (for performance reasons), i.e.\n\t// it's rounded up to the nearest block size.\n\tstatic const size_t MAX_SUBQUEUE_SIZE = details::const_numeric_max<size_t>::value;\n\n\t// The number of times to spin before sleeping when waiting on a semaphore.\n\t// Recommended values are on the order of 1000-10000 unless the number of\n\t// consumer threads exceeds the number of idle cores (in which case try 0-100).\n\t// Only affects instances of the BlockingConcurrentQueue.\n\tstatic const int MAX_SEMA_SPINS = 10000;\n\n\t// Whether to recycle dynamically-allocated blocks into an internal free list or\n\t// not. If false, only pre-allocated blocks (controlled by the constructor\n\t// arguments) will be recycled, and all others will be `free`d back to the heap.\n\t// Note that blocks consumed by explicit producers are only freed on destruction\n\t// of the queue (not following destruction of the token) regardless of this trait.\n\tstatic const bool RECYCLE_ALLOCATED_BLOCKS = false;\n\n\t\n#ifndef MCDBGQ_USE_RELACY\n\t// Memory allocation can be customized if needed.\n\t// malloc should return nullptr on failure, and handle alignment like std::malloc.\n#if defined(malloc) || defined(free)\n\t// Gah, this is 2015, stop defining macros that break standard code already!\n\t// Work around malloc/free being special macros:\n\tstatic inline void* WORKAROUND_malloc(size_t size) { return malloc(size); }\n\tstatic inline void WORKAROUND_free(void* ptr) { return free(ptr); }\n\tstatic inline void* (malloc)(size_t size) { return WORKAROUND_malloc(size); }\n\tstatic inline void (free)(void* ptr) { return WORKAROUND_free(ptr); }\n#else\n\tstatic inline void* malloc(size_t size) { return std::malloc(size); }\n\tstatic inline void free(void* ptr) { return std::free(ptr); }\n#endif\n#else\n\t// Debug versions when running under the Relacy race detector (ignore\n\t// these in user code)\n\tstatic inline void* malloc(size_t size) { return rl::rl_malloc(size, $); }\n\tstatic inline void free(void* ptr) { return rl::rl_free(ptr, $); }\n#endif\n};\n\n\n// When producing or consuming many elements, the most efficient way is to:\n//    1) Use one of the bulk-operation methods of the queue with a token\n//    2) Failing that, use the bulk-operation methods without a token\n//    3) Failing that, create a token and use that with the single-item methods\n//    4) Failing that, use the single-parameter methods of the queue\n// Having said that, don't create tokens willy-nilly -- ideally there should be\n// a maximum of one token per thread (of each kind).\nstruct ProducerToken;\nstruct ConsumerToken;\n\ntemplate<typename T, typename Traits> class ConcurrentQueue;\ntemplate<typename T, typename Traits> class BlockingConcurrentQueue;\nclass ConcurrentQueueTests;\n\n\nnamespace details\n{\n\tstruct ConcurrentQueueProducerTypelessBase\n\t{\n\t\tConcurrentQueueProducerTypelessBase* next;\n\t\tstd::atomic<bool> inactive;\n\t\tProducerToken* token;\n\t\t\n\t\tConcurrentQueueProducerTypelessBase()\n\t\t\t: next(nullptr), inactive(false), token(nullptr)\n\t\t{\n\t\t}\n\t};\n\t\n\ttemplate<bool use32> struct _hash_32_or_64 {\n\t\tstatic inline std::uint32_t hash(std::uint32_t h)\n\t\t{\n\t\t\t// MurmurHash3 finalizer -- see https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp\n\t\t\t// Since the thread ID is already unique, all we really want to do is propagate that\n\t\t\t// uniqueness evenly across all the bits, so that we can use a subset of the bits while\n\t\t\t// reducing collisions significantly\n\t\t\th ^= h >> 16;\n\t\t\th *= 0x85ebca6b;\n\t\t\th ^= h >> 13;\n\t\t\th *= 0xc2b2ae35;\n\t\t\treturn h ^ (h >> 16);\n\t\t}\n\t};\n\ttemplate<> struct _hash_32_or_64<1> {\n\t\tstatic inline std::uint64_t hash(std::uint64_t h)\n\t\t{\n\t\t\th ^= h >> 33;\n\t\t\th *= 0xff51afd7ed558ccd;\n\t\t\th ^= h >> 33;\n\t\t\th *= 0xc4ceb9fe1a85ec53;\n\t\t\treturn h ^ (h >> 33);\n\t\t}\n\t};\n\ttemplate<std::size_t size> struct hash_32_or_64 : public _hash_32_or_64<(size > 4)> {  };\n\t\n\tstatic inline size_t hash_thread_id(thread_id_t id)\n\t{\n\t\tstatic_assert(sizeof(thread_id_t) <= 8, \"Expected a platform where thread IDs are at most 64-bit values\");\n\t\treturn static_cast<size_t>(hash_32_or_64<sizeof(thread_id_converter<thread_id_t>::thread_id_hash_t)>::hash(\n\t\t\tthread_id_converter<thread_id_t>::prehash(id)));\n\t}\n\t\n\ttemplate<typename T>\n\tstatic inline bool circular_less_than(T a, T b)\n\t{\n\t\tstatic_assert(std::is_integral<T>::value && !std::numeric_limits<T>::is_signed, \"circular_less_than is intended to be used only with unsigned integer types\");\n\t\treturn static_cast<T>(a - b) > static_cast<T>(static_cast<T>(1) << (static_cast<T>(sizeof(T) * CHAR_BIT - 1)));\n\t\t// Note: extra parens around rhs of operator<< is MSVC bug: https://developercommunity2.visualstudio.com/t/C4554-triggers-when-both-lhs-and-rhs-is/10034931\n\t\t//       silencing the bug requires #pragma warning(disable: 4554) around the calling code and has no effect when done here.\n\t}\n\t\n\ttemplate<typename U>\n\tstatic inline char* align_for(char* ptr)\n\t{\n\t\tconst std::size_t alignment = std::alignment_of<U>::value;\n\t\treturn ptr + (alignment - (reinterpret_cast<std::uintptr_t>(ptr) % alignment)) % alignment;\n\t}\n\n\ttemplate<typename T>\n\tstatic inline T ceil_to_pow_2(T x)\n\t{\n\t\tstatic_assert(std::is_integral<T>::value && !std::numeric_limits<T>::is_signed, \"ceil_to_pow_2 is intended to be used only with unsigned integer types\");\n\n\t\t// Adapted from http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2\n\t\t--x;\n\t\tx |= x >> 1;\n\t\tx |= x >> 2;\n\t\tx |= x >> 4;\n\t\tfor (std::size_t i = 1; i < sizeof(T); i <<= 1) {\n\t\t\tx |= x >> (i << 3);\n\t\t}\n\t\t++x;\n\t\treturn x;\n\t}\n\t\n\ttemplate<typename T>\n\tstatic inline void swap_relaxed(std::atomic<T>& left, std::atomic<T>& right)\n\t{\n\t\tT temp = std::move(left.load(std::memory_order_relaxed));\n\t\tleft.store(std::move(right.load(std::memory_order_relaxed)), std::memory_order_relaxed);\n\t\tright.store(std::move(temp), std::memory_order_relaxed);\n\t}\n\t\n\ttemplate<typename T>\n\tstatic inline T const& nomove(T const& x)\n\t{\n\t\treturn x;\n\t}\n\t\n\ttemplate<bool Enable>\n\tstruct nomove_if\n\t{\n\t\ttemplate<typename T>\n\t\tstatic inline T const& eval(T const& x)\n\t\t{\n\t\t\treturn x;\n\t\t}\n\t};\n\t\n\ttemplate<>\n\tstruct nomove_if<false>\n\t{\n\t\ttemplate<typename U>\n\t\tstatic inline auto eval(U&& x)\n\t\t\t-> decltype(std::forward<U>(x))\n\t\t{\n\t\t\treturn std::forward<U>(x);\n\t\t}\n\t};\n\t\n\ttemplate<typename It>\n\tstatic inline auto deref_noexcept(It& it) MOODYCAMEL_NOEXCEPT -> decltype(*it)\n\t{\n\t\treturn *it;\n\t}\n\t\n#if defined(__clang__) || !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)\n\ttemplate<typename T> struct is_trivially_destructible : std::is_trivially_destructible<T> { };\n#else\n\ttemplate<typename T> struct is_trivially_destructible : std::has_trivial_destructor<T> { };\n#endif\n\t\n#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED\n#ifdef MCDBGQ_USE_RELACY\n\ttypedef RelacyThreadExitListener ThreadExitListener;\n\ttypedef RelacyThreadExitNotifier ThreadExitNotifier;\n#else\n\tclass ThreadExitNotifier;\n\n\tstruct ThreadExitListener\n\t{\n\t\ttypedef void (*callback_t)(void*);\n\t\tcallback_t callback;\n\t\tvoid* userData;\n\t\t\n\t\tThreadExitListener* next;\t\t// reserved for use by the ThreadExitNotifier\n\t\tThreadExitNotifier* chain;\t\t// reserved for use by the ThreadExitNotifier\n\t};\n\n\tclass ThreadExitNotifier\n\t{\n\tpublic:\n\t\tstatic void subscribe(ThreadExitListener* listener)\n\t\t{\n\t\t\tauto& tlsInst = instance();\n\t\t\tstd::lock_guard<std::mutex> guard(mutex());\n\t\t\tlistener->next = tlsInst.tail;\n\t\t\tlistener->chain = &tlsInst;\n\t\t\ttlsInst.tail = listener;\n\t\t}\n\t\t\n\t\tstatic void unsubscribe(ThreadExitListener* listener)\n\t\t{\n\t\t\tstd::lock_guard<std::mutex> guard(mutex());\n\t\t\tif (!listener->chain) {\n\t\t\t\treturn;  // race with ~ThreadExitNotifier\n\t\t\t}\n\t\t\tauto& tlsInst = *listener->chain;\n\t\t\tlistener->chain = nullptr;\n\t\t\tThreadExitListener** prev = &tlsInst.tail;\n\t\t\tfor (auto ptr = tlsInst.tail; ptr != nullptr; ptr = ptr->next) {\n\t\t\t\tif (ptr == listener) {\n\t\t\t\t\t*prev = ptr->next;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tprev = &ptr->next;\n\t\t\t}\n\t\t}\n\t\t\n\tprivate:\n\t\tThreadExitNotifier() : tail(nullptr) { }\n\t\tThreadExitNotifier(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION;\n\t\tThreadExitNotifier& operator=(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION;\n\t\t\n\t\t~ThreadExitNotifier()\n\t\t{\n\t\t\t// This thread is about to exit, let everyone know!\n\t\t\tassert(this == &instance() && \"If this assert fails, you likely have a buggy compiler! Change the preprocessor conditions such that MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is no longer defined.\");\n\t\t\tstd::lock_guard<std::mutex> guard(mutex());\n\t\t\tfor (auto ptr = tail; ptr != nullptr; ptr = ptr->next) {\n\t\t\t\tptr->chain = nullptr;\n\t\t\t\tptr->callback(ptr->userData);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Thread-local\n\t\tstatic inline ThreadExitNotifier& instance()\n\t\t{\n\t\t\tstatic thread_local ThreadExitNotifier notifier;\n\t\t\treturn notifier;\n\t\t}\n\n\t\tstatic inline std::mutex& mutex()\n\t\t{\n\t\t\t// Must be static because the ThreadExitNotifier could be destroyed while unsubscribe is called\n\t\t\tstatic std::mutex mutex;\n\t\t\treturn mutex;\n\t\t}\n\t\t\n\tprivate:\n\t\tThreadExitListener* tail;\n\t};\n#endif\n#endif\n\t\n\ttemplate<typename T> struct static_is_lock_free_num { enum { value = 0 }; };\n\ttemplate<> struct static_is_lock_free_num<signed char> { enum { value = ATOMIC_CHAR_LOCK_FREE }; };\n\ttemplate<> struct static_is_lock_free_num<short> { enum { value = ATOMIC_SHORT_LOCK_FREE }; };\n\ttemplate<> struct static_is_lock_free_num<int> { enum { value = ATOMIC_INT_LOCK_FREE }; };\n\ttemplate<> struct static_is_lock_free_num<long> { enum { value = ATOMIC_LONG_LOCK_FREE }; };\n\ttemplate<> struct static_is_lock_free_num<long long> { enum { value = ATOMIC_LLONG_LOCK_FREE }; };\n\ttemplate<typename T> struct static_is_lock_free : static_is_lock_free_num<typename std::make_signed<T>::type> {  };\n\ttemplate<> struct static_is_lock_free<bool> { enum { value = ATOMIC_BOOL_LOCK_FREE }; };\n\ttemplate<typename U> struct static_is_lock_free<U*> { enum { value = ATOMIC_POINTER_LOCK_FREE }; };\n}\n\n\nstruct ProducerToken\n{\n\ttemplate<typename T, typename Traits>\n\texplicit ProducerToken(ConcurrentQueue<T, Traits>& queue);\n\t\n\ttemplate<typename T, typename Traits>\n\texplicit ProducerToken(BlockingConcurrentQueue<T, Traits>& queue);\n\t\n\tProducerToken(ProducerToken&& other) MOODYCAMEL_NOEXCEPT\n\t\t: producer(other.producer)\n\t{\n\t\tother.producer = nullptr;\n\t\tif (producer != nullptr) {\n\t\t\tproducer->token = this;\n\t\t}\n\t}\n\t\n\tinline ProducerToken& operator=(ProducerToken&& other) MOODYCAMEL_NOEXCEPT\n\t{\n\t\tswap(other);\n\t\treturn *this;\n\t}\n\t\n\tvoid swap(ProducerToken& other) MOODYCAMEL_NOEXCEPT\n\t{\n\t\tstd::swap(producer, other.producer);\n\t\tif (producer != nullptr) {\n\t\t\tproducer->token = this;\n\t\t}\n\t\tif (other.producer != nullptr) {\n\t\t\tother.producer->token = &other;\n\t\t}\n\t}\n\t\n\t// A token is always valid unless:\n\t//     1) Memory allocation failed during construction\n\t//     2) It was moved via the move constructor\n\t//        (Note: assignment does a swap, leaving both potentially valid)\n\t//     3) The associated queue was destroyed\n\t// Note that if valid() returns true, that only indicates\n\t// that the token is valid for use with a specific queue,\n\t// but not which one; that's up to the user to track.\n\tinline bool valid() const { return producer != nullptr; }\n\t\n\t~ProducerToken()\n\t{\n\t\tif (producer != nullptr) {\n\t\t\tproducer->token = nullptr;\n\t\t\tproducer->inactive.store(true, std::memory_order_release);\n\t\t}\n\t}\n\t\n\t// Disable copying and assignment\n\tProducerToken(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION;\n\tProducerToken& operator=(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION;\n\t\nprivate:\n\ttemplate<typename T, typename Traits> friend class ConcurrentQueue;\n\tfriend class ConcurrentQueueTests;\n\t\nprotected:\n\tdetails::ConcurrentQueueProducerTypelessBase* producer;\n};\n\n\nstruct ConsumerToken\n{\n\ttemplate<typename T, typename Traits>\n\texplicit ConsumerToken(ConcurrentQueue<T, Traits>& q);\n\t\n\ttemplate<typename T, typename Traits>\n\texplicit ConsumerToken(BlockingConcurrentQueue<T, Traits>& q);\n\t\n\tConsumerToken(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT\n\t\t: initialOffset(other.initialOffset), lastKnownGlobalOffset(other.lastKnownGlobalOffset), itemsConsumedFromCurrent(other.itemsConsumedFromCurrent), currentProducer(other.currentProducer), desiredProducer(other.desiredProducer)\n\t{\n\t}\n\t\n\tinline ConsumerToken& operator=(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT\n\t{\n\t\tswap(other);\n\t\treturn *this;\n\t}\n\t\n\tvoid swap(ConsumerToken& other) MOODYCAMEL_NOEXCEPT\n\t{\n\t\tstd::swap(initialOffset, other.initialOffset);\n\t\tstd::swap(lastKnownGlobalOffset, other.lastKnownGlobalOffset);\n\t\tstd::swap(itemsConsumedFromCurrent, other.itemsConsumedFromCurrent);\n\t\tstd::swap(currentProducer, other.currentProducer);\n\t\tstd::swap(desiredProducer, other.desiredProducer);\n\t}\n\t\n\t// Disable copying and assignment\n\tConsumerToken(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION;\n\tConsumerToken& operator=(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION;\n\nprivate:\n\ttemplate<typename T, typename Traits> friend class ConcurrentQueue;\n\tfriend class ConcurrentQueueTests;\n\t\nprivate: // but shared with ConcurrentQueue\n\tstd::uint32_t initialOffset;\n\tstd::uint32_t lastKnownGlobalOffset;\n\tstd::uint32_t itemsConsumedFromCurrent;\n\tdetails::ConcurrentQueueProducerTypelessBase* currentProducer;\n\tdetails::ConcurrentQueueProducerTypelessBase* desiredProducer;\n};\n\n// Need to forward-declare this swap because it's in a namespace.\n// See http://stackoverflow.com/questions/4492062/why-does-a-c-friend-class-need-a-forward-declaration-only-in-other-namespaces\ntemplate<typename T, typename Traits>\ninline void swap(typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP& a, typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT;\n\n\ntemplate<typename T, typename Traits = ConcurrentQueueDefaultTraits>\nclass ConcurrentQueue\n{\npublic:\n\ttypedef ::moodycamel::ProducerToken producer_token_t;\n\ttypedef ::moodycamel::ConsumerToken consumer_token_t;\n\t\n\ttypedef typename Traits::index_t index_t;\n\ttypedef typename Traits::size_t size_t;\n\t\n\tstatic const size_t BLOCK_SIZE = static_cast<size_t>(Traits::BLOCK_SIZE);\n\tstatic const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = static_cast<size_t>(Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD);\n\tstatic const size_t EXPLICIT_INITIAL_INDEX_SIZE = static_cast<size_t>(Traits::EXPLICIT_INITIAL_INDEX_SIZE);\n\tstatic const size_t IMPLICIT_INITIAL_INDEX_SIZE = static_cast<size_t>(Traits::IMPLICIT_INITIAL_INDEX_SIZE);\n\tstatic const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = static_cast<size_t>(Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE);\n\tstatic const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = static_cast<std::uint32_t>(Traits::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE);\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable: 4307)\t\t// + integral constant overflow (that's what the ternary expression is for!)\n#pragma warning(disable: 4309)\t\t// static_cast: Truncation of constant value\n#endif\n\tstatic const size_t MAX_SUBQUEUE_SIZE = (details::const_numeric_max<size_t>::value - static_cast<size_t>(Traits::MAX_SUBQUEUE_SIZE) < BLOCK_SIZE) ? details::const_numeric_max<size_t>::value : ((static_cast<size_t>(Traits::MAX_SUBQUEUE_SIZE) + (BLOCK_SIZE - 1)) / BLOCK_SIZE * BLOCK_SIZE);\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\n\tstatic_assert(!std::numeric_limits<size_t>::is_signed && std::is_integral<size_t>::value, \"Traits::size_t must be an unsigned integral type\");\n\tstatic_assert(!std::numeric_limits<index_t>::is_signed && std::is_integral<index_t>::value, \"Traits::index_t must be an unsigned integral type\");\n\tstatic_assert(sizeof(index_t) >= sizeof(size_t), \"Traits::index_t must be at least as wide as Traits::size_t\");\n\tstatic_assert((BLOCK_SIZE > 1) && !(BLOCK_SIZE & (BLOCK_SIZE - 1)), \"Traits::BLOCK_SIZE must be a power of 2 (and at least 2)\");\n\tstatic_assert((EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD > 1) && !(EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD & (EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD - 1)), \"Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD must be a power of 2 (and greater than 1)\");\n\tstatic_assert((EXPLICIT_INITIAL_INDEX_SIZE > 1) && !(EXPLICIT_INITIAL_INDEX_SIZE & (EXPLICIT_INITIAL_INDEX_SIZE - 1)), \"Traits::EXPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)\");\n\tstatic_assert((IMPLICIT_INITIAL_INDEX_SIZE > 1) && !(IMPLICIT_INITIAL_INDEX_SIZE & (IMPLICIT_INITIAL_INDEX_SIZE - 1)), \"Traits::IMPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)\");\n\tstatic_assert((INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) || !(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE & (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE - 1)), \"Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be a power of 2\");\n\tstatic_assert(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0 || INITIAL_IMPLICIT_PRODUCER_HASH_SIZE >= 1, \"Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be at least 1 (or 0 to disable implicit enqueueing)\");\n\npublic:\n\t// Creates a queue with at least `capacity` element slots; note that the\n\t// actual number of elements that can be inserted without additional memory\n\t// allocation depends on the number of producers and the block size (e.g. if\n\t// the block size is equal to `capacity`, only a single block will be allocated\n\t// up-front, which means only a single producer will be able to enqueue elements\n\t// without an extra allocation -- blocks aren't shared between producers).\n\t// This method is not thread safe -- it is up to the user to ensure that the\n\t// queue is fully constructed before it starts being used by other threads (this\n\t// includes making the memory effects of construction visible, possibly with a\n\t// memory barrier).\n\texplicit ConcurrentQueue(size_t capacity = 32 * BLOCK_SIZE)\n\t\t: producerListTail(nullptr),\n\t\tproducerCount(0),\n\t\tinitialBlockPoolIndex(0),\n\t\tnextExplicitConsumerId(0),\n\t\tglobalExplicitConsumerOffset(0)\n\t{\n\t\timplicitProducerHashResizeInProgress.clear(std::memory_order_relaxed);\n\t\tpopulate_initial_implicit_producer_hash();\n\t\tpopulate_initial_block_list(capacity / BLOCK_SIZE + ((capacity & (BLOCK_SIZE - 1)) == 0 ? 0 : 1));\n\t\t\n#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG\n\t\t// Track all the producers using a fully-resolved typed list for\n\t\t// each kind; this makes it possible to debug them starting from\n\t\t// the root queue object (otherwise wacky casts are needed that\n\t\t// don't compile in the debugger's expression evaluator).\n\t\texplicitProducers.store(nullptr, std::memory_order_relaxed);\n\t\timplicitProducers.store(nullptr, std::memory_order_relaxed);\n#endif\n\t}\n\t\n\t// Computes the correct amount of pre-allocated blocks for you based\n\t// on the minimum number of elements you want available at any given\n\t// time, and the maximum concurrent number of each type of producer.\n\tConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers)\n\t\t: producerListTail(nullptr),\n\t\tproducerCount(0),\n\t\tinitialBlockPoolIndex(0),\n\t\tnextExplicitConsumerId(0),\n\t\tglobalExplicitConsumerOffset(0)\n\t{\n\t\timplicitProducerHashResizeInProgress.clear(std::memory_order_relaxed);\n\t\tpopulate_initial_implicit_producer_hash();\n\t\tsize_t blocks = (((minCapacity + BLOCK_SIZE - 1) / BLOCK_SIZE) - 1) * (maxExplicitProducers + 1) + 2 * (maxExplicitProducers + maxImplicitProducers);\n\t\tpopulate_initial_block_list(blocks);\n\t\t\n#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG\n\t\texplicitProducers.store(nullptr, std::memory_order_relaxed);\n\t\timplicitProducers.store(nullptr, std::memory_order_relaxed);\n#endif\n\t}\n\t\n\t// Note: The queue should not be accessed concurrently while it's\n\t// being deleted. It's up to the user to synchronize this.\n\t// This method is not thread safe.\n\t~ConcurrentQueue()\n\t{\n\t\t// Destroy producers\n\t\tauto ptr = producerListTail.load(std::memory_order_relaxed);\n\t\twhile (ptr != nullptr) {\n\t\t\tauto next = ptr->next_prod();\n\t\t\tif (ptr->token != nullptr) {\n\t\t\t\tptr->token->producer = nullptr;\n\t\t\t}\n\t\t\tdestroy(ptr);\n\t\t\tptr = next;\n\t\t}\n\t\t\n\t\t// Destroy implicit producer hash tables\n\t\tMOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE != 0) {\n\t\t\tauto hash = implicitProducerHash.load(std::memory_order_relaxed);\n\t\t\twhile (hash != nullptr) {\n\t\t\t\tauto prev = hash->prev;\n\t\t\t\tif (prev != nullptr) {\t\t// The last hash is part of this object and was not allocated dynamically\n\t\t\t\t\tfor (size_t i = 0; i != hash->capacity; ++i) {\n\t\t\t\t\t\thash->entries[i].~ImplicitProducerKVP();\n\t\t\t\t\t}\n\t\t\t\t\thash->~ImplicitProducerHash();\n\t\t\t\t\t(Traits::free)(hash);\n\t\t\t\t}\n\t\t\t\thash = prev;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Destroy global free list\n\t\tauto block = freeList.head_unsafe();\n\t\twhile (block != nullptr) {\n\t\t\tauto next = block->freeListNext.load(std::memory_order_relaxed);\n\t\t\tif (block->dynamicallyAllocated) {\n\t\t\t\tdestroy(block);\n\t\t\t}\n\t\t\tblock = next;\n\t\t}\n\t\t\n\t\t// Destroy initial free list\n\t\tdestroy_array(initialBlockPool, initialBlockPoolSize);\n\t}\n\n\t// Disable copying and copy assignment\n\tConcurrentQueue(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION;\n\tConcurrentQueue& operator=(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION;\n\t\n\t// Moving is supported, but note that it is *not* a thread-safe operation.\n\t// Nobody can use the queue while it's being moved, and the memory effects\n\t// of that move must be propagated to other threads before they can use it.\n\t// Note: When a queue is moved, its tokens are still valid but can only be\n\t// used with the destination queue (i.e. semantically they are moved along\n\t// with the queue itself).\n\tConcurrentQueue(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT\n\t\t: producerListTail(other.producerListTail.load(std::memory_order_relaxed)),\n\t\tproducerCount(other.producerCount.load(std::memory_order_relaxed)),\n\t\tinitialBlockPoolIndex(other.initialBlockPoolIndex.load(std::memory_order_relaxed)),\n\t\tinitialBlockPool(other.initialBlockPool),\n\t\tinitialBlockPoolSize(other.initialBlockPoolSize),\n\t\tfreeList(std::move(other.freeList)),\n\t\tnextExplicitConsumerId(other.nextExplicitConsumerId.load(std::memory_order_relaxed)),\n\t\tglobalExplicitConsumerOffset(other.globalExplicitConsumerOffset.load(std::memory_order_relaxed))\n\t{\n\t\t// Move the other one into this, and leave the other one as an empty queue\n\t\timplicitProducerHashResizeInProgress.clear(std::memory_order_relaxed);\n\t\tpopulate_initial_implicit_producer_hash();\n\t\tswap_implicit_producer_hashes(other);\n\t\t\n\t\tother.producerListTail.store(nullptr, std::memory_order_relaxed);\n\t\tother.producerCount.store(0, std::memory_order_relaxed);\n\t\tother.nextExplicitConsumerId.store(0, std::memory_order_relaxed);\n\t\tother.globalExplicitConsumerOffset.store(0, std::memory_order_relaxed);\n\t\t\n#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG\n\t\texplicitProducers.store(other.explicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed);\n\t\tother.explicitProducers.store(nullptr, std::memory_order_relaxed);\n\t\timplicitProducers.store(other.implicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed);\n\t\tother.implicitProducers.store(nullptr, std::memory_order_relaxed);\n#endif\n\t\t\n\t\tother.initialBlockPoolIndex.store(0, std::memory_order_relaxed);\n\t\tother.initialBlockPoolSize = 0;\n\t\tother.initialBlockPool = nullptr;\n\t\t\n\t\treown_producers();\n\t}\n\t\n\tinline ConcurrentQueue& operator=(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT\n\t{\n\t\treturn swap_internal(other);\n\t}\n\t\n\t// Swaps this queue's state with the other's. Not thread-safe.\n\t// Swapping two queues does not invalidate their tokens, however\n\t// the tokens that were created for one queue must be used with\n\t// only the swapped queue (i.e. the tokens are tied to the\n\t// queue's movable state, not the object itself).\n\tinline void swap(ConcurrentQueue& other) MOODYCAMEL_NOEXCEPT\n\t{\n\t\tswap_internal(other);\n\t}\n\t\nprivate:\n\tConcurrentQueue& swap_internal(ConcurrentQueue& other)\n\t{\n\t\tif (this == &other) {\n\t\t\treturn *this;\n\t\t}\n\t\t\n\t\tdetails::swap_relaxed(producerListTail, other.producerListTail);\n\t\tdetails::swap_relaxed(producerCount, other.producerCount);\n\t\tdetails::swap_relaxed(initialBlockPoolIndex, other.initialBlockPoolIndex);\n\t\tstd::swap(initialBlockPool, other.initialBlockPool);\n\t\tstd::swap(initialBlockPoolSize, other.initialBlockPoolSize);\n\t\tfreeList.swap(other.freeList);\n\t\tdetails::swap_relaxed(nextExplicitConsumerId, other.nextExplicitConsumerId);\n\t\tdetails::swap_relaxed(globalExplicitConsumerOffset, other.globalExplicitConsumerOffset);\n\t\t\n\t\tswap_implicit_producer_hashes(other);\n\t\t\n\t\treown_producers();\n\t\tother.reown_producers();\n\t\t\n#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG\n\t\tdetails::swap_relaxed(explicitProducers, other.explicitProducers);\n\t\tdetails::swap_relaxed(implicitProducers, other.implicitProducers);\n#endif\n\t\t\n\t\treturn *this;\n\t}\n\t\npublic:\n\t// Enqueues a single item (by copying it).\n\t// Allocates memory if required. Only fails if memory allocation fails (or implicit\n\t// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0,\n\t// or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).\n\t// Thread-safe.\n\tinline bool enqueue(T const& item)\n\t{\n\t\tMOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false;\n\t\telse return inner_enqueue<CanAlloc>(item);\n\t}\n\t\n\t// Enqueues a single item (by moving it, if possible).\n\t// Allocates memory if required. Only fails if memory allocation fails (or implicit\n\t// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0,\n\t// or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).\n\t// Thread-safe.\n\tinline bool enqueue(T&& item)\n\t{\n\t\tMOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false;\n\t\telse return inner_enqueue<CanAlloc>(std::move(item));\n\t}\n\t\n\t// Enqueues a single item (by copying it) using an explicit producer token.\n\t// Allocates memory if required. Only fails if memory allocation fails (or\n\t// Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).\n\t// Thread-safe.\n\tinline bool enqueue(producer_token_t const& token, T const& item)\n\t{\n\t\treturn inner_enqueue<CanAlloc>(token, item);\n\t}\n\t\n\t// Enqueues a single item (by moving it, if possible) using an explicit producer token.\n\t// Allocates memory if required. Only fails if memory allocation fails (or\n\t// Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).\n\t// Thread-safe.\n\tinline bool enqueue(producer_token_t const& token, T&& item)\n\t{\n\t\treturn inner_enqueue<CanAlloc>(token, std::move(item));\n\t}\n\t\n\t// Enqueues several items.\n\t// Allocates memory if required. Only fails if memory allocation fails (or\n\t// implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE\n\t// is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).\n\t// Note: Use std::make_move_iterator if the elements should be moved instead of copied.\n\t// Thread-safe.\n\ttemplate<typename It>\n\tbool enqueue_bulk(It itemFirst, size_t count)\n\t{\n\t\tMOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false;\n\t\telse return inner_enqueue_bulk<CanAlloc>(itemFirst, count);\n\t}\n\t\n\t// Enqueues several items using an explicit producer token.\n\t// Allocates memory if required. Only fails if memory allocation fails\n\t// (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).\n\t// Note: Use std::make_move_iterator if the elements should be moved\n\t// instead of copied.\n\t// Thread-safe.\n\ttemplate<typename It>\n\tbool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)\n\t{\n\t\treturn inner_enqueue_bulk<CanAlloc>(token, itemFirst, count);\n\t}\n\t\n\t// Enqueues a single item (by copying it).\n\t// Does not allocate memory. Fails if not enough room to enqueue (or implicit\n\t// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE\n\t// is 0).\n\t// Thread-safe.\n\tinline bool try_enqueue(T const& item)\n\t{\n\t\tMOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false;\n\t\telse return inner_enqueue<CannotAlloc>(item);\n\t}\n\t\n\t// Enqueues a single item (by moving it, if possible).\n\t// Does not allocate memory (except for one-time implicit producer).\n\t// Fails if not enough room to enqueue (or implicit production is\n\t// disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0).\n\t// Thread-safe.\n\tinline bool try_enqueue(T&& item)\n\t{\n\t\tMOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false;\n\t\telse return inner_enqueue<CannotAlloc>(std::move(item));\n\t}\n\t\n\t// Enqueues a single item (by copying it) using an explicit producer token.\n\t// Does not allocate memory. Fails if not enough room to enqueue.\n\t// Thread-safe.\n\tinline bool try_enqueue(producer_token_t const& token, T const& item)\n\t{\n\t\treturn inner_enqueue<CannotAlloc>(token, item);\n\t}\n\t\n\t// Enqueues a single item (by moving it, if possible) using an explicit producer token.\n\t// Does not allocate memory. Fails if not enough room to enqueue.\n\t// Thread-safe.\n\tinline bool try_enqueue(producer_token_t const& token, T&& item)\n\t{\n\t\treturn inner_enqueue<CannotAlloc>(token, std::move(item));\n\t}\n\t\n\t// Enqueues several items.\n\t// Does not allocate memory (except for one-time implicit producer).\n\t// Fails if not enough room to enqueue (or implicit production is\n\t// disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0).\n\t// Note: Use std::make_move_iterator if the elements should be moved\n\t// instead of copied.\n\t// Thread-safe.\n\ttemplate<typename It>\n\tbool try_enqueue_bulk(It itemFirst, size_t count)\n\t{\n\t\tMOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false;\n\t\telse return inner_enqueue_bulk<CannotAlloc>(itemFirst, count);\n\t}\n\t\n\t// Enqueues several items using an explicit producer token.\n\t// Does not allocate memory. Fails if not enough room to enqueue.\n\t// Note: Use std::make_move_iterator if the elements should be moved\n\t// instead of copied.\n\t// Thread-safe.\n\ttemplate<typename It>\n\tbool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)\n\t{\n\t\treturn inner_enqueue_bulk<CannotAlloc>(token, itemFirst, count);\n\t}\n\t\n\t\n\t\n\t// Attempts to dequeue from the queue.\n\t// Returns false if all producer streams appeared empty at the time they\n\t// were checked (so, the queue is likely but not guaranteed to be empty).\n\t// Never allocates. Thread-safe.\n\ttemplate<typename U>\n\tbool try_dequeue(U& item)\n\t{\n\t\t// Instead of simply trying each producer in turn (which could cause needless contention on the first\n\t\t// producer), we score them heuristically.\n\t\tsize_t nonEmptyCount = 0;\n\t\tProducerBase* best = nullptr;\n\t\tsize_t bestSize = 0;\n\t\tfor (auto ptr = producerListTail.load(std::memory_order_acquire); nonEmptyCount < 3 && ptr != nullptr; ptr = ptr->next_prod()) {\n\t\t\tauto size = ptr->size_approx();\n\t\t\tif (size > 0) {\n\t\t\t\tif (size > bestSize) {\n\t\t\t\t\tbestSize = size;\n\t\t\t\t\tbest = ptr;\n\t\t\t\t}\n\t\t\t\t++nonEmptyCount;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// If there was at least one non-empty queue but it appears empty at the time\n\t\t// we try to dequeue from it, we need to make sure every queue's been tried\n\t\tif (nonEmptyCount > 0) {\n\t\t\tif ((details::likely)(best->dequeue(item))) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tfor (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {\n\t\t\t\tif (ptr != best && ptr->dequeue(item)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Attempts to dequeue from the queue.\n\t// Returns false if all producer streams appeared empty at the time they\n\t// were checked (so, the queue is likely but not guaranteed to be empty).\n\t// This differs from the try_dequeue(item) method in that this one does\n\t// not attempt to reduce contention by interleaving the order that producer\n\t// streams are dequeued from. So, using this method can reduce overall throughput\n\t// under contention, but will give more predictable results in single-threaded\n\t// consumer scenarios. This is mostly only useful for internal unit tests.\n\t// Never allocates. Thread-safe.\n\ttemplate<typename U>\n\tbool try_dequeue_non_interleaved(U& item)\n\t{\n\t\tfor (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {\n\t\t\tif (ptr->dequeue(item)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Attempts to dequeue from the queue using an explicit consumer token.\n\t// Returns false if all producer streams appeared empty at the time they\n\t// were checked (so, the queue is likely but not guaranteed to be empty).\n\t// Never allocates. Thread-safe.\n\ttemplate<typename U>\n\tbool try_dequeue(consumer_token_t& token, U& item)\n\t{\n\t\t// The idea is roughly as follows:\n\t\t// Every 256 items from one producer, make everyone rotate (increase the global offset) -> this means the highest efficiency consumer dictates the rotation speed of everyone else, more or less\n\t\t// If you see that the global offset has changed, you must reset your consumption counter and move to your designated place\n\t\t// If there's no items where you're supposed to be, keep moving until you find a producer with some items\n\t\t// If the global offset has not changed but you've run out of items to consume, move over from your current position until you find an producer with something in it\n\t\t\n\t\tif (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) {\n\t\t\tif (!update_current_producer_after_rotation(token)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// If there was at least one non-empty queue but it appears empty at the time\n\t\t// we try to dequeue from it, we need to make sure every queue's been tried\n\t\tif (static_cast<ProducerBase*>(token.currentProducer)->dequeue(item)) {\n\t\t\tif (++token.itemsConsumedFromCurrent == EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) {\n\t\t\t\tglobalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tauto tail = producerListTail.load(std::memory_order_acquire);\n\t\tauto ptr = static_cast<ProducerBase*>(token.currentProducer)->next_prod();\n\t\tif (ptr == nullptr) {\n\t\t\tptr = tail;\n\t\t}\n\t\twhile (ptr != static_cast<ProducerBase*>(token.currentProducer)) {\n\t\t\tif (ptr->dequeue(item)) {\n\t\t\t\ttoken.currentProducer = ptr;\n\t\t\t\ttoken.itemsConsumedFromCurrent = 1;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tptr = ptr->next_prod();\n\t\t\tif (ptr == nullptr) {\n\t\t\t\tptr = tail;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// Attempts to dequeue several elements from the queue.\n\t// Returns the number of items actually dequeued.\n\t// Returns 0 if all producer streams appeared empty at the time they\n\t// were checked (so, the queue is likely but not guaranteed to be empty).\n\t// Never allocates. Thread-safe.\n\ttemplate<typename It>\n\tsize_t try_dequeue_bulk(It itemFirst, size_t max)\n\t{\n\t\tsize_t count = 0;\n\t\tfor (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {\n\t\t\tcount += ptr->dequeue_bulk(itemFirst, max - count);\n\t\t\tif (count == max) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\t\n\t// Attempts to dequeue several elements from the queue using an explicit consumer token.\n\t// Returns the number of items actually dequeued.\n\t// Returns 0 if all producer streams appeared empty at the time they\n\t// were checked (so, the queue is likely but not guaranteed to be empty).\n\t// Never allocates. Thread-safe.\n\ttemplate<typename It>\n\tsize_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max)\n\t{\n\t\tif (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) {\n\t\t\tif (!update_current_producer_after_rotation(token)) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\t\n\t\tsize_t count = static_cast<ProducerBase*>(token.currentProducer)->dequeue_bulk(itemFirst, max);\n\t\tif (count == max) {\n\t\t\tif ((token.itemsConsumedFromCurrent += static_cast<std::uint32_t>(max)) >= EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) {\n\t\t\t\tglobalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed);\n\t\t\t}\n\t\t\treturn max;\n\t\t}\n\t\ttoken.itemsConsumedFromCurrent += static_cast<std::uint32_t>(count);\n\t\tmax -= count;\n\t\t\n\t\tauto tail = producerListTail.load(std::memory_order_acquire);\n\t\tauto ptr = static_cast<ProducerBase*>(token.currentProducer)->next_prod();\n\t\tif (ptr == nullptr) {\n\t\t\tptr = tail;\n\t\t}\n\t\twhile (ptr != static_cast<ProducerBase*>(token.currentProducer)) {\n\t\t\tauto dequeued = ptr->dequeue_bulk(itemFirst, max);\n\t\t\tcount += dequeued;\n\t\t\tif (dequeued != 0) {\n\t\t\t\ttoken.currentProducer = ptr;\n\t\t\t\ttoken.itemsConsumedFromCurrent = static_cast<std::uint32_t>(dequeued);\n\t\t\t}\n\t\t\tif (dequeued == max) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmax -= dequeued;\n\t\t\tptr = ptr->next_prod();\n\t\t\tif (ptr == nullptr) {\n\t\t\t\tptr = tail;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\t\n\t\n\t\n\t// Attempts to dequeue from a specific producer's inner queue.\n\t// If you happen to know which producer you want to dequeue from, this\n\t// is significantly faster than using the general-case try_dequeue methods.\n\t// Returns false if the producer's queue appeared empty at the time it\n\t// was checked (so, the queue is likely but not guaranteed to be empty).\n\t// Never allocates. Thread-safe.\n\ttemplate<typename U>\n\tinline bool try_dequeue_from_producer(producer_token_t const& producer, U& item)\n\t{\n\t\treturn static_cast<ExplicitProducer*>(producer.producer)->dequeue(item);\n\t}\n\t\n\t// Attempts to dequeue several elements from a specific producer's inner queue.\n\t// Returns the number of items actually dequeued.\n\t// If you happen to know which producer you want to dequeue from, this\n\t// is significantly faster than using the general-case try_dequeue methods.\n\t// Returns 0 if the producer's queue appeared empty at the time it\n\t// was checked (so, the queue is likely but not guaranteed to be empty).\n\t// Never allocates. Thread-safe.\n\ttemplate<typename It>\n\tinline size_t try_dequeue_bulk_from_producer(producer_token_t const& producer, It itemFirst, size_t max)\n\t{\n\t\treturn static_cast<ExplicitProducer*>(producer.producer)->dequeue_bulk(itemFirst, max);\n\t}\n\t\n\t\n\t// Returns an estimate of the total number of elements currently in the queue. This\n\t// estimate is only accurate if the queue has completely stabilized before it is called\n\t// (i.e. all enqueue and dequeue operations have completed and their memory effects are\n\t// visible on the calling thread, and no further operations start while this method is\n\t// being called).\n\t// Thread-safe.\n\tsize_t size_approx() const\n\t{\n\t\tsize_t size = 0;\n\t\tfor (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {\n\t\t\tsize += ptr->size_approx();\n\t\t}\n\t\treturn size;\n\t}\n\t\n\t\n\t// Returns true if the underlying atomic variables used by\n\t// the queue are lock-free (they should be on most platforms).\n\t// Thread-safe.\n\tstatic constexpr bool is_lock_free()\n\t{\n\t\treturn\n\t\t\tdetails::static_is_lock_free<bool>::value == 2 &&\n\t\t\tdetails::static_is_lock_free<size_t>::value == 2 &&\n\t\t\tdetails::static_is_lock_free<std::uint32_t>::value == 2 &&\n\t\t\tdetails::static_is_lock_free<index_t>::value == 2 &&\n\t\t\tdetails::static_is_lock_free<void*>::value == 2 &&\n\t\t\tdetails::static_is_lock_free<typename details::thread_id_converter<details::thread_id_t>::thread_id_numeric_size_t>::value == 2;\n\t}\n\n\nprivate:\n\tfriend struct ProducerToken;\n\tfriend struct ConsumerToken;\n\tstruct ExplicitProducer;\n\tfriend struct ExplicitProducer;\n\tstruct ImplicitProducer;\n\tfriend struct ImplicitProducer;\n\tfriend class ConcurrentQueueTests;\n\t\t\n\tenum AllocationMode { CanAlloc, CannotAlloc };\n\t\n\t\n\t///////////////////////////////\n\t// Queue methods\n\t///////////////////////////////\n\t\n\ttemplate<AllocationMode canAlloc, typename U>\n\tinline bool inner_enqueue(producer_token_t const& token, U&& element)\n\t{\n\t\treturn static_cast<ExplicitProducer*>(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue<canAlloc>(std::forward<U>(element));\n\t}\n\t\n\ttemplate<AllocationMode canAlloc, typename U>\n\tinline bool inner_enqueue(U&& element)\n\t{\n\t\tauto producer = get_or_add_implicit_producer();\n\t\treturn producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue<canAlloc>(std::forward<U>(element));\n\t}\n\t\n\ttemplate<AllocationMode canAlloc, typename It>\n\tinline bool inner_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)\n\t{\n\t\treturn static_cast<ExplicitProducer*>(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue_bulk<canAlloc>(itemFirst, count);\n\t}\n\t\n\ttemplate<AllocationMode canAlloc, typename It>\n\tinline bool inner_enqueue_bulk(It itemFirst, size_t count)\n\t{\n\t\tauto producer = get_or_add_implicit_producer();\n\t\treturn producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue_bulk<canAlloc>(itemFirst, count);\n\t}\n\t\n\tinline bool update_current_producer_after_rotation(consumer_token_t& token)\n\t{\n\t\t// Ah, there's been a rotation, figure out where we should be!\n\t\tauto tail = producerListTail.load(std::memory_order_acquire);\n\t\tif (token.desiredProducer == nullptr && tail == nullptr) {\n\t\t\treturn false;\n\t\t}\n\t\tauto prodCount = producerCount.load(std::memory_order_relaxed);\n\t\tauto globalOffset = globalExplicitConsumerOffset.load(std::memory_order_relaxed);\n\t\tif ((details::unlikely)(token.desiredProducer == nullptr)) {\n\t\t\t// Aha, first time we're dequeueing anything.\n\t\t\t// Figure out our local position\n\t\t\t// Note: offset is from start, not end, but we're traversing from end -- subtract from count first\n\t\t\tstd::uint32_t offset = prodCount - 1 - (token.initialOffset % prodCount);\n\t\t\ttoken.desiredProducer = tail;\n\t\t\tfor (std::uint32_t i = 0; i != offset; ++i) {\n\t\t\t\ttoken.desiredProducer = static_cast<ProducerBase*>(token.desiredProducer)->next_prod();\n\t\t\t\tif (token.desiredProducer == nullptr) {\n\t\t\t\t\ttoken.desiredProducer = tail;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tstd::uint32_t delta = globalOffset - token.lastKnownGlobalOffset;\n\t\tif (delta >= prodCount) {\n\t\t\tdelta = delta % prodCount;\n\t\t}\n\t\tfor (std::uint32_t i = 0; i != delta; ++i) {\n\t\t\ttoken.desiredProducer = static_cast<ProducerBase*>(token.desiredProducer)->next_prod();\n\t\t\tif (token.desiredProducer == nullptr) {\n\t\t\t\ttoken.desiredProducer = tail;\n\t\t\t}\n\t\t}\n\t\t\n\t\ttoken.lastKnownGlobalOffset = globalOffset;\n\t\ttoken.currentProducer = token.desiredProducer;\n\t\ttoken.itemsConsumedFromCurrent = 0;\n\t\treturn true;\n\t}\n\t\n\t\n\t///////////////////////////\n\t// Free list\n\t///////////////////////////\n\t\n\ttemplate <typename N>\n\tstruct FreeListNode\n\t{\n\t\tFreeListNode() : freeListRefs(0), freeListNext(nullptr) { }\n\t\t\n\t\tstd::atomic<std::uint32_t> freeListRefs;\n\t\tstd::atomic<N*> freeListNext;\n\t};\n\t\n\t// A simple CAS-based lock-free free list. Not the fastest thing in the world under heavy contention, but\n\t// simple and correct (assuming nodes are never freed until after the free list is destroyed), and fairly\n\t// speedy under low contention.\n\ttemplate<typename N>\t\t// N must inherit FreeListNode or have the same fields (and initialization of them)\n\tstruct FreeList\n\t{\n\t\tFreeList() : freeListHead(nullptr) { }\n\t\tFreeList(FreeList&& other) : freeListHead(other.freeListHead.load(std::memory_order_relaxed)) { other.freeListHead.store(nullptr, std::memory_order_relaxed); }\n\t\tvoid swap(FreeList& other) { details::swap_relaxed(freeListHead, other.freeListHead); }\n\t\t\n\t\tFreeList(FreeList const&) MOODYCAMEL_DELETE_FUNCTION;\n\t\tFreeList& operator=(FreeList const&) MOODYCAMEL_DELETE_FUNCTION;\n\t\t\n\t\tinline void add(N* node)\n\t\t{\n#ifdef MCDBGQ_NOLOCKFREE_FREELIST\n\t\t\tdebug::DebugLock lock(mutex);\n#endif\t\t\n\t\t\t// We know that the should-be-on-freelist bit is 0 at this point, so it's safe to\n\t\t\t// set it using a fetch_add\n\t\t\tif (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST, std::memory_order_acq_rel) == 0) {\n\t\t\t\t// Oh look! We were the last ones referencing this node, and we know\n\t\t\t\t// we want to add it to the free list, so let's do it!\n\t\t \t\tadd_knowing_refcount_is_zero(node);\n\t\t\t}\n\t\t}\n\t\t\n\t\tinline N* try_get()\n\t\t{\n#ifdef MCDBGQ_NOLOCKFREE_FREELIST\n\t\t\tdebug::DebugLock lock(mutex);\n#endif\t\t\n\t\t\tauto head = freeListHead.load(std::memory_order_acquire);\n\t\t\twhile (head != nullptr) {\n\t\t\t\tauto prevHead = head;\n\t\t\t\tauto refs = head->freeListRefs.load(std::memory_order_relaxed);\n\t\t\t\tif ((refs & REFS_MASK) == 0 || !head->freeListRefs.compare_exchange_strong(refs, refs + 1, std::memory_order_acquire, std::memory_order_relaxed)) {\n\t\t\t\t\thead = freeListHead.load(std::memory_order_acquire);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Good, reference count has been incremented (it wasn't at zero), which means we can read the\n\t\t\t\t// next and not worry about it changing between now and the time we do the CAS\n\t\t\t\tauto next = head->freeListNext.load(std::memory_order_relaxed);\n\t\t\t\tif (freeListHead.compare_exchange_strong(head, next, std::memory_order_acquire, std::memory_order_relaxed)) {\n\t\t\t\t\t// Yay, got the node. This means it was on the list, which means shouldBeOnFreeList must be false no\n\t\t\t\t\t// matter the refcount (because nobody else knows it's been taken off yet, it can't have been put back on).\n\t\t\t\t\tassert((head->freeListRefs.load(std::memory_order_relaxed) & SHOULD_BE_ON_FREELIST) == 0);\n\t\t\t\t\t\n\t\t\t\t\t// Decrease refcount twice, once for our ref, and once for the list's ref\n\t\t\t\t\thead->freeListRefs.fetch_sub(2, std::memory_order_release);\n\t\t\t\t\treturn head;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// OK, the head must have changed on us, but we still need to decrease the refcount we increased.\n\t\t\t\t// Note that we don't need to release any memory effects, but we do need to ensure that the reference\n\t\t\t\t// count decrement happens-after the CAS on the head.\n\t\t\t\trefs = prevHead->freeListRefs.fetch_sub(1, std::memory_order_acq_rel);\n\t\t\t\tif (refs == SHOULD_BE_ON_FREELIST + 1) {\n\t\t\t\t\tadd_knowing_refcount_is_zero(prevHead);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn nullptr;\n\t\t}\n\t\t\n\t\t// Useful for traversing the list when there's no contention (e.g. to destroy remaining nodes)\n\t\tN* head_unsafe() const { return freeListHead.load(std::memory_order_relaxed); }\n\t\t\n\tprivate:\n\t\tinline void add_knowing_refcount_is_zero(N* node)\n\t\t{\n\t\t\t// Since the refcount is zero, and nobody can increase it once it's zero (except us, and we run\n\t\t\t// only one copy of this method per node at a time, i.e. the single thread case), then we know\n\t\t\t// we can safely change the next pointer of the node; however, once the refcount is back above\n\t\t\t// zero, then other threads could increase it (happens under heavy contention, when the refcount\n\t\t\t// goes to zero in between a load and a refcount increment of a node in try_get, then back up to\n\t\t\t// something non-zero, then the refcount increment is done by the other thread) -- so, if the CAS\n\t\t\t// to add the node to the actual list fails, decrease the refcount and leave the add operation to\n\t\t\t// the next thread who puts the refcount back at zero (which could be us, hence the loop).\n\t\t\tauto head = freeListHead.load(std::memory_order_relaxed);\n\t\t\twhile (true) {\n\t\t\t\tnode->freeListNext.store(head, std::memory_order_relaxed);\n\t\t\t\tnode->freeListRefs.store(1, std::memory_order_release);\n\t\t\t\tif (!freeListHead.compare_exchange_strong(head, node, std::memory_order_release, std::memory_order_relaxed)) {\n\t\t\t\t\t// Hmm, the add failed, but we can only try again when the refcount goes back to zero\n\t\t\t\t\tif (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST - 1, std::memory_order_release) == 1) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t\n\tprivate:\n\t\t// Implemented like a stack, but where node order doesn't matter (nodes are inserted out of order under contention)\n\t\tstd::atomic<N*> freeListHead;\n\t\n\tstatic const std::uint32_t REFS_MASK = 0x7FFFFFFF;\n\tstatic const std::uint32_t SHOULD_BE_ON_FREELIST = 0x80000000;\n\t\t\n#ifdef MCDBGQ_NOLOCKFREE_FREELIST\n\t\tdebug::DebugMutex mutex;\n#endif\n\t};\n\t\n\t\n\t///////////////////////////\n\t// Block\n\t///////////////////////////\n\t\n\tenum InnerQueueContext { implicit_context = 0, explicit_context = 1 };\n\t\n\tstruct Block\n\t{\n\t\tBlock()\n\t\t\t: next(nullptr), elementsCompletelyDequeued(0), freeListRefs(0), freeListNext(nullptr), dynamicallyAllocated(true)\n\t\t{\n#ifdef MCDBGQ_TRACKMEM\n\t\t\towner = nullptr;\n#endif\n\t\t}\n\t\t\n\t\ttemplate<InnerQueueContext context>\n\t\tinline bool is_empty() const\n\t\t{\n\t\t\tMOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) {\n\t\t\t\t// Check flags\n\t\t\t\tfor (size_t i = 0; i < BLOCK_SIZE; ++i) {\n\t\t\t\t\tif (!emptyFlags[i].load(std::memory_order_relaxed)) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Aha, empty; make sure we have all other memory effects that happened before the empty flags were set\n\t\t\t\tstd::atomic_thread_fence(std::memory_order_acquire);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Check counter\n\t\t\t\tif (elementsCompletelyDequeued.load(std::memory_order_relaxed) == BLOCK_SIZE) {\n\t\t\t\t\tstd::atomic_thread_fence(std::memory_order_acquire);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tassert(elementsCompletelyDequeued.load(std::memory_order_relaxed) <= BLOCK_SIZE);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Returns true if the block is now empty (does not apply in explicit context)\n\t\ttemplate<InnerQueueContext context>\n\t\tinline bool set_empty(MOODYCAMEL_MAYBE_UNUSED index_t i)\n\t\t{\n\t\t\tMOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) {\n\t\t\t\t// Set flag\n\t\t\t\tassert(!emptyFlags[BLOCK_SIZE - 1 - static_cast<size_t>(i & static_cast<index_t>(BLOCK_SIZE - 1))].load(std::memory_order_relaxed));\n\t\t\t\temptyFlags[BLOCK_SIZE - 1 - static_cast<size_t>(i & static_cast<index_t>(BLOCK_SIZE - 1))].store(true, std::memory_order_release);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Increment counter\n\t\t\t\tauto prevVal = elementsCompletelyDequeued.fetch_add(1, std::memory_order_release);\n\t\t\t\tassert(prevVal < BLOCK_SIZE);\n\t\t\t\treturn prevVal == BLOCK_SIZE - 1;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Sets multiple contiguous item statuses to 'empty' (assumes no wrapping and count > 0).\n\t\t// Returns true if the block is now empty (does not apply in explicit context).\n\t\ttemplate<InnerQueueContext context>\n\t\tinline bool set_many_empty(MOODYCAMEL_MAYBE_UNUSED index_t i, size_t count)\n\t\t{\n\t\t\tMOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) {\n\t\t\t\t// Set flags\n\t\t\t\tstd::atomic_thread_fence(std::memory_order_release);\n\t\t\t\ti = BLOCK_SIZE - 1 - static_cast<size_t>(i & static_cast<index_t>(BLOCK_SIZE - 1)) - count + 1;\n\t\t\t\tfor (size_t j = 0; j != count; ++j) {\n\t\t\t\t\tassert(!emptyFlags[i + j].load(std::memory_order_relaxed));\n\t\t\t\t\temptyFlags[i + j].store(true, std::memory_order_relaxed);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Increment counter\n\t\t\t\tauto prevVal = elementsCompletelyDequeued.fetch_add(count, std::memory_order_release);\n\t\t\t\tassert(prevVal + count <= BLOCK_SIZE);\n\t\t\t\treturn prevVal + count == BLOCK_SIZE;\n\t\t\t}\n\t\t}\n\t\t\n\t\ttemplate<InnerQueueContext context>\n\t\tinline void set_all_empty()\n\t\t{\n\t\t\tMOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) {\n\t\t\t\t// Set all flags\n\t\t\t\tfor (size_t i = 0; i != BLOCK_SIZE; ++i) {\n\t\t\t\t\temptyFlags[i].store(true, std::memory_order_relaxed);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Reset counter\n\t\t\t\telementsCompletelyDequeued.store(BLOCK_SIZE, std::memory_order_relaxed);\n\t\t\t}\n\t\t}\n\t\t\n\t\ttemplate<InnerQueueContext context>\n\t\tinline void reset_empty()\n\t\t{\n\t\t\tMOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) {\n\t\t\t\t// Reset flags\n\t\t\t\tfor (size_t i = 0; i != BLOCK_SIZE; ++i) {\n\t\t\t\t\temptyFlags[i].store(false, std::memory_order_relaxed);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Reset counter\n\t\t\t\telementsCompletelyDequeued.store(0, std::memory_order_relaxed);\n\t\t\t}\n\t\t}\n\t\t\n\t\tinline T* operator[](index_t idx) MOODYCAMEL_NOEXCEPT { return static_cast<T*>(static_cast<void*>(elements)) + static_cast<size_t>(idx & static_cast<index_t>(BLOCK_SIZE - 1)); }\n\t\tinline T const* operator[](index_t idx) const MOODYCAMEL_NOEXCEPT { return static_cast<T const*>(static_cast<void const*>(elements)) + static_cast<size_t>(idx & static_cast<index_t>(BLOCK_SIZE - 1)); }\n\t\t\n\tprivate:\n\t\tstatic_assert(std::alignment_of<T>::value <= sizeof(T), \"The queue does not support types with an alignment greater than their size at this time\");\n\t\tMOODYCAMEL_ALIGNED_TYPE_LIKE(char[sizeof(T) * BLOCK_SIZE], T) elements;\n\tpublic:\n\t\tBlock* next;\n\t\tstd::atomic<size_t> elementsCompletelyDequeued;\n\t\tstd::atomic<bool> emptyFlags[BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD ? BLOCK_SIZE : 1];\n\tpublic:\n\t\tstd::atomic<std::uint32_t> freeListRefs;\n\t\tstd::atomic<Block*> freeListNext;\n\t\tbool dynamicallyAllocated;\t\t// Perhaps a better name for this would be 'isNotPartOfInitialBlockPool'\n\t\t\n#ifdef MCDBGQ_TRACKMEM\n\t\tvoid* owner;\n#endif\n\t};\n\tstatic_assert(std::alignment_of<Block>::value >= std::alignment_of<T>::value, \"Internal error: Blocks must be at least as aligned as the type they are wrapping\");\n\n\n#ifdef MCDBGQ_TRACKMEM\npublic:\n\tstruct MemStats;\nprivate:\n#endif\n\t\n\t///////////////////////////\n\t// Producer base\n\t///////////////////////////\n\t\n\tstruct ProducerBase : public details::ConcurrentQueueProducerTypelessBase\n\t{\n\t\tProducerBase(ConcurrentQueue* parent_, bool isExplicit_) :\n\t\t\ttailIndex(0),\n\t\t\theadIndex(0),\n\t\t\tdequeueOptimisticCount(0),\n\t\t\tdequeueOvercommit(0),\n\t\t\ttailBlock(nullptr),\n\t\t\tisExplicit(isExplicit_),\n\t\t\tparent(parent_)\n\t\t{\n\t\t}\n\t\t\n\t\tvirtual ~ProducerBase() { }\n\t\t\n\t\ttemplate<typename U>\n\t\tinline bool dequeue(U& element)\n\t\t{\n\t\t\tif (isExplicit) {\n\t\t\t\treturn static_cast<ExplicitProducer*>(this)->dequeue(element);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn static_cast<ImplicitProducer*>(this)->dequeue(element);\n\t\t\t}\n\t\t}\n\t\t\n\t\ttemplate<typename It>\n\t\tinline size_t dequeue_bulk(It& itemFirst, size_t max)\n\t\t{\n\t\t\tif (isExplicit) {\n\t\t\t\treturn static_cast<ExplicitProducer*>(this)->dequeue_bulk(itemFirst, max);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn static_cast<ImplicitProducer*>(this)->dequeue_bulk(itemFirst, max);\n\t\t\t}\n\t\t}\n\t\t\n\t\tinline ProducerBase* next_prod() const { return static_cast<ProducerBase*>(next); }\n\t\t\n\t\tinline size_t size_approx() const\n\t\t{\n\t\t\tauto tail = tailIndex.load(std::memory_order_relaxed);\n\t\t\tauto head = headIndex.load(std::memory_order_relaxed);\n\t\t\treturn details::circular_less_than(head, tail) ? static_cast<size_t>(tail - head) : 0;\n\t\t}\n\t\t\n\t\tinline index_t getTail() const { return tailIndex.load(std::memory_order_relaxed); }\n\tprotected:\n\t\tstd::atomic<index_t> tailIndex;\t\t// Where to enqueue to next\n\t\tstd::atomic<index_t> headIndex;\t\t// Where to dequeue from next\n\t\t\n\t\tstd::atomic<index_t> dequeueOptimisticCount;\n\t\tstd::atomic<index_t> dequeueOvercommit;\n\t\t\n\t\tBlock* tailBlock;\n\t\t\n\tpublic:\n\t\tbool isExplicit;\n\t\tConcurrentQueue* parent;\n\t\t\n\tprotected:\n#ifdef MCDBGQ_TRACKMEM\n\t\tfriend struct MemStats;\n#endif\n\t};\n\t\n\t\n\t///////////////////////////\n\t// Explicit queue\n\t///////////////////////////\n\t\t\n\tstruct ExplicitProducer : public ProducerBase\n\t{\n\t\texplicit ExplicitProducer(ConcurrentQueue* parent_) :\n\t\t\tProducerBase(parent_, true),\n\t\t\tblockIndex(nullptr),\n\t\t\tpr_blockIndexSlotsUsed(0),\n\t\t\tpr_blockIndexSize(EXPLICIT_INITIAL_INDEX_SIZE >> 1),\n\t\t\tpr_blockIndexFront(0),\n\t\t\tpr_blockIndexEntries(nullptr),\n\t\t\tpr_blockIndexRaw(nullptr)\n\t\t{\n\t\t\tsize_t poolBasedIndexSize = details::ceil_to_pow_2(parent_->initialBlockPoolSize) >> 1;\n\t\t\tif (poolBasedIndexSize > pr_blockIndexSize) {\n\t\t\t\tpr_blockIndexSize = poolBasedIndexSize;\n\t\t\t}\n\t\t\t\n\t\t\tnew_block_index(0);\t\t// This creates an index with double the number of current entries, i.e. EXPLICIT_INITIAL_INDEX_SIZE\n\t\t}\n\t\t\n\t\t~ExplicitProducer()\n\t\t{\n\t\t\t// Destruct any elements not yet dequeued.\n\t\t\t// Since we're in the destructor, we can assume all elements\n\t\t\t// are either completely dequeued or completely not (no halfways).\n\t\t\tif (this->tailBlock != nullptr) {\t\t// Note this means there must be a block index too\n\t\t\t\t// First find the block that's partially dequeued, if any\n\t\t\t\tBlock* halfDequeuedBlock = nullptr;\n\t\t\t\tif ((this->headIndex.load(std::memory_order_relaxed) & static_cast<index_t>(BLOCK_SIZE - 1)) != 0) {\n\t\t\t\t\t// The head's not on a block boundary, meaning a block somewhere is partially dequeued\n\t\t\t\t\t// (or the head block is the tail block and was fully dequeued, but the head/tail are still not on a boundary)\n\t\t\t\t\tsize_t i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & (pr_blockIndexSize - 1);\n\t\t\t\t\twhile (details::circular_less_than<index_t>(pr_blockIndexEntries[i].base + BLOCK_SIZE, this->headIndex.load(std::memory_order_relaxed))) {\n\t\t\t\t\t\ti = (i + 1) & (pr_blockIndexSize - 1);\n\t\t\t\t\t}\n\t\t\t\t\tassert(details::circular_less_than<index_t>(pr_blockIndexEntries[i].base, this->headIndex.load(std::memory_order_relaxed)));\n\t\t\t\t\thalfDequeuedBlock = pr_blockIndexEntries[i].block;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Start at the head block (note the first line in the loop gives us the head from the tail on the first iteration)\n\t\t\t\tauto block = this->tailBlock;\n\t\t\t\tdo {\n\t\t\t\t\tblock = block->next;\n\t\t\t\t\tif (block->ConcurrentQueue::Block::template is_empty<explicit_context>()) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tsize_t i = 0;\t// Offset into block\n\t\t\t\t\tif (block == halfDequeuedBlock) {\n\t\t\t\t\t\ti = static_cast<size_t>(this->headIndex.load(std::memory_order_relaxed) & static_cast<index_t>(BLOCK_SIZE - 1));\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Walk through all the items in the block; if this is the tail block, we need to stop when we reach the tail index\n\t\t\t\t\tauto lastValidIndex = (this->tailIndex.load(std::memory_order_relaxed) & static_cast<index_t>(BLOCK_SIZE - 1)) == 0 ? BLOCK_SIZE : static_cast<size_t>(this->tailIndex.load(std::memory_order_relaxed) & static_cast<index_t>(BLOCK_SIZE - 1));\n\t\t\t\t\twhile (i != BLOCK_SIZE && (block != this->tailBlock || i != lastValidIndex)) {\n\t\t\t\t\t\t(*block)[i++]->~T();\n\t\t\t\t\t}\n\t\t\t\t} while (block != this->tailBlock);\n\t\t\t}\n\t\t\t\n\t\t\t// Destroy all blocks that we own\n\t\t\tif (this->tailBlock != nullptr) {\n\t\t\t\tauto block = this->tailBlock;\n\t\t\t\tdo {\n\t\t\t\t\tauto nextBlock = block->next;\n\t\t\t\t\tthis->parent->add_block_to_free_list(block);\n\t\t\t\t\tblock = nextBlock;\n\t\t\t\t} while (block != this->tailBlock);\n\t\t\t}\n\t\t\t\n\t\t\t// Destroy the block indices\n\t\t\tauto header = static_cast<BlockIndexHeader*>(pr_blockIndexRaw);\n\t\t\twhile (header != nullptr) {\n\t\t\t\tauto prev = static_cast<BlockIndexHeader*>(header->prev);\n\t\t\t\theader->~BlockIndexHeader();\n\t\t\t\t(Traits::free)(header);\n\t\t\t\theader = prev;\n\t\t\t}\n\t\t}\n\t\t\n\t\ttemplate<AllocationMode allocMode, typename U>\n\t\tinline bool enqueue(U&& element)\n\t\t{\n\t\t\tindex_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed);\n\t\t\tindex_t newTailIndex = 1 + currentTailIndex;\n\t\t\tif ((currentTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0) {\n\t\t\t\t// We reached the end of a block, start a new one\n\t\t\t\tauto startBlock = this->tailBlock;\n\t\t\t\tauto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed;\n\t\t\t\tif (this->tailBlock != nullptr && this->tailBlock->next->ConcurrentQueue::Block::template is_empty<explicit_context>()) {\n\t\t\t\t\t// We can re-use the block ahead of us, it's empty!\t\t\t\t\t\n\t\t\t\t\tthis->tailBlock = this->tailBlock->next;\n\t\t\t\t\tthis->tailBlock->ConcurrentQueue::Block::template reset_empty<explicit_context>();\n\t\t\t\t\t\n\t\t\t\t\t// We'll put the block on the block index (guaranteed to be room since we're conceptually removing the\n\t\t\t\t\t// last block from it first -- except instead of removing then adding, we can just overwrite).\n\t\t\t\t\t// Note that there must be a valid block index here, since even if allocation failed in the ctor,\n\t\t\t\t\t// it would have been re-attempted when adding the first block to the queue; since there is such\n\t\t\t\t\t// a block, a block index must have been successfully allocated.\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Whatever head value we see here is >= the last value we saw here (relatively),\n\t\t\t\t\t// and <= its current value. Since we have the most recent tail, the head must be\n\t\t\t\t\t// <= to it.\n\t\t\t\t\tauto head = this->headIndex.load(std::memory_order_relaxed);\n\t\t\t\t\tassert(!details::circular_less_than<index_t>(currentTailIndex, head));\n\t\t\t\t\tif (!details::circular_less_than<index_t>(head, currentTailIndex + BLOCK_SIZE)\n\t\t\t\t\t\t|| (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) {\n\t\t\t\t\t\t// We can't enqueue in another block because there's not enough leeway -- the\n\t\t\t\t\t\t// tail could surpass the head by the time the block fills up! (Or we'll exceed\n\t\t\t\t\t\t// the size limit, if the second part of the condition was true.)\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// We're going to need a new block; check that the block index has room\n\t\t\t\t\tif (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize) {\n\t\t\t\t\t\t// Hmm, the circular block index is already full -- we'll need\n\t\t\t\t\t\t// to allocate a new index. Note pr_blockIndexRaw can only be nullptr if\n\t\t\t\t\t\t// the initial allocation failed in the constructor.\n\t\t\t\t\t\t\n\t\t\t\t\t\tMOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (!new_block_index(pr_blockIndexSlotsUsed)) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Insert a new block in the circular linked list\n\t\t\t\t\tauto newBlock = this->parent->ConcurrentQueue::template requisition_block<allocMode>();\n\t\t\t\t\tif (newBlock == nullptr) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n#ifdef MCDBGQ_TRACKMEM\n\t\t\t\t\tnewBlock->owner = this;\n#endif\n\t\t\t\t\tnewBlock->ConcurrentQueue::Block::template reset_empty<explicit_context>();\n\t\t\t\t\tif (this->tailBlock == nullptr) {\n\t\t\t\t\t\tnewBlock->next = newBlock;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tnewBlock->next = this->tailBlock->next;\n\t\t\t\t\t\tthis->tailBlock->next = newBlock;\n\t\t\t\t\t}\n\t\t\t\t\tthis->tailBlock = newBlock;\n\t\t\t\t\t++pr_blockIndexSlotsUsed;\n\t\t\t\t}\n\n\t\t\t\tMOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast<T*>(nullptr)) T(std::forward<U>(element)))) {\n\t\t\t\t\t// The constructor may throw. We want the element not to appear in the queue in\n\t\t\t\t\t// that case (without corrupting the queue):\n\t\t\t\t\tMOODYCAMEL_TRY {\n\t\t\t\t\t\tnew ((*this->tailBlock)[currentTailIndex]) T(std::forward<U>(element));\n\t\t\t\t\t}\n\t\t\t\t\tMOODYCAMEL_CATCH (...) {\n\t\t\t\t\t\t// Revert change to the current block, but leave the new block available\n\t\t\t\t\t\t// for next time\n\t\t\t\t\t\tpr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed;\n\t\t\t\t\t\tthis->tailBlock = startBlock == nullptr ? this->tailBlock : startBlock;\n\t\t\t\t\t\tMOODYCAMEL_RETHROW;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t(void)startBlock;\n\t\t\t\t\t(void)originalBlockIndexSlotsUsed;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Add block to block index\n\t\t\t\tauto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront];\n\t\t\t\tentry.base = currentTailIndex;\n\t\t\t\tentry.block = this->tailBlock;\n\t\t\t\tblockIndex.load(std::memory_order_relaxed)->front.store(pr_blockIndexFront, std::memory_order_release);\n\t\t\t\tpr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1);\n\t\t\t\t\n\t\t\t\tMOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast<T*>(nullptr)) T(std::forward<U>(element)))) {\n\t\t\t\t\tthis->tailIndex.store(newTailIndex, std::memory_order_release);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Enqueue\n\t\t\tnew ((*this->tailBlock)[currentTailIndex]) T(std::forward<U>(element));\n\t\t\t\n\t\t\tthis->tailIndex.store(newTailIndex, std::memory_order_release);\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\ttemplate<typename U>\n\t\tbool dequeue(U& element)\n\t\t{\n\t\t\tauto tail = this->tailIndex.load(std::memory_order_relaxed);\n\t\t\tauto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed);\n\t\t\tif (details::circular_less_than<index_t>(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) {\n\t\t\t\t// Might be something to dequeue, let's give it a try\n\t\t\t\t\n\t\t\t\t// Note that this if is purely for performance purposes in the common case when the queue is\n\t\t\t\t// empty and the values are eventually consistent -- we may enter here spuriously.\n\t\t\t\t\n\t\t\t\t// Note that whatever the values of overcommit and tail are, they are not going to change (unless we\n\t\t\t\t// change them) and must be the same value at this point (inside the if) as when the if condition was\n\t\t\t\t// evaluated.\n\n\t\t\t\t// We insert an acquire fence here to synchronize-with the release upon incrementing dequeueOvercommit below.\n\t\t\t\t// This ensures that whatever the value we got loaded into overcommit, the load of dequeueOptisticCount in\n\t\t\t\t// the fetch_add below will result in a value at least as recent as that (and therefore at least as large).\n\t\t\t\t// Note that I believe a compiler (signal) fence here would be sufficient due to the nature of fetch_add (all\n\t\t\t\t// read-modify-write operations are guaranteed to work on the latest value in the modification order), but\n\t\t\t\t// unfortunately that can't be shown to be correct using only the C++11 standard.\n\t\t\t\t// See http://stackoverflow.com/questions/18223161/what-are-the-c11-memory-ordering-guarantees-in-this-corner-case\n\t\t\t\tstd::atomic_thread_fence(std::memory_order_acquire);\n\t\t\t\t\n\t\t\t\t// Increment optimistic counter, then check if it went over the boundary\n\t\t\t\tauto myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed);\n\t\t\t\t\n\t\t\t\t// Note that since dequeueOvercommit must be <= dequeueOptimisticCount (because dequeueOvercommit is only ever\n\t\t\t\t// incremented after dequeueOptimisticCount -- this is enforced in the `else` block below), and since we now\n\t\t\t\t// have a version of dequeueOptimisticCount that is at least as recent as overcommit (due to the release upon\n\t\t\t\t// incrementing dequeueOvercommit and the acquire above that synchronizes with it), overcommit <= myDequeueCount.\n\t\t\t\t// However, we can't assert this since both dequeueOptimisticCount and dequeueOvercommit may (independently)\n\t\t\t\t// overflow; in such a case, though, the logic still holds since the difference between the two is maintained.\n\t\t\t\t\n\t\t\t\t// Note that we reload tail here in case it changed; it will be the same value as before or greater, since\n\t\t\t\t// this load is sequenced after (happens after) the earlier load above. This is supported by read-read\n\t\t\t\t// coherency (as defined in the standard), explained here: http://en.cppreference.com/w/cpp/atomic/memory_order\n\t\t\t\ttail = this->tailIndex.load(std::memory_order_acquire);\n\t\t\t\tif ((details::likely)(details::circular_less_than<index_t>(myDequeueCount - overcommit, tail))) {\n\t\t\t\t\t// Guaranteed to be at least one element to dequeue!\n\t\t\t\t\t\n\t\t\t\t\t// Get the index. Note that since there's guaranteed to be at least one element, this\n\t\t\t\t\t// will never exceed tail. We need to do an acquire-release fence here since it's possible\n\t\t\t\t\t// that whatever condition got us to this point was for an earlier enqueued element (that\n\t\t\t\t\t// we already see the memory effects for), but that by the time we increment somebody else\n\t\t\t\t\t// has incremented it, and we need to see the memory effects for *that* element, which is\n\t\t\t\t\t// in such a case is necessarily visible on the thread that incremented it in the first\n\t\t\t\t\t// place with the more current condition (they must have acquired a tail that is at least\n\t\t\t\t\t// as recent).\n\t\t\t\t\tauto index = this->headIndex.fetch_add(1, std::memory_order_acq_rel);\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t// Determine which block the element is in\n\t\t\t\t\t\n\t\t\t\t\tauto localBlockIndex = blockIndex.load(std::memory_order_acquire);\n\t\t\t\t\tauto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire);\n\t\t\t\t\t\n\t\t\t\t\t// We need to be careful here about subtracting and dividing because of index wrap-around.\n\t\t\t\t\t// When an index wraps, we need to preserve the sign of the offset when dividing it by the\n\t\t\t\t\t// block size (in order to get a correct signed block count offset in all cases):\n\t\t\t\t\tauto headBase = localBlockIndex->entries[localBlockIndexHead].base;\n\t\t\t\t\tauto blockBaseIndex = index & ~static_cast<index_t>(BLOCK_SIZE - 1);\n\t\t\t\t\tauto offset = static_cast<size_t>(static_cast<typename std::make_signed<index_t>::type>(blockBaseIndex - headBase) / static_cast<typename std::make_signed<index_t>::type>(BLOCK_SIZE));\n\t\t\t\t\tauto block = localBlockIndex->entries[(localBlockIndexHead + offset) & (localBlockIndex->size - 1)].block;\n\t\t\t\t\t\n\t\t\t\t\t// Dequeue\n\t\t\t\t\tauto& el = *((*block)[index]);\n\t\t\t\t\tif (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) {\n\t\t\t\t\t\t// Make sure the element is still fully dequeued and destroyed even if the assignment\n\t\t\t\t\t\t// throws\n\t\t\t\t\t\tstruct Guard {\n\t\t\t\t\t\t\tBlock* block;\n\t\t\t\t\t\t\tindex_t index;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t~Guard()\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t(*block)[index]->~T();\n\t\t\t\t\t\t\t\tblock->ConcurrentQueue::Block::template set_empty<explicit_context>(index);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} guard = { block, index };\n\n\t\t\t\t\t\telement = std::move(el); // NOLINT\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\telement = std::move(el); // NOLINT\n\t\t\t\t\t\tel.~T(); // NOLINT\n\t\t\t\t\t\tblock->ConcurrentQueue::Block::template set_empty<explicit_context>(index);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent\n\t\t\t\t\tthis->dequeueOvercommit.fetch_add(1, std::memory_order_release);\t\t// Release so that the fetch_add on dequeueOptimisticCount is guaranteed to happen before this write\n\t\t\t\t}\n\t\t\t}\n\t\t\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\ttemplate<AllocationMode allocMode, typename It>\n\t\tbool MOODYCAMEL_NO_TSAN enqueue_bulk(It itemFirst, size_t count)\n\t\t{\n\t\t\t// First, we need to make sure we have enough room to enqueue all of the elements;\n\t\t\t// this means pre-allocating blocks and putting them in the block index (but only if\n\t\t\t// all the allocations succeeded).\n\t\t\tindex_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed);\n\t\t\tauto startBlock = this->tailBlock;\n\t\t\tauto originalBlockIndexFront = pr_blockIndexFront;\n\t\t\tauto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed;\n\t\t\t\n\t\t\tBlock* firstAllocatedBlock = nullptr;\n\t\t\t\n\t\t\t// Figure out how many blocks we'll need to allocate, and do so\n\t\t\tsize_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1));\n\t\t\tindex_t currentTailIndex = (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1);\n\t\t\tif (blockBaseDiff > 0) {\n\t\t\t\t// Allocate as many blocks as possible from ahead\n\t\t\t\twhile (blockBaseDiff > 0 && this->tailBlock != nullptr && this->tailBlock->next != firstAllocatedBlock && this->tailBlock->next->ConcurrentQueue::Block::template is_empty<explicit_context>()) {\n\t\t\t\t\tblockBaseDiff -= static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\tcurrentTailIndex += static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\t\n\t\t\t\t\tthis->tailBlock = this->tailBlock->next;\n\t\t\t\t\tfirstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock;\n\t\t\t\t\t\n\t\t\t\t\tauto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront];\n\t\t\t\t\tentry.base = currentTailIndex;\n\t\t\t\t\tentry.block = this->tailBlock;\n\t\t\t\t\tpr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Now allocate as many blocks as necessary from the block pool\n\t\t\t\twhile (blockBaseDiff > 0) {\n\t\t\t\t\tblockBaseDiff -= static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\tcurrentTailIndex += static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\t\n\t\t\t\t\tauto head = this->headIndex.load(std::memory_order_relaxed);\n\t\t\t\t\tassert(!details::circular_less_than<index_t>(currentTailIndex, head));\n\t\t\t\t\tbool full = !details::circular_less_than<index_t>(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head));\n\t\t\t\t\tif (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize || full) {\n\t\t\t\t\t\tMOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) {\n\t\t\t\t\t\t\t// Failed to allocate, undo changes (but keep injected blocks)\n\t\t\t\t\t\t\tpr_blockIndexFront = originalBlockIndexFront;\n\t\t\t\t\t\t\tpr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed;\n\t\t\t\t\t\t\tthis->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock;\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (full || !new_block_index(originalBlockIndexSlotsUsed)) {\n\t\t\t\t\t\t\t// Failed to allocate, undo changes (but keep injected blocks)\n\t\t\t\t\t\t\tpr_blockIndexFront = originalBlockIndexFront;\n\t\t\t\t\t\t\tpr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed;\n\t\t\t\t\t\t\tthis->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock;\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// pr_blockIndexFront is updated inside new_block_index, so we need to\n\t\t\t\t\t\t// update our fallback value too (since we keep the new index even if we\n\t\t\t\t\t\t// later fail)\n\t\t\t\t\t\toriginalBlockIndexFront = originalBlockIndexSlotsUsed;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Insert a new block in the circular linked list\n\t\t\t\t\tauto newBlock = this->parent->ConcurrentQueue::template requisition_block<allocMode>();\n\t\t\t\t\tif (newBlock == nullptr) {\n\t\t\t\t\t\tpr_blockIndexFront = originalBlockIndexFront;\n\t\t\t\t\t\tpr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed;\n\t\t\t\t\t\tthis->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t\n#ifdef MCDBGQ_TRACKMEM\n\t\t\t\t\tnewBlock->owner = this;\n#endif\n\t\t\t\t\tnewBlock->ConcurrentQueue::Block::template set_all_empty<explicit_context>();\n\t\t\t\t\tif (this->tailBlock == nullptr) {\n\t\t\t\t\t\tnewBlock->next = newBlock;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tnewBlock->next = this->tailBlock->next;\n\t\t\t\t\t\tthis->tailBlock->next = newBlock;\n\t\t\t\t\t}\n\t\t\t\t\tthis->tailBlock = newBlock;\n\t\t\t\t\tfirstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock;\n\t\t\t\t\t\n\t\t\t\t\t++pr_blockIndexSlotsUsed;\n\t\t\t\t\t\n\t\t\t\t\tauto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront];\n\t\t\t\t\tentry.base = currentTailIndex;\n\t\t\t\t\tentry.block = this->tailBlock;\n\t\t\t\t\tpr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Excellent, all allocations succeeded. Reset each block's emptiness before we fill them up, and\n\t\t\t\t// publish the new block index front\n\t\t\t\tauto block = firstAllocatedBlock;\n\t\t\t\twhile (true) {\n\t\t\t\t\tblock->ConcurrentQueue::Block::template reset_empty<explicit_context>();\n\t\t\t\t\tif (block == this->tailBlock) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tblock = block->next;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tMOODYCAMEL_CONSTEXPR_IF (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast<T*>(nullptr)) T(details::deref_noexcept(itemFirst)))) {\n\t\t\t\t\tblockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Enqueue, one block at a time\n\t\t\tindex_t newTailIndex = startTailIndex + static_cast<index_t>(count);\n\t\t\tcurrentTailIndex = startTailIndex;\n\t\t\tauto endBlock = this->tailBlock;\n\t\t\tthis->tailBlock = startBlock;\n\t\t\tassert((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0);\n\t\t\tif ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) {\n\t\t\t\tthis->tailBlock = firstAllocatedBlock;\n\t\t\t}\n\t\t\twhile (true) {\n\t\t\t\tindex_t stopIndex = (currentTailIndex & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\tif (details::circular_less_than<index_t>(newTailIndex, stopIndex)) {\n\t\t\t\t\tstopIndex = newTailIndex;\n\t\t\t\t}\n\t\t\t\tMOODYCAMEL_CONSTEXPR_IF (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast<T*>(nullptr)) T(details::deref_noexcept(itemFirst)))) {\n\t\t\t\t\twhile (currentTailIndex != stopIndex) {\n\t\t\t\t\t\tnew ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tMOODYCAMEL_TRY {\n\t\t\t\t\t\twhile (currentTailIndex != stopIndex) {\n\t\t\t\t\t\t\t// Must use copy constructor even if move constructor is available\n\t\t\t\t\t\t\t// because we may have to revert if there's an exception.\n\t\t\t\t\t\t\t// Sorry about the horrible templated next line, but it was the only way\n\t\t\t\t\t\t\t// to disable moving *at compile time*, which is important because a type\n\t\t\t\t\t\t\t// may only define a (noexcept) move constructor, and so calls to the\n\t\t\t\t\t\t\t// cctor will not compile, even if they are in an if branch that will never\n\t\t\t\t\t\t\t// be executed\n\t\t\t\t\t\t\tnew ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if<!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast<T*>(nullptr)) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst));\n\t\t\t\t\t\t\t++currentTailIndex;\n\t\t\t\t\t\t\t++itemFirst;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tMOODYCAMEL_CATCH (...) {\n\t\t\t\t\t\t// Oh dear, an exception's been thrown -- destroy the elements that\n\t\t\t\t\t\t// were enqueued so far and revert the entire bulk operation (we'll keep\n\t\t\t\t\t\t// any allocated blocks in our linked list for later, though).\n\t\t\t\t\t\tauto constructedStopIndex = currentTailIndex;\n\t\t\t\t\t\tauto lastBlockEnqueued = this->tailBlock;\n\t\t\t\t\t\t\n\t\t\t\t\t\tpr_blockIndexFront = originalBlockIndexFront;\n\t\t\t\t\t\tpr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed;\n\t\t\t\t\t\tthis->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!details::is_trivially_destructible<T>::value) {\n\t\t\t\t\t\t\tauto block = startBlock;\n\t\t\t\t\t\t\tif ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0) {\n\t\t\t\t\t\t\t\tblock = firstAllocatedBlock;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcurrentTailIndex = startTailIndex;\n\t\t\t\t\t\t\twhile (true) {\n\t\t\t\t\t\t\t\tstopIndex = (currentTailIndex & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\t\t\t\tif (details::circular_less_than<index_t>(constructedStopIndex, stopIndex)) {\n\t\t\t\t\t\t\t\t\tstopIndex = constructedStopIndex;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\twhile (currentTailIndex != stopIndex) {\n\t\t\t\t\t\t\t\t\t(*block)[currentTailIndex++]->~T();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (block == lastBlockEnqueued) {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tblock = block->next;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tMOODYCAMEL_RETHROW;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (this->tailBlock == endBlock) {\n\t\t\t\t\tassert(currentTailIndex == newTailIndex);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tthis->tailBlock = this->tailBlock->next;\n\t\t\t}\n\t\t\t\n\t\t\tMOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast<T*>(nullptr)) T(details::deref_noexcept(itemFirst)))) {\n\t\t\t\tif (firstAllocatedBlock != nullptr)\n\t\t\t\t\tblockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release);\n\t\t\t}\n\t\t\t\n\t\t\tthis->tailIndex.store(newTailIndex, std::memory_order_release);\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\ttemplate<typename It>\n\t\tsize_t dequeue_bulk(It& itemFirst, size_t max)\n\t\t{\n\t\t\tauto tail = this->tailIndex.load(std::memory_order_relaxed);\n\t\t\tauto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed);\n\t\t\tauto desiredCount = static_cast<size_t>(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit));\n\t\t\tif (details::circular_less_than<size_t>(0, desiredCount)) {\n\t\t\t\tdesiredCount = desiredCount < max ? desiredCount : max;\n\t\t\t\tstd::atomic_thread_fence(std::memory_order_acquire);\n\t\t\t\t\n\t\t\t\tauto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed);\n\t\t\t\t\n\t\t\t\ttail = this->tailIndex.load(std::memory_order_acquire);\n\t\t\t\tauto actualCount = static_cast<size_t>(tail - (myDequeueCount - overcommit));\n\t\t\t\tif (details::circular_less_than<size_t>(0, actualCount)) {\n\t\t\t\t\tactualCount = desiredCount < actualCount ? desiredCount : actualCount;\n\t\t\t\t\tif (actualCount < desiredCount) {\n\t\t\t\t\t\tthis->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Get the first index. Note that since there's guaranteed to be at least actualCount elements, this\n\t\t\t\t\t// will never exceed tail.\n\t\t\t\t\tauto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel);\n\t\t\t\t\t\n\t\t\t\t\t// Determine which block the first element is in\n\t\t\t\t\tauto localBlockIndex = blockIndex.load(std::memory_order_acquire);\n\t\t\t\t\tauto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire);\n\t\t\t\t\t\n\t\t\t\t\tauto headBase = localBlockIndex->entries[localBlockIndexHead].base;\n\t\t\t\t\tauto firstBlockBaseIndex = firstIndex & ~static_cast<index_t>(BLOCK_SIZE - 1);\n\t\t\t\t\tauto offset = static_cast<size_t>(static_cast<typename std::make_signed<index_t>::type>(firstBlockBaseIndex - headBase) / static_cast<typename std::make_signed<index_t>::type>(BLOCK_SIZE));\n\t\t\t\t\tauto indexIndex = (localBlockIndexHead + offset) & (localBlockIndex->size - 1);\n\t\t\t\t\t\n\t\t\t\t\t// Iterate the blocks and dequeue\n\t\t\t\t\tauto index = firstIndex;\n\t\t\t\t\tdo {\n\t\t\t\t\t\tauto firstIndexInBlock = index;\n\t\t\t\t\t\tindex_t endIndex = (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\t\tendIndex = details::circular_less_than<index_t>(firstIndex + static_cast<index_t>(actualCount), endIndex) ? firstIndex + static_cast<index_t>(actualCount) : endIndex;\n\t\t\t\t\t\tauto block = localBlockIndex->entries[indexIndex].block;\n\t\t\t\t\t\tif (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) {\n\t\t\t\t\t\t\twhile (index != endIndex) {\n\t\t\t\t\t\t\t\tauto& el = *((*block)[index]);\n\t\t\t\t\t\t\t\t*itemFirst++ = std::move(el);\n\t\t\t\t\t\t\t\tel.~T();\n\t\t\t\t\t\t\t\t++index;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tMOODYCAMEL_TRY {\n\t\t\t\t\t\t\t\twhile (index != endIndex) {\n\t\t\t\t\t\t\t\t\tauto& el = *((*block)[index]);\n\t\t\t\t\t\t\t\t\t*itemFirst = std::move(el);\n\t\t\t\t\t\t\t\t\t++itemFirst;\n\t\t\t\t\t\t\t\t\tel.~T();\n\t\t\t\t\t\t\t\t\t++index;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tMOODYCAMEL_CATCH (...) {\n\t\t\t\t\t\t\t\t// It's too late to revert the dequeue, but we can make sure that all\n\t\t\t\t\t\t\t\t// the dequeued objects are properly destroyed and the block index\n\t\t\t\t\t\t\t\t// (and empty count) are properly updated before we propagate the exception\n\t\t\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t\t\tblock = localBlockIndex->entries[indexIndex].block;\n\t\t\t\t\t\t\t\t\twhile (index != endIndex) {\n\t\t\t\t\t\t\t\t\t\t(*block)[index++]->~T();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tblock->ConcurrentQueue::Block::template set_many_empty<explicit_context>(firstIndexInBlock, static_cast<size_t>(endIndex - firstIndexInBlock));\n\t\t\t\t\t\t\t\t\tindexIndex = (indexIndex + 1) & (localBlockIndex->size - 1);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tfirstIndexInBlock = index;\n\t\t\t\t\t\t\t\t\tendIndex = (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\t\t\t\t\tendIndex = details::circular_less_than<index_t>(firstIndex + static_cast<index_t>(actualCount), endIndex) ? firstIndex + static_cast<index_t>(actualCount) : endIndex;\n\t\t\t\t\t\t\t\t} while (index != firstIndex + actualCount);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tMOODYCAMEL_RETHROW;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tblock->ConcurrentQueue::Block::template set_many_empty<explicit_context>(firstIndexInBlock, static_cast<size_t>(endIndex - firstIndexInBlock));\n\t\t\t\t\t\tindexIndex = (indexIndex + 1) & (localBlockIndex->size - 1);\n\t\t\t\t\t} while (index != firstIndex + actualCount);\n\t\t\t\t\t\n\t\t\t\t\treturn actualCount;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent\n\t\t\t\t\tthis->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn 0;\n\t\t}\n\t\t\n\tprivate:\n\t\tstruct BlockIndexEntry\n\t\t{\n\t\t\tindex_t base;\n\t\t\tBlock* block;\n\t\t};\n\t\t\n\t\tstruct BlockIndexHeader\n\t\t{\n\t\t\tsize_t size;\n\t\t\tstd::atomic<size_t> front;\t\t// Current slot (not next, like pr_blockIndexFront)\n\t\t\tBlockIndexEntry* entries;\n\t\t\tvoid* prev;\n\t\t};\n\t\t\n\t\t\n\t\tbool new_block_index(size_t numberOfFilledSlotsToExpose)\n\t\t{\n\t\t\tauto prevBlockSizeMask = pr_blockIndexSize - 1;\n\t\t\t\n\t\t\t// Create the new block\n\t\t\tpr_blockIndexSize <<= 1;\n\t\t\tauto newRawPtr = static_cast<char*>((Traits::malloc)(sizeof(BlockIndexHeader) + std::alignment_of<BlockIndexEntry>::value - 1 + sizeof(BlockIndexEntry) * pr_blockIndexSize));\n\t\t\tif (newRawPtr == nullptr) {\n\t\t\t\tpr_blockIndexSize >>= 1;\t\t// Reset to allow graceful retry\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tauto newBlockIndexEntries = reinterpret_cast<BlockIndexEntry*>(details::align_for<BlockIndexEntry>(newRawPtr + sizeof(BlockIndexHeader)));\n\t\t\t\n\t\t\t// Copy in all the old indices, if any\n\t\t\tsize_t j = 0;\n\t\t\tif (pr_blockIndexSlotsUsed != 0) {\n\t\t\t\tauto i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & prevBlockSizeMask;\n\t\t\t\tdo {\n\t\t\t\t\tnewBlockIndexEntries[j++] = pr_blockIndexEntries[i];\n\t\t\t\t\ti = (i + 1) & prevBlockSizeMask;\n\t\t\t\t} while (i != pr_blockIndexFront);\n\t\t\t}\n\t\t\t\n\t\t\t// Update everything\n\t\t\tauto header = new (newRawPtr) BlockIndexHeader;\n\t\t\theader->size = pr_blockIndexSize;\n\t\t\theader->front.store(numberOfFilledSlotsToExpose - 1, std::memory_order_relaxed);\n\t\t\theader->entries = newBlockIndexEntries;\n\t\t\theader->prev = pr_blockIndexRaw;\t\t// we link the new block to the old one so we can free it later\n\t\t\t\n\t\t\tpr_blockIndexFront = j;\n\t\t\tpr_blockIndexEntries = newBlockIndexEntries;\n\t\t\tpr_blockIndexRaw = newRawPtr;\n\t\t\tblockIndex.store(header, std::memory_order_release);\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\t\t\n\tprivate:\n\t\tstd::atomic<BlockIndexHeader*> blockIndex;\n\t\t\n\t\t// To be used by producer only -- consumer must use the ones in referenced by blockIndex\n\t\tsize_t pr_blockIndexSlotsUsed;\n\t\tsize_t pr_blockIndexSize;\n\t\tsize_t pr_blockIndexFront;\t\t// Next slot (not current)\n\t\tBlockIndexEntry* pr_blockIndexEntries;\n\t\tvoid* pr_blockIndexRaw;\n\t\t\n#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG\n\tpublic:\n\t\tExplicitProducer* nextExplicitProducer;\n\tprivate:\n#endif\n\t\t\n#ifdef MCDBGQ_TRACKMEM\n\t\tfriend struct MemStats;\n#endif\n\t};\n\t\n\t\n\t//////////////////////////////////\n\t// Implicit queue\n\t//////////////////////////////////\n\t\n\tstruct ImplicitProducer : public ProducerBase\n\t{\t\t\t\n\t\tImplicitProducer(ConcurrentQueue* parent_) :\n\t\t\tProducerBase(parent_, false),\n\t\t\tnextBlockIndexCapacity(IMPLICIT_INITIAL_INDEX_SIZE),\n\t\t\tblockIndex(nullptr)\n\t\t{\n\t\t\tnew_block_index();\n\t\t}\n\t\t\n\t\t~ImplicitProducer()\n\t\t{\n\t\t\t// Note that since we're in the destructor we can assume that all enqueue/dequeue operations\n\t\t\t// completed already; this means that all undequeued elements are placed contiguously across\n\t\t\t// contiguous blocks, and that only the first and last remaining blocks can be only partially\n\t\t\t// empty (all other remaining blocks must be completely full).\n\t\t\t\n#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED\n\t\t\t// Unregister ourselves for thread termination notification\n\t\t\tif (!this->inactive.load(std::memory_order_relaxed)) {\n\t\t\t\tdetails::ThreadExitNotifier::unsubscribe(&threadExitListener);\n\t\t\t}\n#endif\n\t\t\t\n\t\t\t// Destroy all remaining elements!\n\t\t\tauto tail = this->tailIndex.load(std::memory_order_relaxed);\n\t\t\tauto index = this->headIndex.load(std::memory_order_relaxed);\n\t\t\tBlock* block = nullptr;\n\t\t\tassert(index == tail || details::circular_less_than(index, tail));\n\t\t\tbool forceFreeLastBlock = index != tail;\t\t// If we enter the loop, then the last (tail) block will not be freed\n\t\t\twhile (index != tail) {\n\t\t\t\tif ((index & static_cast<index_t>(BLOCK_SIZE - 1)) == 0 || block == nullptr) {\n\t\t\t\t\tif (block != nullptr) {\n\t\t\t\t\t\t// Free the old block\n\t\t\t\t\t\tthis->parent->add_block_to_free_list(block);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tblock = get_block_index_entry_for_index(index)->value.load(std::memory_order_relaxed);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t((*block)[index])->~T();\n\t\t\t\t++index;\n\t\t\t}\n\t\t\t// Even if the queue is empty, there's still one block that's not on the free list\n\t\t\t// (unless the head index reached the end of it, in which case the tail will be poised\n\t\t\t// to create a new block).\n\t\t\tif (this->tailBlock != nullptr && (forceFreeLastBlock || (tail & static_cast<index_t>(BLOCK_SIZE - 1)) != 0)) {\n\t\t\t\tthis->parent->add_block_to_free_list(this->tailBlock);\n\t\t\t}\n\t\t\t\n\t\t\t// Destroy block index\n\t\t\tauto localBlockIndex = blockIndex.load(std::memory_order_relaxed);\n\t\t\tif (localBlockIndex != nullptr) {\n\t\t\t\tfor (size_t i = 0; i != localBlockIndex->capacity; ++i) {\n\t\t\t\t\tlocalBlockIndex->index[i]->~BlockIndexEntry();\n\t\t\t\t}\n\t\t\t\tdo {\n\t\t\t\t\tauto prev = localBlockIndex->prev;\n\t\t\t\t\tlocalBlockIndex->~BlockIndexHeader();\n\t\t\t\t\t(Traits::free)(localBlockIndex);\n\t\t\t\t\tlocalBlockIndex = prev;\n\t\t\t\t} while (localBlockIndex != nullptr);\n\t\t\t}\n\t\t}\n\t\t\n\t\ttemplate<AllocationMode allocMode, typename U>\n\t\tinline bool enqueue(U&& element)\n\t\t{\n\t\t\tindex_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed);\n\t\t\tindex_t newTailIndex = 1 + currentTailIndex;\n\t\t\tif ((currentTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0) {\n\t\t\t\t// We reached the end of a block, start a new one\n\t\t\t\tauto head = this->headIndex.load(std::memory_order_relaxed);\n\t\t\t\tassert(!details::circular_less_than<index_t>(currentTailIndex, head));\n\t\t\t\tif (!details::circular_less_than<index_t>(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX\n\t\t\t\tdebug::DebugLock lock(mutex);\n#endif\n\t\t\t\t// Find out where we'll be inserting this block in the block index\n\t\t\t\tBlockIndexEntry* idxEntry;\n\t\t\t\tif (!insert_block_index_entry<allocMode>(idxEntry, currentTailIndex)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Get ahold of a new block\n\t\t\t\tauto newBlock = this->parent->ConcurrentQueue::template requisition_block<allocMode>();\n\t\t\t\tif (newBlock == nullptr) {\n\t\t\t\t\trewind_block_index_tail();\n\t\t\t\t\tidxEntry->value.store(nullptr, std::memory_order_relaxed);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n#ifdef MCDBGQ_TRACKMEM\n\t\t\t\tnewBlock->owner = this;\n#endif\n\t\t\t\tnewBlock->ConcurrentQueue::Block::template reset_empty<implicit_context>();\n\n\t\t\t\tMOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast<T*>(nullptr)) T(std::forward<U>(element)))) {\n\t\t\t\t\t// May throw, try to insert now before we publish the fact that we have this new block\n\t\t\t\t\tMOODYCAMEL_TRY {\n\t\t\t\t\t\tnew ((*newBlock)[currentTailIndex]) T(std::forward<U>(element));\n\t\t\t\t\t}\n\t\t\t\t\tMOODYCAMEL_CATCH (...) {\n\t\t\t\t\t\trewind_block_index_tail();\n\t\t\t\t\t\tidxEntry->value.store(nullptr, std::memory_order_relaxed);\n\t\t\t\t\t\tthis->parent->add_block_to_free_list(newBlock);\n\t\t\t\t\t\tMOODYCAMEL_RETHROW;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Insert the new block into the index\n\t\t\t\tidxEntry->value.store(newBlock, std::memory_order_relaxed);\n\t\t\t\t\n\t\t\t\tthis->tailBlock = newBlock;\n\t\t\t\t\n\t\t\t\tMOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast<T*>(nullptr)) T(std::forward<U>(element)))) {\n\t\t\t\t\tthis->tailIndex.store(newTailIndex, std::memory_order_release);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Enqueue\n\t\t\tnew ((*this->tailBlock)[currentTailIndex]) T(std::forward<U>(element));\n\t\t\t\n\t\t\tthis->tailIndex.store(newTailIndex, std::memory_order_release);\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\ttemplate<typename U>\n\t\tbool dequeue(U& element)\n\t\t{\n\t\t\t// See ExplicitProducer::dequeue for rationale and explanation\n\t\t\tindex_t tail = this->tailIndex.load(std::memory_order_relaxed);\n\t\t\tindex_t overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed);\n\t\t\tif (details::circular_less_than<index_t>(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) {\n\t\t\t\tstd::atomic_thread_fence(std::memory_order_acquire);\n\t\t\t\t\n\t\t\t\tindex_t myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed);\n\t\t\t\ttail = this->tailIndex.load(std::memory_order_acquire);\n\t\t\t\tif ((details::likely)(details::circular_less_than<index_t>(myDequeueCount - overcommit, tail))) {\n\t\t\t\t\tindex_t index = this->headIndex.fetch_add(1, std::memory_order_acq_rel);\n\t\t\t\t\t\n\t\t\t\t\t// Determine which block the element is in\n\t\t\t\t\tauto entry = get_block_index_entry_for_index(index);\n\t\t\t\t\t\n\t\t\t\t\t// Dequeue\n\t\t\t\t\tauto block = entry->value.load(std::memory_order_relaxed);\n\t\t\t\t\tauto& el = *((*block)[index]);\n\t\t\t\t\t\n\t\t\t\t\tif (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) {\n#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX\n\t\t\t\t\t\t// Note: Acquiring the mutex with every dequeue instead of only when a block\n\t\t\t\t\t\t// is released is very sub-optimal, but it is, after all, purely debug code.\n\t\t\t\t\t\tdebug::DebugLock lock(producer->mutex);\n#endif\n\t\t\t\t\t\tstruct Guard {\n\t\t\t\t\t\t\tBlock* block;\n\t\t\t\t\t\t\tindex_t index;\n\t\t\t\t\t\t\tBlockIndexEntry* entry;\n\t\t\t\t\t\t\tConcurrentQueue* parent;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t~Guard()\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t(*block)[index]->~T();\n\t\t\t\t\t\t\t\tif (block->ConcurrentQueue::Block::template set_empty<implicit_context>(index)) {\n\t\t\t\t\t\t\t\t\tentry->value.store(nullptr, std::memory_order_relaxed);\n\t\t\t\t\t\t\t\t\tparent->add_block_to_free_list(block);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} guard = { block, index, entry, this->parent };\n\n\t\t\t\t\t\telement = std::move(el); // NOLINT\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\telement = std::move(el); // NOLINT\n\t\t\t\t\t\tel.~T(); // NOLINT\n\n\t\t\t\t\t\tif (block->ConcurrentQueue::Block::template set_empty<implicit_context>(index)) {\n\t\t\t\t\t\t\t{\n#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX\n\t\t\t\t\t\t\t\tdebug::DebugLock lock(mutex);\n#endif\n\t\t\t\t\t\t\t\t// Add the block back into the global free pool (and remove from block index)\n\t\t\t\t\t\t\t\tentry->value.store(nullptr, std::memory_order_relaxed);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis->parent->add_block_to_free_list(block);\t\t// releases the above store\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis->dequeueOvercommit.fetch_add(1, std::memory_order_release);\n\t\t\t\t}\n\t\t\t}\n\t\t\n\t\t\treturn false;\n\t\t}\n\t\t\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable: 4706)  // assignment within conditional expression\n#endif\n\t\ttemplate<AllocationMode allocMode, typename It>\n\t\tbool enqueue_bulk(It itemFirst, size_t count)\n\t\t{\n\t\t\t// First, we need to make sure we have enough room to enqueue all of the elements;\n\t\t\t// this means pre-allocating blocks and putting them in the block index (but only if\n\t\t\t// all the allocations succeeded).\n\t\t\t\n\t\t\t// Note that the tailBlock we start off with may not be owned by us any more;\n\t\t\t// this happens if it was filled up exactly to the top (setting tailIndex to\n\t\t\t// the first index of the next block which is not yet allocated), then dequeued\n\t\t\t// completely (putting it on the free list) before we enqueue again.\n\t\t\t\n\t\t\tindex_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed);\n\t\t\tauto startBlock = this->tailBlock;\n\t\t\tBlock* firstAllocatedBlock = nullptr;\n\t\t\tauto endBlock = this->tailBlock;\n\t\t\t\n\t\t\t// Figure out how many blocks we'll need to allocate, and do so\n\t\t\tsize_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1));\n\t\t\tindex_t currentTailIndex = (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1);\n\t\t\tif (blockBaseDiff > 0) {\n#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX\n\t\t\t\tdebug::DebugLock lock(mutex);\n#endif\n\t\t\t\tdo {\n\t\t\t\t\tblockBaseDiff -= static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\tcurrentTailIndex += static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\t\n\t\t\t\t\t// Find out where we'll be inserting this block in the block index\n\t\t\t\t\tBlockIndexEntry* idxEntry = nullptr;  // initialization here unnecessary but compiler can't always tell\n\t\t\t\t\tBlock* newBlock;\n\t\t\t\t\tbool indexInserted = false;\n\t\t\t\t\tauto head = this->headIndex.load(std::memory_order_relaxed);\n\t\t\t\t\tassert(!details::circular_less_than<index_t>(currentTailIndex, head));\n\t\t\t\t\tbool full = !details::circular_less_than<index_t>(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head));\n\n\t\t\t\t\tif (full || !(indexInserted = insert_block_index_entry<allocMode>(idxEntry, currentTailIndex)) || (newBlock = this->parent->ConcurrentQueue::template requisition_block<allocMode>()) == nullptr) {\n\t\t\t\t\t\t// Index allocation or block allocation failed; revert any other allocations\n\t\t\t\t\t\t// and index insertions done so far for this operation\n\t\t\t\t\t\tif (indexInserted) {\n\t\t\t\t\t\t\trewind_block_index_tail();\n\t\t\t\t\t\t\tidxEntry->value.store(nullptr, std::memory_order_relaxed);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcurrentTailIndex = (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1);\n\t\t\t\t\t\tfor (auto block = firstAllocatedBlock; block != nullptr; block = block->next) {\n\t\t\t\t\t\t\tcurrentTailIndex += static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\t\t\tidxEntry = get_block_index_entry_for_index(currentTailIndex);\n\t\t\t\t\t\t\tidxEntry->value.store(nullptr, std::memory_order_relaxed);\n\t\t\t\t\t\t\trewind_block_index_tail();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis->parent->add_blocks_to_free_list(firstAllocatedBlock);\n\t\t\t\t\t\tthis->tailBlock = startBlock;\n\t\t\t\t\t\t\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t\n#ifdef MCDBGQ_TRACKMEM\n\t\t\t\t\tnewBlock->owner = this;\n#endif\n\t\t\t\t\tnewBlock->ConcurrentQueue::Block::template reset_empty<implicit_context>();\n\t\t\t\t\tnewBlock->next = nullptr;\n\t\t\t\t\t\n\t\t\t\t\t// Insert the new block into the index\n\t\t\t\t\tidxEntry->value.store(newBlock, std::memory_order_relaxed);\n\t\t\t\t\t\n\t\t\t\t\t// Store the chain of blocks so that we can undo if later allocations fail,\n\t\t\t\t\t// and so that we can find the blocks when we do the actual enqueueing\n\t\t\t\t\tif ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr) {\n\t\t\t\t\t\tassert(this->tailBlock != nullptr);\n\t\t\t\t\t\tthis->tailBlock->next = newBlock;\n\t\t\t\t\t}\n\t\t\t\t\tthis->tailBlock = newBlock;\n\t\t\t\t\tendBlock = newBlock;\n\t\t\t\t\tfirstAllocatedBlock = firstAllocatedBlock == nullptr ? newBlock : firstAllocatedBlock;\n\t\t\t\t} while (blockBaseDiff > 0);\n\t\t\t}\n\t\t\t\n\t\t\t// Enqueue, one block at a time\n\t\t\tindex_t newTailIndex = startTailIndex + static_cast<index_t>(count);\n\t\t\tcurrentTailIndex = startTailIndex;\n\t\t\tthis->tailBlock = startBlock;\n\t\t\tassert((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0);\n\t\t\tif ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) {\n\t\t\t\tthis->tailBlock = firstAllocatedBlock;\n\t\t\t}\n\t\t\twhile (true) {\n\t\t\t\tindex_t stopIndex = (currentTailIndex & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\tif (details::circular_less_than<index_t>(newTailIndex, stopIndex)) {\n\t\t\t\t\tstopIndex = newTailIndex;\n\t\t\t\t}\n\t\t\t\tMOODYCAMEL_CONSTEXPR_IF (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast<T*>(nullptr)) T(details::deref_noexcept(itemFirst)))) {\n\t\t\t\t\twhile (currentTailIndex != stopIndex) {\n\t\t\t\t\t\tnew ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tMOODYCAMEL_TRY {\n\t\t\t\t\t\twhile (currentTailIndex != stopIndex) {\n\t\t\t\t\t\t\tnew ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if<!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast<T*>(nullptr)) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst));\n\t\t\t\t\t\t\t++currentTailIndex;\n\t\t\t\t\t\t\t++itemFirst;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tMOODYCAMEL_CATCH (...) {\n\t\t\t\t\t\tauto constructedStopIndex = currentTailIndex;\n\t\t\t\t\t\tauto lastBlockEnqueued = this->tailBlock;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!details::is_trivially_destructible<T>::value) {\n\t\t\t\t\t\t\tauto block = startBlock;\n\t\t\t\t\t\t\tif ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0) {\n\t\t\t\t\t\t\t\tblock = firstAllocatedBlock;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcurrentTailIndex = startTailIndex;\n\t\t\t\t\t\t\twhile (true) {\n\t\t\t\t\t\t\t\tstopIndex = (currentTailIndex & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\t\t\t\tif (details::circular_less_than<index_t>(constructedStopIndex, stopIndex)) {\n\t\t\t\t\t\t\t\t\tstopIndex = constructedStopIndex;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\twhile (currentTailIndex != stopIndex) {\n\t\t\t\t\t\t\t\t\t(*block)[currentTailIndex++]->~T();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (block == lastBlockEnqueued) {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tblock = block->next;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tcurrentTailIndex = (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1);\n\t\t\t\t\t\tfor (auto block = firstAllocatedBlock; block != nullptr; block = block->next) {\n\t\t\t\t\t\t\tcurrentTailIndex += static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\t\t\tauto idxEntry = get_block_index_entry_for_index(currentTailIndex);\n\t\t\t\t\t\t\tidxEntry->value.store(nullptr, std::memory_order_relaxed);\n\t\t\t\t\t\t\trewind_block_index_tail();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis->parent->add_blocks_to_free_list(firstAllocatedBlock);\n\t\t\t\t\t\tthis->tailBlock = startBlock;\n\t\t\t\t\t\tMOODYCAMEL_RETHROW;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (this->tailBlock == endBlock) {\n\t\t\t\t\tassert(currentTailIndex == newTailIndex);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tthis->tailBlock = this->tailBlock->next;\n\t\t\t}\n\t\t\tthis->tailIndex.store(newTailIndex, std::memory_order_release);\n\t\t\treturn true;\n\t\t}\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\t\t\n\t\ttemplate<typename It>\n\t\tsize_t dequeue_bulk(It& itemFirst, size_t max)\n\t\t{\n\t\t\tauto tail = this->tailIndex.load(std::memory_order_relaxed);\n\t\t\tauto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed);\n\t\t\tauto desiredCount = static_cast<size_t>(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit));\n\t\t\tif (details::circular_less_than<size_t>(0, desiredCount)) {\n\t\t\t\tdesiredCount = desiredCount < max ? desiredCount : max;\n\t\t\t\tstd::atomic_thread_fence(std::memory_order_acquire);\n\t\t\t\t\n\t\t\t\tauto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed);\n\t\t\t\t\n\t\t\t\ttail = this->tailIndex.load(std::memory_order_acquire);\n\t\t\t\tauto actualCount = static_cast<size_t>(tail - (myDequeueCount - overcommit));\n\t\t\t\tif (details::circular_less_than<size_t>(0, actualCount)) {\n\t\t\t\t\tactualCount = desiredCount < actualCount ? desiredCount : actualCount;\n\t\t\t\t\tif (actualCount < desiredCount) {\n\t\t\t\t\t\tthis->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Get the first index. Note that since there's guaranteed to be at least actualCount elements, this\n\t\t\t\t\t// will never exceed tail.\n\t\t\t\t\tauto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel);\n\t\t\t\t\t\n\t\t\t\t\t// Iterate the blocks and dequeue\n\t\t\t\t\tauto index = firstIndex;\n\t\t\t\t\tBlockIndexHeader* localBlockIndex;\n\t\t\t\t\tauto indexIndex = get_block_index_index_for_index(index, localBlockIndex);\n\t\t\t\t\tdo {\n\t\t\t\t\t\tauto blockStartIndex = index;\n\t\t\t\t\t\tindex_t endIndex = (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\t\tendIndex = details::circular_less_than<index_t>(firstIndex + static_cast<index_t>(actualCount), endIndex) ? firstIndex + static_cast<index_t>(actualCount) : endIndex;\n\t\t\t\t\t\t\n\t\t\t\t\t\tauto entry = localBlockIndex->index[indexIndex];\n\t\t\t\t\t\tauto block = entry->value.load(std::memory_order_relaxed);\n\t\t\t\t\t\tif (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) {\n\t\t\t\t\t\t\twhile (index != endIndex) {\n\t\t\t\t\t\t\t\tauto& el = *((*block)[index]);\n\t\t\t\t\t\t\t\t*itemFirst++ = std::move(el);\n\t\t\t\t\t\t\t\tel.~T();\n\t\t\t\t\t\t\t\t++index;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tMOODYCAMEL_TRY {\n\t\t\t\t\t\t\t\twhile (index != endIndex) {\n\t\t\t\t\t\t\t\t\tauto& el = *((*block)[index]);\n\t\t\t\t\t\t\t\t\t*itemFirst = std::move(el);\n\t\t\t\t\t\t\t\t\t++itemFirst;\n\t\t\t\t\t\t\t\t\tel.~T();\n\t\t\t\t\t\t\t\t\t++index;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tMOODYCAMEL_CATCH (...) {\n\t\t\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t\t\tentry = localBlockIndex->index[indexIndex];\n\t\t\t\t\t\t\t\t\tblock = entry->value.load(std::memory_order_relaxed);\n\t\t\t\t\t\t\t\t\twhile (index != endIndex) {\n\t\t\t\t\t\t\t\t\t\t(*block)[index++]->~T();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (block->ConcurrentQueue::Block::template set_many_empty<implicit_context>(blockStartIndex, static_cast<size_t>(endIndex - blockStartIndex))) {\n#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX\n\t\t\t\t\t\t\t\t\t\tdebug::DebugLock lock(mutex);\n#endif\n\t\t\t\t\t\t\t\t\t\tentry->value.store(nullptr, std::memory_order_relaxed);\n\t\t\t\t\t\t\t\t\t\tthis->parent->add_block_to_free_list(block);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tindexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tblockStartIndex = index;\n\t\t\t\t\t\t\t\t\tendIndex = (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\t\t\t\t\tendIndex = details::circular_less_than<index_t>(firstIndex + static_cast<index_t>(actualCount), endIndex) ? firstIndex + static_cast<index_t>(actualCount) : endIndex;\n\t\t\t\t\t\t\t\t} while (index != firstIndex + actualCount);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tMOODYCAMEL_RETHROW;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (block->ConcurrentQueue::Block::template set_many_empty<implicit_context>(blockStartIndex, static_cast<size_t>(endIndex - blockStartIndex))) {\n\t\t\t\t\t\t\t{\n#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX\n\t\t\t\t\t\t\t\tdebug::DebugLock lock(mutex);\n#endif\n\t\t\t\t\t\t\t\t// Note that the set_many_empty above did a release, meaning that anybody who acquires the block\n\t\t\t\t\t\t\t\t// we're about to free can use it safely since our writes (and reads!) will have happened-before then.\n\t\t\t\t\t\t\t\tentry->value.store(nullptr, std::memory_order_relaxed);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis->parent->add_block_to_free_list(block);\t\t// releases the above store\n\t\t\t\t\t\t}\n\t\t\t\t\t\tindexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1);\n\t\t\t\t\t} while (index != firstIndex + actualCount);\n\t\t\t\t\t\n\t\t\t\t\treturn actualCount;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn 0;\n\t\t}\n\t\t\n\tprivate:\n\t\t// The block size must be > 1, so any number with the low bit set is an invalid block base index\n\t\tstatic const index_t INVALID_BLOCK_BASE = 1;\n\t\t\n\t\tstruct BlockIndexEntry\n\t\t{\n\t\t\tstd::atomic<index_t> key;\n\t\t\tstd::atomic<Block*> value;\n\t\t};\n\t\t\n\t\tstruct BlockIndexHeader\n\t\t{\n\t\t\tsize_t capacity;\n\t\t\tstd::atomic<size_t> tail;\n\t\t\tBlockIndexEntry* entries;\n\t\t\tBlockIndexEntry** index;\n\t\t\tBlockIndexHeader* prev;\n\t\t};\n\t\t\n\t\ttemplate<AllocationMode allocMode>\n\t\tinline bool insert_block_index_entry(BlockIndexEntry*& idxEntry, index_t blockStartIndex)\n\t\t{\n\t\t\tauto localBlockIndex = blockIndex.load(std::memory_order_relaxed);\t\t// We're the only writer thread, relaxed is OK\n\t\t\tif (localBlockIndex == nullptr) {\n\t\t\t\treturn false;  // this can happen if new_block_index failed in the constructor\n\t\t\t}\n\t\t\tsize_t newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1);\n\t\t\tidxEntry = localBlockIndex->index[newTail];\n\t\t\tif (idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE ||\n\t\t\t\tidxEntry->value.load(std::memory_order_relaxed) == nullptr) {\n\t\t\t\t\n\t\t\t\tidxEntry->key.store(blockStartIndex, std::memory_order_relaxed);\n\t\t\t\tlocalBlockIndex->tail.store(newTail, std::memory_order_release);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\t// No room in the old block index, try to allocate another one!\n\t\t\tMOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse if (!new_block_index()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlocalBlockIndex = blockIndex.load(std::memory_order_relaxed);\n\t\t\t\tnewTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1);\n\t\t\t\tidxEntry = localBlockIndex->index[newTail];\n\t\t\t\tassert(idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE);\n\t\t\t\tidxEntry->key.store(blockStartIndex, std::memory_order_relaxed);\n\t\t\t\tlocalBlockIndex->tail.store(newTail, std::memory_order_release);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t\n\t\tinline void rewind_block_index_tail()\n\t\t{\n\t\t\tauto localBlockIndex = blockIndex.load(std::memory_order_relaxed);\n\t\t\tlocalBlockIndex->tail.store((localBlockIndex->tail.load(std::memory_order_relaxed) - 1) & (localBlockIndex->capacity - 1), std::memory_order_relaxed);\n\t\t}\n\t\t\n\t\tinline BlockIndexEntry* get_block_index_entry_for_index(index_t index) const\n\t\t{\n\t\t\tBlockIndexHeader* localBlockIndex;\n\t\t\tauto idx = get_block_index_index_for_index(index, localBlockIndex);\n\t\t\treturn localBlockIndex->index[idx];\n\t\t}\n\t\t\n\t\tinline size_t get_block_index_index_for_index(index_t index, BlockIndexHeader*& localBlockIndex) const\n\t\t{\n#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX\n\t\t\tdebug::DebugLock lock(mutex);\n#endif\n\t\t\tindex &= ~static_cast<index_t>(BLOCK_SIZE - 1);\n\t\t\tlocalBlockIndex = blockIndex.load(std::memory_order_acquire);\n\t\t\tauto tail = localBlockIndex->tail.load(std::memory_order_acquire);\n\t\t\tauto tailBase = localBlockIndex->index[tail]->key.load(std::memory_order_relaxed);\n\t\t\tassert(tailBase != INVALID_BLOCK_BASE);\n\t\t\t// Note: Must use division instead of shift because the index may wrap around, causing a negative\n\t\t\t// offset, whose negativity we want to preserve\n\t\t\tauto offset = static_cast<size_t>(static_cast<typename std::make_signed<index_t>::type>(index - tailBase) / static_cast<typename std::make_signed<index_t>::type>(BLOCK_SIZE));\n\t\t\tsize_t idx = (tail + offset) & (localBlockIndex->capacity - 1);\n\t\t\tassert(localBlockIndex->index[idx]->key.load(std::memory_order_relaxed) == index && localBlockIndex->index[idx]->value.load(std::memory_order_relaxed) != nullptr);\n\t\t\treturn idx;\n\t\t}\n\t\t\n\t\tbool new_block_index()\n\t\t{\n\t\t\tauto prev = blockIndex.load(std::memory_order_relaxed);\n\t\t\tsize_t prevCapacity = prev == nullptr ? 0 : prev->capacity;\n\t\t\tauto entryCount = prev == nullptr ? nextBlockIndexCapacity : prevCapacity;\n\t\t\tauto raw = static_cast<char*>((Traits::malloc)(\n\t\t\t\tsizeof(BlockIndexHeader) +\n\t\t\t\tstd::alignment_of<BlockIndexEntry>::value - 1 + sizeof(BlockIndexEntry) * entryCount +\n\t\t\t\tstd::alignment_of<BlockIndexEntry*>::value - 1 + sizeof(BlockIndexEntry*) * nextBlockIndexCapacity));\n\t\t\tif (raw == nullptr) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\tauto header = new (raw) BlockIndexHeader;\n\t\t\tauto entries = reinterpret_cast<BlockIndexEntry*>(details::align_for<BlockIndexEntry>(raw + sizeof(BlockIndexHeader)));\n\t\t\tauto index = reinterpret_cast<BlockIndexEntry**>(details::align_for<BlockIndexEntry*>(reinterpret_cast<char*>(entries) + sizeof(BlockIndexEntry) * entryCount));\n\t\t\tif (prev != nullptr) {\n\t\t\t\tauto prevTail = prev->tail.load(std::memory_order_relaxed);\n\t\t\t\tauto prevPos = prevTail;\n\t\t\t\tsize_t i = 0;\n\t\t\t\tdo {\n\t\t\t\t\tprevPos = (prevPos + 1) & (prev->capacity - 1);\n\t\t\t\t\tindex[i++] = prev->index[prevPos];\n\t\t\t\t} while (prevPos != prevTail);\n\t\t\t\tassert(i == prevCapacity);\n\t\t\t}\n\t\t\tfor (size_t i = 0; i != entryCount; ++i) {\n\t\t\t\tnew (entries + i) BlockIndexEntry;\n\t\t\t\tentries[i].key.store(INVALID_BLOCK_BASE, std::memory_order_relaxed);\n\t\t\t\tindex[prevCapacity + i] = entries + i;\n\t\t\t}\n\t\t\theader->prev = prev;\n\t\t\theader->entries = entries;\n\t\t\theader->index = index;\n\t\t\theader->capacity = nextBlockIndexCapacity;\n\t\t\theader->tail.store((prevCapacity - 1) & (nextBlockIndexCapacity - 1), std::memory_order_relaxed);\n\t\t\t\n\t\t\tblockIndex.store(header, std::memory_order_release);\n\t\t\t\n\t\t\tnextBlockIndexCapacity <<= 1;\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\t\t\n\tprivate:\n\t\tsize_t nextBlockIndexCapacity;\n\t\tstd::atomic<BlockIndexHeader*> blockIndex;\n\n#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED\n\tpublic:\n\t\tdetails::ThreadExitListener threadExitListener;\n\tprivate:\n#endif\n\t\t\n#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG\n\tpublic:\n\t\tImplicitProducer* nextImplicitProducer;\n\tprivate:\n#endif\n\n#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX\n\t\tmutable debug::DebugMutex mutex;\n#endif\n#ifdef MCDBGQ_TRACKMEM\n\t\tfriend struct MemStats;\n#endif\n\t};\n\t\n\t\n\t//////////////////////////////////\n\t// Block pool manipulation\n\t//////////////////////////////////\n\t\n\tvoid populate_initial_block_list(size_t blockCount)\n\t{\n\t\tinitialBlockPoolSize = blockCount;\n\t\tif (initialBlockPoolSize == 0) {\n\t\t\tinitialBlockPool = nullptr;\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tinitialBlockPool = create_array<Block>(blockCount);\n\t\tif (initialBlockPool == nullptr) {\n\t\t\tinitialBlockPoolSize = 0;\n\t\t}\n\t\tfor (size_t i = 0; i < initialBlockPoolSize; ++i) {\n\t\t\tinitialBlockPool[i].dynamicallyAllocated = false;\n\t\t}\n\t}\n\t\n\tinline Block* try_get_block_from_initial_pool()\n\t{\n\t\tif (initialBlockPoolIndex.load(std::memory_order_relaxed) >= initialBlockPoolSize) {\n\t\t\treturn nullptr;\n\t\t}\n\t\t\n\t\tauto index = initialBlockPoolIndex.fetch_add(1, std::memory_order_relaxed);\n\t\t\n\t\treturn index < initialBlockPoolSize ? (initialBlockPool + index) : nullptr;\n\t}\n\t\n\tinline void add_block_to_free_list(Block* block)\n\t{\n#ifdef MCDBGQ_TRACKMEM\n\t\tblock->owner = nullptr;\n#endif\n\t\tif (!Traits::RECYCLE_ALLOCATED_BLOCKS && block->dynamicallyAllocated) {\n\t\t\tdestroy(block);\n\t\t}\n\t\telse {\n\t\t\tfreeList.add(block);\n\t\t}\n\t}\n\t\n\tinline void add_blocks_to_free_list(Block* block)\n\t{\n\t\twhile (block != nullptr) {\n\t\t\tauto next = block->next;\n\t\t\tadd_block_to_free_list(block);\n\t\t\tblock = next;\n\t\t}\n\t}\n\t\n\tinline Block* try_get_block_from_free_list()\n\t{\n\t\treturn freeList.try_get();\n\t}\n\t\n\t// Gets a free block from one of the memory pools, or allocates a new one (if applicable)\n\ttemplate<AllocationMode canAlloc>\n\tBlock* requisition_block()\n\t{\n\t\tauto block = try_get_block_from_initial_pool();\n\t\tif (block != nullptr) {\n\t\t\treturn block;\n\t\t}\n\t\t\n\t\tblock = try_get_block_from_free_list();\n\t\tif (block != nullptr) {\n\t\t\treturn block;\n\t\t}\n\t\t\n\t\tMOODYCAMEL_CONSTEXPR_IF (canAlloc == CanAlloc) {\n\t\t\treturn create<Block>();\n\t\t}\n\t\telse {\n\t\t\treturn nullptr;\n\t\t}\n\t}\n\t\n\n#ifdef MCDBGQ_TRACKMEM\n\tpublic:\n\t\tstruct MemStats {\n\t\t\tsize_t allocatedBlocks;\n\t\t\tsize_t usedBlocks;\n\t\t\tsize_t freeBlocks;\n\t\t\tsize_t ownedBlocksExplicit;\n\t\t\tsize_t ownedBlocksImplicit;\n\t\t\tsize_t implicitProducers;\n\t\t\tsize_t explicitProducers;\n\t\t\tsize_t elementsEnqueued;\n\t\t\tsize_t blockClassBytes;\n\t\t\tsize_t queueClassBytes;\n\t\t\tsize_t implicitBlockIndexBytes;\n\t\t\tsize_t explicitBlockIndexBytes;\n\t\t\t\n\t\t\tfriend class ConcurrentQueue;\n\t\t\t\n\t\tprivate:\n\t\t\tstatic MemStats getFor(ConcurrentQueue* q)\n\t\t\t{\n\t\t\t\tMemStats stats = { 0 };\n\t\t\t\t\n\t\t\t\tstats.elementsEnqueued = q->size_approx();\n\t\t\t\n\t\t\t\tauto block = q->freeList.head_unsafe();\n\t\t\t\twhile (block != nullptr) {\n\t\t\t\t\t++stats.allocatedBlocks;\n\t\t\t\t\t++stats.freeBlocks;\n\t\t\t\t\tblock = block->freeListNext.load(std::memory_order_relaxed);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (auto ptr = q->producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {\n\t\t\t\t\tbool implicit = dynamic_cast<ImplicitProducer*>(ptr) != nullptr;\n\t\t\t\t\tstats.implicitProducers += implicit ? 1 : 0;\n\t\t\t\t\tstats.explicitProducers += implicit ? 0 : 1;\n\t\t\t\t\t\n\t\t\t\t\tif (implicit) {\n\t\t\t\t\t\tauto prod = static_cast<ImplicitProducer*>(ptr);\n\t\t\t\t\t\tstats.queueClassBytes += sizeof(ImplicitProducer);\n\t\t\t\t\t\tauto head = prod->headIndex.load(std::memory_order_relaxed);\n\t\t\t\t\t\tauto tail = prod->tailIndex.load(std::memory_order_relaxed);\n\t\t\t\t\t\tauto hash = prod->blockIndex.load(std::memory_order_relaxed);\n\t\t\t\t\t\tif (hash != nullptr) {\n\t\t\t\t\t\t\tfor (size_t i = 0; i != hash->capacity; ++i) {\n\t\t\t\t\t\t\t\tif (hash->index[i]->key.load(std::memory_order_relaxed) != ImplicitProducer::INVALID_BLOCK_BASE && hash->index[i]->value.load(std::memory_order_relaxed) != nullptr) {\n\t\t\t\t\t\t\t\t\t++stats.allocatedBlocks;\n\t\t\t\t\t\t\t\t\t++stats.ownedBlocksImplicit;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tstats.implicitBlockIndexBytes += hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry);\n\t\t\t\t\t\t\tfor (; hash != nullptr; hash = hash->prev) {\n\t\t\t\t\t\t\t\tstats.implicitBlockIndexBytes += sizeof(typename ImplicitProducer::BlockIndexHeader) + hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry*);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (; details::circular_less_than<index_t>(head, tail); head += BLOCK_SIZE) {\n\t\t\t\t\t\t\t//auto block = prod->get_block_index_entry_for_index(head);\n\t\t\t\t\t\t\t++stats.usedBlocks;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tauto prod = static_cast<ExplicitProducer*>(ptr);\n\t\t\t\t\t\tstats.queueClassBytes += sizeof(ExplicitProducer);\n\t\t\t\t\t\tauto tailBlock = prod->tailBlock;\n\t\t\t\t\t\tbool wasNonEmpty = false;\n\t\t\t\t\t\tif (tailBlock != nullptr) {\n\t\t\t\t\t\t\tauto block = tailBlock;\n\t\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t\t++stats.allocatedBlocks;\n\t\t\t\t\t\t\t\tif (!block->ConcurrentQueue::Block::template is_empty<explicit_context>() || wasNonEmpty) {\n\t\t\t\t\t\t\t\t\t++stats.usedBlocks;\n\t\t\t\t\t\t\t\t\twasNonEmpty = wasNonEmpty || block != tailBlock;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t++stats.ownedBlocksExplicit;\n\t\t\t\t\t\t\t\tblock = block->next;\n\t\t\t\t\t\t\t} while (block != tailBlock);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tauto index = prod->blockIndex.load(std::memory_order_relaxed);\n\t\t\t\t\t\twhile (index != nullptr) {\n\t\t\t\t\t\t\tstats.explicitBlockIndexBytes += sizeof(typename ExplicitProducer::BlockIndexHeader) + index->size * sizeof(typename ExplicitProducer::BlockIndexEntry);\n\t\t\t\t\t\t\tindex = static_cast<typename ExplicitProducer::BlockIndexHeader*>(index->prev);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tauto freeOnInitialPool = q->initialBlockPoolIndex.load(std::memory_order_relaxed) >= q->initialBlockPoolSize ? 0 : q->initialBlockPoolSize - q->initialBlockPoolIndex.load(std::memory_order_relaxed);\n\t\t\t\tstats.allocatedBlocks += freeOnInitialPool;\n\t\t\t\tstats.freeBlocks += freeOnInitialPool;\n\t\t\t\t\n\t\t\t\tstats.blockClassBytes = sizeof(Block) * stats.allocatedBlocks;\n\t\t\t\tstats.queueClassBytes += sizeof(ConcurrentQueue);\n\t\t\t\t\n\t\t\t\treturn stats;\n\t\t\t}\n\t\t};\n\t\t\n\t\t// For debugging only. Not thread-safe.\n\t\tMemStats getMemStats()\n\t\t{\n\t\t\treturn MemStats::getFor(this);\n\t\t}\n\tprivate:\n\t\tfriend struct MemStats;\n#endif\n\t\n\t\n\t//////////////////////////////////\n\t// Producer list manipulation\n\t//////////////////////////////////\t\n\t\n\tProducerBase* recycle_or_create_producer(bool isExplicit)\n\t{\n#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH\n\t\tdebug::DebugLock lock(implicitProdMutex);\n#endif\n\t\t// Try to re-use one first\n\t\tfor (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {\n\t\t\tif (ptr->inactive.load(std::memory_order_relaxed) && ptr->isExplicit == isExplicit) {\n\t\t\t\tbool expected = true;\n\t\t\t\tif (ptr->inactive.compare_exchange_strong(expected, /* desired */ false, std::memory_order_acquire, std::memory_order_relaxed)) {\n\t\t\t\t\t// We caught one! It's been marked as activated, the caller can have it\n\t\t\t\t\treturn ptr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn add_producer(isExplicit ? static_cast<ProducerBase*>(create<ExplicitProducer>(this)) : create<ImplicitProducer>(this));\n\t}\n\t\n\tProducerBase* add_producer(ProducerBase* producer)\n\t{\n\t\t// Handle failed memory allocation\n\t\tif (producer == nullptr) {\n\t\t\treturn nullptr;\n\t\t}\n\t\t\n\t\tproducerCount.fetch_add(1, std::memory_order_relaxed);\n\t\t\n\t\t// Add it to the lock-free list\n\t\tauto prevTail = producerListTail.load(std::memory_order_relaxed);\n\t\tdo {\n\t\t\tproducer->next = prevTail;\n\t\t} while (!producerListTail.compare_exchange_weak(prevTail, producer, std::memory_order_release, std::memory_order_relaxed));\n\t\t\n#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG\n\t\tif (producer->isExplicit) {\n\t\t\tauto prevTailExplicit = explicitProducers.load(std::memory_order_relaxed);\n\t\t\tdo {\n\t\t\t\tstatic_cast<ExplicitProducer*>(producer)->nextExplicitProducer = prevTailExplicit;\n\t\t\t} while (!explicitProducers.compare_exchange_weak(prevTailExplicit, static_cast<ExplicitProducer*>(producer), std::memory_order_release, std::memory_order_relaxed));\n\t\t}\n\t\telse {\n\t\t\tauto prevTailImplicit = implicitProducers.load(std::memory_order_relaxed);\n\t\t\tdo {\n\t\t\t\tstatic_cast<ImplicitProducer*>(producer)->nextImplicitProducer = prevTailImplicit;\n\t\t\t} while (!implicitProducers.compare_exchange_weak(prevTailImplicit, static_cast<ImplicitProducer*>(producer), std::memory_order_release, std::memory_order_relaxed));\n\t\t}\n#endif\n\t\t\n\t\treturn producer;\n\t}\n\t\n\tvoid reown_producers()\n\t{\n\t\t// After another instance is moved-into/swapped-with this one, all the\n\t\t// producers we stole still think their parents are the other queue.\n\t\t// So fix them up!\n\t\tfor (auto ptr = producerListTail.load(std::memory_order_relaxed); ptr != nullptr; ptr = ptr->next_prod()) {\n\t\t\tptr->parent = this;\n\t\t}\n\t}\n\t\n\t\n\t//////////////////////////////////\n\t// Implicit producer hash\n\t//////////////////////////////////\n\t\n\tstruct ImplicitProducerKVP\n\t{\n\t\tstd::atomic<details::thread_id_t> key;\n\t\tImplicitProducer* value;\t\t// No need for atomicity since it's only read by the thread that sets it in the first place\n\t\t\n\t\tImplicitProducerKVP() : value(nullptr) { }\n\t\t\n\t\tImplicitProducerKVP(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT\n\t\t{\n\t\t\tkey.store(other.key.load(std::memory_order_relaxed), std::memory_order_relaxed);\n\t\t\tvalue = other.value;\n\t\t}\n\t\t\n\t\tinline ImplicitProducerKVP& operator=(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT\n\t\t{\n\t\t\tswap(other);\n\t\t\treturn *this;\n\t\t}\n\t\t\n\t\tinline void swap(ImplicitProducerKVP& other) MOODYCAMEL_NOEXCEPT\n\t\t{\n\t\t\tif (this != &other) {\n\t\t\t\tdetails::swap_relaxed(key, other.key);\n\t\t\t\tstd::swap(value, other.value);\n\t\t\t}\n\t\t}\n\t};\n\t\n\ttemplate<typename XT, typename XTraits>\n\tfriend void moodycamel::swap(typename ConcurrentQueue<XT, XTraits>::ImplicitProducerKVP&, typename ConcurrentQueue<XT, XTraits>::ImplicitProducerKVP&) MOODYCAMEL_NOEXCEPT;\n\t\n\tstruct ImplicitProducerHash\n\t{\n\t\tsize_t capacity;\n\t\tImplicitProducerKVP* entries;\n\t\tImplicitProducerHash* prev;\n\t};\n\t\n\tinline void populate_initial_implicit_producer_hash()\n\t{\n\t\tMOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) {\n\t\t\treturn;\n\t\t}\n\t\telse {\n\t\t\timplicitProducerHashCount.store(0, std::memory_order_relaxed);\n\t\t\tauto hash = &initialImplicitProducerHash;\n\t\t\thash->capacity = INITIAL_IMPLICIT_PRODUCER_HASH_SIZE;\n\t\t\thash->entries = &initialImplicitProducerHashEntries[0];\n\t\t\tfor (size_t i = 0; i != INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; ++i) {\n\t\t\t\tinitialImplicitProducerHashEntries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed);\n\t\t\t}\n\t\t\thash->prev = nullptr;\n\t\t\timplicitProducerHash.store(hash, std::memory_order_relaxed);\n\t\t}\n\t}\n\t\n\tvoid swap_implicit_producer_hashes(ConcurrentQueue& other)\n\t{\n\t\tMOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) {\n\t\t\treturn;\n\t\t}\n\t\telse {\n\t\t\t// Swap (assumes our implicit producer hash is initialized)\n\t\t\tinitialImplicitProducerHashEntries.swap(other.initialImplicitProducerHashEntries);\n\t\t\tinitialImplicitProducerHash.entries = &initialImplicitProducerHashEntries[0];\n\t\t\tother.initialImplicitProducerHash.entries = &other.initialImplicitProducerHashEntries[0];\n\t\t\t\n\t\t\tdetails::swap_relaxed(implicitProducerHashCount, other.implicitProducerHashCount);\n\t\t\t\n\t\t\tdetails::swap_relaxed(implicitProducerHash, other.implicitProducerHash);\n\t\t\tif (implicitProducerHash.load(std::memory_order_relaxed) == &other.initialImplicitProducerHash) {\n\t\t\t\timplicitProducerHash.store(&initialImplicitProducerHash, std::memory_order_relaxed);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tImplicitProducerHash* hash;\n\t\t\t\tfor (hash = implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &other.initialImplicitProducerHash; hash = hash->prev) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\thash->prev = &initialImplicitProducerHash;\n\t\t\t}\n\t\t\tif (other.implicitProducerHash.load(std::memory_order_relaxed) == &initialImplicitProducerHash) {\n\t\t\t\tother.implicitProducerHash.store(&other.initialImplicitProducerHash, std::memory_order_relaxed);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tImplicitProducerHash* hash;\n\t\t\t\tfor (hash = other.implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &initialImplicitProducerHash; hash = hash->prev) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\thash->prev = &other.initialImplicitProducerHash;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Only fails (returns nullptr) if memory allocation fails\n\tImplicitProducer* get_or_add_implicit_producer()\n\t{\n\t\t// Note that since the data is essentially thread-local (key is thread ID),\n\t\t// there's a reduced need for fences (memory ordering is already consistent\n\t\t// for any individual thread), except for the current table itself.\n\t\t\n\t\t// Start by looking for the thread ID in the current and all previous hash tables.\n\t\t// If it's not found, it must not be in there yet, since this same thread would\n\t\t// have added it previously to one of the tables that we traversed.\n\t\t\n\t\t// Code and algorithm adapted from http://preshing.com/20130605/the-worlds-simplest-lock-free-hash-table\n\t\t\n#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH\n\t\tdebug::DebugLock lock(implicitProdMutex);\n#endif\n\t\t\n\t\tauto id = details::thread_id();\n\t\tauto hashedId = details::hash_thread_id(id);\n\t\t\n\t\tauto mainHash = implicitProducerHash.load(std::memory_order_acquire);\n\t\tassert(mainHash != nullptr);  // silence clang-tidy and MSVC warnings (hash cannot be null)\n\t\tfor (auto hash = mainHash; hash != nullptr; hash = hash->prev) {\n\t\t\t// Look for the id in this hash\n\t\t\tauto index = hashedId;\n\t\t\twhile (true) {\t\t// Not an infinite loop because at least one slot is free in the hash table\n\t\t\t\tindex &= hash->capacity - 1u;\n\t\t\t\t\n\t\t\t\tauto probedKey = hash->entries[index].key.load(std::memory_order_relaxed);\n\t\t\t\tif (probedKey == id) {\n\t\t\t\t\t// Found it! If we had to search several hashes deep, though, we should lazily add it\n\t\t\t\t\t// to the current main hash table to avoid the extended search next time.\n\t\t\t\t\t// Note there's guaranteed to be room in the current hash table since every subsequent\n\t\t\t\t\t// table implicitly reserves space for all previous tables (there's only one\n\t\t\t\t\t// implicitProducerHashCount).\n\t\t\t\t\tauto value = hash->entries[index].value;\n\t\t\t\t\tif (hash != mainHash) {\n\t\t\t\t\t\tindex = hashedId;\n\t\t\t\t\t\twhile (true) {\n\t\t\t\t\t\t\tindex &= mainHash->capacity - 1u;\n\t\t\t\t\t\t\tauto empty = details::invalid_thread_id;\n#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED\n\t\t\t\t\t\t\tauto reusable = details::invalid_thread_id2;\n\t\t\t\t\t\t\tif (mainHash->entries[index].key.compare_exchange_strong(empty,    id, std::memory_order_seq_cst, std::memory_order_relaxed) ||\n\t\t\t\t\t\t\t\tmainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_seq_cst, std::memory_order_relaxed)) {\n#else\n\t\t\t\t\t\t\tif (mainHash->entries[index].key.compare_exchange_strong(empty,    id, std::memory_order_seq_cst, std::memory_order_relaxed)) {\n#endif\n\t\t\t\t\t\t\t\tmainHash->entries[index].value = value;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t++index;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t\tif (probedKey == details::invalid_thread_id) {\n\t\t\t\t\tbreak;\t\t// Not in this hash table\n\t\t\t\t}\n\t\t\t\t++index;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Insert!\n\t\tauto newCount = 1 + implicitProducerHashCount.fetch_add(1, std::memory_order_relaxed);\n\t\twhile (true) {\n\t\t\t// NOLINTNEXTLINE(clang-analyzer-core.NullDereference)\n\t\t\tif (newCount >= (mainHash->capacity >> 1) && !implicitProducerHashResizeInProgress.test_and_set(std::memory_order_acquire)) {\n\t\t\t\t// We've acquired the resize lock, try to allocate a bigger hash table.\n\t\t\t\t// Note the acquire fence synchronizes with the release fence at the end of this block, and hence when\n\t\t\t\t// we reload implicitProducerHash it must be the most recent version (it only gets changed within this\n\t\t\t\t// locked block).\n\t\t\t\tmainHash = implicitProducerHash.load(std::memory_order_acquire);\n\t\t\t\tif (newCount >= (mainHash->capacity >> 1)) {\n\t\t\t\t\tsize_t newCapacity = mainHash->capacity << 1;\n\t\t\t\t\twhile (newCount >= (newCapacity >> 1)) {\n\t\t\t\t\t\tnewCapacity <<= 1;\n\t\t\t\t\t}\n\t\t\t\t\tauto raw = static_cast<char*>((Traits::malloc)(sizeof(ImplicitProducerHash) + std::alignment_of<ImplicitProducerKVP>::value - 1 + sizeof(ImplicitProducerKVP) * newCapacity));\n\t\t\t\t\tif (raw == nullptr) {\n\t\t\t\t\t\t// Allocation failed\n\t\t\t\t\t\timplicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed);\n\t\t\t\t\t\timplicitProducerHashResizeInProgress.clear(std::memory_order_relaxed);\n\t\t\t\t\t\treturn nullptr;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tauto newHash = new (raw) ImplicitProducerHash;\n\t\t\t\t\tnewHash->capacity = static_cast<size_t>(newCapacity);\n\t\t\t\t\tnewHash->entries = reinterpret_cast<ImplicitProducerKVP*>(details::align_for<ImplicitProducerKVP>(raw + sizeof(ImplicitProducerHash)));\n\t\t\t\t\tfor (size_t i = 0; i != newCapacity; ++i) {\n\t\t\t\t\t\tnew (newHash->entries + i) ImplicitProducerKVP;\n\t\t\t\t\t\tnewHash->entries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed);\n\t\t\t\t\t}\n\t\t\t\t\tnewHash->prev = mainHash;\n\t\t\t\t\timplicitProducerHash.store(newHash, std::memory_order_release);\n\t\t\t\t\timplicitProducerHashResizeInProgress.clear(std::memory_order_release);\n\t\t\t\t\tmainHash = newHash;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\timplicitProducerHashResizeInProgress.clear(std::memory_order_release);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// If it's < three-quarters full, add to the old one anyway so that we don't have to wait for the next table\n\t\t\t// to finish being allocated by another thread (and if we just finished allocating above, the condition will\n\t\t\t// always be true)\n\t\t\tif (newCount < (mainHash->capacity >> 1) + (mainHash->capacity >> 2)) {\n\t\t\t\tauto producer = static_cast<ImplicitProducer*>(recycle_or_create_producer(false));\n\t\t\t\tif (producer == nullptr) {\n\t\t\t\t\timplicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed);\n\t\t\t\t\treturn nullptr;\n\t\t\t\t}\n\t\t\t\t\n#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED\n\t\t\t\tproducer->threadExitListener.callback = &ConcurrentQueue::implicit_producer_thread_exited_callback;\n\t\t\t\tproducer->threadExitListener.userData = producer;\n\t\t\t\tdetails::ThreadExitNotifier::subscribe(&producer->threadExitListener);\n#endif\n\t\t\t\t\n\t\t\t\tauto index = hashedId;\n\t\t\t\twhile (true) {\n\t\t\t\t\tindex &= mainHash->capacity - 1u;\n\t\t\t\t\tauto empty = details::invalid_thread_id;\n#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED\n\t\t\t\t\tauto reusable = details::invalid_thread_id2;\n\t\t\t\t\tif (mainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_seq_cst, std::memory_order_relaxed)) {\n\t\t\t\t\t\timplicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed);  // already counted as a used slot\n\t\t\t\t\t\tmainHash->entries[index].value = producer;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n#endif\n\t\t\t\t\tif (mainHash->entries[index].key.compare_exchange_strong(empty,    id, std::memory_order_seq_cst, std::memory_order_relaxed)) {\n\t\t\t\t\t\tmainHash->entries[index].value = producer;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t++index;\n\t\t\t\t}\n\t\t\t\treturn producer;\n\t\t\t}\n\t\t\t\n\t\t\t// Hmm, the old hash is quite full and somebody else is busy allocating a new one.\n\t\t\t// We need to wait for the allocating thread to finish (if it succeeds, we add, if not,\n\t\t\t// we try to allocate ourselves).\n\t\t\tmainHash = implicitProducerHash.load(std::memory_order_acquire);\n\t\t}\n\t}\n\t\n#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED\n\tvoid implicit_producer_thread_exited(ImplicitProducer* producer)\n\t{\n\t\t// Remove from hash\n#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH\n\t\tdebug::DebugLock lock(implicitProdMutex);\n#endif\n\t\tauto hash = implicitProducerHash.load(std::memory_order_acquire);\n\t\tassert(hash != nullptr);\t\t// The thread exit listener is only registered if we were added to a hash in the first place\n\t\tauto id = details::thread_id();\n\t\tauto hashedId = details::hash_thread_id(id);\n\t\tdetails::thread_id_t probedKey;\n\t\t\n\t\t// We need to traverse all the hashes just in case other threads aren't on the current one yet and are\n\t\t// trying to add an entry thinking there's a free slot (because they reused a producer)\n\t\tfor (; hash != nullptr; hash = hash->prev) {\n\t\t\tauto index = hashedId;\n\t\t\tdo {\n\t\t\t\tindex &= hash->capacity - 1u;\n\t\t\t\tprobedKey = id;\n\t\t\t\tif (hash->entries[index].key.compare_exchange_strong(probedKey, details::invalid_thread_id2, std::memory_order_seq_cst, std::memory_order_relaxed)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t++index;\n\t\t\t} while (probedKey != details::invalid_thread_id);\t\t// Can happen if the hash has changed but we weren't put back in it yet, or if we weren't added to this hash in the first place\n\t\t}\n\t\t\n\t\t// Mark the queue as being recyclable\n\t\tproducer->inactive.store(true, std::memory_order_release);\n\t}\n\t\n\tstatic void implicit_producer_thread_exited_callback(void* userData)\n\t{\n\t\tauto producer = static_cast<ImplicitProducer*>(userData);\n\t\tauto queue = producer->parent;\n\t\tqueue->implicit_producer_thread_exited(producer);\n\t}\n#endif\n\t\n\t//////////////////////////////////\n\t// Utility functions\n\t//////////////////////////////////\n\n\ttemplate<typename TAlign>\n\tstatic inline void* aligned_malloc(size_t size)\n\t{\n\t\tMOODYCAMEL_CONSTEXPR_IF (std::alignment_of<TAlign>::value <= std::alignment_of<details::max_align_t>::value)\n\t\t\treturn (Traits::malloc)(size);\n\t\telse {\n\t\t\tsize_t alignment = std::alignment_of<TAlign>::value;\n\t\t\tvoid* raw = (Traits::malloc)(size + alignment - 1 + sizeof(void*));\n\t\t\tif (!raw)\n\t\t\t\treturn nullptr;\n\t\t\tchar* ptr = details::align_for<TAlign>(reinterpret_cast<char*>(raw) + sizeof(void*));\n\t\t\t*(reinterpret_cast<void**>(ptr) - 1) = raw;\n\t\t\treturn ptr;\n\t\t}\n\t}\n\n\ttemplate<typename TAlign>\n\tstatic inline void aligned_free(void* ptr)\n\t{\n\t\tMOODYCAMEL_CONSTEXPR_IF (std::alignment_of<TAlign>::value <= std::alignment_of<details::max_align_t>::value)\n\t\t\treturn (Traits::free)(ptr);\n\t\telse\n\t\t\t(Traits::free)(ptr ? *(reinterpret_cast<void**>(ptr) - 1) : nullptr);\n\t}\n\n\ttemplate<typename U>\n\tstatic inline U* create_array(size_t count)\n\t{\n\t\tassert(count > 0);\n\t\tU* p = static_cast<U*>(aligned_malloc<U>(sizeof(U) * count));\n\t\tif (p == nullptr)\n\t\t\treturn nullptr;\n\n\t\tfor (size_t i = 0; i != count; ++i)\n\t\t\tnew (p + i) U();\n\t\treturn p;\n\t}\n\n\ttemplate<typename U>\n\tstatic inline void destroy_array(U* p, size_t count)\n\t{\n\t\tif (p != nullptr) {\n\t\t\tassert(count > 0);\n\t\t\tfor (size_t i = count; i != 0; )\n\t\t\t\t(p + --i)->~U();\n\t\t}\n\t\taligned_free<U>(p);\n\t}\n\n\ttemplate<typename U>\n\tstatic inline U* create()\n\t{\n\t\tvoid* p = aligned_malloc<U>(sizeof(U));\n\t\treturn p != nullptr ? new (p) U : nullptr;\n\t}\n\n\ttemplate<typename U, typename A1>\n\tstatic inline U* create(A1&& a1)\n\t{\n\t\tvoid* p = aligned_malloc<U>(sizeof(U));\n\t\treturn p != nullptr ? new (p) U(std::forward<A1>(a1)) : nullptr;\n\t}\n\n\ttemplate<typename U>\n\tstatic inline void destroy(U* p)\n\t{\n\t\tif (p != nullptr)\n\t\t\tp->~U();\n\t\taligned_free<U>(p);\n\t}\n\nprivate:\n\tstd::atomic<ProducerBase*> producerListTail;\n\tstd::atomic<std::uint32_t> producerCount;\n\t\n\tstd::atomic<size_t> initialBlockPoolIndex;\n\tBlock* initialBlockPool;\n\tsize_t initialBlockPoolSize;\n\t\n#ifndef MCDBGQ_USEDEBUGFREELIST\n\tFreeList<Block> freeList;\n#else\n\tdebug::DebugFreeList<Block> freeList;\n#endif\n\t\n\tstd::atomic<ImplicitProducerHash*> implicitProducerHash;\n\tstd::atomic<size_t> implicitProducerHashCount;\t\t// Number of slots logically used\n\tImplicitProducerHash initialImplicitProducerHash;\n\tstd::array<ImplicitProducerKVP, INITIAL_IMPLICIT_PRODUCER_HASH_SIZE> initialImplicitProducerHashEntries;\n\tstd::atomic_flag implicitProducerHashResizeInProgress;\n\t\n\tstd::atomic<std::uint32_t> nextExplicitConsumerId;\n\tstd::atomic<std::uint32_t> globalExplicitConsumerOffset;\n\t\n#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH\n\tdebug::DebugMutex implicitProdMutex;\n#endif\n\t\n#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG\n\tstd::atomic<ExplicitProducer*> explicitProducers;\n\tstd::atomic<ImplicitProducer*> implicitProducers;\n#endif\n};\n\n\ntemplate<typename T, typename Traits>\nProducerToken::ProducerToken(ConcurrentQueue<T, Traits>& queue)\n\t: producer(queue.recycle_or_create_producer(true))\n{\n\tif (producer != nullptr) {\n\t\tproducer->token = this;\n\t}\n}\n\ntemplate<typename T, typename Traits>\nProducerToken::ProducerToken(BlockingConcurrentQueue<T, Traits>& queue)\n\t: producer(reinterpret_cast<ConcurrentQueue<T, Traits>*>(&queue)->recycle_or_create_producer(true))\n{\n\tif (producer != nullptr) {\n\t\tproducer->token = this;\n\t}\n}\n\ntemplate<typename T, typename Traits>\nConsumerToken::ConsumerToken(ConcurrentQueue<T, Traits>& queue)\n\t: itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr)\n{\n\tinitialOffset = queue.nextExplicitConsumerId.fetch_add(1, std::memory_order_release);\n\tlastKnownGlobalOffset = static_cast<std::uint32_t>(-1);\n}\n\ntemplate<typename T, typename Traits>\nConsumerToken::ConsumerToken(BlockingConcurrentQueue<T, Traits>& queue)\n\t: itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr)\n{\n\tinitialOffset = reinterpret_cast<ConcurrentQueue<T, Traits>*>(&queue)->nextExplicitConsumerId.fetch_add(1, std::memory_order_release);\n\tlastKnownGlobalOffset = static_cast<std::uint32_t>(-1);\n}\n\ntemplate<typename T, typename Traits>\ninline void swap(ConcurrentQueue<T, Traits>& a, ConcurrentQueue<T, Traits>& b) MOODYCAMEL_NOEXCEPT\n{\n\ta.swap(b);\n}\n\ninline void swap(ProducerToken& a, ProducerToken& b) MOODYCAMEL_NOEXCEPT\n{\n\ta.swap(b);\n}\n\ninline void swap(ConsumerToken& a, ConsumerToken& b) MOODYCAMEL_NOEXCEPT\n{\n\ta.swap(b);\n}\n\ntemplate<typename T, typename Traits>\ninline void swap(typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP& a, typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT\n{\n\ta.swap(b);\n}\n\n}\n\n#if defined(_MSC_VER) && (!defined(_HAS_CXX17) || !_HAS_CXX17)\n#pragma warning(pop)\n#endif\n\n#if defined(__GNUC__) && !defined(__INTEL_COMPILER)\n#pragma GCC diagnostic pop\n#endif\n"
  },
  {
    "path": "External/concurrentqueue/lightweightsemaphore.h",
    "content": "// Provides an efficient implementation of a semaphore (LightweightSemaphore).\n// This is an extension of Jeff Preshing's sempahore implementation (licensed \n// under the terms of its separate zlib license) that has been adapted and\n// extended by Cameron Desrochers.\n\n#pragma once\n\n#include <cstddef> // For std::size_t\n#include <atomic>\n#include <type_traits> // For std::make_signed<T>\n\n#if defined(_WIN32)\n// Avoid including windows.h in a header; we only need a handful of\n// items, so we'll redeclare them here (this is relatively safe since\n// the API generally has to remain stable between Windows versions).\n// I know this is an ugly hack but it still beats polluting the global\n// namespace with thousands of generic names or adding a .cpp for nothing.\nextern \"C\" {\n\tstruct _SECURITY_ATTRIBUTES;\n\t__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes, long lInitialCount, long lMaximumCount, const wchar_t* lpName);\n\t__declspec(dllimport) int __stdcall CloseHandle(void* hObject);\n\t__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void* hHandle, unsigned long dwMilliseconds);\n\t__declspec(dllimport) int __stdcall ReleaseSemaphore(void* hSemaphore, long lReleaseCount, long* lpPreviousCount);\n}\n#elif defined(__MACH__)\n#include <mach/mach.h>\n#elif defined(__unix__)\n#include <semaphore.h>\n\n#if defined(__GLIBC_PREREQ) && defined(_GNU_SOURCE)\n#if __GLIBC_PREREQ(2,30)\n#define MOODYCAMEL_LIGHTWEIGHTSEMAPHORE_MONOTONIC\n#endif\n#endif\n#endif\n\nnamespace moodycamel\n{\nnamespace details\n{\n\n// Code in the mpmc_sema namespace below is an adaptation of Jeff Preshing's\n// portable + lightweight semaphore implementations, originally from\n// https://github.com/preshing/cpp11-on-multicore/blob/master/common/sema.h\n// LICENSE:\n// Copyright (c) 2015 Jeff Preshing\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//\tclaim that you wrote the original software. If you use this software\n//\tin a product, an acknowledgement in the product documentation would be\n//\tappreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//\tmisrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n#if defined(_WIN32)\nclass Semaphore\n{\nprivate:\n\tvoid* m_hSema;\n\t\n\tSemaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;\n\tSemaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;\n\npublic:\n\tSemaphore(int initialCount = 0)\n\t{\n\t\tassert(initialCount >= 0);\n\t\tconst long maxLong = 0x7fffffff;\n\t\tm_hSema = CreateSemaphoreW(nullptr, initialCount, maxLong, nullptr);\n\t\tassert(m_hSema);\n\t}\n\n\t~Semaphore()\n\t{\n\t\tCloseHandle(m_hSema);\n\t}\n\n\tbool wait()\n\t{\n\t\tconst unsigned long infinite = 0xffffffff;\n\t\treturn WaitForSingleObject(m_hSema, infinite) == 0;\n\t}\n\t\n\tbool try_wait()\n\t{\n\t\treturn WaitForSingleObject(m_hSema, 0) == 0;\n\t}\n\t\n\tbool timed_wait(std::uint64_t usecs)\n\t{\n\t\treturn WaitForSingleObject(m_hSema, (unsigned long)(usecs / 1000)) == 0;\n\t}\n\n\tvoid signal(int count = 1)\n\t{\n\t\twhile (!ReleaseSemaphore(m_hSema, count, nullptr));\n\t}\n};\n#elif defined(__MACH__)\n//---------------------------------------------------------\n// Semaphore (Apple iOS and OSX)\n// Can't use POSIX semaphores due to http://lists.apple.com/archives/darwin-kernel/2009/Apr/msg00010.html\n//---------------------------------------------------------\nclass Semaphore\n{\nprivate:\n\tsemaphore_t m_sema;\n\n\tSemaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;\n\tSemaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;\n\npublic:\n\tSemaphore(int initialCount = 0)\n\t{\n\t\tassert(initialCount >= 0);\n\t\tkern_return_t rc = semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount);\n\t\tassert(rc == KERN_SUCCESS);\n\t\t(void)rc;\n\t}\n\n\t~Semaphore()\n\t{\n\t\tsemaphore_destroy(mach_task_self(), m_sema);\n\t}\n\n\tbool wait()\n\t{\n\t\treturn semaphore_wait(m_sema) == KERN_SUCCESS;\n\t}\n\t\n\tbool try_wait()\n\t{\n\t\treturn timed_wait(0);\n\t}\n\t\n\tbool timed_wait(std::uint64_t timeout_usecs)\n\t{\n\t\tmach_timespec_t ts;\n\t\tts.tv_sec = static_cast<unsigned int>(timeout_usecs / 1000000);\n\t\tts.tv_nsec = static_cast<int>((timeout_usecs % 1000000) * 1000);\n\n\t\t// added in OSX 10.10: https://developer.apple.com/library/prerelease/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/modules/Darwin.html\n\t\tkern_return_t rc = semaphore_timedwait(m_sema, ts);\n\t\treturn rc == KERN_SUCCESS;\n\t}\n\n\tvoid signal()\n\t{\n\t\twhile (semaphore_signal(m_sema) != KERN_SUCCESS);\n\t}\n\n\tvoid signal(int count)\n\t{\n\t\twhile (count-- > 0)\n\t\t{\n\t\t\twhile (semaphore_signal(m_sema) != KERN_SUCCESS);\n\t\t}\n\t}\n};\n#elif defined(__unix__)\n//---------------------------------------------------------\n// Semaphore (POSIX, Linux)\n//---------------------------------------------------------\nclass Semaphore\n{\nprivate:\n\tsem_t m_sema;\n\n\tSemaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;\n\tSemaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;\n\npublic:\n\tSemaphore(int initialCount = 0)\n\t{\n\t\tassert(initialCount >= 0);\n\t\tint rc = sem_init(&m_sema, 0, static_cast<unsigned int>(initialCount));\n\t\tassert(rc == 0);\n\t\t(void)rc;\n\t}\n\n\t~Semaphore()\n\t{\n\t\tsem_destroy(&m_sema);\n\t}\n\n\tbool wait()\n\t{\n\t\t// http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error\n\t\tint rc;\n\t\tdo {\n\t\t\trc = sem_wait(&m_sema);\n\t\t} while (rc == -1 && errno == EINTR);\n\t\treturn rc == 0;\n\t}\n\n\tbool try_wait()\n\t{\n\t\tint rc;\n\t\tdo {\n\t\t\trc = sem_trywait(&m_sema);\n\t\t} while (rc == -1 && errno == EINTR);\n\t\treturn rc == 0;\n\t}\n\n\tbool timed_wait(std::uint64_t usecs)\n\t{\n\t\tstruct timespec ts;\n\t\tconst int usecs_in_1_sec = 1000000;\n\t\tconst int nsecs_in_1_sec = 1000000000;\n#ifdef MOODYCAMEL_LIGHTWEIGHTSEMAPHORE_MONOTONIC\n\t\tclock_gettime(CLOCK_MONOTONIC, &ts);\n#else\n\t\tclock_gettime(CLOCK_REALTIME, &ts);\n#endif\n\t\tts.tv_sec += (time_t)(usecs / usecs_in_1_sec);\n\t\tts.tv_nsec += (long)(usecs % usecs_in_1_sec) * 1000;\n\t\t// sem_timedwait bombs if you have more than 1e9 in tv_nsec\n\t\t// so we have to clean things up before passing it in\n\t\tif (ts.tv_nsec >= nsecs_in_1_sec) {\n\t\t\tts.tv_nsec -= nsecs_in_1_sec;\n\t\t\t++ts.tv_sec;\n\t\t}\n\n\t\tint rc;\n\t\tdo {\n#ifdef MOODYCAMEL_LIGHTWEIGHTSEMAPHORE_MONOTONIC\n\t\t\trc = sem_clockwait(&m_sema, CLOCK_MONOTONIC, &ts);\n#else\n\t\t\trc = sem_timedwait(&m_sema, &ts);\n#endif\n\t\t} while (rc == -1 && errno == EINTR);\n\t\treturn rc == 0;\n\t}\n\n\tvoid signal()\n\t{\n\t\twhile (sem_post(&m_sema) == -1);\n\t}\n\n\tvoid signal(int count)\n\t{\n\t\twhile (count-- > 0)\n\t\t{\n\t\t\twhile (sem_post(&m_sema) == -1);\n\t\t}\n\t}\n};\n#else\n#error Unsupported platform! (No semaphore wrapper available)\n#endif\n\n}\t// end namespace details\n\n\n//---------------------------------------------------------\n// LightweightSemaphore\n//---------------------------------------------------------\nclass LightweightSemaphore\n{\npublic:\n\ttypedef std::make_signed<std::size_t>::type ssize_t;\n\nprivate:\n\tstd::atomic<ssize_t> m_count;\n\tdetails::Semaphore m_sema;\n\tint m_maxSpins;\n\n\tbool waitWithPartialSpinning(std::int64_t timeout_usecs = -1)\n\t{\n\t\tssize_t oldCount;\n\t\tint spin = m_maxSpins;\n\t\twhile (--spin >= 0)\n\t\t{\n\t\t\toldCount = m_count.load(std::memory_order_relaxed);\n\t\t\tif ((oldCount > 0) && m_count.compare_exchange_strong(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed))\n\t\t\t\treturn true;\n\t\t\tstd::atomic_signal_fence(std::memory_order_acquire);\t // Prevent the compiler from collapsing the loop.\n\t\t}\n\t\toldCount = m_count.fetch_sub(1, std::memory_order_acquire);\n\t\tif (oldCount > 0)\n\t\t\treturn true;\n\t\tif (timeout_usecs < 0)\n\t\t{\n\t\t\tif (m_sema.wait())\n\t\t\t\treturn true;\n\t\t}\n\t\tif (timeout_usecs > 0 && m_sema.timed_wait((std::uint64_t)timeout_usecs))\n\t\t\treturn true;\n\t\t// At this point, we've timed out waiting for the semaphore, but the\n\t\t// count is still decremented indicating we may still be waiting on\n\t\t// it. So we have to re-adjust the count, but only if the semaphore\n\t\t// wasn't signaled enough times for us too since then. If it was, we\n\t\t// need to release the semaphore too.\n\t\twhile (true)\n\t\t{\n\t\t\toldCount = m_count.load(std::memory_order_acquire);\n\t\t\tif (oldCount >= 0 && m_sema.try_wait())\n\t\t\t\treturn true;\n\t\t\tif (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed))\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tssize_t waitManyWithPartialSpinning(ssize_t max, std::int64_t timeout_usecs = -1)\n\t{\n\t\tassert(max > 0);\n\t\tssize_t oldCount;\n\t\tint spin = m_maxSpins;\n\t\twhile (--spin >= 0)\n\t\t{\n\t\t\toldCount = m_count.load(std::memory_order_relaxed);\n\t\t\tif (oldCount > 0)\n\t\t\t{\n\t\t\t\tssize_t newCount = oldCount > max ? oldCount - max : 0;\n\t\t\t\tif (m_count.compare_exchange_strong(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed))\n\t\t\t\t\treturn oldCount - newCount;\n\t\t\t}\n\t\t\tstd::atomic_signal_fence(std::memory_order_acquire);\n\t\t}\n\t\toldCount = m_count.fetch_sub(1, std::memory_order_acquire);\n\t\tif (oldCount <= 0)\n\t\t{\n\t\t\tif ((timeout_usecs == 0) || (timeout_usecs < 0 && !m_sema.wait()) || (timeout_usecs > 0 && !m_sema.timed_wait((std::uint64_t)timeout_usecs)))\n\t\t\t{\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\toldCount = m_count.load(std::memory_order_acquire);\n\t\t\t\t\tif (oldCount >= 0 && m_sema.try_wait())\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tif (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed))\n\t\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (max > 1)\n\t\t\treturn 1 + tryWaitMany(max - 1);\n\t\treturn 1;\n\t}\n\npublic:\n\tLightweightSemaphore(ssize_t initialCount = 0, int maxSpins = 10000) : m_count(initialCount), m_maxSpins(maxSpins)\n\t{\n\t\tassert(initialCount >= 0);\n\t\tassert(maxSpins >= 0);\n\t}\n\n\tbool tryWait()\n\t{\n\t\tssize_t oldCount = m_count.load(std::memory_order_relaxed);\n\t\twhile (oldCount > 0)\n\t\t{\n\t\t\tif (m_count.compare_exchange_weak(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed))\n\t\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tbool wait()\n\t{\n\t\treturn tryWait() || waitWithPartialSpinning();\n\t}\n\n\tbool wait(std::int64_t timeout_usecs)\n\t{\n\t\treturn tryWait() || waitWithPartialSpinning(timeout_usecs);\n\t}\n\n\t// Acquires between 0 and (greedily) max, inclusive\n\tssize_t tryWaitMany(ssize_t max)\n\t{\n\t\tassert(max >= 0);\n\t\tssize_t oldCount = m_count.load(std::memory_order_relaxed);\n\t\twhile (oldCount > 0)\n\t\t{\n\t\t\tssize_t newCount = oldCount > max ? oldCount - max : 0;\n\t\t\tif (m_count.compare_exchange_weak(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed))\n\t\t\t\treturn oldCount - newCount;\n\t\t}\n\t\treturn 0;\n\t}\n\n\t// Acquires at least one, and (greedily) at most max\n\tssize_t waitMany(ssize_t max, std::int64_t timeout_usecs)\n\t{\n\t\tassert(max >= 0);\n\t\tssize_t result = tryWaitMany(max);\n\t\tif (result == 0 && max > 0)\n\t\t\tresult = waitManyWithPartialSpinning(max, timeout_usecs);\n\t\treturn result;\n\t}\n\t\n\tssize_t waitMany(ssize_t max)\n\t{\n\t\tssize_t result = waitMany(max, -1);\n\t\tassert(result > 0);\n\t\treturn result;\n\t}\n\n\tvoid signal(ssize_t count = 1)\n\t{\n\t\tassert(count >= 0);\n\t\tssize_t oldCount = m_count.fetch_add(count, std::memory_order_release);\n\t\tssize_t toRelease = -oldCount < count ? -oldCount : count;\n\t\tif (toRelease > 0)\n\t\t{\n\t\t\tm_sema.signal((int)toRelease);\n\t\t}\n\t}\n\t\n\tstd::size_t availableApprox() const\n\t{\n\t\tssize_t count = m_count.load(std::memory_order_relaxed);\n\t\treturn count > 0 ? static_cast<std::size_t>(count) : 0;\n\t}\n};\n\n}   // end namespace moodycamel\n"
  },
  {
    "path": "External/stb/stb_image.h",
    "content": "/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb\n                                  no warranty implied; use at your own risk\n\n   Do this:\n      #define STB_IMAGE_IMPLEMENTATION\n   before you include this file in *one* C or C++ file to create the implementation.\n\n   // i.e. it should look like this:\n   #include ...\n   #include ...\n   #include ...\n   #define STB_IMAGE_IMPLEMENTATION\n   #include \"stb_image.h\"\n\n   You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.\n   And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free\n\n\n   QUICK NOTES:\n      Primarily of interest to game developers and other people who can\n          avoid problematic images and only need the trivial interface\n\n      JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)\n      PNG 1/2/4/8/16-bit-per-channel\n\n      TGA (not sure what subset, if a subset)\n      BMP non-1bpp, non-RLE\n      PSD (composited view only, no extra channels, 8/16 bit-per-channel)\n\n      GIF (*comp always reports as 4-channel)\n      HDR (radiance rgbE format)\n      PIC (Softimage PIC)\n      PNM (PPM and PGM binary only)\n\n      Animated GIF still needs a proper API, but here's one way to do it:\n          http://gist.github.com/urraka/685d9a6340b26b830d49\n\n      - decode from memory or through FILE (define STBI_NO_STDIO to remove code)\n      - decode from arbitrary I/O callbacks\n      - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)\n\n   Full documentation under \"DOCUMENTATION\" below.\n\n\nLICENSE\n\n  See end of file for license information.\n\nRECENT REVISION HISTORY:\n\n      2.28  (2023-01-29) many error fixes, security errors, just tons of stuff\n      2.27  (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes\n      2.26  (2020-07-13) many minor fixes\n      2.25  (2020-02-02) fix warnings\n      2.24  (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically\n      2.23  (2019-08-11) fix clang static analysis warning\n      2.22  (2019-03-04) gif fixes, fix warnings\n      2.21  (2019-02-25) fix typo in comment\n      2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs\n      2.19  (2018-02-11) fix warning\n      2.18  (2018-01-30) fix warnings\n      2.17  (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings\n      2.16  (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes\n      2.15  (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC\n      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs\n      2.13  (2016-12-04) experimental 16-bit API, only for PNG so far; fixes\n      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes\n      2.11  (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64\n                         RGB-format JPEG; remove white matting in PSD;\n                         allocate large structures on the stack;\n                         correct channel count for PNG & BMP\n      2.10  (2016-01-22) avoid warning introduced in 2.09\n      2.09  (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED\n\n   See end of file for full revision history.\n\n\n ============================    Contributors    =========================\n\n Image formats                          Extensions, features\n    Sean Barrett (jpeg, png, bmp)          Jetro Lauha (stbi_info)\n    Nicolas Schulz (hdr, psd)              Martin \"SpartanJ\" Golini (stbi_info)\n    Jonathan Dummer (tga)                  James \"moose2000\" Brown (iPhone PNG)\n    Jean-Marc Lienher (gif)                Ben \"Disch\" Wenger (io callbacks)\n    Tom Seddon (pic)                       Omar Cornut (1/2/4-bit PNG)\n    Thatcher Ulrich (psd)                  Nicolas Guillemot (vertical flip)\n    Ken Miller (pgm, ppm)                  Richard Mitton (16-bit PSD)\n    github:urraka (animated gif)           Junggon Kim (PNM comments)\n    Christopher Forseth (animated gif)     Daniel Gibson (16-bit TGA)\n                                           socks-the-fox (16-bit PNG)\n                                           Jeremy Sawicki (handle all ImageNet JPGs)\n Optimizations & bugfixes                  Mikhail Morozov (1-bit BMP)\n    Fabian \"ryg\" Giesen                    Anael Seghezzi (is-16-bit query)\n    Arseny Kapoulkine                      Simon Breuss (16-bit PNM)\n    John-Mark Allen\n    Carmelo J Fdez-Aguera\n\n Bug & warning fixes\n    Marc LeBlanc            David Woo          Guillaume George     Martins Mozeiko\n    Christpher Lloyd        Jerry Jansson      Joseph Thomson       Blazej Dariusz Roszkowski\n    Phil Jordan                                Dave Moore           Roy Eltham\n    Hayaki Saito            Nathan Reed        Won Chun\n    Luke Graham             Johan Duparc       Nick Verigakis       the Horde3D community\n    Thomas Ruf              Ronny Chevalier                         github:rlyeh\n    Janez Zemva             John Bartholomew   Michal Cichon        github:romigrou\n    Jonathan Blow           Ken Hamada         Tero Hanninen        github:svdijk\n    Eugene Golushkov        Laurent Gomila     Cort Stratton        github:snagar\n    Aruelien Pocheville     Sergio Gonzalez    Thibault Reuille     github:Zelex\n    Cass Everitt            Ryamond Barbiero                        github:grim210\n    Paul Du Bois            Engin Manap        Aldo Culquicondor    github:sammyhw\n    Philipp Wiesemann       Dale Weiler        Oriol Ferrer Mesia   github:phprus\n    Josh Tobin              Neil Bickford      Matthew Gregan       github:poppolopoppo\n    Julian Raschke          Gregory Mullen     Christian Floisand   github:darealshinji\n    Baldur Karlsson         Kevin Schmidt      JR Smith             github:Michaelangel007\n                            Brad Weinberger    Matvey Cherevko      github:mosra\n    Luca Sas                Alexander Veselov  Zack Middleton       [reserved]\n    Ryan C. Gordon          [reserved]                              [reserved]\n                     DO NOT ADD YOUR NAME HERE\n\n                     Jacko Dirks\n\n  To add your name to the credits, pick a random blank space in the middle and fill it.\n  80% of merge conflicts on stb PRs are due to people adding their name at the end\n  of the credits.\n*/\n\n#ifndef STBI_INCLUDE_STB_IMAGE_H\n#define STBI_INCLUDE_STB_IMAGE_H\n\n// DOCUMENTATION\n//\n// Limitations:\n//    - no 12-bit-per-channel JPEG\n//    - no JPEGs with arithmetic coding\n//    - GIF always returns *comp=4\n//\n// Basic usage (see HDR discussion below for HDR usage):\n//    int x,y,n;\n//    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);\n//    // ... process data if not NULL ...\n//    // ... x = width, y = height, n = # 8-bit components per pixel ...\n//    // ... replace '0' with '1'..'4' to force that many components per pixel\n//    // ... but 'n' will always be the number that it would have been if you said 0\n//    stbi_image_free(data);\n//\n// Standard parameters:\n//    int *x                 -- outputs image width in pixels\n//    int *y                 -- outputs image height in pixels\n//    int *channels_in_file  -- outputs # of image components in image file\n//    int desired_channels   -- if non-zero, # of image components requested in result\n//\n// The return value from an image loader is an 'unsigned char *' which points\n// to the pixel data, or NULL on an allocation failure or if the image is\n// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,\n// with each pixel consisting of N interleaved 8-bit components; the first\n// pixel pointed to is top-left-most in the image. There is no padding between\n// image scanlines or between pixels, regardless of format. The number of\n// components N is 'desired_channels' if desired_channels is non-zero, or\n// *channels_in_file otherwise. If desired_channels is non-zero,\n// *channels_in_file has the number of components that _would_ have been\n// output otherwise. E.g. if you set desired_channels to 4, you will always\n// get RGBA output, but you can check *channels_in_file to see if it's trivially\n// opaque because e.g. there were only 3 channels in the source image.\n//\n// An output image with N components has the following components interleaved\n// in this order in each pixel:\n//\n//     N=#comp     components\n//       1           grey\n//       2           grey, alpha\n//       3           red, green, blue\n//       4           red, green, blue, alpha\n//\n// If image loading fails for any reason, the return value will be NULL,\n// and *x, *y, *channels_in_file will be unchanged. The function\n// stbi_failure_reason() can be queried for an extremely brief, end-user\n// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS\n// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly\n// more user-friendly ones.\n//\n// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.\n//\n// To query the width, height and component count of an image without having to\n// decode the full file, you can use the stbi_info family of functions:\n//\n//   int x,y,n,ok;\n//   ok = stbi_info(filename, &x, &y, &n);\n//   // returns ok=1 and sets x, y, n if image is a supported format,\n//   // 0 otherwise.\n//\n// Note that stb_image pervasively uses ints in its public API for sizes,\n// including sizes of memory buffers. This is now part of the API and thus\n// hard to change without causing breakage. As a result, the various image\n// loaders all have certain limits on image size; these differ somewhat\n// by format but generally boil down to either just under 2GB or just under\n// 1GB. When the decoded image would be larger than this, stb_image decoding\n// will fail.\n//\n// Additionally, stb_image will reject image files that have any of their\n// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS,\n// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit,\n// the only way to have an image with such dimensions load correctly\n// is for it to have a rather extreme aspect ratio. Either way, the\n// assumption here is that such larger images are likely to be malformed\n// or malicious. If you do need to load an image with individual dimensions\n// larger than that, and it still fits in the overall size limit, you can\n// #define STBI_MAX_DIMENSIONS on your own to be something larger.\n//\n// ===========================================================================\n//\n// UNICODE:\n//\n//   If compiling for Windows and you wish to use Unicode filenames, compile\n//   with\n//       #define STBI_WINDOWS_UTF8\n//   and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert\n//   Windows wchar_t filenames to utf8.\n//\n// ===========================================================================\n//\n// Philosophy\n//\n// stb libraries are designed with the following priorities:\n//\n//    1. easy to use\n//    2. easy to maintain\n//    3. good performance\n//\n// Sometimes I let \"good performance\" creep up in priority over \"easy to maintain\",\n// and for best performance I may provide less-easy-to-use APIs that give higher\n// performance, in addition to the easy-to-use ones. Nevertheless, it's important\n// to keep in mind that from the standpoint of you, a client of this library,\n// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.\n//\n// Some secondary priorities arise directly from the first two, some of which\n// provide more explicit reasons why performance can't be emphasized.\n//\n//    - Portable (\"ease of use\")\n//    - Small source code footprint (\"easy to maintain\")\n//    - No dependencies (\"ease of use\")\n//\n// ===========================================================================\n//\n// I/O callbacks\n//\n// I/O callbacks allow you to read from arbitrary sources, like packaged\n// files or some other source. Data read from callbacks are processed\n// through a small internal buffer (currently 128 bytes) to try to reduce\n// overhead.\n//\n// The three functions you must define are \"read\" (reads some bytes of data),\n// \"skip\" (skips some bytes of data), \"eof\" (reports if the stream is at the end).\n//\n// ===========================================================================\n//\n// SIMD support\n//\n// The JPEG decoder will try to automatically use SIMD kernels on x86 when\n// supported by the compiler. For ARM Neon support, you must explicitly\n// request it.\n//\n// (The old do-it-yourself SIMD API is no longer supported in the current\n// code.)\n//\n// On x86, SSE2 will automatically be used when available based on a run-time\n// test; if not, the generic C versions are used as a fall-back. On ARM targets,\n// the typical path is to have separate builds for NEON and non-NEON devices\n// (at least this is true for iOS and Android). Therefore, the NEON support is\n// toggled by a build flag: define STBI_NEON to get NEON loops.\n//\n// If for some reason you do not want to use any of SIMD code, or if\n// you have issues compiling it, you can disable it entirely by\n// defining STBI_NO_SIMD.\n//\n// ===========================================================================\n//\n// HDR image support   (disable by defining STBI_NO_HDR)\n//\n// stb_image supports loading HDR images in general, and currently the Radiance\n// .HDR file format specifically. You can still load any file through the existing\n// interface; if you attempt to load an HDR file, it will be automatically remapped\n// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;\n// both of these constants can be reconfigured through this interface:\n//\n//     stbi_hdr_to_ldr_gamma(2.2f);\n//     stbi_hdr_to_ldr_scale(1.0f);\n//\n// (note, do not use _inverse_ constants; stbi_image will invert them\n// appropriately).\n//\n// Additionally, there is a new, parallel interface for loading files as\n// (linear) floats to preserve the full dynamic range:\n//\n//    float *data = stbi_loadf(filename, &x, &y, &n, 0);\n//\n// If you load LDR images through this interface, those images will\n// be promoted to floating point values, run through the inverse of\n// constants corresponding to the above:\n//\n//     stbi_ldr_to_hdr_scale(1.0f);\n//     stbi_ldr_to_hdr_gamma(2.2f);\n//\n// Finally, given a filename (or an open file or memory block--see header\n// file for details) containing image data, you can query for the \"most\n// appropriate\" interface to use (that is, whether the image is HDR or\n// not), using:\n//\n//     stbi_is_hdr(char *filename);\n//\n// ===========================================================================\n//\n// iPhone PNG support:\n//\n// We optionally support converting iPhone-formatted PNGs (which store\n// premultiplied BGRA) back to RGB, even though they're internally encoded\n// differently. To enable this conversion, call\n// stbi_convert_iphone_png_to_rgb(1).\n//\n// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per\n// pixel to remove any premultiplied alpha *only* if the image file explicitly\n// says there's premultiplied data (currently only happens in iPhone images,\n// and only if iPhone convert-to-rgb processing is on).\n//\n// ===========================================================================\n//\n// ADDITIONAL CONFIGURATION\n//\n//  - You can suppress implementation of any of the decoders to reduce\n//    your code footprint by #defining one or more of the following\n//    symbols before creating the implementation.\n//\n//        STBI_NO_JPEG\n//        STBI_NO_PNG\n//        STBI_NO_BMP\n//        STBI_NO_PSD\n//        STBI_NO_TGA\n//        STBI_NO_GIF\n//        STBI_NO_HDR\n//        STBI_NO_PIC\n//        STBI_NO_PNM   (.ppm and .pgm)\n//\n//  - You can request *only* certain decoders and suppress all other ones\n//    (this will be more forward-compatible, as addition of new decoders\n//    doesn't require you to disable them explicitly):\n//\n//        STBI_ONLY_JPEG\n//        STBI_ONLY_PNG\n//        STBI_ONLY_BMP\n//        STBI_ONLY_PSD\n//        STBI_ONLY_TGA\n//        STBI_ONLY_GIF\n//        STBI_ONLY_HDR\n//        STBI_ONLY_PIC\n//        STBI_ONLY_PNM   (.ppm and .pgm)\n//\n//   - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still\n//     want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB\n//\n//  - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater\n//    than that size (in either width or height) without further processing.\n//    This is to let programs in the wild set an upper bound to prevent\n//    denial-of-service attacks on untrusted data, as one could generate a\n//    valid image of gigantic dimensions and force stb_image to allocate a\n//    huge block of memory and spend disproportionate time decoding it. By\n//    default this is set to (1 << 24), which is 16777216, but that's still\n//    very big.\n\n#ifndef STBI_NO_STDIO\n#include <stdio.h>\n#endif // STBI_NO_STDIO\n\n#define STBI_VERSION 1\n\nenum\n{\n   STBI_default = 0, // only used for desired_channels\n\n   STBI_grey       = 1,\n   STBI_grey_alpha = 2,\n   STBI_rgb        = 3,\n   STBI_rgb_alpha  = 4\n};\n\n#include <stdlib.h>\ntypedef unsigned char stbi_uc;\ntypedef unsigned short stbi_us;\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef STBIDEF\n#ifdef STB_IMAGE_STATIC\n#define STBIDEF static\n#else\n#define STBIDEF extern\n#endif\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// PRIMARY API - works on images of any type\n//\n\n//\n// load image by filename, open file, or memory buffer\n//\n\ntypedef struct\n{\n   int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read\n   void     (*skip)  (void *user,int n);                 // skip the next 'n' bytes, or 'unget' the last -n bytes if negative\n   int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data\n} stbi_io_callbacks;\n\n////////////////////////////////////\n//\n// 8-bits-per-channel interface\n//\n\nSTBIDEF stbi_uc *stbi_load_from_memory   (stbi_uc           const *buffer, int len   , int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk  , void *user, int *x, int *y, int *channels_in_file, int desired_channels);\n\n#ifndef STBI_NO_STDIO\nSTBIDEF stbi_uc *stbi_load            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_uc *stbi_load_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);\n// for stbi_load_from_file, file pointer is left pointing immediately after image\n#endif\n\n#ifndef STBI_NO_GIF\nSTBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);\n#endif\n\n#ifdef STBI_WINDOWS_UTF8\nSTBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);\n#endif\n\n////////////////////////////////////\n//\n// 16-bits-per-channel interface\n//\n\nSTBIDEF stbi_us *stbi_load_16_from_memory   (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);\n\n#ifndef STBI_NO_STDIO\nSTBIDEF stbi_us *stbi_load_16          (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);\n#endif\n\n////////////////////////////////////\n//\n// float-per-channel interface\n//\n#ifndef STBI_NO_LINEAR\n   STBIDEF float *stbi_loadf_from_memory     (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);\n   STBIDEF float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y,  int *channels_in_file, int desired_channels);\n\n   #ifndef STBI_NO_STDIO\n   STBIDEF float *stbi_loadf            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);\n   STBIDEF float *stbi_loadf_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);\n   #endif\n#endif\n\n#ifndef STBI_NO_HDR\n   STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma);\n   STBIDEF void   stbi_hdr_to_ldr_scale(float scale);\n#endif // STBI_NO_HDR\n\n#ifndef STBI_NO_LINEAR\n   STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma);\n   STBIDEF void   stbi_ldr_to_hdr_scale(float scale);\n#endif // STBI_NO_LINEAR\n\n// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR\nSTBIDEF int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);\nSTBIDEF int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_is_hdr          (char const *filename);\nSTBIDEF int      stbi_is_hdr_from_file(FILE *f);\n#endif // STBI_NO_STDIO\n\n\n// get a VERY brief reason for failure\n// on most compilers (and ALL modern mainstream compilers) this is threadsafe\nSTBIDEF const char *stbi_failure_reason  (void);\n\n// free the loaded image -- this is just free()\nSTBIDEF void     stbi_image_free      (void *retval_from_stbi_load);\n\n// get image dimensions & components without fully decoding\nSTBIDEF int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);\nSTBIDEF int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);\nSTBIDEF int      stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);\nSTBIDEF int      stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_info               (char const *filename,     int *x, int *y, int *comp);\nSTBIDEF int      stbi_info_from_file     (FILE *f,                  int *x, int *y, int *comp);\nSTBIDEF int      stbi_is_16_bit          (char const *filename);\nSTBIDEF int      stbi_is_16_bit_from_file(FILE *f);\n#endif\n\n\n\n// for image formats that explicitly notate that they have premultiplied alpha,\n// we just return the colors as stored in the file. set this flag to force\n// unpremultiplication. results are undefined if the unpremultiply overflow.\nSTBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);\n\n// indicate whether we should process iphone images back to canonical format,\n// or just pass them through \"as-is\"\nSTBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);\n\n// flip the image vertically, so the first pixel in the output array is the bottom left\nSTBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);\n\n// as above, but only applies to images loaded on the thread that calls the function\n// this function is only available if your compiler supports thread-local variables;\n// calling it will fail to link if your compiler doesn't\nSTBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);\nSTBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert);\nSTBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);\n\n// ZLIB client - used by PNG, available for other purposes\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);\nSTBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);\nSTBIDEF int   stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);\n\nSTBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);\nSTBIDEF int   stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);\n\n\n#ifdef __cplusplus\n}\n#endif\n\n//\n//\n////   end header file   /////////////////////////////////////////////////////\n#endif // STBI_INCLUDE_STB_IMAGE_H\n\n#ifdef STB_IMAGE_IMPLEMENTATION\n\n#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \\\n  || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \\\n  || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \\\n  || defined(STBI_ONLY_ZLIB)\n   #ifndef STBI_ONLY_JPEG\n   #define STBI_NO_JPEG\n   #endif\n   #ifndef STBI_ONLY_PNG\n   #define STBI_NO_PNG\n   #endif\n   #ifndef STBI_ONLY_BMP\n   #define STBI_NO_BMP\n   #endif\n   #ifndef STBI_ONLY_PSD\n   #define STBI_NO_PSD\n   #endif\n   #ifndef STBI_ONLY_TGA\n   #define STBI_NO_TGA\n   #endif\n   #ifndef STBI_ONLY_GIF\n   #define STBI_NO_GIF\n   #endif\n   #ifndef STBI_ONLY_HDR\n   #define STBI_NO_HDR\n   #endif\n   #ifndef STBI_ONLY_PIC\n   #define STBI_NO_PIC\n   #endif\n   #ifndef STBI_ONLY_PNM\n   #define STBI_NO_PNM\n   #endif\n#endif\n\n#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)\n#define STBI_NO_ZLIB\n#endif\n\n\n#include <stdarg.h>\n#include <stddef.h> // ptrdiff_t on osx\n#include <stdlib.h>\n#include <string.h>\n#include <limits.h>\n\n#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)\n#include <math.h>  // ldexp, pow\n#endif\n\n#ifndef STBI_NO_STDIO\n#include <stdio.h>\n#endif\n\n#ifndef STBI_ASSERT\n#include <assert.h>\n#define STBI_ASSERT(x) assert(x)\n#endif\n\n#ifdef __cplusplus\n#define STBI_EXTERN extern \"C\"\n#else\n#define STBI_EXTERN extern\n#endif\n\n\n#ifndef _MSC_VER\n   #ifdef __cplusplus\n   #define stbi_inline inline\n   #else\n   #define stbi_inline\n   #endif\n#else\n   #define stbi_inline __forceinline\n#endif\n\n#ifndef STBI_NO_THREAD_LOCALS\n   #if defined(__cplusplus) &&  __cplusplus >= 201103L\n      #define STBI_THREAD_LOCAL       thread_local\n   #elif defined(__GNUC__) && __GNUC__ < 5\n      #define STBI_THREAD_LOCAL       __thread\n   #elif defined(_MSC_VER)\n      #define STBI_THREAD_LOCAL       __declspec(thread)\n   #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)\n      #define STBI_THREAD_LOCAL       _Thread_local\n   #endif\n\n   #ifndef STBI_THREAD_LOCAL\n      #if defined(__GNUC__)\n        #define STBI_THREAD_LOCAL       __thread\n      #endif\n   #endif\n#endif\n\n#if defined(_MSC_VER) || defined(__SYMBIAN32__)\ntypedef unsigned short stbi__uint16;\ntypedef   signed short stbi__int16;\ntypedef unsigned int   stbi__uint32;\ntypedef   signed int   stbi__int32;\n#else\n#include <stdint.h>\ntypedef uint16_t stbi__uint16;\ntypedef int16_t  stbi__int16;\ntypedef uint32_t stbi__uint32;\ntypedef int32_t  stbi__int32;\n#endif\n\n// should produce compiler error if size is wrong\ntypedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];\n\n#ifdef _MSC_VER\n#define STBI_NOTUSED(v)  (void)(v)\n#else\n#define STBI_NOTUSED(v)  (void)sizeof(v)\n#endif\n\n#ifdef _MSC_VER\n#define STBI_HAS_LROTL\n#endif\n\n#ifdef STBI_HAS_LROTL\n   #define stbi_lrot(x,y)  _lrotl(x,y)\n#else\n   #define stbi_lrot(x,y)  (((x) << (y)) | ((x) >> (-(y) & 31)))\n#endif\n\n#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))\n// ok\n#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)\n// ok\n#else\n#error \"Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED).\"\n#endif\n\n#ifndef STBI_MALLOC\n#define STBI_MALLOC(sz)           malloc(sz)\n#define STBI_REALLOC(p,newsz)     realloc(p,newsz)\n#define STBI_FREE(p)              free(p)\n#endif\n\n#ifndef STBI_REALLOC_SIZED\n#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)\n#endif\n\n// x86/x64 detection\n#if defined(__x86_64__) || defined(_M_X64)\n#define STBI__X64_TARGET\n#elif defined(__i386) || defined(_M_IX86)\n#define STBI__X86_TARGET\n#endif\n\n#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)\n// gcc doesn't support sse2 intrinsics unless you compile with -msse2,\n// which in turn means it gets to use SSE2 everywhere. This is unfortunate,\n// but previous attempts to provide the SSE2 functions with runtime\n// detection caused numerous issues. The way architecture extensions are\n// exposed in GCC/Clang is, sadly, not really suited for one-file libs.\n// New behavior: if compiled with -msse2, we use SSE2 without any\n// detection; if not, we don't use it at all.\n#define STBI_NO_SIMD\n#endif\n\n#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)\n// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET\n//\n// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the\n// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.\n// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not\n// simultaneously enabling \"-mstackrealign\".\n//\n// See https://github.com/nothings/stb/issues/81 for more information.\n//\n// So default to no SSE2 on 32-bit MinGW. If you've read this far and added\n// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.\n#define STBI_NO_SIMD\n#endif\n\n#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET))\n#define STBI_SSE2\n#include <emmintrin.h>\n\n#ifdef _MSC_VER\n\n#if _MSC_VER >= 1400  // not VC6\n#include <intrin.h> // __cpuid\nstatic int stbi__cpuid3(void)\n{\n   int info[4];\n   __cpuid(info,1);\n   return info[3];\n}\n#else\nstatic int stbi__cpuid3(void)\n{\n   int res;\n   __asm {\n      mov  eax,1\n      cpuid\n      mov  res,edx\n   }\n   return res;\n}\n#endif\n\n#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name\n\n#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)\nstatic int stbi__sse2_available(void)\n{\n   int info3 = stbi__cpuid3();\n   return ((info3 >> 26) & 1) != 0;\n}\n#endif\n\n#else // assume GCC-style if not VC++\n#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))\n\n#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)\nstatic int stbi__sse2_available(void)\n{\n   // If we're even attempting to compile this on GCC/Clang, that means\n   // -msse2 is on, which means the compiler is allowed to use SSE2\n   // instructions at will, and so are we.\n   return 1;\n}\n#endif\n\n#endif\n#endif\n\n// ARM NEON\n#if defined(STBI_NO_SIMD) && defined(STBI_NEON)\n#undef STBI_NEON\n#endif\n\n#ifdef STBI_NEON\n#include <arm_neon.h>\n#ifdef _MSC_VER\n#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name\n#else\n#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))\n#endif\n#endif\n\n#ifndef STBI_SIMD_ALIGN\n#define STBI_SIMD_ALIGN(type, name) type name\n#endif\n\n#ifndef STBI_MAX_DIMENSIONS\n#define STBI_MAX_DIMENSIONS (1 << 24)\n#endif\n\n///////////////////////////////////////////////\n//\n//  stbi__context struct and start_xxx functions\n\n// stbi__context structure is our basic context used by all images, so it\n// contains all the IO context, plus some basic image information\ntypedef struct\n{\n   stbi__uint32 img_x, img_y;\n   int img_n, img_out_n;\n\n   stbi_io_callbacks io;\n   void *io_user_data;\n\n   int read_from_callbacks;\n   int buflen;\n   stbi_uc buffer_start[128];\n   int callback_already_read;\n\n   stbi_uc *img_buffer, *img_buffer_end;\n   stbi_uc *img_buffer_original, *img_buffer_original_end;\n} stbi__context;\n\n\nstatic void stbi__refill_buffer(stbi__context *s);\n\n// initialize a memory-decode context\nstatic void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)\n{\n   s->io.read = NULL;\n   s->read_from_callbacks = 0;\n   s->callback_already_read = 0;\n   s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;\n   s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;\n}\n\n// initialize a callback-based context\nstatic void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)\n{\n   s->io = *c;\n   s->io_user_data = user;\n   s->buflen = sizeof(s->buffer_start);\n   s->read_from_callbacks = 1;\n   s->callback_already_read = 0;\n   s->img_buffer = s->img_buffer_original = s->buffer_start;\n   stbi__refill_buffer(s);\n   s->img_buffer_original_end = s->img_buffer_end;\n}\n\n#ifndef STBI_NO_STDIO\n\nstatic int stbi__stdio_read(void *user, char *data, int size)\n{\n   return (int) fread(data,1,size,(FILE*) user);\n}\n\nstatic void stbi__stdio_skip(void *user, int n)\n{\n   int ch;\n   fseek((FILE*) user, n, SEEK_CUR);\n   ch = fgetc((FILE*) user);  /* have to read a byte to reset feof()'s flag */\n   if (ch != EOF) {\n      ungetc(ch, (FILE *) user);  /* push byte back onto stream if valid. */\n   }\n}\n\nstatic int stbi__stdio_eof(void *user)\n{\n   return feof((FILE*) user) || ferror((FILE *) user);\n}\n\nstatic stbi_io_callbacks stbi__stdio_callbacks =\n{\n   stbi__stdio_read,\n   stbi__stdio_skip,\n   stbi__stdio_eof,\n};\n\nstatic void stbi__start_file(stbi__context *s, FILE *f)\n{\n   stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);\n}\n\n//static void stop_file(stbi__context *s) { }\n\n#endif // !STBI_NO_STDIO\n\nstatic void stbi__rewind(stbi__context *s)\n{\n   // conceptually rewind SHOULD rewind to the beginning of the stream,\n   // but we just rewind to the beginning of the initial buffer, because\n   // we only use it after doing 'test', which only ever looks at at most 92 bytes\n   s->img_buffer = s->img_buffer_original;\n   s->img_buffer_end = s->img_buffer_original_end;\n}\n\nenum\n{\n   STBI_ORDER_RGB,\n   STBI_ORDER_BGR\n};\n\ntypedef struct\n{\n   int bits_per_channel;\n   int num_channels;\n   int channel_order;\n} stbi__result_info;\n\n#ifndef STBI_NO_JPEG\nstatic int      stbi__jpeg_test(stbi__context *s);\nstatic void    *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PNG\nstatic int      stbi__png_test(stbi__context *s);\nstatic void    *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__png_info(stbi__context *s, int *x, int *y, int *comp);\nstatic int      stbi__png_is16(stbi__context *s);\n#endif\n\n#ifndef STBI_NO_BMP\nstatic int      stbi__bmp_test(stbi__context *s);\nstatic void    *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_TGA\nstatic int      stbi__tga_test(stbi__context *s);\nstatic void    *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PSD\nstatic int      stbi__psd_test(stbi__context *s);\nstatic void    *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);\nstatic int      stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);\nstatic int      stbi__psd_is16(stbi__context *s);\n#endif\n\n#ifndef STBI_NO_HDR\nstatic int      stbi__hdr_test(stbi__context *s);\nstatic float   *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PIC\nstatic int      stbi__pic_test(stbi__context *s);\nstatic void    *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_GIF\nstatic int      stbi__gif_test(stbi__context *s);\nstatic void    *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic void    *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp);\nstatic int      stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PNM\nstatic int      stbi__pnm_test(stbi__context *s);\nstatic void    *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);\nstatic int      stbi__pnm_is16(stbi__context *s);\n#endif\n\nstatic\n#ifdef STBI_THREAD_LOCAL\nSTBI_THREAD_LOCAL\n#endif\nconst char *stbi__g_failure_reason;\n\nSTBIDEF const char *stbi_failure_reason(void)\n{\n   return stbi__g_failure_reason;\n}\n\n#ifndef STBI_NO_FAILURE_STRINGS\nstatic int stbi__err(const char *str)\n{\n   stbi__g_failure_reason = str;\n   return 0;\n}\n#endif\n\nstatic void *stbi__malloc(size_t size)\n{\n    return STBI_MALLOC(size);\n}\n\n// stb_image uses ints pervasively, including for offset calculations.\n// therefore the largest decoded image size we can support with the\n// current code, even on 64-bit targets, is INT_MAX. this is not a\n// significant limitation for the intended use case.\n//\n// we do, however, need to make sure our size calculations don't\n// overflow. hence a few helper functions for size calculations that\n// multiply integers together, making sure that they're non-negative\n// and no overflow occurs.\n\n// return 1 if the sum is valid, 0 on overflow.\n// negative terms are considered invalid.\nstatic int stbi__addsizes_valid(int a, int b)\n{\n   if (b < 0) return 0;\n   // now 0 <= b <= INT_MAX, hence also\n   // 0 <= INT_MAX - b <= INTMAX.\n   // And \"a + b <= INT_MAX\" (which might overflow) is the\n   // same as a <= INT_MAX - b (no overflow)\n   return a <= INT_MAX - b;\n}\n\n// returns 1 if the product is valid, 0 on overflow.\n// negative factors are considered invalid.\nstatic int stbi__mul2sizes_valid(int a, int b)\n{\n   if (a < 0 || b < 0) return 0;\n   if (b == 0) return 1; // mul-by-0 is always safe\n   // portable way to check for no overflows in a*b\n   return a <= INT_MAX/b;\n}\n\n#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)\n// returns 1 if \"a*b + add\" has no negative terms/factors and doesn't overflow\nstatic int stbi__mad2sizes_valid(int a, int b, int add)\n{\n   return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);\n}\n#endif\n\n// returns 1 if \"a*b*c + add\" has no negative terms/factors and doesn't overflow\nstatic int stbi__mad3sizes_valid(int a, int b, int c, int add)\n{\n   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&\n      stbi__addsizes_valid(a*b*c, add);\n}\n\n// returns 1 if \"a*b*c*d + add\" has no negative terms/factors and doesn't overflow\n#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)\nstatic int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)\n{\n   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&\n      stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);\n}\n#endif\n\n#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)\n// mallocs with size overflow checking\nstatic void *stbi__malloc_mad2(int a, int b, int add)\n{\n   if (!stbi__mad2sizes_valid(a, b, add)) return NULL;\n   return stbi__malloc(a*b + add);\n}\n#endif\n\nstatic void *stbi__malloc_mad3(int a, int b, int c, int add)\n{\n   if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;\n   return stbi__malloc(a*b*c + add);\n}\n\n#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)\nstatic void *stbi__malloc_mad4(int a, int b, int c, int d, int add)\n{\n   if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;\n   return stbi__malloc(a*b*c*d + add);\n}\n#endif\n\n// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow.\nstatic int stbi__addints_valid(int a, int b)\n{\n   if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow\n   if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0.\n   return a <= INT_MAX - b;\n}\n\n// returns 1 if the product of two signed shorts is valid, 0 on overflow.\nstatic int stbi__mul2shorts_valid(short a, short b)\n{\n   if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow\n   if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid\n   if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN\n   return a >= SHRT_MIN / b;\n}\n\n// stbi__err - error\n// stbi__errpf - error returning pointer to float\n// stbi__errpuc - error returning pointer to unsigned char\n\n#ifdef STBI_NO_FAILURE_STRINGS\n   #define stbi__err(x,y)  0\n#elif defined(STBI_FAILURE_USERMSG)\n   #define stbi__err(x,y)  stbi__err(y)\n#else\n   #define stbi__err(x,y)  stbi__err(x)\n#endif\n\n#define stbi__errpf(x,y)   ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))\n#define stbi__errpuc(x,y)  ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))\n\nSTBIDEF void stbi_image_free(void *retval_from_stbi_load)\n{\n   STBI_FREE(retval_from_stbi_load);\n}\n\n#ifndef STBI_NO_LINEAR\nstatic float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);\n#endif\n\n#ifndef STBI_NO_HDR\nstatic stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp);\n#endif\n\nstatic int stbi__vertically_flip_on_load_global = 0;\n\nSTBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)\n{\n   stbi__vertically_flip_on_load_global = flag_true_if_should_flip;\n}\n\n#ifndef STBI_THREAD_LOCAL\n#define stbi__vertically_flip_on_load  stbi__vertically_flip_on_load_global\n#else\nstatic STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set;\n\nSTBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip)\n{\n   stbi__vertically_flip_on_load_local = flag_true_if_should_flip;\n   stbi__vertically_flip_on_load_set = 1;\n}\n\n#define stbi__vertically_flip_on_load  (stbi__vertically_flip_on_load_set       \\\n                                         ? stbi__vertically_flip_on_load_local  \\\n                                         : stbi__vertically_flip_on_load_global)\n#endif // STBI_THREAD_LOCAL\n\nstatic void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)\n{\n   memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields\n   ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed\n   ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order\n   ri->num_channels = 0;\n\n   // test the formats with a very explicit header first (at least a FOURCC\n   // or distinctive magic number first)\n   #ifndef STBI_NO_PNG\n   if (stbi__png_test(s))  return stbi__png_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_BMP\n   if (stbi__bmp_test(s))  return stbi__bmp_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_GIF\n   if (stbi__gif_test(s))  return stbi__gif_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_test(s))  return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);\n   #else\n   STBI_NOTUSED(bpc);\n   #endif\n   #ifndef STBI_NO_PIC\n   if (stbi__pic_test(s))  return stbi__pic_load(s,x,y,comp,req_comp, ri);\n   #endif\n\n   // then the formats that can end up attempting to load with just 1 or 2\n   // bytes matching expectations; these are prone to false positives, so\n   // try them later\n   #ifndef STBI_NO_JPEG\n   if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_test(s))  return stbi__pnm_load(s,x,y,comp,req_comp, ri);\n   #endif\n\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_test(s)) {\n      float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri);\n      return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);\n   }\n   #endif\n\n   #ifndef STBI_NO_TGA\n   // test tga last because it's a crappy test!\n   if (stbi__tga_test(s))\n      return stbi__tga_load(s,x,y,comp,req_comp, ri);\n   #endif\n\n   return stbi__errpuc(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\nstatic stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels)\n{\n   int i;\n   int img_len = w * h * channels;\n   stbi_uc *reduced;\n\n   reduced = (stbi_uc *) stbi__malloc(img_len);\n   if (reduced == NULL) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   for (i = 0; i < img_len; ++i)\n      reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling\n\n   STBI_FREE(orig);\n   return reduced;\n}\n\nstatic stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels)\n{\n   int i;\n   int img_len = w * h * channels;\n   stbi__uint16 *enlarged;\n\n   enlarged = (stbi__uint16 *) stbi__malloc(img_len*2);\n   if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   for (i = 0; i < img_len; ++i)\n      enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff\n\n   STBI_FREE(orig);\n   return enlarged;\n}\n\nstatic void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)\n{\n   int row;\n   size_t bytes_per_row = (size_t)w * bytes_per_pixel;\n   stbi_uc temp[2048];\n   stbi_uc *bytes = (stbi_uc *)image;\n\n   for (row = 0; row < (h>>1); row++) {\n      stbi_uc *row0 = bytes + row*bytes_per_row;\n      stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row;\n      // swap row0 with row1\n      size_t bytes_left = bytes_per_row;\n      while (bytes_left) {\n         size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp);\n         memcpy(temp, row0, bytes_copy);\n         memcpy(row0, row1, bytes_copy);\n         memcpy(row1, temp, bytes_copy);\n         row0 += bytes_copy;\n         row1 += bytes_copy;\n         bytes_left -= bytes_copy;\n      }\n   }\n}\n\n#ifndef STBI_NO_GIF\nstatic void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel)\n{\n   int slice;\n   int slice_size = w * h * bytes_per_pixel;\n\n   stbi_uc *bytes = (stbi_uc *)image;\n   for (slice = 0; slice < z; ++slice) {\n      stbi__vertical_flip(bytes, w, h, bytes_per_pixel);\n      bytes += slice_size;\n   }\n}\n#endif\n\nstatic unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__result_info ri;\n   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);\n\n   if (result == NULL)\n      return NULL;\n\n   // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.\n   STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);\n\n   if (ri.bits_per_channel != 8) {\n      result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);\n      ri.bits_per_channel = 8;\n   }\n\n   // @TODO: move stbi__convert_format to here\n\n   if (stbi__vertically_flip_on_load) {\n      int channels = req_comp ? req_comp : *comp;\n      stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc));\n   }\n\n   return (unsigned char *) result;\n}\n\nstatic stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__result_info ri;\n   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);\n\n   if (result == NULL)\n      return NULL;\n\n   // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.\n   STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);\n\n   if (ri.bits_per_channel != 16) {\n      result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);\n      ri.bits_per_channel = 16;\n   }\n\n   // @TODO: move stbi__convert_format16 to here\n   // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision\n\n   if (stbi__vertically_flip_on_load) {\n      int channels = req_comp ? req_comp : *comp;\n      stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16));\n   }\n\n   return (stbi__uint16 *) result;\n}\n\n#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR)\nstatic void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)\n{\n   if (stbi__vertically_flip_on_load && result != NULL) {\n      int channels = req_comp ? req_comp : *comp;\n      stbi__vertical_flip(result, *x, *y, channels * sizeof(float));\n   }\n}\n#endif\n\n#ifndef STBI_NO_STDIO\n\n#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)\nSTBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);\nSTBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);\n#endif\n\n#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)\nSTBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)\n{\n\treturn WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);\n}\n#endif\n\nstatic FILE *stbi__fopen(char const *filename, char const *mode)\n{\n   FILE *f;\n#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)\n   wchar_t wMode[64];\n   wchar_t wFilename[1024];\n\tif (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))\n      return 0;\n\n\tif (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))\n      return 0;\n\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n\tif (0 != _wfopen_s(&f, wFilename, wMode))\n\t\tf = 0;\n#else\n   f = _wfopen(wFilename, wMode);\n#endif\n\n#elif defined(_MSC_VER) && _MSC_VER >= 1400\n   if (0 != fopen_s(&f, filename, mode))\n      f=0;\n#else\n   f = fopen(filename, mode);\n#endif\n   return f;\n}\n\n\nSTBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   unsigned char *result;\n   if (!f) return stbi__errpuc(\"can't fopen\", \"Unable to open file\");\n   result = stbi_load_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\nSTBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   unsigned char *result;\n   stbi__context s;\n   stbi__start_file(&s,f);\n   result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);\n   if (result) {\n      // need to 'unget' all the characters in the IO buffer\n      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);\n   }\n   return result;\n}\n\nSTBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__uint16 *result;\n   stbi__context s;\n   stbi__start_file(&s,f);\n   result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp);\n   if (result) {\n      // need to 'unget' all the characters in the IO buffer\n      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);\n   }\n   return result;\n}\n\nSTBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   stbi__uint16 *result;\n   if (!f) return (stbi_us *) stbi__errpuc(\"can't fopen\", \"Unable to open file\");\n   result = stbi_load_from_file_16(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\n\n#endif //!STBI_NO_STDIO\n\nSTBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);\n}\n\nSTBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user);\n   return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);\n}\n\nSTBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);\n}\n\nSTBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);\n}\n\n#ifndef STBI_NO_GIF\nSTBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp)\n{\n   unsigned char *result;\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n\n   result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);\n   if (stbi__vertically_flip_on_load) {\n      stbi__vertical_flip_slices( result, *x, *y, *z, *comp );\n   }\n\n   return result;\n}\n#endif\n\n#ifndef STBI_NO_LINEAR\nstatic float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   unsigned char *data;\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_test(s)) {\n      stbi__result_info ri;\n      float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri);\n      if (hdr_data)\n         stbi__float_postprocess(hdr_data,x,y,comp,req_comp);\n      return hdr_data;\n   }\n   #endif\n   data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp);\n   if (data)\n      return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);\n   return stbi__errpf(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\nSTBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n\nSTBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   float *result;\n   FILE *f = stbi__fopen(filename, \"rb\");\n   if (!f) return stbi__errpf(\"can't fopen\", \"Unable to open file\");\n   result = stbi_loadf_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\nSTBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_file(&s,f);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n#endif // !STBI_NO_STDIO\n\n#endif // !STBI_NO_LINEAR\n\n// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is\n// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always\n// reports false!\n\nSTBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)\n{\n   #ifndef STBI_NO_HDR\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__hdr_test(&s);\n   #else\n   STBI_NOTUSED(buffer);\n   STBI_NOTUSED(len);\n   return 0;\n   #endif\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_is_hdr          (char const *filename)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   int result=0;\n   if (f) {\n      result = stbi_is_hdr_from_file(f);\n      fclose(f);\n   }\n   return result;\n}\n\nSTBIDEF int stbi_is_hdr_from_file(FILE *f)\n{\n   #ifndef STBI_NO_HDR\n   long pos = ftell(f);\n   int res;\n   stbi__context s;\n   stbi__start_file(&s,f);\n   res = stbi__hdr_test(&s);\n   fseek(f, pos, SEEK_SET);\n   return res;\n   #else\n   STBI_NOTUSED(f);\n   return 0;\n   #endif\n}\n#endif // !STBI_NO_STDIO\n\nSTBIDEF int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)\n{\n   #ifndef STBI_NO_HDR\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__hdr_test(&s);\n   #else\n   STBI_NOTUSED(clbk);\n   STBI_NOTUSED(user);\n   return 0;\n   #endif\n}\n\n#ifndef STBI_NO_LINEAR\nstatic float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;\n\nSTBIDEF void   stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }\nSTBIDEF void   stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }\n#endif\n\nstatic float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;\n\nSTBIDEF void   stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }\nSTBIDEF void   stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Common code used by all image loaders\n//\n\nenum\n{\n   STBI__SCAN_load=0,\n   STBI__SCAN_type,\n   STBI__SCAN_header\n};\n\nstatic void stbi__refill_buffer(stbi__context *s)\n{\n   int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);\n   s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original);\n   if (n == 0) {\n      // at end of file, treat same as if from memory, but need to handle case\n      // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file\n      s->read_from_callbacks = 0;\n      s->img_buffer = s->buffer_start;\n      s->img_buffer_end = s->buffer_start+1;\n      *s->img_buffer = 0;\n   } else {\n      s->img_buffer = s->buffer_start;\n      s->img_buffer_end = s->buffer_start + n;\n   }\n}\n\nstbi_inline static stbi_uc stbi__get8(stbi__context *s)\n{\n   if (s->img_buffer < s->img_buffer_end)\n      return *s->img_buffer++;\n   if (s->read_from_callbacks) {\n      stbi__refill_buffer(s);\n      return *s->img_buffer++;\n   }\n   return 0;\n}\n\n#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)\n// nothing\n#else\nstbi_inline static int stbi__at_eof(stbi__context *s)\n{\n   if (s->io.read) {\n      if (!(s->io.eof)(s->io_user_data)) return 0;\n      // if feof() is true, check if buffer = end\n      // special case: we've only got the special 0 character at the end\n      if (s->read_from_callbacks == 0) return 1;\n   }\n\n   return s->img_buffer >= s->img_buffer_end;\n}\n#endif\n\n#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC)\n// nothing\n#else\nstatic void stbi__skip(stbi__context *s, int n)\n{\n   if (n == 0) return;  // already there!\n   if (n < 0) {\n      s->img_buffer = s->img_buffer_end;\n      return;\n   }\n   if (s->io.read) {\n      int blen = (int) (s->img_buffer_end - s->img_buffer);\n      if (blen < n) {\n         s->img_buffer = s->img_buffer_end;\n         (s->io.skip)(s->io_user_data, n - blen);\n         return;\n      }\n   }\n   s->img_buffer += n;\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM)\n// nothing\n#else\nstatic int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)\n{\n   if (s->io.read) {\n      int blen = (int) (s->img_buffer_end - s->img_buffer);\n      if (blen < n) {\n         int res, count;\n\n         memcpy(buffer, s->img_buffer, blen);\n\n         count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);\n         res = (count == (n-blen));\n         s->img_buffer = s->img_buffer_end;\n         return res;\n      }\n   }\n\n   if (s->img_buffer+n <= s->img_buffer_end) {\n      memcpy(buffer, s->img_buffer, n);\n      s->img_buffer += n;\n      return 1;\n   } else\n      return 0;\n}\n#endif\n\n#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)\n// nothing\n#else\nstatic int stbi__get16be(stbi__context *s)\n{\n   int z = stbi__get8(s);\n   return (z << 8) + stbi__get8(s);\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)\n// nothing\n#else\nstatic stbi__uint32 stbi__get32be(stbi__context *s)\n{\n   stbi__uint32 z = stbi__get16be(s);\n   return (z << 16) + stbi__get16be(s);\n}\n#endif\n\n#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)\n// nothing\n#else\nstatic int stbi__get16le(stbi__context *s)\n{\n   int z = stbi__get8(s);\n   return z + (stbi__get8(s) << 8);\n}\n#endif\n\n#ifndef STBI_NO_BMP\nstatic stbi__uint32 stbi__get32le(stbi__context *s)\n{\n   stbi__uint32 z = stbi__get16le(s);\n   z += (stbi__uint32)stbi__get16le(s) << 16;\n   return z;\n}\n#endif\n\n#define STBI__BYTECAST(x)  ((stbi_uc) ((x) & 255))  // truncate int to byte without warnings\n\n#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)\n// nothing\n#else\n//////////////////////////////////////////////////////////////////////////////\n//\n//  generic converter from built-in img_n to req_comp\n//    individual types do this automatically as much as possible (e.g. jpeg\n//    does all cases internally since it needs to colorspace convert anyway,\n//    and it never has alpha, so very few cases ). png can automatically\n//    interleave an alpha=255 channel, but falls back to this for other cases\n//\n//  assume data buffer is malloced, so malloc a new one and free that one\n//  only failure mode is malloc failing\n\nstatic stbi_uc stbi__compute_y(int r, int g, int b)\n{\n   return (stbi_uc) (((r*77) + (g*150) +  (29*b)) >> 8);\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)\n// nothing\n#else\nstatic unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)\n{\n   int i,j;\n   unsigned char *good;\n\n   if (req_comp == img_n) return data;\n   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);\n\n   good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);\n   if (good == NULL) {\n      STBI_FREE(data);\n      return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   }\n\n   for (j=0; j < (int) y; ++j) {\n      unsigned char *src  = data + j * x * img_n   ;\n      unsigned char *dest = good + j * x * req_comp;\n\n      #define STBI__COMBO(a,b)  ((a)*8+(b))\n      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)\n      // convert source image with img_n components to one with req_comp components;\n      // avoid switch per pixel, so use switch per scanline and massive macros\n      switch (STBI__COMBO(img_n, req_comp)) {\n         STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255;                                     } break;\n         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;\n         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255;                     } break;\n         STBI__CASE(2,1) { dest[0]=src[0];                                                  } break;\n         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;\n         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1];                  } break;\n         STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255;        } break;\n         STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255;    } break;\n         STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break;\n         STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];                    } break;\n         default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc(\"unsupported\", \"Unsupported format conversion\");\n      }\n      #undef STBI__CASE\n   }\n\n   STBI_FREE(data);\n   return good;\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)\n// nothing\n#else\nstatic stbi__uint16 stbi__compute_y_16(int r, int g, int b)\n{\n   return (stbi__uint16) (((r*77) + (g*150) +  (29*b)) >> 8);\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)\n// nothing\n#else\nstatic stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)\n{\n   int i,j;\n   stbi__uint16 *good;\n\n   if (req_comp == img_n) return data;\n   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);\n\n   good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);\n   if (good == NULL) {\n      STBI_FREE(data);\n      return (stbi__uint16 *) stbi__errpuc(\"outofmem\", \"Out of memory\");\n   }\n\n   for (j=0; j < (int) y; ++j) {\n      stbi__uint16 *src  = data + j * x * img_n   ;\n      stbi__uint16 *dest = good + j * x * req_comp;\n\n      #define STBI__COMBO(a,b)  ((a)*8+(b))\n      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)\n      // convert source image with img_n components to one with req_comp components;\n      // avoid switch per pixel, so use switch per scanline and massive macros\n      switch (STBI__COMBO(img_n, req_comp)) {\n         STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff;                                     } break;\n         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;\n         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff;                     } break;\n         STBI__CASE(2,1) { dest[0]=src[0];                                                     } break;\n         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;\n         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1];                     } break;\n         STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff;        } break;\n         STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break;\n         STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break;\n         STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];                       } break;\n         default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc(\"unsupported\", \"Unsupported format conversion\");\n      }\n      #undef STBI__CASE\n   }\n\n   STBI_FREE(data);\n   return good;\n}\n#endif\n\n#ifndef STBI_NO_LINEAR\nstatic float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)\n{\n   int i,k,n;\n   float *output;\n   if (!data) return NULL;\n   output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0);\n   if (output == NULL) { STBI_FREE(data); return stbi__errpf(\"outofmem\", \"Out of memory\"); }\n   // compute number of non-alpha components\n   if (comp & 1) n = comp; else n = comp-1;\n   for (i=0; i < x*y; ++i) {\n      for (k=0; k < n; ++k) {\n         output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);\n      }\n   }\n   if (n < comp) {\n      for (i=0; i < x*y; ++i) {\n         output[i*comp + n] = data[i*comp + n]/255.0f;\n      }\n   }\n   STBI_FREE(data);\n   return output;\n}\n#endif\n\n#ifndef STBI_NO_HDR\n#define stbi__float2int(x)   ((int) (x))\nstatic stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp)\n{\n   int i,k,n;\n   stbi_uc *output;\n   if (!data) return NULL;\n   output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0);\n   if (output == NULL) { STBI_FREE(data); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n   // compute number of non-alpha components\n   if (comp & 1) n = comp; else n = comp-1;\n   for (i=0; i < x*y; ++i) {\n      for (k=0; k < n; ++k) {\n         float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;\n         if (z < 0) z = 0;\n         if (z > 255) z = 255;\n         output[i*comp + k] = (stbi_uc) stbi__float2int(z);\n      }\n      if (k < comp) {\n         float z = data[i*comp+k] * 255 + 0.5f;\n         if (z < 0) z = 0;\n         if (z > 255) z = 255;\n         output[i*comp + k] = (stbi_uc) stbi__float2int(z);\n      }\n   }\n   STBI_FREE(data);\n   return output;\n}\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//  \"baseline\" JPEG/JFIF decoder\n//\n//    simple implementation\n//      - doesn't support delayed output of y-dimension\n//      - simple interface (only one output format: 8-bit interleaved RGB)\n//      - doesn't try to recover corrupt jpegs\n//      - doesn't allow partial loading, loading multiple at once\n//      - still fast on x86 (copying globals into locals doesn't help x86)\n//      - allocates lots of intermediate memory (full size of all components)\n//        - non-interleaved case requires this anyway\n//        - allows good upsampling (see next)\n//    high-quality\n//      - upsampled channels are bilinearly interpolated, even across blocks\n//      - quality integer IDCT derived from IJG's 'slow'\n//    performance\n//      - fast huffman; reasonable integer IDCT\n//      - some SIMD kernels for common paths on targets with SSE2/NEON\n//      - uses a lot of intermediate memory, could cache poorly\n\n#ifndef STBI_NO_JPEG\n\n// huffman decoding acceleration\n#define FAST_BITS   9  // larger handles more cases; smaller stomps less cache\n\ntypedef struct\n{\n   stbi_uc  fast[1 << FAST_BITS];\n   // weirdly, repacking this into AoS is a 10% speed loss, instead of a win\n   stbi__uint16 code[256];\n   stbi_uc  values[256];\n   stbi_uc  size[257];\n   unsigned int maxcode[18];\n   int    delta[17];   // old 'firstsymbol' - old 'firstcode'\n} stbi__huffman;\n\ntypedef struct\n{\n   stbi__context *s;\n   stbi__huffman huff_dc[4];\n   stbi__huffman huff_ac[4];\n   stbi__uint16 dequant[4][64];\n   stbi__int16 fast_ac[4][1 << FAST_BITS];\n\n// sizes for components, interleaved MCUs\n   int img_h_max, img_v_max;\n   int img_mcu_x, img_mcu_y;\n   int img_mcu_w, img_mcu_h;\n\n// definition of jpeg image component\n   struct\n   {\n      int id;\n      int h,v;\n      int tq;\n      int hd,ha;\n      int dc_pred;\n\n      int x,y,w2,h2;\n      stbi_uc *data;\n      void *raw_data, *raw_coeff;\n      stbi_uc *linebuf;\n      short   *coeff;   // progressive only\n      int      coeff_w, coeff_h; // number of 8x8 coefficient blocks\n   } img_comp[4];\n\n   stbi__uint32   code_buffer; // jpeg entropy-coded buffer\n   int            code_bits;   // number of valid bits\n   unsigned char  marker;      // marker seen while filling entropy buffer\n   int            nomore;      // flag if we saw a marker so must stop\n\n   int            progressive;\n   int            spec_start;\n   int            spec_end;\n   int            succ_high;\n   int            succ_low;\n   int            eob_run;\n   int            jfif;\n   int            app14_color_transform; // Adobe APP14 tag\n   int            rgb;\n\n   int scan_n, order[4];\n   int restart_interval, todo;\n\n// kernels\n   void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);\n   void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);\n   stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);\n} stbi__jpeg;\n\nstatic int stbi__build_huffman(stbi__huffman *h, int *count)\n{\n   int i,j,k=0;\n   unsigned int code;\n   // build size list for each symbol (from JPEG spec)\n   for (i=0; i < 16; ++i) {\n      for (j=0; j < count[i]; ++j) {\n         h->size[k++] = (stbi_uc) (i+1);\n         if(k >= 257) return stbi__err(\"bad size list\",\"Corrupt JPEG\");\n      }\n   }\n   h->size[k] = 0;\n\n   // compute actual symbols (from jpeg spec)\n   code = 0;\n   k = 0;\n   for(j=1; j <= 16; ++j) {\n      // compute delta to add to code to compute symbol id\n      h->delta[j] = k - code;\n      if (h->size[k] == j) {\n         while (h->size[k] == j)\n            h->code[k++] = (stbi__uint16) (code++);\n         if (code-1 >= (1u << j)) return stbi__err(\"bad code lengths\",\"Corrupt JPEG\");\n      }\n      // compute largest code + 1 for this size, preshifted as needed later\n      h->maxcode[j] = code << (16-j);\n      code <<= 1;\n   }\n   h->maxcode[j] = 0xffffffff;\n\n   // build non-spec acceleration table; 255 is flag for not-accelerated\n   memset(h->fast, 255, 1 << FAST_BITS);\n   for (i=0; i < k; ++i) {\n      int s = h->size[i];\n      if (s <= FAST_BITS) {\n         int c = h->code[i] << (FAST_BITS-s);\n         int m = 1 << (FAST_BITS-s);\n         for (j=0; j < m; ++j) {\n            h->fast[c+j] = (stbi_uc) i;\n         }\n      }\n   }\n   return 1;\n}\n\n// build a table that decodes both magnitude and value of small ACs in\n// one go.\nstatic void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)\n{\n   int i;\n   for (i=0; i < (1 << FAST_BITS); ++i) {\n      stbi_uc fast = h->fast[i];\n      fast_ac[i] = 0;\n      if (fast < 255) {\n         int rs = h->values[fast];\n         int run = (rs >> 4) & 15;\n         int magbits = rs & 15;\n         int len = h->size[fast];\n\n         if (magbits && len + magbits <= FAST_BITS) {\n            // magnitude code followed by receive_extend code\n            int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);\n            int m = 1 << (magbits - 1);\n            if (k < m) k += (~0U << magbits) + 1;\n            // if the result is small enough, we can fit it in fast_ac table\n            if (k >= -128 && k <= 127)\n               fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits));\n         }\n      }\n   }\n}\n\nstatic void stbi__grow_buffer_unsafe(stbi__jpeg *j)\n{\n   do {\n      unsigned int b = j->nomore ? 0 : stbi__get8(j->s);\n      if (b == 0xff) {\n         int c = stbi__get8(j->s);\n         while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes\n         if (c != 0) {\n            j->marker = (unsigned char) c;\n            j->nomore = 1;\n            return;\n         }\n      }\n      j->code_buffer |= b << (24 - j->code_bits);\n      j->code_bits += 8;\n   } while (j->code_bits <= 24);\n}\n\n// (1 << n) - 1\nstatic const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};\n\n// decode a jpeg huffman value from the bitstream\nstbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)\n{\n   unsigned int temp;\n   int c,k;\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n\n   // look at the top FAST_BITS and determine what symbol ID it is,\n   // if the code is <= FAST_BITS\n   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n   k = h->fast[c];\n   if (k < 255) {\n      int s = h->size[k];\n      if (s > j->code_bits)\n         return -1;\n      j->code_buffer <<= s;\n      j->code_bits -= s;\n      return h->values[k];\n   }\n\n   // naive test is to shift the code_buffer down so k bits are\n   // valid, then test against maxcode. To speed this up, we've\n   // preshifted maxcode left so that it has (16-k) 0s at the\n   // end; in other words, regardless of the number of bits, it\n   // wants to be compared against something shifted to have 16;\n   // that way we don't need to shift inside the loop.\n   temp = j->code_buffer >> 16;\n   for (k=FAST_BITS+1 ; ; ++k)\n      if (temp < h->maxcode[k])\n         break;\n   if (k == 17) {\n      // error! code not found\n      j->code_bits -= 16;\n      return -1;\n   }\n\n   if (k > j->code_bits)\n      return -1;\n\n   // convert the huffman code to the symbol id\n   c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];\n   if(c < 0 || c >= 256) // symbol id out of bounds!\n       return -1;\n   STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);\n\n   // convert the id to a symbol\n   j->code_bits -= k;\n   j->code_buffer <<= k;\n   return h->values[c];\n}\n\n// bias[n] = (-1<<n) + 1\nstatic const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};\n\n// combined JPEG 'receive' and JPEG 'extend', since baseline\n// always extends everything it receives.\nstbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)\n{\n   unsigned int k;\n   int sgn;\n   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);\n   if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing\n\n   sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative)\n   k = stbi_lrot(j->code_buffer, n);\n   j->code_buffer = k & ~stbi__bmask[n];\n   k &= stbi__bmask[n];\n   j->code_bits -= n;\n   return k + (stbi__jbias[n] & (sgn - 1));\n}\n\n// get some unsigned bits\nstbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)\n{\n   unsigned int k;\n   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);\n   if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing\n   k = stbi_lrot(j->code_buffer, n);\n   j->code_buffer = k & ~stbi__bmask[n];\n   k &= stbi__bmask[n];\n   j->code_bits -= n;\n   return k;\n}\n\nstbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)\n{\n   unsigned int k;\n   if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);\n   if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing\n   k = j->code_buffer;\n   j->code_buffer <<= 1;\n   --j->code_bits;\n   return k & 0x80000000;\n}\n\n// given a value that's at position X in the zigzag stream,\n// where does it appear in the 8x8 matrix coded as row-major?\nstatic const stbi_uc stbi__jpeg_dezigzag[64+15] =\n{\n    0,  1,  8, 16,  9,  2,  3, 10,\n   17, 24, 32, 25, 18, 11,  4,  5,\n   12, 19, 26, 33, 40, 48, 41, 34,\n   27, 20, 13,  6,  7, 14, 21, 28,\n   35, 42, 49, 56, 57, 50, 43, 36,\n   29, 22, 15, 23, 30, 37, 44, 51,\n   58, 59, 52, 45, 38, 31, 39, 46,\n   53, 60, 61, 54, 47, 55, 62, 63,\n   // let corrupt input sample past end\n   63, 63, 63, 63, 63, 63, 63, 63,\n   63, 63, 63, 63, 63, 63, 63\n};\n\n// decode one 64-entry block--\nstatic int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant)\n{\n   int diff,dc,k;\n   int t;\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n   t = stbi__jpeg_huff_decode(j, hdc);\n   if (t < 0 || t > 15) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n\n   // 0 all the ac values now so we can do it 32-bits at a time\n   memset(data,0,64*sizeof(data[0]));\n\n   diff = t ? stbi__extend_receive(j, t) : 0;\n   if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err(\"bad delta\",\"Corrupt JPEG\");\n   dc = j->img_comp[b].dc_pred + diff;\n   j->img_comp[b].dc_pred = dc;\n   if (!stbi__mul2shorts_valid((short)dc, dequant[0])) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n   data[0] = (short) (dc * dequant[0]);\n\n   // decode AC components, see JPEG spec\n   k = 1;\n   do {\n      unsigned int zig;\n      int c,r,s;\n      if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n      c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n      r = fac[c];\n      if (r) { // fast-AC path\n         k += (r >> 4) & 15; // run\n         s = r & 15; // combined length\n         if (s > j->code_bits) return stbi__err(\"bad huffman code\", \"Combined length longer than code bits available\");\n         j->code_buffer <<= s;\n         j->code_bits -= s;\n         // decode into unzigzag'd location\n         zig = stbi__jpeg_dezigzag[k++];\n         data[zig] = (short) ((r >> 8) * dequant[zig]);\n      } else {\n         int rs = stbi__jpeg_huff_decode(j, hac);\n         if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n         s = rs & 15;\n         r = rs >> 4;\n         if (s == 0) {\n            if (rs != 0xf0) break; // end block\n            k += 16;\n         } else {\n            k += r;\n            // decode into unzigzag'd location\n            zig = stbi__jpeg_dezigzag[k++];\n            data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);\n         }\n      }\n   } while (k < 64);\n   return 1;\n}\n\nstatic int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)\n{\n   int diff,dc;\n   int t;\n   if (j->spec_end != 0) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n\n   if (j->succ_high == 0) {\n      // first scan for DC coefficient, must be first\n      memset(data,0,64*sizeof(data[0])); // 0 all the ac values now\n      t = stbi__jpeg_huff_decode(j, hdc);\n      if (t < 0 || t > 15) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n      diff = t ? stbi__extend_receive(j, t) : 0;\n\n      if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err(\"bad delta\", \"Corrupt JPEG\");\n      dc = j->img_comp[b].dc_pred + diff;\n      j->img_comp[b].dc_pred = dc;\n      if (!stbi__mul2shorts_valid((short)dc, 1 << j->succ_low)) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n      data[0] = (short) (dc * (1 << j->succ_low));\n   } else {\n      // refinement scan for DC coefficient\n      if (stbi__jpeg_get_bit(j))\n         data[0] += (short) (1 << j->succ_low);\n   }\n   return 1;\n}\n\n// @OPTIMIZE: store non-zigzagged during the decode passes,\n// and only de-zigzag when dequantizing\nstatic int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)\n{\n   int k;\n   if (j->spec_start == 0) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n\n   if (j->succ_high == 0) {\n      int shift = j->succ_low;\n\n      if (j->eob_run) {\n         --j->eob_run;\n         return 1;\n      }\n\n      k = j->spec_start;\n      do {\n         unsigned int zig;\n         int c,r,s;\n         if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n         c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n         r = fac[c];\n         if (r) { // fast-AC path\n            k += (r >> 4) & 15; // run\n            s = r & 15; // combined length\n            if (s > j->code_bits) return stbi__err(\"bad huffman code\", \"Combined length longer than code bits available\");\n            j->code_buffer <<= s;\n            j->code_bits -= s;\n            zig = stbi__jpeg_dezigzag[k++];\n            data[zig] = (short) ((r >> 8) * (1 << shift));\n         } else {\n            int rs = stbi__jpeg_huff_decode(j, hac);\n            if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n            s = rs & 15;\n            r = rs >> 4;\n            if (s == 0) {\n               if (r < 15) {\n                  j->eob_run = (1 << r);\n                  if (r)\n                     j->eob_run += stbi__jpeg_get_bits(j, r);\n                  --j->eob_run;\n                  break;\n               }\n               k += 16;\n            } else {\n               k += r;\n               zig = stbi__jpeg_dezigzag[k++];\n               data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift));\n            }\n         }\n      } while (k <= j->spec_end);\n   } else {\n      // refinement scan for these AC coefficients\n\n      short bit = (short) (1 << j->succ_low);\n\n      if (j->eob_run) {\n         --j->eob_run;\n         for (k = j->spec_start; k <= j->spec_end; ++k) {\n            short *p = &data[stbi__jpeg_dezigzag[k]];\n            if (*p != 0)\n               if (stbi__jpeg_get_bit(j))\n                  if ((*p & bit)==0) {\n                     if (*p > 0)\n                        *p += bit;\n                     else\n                        *p -= bit;\n                  }\n         }\n      } else {\n         k = j->spec_start;\n         do {\n            int r,s;\n            int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh\n            if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n            s = rs & 15;\n            r = rs >> 4;\n            if (s == 0) {\n               if (r < 15) {\n                  j->eob_run = (1 << r) - 1;\n                  if (r)\n                     j->eob_run += stbi__jpeg_get_bits(j, r);\n                  r = 64; // force end of block\n               } else {\n                  // r=15 s=0 should write 16 0s, so we just do\n                  // a run of 15 0s and then write s (which is 0),\n                  // so we don't have to do anything special here\n               }\n            } else {\n               if (s != 1) return stbi__err(\"bad huffman code\", \"Corrupt JPEG\");\n               // sign bit\n               if (stbi__jpeg_get_bit(j))\n                  s = bit;\n               else\n                  s = -bit;\n            }\n\n            // advance by r\n            while (k <= j->spec_end) {\n               short *p = &data[stbi__jpeg_dezigzag[k++]];\n               if (*p != 0) {\n                  if (stbi__jpeg_get_bit(j))\n                     if ((*p & bit)==0) {\n                        if (*p > 0)\n                           *p += bit;\n                        else\n                           *p -= bit;\n                     }\n               } else {\n                  if (r == 0) {\n                     *p = (short) s;\n                     break;\n                  }\n                  --r;\n               }\n            }\n         } while (k <= j->spec_end);\n      }\n   }\n   return 1;\n}\n\n// take a -128..127 value and stbi__clamp it and convert to 0..255\nstbi_inline static stbi_uc stbi__clamp(int x)\n{\n   // trick to use a single test to catch both cases\n   if ((unsigned int) x > 255) {\n      if (x < 0) return 0;\n      if (x > 255) return 255;\n   }\n   return (stbi_uc) x;\n}\n\n#define stbi__f2f(x)  ((int) (((x) * 4096 + 0.5)))\n#define stbi__fsh(x)  ((x) * 4096)\n\n// derived from jidctint -- DCT_ISLOW\n#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \\\n   int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \\\n   p2 = s2;                                    \\\n   p3 = s6;                                    \\\n   p1 = (p2+p3) * stbi__f2f(0.5411961f);       \\\n   t2 = p1 + p3*stbi__f2f(-1.847759065f);      \\\n   t3 = p1 + p2*stbi__f2f( 0.765366865f);      \\\n   p2 = s0;                                    \\\n   p3 = s4;                                    \\\n   t0 = stbi__fsh(p2+p3);                      \\\n   t1 = stbi__fsh(p2-p3);                      \\\n   x0 = t0+t3;                                 \\\n   x3 = t0-t3;                                 \\\n   x1 = t1+t2;                                 \\\n   x2 = t1-t2;                                 \\\n   t0 = s7;                                    \\\n   t1 = s5;                                    \\\n   t2 = s3;                                    \\\n   t3 = s1;                                    \\\n   p3 = t0+t2;                                 \\\n   p4 = t1+t3;                                 \\\n   p1 = t0+t3;                                 \\\n   p2 = t1+t2;                                 \\\n   p5 = (p3+p4)*stbi__f2f( 1.175875602f);      \\\n   t0 = t0*stbi__f2f( 0.298631336f);           \\\n   t1 = t1*stbi__f2f( 2.053119869f);           \\\n   t2 = t2*stbi__f2f( 3.072711026f);           \\\n   t3 = t3*stbi__f2f( 1.501321110f);           \\\n   p1 = p5 + p1*stbi__f2f(-0.899976223f);      \\\n   p2 = p5 + p2*stbi__f2f(-2.562915447f);      \\\n   p3 = p3*stbi__f2f(-1.961570560f);           \\\n   p4 = p4*stbi__f2f(-0.390180644f);           \\\n   t3 += p1+p4;                                \\\n   t2 += p2+p3;                                \\\n   t1 += p2+p4;                                \\\n   t0 += p1+p3;\n\nstatic void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])\n{\n   int i,val[64],*v=val;\n   stbi_uc *o;\n   short *d = data;\n\n   // columns\n   for (i=0; i < 8; ++i,++d, ++v) {\n      // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing\n      if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0\n           && d[40]==0 && d[48]==0 && d[56]==0) {\n         //    no shortcut                 0     seconds\n         //    (1|2|3|4|5|6|7)==0          0     seconds\n         //    all separate               -0.047 seconds\n         //    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds\n         int dcterm = d[0]*4;\n         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;\n      } else {\n         STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])\n         // constants scaled things up by 1<<12; let's bring them back\n         // down, but keep 2 extra bits of precision\n         x0 += 512; x1 += 512; x2 += 512; x3 += 512;\n         v[ 0] = (x0+t3) >> 10;\n         v[56] = (x0-t3) >> 10;\n         v[ 8] = (x1+t2) >> 10;\n         v[48] = (x1-t2) >> 10;\n         v[16] = (x2+t1) >> 10;\n         v[40] = (x2-t1) >> 10;\n         v[24] = (x3+t0) >> 10;\n         v[32] = (x3-t0) >> 10;\n      }\n   }\n\n   for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {\n      // no fast case since the first 1D IDCT spread components out\n      STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])\n      // constants scaled things up by 1<<12, plus we had 1<<2 from first\n      // loop, plus horizontal and vertical each scale by sqrt(8) so together\n      // we've got an extra 1<<3, so 1<<17 total we need to remove.\n      // so we want to round that, which means adding 0.5 * 1<<17,\n      // aka 65536. Also, we'll end up with -128 to 127 that we want\n      // to encode as 0..255 by adding 128, so we'll add that before the shift\n      x0 += 65536 + (128<<17);\n      x1 += 65536 + (128<<17);\n      x2 += 65536 + (128<<17);\n      x3 += 65536 + (128<<17);\n      // tried computing the shifts into temps, or'ing the temps to see\n      // if any were out of range, but that was slower\n      o[0] = stbi__clamp((x0+t3) >> 17);\n      o[7] = stbi__clamp((x0-t3) >> 17);\n      o[1] = stbi__clamp((x1+t2) >> 17);\n      o[6] = stbi__clamp((x1-t2) >> 17);\n      o[2] = stbi__clamp((x2+t1) >> 17);\n      o[5] = stbi__clamp((x2-t1) >> 17);\n      o[3] = stbi__clamp((x3+t0) >> 17);\n      o[4] = stbi__clamp((x3-t0) >> 17);\n   }\n}\n\n#ifdef STBI_SSE2\n// sse2 integer IDCT. not the fastest possible implementation but it\n// produces bit-identical results to the generic C version so it's\n// fully \"transparent\".\nstatic void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])\n{\n   // This is constructed to match our regular (generic) integer IDCT exactly.\n   __m128i row0, row1, row2, row3, row4, row5, row6, row7;\n   __m128i tmp;\n\n   // dot product constant: even elems=x, odd elems=y\n   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))\n\n   // out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)\n   // out(1) = c1[even]*x + c1[odd]*y\n   #define dct_rot(out0,out1, x,y,c0,c1) \\\n      __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \\\n      __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \\\n      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \\\n      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \\\n      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \\\n      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)\n\n   // out = in << 12  (in 16-bit, out 32-bit)\n   #define dct_widen(out, in) \\\n      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \\\n      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)\n\n   // wide add\n   #define dct_wadd(out, a, b) \\\n      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)\n\n   // wide sub\n   #define dct_wsub(out, a, b) \\\n      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)\n\n   // butterfly a/b, add bias, then shift by \"s\" and pack\n   #define dct_bfly32o(out0, out1, a,b,bias,s) \\\n      { \\\n         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \\\n         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \\\n         dct_wadd(sum, abiased, b); \\\n         dct_wsub(dif, abiased, b); \\\n         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \\\n         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \\\n      }\n\n   // 8-bit interleave step (for transposes)\n   #define dct_interleave8(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi8(a, b); \\\n      b = _mm_unpackhi_epi8(tmp, b)\n\n   // 16-bit interleave step (for transposes)\n   #define dct_interleave16(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi16(a, b); \\\n      b = _mm_unpackhi_epi16(tmp, b)\n\n   #define dct_pass(bias,shift) \\\n      { \\\n         /* even part */ \\\n         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \\\n         __m128i sum04 = _mm_add_epi16(row0, row4); \\\n         __m128i dif04 = _mm_sub_epi16(row0, row4); \\\n         dct_widen(t0e, sum04); \\\n         dct_widen(t1e, dif04); \\\n         dct_wadd(x0, t0e, t3e); \\\n         dct_wsub(x3, t0e, t3e); \\\n         dct_wadd(x1, t1e, t2e); \\\n         dct_wsub(x2, t1e, t2e); \\\n         /* odd part */ \\\n         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \\\n         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \\\n         __m128i sum17 = _mm_add_epi16(row1, row7); \\\n         __m128i sum35 = _mm_add_epi16(row3, row5); \\\n         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \\\n         dct_wadd(x4, y0o, y4o); \\\n         dct_wadd(x5, y1o, y5o); \\\n         dct_wadd(x6, y2o, y5o); \\\n         dct_wadd(x7, y3o, y4o); \\\n         dct_bfly32o(row0,row7, x0,x7,bias,shift); \\\n         dct_bfly32o(row1,row6, x1,x6,bias,shift); \\\n         dct_bfly32o(row2,row5, x2,x5,bias,shift); \\\n         dct_bfly32o(row3,row4, x3,x4,bias,shift); \\\n      }\n\n   __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f));\n   __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f));\n   __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f));\n   __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f));\n   __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f));\n   __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f));\n   __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f));\n   __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f));\n\n   // rounding biases in column/row passes, see stbi__idct_block for explanation.\n   __m128i bias_0 = _mm_set1_epi32(512);\n   __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));\n\n   // load\n   row0 = _mm_load_si128((const __m128i *) (data + 0*8));\n   row1 = _mm_load_si128((const __m128i *) (data + 1*8));\n   row2 = _mm_load_si128((const __m128i *) (data + 2*8));\n   row3 = _mm_load_si128((const __m128i *) (data + 3*8));\n   row4 = _mm_load_si128((const __m128i *) (data + 4*8));\n   row5 = _mm_load_si128((const __m128i *) (data + 5*8));\n   row6 = _mm_load_si128((const __m128i *) (data + 6*8));\n   row7 = _mm_load_si128((const __m128i *) (data + 7*8));\n\n   // column pass\n   dct_pass(bias_0, 10);\n\n   {\n      // 16bit 8x8 transpose pass 1\n      dct_interleave16(row0, row4);\n      dct_interleave16(row1, row5);\n      dct_interleave16(row2, row6);\n      dct_interleave16(row3, row7);\n\n      // transpose pass 2\n      dct_interleave16(row0, row2);\n      dct_interleave16(row1, row3);\n      dct_interleave16(row4, row6);\n      dct_interleave16(row5, row7);\n\n      // transpose pass 3\n      dct_interleave16(row0, row1);\n      dct_interleave16(row2, row3);\n      dct_interleave16(row4, row5);\n      dct_interleave16(row6, row7);\n   }\n\n   // row pass\n   dct_pass(bias_1, 17);\n\n   {\n      // pack\n      __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7\n      __m128i p1 = _mm_packus_epi16(row2, row3);\n      __m128i p2 = _mm_packus_epi16(row4, row5);\n      __m128i p3 = _mm_packus_epi16(row6, row7);\n\n      // 8bit 8x8 transpose pass 1\n      dct_interleave8(p0, p2); // a0e0a1e1...\n      dct_interleave8(p1, p3); // c0g0c1g1...\n\n      // transpose pass 2\n      dct_interleave8(p0, p1); // a0c0e0g0...\n      dct_interleave8(p2, p3); // b0d0f0h0...\n\n      // transpose pass 3\n      dct_interleave8(p0, p2); // a0b0c0d0...\n      dct_interleave8(p1, p3); // a4b4c4d4...\n\n      // store\n      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));\n   }\n\n#undef dct_const\n#undef dct_rot\n#undef dct_widen\n#undef dct_wadd\n#undef dct_wsub\n#undef dct_bfly32o\n#undef dct_interleave8\n#undef dct_interleave16\n#undef dct_pass\n}\n\n#endif // STBI_SSE2\n\n#ifdef STBI_NEON\n\n// NEON integer IDCT. should produce bit-identical\n// results to the generic C version.\nstatic void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])\n{\n   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;\n\n   int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f));\n   int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f));\n   int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f));\n   int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f));\n   int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f));\n   int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f));\n   int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f));\n   int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f));\n   int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f));\n   int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f));\n   int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f));\n   int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f));\n\n#define dct_long_mul(out, inq, coeff) \\\n   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \\\n   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)\n\n#define dct_long_mac(out, acc, inq, coeff) \\\n   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \\\n   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)\n\n#define dct_widen(out, inq) \\\n   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \\\n   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)\n\n// wide add\n#define dct_wadd(out, a, b) \\\n   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \\\n   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)\n\n// wide sub\n#define dct_wsub(out, a, b) \\\n   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \\\n   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)\n\n// butterfly a/b, then shift using \"shiftop\" by \"s\" and pack\n#define dct_bfly32o(out0,out1, a,b,shiftop,s) \\\n   { \\\n      dct_wadd(sum, a, b); \\\n      dct_wsub(dif, a, b); \\\n      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \\\n      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \\\n   }\n\n#define dct_pass(shiftop, shift) \\\n   { \\\n      /* even part */ \\\n      int16x8_t sum26 = vaddq_s16(row2, row6); \\\n      dct_long_mul(p1e, sum26, rot0_0); \\\n      dct_long_mac(t2e, p1e, row6, rot0_1); \\\n      dct_long_mac(t3e, p1e, row2, rot0_2); \\\n      int16x8_t sum04 = vaddq_s16(row0, row4); \\\n      int16x8_t dif04 = vsubq_s16(row0, row4); \\\n      dct_widen(t0e, sum04); \\\n      dct_widen(t1e, dif04); \\\n      dct_wadd(x0, t0e, t3e); \\\n      dct_wsub(x3, t0e, t3e); \\\n      dct_wadd(x1, t1e, t2e); \\\n      dct_wsub(x2, t1e, t2e); \\\n      /* odd part */ \\\n      int16x8_t sum15 = vaddq_s16(row1, row5); \\\n      int16x8_t sum17 = vaddq_s16(row1, row7); \\\n      int16x8_t sum35 = vaddq_s16(row3, row5); \\\n      int16x8_t sum37 = vaddq_s16(row3, row7); \\\n      int16x8_t sumodd = vaddq_s16(sum17, sum35); \\\n      dct_long_mul(p5o, sumodd, rot1_0); \\\n      dct_long_mac(p1o, p5o, sum17, rot1_1); \\\n      dct_long_mac(p2o, p5o, sum35, rot1_2); \\\n      dct_long_mul(p3o, sum37, rot2_0); \\\n      dct_long_mul(p4o, sum15, rot2_1); \\\n      dct_wadd(sump13o, p1o, p3o); \\\n      dct_wadd(sump24o, p2o, p4o); \\\n      dct_wadd(sump23o, p2o, p3o); \\\n      dct_wadd(sump14o, p1o, p4o); \\\n      dct_long_mac(x4, sump13o, row7, rot3_0); \\\n      dct_long_mac(x5, sump24o, row5, rot3_1); \\\n      dct_long_mac(x6, sump23o, row3, rot3_2); \\\n      dct_long_mac(x7, sump14o, row1, rot3_3); \\\n      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \\\n      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \\\n      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \\\n      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \\\n   }\n\n   // load\n   row0 = vld1q_s16(data + 0*8);\n   row1 = vld1q_s16(data + 1*8);\n   row2 = vld1q_s16(data + 2*8);\n   row3 = vld1q_s16(data + 3*8);\n   row4 = vld1q_s16(data + 4*8);\n   row5 = vld1q_s16(data + 5*8);\n   row6 = vld1q_s16(data + 6*8);\n   row7 = vld1q_s16(data + 7*8);\n\n   // add DC bias\n   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));\n\n   // column pass\n   dct_pass(vrshrn_n_s32, 10);\n\n   // 16bit 8x8 transpose\n   {\n// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.\n// whether compilers actually get this is another story, sadly.\n#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }\n#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }\n#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }\n\n      // pass 1\n      dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6\n      dct_trn16(row2, row3);\n      dct_trn16(row4, row5);\n      dct_trn16(row6, row7);\n\n      // pass 2\n      dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4\n      dct_trn32(row1, row3);\n      dct_trn32(row4, row6);\n      dct_trn32(row5, row7);\n\n      // pass 3\n      dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0\n      dct_trn64(row1, row5);\n      dct_trn64(row2, row6);\n      dct_trn64(row3, row7);\n\n#undef dct_trn16\n#undef dct_trn32\n#undef dct_trn64\n   }\n\n   // row pass\n   // vrshrn_n_s32 only supports shifts up to 16, we need\n   // 17. so do a non-rounding shift of 16 first then follow\n   // up with a rounding shift by 1.\n   dct_pass(vshrn_n_s32, 16);\n\n   {\n      // pack and round\n      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);\n      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);\n      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);\n      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);\n      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);\n      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);\n      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);\n      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);\n\n      // again, these can translate into one instruction, but often don't.\n#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }\n#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }\n#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }\n\n      // sadly can't use interleaved stores here since we only write\n      // 8 bytes to each scan line!\n\n      // 8x8 8-bit transpose pass 1\n      dct_trn8_8(p0, p1);\n      dct_trn8_8(p2, p3);\n      dct_trn8_8(p4, p5);\n      dct_trn8_8(p6, p7);\n\n      // pass 2\n      dct_trn8_16(p0, p2);\n      dct_trn8_16(p1, p3);\n      dct_trn8_16(p4, p6);\n      dct_trn8_16(p5, p7);\n\n      // pass 3\n      dct_trn8_32(p0, p4);\n      dct_trn8_32(p1, p5);\n      dct_trn8_32(p2, p6);\n      dct_trn8_32(p3, p7);\n\n      // store\n      vst1_u8(out, p0); out += out_stride;\n      vst1_u8(out, p1); out += out_stride;\n      vst1_u8(out, p2); out += out_stride;\n      vst1_u8(out, p3); out += out_stride;\n      vst1_u8(out, p4); out += out_stride;\n      vst1_u8(out, p5); out += out_stride;\n      vst1_u8(out, p6); out += out_stride;\n      vst1_u8(out, p7);\n\n#undef dct_trn8_8\n#undef dct_trn8_16\n#undef dct_trn8_32\n   }\n\n#undef dct_long_mul\n#undef dct_long_mac\n#undef dct_widen\n#undef dct_wadd\n#undef dct_wsub\n#undef dct_bfly32o\n#undef dct_pass\n}\n\n#endif // STBI_NEON\n\n#define STBI__MARKER_none  0xff\n// if there's a pending marker from the entropy stream, return that\n// otherwise, fetch from the stream and get a marker. if there's no\n// marker, return 0xff, which is never a valid marker value\nstatic stbi_uc stbi__get_marker(stbi__jpeg *j)\n{\n   stbi_uc x;\n   if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; }\n   x = stbi__get8(j->s);\n   if (x != 0xff) return STBI__MARKER_none;\n   while (x == 0xff)\n      x = stbi__get8(j->s); // consume repeated 0xff fill bytes\n   return x;\n}\n\n// in each scan, we'll have scan_n components, and the order\n// of the components is specified by order[]\n#define STBI__RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)\n\n// after a restart interval, stbi__jpeg_reset the entropy decoder and\n// the dc prediction\nstatic void stbi__jpeg_reset(stbi__jpeg *j)\n{\n   j->code_bits = 0;\n   j->code_buffer = 0;\n   j->nomore = 0;\n   j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0;\n   j->marker = STBI__MARKER_none;\n   j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;\n   j->eob_run = 0;\n   // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,\n   // since we don't even allow 1<<30 pixels\n}\n\nstatic int stbi__parse_entropy_coded_data(stbi__jpeg *z)\n{\n   stbi__jpeg_reset(z);\n   if (!z->progressive) {\n      if (z->scan_n == 1) {\n         int i,j;\n         STBI_SIMD_ALIGN(short, data[64]);\n         int n = z->order[0];\n         // non-interleaved data, we just need to process one block at a time,\n         // in trivial scanline order\n         // number of blocks to do just depends on how many actual \"pixels\" this\n         // component has, independent of interleaved MCU blocking and such\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               int ha = z->img_comp[n].ha;\n               if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;\n               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);\n               // every data block is an MCU, so countdown the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  // if it's NOT a restart, then just bail, so we get corrupt data\n                  // rather than no data\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      } else { // interleaved\n         int i,j,k,x,y;\n         STBI_SIMD_ALIGN(short, data[64]);\n         for (j=0; j < z->img_mcu_y; ++j) {\n            for (i=0; i < z->img_mcu_x; ++i) {\n               // scan an interleaved mcu... process scan_n components in order\n               for (k=0; k < z->scan_n; ++k) {\n                  int n = z->order[k];\n                  // scan out an mcu's worth of this component; that's just determined\n                  // by the basic H and V specified for the component\n                  for (y=0; y < z->img_comp[n].v; ++y) {\n                     for (x=0; x < z->img_comp[n].h; ++x) {\n                        int x2 = (i*z->img_comp[n].h + x)*8;\n                        int y2 = (j*z->img_comp[n].v + y)*8;\n                        int ha = z->img_comp[n].ha;\n                        if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;\n                        z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data);\n                     }\n                  }\n               }\n               // after all interleaved components, that's an interleaved MCU,\n               // so now count down the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      }\n   } else {\n      if (z->scan_n == 1) {\n         int i,j;\n         int n = z->order[0];\n         // non-interleaved data, we just need to process one block at a time,\n         // in trivial scanline order\n         // number of blocks to do just depends on how many actual \"pixels\" this\n         // component has, independent of interleaved MCU blocking and such\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);\n               if (z->spec_start == 0) {\n                  if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))\n                     return 0;\n               } else {\n                  int ha = z->img_comp[n].ha;\n                  if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))\n                     return 0;\n               }\n               // every data block is an MCU, so countdown the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      } else { // interleaved\n         int i,j,k,x,y;\n         for (j=0; j < z->img_mcu_y; ++j) {\n            for (i=0; i < z->img_mcu_x; ++i) {\n               // scan an interleaved mcu... process scan_n components in order\n               for (k=0; k < z->scan_n; ++k) {\n                  int n = z->order[k];\n                  // scan out an mcu's worth of this component; that's just determined\n                  // by the basic H and V specified for the component\n                  for (y=0; y < z->img_comp[n].v; ++y) {\n                     for (x=0; x < z->img_comp[n].h; ++x) {\n                        int x2 = (i*z->img_comp[n].h + x);\n                        int y2 = (j*z->img_comp[n].v + y);\n                        short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);\n                        if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))\n                           return 0;\n                     }\n                  }\n               }\n               // after all interleaved components, that's an interleaved MCU,\n               // so now count down the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      }\n   }\n}\n\nstatic void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant)\n{\n   int i;\n   for (i=0; i < 64; ++i)\n      data[i] *= dequant[i];\n}\n\nstatic void stbi__jpeg_finish(stbi__jpeg *z)\n{\n   if (z->progressive) {\n      // dequantize and idct the data\n      int i,j,n;\n      for (n=0; n < z->s->img_n; ++n) {\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);\n               stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);\n               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);\n            }\n         }\n      }\n   }\n}\n\nstatic int stbi__process_marker(stbi__jpeg *z, int m)\n{\n   int L;\n   switch (m) {\n      case STBI__MARKER_none: // no marker found\n         return stbi__err(\"expected marker\",\"Corrupt JPEG\");\n\n      case 0xDD: // DRI - specify restart interval\n         if (stbi__get16be(z->s) != 4) return stbi__err(\"bad DRI len\",\"Corrupt JPEG\");\n         z->restart_interval = stbi__get16be(z->s);\n         return 1;\n\n      case 0xDB: // DQT - define quantization table\n         L = stbi__get16be(z->s)-2;\n         while (L > 0) {\n            int q = stbi__get8(z->s);\n            int p = q >> 4, sixteen = (p != 0);\n            int t = q & 15,i;\n            if (p != 0 && p != 1) return stbi__err(\"bad DQT type\",\"Corrupt JPEG\");\n            if (t > 3) return stbi__err(\"bad DQT table\",\"Corrupt JPEG\");\n\n            for (i=0; i < 64; ++i)\n               z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s));\n            L -= (sixteen ? 129 : 65);\n         }\n         return L==0;\n\n      case 0xC4: // DHT - define huffman table\n         L = stbi__get16be(z->s)-2;\n         while (L > 0) {\n            stbi_uc *v;\n            int sizes[16],i,n=0;\n            int q = stbi__get8(z->s);\n            int tc = q >> 4;\n            int th = q & 15;\n            if (tc > 1 || th > 3) return stbi__err(\"bad DHT header\",\"Corrupt JPEG\");\n            for (i=0; i < 16; ++i) {\n               sizes[i] = stbi__get8(z->s);\n               n += sizes[i];\n            }\n            if(n > 256) return stbi__err(\"bad DHT header\",\"Corrupt JPEG\"); // Loop over i < n would write past end of values!\n            L -= 17;\n            if (tc == 0) {\n               if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;\n               v = z->huff_dc[th].values;\n            } else {\n               if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0;\n               v = z->huff_ac[th].values;\n            }\n            for (i=0; i < n; ++i)\n               v[i] = stbi__get8(z->s);\n            if (tc != 0)\n               stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th);\n            L -= n;\n         }\n         return L==0;\n   }\n\n   // check for comment block or APP blocks\n   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {\n      L = stbi__get16be(z->s);\n      if (L < 2) {\n         if (m == 0xFE)\n            return stbi__err(\"bad COM len\",\"Corrupt JPEG\");\n         else\n            return stbi__err(\"bad APP len\",\"Corrupt JPEG\");\n      }\n      L -= 2;\n\n      if (m == 0xE0 && L >= 5) { // JFIF APP0 segment\n         static const unsigned char tag[5] = {'J','F','I','F','\\0'};\n         int ok = 1;\n         int i;\n         for (i=0; i < 5; ++i)\n            if (stbi__get8(z->s) != tag[i])\n               ok = 0;\n         L -= 5;\n         if (ok)\n            z->jfif = 1;\n      } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment\n         static const unsigned char tag[6] = {'A','d','o','b','e','\\0'};\n         int ok = 1;\n         int i;\n         for (i=0; i < 6; ++i)\n            if (stbi__get8(z->s) != tag[i])\n               ok = 0;\n         L -= 6;\n         if (ok) {\n            stbi__get8(z->s); // version\n            stbi__get16be(z->s); // flags0\n            stbi__get16be(z->s); // flags1\n            z->app14_color_transform = stbi__get8(z->s); // color transform\n            L -= 6;\n         }\n      }\n\n      stbi__skip(z->s, L);\n      return 1;\n   }\n\n   return stbi__err(\"unknown marker\",\"Corrupt JPEG\");\n}\n\n// after we see SOS\nstatic int stbi__process_scan_header(stbi__jpeg *z)\n{\n   int i;\n   int Ls = stbi__get16be(z->s);\n   z->scan_n = stbi__get8(z->s);\n   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err(\"bad SOS component count\",\"Corrupt JPEG\");\n   if (Ls != 6+2*z->scan_n) return stbi__err(\"bad SOS len\",\"Corrupt JPEG\");\n   for (i=0; i < z->scan_n; ++i) {\n      int id = stbi__get8(z->s), which;\n      int q = stbi__get8(z->s);\n      for (which = 0; which < z->s->img_n; ++which)\n         if (z->img_comp[which].id == id)\n            break;\n      if (which == z->s->img_n) return 0; // no match\n      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3) return stbi__err(\"bad DC huff\",\"Corrupt JPEG\");\n      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3) return stbi__err(\"bad AC huff\",\"Corrupt JPEG\");\n      z->order[i] = which;\n   }\n\n   {\n      int aa;\n      z->spec_start = stbi__get8(z->s);\n      z->spec_end   = stbi__get8(z->s); // should be 63, but might be 0\n      aa = stbi__get8(z->s);\n      z->succ_high = (aa >> 4);\n      z->succ_low  = (aa & 15);\n      if (z->progressive) {\n         if (z->spec_start > 63 || z->spec_end > 63  || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13)\n            return stbi__err(\"bad SOS\", \"Corrupt JPEG\");\n      } else {\n         if (z->spec_start != 0) return stbi__err(\"bad SOS\",\"Corrupt JPEG\");\n         if (z->succ_high != 0 || z->succ_low != 0) return stbi__err(\"bad SOS\",\"Corrupt JPEG\");\n         z->spec_end = 63;\n      }\n   }\n\n   return 1;\n}\n\nstatic int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why)\n{\n   int i;\n   for (i=0; i < ncomp; ++i) {\n      if (z->img_comp[i].raw_data) {\n         STBI_FREE(z->img_comp[i].raw_data);\n         z->img_comp[i].raw_data = NULL;\n         z->img_comp[i].data = NULL;\n      }\n      if (z->img_comp[i].raw_coeff) {\n         STBI_FREE(z->img_comp[i].raw_coeff);\n         z->img_comp[i].raw_coeff = 0;\n         z->img_comp[i].coeff = 0;\n      }\n      if (z->img_comp[i].linebuf) {\n         STBI_FREE(z->img_comp[i].linebuf);\n         z->img_comp[i].linebuf = NULL;\n      }\n   }\n   return why;\n}\n\nstatic int stbi__process_frame_header(stbi__jpeg *z, int scan)\n{\n   stbi__context *s = z->s;\n   int Lf,p,i,q, h_max=1,v_max=1,c;\n   Lf = stbi__get16be(s);         if (Lf < 11) return stbi__err(\"bad SOF len\",\"Corrupt JPEG\"); // JPEG\n   p  = stbi__get8(s);            if (p != 8) return stbi__err(\"only 8-bit\",\"JPEG format not supported: 8-bit only\"); // JPEG baseline\n   s->img_y = stbi__get16be(s);   if (s->img_y == 0) return stbi__err(\"no header height\", \"JPEG format not supported: delayed height\"); // Legal, but we don't handle it--but neither does IJG\n   s->img_x = stbi__get16be(s);   if (s->img_x == 0) return stbi__err(\"0 width\",\"Corrupt JPEG\"); // JPEG requires\n   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n   c = stbi__get8(s);\n   if (c != 3 && c != 1 && c != 4) return stbi__err(\"bad component count\",\"Corrupt JPEG\");\n   s->img_n = c;\n   for (i=0; i < c; ++i) {\n      z->img_comp[i].data = NULL;\n      z->img_comp[i].linebuf = NULL;\n   }\n\n   if (Lf != 8+3*s->img_n) return stbi__err(\"bad SOF len\",\"Corrupt JPEG\");\n\n   z->rgb = 0;\n   for (i=0; i < s->img_n; ++i) {\n      static const unsigned char rgb[3] = { 'R', 'G', 'B' };\n      z->img_comp[i].id = stbi__get8(s);\n      if (s->img_n == 3 && z->img_comp[i].id == rgb[i])\n         ++z->rgb;\n      q = stbi__get8(s);\n      z->img_comp[i].h = (q >> 4);  if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err(\"bad H\",\"Corrupt JPEG\");\n      z->img_comp[i].v = q & 15;    if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err(\"bad V\",\"Corrupt JPEG\");\n      z->img_comp[i].tq = stbi__get8(s);  if (z->img_comp[i].tq > 3) return stbi__err(\"bad TQ\",\"Corrupt JPEG\");\n   }\n\n   if (scan != STBI__SCAN_load) return 1;\n\n   if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err(\"too large\", \"Image too large to decode\");\n\n   for (i=0; i < s->img_n; ++i) {\n      if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;\n      if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;\n   }\n\n   // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios\n   // and I've never seen a non-corrupted JPEG file actually use them\n   for (i=0; i < s->img_n; ++i) {\n      if (h_max % z->img_comp[i].h != 0) return stbi__err(\"bad H\",\"Corrupt JPEG\");\n      if (v_max % z->img_comp[i].v != 0) return stbi__err(\"bad V\",\"Corrupt JPEG\");\n   }\n\n   // compute interleaved mcu info\n   z->img_h_max = h_max;\n   z->img_v_max = v_max;\n   z->img_mcu_w = h_max * 8;\n   z->img_mcu_h = v_max * 8;\n   // these sizes can't be more than 17 bits\n   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;\n   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;\n\n   for (i=0; i < s->img_n; ++i) {\n      // number of effective pixels (e.g. for non-interleaved MCU)\n      z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;\n      z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;\n      // to simplify generation, we'll allocate enough memory to decode\n      // the bogus oversized data from using interleaved MCUs and their\n      // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't\n      // discard the extra data until colorspace conversion\n      //\n      // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier)\n      // so these muls can't overflow with 32-bit ints (which we require)\n      z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;\n      z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;\n      z->img_comp[i].coeff = 0;\n      z->img_comp[i].raw_coeff = 0;\n      z->img_comp[i].linebuf = NULL;\n      z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15);\n      if (z->img_comp[i].raw_data == NULL)\n         return stbi__free_jpeg_components(z, i+1, stbi__err(\"outofmem\", \"Out of memory\"));\n      // align blocks for idct using mmx/sse\n      z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);\n      if (z->progressive) {\n         // w2, h2 are multiples of 8 (see above)\n         z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8;\n         z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8;\n         z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15);\n         if (z->img_comp[i].raw_coeff == NULL)\n            return stbi__free_jpeg_components(z, i+1, stbi__err(\"outofmem\", \"Out of memory\"));\n         z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);\n      }\n   }\n\n   return 1;\n}\n\n// use comparisons since in some cases we handle more than one case (e.g. SOF)\n#define stbi__DNL(x)         ((x) == 0xdc)\n#define stbi__SOI(x)         ((x) == 0xd8)\n#define stbi__EOI(x)         ((x) == 0xd9)\n#define stbi__SOF(x)         ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)\n#define stbi__SOS(x)         ((x) == 0xda)\n\n#define stbi__SOF_progressive(x)   ((x) == 0xc2)\n\nstatic int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)\n{\n   int m;\n   z->jfif = 0;\n   z->app14_color_transform = -1; // valid values are 0,1,2\n   z->marker = STBI__MARKER_none; // initialize cached marker to empty\n   m = stbi__get_marker(z);\n   if (!stbi__SOI(m)) return stbi__err(\"no SOI\",\"Corrupt JPEG\");\n   if (scan == STBI__SCAN_type) return 1;\n   m = stbi__get_marker(z);\n   while (!stbi__SOF(m)) {\n      if (!stbi__process_marker(z,m)) return 0;\n      m = stbi__get_marker(z);\n      while (m == STBI__MARKER_none) {\n         // some files have extra padding after their blocks, so ok, we'll scan\n         if (stbi__at_eof(z->s)) return stbi__err(\"no SOF\", \"Corrupt JPEG\");\n         m = stbi__get_marker(z);\n      }\n   }\n   z->progressive = stbi__SOF_progressive(m);\n   if (!stbi__process_frame_header(z, scan)) return 0;\n   return 1;\n}\n\nstatic int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)\n{\n   // some JPEGs have junk at end, skip over it but if we find what looks\n   // like a valid marker, resume there\n   while (!stbi__at_eof(j->s)) {\n      int x = stbi__get8(j->s);\n      while (x == 255) { // might be a marker\n         if (stbi__at_eof(j->s)) return STBI__MARKER_none;\n         x = stbi__get8(j->s);\n         if (x != 0x00 && x != 0xff) {\n            // not a stuffed zero or lead-in to another marker, looks\n            // like an actual marker, return it\n            return x;\n         }\n         // stuffed zero has x=0 now which ends the loop, meaning we go\n         // back to regular scan loop.\n         // repeated 0xff keeps trying to read the next byte of the marker.\n      }\n   }\n   return STBI__MARKER_none;\n}\n\n// decode image to YCbCr format\nstatic int stbi__decode_jpeg_image(stbi__jpeg *j)\n{\n   int m;\n   for (m = 0; m < 4; m++) {\n      j->img_comp[m].raw_data = NULL;\n      j->img_comp[m].raw_coeff = NULL;\n   }\n   j->restart_interval = 0;\n   if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;\n   m = stbi__get_marker(j);\n   while (!stbi__EOI(m)) {\n      if (stbi__SOS(m)) {\n         if (!stbi__process_scan_header(j)) return 0;\n         if (!stbi__parse_entropy_coded_data(j)) return 0;\n         if (j->marker == STBI__MARKER_none ) {\n         j->marker = (unsigned char)stbi__skip_jpeg_junk_at_end(j);\n            // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0\n         }\n         m = stbi__get_marker(j);\n         if (STBI__RESTART(m))\n            m = stbi__get_marker(j);\n      } else if (stbi__DNL(m)) {\n         int Ld = stbi__get16be(j->s);\n         stbi__uint32 NL = stbi__get16be(j->s);\n         if (Ld != 4) return stbi__err(\"bad DNL len\", \"Corrupt JPEG\");\n         if (NL != j->s->img_y) return stbi__err(\"bad DNL height\", \"Corrupt JPEG\");\n         m = stbi__get_marker(j);\n      } else {\n         if (!stbi__process_marker(j, m)) return 1;\n         m = stbi__get_marker(j);\n      }\n   }\n   if (j->progressive)\n      stbi__jpeg_finish(j);\n   return 1;\n}\n\n// static jfif-centered resampling (across block boundaries)\n\ntypedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1,\n                                    int w, int hs);\n\n#define stbi__div4(x) ((stbi_uc) ((x) >> 2))\n\nstatic stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   STBI_NOTUSED(out);\n   STBI_NOTUSED(in_far);\n   STBI_NOTUSED(w);\n   STBI_NOTUSED(hs);\n   return in_near;\n}\n\nstatic stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate two samples vertically for every one in input\n   int i;\n   STBI_NOTUSED(hs);\n   for (i=0; i < w; ++i)\n      out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2);\n   return out;\n}\n\nstatic stbi_uc*  stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate two samples horizontally for every one in input\n   int i;\n   stbi_uc *input = in_near;\n\n   if (w == 1) {\n      // if only one sample, can't do any interpolation\n      out[0] = out[1] = input[0];\n      return out;\n   }\n\n   out[0] = input[0];\n   out[1] = stbi__div4(input[0]*3 + input[1] + 2);\n   for (i=1; i < w-1; ++i) {\n      int n = 3*input[i]+2;\n      out[i*2+0] = stbi__div4(n+input[i-1]);\n      out[i*2+1] = stbi__div4(n+input[i+1]);\n   }\n   out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2);\n   out[i*2+1] = input[w-1];\n\n   STBI_NOTUSED(in_far);\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n\n#define stbi__div16(x) ((stbi_uc) ((x) >> 4))\n\nstatic stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate 2x2 samples for every one in input\n   int i,t0,t1;\n   if (w == 1) {\n      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);\n      return out;\n   }\n\n   t1 = 3*in_near[0] + in_far[0];\n   out[0] = stbi__div4(t1+2);\n   for (i=1; i < w; ++i) {\n      t0 = t1;\n      t1 = 3*in_near[i]+in_far[i];\n      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);\n      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);\n   }\n   out[w*2-1] = stbi__div4(t1+2);\n\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n\n#if defined(STBI_SSE2) || defined(STBI_NEON)\nstatic stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate 2x2 samples for every one in input\n   int i=0,t0,t1;\n\n   if (w == 1) {\n      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);\n      return out;\n   }\n\n   t1 = 3*in_near[0] + in_far[0];\n   // process groups of 8 pixels for as long as we can.\n   // note we can't handle the last pixel in a row in this loop\n   // because we need to handle the filter boundary conditions.\n   for (; i < ((w-1) & ~7); i += 8) {\n#if defined(STBI_SSE2)\n      // load and perform the vertical filtering pass\n      // this uses 3*x + y = 4*x + (y - x)\n      __m128i zero  = _mm_setzero_si128();\n      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));\n      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));\n      __m128i farw  = _mm_unpacklo_epi8(farb, zero);\n      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);\n      __m128i diff  = _mm_sub_epi16(farw, nearw);\n      __m128i nears = _mm_slli_epi16(nearw, 2);\n      __m128i curr  = _mm_add_epi16(nears, diff); // current row\n\n      // horizontal filter works the same based on shifted vers of current\n      // row. \"prev\" is current row shifted right by 1 pixel; we need to\n      // insert the previous pixel value (from t1).\n      // \"next\" is current row shifted left by 1 pixel, with first pixel\n      // of next block of 8 pixels added in.\n      __m128i prv0 = _mm_slli_si128(curr, 2);\n      __m128i nxt0 = _mm_srli_si128(curr, 2);\n      __m128i prev = _mm_insert_epi16(prv0, t1, 0);\n      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);\n\n      // horizontal filter, polyphase implementation since it's convenient:\n      // even pixels = 3*cur + prev = cur*4 + (prev - cur)\n      // odd  pixels = 3*cur + next = cur*4 + (next - cur)\n      // note the shared term.\n      __m128i bias  = _mm_set1_epi16(8);\n      __m128i curs = _mm_slli_epi16(curr, 2);\n      __m128i prvd = _mm_sub_epi16(prev, curr);\n      __m128i nxtd = _mm_sub_epi16(next, curr);\n      __m128i curb = _mm_add_epi16(curs, bias);\n      __m128i even = _mm_add_epi16(prvd, curb);\n      __m128i odd  = _mm_add_epi16(nxtd, curb);\n\n      // interleave even and odd pixels, then undo scaling.\n      __m128i int0 = _mm_unpacklo_epi16(even, odd);\n      __m128i int1 = _mm_unpackhi_epi16(even, odd);\n      __m128i de0  = _mm_srli_epi16(int0, 4);\n      __m128i de1  = _mm_srli_epi16(int1, 4);\n\n      // pack and write output\n      __m128i outv = _mm_packus_epi16(de0, de1);\n      _mm_storeu_si128((__m128i *) (out + i*2), outv);\n#elif defined(STBI_NEON)\n      // load and perform the vertical filtering pass\n      // this uses 3*x + y = 4*x + (y - x)\n      uint8x8_t farb  = vld1_u8(in_far + i);\n      uint8x8_t nearb = vld1_u8(in_near + i);\n      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));\n      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));\n      int16x8_t curr  = vaddq_s16(nears, diff); // current row\n\n      // horizontal filter works the same based on shifted vers of current\n      // row. \"prev\" is current row shifted right by 1 pixel; we need to\n      // insert the previous pixel value (from t1).\n      // \"next\" is current row shifted left by 1 pixel, with first pixel\n      // of next block of 8 pixels added in.\n      int16x8_t prv0 = vextq_s16(curr, curr, 7);\n      int16x8_t nxt0 = vextq_s16(curr, curr, 1);\n      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);\n      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);\n\n      // horizontal filter, polyphase implementation since it's convenient:\n      // even pixels = 3*cur + prev = cur*4 + (prev - cur)\n      // odd  pixels = 3*cur + next = cur*4 + (next - cur)\n      // note the shared term.\n      int16x8_t curs = vshlq_n_s16(curr, 2);\n      int16x8_t prvd = vsubq_s16(prev, curr);\n      int16x8_t nxtd = vsubq_s16(next, curr);\n      int16x8_t even = vaddq_s16(curs, prvd);\n      int16x8_t odd  = vaddq_s16(curs, nxtd);\n\n      // undo scaling and round, then store with even/odd phases interleaved\n      uint8x8x2_t o;\n      o.val[0] = vqrshrun_n_s16(even, 4);\n      o.val[1] = vqrshrun_n_s16(odd,  4);\n      vst2_u8(out + i*2, o);\n#endif\n\n      // \"previous\" value for next iter\n      t1 = 3*in_near[i+7] + in_far[i+7];\n   }\n\n   t0 = t1;\n   t1 = 3*in_near[i] + in_far[i];\n   out[i*2] = stbi__div16(3*t1 + t0 + 8);\n\n   for (++i; i < w; ++i) {\n      t0 = t1;\n      t1 = 3*in_near[i]+in_far[i];\n      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);\n      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);\n   }\n   out[w*2-1] = stbi__div4(t1+2);\n\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n#endif\n\nstatic stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // resample with nearest-neighbor\n   int i,j;\n   STBI_NOTUSED(in_far);\n   for (i=0; i < w; ++i)\n      for (j=0; j < hs; ++j)\n         out[i*hs+j] = in_near[i];\n   return out;\n}\n\n// this is a reduced-precision calculation of YCbCr-to-RGB introduced\n// to make sure the code produces the same results in both SIMD and scalar\n#define stbi__float2fixed(x)  (((int) ((x) * 4096.0f + 0.5f)) << 8)\nstatic void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)\n{\n   int i;\n   for (i=0; i < count; ++i) {\n      int y_fixed = (y[i] << 20) + (1<<19); // rounding\n      int r,g,b;\n      int cr = pcr[i] - 128;\n      int cb = pcb[i] - 128;\n      r = y_fixed +  cr* stbi__float2fixed(1.40200f);\n      g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);\n      b = y_fixed                                     +   cb* stbi__float2fixed(1.77200f);\n      r >>= 20;\n      g >>= 20;\n      b >>= 20;\n      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }\n      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }\n      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }\n      out[0] = (stbi_uc)r;\n      out[1] = (stbi_uc)g;\n      out[2] = (stbi_uc)b;\n      out[3] = 255;\n      out += step;\n   }\n}\n\n#if defined(STBI_SSE2) || defined(STBI_NEON)\nstatic void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)\n{\n   int i = 0;\n\n#ifdef STBI_SSE2\n   // step == 3 is pretty ugly on the final interleave, and i'm not convinced\n   // it's useful in practice (you wouldn't use it for textures, for example).\n   // so just accelerate step == 4 case.\n   if (step == 4) {\n      // this is a fairly straightforward implementation and not super-optimized.\n      __m128i signflip  = _mm_set1_epi8(-0x80);\n      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));\n      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));\n      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));\n      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));\n      __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);\n      __m128i xw = _mm_set1_epi16(255); // alpha channel\n\n      for (; i+7 < count; i += 8) {\n         // load\n         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));\n         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));\n         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));\n         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128\n         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128\n\n         // unpack to short (and left-shift cr, cb by 8)\n         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);\n         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);\n         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);\n\n         // color transform\n         __m128i yws = _mm_srli_epi16(yw, 4);\n         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);\n         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);\n         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);\n         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);\n         __m128i rws = _mm_add_epi16(cr0, yws);\n         __m128i gwt = _mm_add_epi16(cb0, yws);\n         __m128i bws = _mm_add_epi16(yws, cb1);\n         __m128i gws = _mm_add_epi16(gwt, cr1);\n\n         // descale\n         __m128i rw = _mm_srai_epi16(rws, 4);\n         __m128i bw = _mm_srai_epi16(bws, 4);\n         __m128i gw = _mm_srai_epi16(gws, 4);\n\n         // back to byte, set up for transpose\n         __m128i brb = _mm_packus_epi16(rw, bw);\n         __m128i gxb = _mm_packus_epi16(gw, xw);\n\n         // transpose to interleave channels\n         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);\n         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);\n         __m128i o0 = _mm_unpacklo_epi16(t0, t1);\n         __m128i o1 = _mm_unpackhi_epi16(t0, t1);\n\n         // store\n         _mm_storeu_si128((__m128i *) (out + 0), o0);\n         _mm_storeu_si128((__m128i *) (out + 16), o1);\n         out += 32;\n      }\n   }\n#endif\n\n#ifdef STBI_NEON\n   // in this version, step=3 support would be easy to add. but is there demand?\n   if (step == 4) {\n      // this is a fairly straightforward implementation and not super-optimized.\n      uint8x8_t signflip = vdup_n_u8(0x80);\n      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));\n      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));\n      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));\n      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));\n\n      for (; i+7 < count; i += 8) {\n         // load\n         uint8x8_t y_bytes  = vld1_u8(y + i);\n         uint8x8_t cr_bytes = vld1_u8(pcr + i);\n         uint8x8_t cb_bytes = vld1_u8(pcb + i);\n         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));\n         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));\n\n         // expand to s16\n         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));\n         int16x8_t crw = vshll_n_s8(cr_biased, 7);\n         int16x8_t cbw = vshll_n_s8(cb_biased, 7);\n\n         // color transform\n         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);\n         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);\n         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);\n         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);\n         int16x8_t rws = vaddq_s16(yws, cr0);\n         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);\n         int16x8_t bws = vaddq_s16(yws, cb1);\n\n         // undo scaling, round, convert to byte\n         uint8x8x4_t o;\n         o.val[0] = vqrshrun_n_s16(rws, 4);\n         o.val[1] = vqrshrun_n_s16(gws, 4);\n         o.val[2] = vqrshrun_n_s16(bws, 4);\n         o.val[3] = vdup_n_u8(255);\n\n         // store, interleaving r/g/b/a\n         vst4_u8(out, o);\n         out += 8*4;\n      }\n   }\n#endif\n\n   for (; i < count; ++i) {\n      int y_fixed = (y[i] << 20) + (1<<19); // rounding\n      int r,g,b;\n      int cr = pcr[i] - 128;\n      int cb = pcb[i] - 128;\n      r = y_fixed + cr* stbi__float2fixed(1.40200f);\n      g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);\n      b = y_fixed                                   +   cb* stbi__float2fixed(1.77200f);\n      r >>= 20;\n      g >>= 20;\n      b >>= 20;\n      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }\n      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }\n      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }\n      out[0] = (stbi_uc)r;\n      out[1] = (stbi_uc)g;\n      out[2] = (stbi_uc)b;\n      out[3] = 255;\n      out += step;\n   }\n}\n#endif\n\n// set up the kernels\nstatic void stbi__setup_jpeg(stbi__jpeg *j)\n{\n   j->idct_block_kernel = stbi__idct_block;\n   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row;\n   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2;\n\n#ifdef STBI_SSE2\n   if (stbi__sse2_available()) {\n      j->idct_block_kernel = stbi__idct_simd;\n      j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;\n      j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;\n   }\n#endif\n\n#ifdef STBI_NEON\n   j->idct_block_kernel = stbi__idct_simd;\n   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;\n   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;\n#endif\n}\n\n// clean up the temporary component buffers\nstatic void stbi__cleanup_jpeg(stbi__jpeg *j)\n{\n   stbi__free_jpeg_components(j, j->s->img_n, 0);\n}\n\ntypedef struct\n{\n   resample_row_func resample;\n   stbi_uc *line0,*line1;\n   int hs,vs;   // expansion factor in each axis\n   int w_lores; // horizontal pixels pre-expansion\n   int ystep;   // how far through vertical expansion we are\n   int ypos;    // which pre-expansion row we're on\n} stbi__resample;\n\n// fast 0..255 * 0..255 => 0..255 rounded multiplication\nstatic stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y)\n{\n   unsigned int t = x*y + 128;\n   return (stbi_uc) ((t + (t >>8)) >> 8);\n}\n\nstatic stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)\n{\n   int n, decode_n, is_rgb;\n   z->s->img_n = 0; // make stbi__cleanup_jpeg safe\n\n   // validate req_comp\n   if (req_comp < 0 || req_comp > 4) return stbi__errpuc(\"bad req_comp\", \"Internal error\");\n\n   // load a jpeg image from whichever source, but leave in YCbCr format\n   if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }\n\n   // determine actual number of components to generate\n   n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1;\n\n   is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif));\n\n   if (z->s->img_n == 3 && n < 3 && !is_rgb)\n      decode_n = 1;\n   else\n      decode_n = z->s->img_n;\n\n   // nothing to do if no components requested; check this now to avoid\n   // accessing uninitialized coutput[0] later\n   if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; }\n\n   // resample and color-convert\n   {\n      int k;\n      unsigned int i,j;\n      stbi_uc *output;\n      stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL };\n\n      stbi__resample res_comp[4];\n\n      for (k=0; k < decode_n; ++k) {\n         stbi__resample *r = &res_comp[k];\n\n         // allocate line buffer big enough for upsampling off the edges\n         // with upsample factor of 4\n         z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);\n         if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n\n         r->hs      = z->img_h_max / z->img_comp[k].h;\n         r->vs      = z->img_v_max / z->img_comp[k].v;\n         r->ystep   = r->vs >> 1;\n         r->w_lores = (z->s->img_x + r->hs-1) / r->hs;\n         r->ypos    = 0;\n         r->line0   = r->line1 = z->img_comp[k].data;\n\n         if      (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;\n         else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2;\n         else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2;\n         else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel;\n         else                               r->resample = stbi__resample_row_generic;\n      }\n\n      // can't error after this so, this is safe\n      output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1);\n      if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n\n      // now go ahead and resample\n      for (j=0; j < z->s->img_y; ++j) {\n         stbi_uc *out = output + n * z->s->img_x * j;\n         for (k=0; k < decode_n; ++k) {\n            stbi__resample *r = &res_comp[k];\n            int y_bot = r->ystep >= (r->vs >> 1);\n            coutput[k] = r->resample(z->img_comp[k].linebuf,\n                                     y_bot ? r->line1 : r->line0,\n                                     y_bot ? r->line0 : r->line1,\n                                     r->w_lores, r->hs);\n            if (++r->ystep >= r->vs) {\n               r->ystep = 0;\n               r->line0 = r->line1;\n               if (++r->ypos < z->img_comp[k].y)\n                  r->line1 += z->img_comp[k].w2;\n            }\n         }\n         if (n >= 3) {\n            stbi_uc *y = coutput[0];\n            if (z->s->img_n == 3) {\n               if (is_rgb) {\n                  for (i=0; i < z->s->img_x; ++i) {\n                     out[0] = y[i];\n                     out[1] = coutput[1][i];\n                     out[2] = coutput[2][i];\n                     out[3] = 255;\n                     out += n;\n                  }\n               } else {\n                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);\n               }\n            } else if (z->s->img_n == 4) {\n               if (z->app14_color_transform == 0) { // CMYK\n                  for (i=0; i < z->s->img_x; ++i) {\n                     stbi_uc m = coutput[3][i];\n                     out[0] = stbi__blinn_8x8(coutput[0][i], m);\n                     out[1] = stbi__blinn_8x8(coutput[1][i], m);\n                     out[2] = stbi__blinn_8x8(coutput[2][i], m);\n                     out[3] = 255;\n                     out += n;\n                  }\n               } else if (z->app14_color_transform == 2) { // YCCK\n                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);\n                  for (i=0; i < z->s->img_x; ++i) {\n                     stbi_uc m = coutput[3][i];\n                     out[0] = stbi__blinn_8x8(255 - out[0], m);\n                     out[1] = stbi__blinn_8x8(255 - out[1], m);\n                     out[2] = stbi__blinn_8x8(255 - out[2], m);\n                     out += n;\n                  }\n               } else { // YCbCr + alpha?  Ignore the fourth channel for now\n                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);\n               }\n            } else\n               for (i=0; i < z->s->img_x; ++i) {\n                  out[0] = out[1] = out[2] = y[i];\n                  out[3] = 255; // not used if n==3\n                  out += n;\n               }\n         } else {\n            if (is_rgb) {\n               if (n == 1)\n                  for (i=0; i < z->s->img_x; ++i)\n                     *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);\n               else {\n                  for (i=0; i < z->s->img_x; ++i, out += 2) {\n                     out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);\n                     out[1] = 255;\n                  }\n               }\n            } else if (z->s->img_n == 4 && z->app14_color_transform == 0) {\n               for (i=0; i < z->s->img_x; ++i) {\n                  stbi_uc m = coutput[3][i];\n                  stbi_uc r = stbi__blinn_8x8(coutput[0][i], m);\n                  stbi_uc g = stbi__blinn_8x8(coutput[1][i], m);\n                  stbi_uc b = stbi__blinn_8x8(coutput[2][i], m);\n                  out[0] = stbi__compute_y(r, g, b);\n                  out[1] = 255;\n                  out += n;\n               }\n            } else if (z->s->img_n == 4 && z->app14_color_transform == 2) {\n               for (i=0; i < z->s->img_x; ++i) {\n                  out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]);\n                  out[1] = 255;\n                  out += n;\n               }\n            } else {\n               stbi_uc *y = coutput[0];\n               if (n == 1)\n                  for (i=0; i < z->s->img_x; ++i) out[i] = y[i];\n               else\n                  for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; }\n            }\n         }\n      }\n      stbi__cleanup_jpeg(z);\n      *out_x = z->s->img_x;\n      *out_y = z->s->img_y;\n      if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output\n      return output;\n   }\n}\n\nstatic void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   unsigned char* result;\n   stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));\n   if (!j) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   memset(j, 0, sizeof(stbi__jpeg));\n   STBI_NOTUSED(ri);\n   j->s = s;\n   stbi__setup_jpeg(j);\n   result = load_jpeg_image(j, x,y,comp,req_comp);\n   STBI_FREE(j);\n   return result;\n}\n\nstatic int stbi__jpeg_test(stbi__context *s)\n{\n   int r;\n   stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));\n   if (!j) return stbi__err(\"outofmem\", \"Out of memory\");\n   memset(j, 0, sizeof(stbi__jpeg));\n   j->s = s;\n   stbi__setup_jpeg(j);\n   r = stbi__decode_jpeg_header(j, STBI__SCAN_type);\n   stbi__rewind(s);\n   STBI_FREE(j);\n   return r;\n}\n\nstatic int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)\n{\n   if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) {\n      stbi__rewind( j->s );\n      return 0;\n   }\n   if (x) *x = j->s->img_x;\n   if (y) *y = j->s->img_y;\n   if (comp) *comp = j->s->img_n >= 3 ? 3 : 1;\n   return 1;\n}\n\nstatic int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int result;\n   stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));\n   if (!j) return stbi__err(\"outofmem\", \"Out of memory\");\n   memset(j, 0, sizeof(stbi__jpeg));\n   j->s = s;\n   result = stbi__jpeg_info_raw(j, x, y, comp);\n   STBI_FREE(j);\n   return result;\n}\n#endif\n\n// public domain zlib decode    v0.2  Sean Barrett 2006-11-18\n//    simple implementation\n//      - all input must be provided in an upfront buffer\n//      - all output is written to a single output buffer (can malloc/realloc)\n//    performance\n//      - fast huffman\n\n#ifndef STBI_NO_ZLIB\n\n// fast-way is faster to check than jpeg huffman, but slow way is slower\n#define STBI__ZFAST_BITS  9 // accelerate all cases in default tables\n#define STBI__ZFAST_MASK  ((1 << STBI__ZFAST_BITS) - 1)\n#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet\n\n// zlib-style huffman encoding\n// (jpegs packs from left, zlib from right, so can't share code)\ntypedef struct\n{\n   stbi__uint16 fast[1 << STBI__ZFAST_BITS];\n   stbi__uint16 firstcode[16];\n   int maxcode[17];\n   stbi__uint16 firstsymbol[16];\n   stbi_uc  size[STBI__ZNSYMS];\n   stbi__uint16 value[STBI__ZNSYMS];\n} stbi__zhuffman;\n\nstbi_inline static int stbi__bitreverse16(int n)\n{\n  n = ((n & 0xAAAA) >>  1) | ((n & 0x5555) << 1);\n  n = ((n & 0xCCCC) >>  2) | ((n & 0x3333) << 2);\n  n = ((n & 0xF0F0) >>  4) | ((n & 0x0F0F) << 4);\n  n = ((n & 0xFF00) >>  8) | ((n & 0x00FF) << 8);\n  return n;\n}\n\nstbi_inline static int stbi__bit_reverse(int v, int bits)\n{\n   STBI_ASSERT(bits <= 16);\n   // to bit reverse n bits, reverse 16 and shift\n   // e.g. 11 bits, bit reverse and shift away 5\n   return stbi__bitreverse16(v) >> (16-bits);\n}\n\nstatic int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num)\n{\n   int i,k=0;\n   int code, next_code[16], sizes[17];\n\n   // DEFLATE spec for generating codes\n   memset(sizes, 0, sizeof(sizes));\n   memset(z->fast, 0, sizeof(z->fast));\n   for (i=0; i < num; ++i)\n      ++sizes[sizelist[i]];\n   sizes[0] = 0;\n   for (i=1; i < 16; ++i)\n      if (sizes[i] > (1 << i))\n         return stbi__err(\"bad sizes\", \"Corrupt PNG\");\n   code = 0;\n   for (i=1; i < 16; ++i) {\n      next_code[i] = code;\n      z->firstcode[i] = (stbi__uint16) code;\n      z->firstsymbol[i] = (stbi__uint16) k;\n      code = (code + sizes[i]);\n      if (sizes[i])\n         if (code-1 >= (1 << i)) return stbi__err(\"bad codelengths\",\"Corrupt PNG\");\n      z->maxcode[i] = code << (16-i); // preshift for inner loop\n      code <<= 1;\n      k += sizes[i];\n   }\n   z->maxcode[16] = 0x10000; // sentinel\n   for (i=0; i < num; ++i) {\n      int s = sizelist[i];\n      if (s) {\n         int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];\n         stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);\n         z->size [c] = (stbi_uc     ) s;\n         z->value[c] = (stbi__uint16) i;\n         if (s <= STBI__ZFAST_BITS) {\n            int j = stbi__bit_reverse(next_code[s],s);\n            while (j < (1 << STBI__ZFAST_BITS)) {\n               z->fast[j] = fastv;\n               j += (1 << s);\n            }\n         }\n         ++next_code[s];\n      }\n   }\n   return 1;\n}\n\n// zlib-from-memory implementation for PNG reading\n//    because PNG allows splitting the zlib stream arbitrarily,\n//    and it's annoying structurally to have PNG call ZLIB call PNG,\n//    we require PNG read all the IDATs and combine them into a single\n//    memory buffer\n\ntypedef struct\n{\n   stbi_uc *zbuffer, *zbuffer_end;\n   int num_bits;\n   stbi__uint32 code_buffer;\n\n   char *zout;\n   char *zout_start;\n   char *zout_end;\n   int   z_expandable;\n\n   stbi__zhuffman z_length, z_distance;\n} stbi__zbuf;\n\nstbi_inline static int stbi__zeof(stbi__zbuf *z)\n{\n   return (z->zbuffer >= z->zbuffer_end);\n}\n\nstbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)\n{\n   return stbi__zeof(z) ? 0 : *z->zbuffer++;\n}\n\nstatic void stbi__fill_bits(stbi__zbuf *z)\n{\n   do {\n      if (z->code_buffer >= (1U << z->num_bits)) {\n        z->zbuffer = z->zbuffer_end;  /* treat this as EOF so we fail. */\n        return;\n      }\n      z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;\n      z->num_bits += 8;\n   } while (z->num_bits <= 24);\n}\n\nstbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)\n{\n   unsigned int k;\n   if (z->num_bits < n) stbi__fill_bits(z);\n   k = z->code_buffer & ((1 << n) - 1);\n   z->code_buffer >>= n;\n   z->num_bits -= n;\n   return k;\n}\n\nstatic int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)\n{\n   int b,s,k;\n   // not resolved by fast table, so compute it the slow way\n   // use jpeg approach, which requires MSbits at top\n   k = stbi__bit_reverse(a->code_buffer, 16);\n   for (s=STBI__ZFAST_BITS+1; ; ++s)\n      if (k < z->maxcode[s])\n         break;\n   if (s >= 16) return -1; // invalid code!\n   // code size is s, so:\n   b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];\n   if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere!\n   if (z->size[b] != s) return -1;  // was originally an assert, but report failure instead.\n   a->code_buffer >>= s;\n   a->num_bits -= s;\n   return z->value[b];\n}\n\nstbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)\n{\n   int b,s;\n   if (a->num_bits < 16) {\n      if (stbi__zeof(a)) {\n         return -1;   /* report error for unexpected end of data. */\n      }\n      stbi__fill_bits(a);\n   }\n   b = z->fast[a->code_buffer & STBI__ZFAST_MASK];\n   if (b) {\n      s = b >> 9;\n      a->code_buffer >>= s;\n      a->num_bits -= s;\n      return b & 511;\n   }\n   return stbi__zhuffman_decode_slowpath(a, z);\n}\n\nstatic int stbi__zexpand(stbi__zbuf *z, char *zout, int n)  // need to make room for n bytes\n{\n   char *q;\n   unsigned int cur, limit, old_limit;\n   z->zout = zout;\n   if (!z->z_expandable) return stbi__err(\"output buffer limit\",\"Corrupt PNG\");\n   cur   = (unsigned int) (z->zout - z->zout_start);\n   limit = old_limit = (unsigned) (z->zout_end - z->zout_start);\n   if (UINT_MAX - cur < (unsigned) n) return stbi__err(\"outofmem\", \"Out of memory\");\n   while (cur + n > limit) {\n      if(limit > UINT_MAX / 2) return stbi__err(\"outofmem\", \"Out of memory\");\n      limit *= 2;\n   }\n   q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);\n   STBI_NOTUSED(old_limit);\n   if (q == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n   z->zout_start = q;\n   z->zout       = q + cur;\n   z->zout_end   = q + limit;\n   return 1;\n}\n\nstatic const int stbi__zlength_base[31] = {\n   3,4,5,6,7,8,9,10,11,13,\n   15,17,19,23,27,31,35,43,51,59,\n   67,83,99,115,131,163,195,227,258,0,0 };\n\nstatic const int stbi__zlength_extra[31]=\n{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };\n\nstatic const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,\n257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};\n\nstatic const int stbi__zdist_extra[32] =\n{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};\n\nstatic int stbi__parse_huffman_block(stbi__zbuf *a)\n{\n   char *zout = a->zout;\n   for(;;) {\n      int z = stbi__zhuffman_decode(a, &a->z_length);\n      if (z < 256) {\n         if (z < 0) return stbi__err(\"bad huffman code\",\"Corrupt PNG\"); // error in huffman codes\n         if (zout >= a->zout_end) {\n            if (!stbi__zexpand(a, zout, 1)) return 0;\n            zout = a->zout;\n         }\n         *zout++ = (char) z;\n      } else {\n         stbi_uc *p;\n         int len,dist;\n         if (z == 256) {\n            a->zout = zout;\n            return 1;\n         }\n         if (z >= 286) return stbi__err(\"bad huffman code\",\"Corrupt PNG\"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data\n         z -= 257;\n         len = stbi__zlength_base[z];\n         if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);\n         z = stbi__zhuffman_decode(a, &a->z_distance);\n         if (z < 0 || z >= 30) return stbi__err(\"bad huffman code\",\"Corrupt PNG\"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data\n         dist = stbi__zdist_base[z];\n         if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);\n         if (zout - a->zout_start < dist) return stbi__err(\"bad dist\",\"Corrupt PNG\");\n         if (zout + len > a->zout_end) {\n            if (!stbi__zexpand(a, zout, len)) return 0;\n            zout = a->zout;\n         }\n         p = (stbi_uc *) (zout - dist);\n         if (dist == 1) { // run of one byte; common in images.\n            stbi_uc v = *p;\n            if (len) { do *zout++ = v; while (--len); }\n         } else {\n            if (len) { do *zout++ = *p++; while (--len); }\n         }\n      }\n   }\n}\n\nstatic int stbi__compute_huffman_codes(stbi__zbuf *a)\n{\n   static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };\n   stbi__zhuffman z_codelength;\n   stbi_uc lencodes[286+32+137];//padding for maximum single op\n   stbi_uc codelength_sizes[19];\n   int i,n;\n\n   int hlit  = stbi__zreceive(a,5) + 257;\n   int hdist = stbi__zreceive(a,5) + 1;\n   int hclen = stbi__zreceive(a,4) + 4;\n   int ntot  = hlit + hdist;\n\n   memset(codelength_sizes, 0, sizeof(codelength_sizes));\n   for (i=0; i < hclen; ++i) {\n      int s = stbi__zreceive(a,3);\n      codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;\n   }\n   if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;\n\n   n = 0;\n   while (n < ntot) {\n      int c = stbi__zhuffman_decode(a, &z_codelength);\n      if (c < 0 || c >= 19) return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n      if (c < 16)\n         lencodes[n++] = (stbi_uc) c;\n      else {\n         stbi_uc fill = 0;\n         if (c == 16) {\n            c = stbi__zreceive(a,2)+3;\n            if (n == 0) return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n            fill = lencodes[n-1];\n         } else if (c == 17) {\n            c = stbi__zreceive(a,3)+3;\n         } else if (c == 18) {\n            c = stbi__zreceive(a,7)+11;\n         } else {\n            return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n         }\n         if (ntot - n < c) return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n         memset(lencodes+n, fill, c);\n         n += c;\n      }\n   }\n   if (n != ntot) return stbi__err(\"bad codelengths\",\"Corrupt PNG\");\n   if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;\n   if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;\n   return 1;\n}\n\nstatic int stbi__parse_uncompressed_block(stbi__zbuf *a)\n{\n   stbi_uc header[4];\n   int len,nlen,k;\n   if (a->num_bits & 7)\n      stbi__zreceive(a, a->num_bits & 7); // discard\n   // drain the bit-packed data into header\n   k = 0;\n   while (a->num_bits > 0) {\n      header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check\n      a->code_buffer >>= 8;\n      a->num_bits -= 8;\n   }\n   if (a->num_bits < 0) return stbi__err(\"zlib corrupt\",\"Corrupt PNG\");\n   // now fill header the normal way\n   while (k < 4)\n      header[k++] = stbi__zget8(a);\n   len  = header[1] * 256 + header[0];\n   nlen = header[3] * 256 + header[2];\n   if (nlen != (len ^ 0xffff)) return stbi__err(\"zlib corrupt\",\"Corrupt PNG\");\n   if (a->zbuffer + len > a->zbuffer_end) return stbi__err(\"read past buffer\",\"Corrupt PNG\");\n   if (a->zout + len > a->zout_end)\n      if (!stbi__zexpand(a, a->zout, len)) return 0;\n   memcpy(a->zout, a->zbuffer, len);\n   a->zbuffer += len;\n   a->zout += len;\n   return 1;\n}\n\nstatic int stbi__parse_zlib_header(stbi__zbuf *a)\n{\n   int cmf   = stbi__zget8(a);\n   int cm    = cmf & 15;\n   /* int cinfo = cmf >> 4; */\n   int flg   = stbi__zget8(a);\n   if (stbi__zeof(a)) return stbi__err(\"bad zlib header\",\"Corrupt PNG\"); // zlib spec\n   if ((cmf*256+flg) % 31 != 0) return stbi__err(\"bad zlib header\",\"Corrupt PNG\"); // zlib spec\n   if (flg & 32) return stbi__err(\"no preset dict\",\"Corrupt PNG\"); // preset dictionary not allowed in png\n   if (cm != 8) return stbi__err(\"bad compression\",\"Corrupt PNG\"); // DEFLATE required for png\n   // window = 1 << (8 + cinfo)... but who cares, we fully buffer output\n   return 1;\n}\n\nstatic const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] =\n{\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8\n};\nstatic const stbi_uc stbi__zdefault_distance[32] =\n{\n   5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5\n};\n/*\nInit algorithm:\n{\n   int i;   // use <= to match clearly with spec\n   for (i=0; i <= 143; ++i)     stbi__zdefault_length[i]   = 8;\n   for (   ; i <= 255; ++i)     stbi__zdefault_length[i]   = 9;\n   for (   ; i <= 279; ++i)     stbi__zdefault_length[i]   = 7;\n   for (   ; i <= 287; ++i)     stbi__zdefault_length[i]   = 8;\n\n   for (i=0; i <=  31; ++i)     stbi__zdefault_distance[i] = 5;\n}\n*/\n\nstatic int stbi__parse_zlib(stbi__zbuf *a, int parse_header)\n{\n   int final, type;\n   if (parse_header)\n      if (!stbi__parse_zlib_header(a)) return 0;\n   a->num_bits = 0;\n   a->code_buffer = 0;\n   do {\n      final = stbi__zreceive(a,1);\n      type = stbi__zreceive(a,2);\n      if (type == 0) {\n         if (!stbi__parse_uncompressed_block(a)) return 0;\n      } else if (type == 3) {\n         return 0;\n      } else {\n         if (type == 1) {\n            // use fixed code lengths\n            if (!stbi__zbuild_huffman(&a->z_length  , stbi__zdefault_length  , STBI__ZNSYMS)) return 0;\n            if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance,  32)) return 0;\n         } else {\n            if (!stbi__compute_huffman_codes(a)) return 0;\n         }\n         if (!stbi__parse_huffman_block(a)) return 0;\n      }\n   } while (!final);\n   return 1;\n}\n\nstatic int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)\n{\n   a->zout_start = obuf;\n   a->zout       = obuf;\n   a->zout_end   = obuf + olen;\n   a->z_expandable = exp;\n\n   return stbi__parse_zlib(a, parse_header);\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(initial_size);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer + len;\n   if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)\n{\n   return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(initial_size);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer + len;\n   if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)\n{\n   stbi__zbuf a;\n   a.zbuffer = (stbi_uc *) ibuffer;\n   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;\n   if (stbi__do_zlib(&a, obuffer, olen, 0, 1))\n      return (int) (a.zout - a.zout_start);\n   else\n      return -1;\n}\n\nSTBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(16384);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer+len;\n   if (stbi__do_zlib(&a, p, 16384, 1, 0)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)\n{\n   stbi__zbuf a;\n   a.zbuffer = (stbi_uc *) ibuffer;\n   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;\n   if (stbi__do_zlib(&a, obuffer, olen, 0, 0))\n      return (int) (a.zout - a.zout_start);\n   else\n      return -1;\n}\n#endif\n\n// public domain \"baseline\" PNG decoder   v0.10  Sean Barrett 2006-11-18\n//    simple implementation\n//      - only 8-bit samples\n//      - no CRC checking\n//      - allocates lots of intermediate memory\n//        - avoids problem of streaming data between subsystems\n//        - avoids explicit window management\n//    performance\n//      - uses stb_zlib, a PD zlib implementation with fast huffman decoding\n\n#ifndef STBI_NO_PNG\ntypedef struct\n{\n   stbi__uint32 length;\n   stbi__uint32 type;\n} stbi__pngchunk;\n\nstatic stbi__pngchunk stbi__get_chunk_header(stbi__context *s)\n{\n   stbi__pngchunk c;\n   c.length = stbi__get32be(s);\n   c.type   = stbi__get32be(s);\n   return c;\n}\n\nstatic int stbi__check_png_header(stbi__context *s)\n{\n   static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };\n   int i;\n   for (i=0; i < 8; ++i)\n      if (stbi__get8(s) != png_sig[i]) return stbi__err(\"bad png sig\",\"Not a PNG\");\n   return 1;\n}\n\ntypedef struct\n{\n   stbi__context *s;\n   stbi_uc *idata, *expanded, *out;\n   int depth;\n} stbi__png;\n\n\nenum {\n   STBI__F_none=0,\n   STBI__F_sub=1,\n   STBI__F_up=2,\n   STBI__F_avg=3,\n   STBI__F_paeth=4,\n   // synthetic filters used for first scanline to avoid needing a dummy row of 0s\n   STBI__F_avg_first,\n   STBI__F_paeth_first\n};\n\nstatic stbi_uc first_row_filter[5] =\n{\n   STBI__F_none,\n   STBI__F_sub,\n   STBI__F_none,\n   STBI__F_avg_first,\n   STBI__F_paeth_first\n};\n\nstatic int stbi__paeth(int a, int b, int c)\n{\n   int p = a + b - c;\n   int pa = abs(p-a);\n   int pb = abs(p-b);\n   int pc = abs(p-c);\n   if (pa <= pb && pa <= pc) return a;\n   if (pb <= pc) return b;\n   return c;\n}\n\nstatic const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };\n\n// create the png data from post-deflated data\nstatic int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)\n{\n   int bytes = (depth == 16? 2 : 1);\n   stbi__context *s = a->s;\n   stbi__uint32 i,j,stride = x*out_n*bytes;\n   stbi__uint32 img_len, img_width_bytes;\n   int k;\n   int img_n = s->img_n; // copy it into a local for later\n\n   int output_bytes = out_n*bytes;\n   int filter_bytes = img_n*bytes;\n   int width = x;\n\n   STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);\n   a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into\n   if (!a->out) return stbi__err(\"outofmem\", \"Out of memory\");\n\n   if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err(\"too large\", \"Corrupt PNG\");\n   img_width_bytes = (((img_n * x * depth) + 7) >> 3);\n   img_len = (img_width_bytes + 1) * y;\n\n   // we used to check for exact match between raw_len and img_len on non-interlaced PNGs,\n   // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros),\n   // so just check for raw_len < img_len always.\n   if (raw_len < img_len) return stbi__err(\"not enough pixels\",\"Corrupt PNG\");\n\n   for (j=0; j < y; ++j) {\n      stbi_uc *cur = a->out + stride*j;\n      stbi_uc *prior;\n      int filter = *raw++;\n\n      if (filter > 4)\n         return stbi__err(\"invalid filter\",\"Corrupt PNG\");\n\n      if (depth < 8) {\n         if (img_width_bytes > x) return stbi__err(\"invalid width\",\"Corrupt PNG\");\n         cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place\n         filter_bytes = 1;\n         width = img_width_bytes;\n      }\n      prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above\n\n      // if first row, use special filter that doesn't sample previous row\n      if (j == 0) filter = first_row_filter[filter];\n\n      // handle first byte explicitly\n      for (k=0; k < filter_bytes; ++k) {\n         switch (filter) {\n            case STBI__F_none       : cur[k] = raw[k]; break;\n            case STBI__F_sub        : cur[k] = raw[k]; break;\n            case STBI__F_up         : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;\n            case STBI__F_avg        : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;\n            case STBI__F_paeth      : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;\n            case STBI__F_avg_first  : cur[k] = raw[k]; break;\n            case STBI__F_paeth_first: cur[k] = raw[k]; break;\n         }\n      }\n\n      if (depth == 8) {\n         if (img_n != out_n)\n            cur[img_n] = 255; // first pixel\n         raw += img_n;\n         cur += out_n;\n         prior += out_n;\n      } else if (depth == 16) {\n         if (img_n != out_n) {\n            cur[filter_bytes]   = 255; // first pixel top byte\n            cur[filter_bytes+1] = 255; // first pixel bottom byte\n         }\n         raw += filter_bytes;\n         cur += output_bytes;\n         prior += output_bytes;\n      } else {\n         raw += 1;\n         cur += 1;\n         prior += 1;\n      }\n\n      // this is a little gross, so that we don't switch per-pixel or per-component\n      if (depth < 8 || img_n == out_n) {\n         int nk = (width - 1)*filter_bytes;\n         #define STBI__CASE(f) \\\n             case f:     \\\n                for (k=0; k < nk; ++k)\n         switch (filter) {\n            // \"none\" filter turns into a memcpy here; make that explicit.\n            case STBI__F_none:         memcpy(cur, raw, nk); break;\n            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;\n            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;\n            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;\n            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;\n            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;\n            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;\n         }\n         #undef STBI__CASE\n         raw += nk;\n      } else {\n         STBI_ASSERT(img_n+1 == out_n);\n         #define STBI__CASE(f) \\\n             case f:     \\\n                for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \\\n                   for (k=0; k < filter_bytes; ++k)\n         switch (filter) {\n            STBI__CASE(STBI__F_none)         { cur[k] = raw[k]; } break;\n            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;\n            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;\n            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;\n            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;\n            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;\n            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;\n         }\n         #undef STBI__CASE\n\n         // the loop above sets the high byte of the pixels' alpha, but for\n         // 16 bit png files we also need the low byte set. we'll do that here.\n         if (depth == 16) {\n            cur = a->out + stride*j; // start at the beginning of the row again\n            for (i=0; i < x; ++i,cur+=output_bytes) {\n               cur[filter_bytes+1] = 255;\n            }\n         }\n      }\n   }\n\n   // we make a separate pass to expand bits to pixels; for performance,\n   // this could run two scanlines behind the above code, so it won't\n   // intefere with filtering but will still be in the cache.\n   if (depth < 8) {\n      for (j=0; j < y; ++j) {\n         stbi_uc *cur = a->out + stride*j;\n         stbi_uc *in  = a->out + stride*j + x*out_n - img_width_bytes;\n         // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit\n         // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop\n         stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range\n\n         // note that the final byte might overshoot and write more data than desired.\n         // we can allocate enough data that this never writes out of memory, but it\n         // could also overwrite the next scanline. can it overwrite non-empty data\n         // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.\n         // so we need to explicitly clamp the final ones\n\n         if (depth == 4) {\n            for (k=x*img_n; k >= 2; k-=2, ++in) {\n               *cur++ = scale * ((*in >> 4)       );\n               *cur++ = scale * ((*in     ) & 0x0f);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 4)       );\n         } else if (depth == 2) {\n            for (k=x*img_n; k >= 4; k-=4, ++in) {\n               *cur++ = scale * ((*in >> 6)       );\n               *cur++ = scale * ((*in >> 4) & 0x03);\n               *cur++ = scale * ((*in >> 2) & 0x03);\n               *cur++ = scale * ((*in     ) & 0x03);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 6)       );\n            if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);\n            if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);\n         } else if (depth == 1) {\n            for (k=x*img_n; k >= 8; k-=8, ++in) {\n               *cur++ = scale * ((*in >> 7)       );\n               *cur++ = scale * ((*in >> 6) & 0x01);\n               *cur++ = scale * ((*in >> 5) & 0x01);\n               *cur++ = scale * ((*in >> 4) & 0x01);\n               *cur++ = scale * ((*in >> 3) & 0x01);\n               *cur++ = scale * ((*in >> 2) & 0x01);\n               *cur++ = scale * ((*in >> 1) & 0x01);\n               *cur++ = scale * ((*in     ) & 0x01);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 7)       );\n            if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);\n            if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);\n            if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);\n            if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);\n            if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);\n            if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);\n         }\n         if (img_n != out_n) {\n            int q;\n            // insert alpha = 255\n            cur = a->out + stride*j;\n            if (img_n == 1) {\n               for (q=x-1; q >= 0; --q) {\n                  cur[q*2+1] = 255;\n                  cur[q*2+0] = cur[q];\n               }\n            } else {\n               STBI_ASSERT(img_n == 3);\n               for (q=x-1; q >= 0; --q) {\n                  cur[q*4+3] = 255;\n                  cur[q*4+2] = cur[q*3+2];\n                  cur[q*4+1] = cur[q*3+1];\n                  cur[q*4+0] = cur[q*3+0];\n               }\n            }\n         }\n      }\n   } else if (depth == 16) {\n      // force the image data from big-endian to platform-native.\n      // this is done in a separate pass due to the decoding relying\n      // on the data being untouched, but could probably be done\n      // per-line during decode if care is taken.\n      stbi_uc *cur = a->out;\n      stbi__uint16 *cur16 = (stbi__uint16*)cur;\n\n      for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {\n         *cur16 = (cur[0] << 8) | cur[1];\n      }\n   }\n\n   return 1;\n}\n\nstatic int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)\n{\n   int bytes = (depth == 16 ? 2 : 1);\n   int out_bytes = out_n * bytes;\n   stbi_uc *final;\n   int p;\n   if (!interlaced)\n      return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);\n\n   // de-interlacing\n   final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);\n   if (!final) return stbi__err(\"outofmem\", \"Out of memory\");\n   for (p=0; p < 7; ++p) {\n      int xorig[] = { 0,4,0,2,0,1,0 };\n      int yorig[] = { 0,0,4,0,2,0,1 };\n      int xspc[]  = { 8,8,4,4,2,2,1 };\n      int yspc[]  = { 8,8,8,4,4,2,2 };\n      int i,j,x,y;\n      // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1\n      x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];\n      y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];\n      if (x && y) {\n         stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;\n         if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {\n            STBI_FREE(final);\n            return 0;\n         }\n         for (j=0; j < y; ++j) {\n            for (i=0; i < x; ++i) {\n               int out_y = j*yspc[p]+yorig[p];\n               int out_x = i*xspc[p]+xorig[p];\n               memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes,\n                      a->out + (j*x+i)*out_bytes, out_bytes);\n            }\n         }\n         STBI_FREE(a->out);\n         image_data += img_len;\n         image_data_len -= img_len;\n      }\n   }\n   a->out = final;\n\n   return 1;\n}\n\nstatic int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi_uc *p = z->out;\n\n   // compute color-based transparency, assuming we've\n   // already got 255 as the alpha value in the output\n   STBI_ASSERT(out_n == 2 || out_n == 4);\n\n   if (out_n == 2) {\n      for (i=0; i < pixel_count; ++i) {\n         p[1] = (p[0] == tc[0] ? 0 : 255);\n         p += 2;\n      }\n   } else {\n      for (i=0; i < pixel_count; ++i) {\n         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])\n            p[3] = 0;\n         p += 4;\n      }\n   }\n   return 1;\n}\n\nstatic int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi__uint16 *p = (stbi__uint16*) z->out;\n\n   // compute color-based transparency, assuming we've\n   // already got 65535 as the alpha value in the output\n   STBI_ASSERT(out_n == 2 || out_n == 4);\n\n   if (out_n == 2) {\n      for (i = 0; i < pixel_count; ++i) {\n         p[1] = (p[0] == tc[0] ? 0 : 65535);\n         p += 2;\n      }\n   } else {\n      for (i = 0; i < pixel_count; ++i) {\n         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])\n            p[3] = 0;\n         p += 4;\n      }\n   }\n   return 1;\n}\n\nstatic int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)\n{\n   stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;\n   stbi_uc *p, *temp_out, *orig = a->out;\n\n   p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);\n   if (p == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n\n   // between here and free(out) below, exitting would leak\n   temp_out = p;\n\n   if (pal_img_n == 3) {\n      for (i=0; i < pixel_count; ++i) {\n         int n = orig[i]*4;\n         p[0] = palette[n  ];\n         p[1] = palette[n+1];\n         p[2] = palette[n+2];\n         p += 3;\n      }\n   } else {\n      for (i=0; i < pixel_count; ++i) {\n         int n = orig[i]*4;\n         p[0] = palette[n  ];\n         p[1] = palette[n+1];\n         p[2] = palette[n+2];\n         p[3] = palette[n+3];\n         p += 4;\n      }\n   }\n   STBI_FREE(a->out);\n   a->out = temp_out;\n\n   STBI_NOTUSED(len);\n\n   return 1;\n}\n\nstatic int stbi__unpremultiply_on_load_global = 0;\nstatic int stbi__de_iphone_flag_global = 0;\n\nSTBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)\n{\n   stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply;\n}\n\nSTBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)\n{\n   stbi__de_iphone_flag_global = flag_true_if_should_convert;\n}\n\n#ifndef STBI_THREAD_LOCAL\n#define stbi__unpremultiply_on_load  stbi__unpremultiply_on_load_global\n#define stbi__de_iphone_flag  stbi__de_iphone_flag_global\n#else\nstatic STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set;\nstatic STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set;\n\nSTBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply)\n{\n   stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply;\n   stbi__unpremultiply_on_load_set = 1;\n}\n\nSTBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert)\n{\n   stbi__de_iphone_flag_local = flag_true_if_should_convert;\n   stbi__de_iphone_flag_set = 1;\n}\n\n#define stbi__unpremultiply_on_load  (stbi__unpremultiply_on_load_set           \\\n                                       ? stbi__unpremultiply_on_load_local      \\\n                                       : stbi__unpremultiply_on_load_global)\n#define stbi__de_iphone_flag  (stbi__de_iphone_flag_set                         \\\n                                ? stbi__de_iphone_flag_local                    \\\n                                : stbi__de_iphone_flag_global)\n#endif // STBI_THREAD_LOCAL\n\nstatic void stbi__de_iphone(stbi__png *z)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi_uc *p = z->out;\n\n   if (s->img_out_n == 3) {  // convert bgr to rgb\n      for (i=0; i < pixel_count; ++i) {\n         stbi_uc t = p[0];\n         p[0] = p[2];\n         p[2] = t;\n         p += 3;\n      }\n   } else {\n      STBI_ASSERT(s->img_out_n == 4);\n      if (stbi__unpremultiply_on_load) {\n         // convert bgr to rgb and unpremultiply\n         for (i=0; i < pixel_count; ++i) {\n            stbi_uc a = p[3];\n            stbi_uc t = p[0];\n            if (a) {\n               stbi_uc half = a / 2;\n               p[0] = (p[2] * 255 + half) / a;\n               p[1] = (p[1] * 255 + half) / a;\n               p[2] = ( t   * 255 + half) / a;\n            } else {\n               p[0] = p[2];\n               p[2] = t;\n            }\n            p += 4;\n         }\n      } else {\n         // convert bgr to rgb\n         for (i=0; i < pixel_count; ++i) {\n            stbi_uc t = p[0];\n            p[0] = p[2];\n            p[2] = t;\n            p += 4;\n         }\n      }\n   }\n}\n\n#define STBI__PNG_TYPE(a,b,c,d)  (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))\n\nstatic int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)\n{\n   stbi_uc palette[1024], pal_img_n=0;\n   stbi_uc has_trans=0, tc[3]={0};\n   stbi__uint16 tc16[3];\n   stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;\n   int first=1,k,interlace=0, color=0, is_iphone=0;\n   stbi__context *s = z->s;\n\n   z->expanded = NULL;\n   z->idata = NULL;\n   z->out = NULL;\n\n   if (!stbi__check_png_header(s)) return 0;\n\n   if (scan == STBI__SCAN_type) return 1;\n\n   for (;;) {\n      stbi__pngchunk c = stbi__get_chunk_header(s);\n      switch (c.type) {\n         case STBI__PNG_TYPE('C','g','B','I'):\n            is_iphone = 1;\n            stbi__skip(s, c.length);\n            break;\n         case STBI__PNG_TYPE('I','H','D','R'): {\n            int comp,filter;\n            if (!first) return stbi__err(\"multiple IHDR\",\"Corrupt PNG\");\n            first = 0;\n            if (c.length != 13) return stbi__err(\"bad IHDR len\",\"Corrupt PNG\");\n            s->img_x = stbi__get32be(s);\n            s->img_y = stbi__get32be(s);\n            if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n            if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n            z->depth = stbi__get8(s);  if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16)  return stbi__err(\"1/2/4/8/16-bit only\",\"PNG not supported: 1/2/4/8/16-bit only\");\n            color = stbi__get8(s);  if (color > 6)         return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n            if (color == 3 && z->depth == 16)                  return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n            if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n            comp  = stbi__get8(s);  if (comp) return stbi__err(\"bad comp method\",\"Corrupt PNG\");\n            filter= stbi__get8(s);  if (filter) return stbi__err(\"bad filter method\",\"Corrupt PNG\");\n            interlace = stbi__get8(s); if (interlace>1) return stbi__err(\"bad interlace method\",\"Corrupt PNG\");\n            if (!s->img_x || !s->img_y) return stbi__err(\"0-pixel image\",\"Corrupt PNG\");\n            if (!pal_img_n) {\n               s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);\n               if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err(\"too large\", \"Image too large to decode\");\n            } else {\n               // if paletted, then pal_n is our final components, and\n               // img_n is # components to decompress/filter.\n               s->img_n = 1;\n               if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err(\"too large\",\"Corrupt PNG\");\n            }\n            // even with SCAN_header, have to scan to see if we have a tRNS\n            break;\n         }\n\n         case STBI__PNG_TYPE('P','L','T','E'):  {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (c.length > 256*3) return stbi__err(\"invalid PLTE\",\"Corrupt PNG\");\n            pal_len = c.length / 3;\n            if (pal_len * 3 != c.length) return stbi__err(\"invalid PLTE\",\"Corrupt PNG\");\n            for (i=0; i < pal_len; ++i) {\n               palette[i*4+0] = stbi__get8(s);\n               palette[i*4+1] = stbi__get8(s);\n               palette[i*4+2] = stbi__get8(s);\n               palette[i*4+3] = 255;\n            }\n            break;\n         }\n\n         case STBI__PNG_TYPE('t','R','N','S'): {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (z->idata) return stbi__err(\"tRNS after IDAT\",\"Corrupt PNG\");\n            if (pal_img_n) {\n               if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }\n               if (pal_len == 0) return stbi__err(\"tRNS before PLTE\",\"Corrupt PNG\");\n               if (c.length > pal_len) return stbi__err(\"bad tRNS len\",\"Corrupt PNG\");\n               pal_img_n = 4;\n               for (i=0; i < c.length; ++i)\n                  palette[i*4+3] = stbi__get8(s);\n            } else {\n               if (!(s->img_n & 1)) return stbi__err(\"tRNS with alpha\",\"Corrupt PNG\");\n               if (c.length != (stbi__uint32) s->img_n*2) return stbi__err(\"bad tRNS len\",\"Corrupt PNG\");\n               has_trans = 1;\n               // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now.\n               if (scan == STBI__SCAN_header) { ++s->img_n; return 1; }\n               if (z->depth == 16) {\n                  for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is\n               } else {\n                  for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger\n               }\n            }\n            break;\n         }\n\n         case STBI__PNG_TYPE('I','D','A','T'): {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (pal_img_n && !pal_len) return stbi__err(\"no PLTE\",\"Corrupt PNG\");\n            if (scan == STBI__SCAN_header) {\n               // header scan definitely stops at first IDAT\n               if (pal_img_n)\n                  s->img_n = pal_img_n;\n               return 1;\n            }\n            if (c.length > (1u << 30)) return stbi__err(\"IDAT size limit\", \"IDAT section larger than 2^30 bytes\");\n            if ((int)(ioff + c.length) < (int)ioff) return 0;\n            if (ioff + c.length > idata_limit) {\n               stbi__uint32 idata_limit_old = idata_limit;\n               stbi_uc *p;\n               if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;\n               while (ioff + c.length > idata_limit)\n                  idata_limit *= 2;\n               STBI_NOTUSED(idata_limit_old);\n               p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n               z->idata = p;\n            }\n            if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err(\"outofdata\",\"Corrupt PNG\");\n            ioff += c.length;\n            break;\n         }\n\n         case STBI__PNG_TYPE('I','E','N','D'): {\n            stbi__uint32 raw_len, bpl;\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (scan != STBI__SCAN_load) return 1;\n            if (z->idata == NULL) return stbi__err(\"no IDAT\",\"Corrupt PNG\");\n            // initial guess for decoded data size to avoid unnecessary reallocs\n            bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component\n            raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;\n            z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);\n            if (z->expanded == NULL) return 0; // zlib should set error\n            STBI_FREE(z->idata); z->idata = NULL;\n            if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)\n               s->img_out_n = s->img_n+1;\n            else\n               s->img_out_n = s->img_n;\n            if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;\n            if (has_trans) {\n               if (z->depth == 16) {\n                  if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;\n               } else {\n                  if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;\n               }\n            }\n            if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)\n               stbi__de_iphone(z);\n            if (pal_img_n) {\n               // pal_img_n == 3 or 4\n               s->img_n = pal_img_n; // record the actual colors we had\n               s->img_out_n = pal_img_n;\n               if (req_comp >= 3) s->img_out_n = req_comp;\n               if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))\n                  return 0;\n            } else if (has_trans) {\n               // non-paletted image with tRNS -> source image has (constant) alpha\n               ++s->img_n;\n            }\n            STBI_FREE(z->expanded); z->expanded = NULL;\n            // end of PNG chunk, read and skip CRC\n            stbi__get32be(s);\n            return 1;\n         }\n\n         default:\n            // if critical, fail\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if ((c.type & (1 << 29)) == 0) {\n               #ifndef STBI_NO_FAILURE_STRINGS\n               // not threadsafe\n               static char invalid_chunk[] = \"XXXX PNG chunk not known\";\n               invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);\n               invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);\n               invalid_chunk[2] = STBI__BYTECAST(c.type >>  8);\n               invalid_chunk[3] = STBI__BYTECAST(c.type >>  0);\n               #endif\n               return stbi__err(invalid_chunk, \"PNG not supported: unknown PNG chunk type\");\n            }\n            stbi__skip(s, c.length);\n            break;\n      }\n      // end of PNG chunk, read and skip CRC\n      stbi__get32be(s);\n   }\n}\n\nstatic void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)\n{\n   void *result=NULL;\n   if (req_comp < 0 || req_comp > 4) return stbi__errpuc(\"bad req_comp\", \"Internal error\");\n   if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {\n      if (p->depth <= 8)\n         ri->bits_per_channel = 8;\n      else if (p->depth == 16)\n         ri->bits_per_channel = 16;\n      else\n         return stbi__errpuc(\"bad bits_per_channel\", \"PNG not supported: unsupported color depth\");\n      result = p->out;\n      p->out = NULL;\n      if (req_comp && req_comp != p->s->img_out_n) {\n         if (ri->bits_per_channel == 8)\n            result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);\n         else\n            result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);\n         p->s->img_out_n = req_comp;\n         if (result == NULL) return result;\n      }\n      *x = p->s->img_x;\n      *y = p->s->img_y;\n      if (n) *n = p->s->img_n;\n   }\n   STBI_FREE(p->out);      p->out      = NULL;\n   STBI_FREE(p->expanded); p->expanded = NULL;\n   STBI_FREE(p->idata);    p->idata    = NULL;\n\n   return result;\n}\n\nstatic void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi__png p;\n   p.s = s;\n   return stbi__do_png(&p, x,y,comp,req_comp, ri);\n}\n\nstatic int stbi__png_test(stbi__context *s)\n{\n   int r;\n   r = stbi__check_png_header(s);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)\n{\n   if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {\n      stbi__rewind( p->s );\n      return 0;\n   }\n   if (x) *x = p->s->img_x;\n   if (y) *y = p->s->img_y;\n   if (comp) *comp = p->s->img_n;\n   return 1;\n}\n\nstatic int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   stbi__png p;\n   p.s = s;\n   return stbi__png_info_raw(&p, x, y, comp);\n}\n\nstatic int stbi__png_is16(stbi__context *s)\n{\n   stbi__png p;\n   p.s = s;\n   if (!stbi__png_info_raw(&p, NULL, NULL, NULL))\n\t   return 0;\n   if (p.depth != 16) {\n      stbi__rewind(p.s);\n      return 0;\n   }\n   return 1;\n}\n#endif\n\n// Microsoft/Windows BMP image\n\n#ifndef STBI_NO_BMP\nstatic int stbi__bmp_test_raw(stbi__context *s)\n{\n   int r;\n   int sz;\n   if (stbi__get8(s) != 'B') return 0;\n   if (stbi__get8(s) != 'M') return 0;\n   stbi__get32le(s); // discard filesize\n   stbi__get16le(s); // discard reserved\n   stbi__get16le(s); // discard reserved\n   stbi__get32le(s); // discard data offset\n   sz = stbi__get32le(s);\n   r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124);\n   return r;\n}\n\nstatic int stbi__bmp_test(stbi__context *s)\n{\n   int r = stbi__bmp_test_raw(s);\n   stbi__rewind(s);\n   return r;\n}\n\n\n// returns 0..31 for the highest set bit\nstatic int stbi__high_bit(unsigned int z)\n{\n   int n=0;\n   if (z == 0) return -1;\n   if (z >= 0x10000) { n += 16; z >>= 16; }\n   if (z >= 0x00100) { n +=  8; z >>=  8; }\n   if (z >= 0x00010) { n +=  4; z >>=  4; }\n   if (z >= 0x00004) { n +=  2; z >>=  2; }\n   if (z >= 0x00002) { n +=  1;/* >>=  1;*/ }\n   return n;\n}\n\nstatic int stbi__bitcount(unsigned int a)\n{\n   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); // max 2\n   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); // max 4\n   a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits\n   a = (a + (a >> 8)); // max 16 per 8 bits\n   a = (a + (a >> 16)); // max 32 per 8 bits\n   return a & 0xff;\n}\n\n// extract an arbitrarily-aligned N-bit value (N=bits)\n// from v, and then make it 8-bits long and fractionally\n// extend it to full full range.\nstatic int stbi__shiftsigned(unsigned int v, int shift, int bits)\n{\n   static unsigned int mul_table[9] = {\n      0,\n      0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/,\n      0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/,\n   };\n   static unsigned int shift_table[9] = {\n      0, 0,0,1,0,2,4,6,0,\n   };\n   if (shift < 0)\n      v <<= -shift;\n   else\n      v >>= shift;\n   STBI_ASSERT(v < 256);\n   v >>= (8-bits);\n   STBI_ASSERT(bits >= 0 && bits <= 8);\n   return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits];\n}\n\ntypedef struct\n{\n   int bpp, offset, hsz;\n   unsigned int mr,mg,mb,ma, all_a;\n   int extra_read;\n} stbi__bmp_data;\n\nstatic int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress)\n{\n   // BI_BITFIELDS specifies masks explicitly, don't override\n   if (compress == 3)\n      return 1;\n\n   if (compress == 0) {\n      if (info->bpp == 16) {\n         info->mr = 31u << 10;\n         info->mg = 31u <<  5;\n         info->mb = 31u <<  0;\n      } else if (info->bpp == 32) {\n         info->mr = 0xffu << 16;\n         info->mg = 0xffu <<  8;\n         info->mb = 0xffu <<  0;\n         info->ma = 0xffu << 24;\n         info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0\n      } else {\n         // otherwise, use defaults, which is all-0\n         info->mr = info->mg = info->mb = info->ma = 0;\n      }\n      return 1;\n   }\n   return 0; // error\n}\n\nstatic void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)\n{\n   int hsz;\n   if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc(\"not BMP\", \"Corrupt BMP\");\n   stbi__get32le(s); // discard filesize\n   stbi__get16le(s); // discard reserved\n   stbi__get16le(s); // discard reserved\n   info->offset = stbi__get32le(s);\n   info->hsz = hsz = stbi__get32le(s);\n   info->mr = info->mg = info->mb = info->ma = 0;\n   info->extra_read = 14;\n\n   if (info->offset < 0) return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n\n   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc(\"unknown BMP\", \"BMP type not supported: unknown\");\n   if (hsz == 12) {\n      s->img_x = stbi__get16le(s);\n      s->img_y = stbi__get16le(s);\n   } else {\n      s->img_x = stbi__get32le(s);\n      s->img_y = stbi__get32le(s);\n   }\n   if (stbi__get16le(s) != 1) return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n   info->bpp = stbi__get16le(s);\n   if (hsz != 12) {\n      int compress = stbi__get32le(s);\n      if (compress == 1 || compress == 2) return stbi__errpuc(\"BMP RLE\", \"BMP type not supported: RLE\");\n      if (compress >= 4) return stbi__errpuc(\"BMP JPEG/PNG\", \"BMP type not supported: unsupported compression\"); // this includes PNG/JPEG modes\n      if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc(\"bad BMP\", \"bad BMP\"); // bitfields requires 16 or 32 bits/pixel\n      stbi__get32le(s); // discard sizeof\n      stbi__get32le(s); // discard hres\n      stbi__get32le(s); // discard vres\n      stbi__get32le(s); // discard colorsused\n      stbi__get32le(s); // discard max important\n      if (hsz == 40 || hsz == 56) {\n         if (hsz == 56) {\n            stbi__get32le(s);\n            stbi__get32le(s);\n            stbi__get32le(s);\n            stbi__get32le(s);\n         }\n         if (info->bpp == 16 || info->bpp == 32) {\n            if (compress == 0) {\n               stbi__bmp_set_mask_defaults(info, compress);\n            } else if (compress == 3) {\n               info->mr = stbi__get32le(s);\n               info->mg = stbi__get32le(s);\n               info->mb = stbi__get32le(s);\n               info->extra_read += 12;\n               // not documented, but generated by photoshop and handled by mspaint\n               if (info->mr == info->mg && info->mg == info->mb) {\n                  // ?!?!?\n                  return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n               }\n            } else\n               return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n         }\n      } else {\n         // V4/V5 header\n         int i;\n         if (hsz != 108 && hsz != 124)\n            return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n         info->mr = stbi__get32le(s);\n         info->mg = stbi__get32le(s);\n         info->mb = stbi__get32le(s);\n         info->ma = stbi__get32le(s);\n         if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs\n            stbi__bmp_set_mask_defaults(info, compress);\n         stbi__get32le(s); // discard color space\n         for (i=0; i < 12; ++i)\n            stbi__get32le(s); // discard color space parameters\n         if (hsz == 124) {\n            stbi__get32le(s); // discard rendering intent\n            stbi__get32le(s); // discard offset of profile data\n            stbi__get32le(s); // discard size of profile data\n            stbi__get32le(s); // discard reserved\n         }\n      }\n   }\n   return (void *) 1;\n}\n\n\nstatic void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *out;\n   unsigned int mr=0,mg=0,mb=0,ma=0, all_a;\n   stbi_uc pal[256][4];\n   int psize=0,i,j,width;\n   int flip_vertically, pad, target;\n   stbi__bmp_data info;\n   STBI_NOTUSED(ri);\n\n   info.all_a = 255;\n   if (stbi__bmp_parse_header(s, &info) == NULL)\n      return NULL; // error code already set\n\n   flip_vertically = ((int) s->img_y) > 0;\n   s->img_y = abs((int) s->img_y);\n\n   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   mr = info.mr;\n   mg = info.mg;\n   mb = info.mb;\n   ma = info.ma;\n   all_a = info.all_a;\n\n   if (info.hsz == 12) {\n      if (info.bpp < 24)\n         psize = (info.offset - info.extra_read - 24) / 3;\n   } else {\n      if (info.bpp < 16)\n         psize = (info.offset - info.extra_read - info.hsz) >> 2;\n   }\n   if (psize == 0) {\n      // accept some number of extra bytes after the header, but if the offset points either to before\n      // the header ends or implies a large amount of extra data, reject the file as malformed\n      int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original);\n      int header_limit = 1024; // max we actually read is below 256 bytes currently.\n      int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size.\n      if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) {\n         return stbi__errpuc(\"bad header\", \"Corrupt BMP\");\n      }\n      // we established that bytes_read_so_far is positive and sensible.\n      // the first half of this test rejects offsets that are either too small positives, or\n      // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn\n      // ensures the number computed in the second half of the test can't overflow.\n      if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) {\n         return stbi__errpuc(\"bad offset\", \"Corrupt BMP\");\n      } else {\n         stbi__skip(s, info.offset - bytes_read_so_far);\n      }\n   }\n\n   if (info.bpp == 24 && ma == 0xff000000)\n      s->img_n = 3;\n   else\n      s->img_n = ma ? 4 : 3;\n   if (req_comp && req_comp >= 3) // we can directly decode 3 or 4\n      target = req_comp;\n   else\n      target = s->img_n; // if they want monochrome, we'll post-convert\n\n   // sanity-check size\n   if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0))\n      return stbi__errpuc(\"too large\", \"Corrupt BMP\");\n\n   out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0);\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   if (info.bpp < 16) {\n      int z=0;\n      if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc(\"invalid\", \"Corrupt BMP\"); }\n      for (i=0; i < psize; ++i) {\n         pal[i][2] = stbi__get8(s);\n         pal[i][1] = stbi__get8(s);\n         pal[i][0] = stbi__get8(s);\n         if (info.hsz != 12) stbi__get8(s);\n         pal[i][3] = 255;\n      }\n      stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4));\n      if (info.bpp == 1) width = (s->img_x + 7) >> 3;\n      else if (info.bpp == 4) width = (s->img_x + 1) >> 1;\n      else if (info.bpp == 8) width = s->img_x;\n      else { STBI_FREE(out); return stbi__errpuc(\"bad bpp\", \"Corrupt BMP\"); }\n      pad = (-width)&3;\n      if (info.bpp == 1) {\n         for (j=0; j < (int) s->img_y; ++j) {\n            int bit_offset = 7, v = stbi__get8(s);\n            for (i=0; i < (int) s->img_x; ++i) {\n               int color = (v>>bit_offset)&0x1;\n               out[z++] = pal[color][0];\n               out[z++] = pal[color][1];\n               out[z++] = pal[color][2];\n               if (target == 4) out[z++] = 255;\n               if (i+1 == (int) s->img_x) break;\n               if((--bit_offset) < 0) {\n                  bit_offset = 7;\n                  v = stbi__get8(s);\n               }\n            }\n            stbi__skip(s, pad);\n         }\n      } else {\n         for (j=0; j < (int) s->img_y; ++j) {\n            for (i=0; i < (int) s->img_x; i += 2) {\n               int v=stbi__get8(s),v2=0;\n               if (info.bpp == 4) {\n                  v2 = v & 15;\n                  v >>= 4;\n               }\n               out[z++] = pal[v][0];\n               out[z++] = pal[v][1];\n               out[z++] = pal[v][2];\n               if (target == 4) out[z++] = 255;\n               if (i+1 == (int) s->img_x) break;\n               v = (info.bpp == 8) ? stbi__get8(s) : v2;\n               out[z++] = pal[v][0];\n               out[z++] = pal[v][1];\n               out[z++] = pal[v][2];\n               if (target == 4) out[z++] = 255;\n            }\n            stbi__skip(s, pad);\n         }\n      }\n   } else {\n      int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;\n      int z = 0;\n      int easy=0;\n      stbi__skip(s, info.offset - info.extra_read - info.hsz);\n      if (info.bpp == 24) width = 3 * s->img_x;\n      else if (info.bpp == 16) width = 2*s->img_x;\n      else /* bpp = 32 and pad = 0 */ width=0;\n      pad = (-width) & 3;\n      if (info.bpp == 24) {\n         easy = 1;\n      } else if (info.bpp == 32) {\n         if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)\n            easy = 2;\n      }\n      if (!easy) {\n         if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc(\"bad masks\", \"Corrupt BMP\"); }\n         // right shift amt to put high bit in position #7\n         rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr);\n         gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);\n         bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);\n         ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);\n         if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc(\"bad masks\", \"Corrupt BMP\"); }\n      }\n      for (j=0; j < (int) s->img_y; ++j) {\n         if (easy) {\n            for (i=0; i < (int) s->img_x; ++i) {\n               unsigned char a;\n               out[z+2] = stbi__get8(s);\n               out[z+1] = stbi__get8(s);\n               out[z+0] = stbi__get8(s);\n               z += 3;\n               a = (easy == 2 ? stbi__get8(s) : 255);\n               all_a |= a;\n               if (target == 4) out[z++] = a;\n            }\n         } else {\n            int bpp = info.bpp;\n            for (i=0; i < (int) s->img_x; ++i) {\n               stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));\n               unsigned int a;\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));\n               a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255);\n               all_a |= a;\n               if (target == 4) out[z++] = STBI__BYTECAST(a);\n            }\n         }\n         stbi__skip(s, pad);\n      }\n   }\n\n   // if alpha channel is all 0s, replace with all 255s\n   if (target == 4 && all_a == 0)\n      for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4)\n         out[i] = 255;\n\n   if (flip_vertically) {\n      stbi_uc t;\n      for (j=0; j < (int) s->img_y>>1; ++j) {\n         stbi_uc *p1 = out +      j     *s->img_x*target;\n         stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;\n         for (i=0; i < (int) s->img_x*target; ++i) {\n            t = p1[i]; p1[i] = p2[i]; p2[i] = t;\n         }\n      }\n   }\n\n   if (req_comp && req_comp != target) {\n      out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y);\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n\n   *x = s->img_x;\n   *y = s->img_y;\n   if (comp) *comp = s->img_n;\n   return out;\n}\n#endif\n\n// Targa Truevision - TGA\n// by Jonathan Dummer\n#ifndef STBI_NO_TGA\n// returns STBI_rgb or whatever, 0 on error\nstatic int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)\n{\n   // only RGB or RGBA (incl. 16bit) or grey allowed\n   if (is_rgb16) *is_rgb16 = 0;\n   switch(bits_per_pixel) {\n      case 8:  return STBI_grey;\n      case 16: if(is_grey) return STBI_grey_alpha;\n               // fallthrough\n      case 15: if(is_rgb16) *is_rgb16 = 1;\n               return STBI_rgb;\n      case 24: // fallthrough\n      case 32: return bits_per_pixel/8;\n      default: return 0;\n   }\n}\n\nstatic int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)\n{\n    int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;\n    int sz, tga_colormap_type;\n    stbi__get8(s);                   // discard Offset\n    tga_colormap_type = stbi__get8(s); // colormap type\n    if( tga_colormap_type > 1 ) {\n        stbi__rewind(s);\n        return 0;      // only RGB or indexed allowed\n    }\n    tga_image_type = stbi__get8(s); // image type\n    if ( tga_colormap_type == 1 ) { // colormapped (paletted) image\n        if (tga_image_type != 1 && tga_image_type != 9) {\n            stbi__rewind(s);\n            return 0;\n        }\n        stbi__skip(s,4);       // skip index of first colormap entry and number of entries\n        sz = stbi__get8(s);    //   check bits per palette color entry\n        if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) {\n            stbi__rewind(s);\n            return 0;\n        }\n        stbi__skip(s,4);       // skip image x and y origin\n        tga_colormap_bpp = sz;\n    } else { // \"normal\" image w/o colormap - only RGB or grey allowed, +/- RLE\n        if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) {\n            stbi__rewind(s);\n            return 0; // only RGB or grey allowed, +/- RLE\n        }\n        stbi__skip(s,9); // skip colormap specification and image x/y origin\n        tga_colormap_bpp = 0;\n    }\n    tga_w = stbi__get16le(s);\n    if( tga_w < 1 ) {\n        stbi__rewind(s);\n        return 0;   // test width\n    }\n    tga_h = stbi__get16le(s);\n    if( tga_h < 1 ) {\n        stbi__rewind(s);\n        return 0;   // test height\n    }\n    tga_bits_per_pixel = stbi__get8(s); // bits per pixel\n    stbi__get8(s); // ignore alpha bits\n    if (tga_colormap_bpp != 0) {\n        if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {\n            // when using a colormap, tga_bits_per_pixel is the size of the indexes\n            // I don't think anything but 8 or 16bit indexes makes sense\n            stbi__rewind(s);\n            return 0;\n        }\n        tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);\n    } else {\n        tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL);\n    }\n    if(!tga_comp) {\n      stbi__rewind(s);\n      return 0;\n    }\n    if (x) *x = tga_w;\n    if (y) *y = tga_h;\n    if (comp) *comp = tga_comp;\n    return 1;                   // seems to have passed everything\n}\n\nstatic int stbi__tga_test(stbi__context *s)\n{\n   int res = 0;\n   int sz, tga_color_type;\n   stbi__get8(s);      //   discard Offset\n   tga_color_type = stbi__get8(s);   //   color type\n   if ( tga_color_type > 1 ) goto errorEnd;   //   only RGB or indexed allowed\n   sz = stbi__get8(s);   //   image type\n   if ( tga_color_type == 1 ) { // colormapped (paletted) image\n      if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9\n      stbi__skip(s,4);       // skip index of first colormap entry and number of entries\n      sz = stbi__get8(s);    //   check bits per palette color entry\n      if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;\n      stbi__skip(s,4);       // skip image x and y origin\n   } else { // \"normal\" image w/o colormap\n      if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE\n      stbi__skip(s,9); // skip colormap specification and image x/y origin\n   }\n   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test width\n   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test height\n   sz = stbi__get8(s);   //   bits per pixel\n   if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index\n   if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;\n\n   res = 1; // if we got this far, everything's good and we can return 1 instead of 0\n\nerrorEnd:\n   stbi__rewind(s);\n   return res;\n}\n\n// read 16bit value and convert to 24bit RGB\nstatic void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)\n{\n   stbi__uint16 px = (stbi__uint16)stbi__get16le(s);\n   stbi__uint16 fiveBitMask = 31;\n   // we have 3 channels with 5bits each\n   int r = (px >> 10) & fiveBitMask;\n   int g = (px >> 5) & fiveBitMask;\n   int b = px & fiveBitMask;\n   // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later\n   out[0] = (stbi_uc)((r * 255)/31);\n   out[1] = (stbi_uc)((g * 255)/31);\n   out[2] = (stbi_uc)((b * 255)/31);\n\n   // some people claim that the most significant bit might be used for alpha\n   // (possibly if an alpha-bit is set in the \"image descriptor byte\")\n   // but that only made 16bit test images completely translucent..\n   // so let's treat all 15 and 16bit TGAs as RGB with no alpha.\n}\n\nstatic void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   //   read in the TGA header stuff\n   int tga_offset = stbi__get8(s);\n   int tga_indexed = stbi__get8(s);\n   int tga_image_type = stbi__get8(s);\n   int tga_is_RLE = 0;\n   int tga_palette_start = stbi__get16le(s);\n   int tga_palette_len = stbi__get16le(s);\n   int tga_palette_bits = stbi__get8(s);\n   int tga_x_origin = stbi__get16le(s);\n   int tga_y_origin = stbi__get16le(s);\n   int tga_width = stbi__get16le(s);\n   int tga_height = stbi__get16le(s);\n   int tga_bits_per_pixel = stbi__get8(s);\n   int tga_comp, tga_rgb16=0;\n   int tga_inverted = stbi__get8(s);\n   // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)\n   //   image data\n   unsigned char *tga_data;\n   unsigned char *tga_palette = NULL;\n   int i, j;\n   unsigned char raw_data[4] = {0};\n   int RLE_count = 0;\n   int RLE_repeating = 0;\n   int read_next_pixel = 1;\n   STBI_NOTUSED(ri);\n   STBI_NOTUSED(tga_x_origin); // @TODO\n   STBI_NOTUSED(tga_y_origin); // @TODO\n\n   if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   //   do a tiny bit of precessing\n   if ( tga_image_type >= 8 )\n   {\n      tga_image_type -= 8;\n      tga_is_RLE = 1;\n   }\n   tga_inverted = 1 - ((tga_inverted >> 5) & 1);\n\n   //   If I'm paletted, then I'll use the number of bits from the palette\n   if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);\n   else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);\n\n   if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency\n      return stbi__errpuc(\"bad format\", \"Can't find out TGA pixelformat\");\n\n   //   tga info\n   *x = tga_width;\n   *y = tga_height;\n   if (comp) *comp = tga_comp;\n\n   if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0))\n      return stbi__errpuc(\"too large\", \"Corrupt TGA\");\n\n   tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0);\n   if (!tga_data) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   // skip to the data's starting position (offset usually = 0)\n   stbi__skip(s, tga_offset );\n\n   if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) {\n      for (i=0; i < tga_height; ++i) {\n         int row = tga_inverted ? tga_height -i - 1 : i;\n         stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;\n         stbi__getn(s, tga_row, tga_width * tga_comp);\n      }\n   } else  {\n      //   do I need to load a palette?\n      if ( tga_indexed)\n      {\n         if (tga_palette_len == 0) {  /* you have to have at least one entry! */\n            STBI_FREE(tga_data);\n            return stbi__errpuc(\"bad palette\", \"Corrupt TGA\");\n         }\n\n         //   any data to skip? (offset usually = 0)\n         stbi__skip(s, tga_palette_start );\n         //   load the palette\n         tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0);\n         if (!tga_palette) {\n            STBI_FREE(tga_data);\n            return stbi__errpuc(\"outofmem\", \"Out of memory\");\n         }\n         if (tga_rgb16) {\n            stbi_uc *pal_entry = tga_palette;\n            STBI_ASSERT(tga_comp == STBI_rgb);\n            for (i=0; i < tga_palette_len; ++i) {\n               stbi__tga_read_rgb16(s, pal_entry);\n               pal_entry += tga_comp;\n            }\n         } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) {\n               STBI_FREE(tga_data);\n               STBI_FREE(tga_palette);\n               return stbi__errpuc(\"bad palette\", \"Corrupt TGA\");\n         }\n      }\n      //   load the data\n      for (i=0; i < tga_width * tga_height; ++i)\n      {\n         //   if I'm in RLE mode, do I need to get a RLE stbi__pngchunk?\n         if ( tga_is_RLE )\n         {\n            if ( RLE_count == 0 )\n            {\n               //   yep, get the next byte as a RLE command\n               int RLE_cmd = stbi__get8(s);\n               RLE_count = 1 + (RLE_cmd & 127);\n               RLE_repeating = RLE_cmd >> 7;\n               read_next_pixel = 1;\n            } else if ( !RLE_repeating )\n            {\n               read_next_pixel = 1;\n            }\n         } else\n         {\n            read_next_pixel = 1;\n         }\n         //   OK, if I need to read a pixel, do it now\n         if ( read_next_pixel )\n         {\n            //   load however much data we did have\n            if ( tga_indexed )\n            {\n               // read in index, then perform the lookup\n               int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);\n               if ( pal_idx >= tga_palette_len ) {\n                  // invalid index\n                  pal_idx = 0;\n               }\n               pal_idx *= tga_comp;\n               for (j = 0; j < tga_comp; ++j) {\n                  raw_data[j] = tga_palette[pal_idx+j];\n               }\n            } else if(tga_rgb16) {\n               STBI_ASSERT(tga_comp == STBI_rgb);\n               stbi__tga_read_rgb16(s, raw_data);\n            } else {\n               //   read in the data raw\n               for (j = 0; j < tga_comp; ++j) {\n                  raw_data[j] = stbi__get8(s);\n               }\n            }\n            //   clear the reading flag for the next pixel\n            read_next_pixel = 0;\n         } // end of reading a pixel\n\n         // copy data\n         for (j = 0; j < tga_comp; ++j)\n           tga_data[i*tga_comp+j] = raw_data[j];\n\n         //   in case we're in RLE mode, keep counting down\n         --RLE_count;\n      }\n      //   do I need to invert the image?\n      if ( tga_inverted )\n      {\n         for (j = 0; j*2 < tga_height; ++j)\n         {\n            int index1 = j * tga_width * tga_comp;\n            int index2 = (tga_height - 1 - j) * tga_width * tga_comp;\n            for (i = tga_width * tga_comp; i > 0; --i)\n            {\n               unsigned char temp = tga_data[index1];\n               tga_data[index1] = tga_data[index2];\n               tga_data[index2] = temp;\n               ++index1;\n               ++index2;\n            }\n         }\n      }\n      //   clear my palette, if I had one\n      if ( tga_palette != NULL )\n      {\n         STBI_FREE( tga_palette );\n      }\n   }\n\n   // swap RGB - if the source data was RGB16, it already is in the right order\n   if (tga_comp >= 3 && !tga_rgb16)\n   {\n      unsigned char* tga_pixel = tga_data;\n      for (i=0; i < tga_width * tga_height; ++i)\n      {\n         unsigned char temp = tga_pixel[0];\n         tga_pixel[0] = tga_pixel[2];\n         tga_pixel[2] = temp;\n         tga_pixel += tga_comp;\n      }\n   }\n\n   // convert to target component count\n   if (req_comp && req_comp != tga_comp)\n      tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);\n\n   //   the things I do to get rid of an error message, and yet keep\n   //   Microsoft's C compilers happy... [8^(\n   tga_palette_start = tga_palette_len = tga_palette_bits =\n         tga_x_origin = tga_y_origin = 0;\n   STBI_NOTUSED(tga_palette_start);\n   //   OK, done\n   return tga_data;\n}\n#endif\n\n// *************************************************************************************************\n// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB\n\n#ifndef STBI_NO_PSD\nstatic int stbi__psd_test(stbi__context *s)\n{\n   int r = (stbi__get32be(s) == 0x38425053);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount)\n{\n   int count, nleft, len;\n\n   count = 0;\n   while ((nleft = pixelCount - count) > 0) {\n      len = stbi__get8(s);\n      if (len == 128) {\n         // No-op.\n      } else if (len < 128) {\n         // Copy next len+1 bytes literally.\n         len++;\n         if (len > nleft) return 0; // corrupt data\n         count += len;\n         while (len) {\n            *p = stbi__get8(s);\n            p += 4;\n            len--;\n         }\n      } else if (len > 128) {\n         stbi_uc   val;\n         // Next -len+1 bytes in the dest are replicated from next source byte.\n         // (Interpret len as a negative 8-bit int.)\n         len = 257 - len;\n         if (len > nleft) return 0; // corrupt data\n         val = stbi__get8(s);\n         count += len;\n         while (len) {\n            *p = val;\n            p += 4;\n            len--;\n         }\n      }\n   }\n\n   return 1;\n}\n\nstatic void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)\n{\n   int pixelCount;\n   int channelCount, compression;\n   int channel, i;\n   int bitdepth;\n   int w,h;\n   stbi_uc *out;\n   STBI_NOTUSED(ri);\n\n   // Check identifier\n   if (stbi__get32be(s) != 0x38425053)   // \"8BPS\"\n      return stbi__errpuc(\"not PSD\", \"Corrupt PSD image\");\n\n   // Check file type version.\n   if (stbi__get16be(s) != 1)\n      return stbi__errpuc(\"wrong version\", \"Unsupported version of PSD image\");\n\n   // Skip 6 reserved bytes.\n   stbi__skip(s, 6 );\n\n   // Read the number of channels (R, G, B, A, etc).\n   channelCount = stbi__get16be(s);\n   if (channelCount < 0 || channelCount > 16)\n      return stbi__errpuc(\"wrong channel count\", \"Unsupported number of channels in PSD image\");\n\n   // Read the rows and columns of the image.\n   h = stbi__get32be(s);\n   w = stbi__get32be(s);\n\n   if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   // Make sure the depth is 8 bits.\n   bitdepth = stbi__get16be(s);\n   if (bitdepth != 8 && bitdepth != 16)\n      return stbi__errpuc(\"unsupported bit depth\", \"PSD bit depth is not 8 or 16 bit\");\n\n   // Make sure the color mode is RGB.\n   // Valid options are:\n   //   0: Bitmap\n   //   1: Grayscale\n   //   2: Indexed color\n   //   3: RGB color\n   //   4: CMYK color\n   //   7: Multichannel\n   //   8: Duotone\n   //   9: Lab color\n   if (stbi__get16be(s) != 3)\n      return stbi__errpuc(\"wrong color format\", \"PSD is not in RGB color format\");\n\n   // Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)\n   stbi__skip(s,stbi__get32be(s) );\n\n   // Skip the image resources.  (resolution, pen tool paths, etc)\n   stbi__skip(s, stbi__get32be(s) );\n\n   // Skip the reserved data.\n   stbi__skip(s, stbi__get32be(s) );\n\n   // Find out if the data is compressed.\n   // Known values:\n   //   0: no compression\n   //   1: RLE compressed\n   compression = stbi__get16be(s);\n   if (compression > 1)\n      return stbi__errpuc(\"bad compression\", \"PSD has an unknown compression format\");\n\n   // Check size\n   if (!stbi__mad3sizes_valid(4, w, h, 0))\n      return stbi__errpuc(\"too large\", \"Corrupt PSD\");\n\n   // Create the destination image.\n\n   if (!compression && bitdepth == 16 && bpc == 16) {\n      out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0);\n      ri->bits_per_channel = 16;\n   } else\n      out = (stbi_uc *) stbi__malloc(4 * w*h);\n\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   pixelCount = w*h;\n\n   // Initialize the data to zero.\n   //memset( out, 0, pixelCount * 4 );\n\n   // Finally, the image data.\n   if (compression) {\n      // RLE as used by .PSD and .TIFF\n      // Loop until you get the number of unpacked bytes you are expecting:\n      //     Read the next source byte into n.\n      //     If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.\n      //     Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.\n      //     Else if n is 128, noop.\n      // Endloop\n\n      // The RLE-compressed data is preceded by a 2-byte data count for each row in the data,\n      // which we're going to just skip.\n      stbi__skip(s, h * channelCount * 2 );\n\n      // Read the RLE data by channel.\n      for (channel = 0; channel < 4; channel++) {\n         stbi_uc *p;\n\n         p = out+channel;\n         if (channel >= channelCount) {\n            // Fill this channel with default data.\n            for (i = 0; i < pixelCount; i++, p += 4)\n               *p = (channel == 3 ? 255 : 0);\n         } else {\n            // Read the RLE data.\n            if (!stbi__psd_decode_rle(s, p, pixelCount)) {\n               STBI_FREE(out);\n               return stbi__errpuc(\"corrupt\", \"bad RLE data\");\n            }\n         }\n      }\n\n   } else {\n      // We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)\n      // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image.\n\n      // Read the data by channel.\n      for (channel = 0; channel < 4; channel++) {\n         if (channel >= channelCount) {\n            // Fill this channel with default data.\n            if (bitdepth == 16 && bpc == 16) {\n               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;\n               stbi__uint16 val = channel == 3 ? 65535 : 0;\n               for (i = 0; i < pixelCount; i++, q += 4)\n                  *q = val;\n            } else {\n               stbi_uc *p = out+channel;\n               stbi_uc val = channel == 3 ? 255 : 0;\n               for (i = 0; i < pixelCount; i++, p += 4)\n                  *p = val;\n            }\n         } else {\n            if (ri->bits_per_channel == 16) {    // output bpc\n               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;\n               for (i = 0; i < pixelCount; i++, q += 4)\n                  *q = (stbi__uint16) stbi__get16be(s);\n            } else {\n               stbi_uc *p = out+channel;\n               if (bitdepth == 16) {  // input bpc\n                  for (i = 0; i < pixelCount; i++, p += 4)\n                     *p = (stbi_uc) (stbi__get16be(s) >> 8);\n               } else {\n                  for (i = 0; i < pixelCount; i++, p += 4)\n                     *p = stbi__get8(s);\n               }\n            }\n         }\n      }\n   }\n\n   // remove weird white matte from PSD\n   if (channelCount >= 4) {\n      if (ri->bits_per_channel == 16) {\n         for (i=0; i < w*h; ++i) {\n            stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i;\n            if (pixel[3] != 0 && pixel[3] != 65535) {\n               float a = pixel[3] / 65535.0f;\n               float ra = 1.0f / a;\n               float inv_a = 65535.0f * (1 - ra);\n               pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a);\n               pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a);\n               pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a);\n            }\n         }\n      } else {\n         for (i=0; i < w*h; ++i) {\n            unsigned char *pixel = out + 4*i;\n            if (pixel[3] != 0 && pixel[3] != 255) {\n               float a = pixel[3] / 255.0f;\n               float ra = 1.0f / a;\n               float inv_a = 255.0f * (1 - ra);\n               pixel[0] = (unsigned char) (pixel[0]*ra + inv_a);\n               pixel[1] = (unsigned char) (pixel[1]*ra + inv_a);\n               pixel[2] = (unsigned char) (pixel[2]*ra + inv_a);\n            }\n         }\n      }\n   }\n\n   // convert to desired output format\n   if (req_comp && req_comp != 4) {\n      if (ri->bits_per_channel == 16)\n         out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h);\n      else\n         out = stbi__convert_format(out, 4, req_comp, w, h);\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n\n   if (comp) *comp = 4;\n   *y = h;\n   *x = w;\n\n   return out;\n}\n#endif\n\n// *************************************************************************************************\n// Softimage PIC loader\n// by Tom Seddon\n//\n// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format\n// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/\n\n#ifndef STBI_NO_PIC\nstatic int stbi__pic_is4(stbi__context *s,const char *str)\n{\n   int i;\n   for (i=0; i<4; ++i)\n      if (stbi__get8(s) != (stbi_uc)str[i])\n         return 0;\n\n   return 1;\n}\n\nstatic int stbi__pic_test_core(stbi__context *s)\n{\n   int i;\n\n   if (!stbi__pic_is4(s,\"\\x53\\x80\\xF6\\x34\"))\n      return 0;\n\n   for(i=0;i<84;++i)\n      stbi__get8(s);\n\n   if (!stbi__pic_is4(s,\"PICT\"))\n      return 0;\n\n   return 1;\n}\n\ntypedef struct\n{\n   stbi_uc size,type,channel;\n} stbi__pic_packet;\n\nstatic stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)\n{\n   int mask=0x80, i;\n\n   for (i=0; i<4; ++i, mask>>=1) {\n      if (channel & mask) {\n         if (stbi__at_eof(s)) return stbi__errpuc(\"bad file\",\"PIC file too short\");\n         dest[i]=stbi__get8(s);\n      }\n   }\n\n   return dest;\n}\n\nstatic void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)\n{\n   int mask=0x80,i;\n\n   for (i=0;i<4; ++i, mask>>=1)\n      if (channel&mask)\n         dest[i]=src[i];\n}\n\nstatic stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result)\n{\n   int act_comp=0,num_packets=0,y,chained;\n   stbi__pic_packet packets[10];\n\n   // this will (should...) cater for even some bizarre stuff like having data\n    // for the same channel in multiple packets.\n   do {\n      stbi__pic_packet *packet;\n\n      if (num_packets==sizeof(packets)/sizeof(packets[0]))\n         return stbi__errpuc(\"bad format\",\"too many packets\");\n\n      packet = &packets[num_packets++];\n\n      chained = stbi__get8(s);\n      packet->size    = stbi__get8(s);\n      packet->type    = stbi__get8(s);\n      packet->channel = stbi__get8(s);\n\n      act_comp |= packet->channel;\n\n      if (stbi__at_eof(s))          return stbi__errpuc(\"bad file\",\"file too short (reading packets)\");\n      if (packet->size != 8)  return stbi__errpuc(\"bad format\",\"packet isn't 8bpp\");\n   } while (chained);\n\n   *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?\n\n   for(y=0; y<height; ++y) {\n      int packet_idx;\n\n      for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {\n         stbi__pic_packet *packet = &packets[packet_idx];\n         stbi_uc *dest = result+y*width*4;\n\n         switch (packet->type) {\n            default:\n               return stbi__errpuc(\"bad format\",\"packet has bad compression type\");\n\n            case 0: {//uncompressed\n               int x;\n\n               for(x=0;x<width;++x, dest+=4)\n                  if (!stbi__readval(s,packet->channel,dest))\n                     return 0;\n               break;\n            }\n\n            case 1://Pure RLE\n               {\n                  int left=width, i;\n\n                  while (left>0) {\n                     stbi_uc count,value[4];\n\n                     count=stbi__get8(s);\n                     if (stbi__at_eof(s))   return stbi__errpuc(\"bad file\",\"file too short (pure read count)\");\n\n                     if (count > left)\n                        count = (stbi_uc) left;\n\n                     if (!stbi__readval(s,packet->channel,value))  return 0;\n\n                     for(i=0; i<count; ++i,dest+=4)\n                        stbi__copyval(packet->channel,dest,value);\n                     left -= count;\n                  }\n               }\n               break;\n\n            case 2: {//Mixed RLE\n               int left=width;\n               while (left>0) {\n                  int count = stbi__get8(s), i;\n                  if (stbi__at_eof(s))  return stbi__errpuc(\"bad file\",\"file too short (mixed read count)\");\n\n                  if (count >= 128) { // Repeated\n                     stbi_uc value[4];\n\n                     if (count==128)\n                        count = stbi__get16be(s);\n                     else\n                        count -= 127;\n                     if (count > left)\n                        return stbi__errpuc(\"bad file\",\"scanline overrun\");\n\n                     if (!stbi__readval(s,packet->channel,value))\n                        return 0;\n\n                     for(i=0;i<count;++i, dest += 4)\n                        stbi__copyval(packet->channel,dest,value);\n                  } else { // Raw\n                     ++count;\n                     if (count>left) return stbi__errpuc(\"bad file\",\"scanline overrun\");\n\n                     for(i=0;i<count;++i, dest+=4)\n                        if (!stbi__readval(s,packet->channel,dest))\n                           return 0;\n                  }\n                  left-=count;\n               }\n               break;\n            }\n         }\n      }\n   }\n\n   return result;\n}\n\nstatic void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *result;\n   int i, x,y, internal_comp;\n   STBI_NOTUSED(ri);\n\n   if (!comp) comp = &internal_comp;\n\n   for (i=0; i<92; ++i)\n      stbi__get8(s);\n\n   x = stbi__get16be(s);\n   y = stbi__get16be(s);\n\n   if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   if (stbi__at_eof(s))  return stbi__errpuc(\"bad file\",\"file too short (pic header)\");\n   if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc(\"too large\", \"PIC image too large to decode\");\n\n   stbi__get32be(s); //skip `ratio'\n   stbi__get16be(s); //skip `fields'\n   stbi__get16be(s); //skip `pad'\n\n   // intermediate buffer is RGBA\n   result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);\n   if (!result) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   memset(result, 0xff, x*y*4);\n\n   if (!stbi__pic_load_core(s,x,y,comp, result)) {\n      STBI_FREE(result);\n      result=0;\n   }\n   *px = x;\n   *py = y;\n   if (req_comp == 0) req_comp = *comp;\n   result=stbi__convert_format(result,4,req_comp,x,y);\n\n   return result;\n}\n\nstatic int stbi__pic_test(stbi__context *s)\n{\n   int r = stbi__pic_test_core(s);\n   stbi__rewind(s);\n   return r;\n}\n#endif\n\n// *************************************************************************************************\n// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb\n\n#ifndef STBI_NO_GIF\ntypedef struct\n{\n   stbi__int16 prefix;\n   stbi_uc first;\n   stbi_uc suffix;\n} stbi__gif_lzw;\n\ntypedef struct\n{\n   int w,h;\n   stbi_uc *out;                 // output buffer (always 4 components)\n   stbi_uc *background;          // The current \"background\" as far as a gif is concerned\n   stbi_uc *history;\n   int flags, bgindex, ratio, transparent, eflags;\n   stbi_uc  pal[256][4];\n   stbi_uc lpal[256][4];\n   stbi__gif_lzw codes[8192];\n   stbi_uc *color_table;\n   int parse, step;\n   int lflags;\n   int start_x, start_y;\n   int max_x, max_y;\n   int cur_x, cur_y;\n   int line_size;\n   int delay;\n} stbi__gif;\n\nstatic int stbi__gif_test_raw(stbi__context *s)\n{\n   int sz;\n   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0;\n   sz = stbi__get8(s);\n   if (sz != '9' && sz != '7') return 0;\n   if (stbi__get8(s) != 'a') return 0;\n   return 1;\n}\n\nstatic int stbi__gif_test(stbi__context *s)\n{\n   int r = stbi__gif_test_raw(s);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp)\n{\n   int i;\n   for (i=0; i < num_entries; ++i) {\n      pal[i][2] = stbi__get8(s);\n      pal[i][1] = stbi__get8(s);\n      pal[i][0] = stbi__get8(s);\n      pal[i][3] = transp == i ? 0 : 255;\n   }\n}\n\nstatic int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info)\n{\n   stbi_uc version;\n   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8')\n      return stbi__err(\"not GIF\", \"Corrupt GIF\");\n\n   version = stbi__get8(s);\n   if (version != '7' && version != '9')    return stbi__err(\"not GIF\", \"Corrupt GIF\");\n   if (stbi__get8(s) != 'a')                return stbi__err(\"not GIF\", \"Corrupt GIF\");\n\n   stbi__g_failure_reason = \"\";\n   g->w = stbi__get16le(s);\n   g->h = stbi__get16le(s);\n   g->flags = stbi__get8(s);\n   g->bgindex = stbi__get8(s);\n   g->ratio = stbi__get8(s);\n   g->transparent = -1;\n\n   if (g->w > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n   if (g->h > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n\n   if (comp != 0) *comp = 4;  // can't actually tell whether it's 3 or 4 until we parse the comments\n\n   if (is_info) return 1;\n\n   if (g->flags & 0x80)\n      stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);\n\n   return 1;\n}\n\nstatic int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)\n{\n   stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));\n   if (!g) return stbi__err(\"outofmem\", \"Out of memory\");\n   if (!stbi__gif_header(s, g, comp, 1)) {\n      STBI_FREE(g);\n      stbi__rewind( s );\n      return 0;\n   }\n   if (x) *x = g->w;\n   if (y) *y = g->h;\n   STBI_FREE(g);\n   return 1;\n}\n\nstatic void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)\n{\n   stbi_uc *p, *c;\n   int idx;\n\n   // recurse to decode the prefixes, since the linked-list is backwards,\n   // and working backwards through an interleaved image would be nasty\n   if (g->codes[code].prefix >= 0)\n      stbi__out_gif_code(g, g->codes[code].prefix);\n\n   if (g->cur_y >= g->max_y) return;\n\n   idx = g->cur_x + g->cur_y;\n   p = &g->out[idx];\n   g->history[idx / 4] = 1;\n\n   c = &g->color_table[g->codes[code].suffix * 4];\n   if (c[3] > 128) { // don't render transparent pixels;\n      p[0] = c[2];\n      p[1] = c[1];\n      p[2] = c[0];\n      p[3] = c[3];\n   }\n   g->cur_x += 4;\n\n   if (g->cur_x >= g->max_x) {\n      g->cur_x = g->start_x;\n      g->cur_y += g->step;\n\n      while (g->cur_y >= g->max_y && g->parse > 0) {\n         g->step = (1 << g->parse) * g->line_size;\n         g->cur_y = g->start_y + (g->step >> 1);\n         --g->parse;\n      }\n   }\n}\n\nstatic stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)\n{\n   stbi_uc lzw_cs;\n   stbi__int32 len, init_code;\n   stbi__uint32 first;\n   stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;\n   stbi__gif_lzw *p;\n\n   lzw_cs = stbi__get8(s);\n   if (lzw_cs > 12) return NULL;\n   clear = 1 << lzw_cs;\n   first = 1;\n   codesize = lzw_cs + 1;\n   codemask = (1 << codesize) - 1;\n   bits = 0;\n   valid_bits = 0;\n   for (init_code = 0; init_code < clear; init_code++) {\n      g->codes[init_code].prefix = -1;\n      g->codes[init_code].first = (stbi_uc) init_code;\n      g->codes[init_code].suffix = (stbi_uc) init_code;\n   }\n\n   // support no starting clear code\n   avail = clear+2;\n   oldcode = -1;\n\n   len = 0;\n   for(;;) {\n      if (valid_bits < codesize) {\n         if (len == 0) {\n            len = stbi__get8(s); // start new block\n            if (len == 0)\n               return g->out;\n         }\n         --len;\n         bits |= (stbi__int32) stbi__get8(s) << valid_bits;\n         valid_bits += 8;\n      } else {\n         stbi__int32 code = bits & codemask;\n         bits >>= codesize;\n         valid_bits -= codesize;\n         // @OPTIMIZE: is there some way we can accelerate the non-clear path?\n         if (code == clear) {  // clear code\n            codesize = lzw_cs + 1;\n            codemask = (1 << codesize) - 1;\n            avail = clear + 2;\n            oldcode = -1;\n            first = 0;\n         } else if (code == clear + 1) { // end of stream code\n            stbi__skip(s, len);\n            while ((len = stbi__get8(s)) > 0)\n               stbi__skip(s,len);\n            return g->out;\n         } else if (code <= avail) {\n            if (first) {\n               return stbi__errpuc(\"no clear code\", \"Corrupt GIF\");\n            }\n\n            if (oldcode >= 0) {\n               p = &g->codes[avail++];\n               if (avail > 8192) {\n                  return stbi__errpuc(\"too many codes\", \"Corrupt GIF\");\n               }\n\n               p->prefix = (stbi__int16) oldcode;\n               p->first = g->codes[oldcode].first;\n               p->suffix = (code == avail) ? p->first : g->codes[code].first;\n            } else if (code == avail)\n               return stbi__errpuc(\"illegal code in raster\", \"Corrupt GIF\");\n\n            stbi__out_gif_code(g, (stbi__uint16) code);\n\n            if ((avail & codemask) == 0 && avail <= 0x0FFF) {\n               codesize++;\n               codemask = (1 << codesize) - 1;\n            }\n\n            oldcode = code;\n         } else {\n            return stbi__errpuc(\"illegal code in raster\", \"Corrupt GIF\");\n         }\n      }\n   }\n}\n\n// this function is designed to support animated gifs, although stb_image doesn't support it\n// two back is the image from two frames ago, used for a very specific disposal format\nstatic stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)\n{\n   int dispose;\n   int first_frame;\n   int pi;\n   int pcount;\n   STBI_NOTUSED(req_comp);\n\n   // on first frame, any non-written pixels get the background colour (non-transparent)\n   first_frame = 0;\n   if (g->out == 0) {\n      if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header\n      if (!stbi__mad3sizes_valid(4, g->w, g->h, 0))\n         return stbi__errpuc(\"too large\", \"GIF image is too large\");\n      pcount = g->w * g->h;\n      g->out = (stbi_uc *) stbi__malloc(4 * pcount);\n      g->background = (stbi_uc *) stbi__malloc(4 * pcount);\n      g->history = (stbi_uc *) stbi__malloc(pcount);\n      if (!g->out || !g->background || !g->history)\n         return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n      // image is treated as \"transparent\" at the start - ie, nothing overwrites the current background;\n      // background colour is only used for pixels that are not rendered first frame, after that \"background\"\n      // color refers to the color that was there the previous frame.\n      memset(g->out, 0x00, 4 * pcount);\n      memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent)\n      memset(g->history, 0x00, pcount);        // pixels that were affected previous frame\n      first_frame = 1;\n   } else {\n      // second frame - how do we dispose of the previous one?\n      dispose = (g->eflags & 0x1C) >> 2;\n      pcount = g->w * g->h;\n\n      if ((dispose == 3) && (two_back == 0)) {\n         dispose = 2; // if I don't have an image to revert back to, default to the old background\n      }\n\n      if (dispose == 3) { // use previous graphic\n         for (pi = 0; pi < pcount; ++pi) {\n            if (g->history[pi]) {\n               memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );\n            }\n         }\n      } else if (dispose == 2) {\n         // restore what was changed last frame to background before that frame;\n         for (pi = 0; pi < pcount; ++pi) {\n            if (g->history[pi]) {\n               memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );\n            }\n         }\n      } else {\n         // This is a non-disposal case eithe way, so just\n         // leave the pixels as is, and they will become the new background\n         // 1: do not dispose\n         // 0:  not specified.\n      }\n\n      // background is what out is after the undoing of the previou frame;\n      memcpy( g->background, g->out, 4 * g->w * g->h );\n   }\n\n   // clear my history;\n   memset( g->history, 0x00, g->w * g->h );        // pixels that were affected previous frame\n\n   for (;;) {\n      int tag = stbi__get8(s);\n      switch (tag) {\n         case 0x2C: /* Image Descriptor */\n         {\n            stbi__int32 x, y, w, h;\n            stbi_uc *o;\n\n            x = stbi__get16le(s);\n            y = stbi__get16le(s);\n            w = stbi__get16le(s);\n            h = stbi__get16le(s);\n            if (((x + w) > (g->w)) || ((y + h) > (g->h)))\n               return stbi__errpuc(\"bad Image Descriptor\", \"Corrupt GIF\");\n\n            g->line_size = g->w * 4;\n            g->start_x = x * 4;\n            g->start_y = y * g->line_size;\n            g->max_x   = g->start_x + w * 4;\n            g->max_y   = g->start_y + h * g->line_size;\n            g->cur_x   = g->start_x;\n            g->cur_y   = g->start_y;\n\n            // if the width of the specified rectangle is 0, that means\n            // we may not see *any* pixels or the image is malformed;\n            // to make sure this is caught, move the current y down to\n            // max_y (which is what out_gif_code checks).\n            if (w == 0)\n               g->cur_y = g->max_y;\n\n            g->lflags = stbi__get8(s);\n\n            if (g->lflags & 0x40) {\n               g->step = 8 * g->line_size; // first interlaced spacing\n               g->parse = 3;\n            } else {\n               g->step = g->line_size;\n               g->parse = 0;\n            }\n\n            if (g->lflags & 0x80) {\n               stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);\n               g->color_table = (stbi_uc *) g->lpal;\n            } else if (g->flags & 0x80) {\n               g->color_table = (stbi_uc *) g->pal;\n            } else\n               return stbi__errpuc(\"missing color table\", \"Corrupt GIF\");\n\n            o = stbi__process_gif_raster(s, g);\n            if (!o) return NULL;\n\n            // if this was the first frame,\n            pcount = g->w * g->h;\n            if (first_frame && (g->bgindex > 0)) {\n               // if first frame, any pixel not drawn to gets the background color\n               for (pi = 0; pi < pcount; ++pi) {\n                  if (g->history[pi] == 0) {\n                     g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;\n                     memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );\n                  }\n               }\n            }\n\n            return o;\n         }\n\n         case 0x21: // Comment Extension.\n         {\n            int len;\n            int ext = stbi__get8(s);\n            if (ext == 0xF9) { // Graphic Control Extension.\n               len = stbi__get8(s);\n               if (len == 4) {\n                  g->eflags = stbi__get8(s);\n                  g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths.\n\n                  // unset old transparent\n                  if (g->transparent >= 0) {\n                     g->pal[g->transparent][3] = 255;\n                  }\n                  if (g->eflags & 0x01) {\n                     g->transparent = stbi__get8(s);\n                     if (g->transparent >= 0) {\n                        g->pal[g->transparent][3] = 0;\n                     }\n                  } else {\n                     // don't need transparent\n                     stbi__skip(s, 1);\n                     g->transparent = -1;\n                  }\n               } else {\n                  stbi__skip(s, len);\n                  break;\n               }\n            }\n            while ((len = stbi__get8(s)) != 0) {\n               stbi__skip(s, len);\n            }\n            break;\n         }\n\n         case 0x3B: // gif stream termination code\n            return (stbi_uc *) s; // using '1' causes warning on some compilers\n\n         default:\n            return stbi__errpuc(\"unknown code\", \"Corrupt GIF\");\n      }\n   }\n}\n\nstatic void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays)\n{\n   STBI_FREE(g->out);\n   STBI_FREE(g->history);\n   STBI_FREE(g->background);\n\n   if (out) STBI_FREE(out);\n   if (delays && *delays) STBI_FREE(*delays);\n   return stbi__errpuc(\"outofmem\", \"Out of memory\");\n}\n\nstatic void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)\n{\n   if (stbi__gif_test(s)) {\n      int layers = 0;\n      stbi_uc *u = 0;\n      stbi_uc *out = 0;\n      stbi_uc *two_back = 0;\n      stbi__gif g;\n      int stride;\n      int out_size = 0;\n      int delays_size = 0;\n\n      STBI_NOTUSED(out_size);\n      STBI_NOTUSED(delays_size);\n\n      memset(&g, 0, sizeof(g));\n      if (delays) {\n         *delays = 0;\n      }\n\n      do {\n         u = stbi__gif_load_next(s, &g, comp, req_comp, two_back);\n         if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker\n\n         if (u) {\n            *x = g.w;\n            *y = g.h;\n            ++layers;\n            stride = g.w * g.h * 4;\n\n            if (out) {\n               void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride );\n               if (!tmp)\n                  return stbi__load_gif_main_outofmem(&g, out, delays);\n               else {\n                   out = (stbi_uc*) tmp;\n                   out_size = layers * stride;\n               }\n\n               if (delays) {\n                  int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers );\n                  if (!new_delays)\n                     return stbi__load_gif_main_outofmem(&g, out, delays);\n                  *delays = new_delays;\n                  delays_size = layers * sizeof(int);\n               }\n            } else {\n               out = (stbi_uc*)stbi__malloc( layers * stride );\n               if (!out)\n                  return stbi__load_gif_main_outofmem(&g, out, delays);\n               out_size = layers * stride;\n               if (delays) {\n                  *delays = (int*) stbi__malloc( layers * sizeof(int) );\n                  if (!*delays)\n                     return stbi__load_gif_main_outofmem(&g, out, delays);\n                  delays_size = layers * sizeof(int);\n               }\n            }\n            memcpy( out + ((layers - 1) * stride), u, stride );\n            if (layers >= 2) {\n               two_back = out - 2 * stride;\n            }\n\n            if (delays) {\n               (*delays)[layers - 1U] = g.delay;\n            }\n         }\n      } while (u != 0);\n\n      // free temp buffer;\n      STBI_FREE(g.out);\n      STBI_FREE(g.history);\n      STBI_FREE(g.background);\n\n      // do the final conversion after loading everything;\n      if (req_comp && req_comp != 4)\n         out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);\n\n      *z = layers;\n      return out;\n   } else {\n      return stbi__errpuc(\"not GIF\", \"Image was not as a gif type.\");\n   }\n}\n\nstatic void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *u = 0;\n   stbi__gif g;\n   memset(&g, 0, sizeof(g));\n   STBI_NOTUSED(ri);\n\n   u = stbi__gif_load_next(s, &g, comp, req_comp, 0);\n   if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker\n   if (u) {\n      *x = g.w;\n      *y = g.h;\n\n      // moved conversion to after successful load so that the same\n      // can be done for multiple frames.\n      if (req_comp && req_comp != 4)\n         u = stbi__convert_format(u, 4, req_comp, g.w, g.h);\n   } else if (g.out) {\n      // if there was an error and we allocated an image buffer, free it!\n      STBI_FREE(g.out);\n   }\n\n   // free buffers needed for multiple frame loading;\n   STBI_FREE(g.history);\n   STBI_FREE(g.background);\n\n   return u;\n}\n\nstatic int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   return stbi__gif_info_raw(s,x,y,comp);\n}\n#endif\n\n// *************************************************************************************************\n// Radiance RGBE HDR loader\n// originally by Nicolas Schulz\n#ifndef STBI_NO_HDR\nstatic int stbi__hdr_test_core(stbi__context *s, const char *signature)\n{\n   int i;\n   for (i=0; signature[i]; ++i)\n      if (stbi__get8(s) != signature[i])\n          return 0;\n   stbi__rewind(s);\n   return 1;\n}\n\nstatic int stbi__hdr_test(stbi__context* s)\n{\n   int r = stbi__hdr_test_core(s, \"#?RADIANCE\\n\");\n   stbi__rewind(s);\n   if(!r) {\n       r = stbi__hdr_test_core(s, \"#?RGBE\\n\");\n       stbi__rewind(s);\n   }\n   return r;\n}\n\n#define STBI__HDR_BUFLEN  1024\nstatic char *stbi__hdr_gettoken(stbi__context *z, char *buffer)\n{\n   int len=0;\n   char c = '\\0';\n\n   c = (char) stbi__get8(z);\n\n   while (!stbi__at_eof(z) && c != '\\n') {\n      buffer[len++] = c;\n      if (len == STBI__HDR_BUFLEN-1) {\n         // flush to end of line\n         while (!stbi__at_eof(z) && stbi__get8(z) != '\\n')\n            ;\n         break;\n      }\n      c = (char) stbi__get8(z);\n   }\n\n   buffer[len] = 0;\n   return buffer;\n}\n\nstatic void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)\n{\n   if ( input[3] != 0 ) {\n      float f1;\n      // Exponent\n      f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));\n      if (req_comp <= 2)\n         output[0] = (input[0] + input[1] + input[2]) * f1 / 3;\n      else {\n         output[0] = input[0] * f1;\n         output[1] = input[1] * f1;\n         output[2] = input[2] * f1;\n      }\n      if (req_comp == 2) output[1] = 1;\n      if (req_comp == 4) output[3] = 1;\n   } else {\n      switch (req_comp) {\n         case 4: output[3] = 1; /* fallthrough */\n         case 3: output[0] = output[1] = output[2] = 0;\n                 break;\n         case 2: output[1] = 1; /* fallthrough */\n         case 1: output[0] = 0;\n                 break;\n      }\n   }\n}\n\nstatic float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   char buffer[STBI__HDR_BUFLEN];\n   char *token;\n   int valid = 0;\n   int width, height;\n   stbi_uc *scanline;\n   float *hdr_data;\n   int len;\n   unsigned char count, value;\n   int i, j, k, c1,c2, z;\n   const char *headerToken;\n   STBI_NOTUSED(ri);\n\n   // Check identifier\n   headerToken = stbi__hdr_gettoken(s,buffer);\n   if (strcmp(headerToken, \"#?RADIANCE\") != 0 && strcmp(headerToken, \"#?RGBE\") != 0)\n      return stbi__errpf(\"not HDR\", \"Corrupt HDR image\");\n\n   // Parse header\n   for(;;) {\n      token = stbi__hdr_gettoken(s,buffer);\n      if (token[0] == 0) break;\n      if (strcmp(token, \"FORMAT=32-bit_rle_rgbe\") == 0) valid = 1;\n   }\n\n   if (!valid)    return stbi__errpf(\"unsupported format\", \"Unsupported HDR format\");\n\n   // Parse width and height\n   // can't use sscanf() if we're not using stdio!\n   token = stbi__hdr_gettoken(s,buffer);\n   if (strncmp(token, \"-Y \", 3))  return stbi__errpf(\"unsupported data layout\", \"Unsupported HDR format\");\n   token += 3;\n   height = (int) strtol(token, &token, 10);\n   while (*token == ' ') ++token;\n   if (strncmp(token, \"+X \", 3))  return stbi__errpf(\"unsupported data layout\", \"Unsupported HDR format\");\n   token += 3;\n   width = (int) strtol(token, NULL, 10);\n\n   if (height > STBI_MAX_DIMENSIONS) return stbi__errpf(\"too large\",\"Very large image (corrupt?)\");\n   if (width > STBI_MAX_DIMENSIONS) return stbi__errpf(\"too large\",\"Very large image (corrupt?)\");\n\n   *x = width;\n   *y = height;\n\n   if (comp) *comp = 3;\n   if (req_comp == 0) req_comp = 3;\n\n   if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0))\n      return stbi__errpf(\"too large\", \"HDR image is too large\");\n\n   // Read data\n   hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0);\n   if (!hdr_data)\n      return stbi__errpf(\"outofmem\", \"Out of memory\");\n\n   // Load image data\n   // image data is stored as some number of sca\n   if ( width < 8 || width >= 32768) {\n      // Read flat data\n      for (j=0; j < height; ++j) {\n         for (i=0; i < width; ++i) {\n            stbi_uc rgbe[4];\n           main_decode_loop:\n            stbi__getn(s, rgbe, 4);\n            stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);\n         }\n      }\n   } else {\n      // Read RLE-encoded data\n      scanline = NULL;\n\n      for (j = 0; j < height; ++j) {\n         c1 = stbi__get8(s);\n         c2 = stbi__get8(s);\n         len = stbi__get8(s);\n         if (c1 != 2 || c2 != 2 || (len & 0x80)) {\n            // not run-length encoded, so we have to actually use THIS data as a decoded\n            // pixel (note this can't be a valid pixel--one of RGB must be >= 128)\n            stbi_uc rgbe[4];\n            rgbe[0] = (stbi_uc) c1;\n            rgbe[1] = (stbi_uc) c2;\n            rgbe[2] = (stbi_uc) len;\n            rgbe[3] = (stbi_uc) stbi__get8(s);\n            stbi__hdr_convert(hdr_data, rgbe, req_comp);\n            i = 1;\n            j = 0;\n            STBI_FREE(scanline);\n            goto main_decode_loop; // yes, this makes no sense\n         }\n         len <<= 8;\n         len |= stbi__get8(s);\n         if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf(\"invalid decoded scanline length\", \"corrupt HDR\"); }\n         if (scanline == NULL) {\n            scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0);\n            if (!scanline) {\n               STBI_FREE(hdr_data);\n               return stbi__errpf(\"outofmem\", \"Out of memory\");\n            }\n         }\n\n         for (k = 0; k < 4; ++k) {\n            int nleft;\n            i = 0;\n            while ((nleft = width - i) > 0) {\n               count = stbi__get8(s);\n               if (count > 128) {\n                  // Run\n                  value = stbi__get8(s);\n                  count -= 128;\n                  if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf(\"corrupt\", \"bad RLE data in HDR\"); }\n                  for (z = 0; z < count; ++z)\n                     scanline[i++ * 4 + k] = value;\n               } else {\n                  // Dump\n                  if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf(\"corrupt\", \"bad RLE data in HDR\"); }\n                  for (z = 0; z < count; ++z)\n                     scanline[i++ * 4 + k] = stbi__get8(s);\n               }\n            }\n         }\n         for (i=0; i < width; ++i)\n            stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);\n      }\n      if (scanline)\n         STBI_FREE(scanline);\n   }\n\n   return hdr_data;\n}\n\nstatic int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   char buffer[STBI__HDR_BUFLEN];\n   char *token;\n   int valid = 0;\n   int dummy;\n\n   if (!x) x = &dummy;\n   if (!y) y = &dummy;\n   if (!comp) comp = &dummy;\n\n   if (stbi__hdr_test(s) == 0) {\n       stbi__rewind( s );\n       return 0;\n   }\n\n   for(;;) {\n      token = stbi__hdr_gettoken(s,buffer);\n      if (token[0] == 0) break;\n      if (strcmp(token, \"FORMAT=32-bit_rle_rgbe\") == 0) valid = 1;\n   }\n\n   if (!valid) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token = stbi__hdr_gettoken(s,buffer);\n   if (strncmp(token, \"-Y \", 3)) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token += 3;\n   *y = (int) strtol(token, &token, 10);\n   while (*token == ' ') ++token;\n   if (strncmp(token, \"+X \", 3)) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token += 3;\n   *x = (int) strtol(token, NULL, 10);\n   *comp = 3;\n   return 1;\n}\n#endif // STBI_NO_HDR\n\n#ifndef STBI_NO_BMP\nstatic int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   void *p;\n   stbi__bmp_data info;\n\n   info.all_a = 255;\n   p = stbi__bmp_parse_header(s, &info);\n   if (p == NULL) {\n      stbi__rewind( s );\n      return 0;\n   }\n   if (x) *x = s->img_x;\n   if (y) *y = s->img_y;\n   if (comp) {\n      if (info.bpp == 24 && info.ma == 0xff000000)\n         *comp = 3;\n      else\n         *comp = info.ma ? 4 : 3;\n   }\n   return 1;\n}\n#endif\n\n#ifndef STBI_NO_PSD\nstatic int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int channelCount, dummy, depth;\n   if (!x) x = &dummy;\n   if (!y) y = &dummy;\n   if (!comp) comp = &dummy;\n   if (stbi__get32be(s) != 0x38425053) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (stbi__get16be(s) != 1) {\n       stbi__rewind( s );\n       return 0;\n   }\n   stbi__skip(s, 6);\n   channelCount = stbi__get16be(s);\n   if (channelCount < 0 || channelCount > 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   *y = stbi__get32be(s);\n   *x = stbi__get32be(s);\n   depth = stbi__get16be(s);\n   if (depth != 8 && depth != 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (stbi__get16be(s) != 3) {\n       stbi__rewind( s );\n       return 0;\n   }\n   *comp = 4;\n   return 1;\n}\n\nstatic int stbi__psd_is16(stbi__context *s)\n{\n   int channelCount, depth;\n   if (stbi__get32be(s) != 0x38425053) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (stbi__get16be(s) != 1) {\n       stbi__rewind( s );\n       return 0;\n   }\n   stbi__skip(s, 6);\n   channelCount = stbi__get16be(s);\n   if (channelCount < 0 || channelCount > 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   STBI_NOTUSED(stbi__get32be(s));\n   STBI_NOTUSED(stbi__get32be(s));\n   depth = stbi__get16be(s);\n   if (depth != 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   return 1;\n}\n#endif\n\n#ifndef STBI_NO_PIC\nstatic int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int act_comp=0,num_packets=0,chained,dummy;\n   stbi__pic_packet packets[10];\n\n   if (!x) x = &dummy;\n   if (!y) y = &dummy;\n   if (!comp) comp = &dummy;\n\n   if (!stbi__pic_is4(s,\"\\x53\\x80\\xF6\\x34\")) {\n      stbi__rewind(s);\n      return 0;\n   }\n\n   stbi__skip(s, 88);\n\n   *x = stbi__get16be(s);\n   *y = stbi__get16be(s);\n   if (stbi__at_eof(s)) {\n      stbi__rewind( s);\n      return 0;\n   }\n   if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {\n      stbi__rewind( s );\n      return 0;\n   }\n\n   stbi__skip(s, 8);\n\n   do {\n      stbi__pic_packet *packet;\n\n      if (num_packets==sizeof(packets)/sizeof(packets[0]))\n         return 0;\n\n      packet = &packets[num_packets++];\n      chained = stbi__get8(s);\n      packet->size    = stbi__get8(s);\n      packet->type    = stbi__get8(s);\n      packet->channel = stbi__get8(s);\n      act_comp |= packet->channel;\n\n      if (stbi__at_eof(s)) {\n          stbi__rewind( s );\n          return 0;\n      }\n      if (packet->size != 8) {\n          stbi__rewind( s );\n          return 0;\n      }\n   } while (chained);\n\n   *comp = (act_comp & 0x10 ? 4 : 3);\n\n   return 1;\n}\n#endif\n\n// *************************************************************************************************\n// Portable Gray Map and Portable Pixel Map loader\n// by Ken Miller\n//\n// PGM: http://netpbm.sourceforge.net/doc/pgm.html\n// PPM: http://netpbm.sourceforge.net/doc/ppm.html\n//\n// Known limitations:\n//    Does not support comments in the header section\n//    Does not support ASCII image data (formats P2 and P3)\n\n#ifndef STBI_NO_PNM\n\nstatic int      stbi__pnm_test(stbi__context *s)\n{\n   char p, t;\n   p = (char) stbi__get8(s);\n   t = (char) stbi__get8(s);\n   if (p != 'P' || (t != '5' && t != '6')) {\n       stbi__rewind( s );\n       return 0;\n   }\n   return 1;\n}\n\nstatic void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *out;\n   STBI_NOTUSED(ri);\n\n   ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n);\n   if (ri->bits_per_channel == 0)\n      return 0;\n\n   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   *x = s->img_x;\n   *y = s->img_y;\n   if (comp) *comp = s->img_n;\n\n   if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0))\n      return stbi__errpuc(\"too large\", \"PNM too large\");\n\n   out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0);\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) {\n      STBI_FREE(out);\n      return stbi__errpuc(\"bad PNM\", \"PNM file truncated\");\n   }\n\n   if (req_comp && req_comp != s->img_n) {\n      if (ri->bits_per_channel == 16) {\n         out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y);\n      } else {\n         out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);\n      }\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n   return out;\n}\n\nstatic int      stbi__pnm_isspace(char c)\n{\n   return c == ' ' || c == '\\t' || c == '\\n' || c == '\\v' || c == '\\f' || c == '\\r';\n}\n\nstatic void     stbi__pnm_skip_whitespace(stbi__context *s, char *c)\n{\n   for (;;) {\n      while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))\n         *c = (char) stbi__get8(s);\n\n      if (stbi__at_eof(s) || *c != '#')\n         break;\n\n      while (!stbi__at_eof(s) && *c != '\\n' && *c != '\\r' )\n         *c = (char) stbi__get8(s);\n   }\n}\n\nstatic int      stbi__pnm_isdigit(char c)\n{\n   return c >= '0' && c <= '9';\n}\n\nstatic int      stbi__pnm_getinteger(stbi__context *s, char *c)\n{\n   int value = 0;\n\n   while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {\n      value = value*10 + (*c - '0');\n      *c = (char) stbi__get8(s);\n      if((value > 214748364) || (value == 214748364 && *c > '7'))\n          return stbi__err(\"integer parse overflow\", \"Parsing an integer in the PPM header overflowed a 32-bit int\");\n   }\n\n   return value;\n}\n\nstatic int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int maxv, dummy;\n   char c, p, t;\n\n   if (!x) x = &dummy;\n   if (!y) y = &dummy;\n   if (!comp) comp = &dummy;\n\n   stbi__rewind(s);\n\n   // Get identifier\n   p = (char) stbi__get8(s);\n   t = (char) stbi__get8(s);\n   if (p != 'P' || (t != '5' && t != '6')) {\n       stbi__rewind(s);\n       return 0;\n   }\n\n   *comp = (t == '6') ? 3 : 1;  // '5' is 1-component .pgm; '6' is 3-component .ppm\n\n   c = (char) stbi__get8(s);\n   stbi__pnm_skip_whitespace(s, &c);\n\n   *x = stbi__pnm_getinteger(s, &c); // read width\n   if(*x == 0)\n       return stbi__err(\"invalid width\", \"PPM image header had zero or overflowing width\");\n   stbi__pnm_skip_whitespace(s, &c);\n\n   *y = stbi__pnm_getinteger(s, &c); // read height\n   if (*y == 0)\n       return stbi__err(\"invalid width\", \"PPM image header had zero or overflowing width\");\n   stbi__pnm_skip_whitespace(s, &c);\n\n   maxv = stbi__pnm_getinteger(s, &c);  // read max value\n   if (maxv > 65535)\n      return stbi__err(\"max value > 65535\", \"PPM image supports only 8-bit and 16-bit images\");\n   else if (maxv > 255)\n      return 16;\n   else\n      return 8;\n}\n\nstatic int stbi__pnm_is16(stbi__context *s)\n{\n   if (stbi__pnm_info(s, NULL, NULL, NULL) == 16)\n\t   return 1;\n   return 0;\n}\n#endif\n\nstatic int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)\n{\n   #ifndef STBI_NO_JPEG\n   if (stbi__jpeg_info(s, x, y, comp)) return 1;\n   #endif\n\n   #ifndef STBI_NO_PNG\n   if (stbi__png_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_GIF\n   if (stbi__gif_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_BMP\n   if (stbi__bmp_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PIC\n   if (stbi__pic_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_info(s, x, y, comp))  return 1;\n   #endif\n\n   // test tga last because it's a crappy test!\n   #ifndef STBI_NO_TGA\n   if (stbi__tga_info(s, x, y, comp))\n       return 1;\n   #endif\n   return stbi__err(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\nstatic int stbi__is_16_main(stbi__context *s)\n{\n   #ifndef STBI_NO_PNG\n   if (stbi__png_is16(s))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_is16(s))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_is16(s))  return 1;\n   #endif\n   return 0;\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)\n{\n    FILE *f = stbi__fopen(filename, \"rb\");\n    int result;\n    if (!f) return stbi__err(\"can't fopen\", \"Unable to open file\");\n    result = stbi_info_from_file(f, x, y, comp);\n    fclose(f);\n    return result;\n}\n\nSTBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)\n{\n   int r;\n   stbi__context s;\n   long pos = ftell(f);\n   stbi__start_file(&s, f);\n   r = stbi__info_main(&s,x,y,comp);\n   fseek(f,pos,SEEK_SET);\n   return r;\n}\n\nSTBIDEF int stbi_is_16_bit(char const *filename)\n{\n    FILE *f = stbi__fopen(filename, \"rb\");\n    int result;\n    if (!f) return stbi__err(\"can't fopen\", \"Unable to open file\");\n    result = stbi_is_16_bit_from_file(f);\n    fclose(f);\n    return result;\n}\n\nSTBIDEF int stbi_is_16_bit_from_file(FILE *f)\n{\n   int r;\n   stbi__context s;\n   long pos = ftell(f);\n   stbi__start_file(&s, f);\n   r = stbi__is_16_main(&s);\n   fseek(f,pos,SEEK_SET);\n   return r;\n}\n#endif // !STBI_NO_STDIO\n\nSTBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__info_main(&s,x,y,comp);\n}\n\nSTBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);\n   return stbi__info_main(&s,x,y,comp);\n}\n\nSTBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__is_16_main(&s);\n}\n\nSTBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);\n   return stbi__is_16_main(&s);\n}\n\n#endif // STB_IMAGE_IMPLEMENTATION\n\n/*\n   revision history:\n      2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs\n      2.19  (2018-02-11) fix warning\n      2.18  (2018-01-30) fix warnings\n      2.17  (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug\n                         1-bit BMP\n                         *_is_16_bit api\n                         avoid warnings\n      2.16  (2017-07-23) all functions have 16-bit variants;\n                         STBI_NO_STDIO works again;\n                         compilation fixes;\n                         fix rounding in unpremultiply;\n                         optimize vertical flip;\n                         disable raw_len validation;\n                         documentation fixes\n      2.15  (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;\n                         warning fixes; disable run-time SSE detection on gcc;\n                         uniform handling of optional \"return\" values;\n                         thread-safe initialization of zlib tables\n      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs\n      2.13  (2016-11-29) add 16-bit API, only supported for PNG right now\n      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes\n      2.11  (2016-04-02) allocate large structures on the stack\n                         remove white matting for transparent PSD\n                         fix reported channel count for PNG & BMP\n                         re-enable SSE2 in non-gcc 64-bit\n                         support RGB-formatted JPEG\n                         read 16-bit PNGs (only as 8-bit)\n      2.10  (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED\n      2.09  (2016-01-16) allow comments in PNM files\n                         16-bit-per-pixel TGA (not bit-per-component)\n                         info() for TGA could break due to .hdr handling\n                         info() for BMP to shares code instead of sloppy parse\n                         can use STBI_REALLOC_SIZED if allocator doesn't support realloc\n                         code cleanup\n      2.08  (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA\n      2.07  (2015-09-13) fix compiler warnings\n                         partial animated GIF support\n                         limited 16-bpc PSD support\n                         #ifdef unused functions\n                         bug with < 92 byte PIC,PNM,HDR,TGA\n      2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value\n      2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning\n      2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit\n      2.03  (2015-04-12) extra corruption checking (mmozeiko)\n                         stbi_set_flip_vertically_on_load (nguillemot)\n                         fix NEON support; fix mingw support\n      2.02  (2015-01-19) fix incorrect assert, fix warning\n      2.01  (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2\n      2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG\n      2.00  (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)\n                         progressive JPEG (stb)\n                         PGM/PPM support (Ken Miller)\n                         STBI_MALLOC,STBI_REALLOC,STBI_FREE\n                         GIF bugfix -- seemingly never worked\n                         STBI_NO_*, STBI_ONLY_*\n      1.48  (2014-12-14) fix incorrectly-named assert()\n      1.47  (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)\n                         optimize PNG (ryg)\n                         fix bug in interlaced PNG with user-specified channel count (stb)\n      1.46  (2014-08-26)\n              fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG\n      1.45  (2014-08-16)\n              fix MSVC-ARM internal compiler error by wrapping malloc\n      1.44  (2014-08-07)\n              various warning fixes from Ronny Chevalier\n      1.43  (2014-07-15)\n              fix MSVC-only compiler problem in code changed in 1.42\n      1.42  (2014-07-09)\n              don't define _CRT_SECURE_NO_WARNINGS (affects user code)\n              fixes to stbi__cleanup_jpeg path\n              added STBI_ASSERT to avoid requiring assert.h\n      1.41  (2014-06-25)\n              fix search&replace from 1.36 that messed up comments/error messages\n      1.40  (2014-06-22)\n              fix gcc struct-initialization warning\n      1.39  (2014-06-15)\n              fix to TGA optimization when req_comp != number of components in TGA;\n              fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)\n              add support for BMP version 5 (more ignored fields)\n      1.38  (2014-06-06)\n              suppress MSVC warnings on integer casts truncating values\n              fix accidental rename of 'skip' field of I/O\n      1.37  (2014-06-04)\n              remove duplicate typedef\n      1.36  (2014-06-03)\n              convert to header file single-file library\n              if de-iphone isn't set, load iphone images color-swapped instead of returning NULL\n      1.35  (2014-05-27)\n              various warnings\n              fix broken STBI_SIMD path\n              fix bug where stbi_load_from_file no longer left file pointer in correct place\n              fix broken non-easy path for 32-bit BMP (possibly never used)\n              TGA optimization by Arseny Kapoulkine\n      1.34  (unknown)\n              use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case\n      1.33  (2011-07-14)\n              make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements\n      1.32  (2011-07-13)\n              support for \"info\" function for all supported filetypes (SpartanJ)\n      1.31  (2011-06-20)\n              a few more leak fixes, bug in PNG handling (SpartanJ)\n      1.30  (2011-06-11)\n              added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)\n              removed deprecated format-specific test/load functions\n              removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway\n              error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)\n              fix inefficiency in decoding 32-bit BMP (David Woo)\n      1.29  (2010-08-16)\n              various warning fixes from Aurelien Pocheville\n      1.28  (2010-08-01)\n              fix bug in GIF palette transparency (SpartanJ)\n      1.27  (2010-08-01)\n              cast-to-stbi_uc to fix warnings\n      1.26  (2010-07-24)\n              fix bug in file buffering for PNG reported by SpartanJ\n      1.25  (2010-07-17)\n              refix trans_data warning (Won Chun)\n      1.24  (2010-07-12)\n              perf improvements reading from files on platforms with lock-heavy fgetc()\n              minor perf improvements for jpeg\n              deprecated type-specific functions so we'll get feedback if they're needed\n              attempt to fix trans_data warning (Won Chun)\n      1.23    fixed bug in iPhone support\n      1.22  (2010-07-10)\n              removed image *writing* support\n              stbi_info support from Jetro Lauha\n              GIF support from Jean-Marc Lienher\n              iPhone PNG-extensions from James Brown\n              warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)\n      1.21    fix use of 'stbi_uc' in header (reported by jon blow)\n      1.20    added support for Softimage PIC, by Tom Seddon\n      1.19    bug in interlaced PNG corruption check (found by ryg)\n      1.18  (2008-08-02)\n              fix a threading bug (local mutable static)\n      1.17    support interlaced PNG\n      1.16    major bugfix - stbi__convert_format converted one too many pixels\n      1.15    initialize some fields for thread safety\n      1.14    fix threadsafe conversion bug\n              header-file-only version (#define STBI_HEADER_FILE_ONLY before including)\n      1.13    threadsafe\n      1.12    const qualifiers in the API\n      1.11    Support installable IDCT, colorspace conversion routines\n      1.10    Fixes for 64-bit (don't use \"unsigned long\")\n              optimized upsampling by Fabian \"ryg\" Giesen\n      1.09    Fix format-conversion for PSD code (bad global variables!)\n      1.08    Thatcher Ulrich's PSD code integrated by Nicolas Schulz\n      1.07    attempt to fix C++ warning/errors again\n      1.06    attempt to fix C++ warning/errors again\n      1.05    fix TGA loading to return correct *comp and use good luminance calc\n      1.04    default float alpha is 1, not 255; use 'void *' for stbi_image_free\n      1.03    bugfixes to STBI_NO_STDIO, STBI_NO_HDR\n      1.02    support for (subset of) HDR files, float interface for preferred access to them\n      1.01    fix bug: possible bug in handling right-side up bmps... not sure\n              fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all\n      1.00    interface to zlib that skips zlib header\n      0.99    correct handling of alpha in palette\n      0.98    TGA loader by lonesock; dynamically add loaders (untested)\n      0.97    jpeg errors on too large a file; also catch another malloc failure\n      0.96    fix detection of invalid v value - particleman@mollyrocket forum\n      0.95    during header scan, seek to markers in case of padding\n      0.94    STBI_NO_STDIO to disable stdio usage; rename all #defines the same\n      0.93    handle jpegtran output; verbose errors\n      0.92    read 4,8,16,24,32-bit BMP files of several formats\n      0.91    output 24-bit Windows 3.0 BMP files\n      0.90    fix a few more warnings; bump version number to approach 1.0\n      0.61    bugfixes due to Marc LeBlanc, Christopher Lloyd\n      0.60    fix compiling as c++\n      0.59    fix warnings: merge Dave Moore's -Wall fixes\n      0.58    fix bug: zlib uncompressed mode len/nlen was wrong endian\n      0.57    fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available\n      0.56    fix bug: zlib uncompressed mode len vs. nlen\n      0.55    fix bug: restart_interval not initialized to 0\n      0.54    allow NULL for 'int *comp'\n      0.53    fix bug in png 3->4; speedup png decoding\n      0.52    png handles req_comp=3,4 directly; minor cleanup; jpeg comments\n      0.51    obey req_comp requests, 1-component jpegs return as 1-component,\n              on 'test' only check type, not whether we support this variant\n      0.50  (2006-11-19)\n              first released version\n*/\n\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "External/stb/stb_image_write.h",
    "content": "/* stb_image_write - v1.16 - public domain - http://nothings.org/stb\n   writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015\n                                     no warranty implied; use at your own risk\n\n   Before #including,\n\n       #define STB_IMAGE_WRITE_IMPLEMENTATION\n\n   in the file that you want to have the implementation.\n\n   Will probably not work correctly with strict-aliasing optimizations.\n\nABOUT:\n\n   This header file is a library for writing images to C stdio or a callback.\n\n   The PNG output is not optimal; it is 20-50% larger than the file\n   written by a decent optimizing implementation; though providing a custom\n   zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.\n   This library is designed for source code compactness and simplicity,\n   not optimal image file size or run-time performance.\n\nBUILDING:\n\n   You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.\n   You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace\n   malloc,realloc,free.\n   You can #define STBIW_MEMMOVE() to replace memmove()\n   You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function\n   for PNG compression (instead of the builtin one), it must have the following signature:\n   unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);\n   The returned data will be freed with STBIW_FREE() (free() by default),\n   so it must be heap allocated with STBIW_MALLOC() (malloc() by default),\n\nUNICODE:\n\n   If compiling for Windows and you wish to use Unicode filenames, compile\n   with\n       #define STBIW_WINDOWS_UTF8\n   and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert\n   Windows wchar_t filenames to utf8.\n\nUSAGE:\n\n   There are five functions, one for each image file format:\n\n     int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);\n     int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);\n     int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);\n     int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);\n     int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);\n\n     void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically\n\n   There are also five equivalent functions that use an arbitrary write function. You are\n   expected to open/close your file-equivalent before and after calling these:\n\n     int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data, int stride_in_bytes);\n     int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\n     int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\n     int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);\n     int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);\n\n   where the callback is:\n      void stbi_write_func(void *context, void *data, int size);\n\n   You can configure it with these global variables:\n      int stbi_write_tga_with_rle;             // defaults to true; set to 0 to disable RLE\n      int stbi_write_png_compression_level;    // defaults to 8; set to higher for more compression\n      int stbi_write_force_png_filter;         // defaults to -1; set to 0..5 to force a filter mode\n\n\n   You can define STBI_WRITE_NO_STDIO to disable the file variant of these\n   functions, so the library will not use stdio.h at all. However, this will\n   also disable HDR writing, because it requires stdio for formatted output.\n\n   Each function returns 0 on failure and non-0 on success.\n\n   The functions create an image file defined by the parameters. The image\n   is a rectangle of pixels stored from left-to-right, top-to-bottom.\n   Each pixel contains 'comp' channels of data stored interleaved with 8-bits\n   per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is\n   monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.\n   The *data pointer points to the first byte of the top-left-most pixel.\n   For PNG, \"stride_in_bytes\" is the distance in bytes from the first byte of\n   a row of pixels to the first byte of the next row of pixels.\n\n   PNG creates output files with the same number of components as the input.\n   The BMP format expands Y to RGB in the file format and does not\n   output alpha.\n\n   PNG supports writing rectangles of data even when the bytes storing rows of\n   data are not consecutive in memory (e.g. sub-rectangles of a larger image),\n   by supplying the stride between the beginning of adjacent rows. The other\n   formats do not. (Thus you cannot write a native-format BMP through the BMP\n   writer, both because it is in BGR order and because it may have padding\n   at the end of the line.)\n\n   PNG allows you to set the deflate compression level by setting the global\n   variable 'stbi_write_png_compression_level' (it defaults to 8).\n\n   HDR expects linear float data. Since the format is always 32-bit rgb(e)\n   data, alpha (if provided) is discarded, and for monochrome data it is\n   replicated across all three channels.\n\n   TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed\n   data, set the global variable 'stbi_write_tga_with_rle' to 0.\n\n   JPEG does ignore alpha channels in input data; quality is between 1 and 100.\n   Higher quality looks better but results in a bigger image.\n   JPEG baseline (no JPEG progressive).\n\nCREDITS:\n\n\n   Sean Barrett           -    PNG/BMP/TGA\n   Baldur Karlsson        -    HDR\n   Jean-Sebastien Guay    -    TGA monochrome\n   Tim Kelsey             -    misc enhancements\n   Alan Hickman           -    TGA RLE\n   Emmanuel Julien        -    initial file IO callback implementation\n   Jon Olick              -    original jo_jpeg.cpp code\n   Daniel Gibson          -    integrate JPEG, allow external zlib\n   Aarni Koskela          -    allow choosing PNG filter\n\n   bugfixes:\n      github:Chribba\n      Guillaume Chereau\n      github:jry2\n      github:romigrou\n      Sergio Gonzalez\n      Jonas Karlsson\n      Filip Wasil\n      Thatcher Ulrich\n      github:poppolopoppo\n      Patrick Boettcher\n      github:xeekworx\n      Cap Petschulat\n      Simon Rodriguez\n      Ivan Tikhonov\n      github:ignotion\n      Adam Schackart\n      Andrew Kensler\n\nLICENSE\n\n  See end of file for license information.\n\n*/\n\n#ifndef INCLUDE_STB_IMAGE_WRITE_H\n#define INCLUDE_STB_IMAGE_WRITE_H\n\n#include <stdlib.h>\n\n// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'\n#ifndef STBIWDEF\n#ifdef STB_IMAGE_WRITE_STATIC\n#define STBIWDEF  static\n#else\n#ifdef __cplusplus\n#define STBIWDEF  extern \"C\"\n#else\n#define STBIWDEF  extern\n#endif\n#endif\n#endif\n\n#ifndef STB_IMAGE_WRITE_STATIC  // C++ forbids static forward declarations\nSTBIWDEF int stbi_write_tga_with_rle;\nSTBIWDEF int stbi_write_png_compression_level;\nSTBIWDEF int stbi_write_force_png_filter;\n#endif\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void  *data, int stride_in_bytes);\nSTBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);\nSTBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void  *data, int quality);\n\n#ifdef STBIW_WINDOWS_UTF8\nSTBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);\n#endif\n#endif\n\ntypedef void stbi_write_func(void *context, void *data, int size);\n\nSTBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data, int stride_in_bytes);\nSTBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);\nSTBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void  *data, int quality);\n\nSTBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);\n\n#endif//INCLUDE_STB_IMAGE_WRITE_H\n\n#ifdef STB_IMAGE_WRITE_IMPLEMENTATION\n\n#ifdef _WIN32\n   #ifndef _CRT_SECURE_NO_WARNINGS\n   #define _CRT_SECURE_NO_WARNINGS\n   #endif\n   #ifndef _CRT_NONSTDC_NO_DEPRECATE\n   #define _CRT_NONSTDC_NO_DEPRECATE\n   #endif\n#endif\n\n#ifndef STBI_WRITE_NO_STDIO\n#include <stdio.h>\n#endif // STBI_WRITE_NO_STDIO\n\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n\n#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))\n// ok\n#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)\n// ok\n#else\n#error \"Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED).\"\n#endif\n\n#ifndef STBIW_MALLOC\n#define STBIW_MALLOC(sz)        malloc(sz)\n#define STBIW_REALLOC(p,newsz)  realloc(p,newsz)\n#define STBIW_FREE(p)           free(p)\n#endif\n\n#ifndef STBIW_REALLOC_SIZED\n#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)\n#endif\n\n\n#ifndef STBIW_MEMMOVE\n#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)\n#endif\n\n\n#ifndef STBIW_ASSERT\n#include <assert.h>\n#define STBIW_ASSERT(x) assert(x)\n#endif\n\n#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)\n\n#ifdef STB_IMAGE_WRITE_STATIC\nstatic int stbi_write_png_compression_level = 8;\nstatic int stbi_write_tga_with_rle = 1;\nstatic int stbi_write_force_png_filter = -1;\n#else\nint stbi_write_png_compression_level = 8;\nint stbi_write_tga_with_rle = 1;\nint stbi_write_force_png_filter = -1;\n#endif\n\nstatic int stbi__flip_vertically_on_write = 0;\n\nSTBIWDEF void stbi_flip_vertically_on_write(int flag)\n{\n   stbi__flip_vertically_on_write = flag;\n}\n\ntypedef struct\n{\n   stbi_write_func *func;\n   void *context;\n   unsigned char buffer[64];\n   int buf_used;\n} stbi__write_context;\n\n// initialize a callback-based context\nstatic void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)\n{\n   s->func    = c;\n   s->context = context;\n}\n\n#ifndef STBI_WRITE_NO_STDIO\n\nstatic void stbi__stdio_write(void *context, void *data, int size)\n{\n   fwrite(data,1,size,(FILE*) context);\n}\n\n#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)\n#ifdef __cplusplus\n#define STBIW_EXTERN extern \"C\"\n#else\n#define STBIW_EXTERN extern\n#endif\nSTBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);\nSTBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);\n\nSTBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)\n{\n   return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);\n}\n#endif\n\nstatic FILE *stbiw__fopen(char const *filename, char const *mode)\n{\n   FILE *f;\n#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)\n   wchar_t wMode[64];\n   wchar_t wFilename[1024];\n   if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))\n      return 0;\n\n   if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))\n      return 0;\n\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n   if (0 != _wfopen_s(&f, wFilename, wMode))\n      f = 0;\n#else\n   f = _wfopen(wFilename, wMode);\n#endif\n\n#elif defined(_MSC_VER) && _MSC_VER >= 1400\n   if (0 != fopen_s(&f, filename, mode))\n      f=0;\n#else\n   f = fopen(filename, mode);\n#endif\n   return f;\n}\n\nstatic int stbi__start_write_file(stbi__write_context *s, const char *filename)\n{\n   FILE *f = stbiw__fopen(filename, \"wb\");\n   stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);\n   return f != NULL;\n}\n\nstatic void stbi__end_write_file(stbi__write_context *s)\n{\n   fclose((FILE *)s->context);\n}\n\n#endif // !STBI_WRITE_NO_STDIO\n\ntypedef unsigned int stbiw_uint32;\ntypedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];\n\nstatic void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)\n{\n   while (*fmt) {\n      switch (*fmt++) {\n         case ' ': break;\n         case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));\n                     s->func(s->context,&x,1);\n                     break; }\n         case '2': { int x = va_arg(v,int);\n                     unsigned char b[2];\n                     b[0] = STBIW_UCHAR(x);\n                     b[1] = STBIW_UCHAR(x>>8);\n                     s->func(s->context,b,2);\n                     break; }\n         case '4': { stbiw_uint32 x = va_arg(v,int);\n                     unsigned char b[4];\n                     b[0]=STBIW_UCHAR(x);\n                     b[1]=STBIW_UCHAR(x>>8);\n                     b[2]=STBIW_UCHAR(x>>16);\n                     b[3]=STBIW_UCHAR(x>>24);\n                     s->func(s->context,b,4);\n                     break; }\n         default:\n            STBIW_ASSERT(0);\n            return;\n      }\n   }\n}\n\nstatic void stbiw__writef(stbi__write_context *s, const char *fmt, ...)\n{\n   va_list v;\n   va_start(v, fmt);\n   stbiw__writefv(s, fmt, v);\n   va_end(v);\n}\n\nstatic void stbiw__write_flush(stbi__write_context *s)\n{\n   if (s->buf_used) {\n      s->func(s->context, &s->buffer, s->buf_used);\n      s->buf_used = 0;\n   }\n}\n\nstatic void stbiw__putc(stbi__write_context *s, unsigned char c)\n{\n   s->func(s->context, &c, 1);\n}\n\nstatic void stbiw__write1(stbi__write_context *s, unsigned char a)\n{\n   if ((size_t)s->buf_used + 1 > sizeof(s->buffer))\n      stbiw__write_flush(s);\n   s->buffer[s->buf_used++] = a;\n}\n\nstatic void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)\n{\n   int n;\n   if ((size_t)s->buf_used + 3 > sizeof(s->buffer))\n      stbiw__write_flush(s);\n   n = s->buf_used;\n   s->buf_used = n+3;\n   s->buffer[n+0] = a;\n   s->buffer[n+1] = b;\n   s->buffer[n+2] = c;\n}\n\nstatic void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)\n{\n   unsigned char bg[3] = { 255, 0, 255}, px[3];\n   int k;\n\n   if (write_alpha < 0)\n      stbiw__write1(s, d[comp - 1]);\n\n   switch (comp) {\n      case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case\n      case 1:\n         if (expand_mono)\n            stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp\n         else\n            stbiw__write1(s, d[0]);  // monochrome TGA\n         break;\n      case 4:\n         if (!write_alpha) {\n            // composite against pink background\n            for (k = 0; k < 3; ++k)\n               px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;\n            stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);\n            break;\n         }\n         /* FALLTHROUGH */\n      case 3:\n         stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);\n         break;\n   }\n   if (write_alpha > 0)\n      stbiw__write1(s, d[comp - 1]);\n}\n\nstatic void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)\n{\n   stbiw_uint32 zero = 0;\n   int i,j, j_end;\n\n   if (y <= 0)\n      return;\n\n   if (stbi__flip_vertically_on_write)\n      vdir *= -1;\n\n   if (vdir < 0) {\n      j_end = -1; j = y-1;\n   } else {\n      j_end =  y; j = 0;\n   }\n\n   for (; j != j_end; j += vdir) {\n      for (i=0; i < x; ++i) {\n         unsigned char *d = (unsigned char *) data + (j*x+i)*comp;\n         stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);\n      }\n      stbiw__write_flush(s);\n      s->func(s->context, &zero, scanline_pad);\n   }\n}\n\nstatic int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)\n{\n   if (y < 0 || x < 0) {\n      return 0;\n   } else {\n      va_list v;\n      va_start(v, fmt);\n      stbiw__writefv(s, fmt, v);\n      va_end(v);\n      stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);\n      return 1;\n   }\n}\n\nstatic int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)\n{\n   if (comp != 4) {\n      // write RGB bitmap\n      int pad = (-x*3) & 3;\n      return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,\n              \"11 4 22 4\" \"4 44 22 444444\",\n              'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40,  // file header\n               40, x,y, 1,24, 0,0,0,0,0,0);             // bitmap header\n   } else {\n      // RGBA bitmaps need a v4 header\n      // use BI_BITFIELDS mode with 32bpp and alpha mask\n      // (straight BI_RGB with alpha mask doesn't work in most readers)\n      return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0,\n         \"11 4 22 4\" \"4 44 22 444444 4444 4 444 444 444 444\",\n         'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header\n         108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header\n   }\n}\n\nSTBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_bmp_core(&s, x, y, comp, data);\n}\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_bmp_core(&s, x, y, comp, data);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif //!STBI_WRITE_NO_STDIO\n\nstatic int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)\n{\n   int has_alpha = (comp == 2 || comp == 4);\n   int colorbytes = has_alpha ? comp-1 : comp;\n   int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3\n\n   if (y < 0 || x < 0)\n      return 0;\n\n   if (!stbi_write_tga_with_rle) {\n      return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,\n         \"111 221 2222 11\", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);\n   } else {\n      int i,j,k;\n      int jend, jdir;\n\n      stbiw__writef(s, \"111 221 2222 11\", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);\n\n      if (stbi__flip_vertically_on_write) {\n         j = 0;\n         jend = y;\n         jdir = 1;\n      } else {\n         j = y-1;\n         jend = -1;\n         jdir = -1;\n      }\n      for (; j != jend; j += jdir) {\n         unsigned char *row = (unsigned char *) data + j * x * comp;\n         int len;\n\n         for (i = 0; i < x; i += len) {\n            unsigned char *begin = row + i * comp;\n            int diff = 1;\n            len = 1;\n\n            if (i < x - 1) {\n               ++len;\n               diff = memcmp(begin, row + (i + 1) * comp, comp);\n               if (diff) {\n                  const unsigned char *prev = begin;\n                  for (k = i + 2; k < x && len < 128; ++k) {\n                     if (memcmp(prev, row + k * comp, comp)) {\n                        prev += comp;\n                        ++len;\n                     } else {\n                        --len;\n                        break;\n                     }\n                  }\n               } else {\n                  for (k = i + 2; k < x && len < 128; ++k) {\n                     if (!memcmp(begin, row + k * comp, comp)) {\n                        ++len;\n                     } else {\n                        break;\n                     }\n                  }\n               }\n            }\n\n            if (diff) {\n               unsigned char header = STBIW_UCHAR(len - 1);\n               stbiw__write1(s, header);\n               for (k = 0; k < len; ++k) {\n                  stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);\n               }\n            } else {\n               unsigned char header = STBIW_UCHAR(len - 129);\n               stbiw__write1(s, header);\n               stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);\n            }\n         }\n      }\n      stbiw__write_flush(s);\n   }\n   return 1;\n}\n\nSTBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_tga_core(&s, x, y, comp, (void *) data);\n}\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif\n\n// *************************************************************************************************\n// Radiance RGBE HDR writer\n// by Baldur Karlsson\n\n#define stbiw__max(a, b)  ((a) > (b) ? (a) : (b))\n\n#ifndef STBI_WRITE_NO_STDIO\n\nstatic void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)\n{\n   int exponent;\n   float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));\n\n   if (maxcomp < 1e-32f) {\n      rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;\n   } else {\n      float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;\n\n      rgbe[0] = (unsigned char)(linear[0] * normalize);\n      rgbe[1] = (unsigned char)(linear[1] * normalize);\n      rgbe[2] = (unsigned char)(linear[2] * normalize);\n      rgbe[3] = (unsigned char)(exponent + 128);\n   }\n}\n\nstatic void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)\n{\n   unsigned char lengthbyte = STBIW_UCHAR(length+128);\n   STBIW_ASSERT(length+128 <= 255);\n   s->func(s->context, &lengthbyte, 1);\n   s->func(s->context, &databyte, 1);\n}\n\nstatic void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)\n{\n   unsigned char lengthbyte = STBIW_UCHAR(length);\n   STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code\n   s->func(s->context, &lengthbyte, 1);\n   s->func(s->context, data, length);\n}\n\nstatic void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)\n{\n   unsigned char scanlineheader[4] = { 2, 2, 0, 0 };\n   unsigned char rgbe[4];\n   float linear[3];\n   int x;\n\n   scanlineheader[2] = (width&0xff00)>>8;\n   scanlineheader[3] = (width&0x00ff);\n\n   /* skip RLE for images too small or large */\n   if (width < 8 || width >= 32768) {\n      for (x=0; x < width; x++) {\n         switch (ncomp) {\n            case 4: /* fallthrough */\n            case 3: linear[2] = scanline[x*ncomp + 2];\n                    linear[1] = scanline[x*ncomp + 1];\n                    linear[0] = scanline[x*ncomp + 0];\n                    break;\n            default:\n                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];\n                    break;\n         }\n         stbiw__linear_to_rgbe(rgbe, linear);\n         s->func(s->context, rgbe, 4);\n      }\n   } else {\n      int c,r;\n      /* encode into scratch buffer */\n      for (x=0; x < width; x++) {\n         switch(ncomp) {\n            case 4: /* fallthrough */\n            case 3: linear[2] = scanline[x*ncomp + 2];\n                    linear[1] = scanline[x*ncomp + 1];\n                    linear[0] = scanline[x*ncomp + 0];\n                    break;\n            default:\n                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];\n                    break;\n         }\n         stbiw__linear_to_rgbe(rgbe, linear);\n         scratch[x + width*0] = rgbe[0];\n         scratch[x + width*1] = rgbe[1];\n         scratch[x + width*2] = rgbe[2];\n         scratch[x + width*3] = rgbe[3];\n      }\n\n      s->func(s->context, scanlineheader, 4);\n\n      /* RLE each component separately */\n      for (c=0; c < 4; c++) {\n         unsigned char *comp = &scratch[width*c];\n\n         x = 0;\n         while (x < width) {\n            // find first run\n            r = x;\n            while (r+2 < width) {\n               if (comp[r] == comp[r+1] && comp[r] == comp[r+2])\n                  break;\n               ++r;\n            }\n            if (r+2 >= width)\n               r = width;\n            // dump up to first run\n            while (x < r) {\n               int len = r-x;\n               if (len > 128) len = 128;\n               stbiw__write_dump_data(s, len, &comp[x]);\n               x += len;\n            }\n            // if there's a run, output it\n            if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd\n               // find next byte after run\n               while (r < width && comp[r] == comp[x])\n                  ++r;\n               // output run up to r\n               while (x < r) {\n                  int len = r-x;\n                  if (len > 127) len = 127;\n                  stbiw__write_run_data(s, len, comp[x]);\n                  x += len;\n               }\n            }\n         }\n      }\n   }\n}\n\nstatic int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)\n{\n   if (y <= 0 || x <= 0 || data == NULL)\n      return 0;\n   else {\n      // Each component is stored separately. Allocate scratch space for full output scanline.\n      unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);\n      int i, len;\n      char buffer[128];\n      char header[] = \"#?RADIANCE\\n# Written by stb_image_write.h\\nFORMAT=32-bit_rle_rgbe\\n\";\n      s->func(s->context, header, sizeof(header)-1);\n\n#ifdef __STDC_LIB_EXT1__\n      len = sprintf_s(buffer, sizeof(buffer), \"EXPOSURE=          1.0000000000000\\n\\n-Y %d +X %d\\n\", y, x);\n#else\n      len = sprintf(buffer, \"EXPOSURE=          1.0000000000000\\n\\n-Y %d +X %d\\n\", y, x);\n#endif\n      s->func(s->context, buffer, len);\n\n      for(i=0; i < y; i++)\n         stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i));\n      STBIW_FREE(scratch);\n      return 1;\n   }\n}\n\nSTBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_hdr_core(&s, x, y, comp, (float *) data);\n}\n\nSTBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif // STBI_WRITE_NO_STDIO\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// PNG writer\n//\n\n#ifndef STBIW_ZLIB_COMPRESS\n// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()\n#define stbiw__sbraw(a) ((int *) (void *) (a) - 2)\n#define stbiw__sbm(a)   stbiw__sbraw(a)[0]\n#define stbiw__sbn(a)   stbiw__sbraw(a)[1]\n\n#define stbiw__sbneedgrow(a,n)  ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))\n#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)\n#define stbiw__sbgrow(a,n)  stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))\n\n#define stbiw__sbpush(a, v)      (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))\n#define stbiw__sbcount(a)        ((a) ? stbiw__sbn(a) : 0)\n#define stbiw__sbfree(a)         ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)\n\nstatic void *stbiw__sbgrowf(void **arr, int increment, int itemsize)\n{\n   int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;\n   void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);\n   STBIW_ASSERT(p);\n   if (p) {\n      if (!*arr) ((int *) p)[1] = 0;\n      *arr = (void *) ((int *) p + 2);\n      stbiw__sbm(*arr) = m;\n   }\n   return *arr;\n}\n\nstatic unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)\n{\n   while (*bitcount >= 8) {\n      stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));\n      *bitbuffer >>= 8;\n      *bitcount -= 8;\n   }\n   return data;\n}\n\nstatic int stbiw__zlib_bitrev(int code, int codebits)\n{\n   int res=0;\n   while (codebits--) {\n      res = (res << 1) | (code & 1);\n      code >>= 1;\n   }\n   return res;\n}\n\nstatic unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)\n{\n   int i;\n   for (i=0; i < limit && i < 258; ++i)\n      if (a[i] != b[i]) break;\n   return i;\n}\n\nstatic unsigned int stbiw__zhash(unsigned char *data)\n{\n   stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);\n   hash ^= hash << 3;\n   hash += hash >> 5;\n   hash ^= hash << 4;\n   hash += hash >> 17;\n   hash ^= hash << 25;\n   hash += hash >> 6;\n   return hash;\n}\n\n#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))\n#define stbiw__zlib_add(code,codebits) \\\n      (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())\n#define stbiw__zlib_huffa(b,c)  stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)\n// default huffman tables\n#define stbiw__zlib_huff1(n)  stbiw__zlib_huffa(0x30 + (n), 8)\n#define stbiw__zlib_huff2(n)  stbiw__zlib_huffa(0x190 + (n)-144, 9)\n#define stbiw__zlib_huff3(n)  stbiw__zlib_huffa(0 + (n)-256,7)\n#define stbiw__zlib_huff4(n)  stbiw__zlib_huffa(0xc0 + (n)-280,8)\n#define stbiw__zlib_huff(n)  ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n))\n#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))\n\n#define stbiw__ZHASH   16384\n\n#endif // STBIW_ZLIB_COMPRESS\n\nSTBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)\n{\n#ifdef STBIW_ZLIB_COMPRESS\n   // user provided a zlib compress implementation, use that\n   return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);\n#else // use builtin\n   static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };\n   static unsigned char  lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,  4,  5,  5,  5,  5,  0 };\n   static unsigned short distc[]   = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };\n   static unsigned char  disteb[]  = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };\n   unsigned int bitbuf=0;\n   int i,j, bitcount=0;\n   unsigned char *out = NULL;\n   unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**));\n   if (hash_table == NULL)\n      return NULL;\n   if (quality < 5) quality = 5;\n\n   stbiw__sbpush(out, 0x78);   // DEFLATE 32K window\n   stbiw__sbpush(out, 0x5e);   // FLEVEL = 1\n   stbiw__zlib_add(1,1);  // BFINAL = 1\n   stbiw__zlib_add(1,2);  // BTYPE = 1 -- fixed huffman\n\n   for (i=0; i < stbiw__ZHASH; ++i)\n      hash_table[i] = NULL;\n\n   i=0;\n   while (i < data_len-3) {\n      // hash next 3 bytes of data to be compressed\n      int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;\n      unsigned char *bestloc = 0;\n      unsigned char **hlist = hash_table[h];\n      int n = stbiw__sbcount(hlist);\n      for (j=0; j < n; ++j) {\n         if (hlist[j]-data > i-32768) { // if entry lies within window\n            int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);\n            if (d >= best) { best=d; bestloc=hlist[j]; }\n         }\n      }\n      // when hash table entry is too long, delete half the entries\n      if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {\n         STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);\n         stbiw__sbn(hash_table[h]) = quality;\n      }\n      stbiw__sbpush(hash_table[h],data+i);\n\n      if (bestloc) {\n         // \"lazy matching\" - check match at *next* byte, and if it's better, do cur byte as literal\n         h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);\n         hlist = hash_table[h];\n         n = stbiw__sbcount(hlist);\n         for (j=0; j < n; ++j) {\n            if (hlist[j]-data > i-32767) {\n               int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);\n               if (e > best) { // if next match is better, bail on current match\n                  bestloc = NULL;\n                  break;\n               }\n            }\n         }\n      }\n\n      if (bestloc) {\n         int d = (int) (data+i - bestloc); // distance back\n         STBIW_ASSERT(d <= 32767 && best <= 258);\n         for (j=0; best > lengthc[j+1]-1; ++j);\n         stbiw__zlib_huff(j+257);\n         if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);\n         for (j=0; d > distc[j+1]-1; ++j);\n         stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);\n         if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);\n         i += best;\n      } else {\n         stbiw__zlib_huffb(data[i]);\n         ++i;\n      }\n   }\n   // write out final bytes\n   for (;i < data_len; ++i)\n      stbiw__zlib_huffb(data[i]);\n   stbiw__zlib_huff(256); // end of block\n   // pad with 0 bits to byte boundary\n   while (bitcount)\n      stbiw__zlib_add(0,1);\n\n   for (i=0; i < stbiw__ZHASH; ++i)\n      (void) stbiw__sbfree(hash_table[i]);\n   STBIW_FREE(hash_table);\n\n   // store uncompressed instead if compression was worse\n   if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) {\n      stbiw__sbn(out) = 2;  // truncate to DEFLATE 32K window and FLEVEL = 1\n      for (j = 0; j < data_len;) {\n         int blocklen = data_len - j;\n         if (blocklen > 32767) blocklen = 32767;\n         stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression\n         stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN\n         stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8));\n         stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN\n         stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8));\n         memcpy(out+stbiw__sbn(out), data+j, blocklen);\n         stbiw__sbn(out) += blocklen;\n         j += blocklen;\n      }\n   }\n\n   {\n      // compute adler32 on input\n      unsigned int s1=1, s2=0;\n      int blocklen = (int) (data_len % 5552);\n      j=0;\n      while (j < data_len) {\n         for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; }\n         s1 %= 65521; s2 %= 65521;\n         j += blocklen;\n         blocklen = 5552;\n      }\n      stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));\n      stbiw__sbpush(out, STBIW_UCHAR(s2));\n      stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));\n      stbiw__sbpush(out, STBIW_UCHAR(s1));\n   }\n   *out_len = stbiw__sbn(out);\n   // make returned pointer freeable\n   STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);\n   return (unsigned char *) stbiw__sbraw(out);\n#endif // STBIW_ZLIB_COMPRESS\n}\n\nstatic unsigned int stbiw__crc32(unsigned char *buffer, int len)\n{\n#ifdef STBIW_CRC32\n    return STBIW_CRC32(buffer, len);\n#else\n   static unsigned int crc_table[256] =\n   {\n      0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,\n      0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,\n      0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,\n      0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,\n      0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,\n      0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,\n      0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,\n      0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,\n      0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,\n      0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,\n      0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,\n      0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,\n      0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,\n      0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,\n      0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,\n      0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,\n      0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,\n      0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,\n      0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,\n      0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,\n      0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,\n      0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,\n      0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,\n      0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,\n      0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,\n      0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,\n      0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,\n      0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,\n      0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,\n      0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,\n      0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,\n      0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D\n   };\n\n   unsigned int crc = ~0u;\n   int i;\n   for (i=0; i < len; ++i)\n      crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];\n   return ~crc;\n#endif\n}\n\n#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)\n#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));\n#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])\n\nstatic void stbiw__wpcrc(unsigned char **data, int len)\n{\n   unsigned int crc = stbiw__crc32(*data - len - 4, len+4);\n   stbiw__wp32(*data, crc);\n}\n\nstatic unsigned char stbiw__paeth(int a, int b, int c)\n{\n   int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);\n   if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);\n   if (pb <= pc) return STBIW_UCHAR(b);\n   return STBIW_UCHAR(c);\n}\n\n// @OPTIMIZE: provide an option that always forces left-predict or paeth predict\nstatic void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer)\n{\n   static int mapping[] = { 0,1,2,3,4 };\n   static int firstmap[] = { 0,1,0,5,6 };\n   int *mymap = (y != 0) ? mapping : firstmap;\n   int i;\n   int type = mymap[filter_type];\n   unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);\n   int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;\n\n   if (type==0) {\n      memcpy(line_buffer, z, width*n);\n      return;\n   }\n\n   // first loop isn't optimized since it's just one pixel\n   for (i = 0; i < n; ++i) {\n      switch (type) {\n         case 1: line_buffer[i] = z[i]; break;\n         case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break;\n         case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break;\n         case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break;\n         case 5: line_buffer[i] = z[i]; break;\n         case 6: line_buffer[i] = z[i]; break;\n      }\n   }\n   switch (type) {\n      case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break;\n      case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break;\n      case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break;\n      case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break;\n      case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break;\n      case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;\n   }\n}\n\nSTBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)\n{\n   int force_filter = stbi_write_force_png_filter;\n   int ctype[5] = { -1, 0, 4, 2, 6 };\n   unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };\n   unsigned char *out,*o, *filt, *zlib;\n   signed char *line_buffer;\n   int j,zlen;\n\n   if (stride_bytes == 0)\n      stride_bytes = x * n;\n\n   if (force_filter >= 5) {\n      force_filter = -1;\n   }\n\n   filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;\n   line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }\n   for (j=0; j < y; ++j) {\n      int filter_type;\n      if (force_filter > -1) {\n         filter_type = force_filter;\n         stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer);\n      } else { // Estimate the best filter by running through all of them:\n         int best_filter = 0, best_filter_val = 0x7fffffff, est, i;\n         for (filter_type = 0; filter_type < 5; filter_type++) {\n            stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer);\n\n            // Estimate the entropy of the line using this filter; the less, the better.\n            est = 0;\n            for (i = 0; i < x*n; ++i) {\n               est += abs((signed char) line_buffer[i]);\n            }\n            if (est < best_filter_val) {\n               best_filter_val = est;\n               best_filter = filter_type;\n            }\n         }\n         if (filter_type != best_filter) {  // If the last iteration already got us the best filter, don't redo it\n            stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer);\n            filter_type = best_filter;\n         }\n      }\n      // when we get here, filter_type contains the filter type, and line_buffer contains the data\n      filt[j*(x*n+1)] = (unsigned char) filter_type;\n      STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);\n   }\n   STBIW_FREE(line_buffer);\n   zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level);\n   STBIW_FREE(filt);\n   if (!zlib) return 0;\n\n   // each tag requires 12 bytes of overhead\n   out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);\n   if (!out) return 0;\n   *out_len = 8 + 12+13 + 12+zlen + 12;\n\n   o=out;\n   STBIW_MEMMOVE(o,sig,8); o+= 8;\n   stbiw__wp32(o, 13); // header length\n   stbiw__wptag(o, \"IHDR\");\n   stbiw__wp32(o, x);\n   stbiw__wp32(o, y);\n   *o++ = 8;\n   *o++ = STBIW_UCHAR(ctype[n]);\n   *o++ = 0;\n   *o++ = 0;\n   *o++ = 0;\n   stbiw__wpcrc(&o,13);\n\n   stbiw__wp32(o, zlen);\n   stbiw__wptag(o, \"IDAT\");\n   STBIW_MEMMOVE(o, zlib, zlen);\n   o += zlen;\n   STBIW_FREE(zlib);\n   stbiw__wpcrc(&o, zlen);\n\n   stbiw__wp32(o,0);\n   stbiw__wptag(o, \"IEND\");\n   stbiw__wpcrc(&o,0);\n\n   STBIW_ASSERT(o == out + *out_len);\n\n   return out;\n}\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)\n{\n   FILE *f;\n   int len;\n   unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);\n   if (png == NULL) return 0;\n\n   f = stbiw__fopen(filename, \"wb\");\n   if (!f) { STBIW_FREE(png); return 0; }\n   fwrite(png, 1, len, f);\n   fclose(f);\n   STBIW_FREE(png);\n   return 1;\n}\n#endif\n\nSTBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)\n{\n   int len;\n   unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);\n   if (png == NULL) return 0;\n   func(context, png, len);\n   STBIW_FREE(png);\n   return 1;\n}\n\n\n/* ***************************************************************************\n *\n * JPEG writer\n *\n * This is based on Jon Olick's jo_jpeg.cpp:\n * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html\n */\n\nstatic const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,\n      24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 };\n\nstatic void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) {\n   int bitBuf = *bitBufP, bitCnt = *bitCntP;\n   bitCnt += bs[1];\n   bitBuf |= bs[0] << (24 - bitCnt);\n   while(bitCnt >= 8) {\n      unsigned char c = (bitBuf >> 16) & 255;\n      stbiw__putc(s, c);\n      if(c == 255) {\n         stbiw__putc(s, 0);\n      }\n      bitBuf <<= 8;\n      bitCnt -= 8;\n   }\n   *bitBufP = bitBuf;\n   *bitCntP = bitCnt;\n}\n\nstatic void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) {\n   float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p;\n   float z1, z2, z3, z4, z5, z11, z13;\n\n   float tmp0 = d0 + d7;\n   float tmp7 = d0 - d7;\n   float tmp1 = d1 + d6;\n   float tmp6 = d1 - d6;\n   float tmp2 = d2 + d5;\n   float tmp5 = d2 - d5;\n   float tmp3 = d3 + d4;\n   float tmp4 = d3 - d4;\n\n   // Even part\n   float tmp10 = tmp0 + tmp3;   // phase 2\n   float tmp13 = tmp0 - tmp3;\n   float tmp11 = tmp1 + tmp2;\n   float tmp12 = tmp1 - tmp2;\n\n   d0 = tmp10 + tmp11;       // phase 3\n   d4 = tmp10 - tmp11;\n\n   z1 = (tmp12 + tmp13) * 0.707106781f; // c4\n   d2 = tmp13 + z1;       // phase 5\n   d6 = tmp13 - z1;\n\n   // Odd part\n   tmp10 = tmp4 + tmp5;       // phase 2\n   tmp11 = tmp5 + tmp6;\n   tmp12 = tmp6 + tmp7;\n\n   // The rotator is modified from fig 4-8 to avoid extra negations.\n   z5 = (tmp10 - tmp12) * 0.382683433f; // c6\n   z2 = tmp10 * 0.541196100f + z5; // c2-c6\n   z4 = tmp12 * 1.306562965f + z5; // c2+c6\n   z3 = tmp11 * 0.707106781f; // c4\n\n   z11 = tmp7 + z3;      // phase 5\n   z13 = tmp7 - z3;\n\n   *d5p = z13 + z2;         // phase 6\n   *d3p = z13 - z2;\n   *d1p = z11 + z4;\n   *d7p = z11 - z4;\n\n   *d0p = d0;  *d2p = d2;  *d4p = d4;  *d6p = d6;\n}\n\nstatic void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {\n   int tmp1 = val < 0 ? -val : val;\n   val = val < 0 ? val-1 : val;\n   bits[1] = 1;\n   while(tmp1 >>= 1) {\n      ++bits[1];\n   }\n   bits[0] = val & ((1<<bits[1])-1);\n}\n\nstatic int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, int du_stride, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {\n   const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };\n   const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };\n   int dataOff, i, j, n, diff, end0pos, x, y;\n   int DU[64];\n\n   // DCT rows\n   for(dataOff=0, n=du_stride*8; dataOff<n; dataOff+=du_stride) {\n      stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);\n   }\n   // DCT columns\n   for(dataOff=0; dataOff<8; ++dataOff) {\n      stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+du_stride], &CDU[dataOff+du_stride*2], &CDU[dataOff+du_stride*3], &CDU[dataOff+du_stride*4],\n                     &CDU[dataOff+du_stride*5], &CDU[dataOff+du_stride*6], &CDU[dataOff+du_stride*7]);\n   }\n   // Quantize/descale/zigzag the coefficients\n   for(y = 0, j=0; y < 8; ++y) {\n      for(x = 0; x < 8; ++x,++j) {\n         float v;\n         i = y*du_stride+x;\n         v = CDU[i]*fdtbl[j];\n         // DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));\n         // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?\n         DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);\n      }\n   }\n\n   // Encode DC\n   diff = DU[0] - DC;\n   if (diff == 0) {\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);\n   } else {\n      unsigned short bits[2];\n      stbiw__jpg_calcBits(diff, bits);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);\n   }\n   // Encode ACs\n   end0pos = 63;\n   for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) {\n   }\n   // end0pos = first element in reverse order !=0\n   if(end0pos == 0) {\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);\n      return DU[0];\n   }\n   for(i = 1; i <= end0pos; ++i) {\n      int startpos = i;\n      int nrzeroes;\n      unsigned short bits[2];\n      for (; DU[i]==0 && i<=end0pos; ++i) {\n      }\n      nrzeroes = i-startpos;\n      if ( nrzeroes >= 16 ) {\n         int lng = nrzeroes>>4;\n         int nrmarker;\n         for (nrmarker=1; nrmarker <= lng; ++nrmarker)\n            stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes);\n         nrzeroes &= 15;\n      }\n      stbiw__jpg_calcBits(DU[i], bits);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);\n   }\n   if(end0pos != 63) {\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);\n   }\n   return DU[0];\n}\n\nstatic int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) {\n   // Constants that don't pollute global namespace\n   static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};\n   static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};\n   static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};\n   static const unsigned char std_ac_luminance_values[] = {\n      0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,\n      0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,\n      0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,\n      0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,\n      0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,\n      0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,\n      0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa\n   };\n   static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0};\n   static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};\n   static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77};\n   static const unsigned char std_ac_chrominance_values[] = {\n      0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,\n      0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,\n      0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,\n      0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,\n      0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,\n      0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,\n      0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa\n   };\n   // Huffman tables\n   static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}};\n   static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}};\n   static const unsigned short YAC_HT[256][2] = {\n      {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}\n   };\n   static const unsigned short UVAC_HT[256][2] = {\n      {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}\n   };\n   static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22,\n                             37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99};\n   static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,\n                              99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99};\n   static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,\n                                 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };\n\n   int row, col, i, k, subsample;\n   float fdtbl_Y[64], fdtbl_UV[64];\n   unsigned char YTable[64], UVTable[64];\n\n   if(!data || !width || !height || comp > 4 || comp < 1) {\n      return 0;\n   }\n\n   quality = quality ? quality : 90;\n   subsample = quality <= 90 ? 1 : 0;\n   quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;\n   quality = quality < 50 ? 5000 / quality : 200 - quality * 2;\n\n   for(i = 0; i < 64; ++i) {\n      int uvti, yti = (YQT[i]*quality+50)/100;\n      YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti);\n      uvti = (UVQT[i]*quality+50)/100;\n      UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti);\n   }\n\n   for(row = 0, k = 0; row < 8; ++row) {\n      for(col = 0; col < 8; ++col, ++k) {\n         fdtbl_Y[k]  = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);\n         fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);\n      }\n   }\n\n   // Write Headers\n   {\n      static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };\n      static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };\n      const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),\n                                      3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };\n      s->func(s->context, (void*)head0, sizeof(head0));\n      s->func(s->context, (void*)YTable, sizeof(YTable));\n      stbiw__putc(s, 1);\n      s->func(s->context, UVTable, sizeof(UVTable));\n      s->func(s->context, (void*)head1, sizeof(head1));\n      s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1);\n      s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values));\n      stbiw__putc(s, 0x10); // HTYACinfo\n      s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1);\n      s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values));\n      stbiw__putc(s, 1); // HTUDCinfo\n      s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1);\n      s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values));\n      stbiw__putc(s, 0x11); // HTUACinfo\n      s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1);\n      s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values));\n      s->func(s->context, (void*)head2, sizeof(head2));\n   }\n\n   // Encode 8x8 macroblocks\n   {\n      static const unsigned short fillBits[] = {0x7F, 7};\n      int DCY=0, DCU=0, DCV=0;\n      int bitBuf=0, bitCnt=0;\n      // comp == 2 is grey+alpha (alpha is ignored)\n      int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;\n      const unsigned char *dataR = (const unsigned char *)data;\n      const unsigned char *dataG = dataR + ofsG;\n      const unsigned char *dataB = dataR + ofsB;\n      int x, y, pos;\n      if(subsample) {\n         for(y = 0; y < height; y += 16) {\n            for(x = 0; x < width; x += 16) {\n               float Y[256], U[256], V[256];\n               for(row = y, pos = 0; row < y+16; ++row) {\n                  // row >= height => use last input row\n                  int clamped_row = (row < height) ? row : height - 1;\n                  int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;\n                  for(col = x; col < x+16; ++col, ++pos) {\n                     // if col >= width => use pixel from last input column\n                     int p = base_p + ((col < width) ? col : (width-1))*comp;\n                     float r = dataR[p], g = dataG[p], b = dataB[p];\n                     Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;\n                     U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;\n                     V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;\n                  }\n               }\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0,   16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8,   16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n\n               // subsample U,V\n               {\n                  float subU[64], subV[64];\n                  int yy, xx;\n                  for(yy = 0, pos = 0; yy < 8; ++yy) {\n                     for(xx = 0; xx < 8; ++xx, ++pos) {\n                        int j = yy*32+xx*2;\n                        subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f;\n                        subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f;\n                     }\n                  }\n                  DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);\n                  DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);\n               }\n            }\n         }\n      } else {\n         for(y = 0; y < height; y += 8) {\n            for(x = 0; x < width; x += 8) {\n               float Y[64], U[64], V[64];\n               for(row = y, pos = 0; row < y+8; ++row) {\n                  // row >= height => use last input row\n                  int clamped_row = (row < height) ? row : height - 1;\n                  int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;\n                  for(col = x; col < x+8; ++col, ++pos) {\n                     // if col >= width => use pixel from last input column\n                     int p = base_p + ((col < width) ? col : (width-1))*comp;\n                     float r = dataR[p], g = dataG[p], b = dataB[p];\n                     Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;\n                     U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;\n                     V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;\n                  }\n               }\n\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y,  DCY, YDC_HT, YAC_HT);\n               DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);\n               DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);\n            }\n         }\n      }\n\n      // Do the bit alignment of the EOI marker\n      stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);\n   }\n\n   // EOI\n   stbiw__putc(s, 0xFF);\n   stbiw__putc(s, 0xD9);\n\n   return 1;\n}\n\nSTBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);\n}\n\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif\n\n#endif // STB_IMAGE_WRITE_IMPLEMENTATION\n\n/* Revision history\n      1.16  (2021-07-11)\n             make Deflate code emit uncompressed blocks when it would otherwise expand\n             support writing BMPs with alpha channel\n      1.15  (2020-07-13) unknown\n      1.14  (2020-02-02) updated JPEG writer to downsample chroma channels\n      1.13\n      1.12\n      1.11  (2019-08-11)\n\n      1.10  (2019-02-07)\n             support utf8 filenames in Windows; fix warnings and platform ifdefs\n      1.09  (2018-02-11)\n             fix typo in zlib quality API, improve STB_I_W_STATIC in C++\n      1.08  (2018-01-29)\n             add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter\n      1.07  (2017-07-24)\n             doc fix\n      1.06 (2017-07-23)\n             writing JPEG (using Jon Olick's code)\n      1.05   ???\n      1.04 (2017-03-03)\n             monochrome BMP expansion\n      1.03   ???\n      1.02 (2016-04-02)\n             avoid allocating large structures on the stack\n      1.01 (2016-01-16)\n             STBIW_REALLOC_SIZED: support allocators with no realloc support\n             avoid race-condition in crc initialization\n             minor compile issues\n      1.00 (2015-09-14)\n             installable file IO function\n      0.99 (2015-09-13)\n             warning fixes; TGA rle support\n      0.98 (2015-04-08)\n             added STBIW_MALLOC, STBIW_ASSERT etc\n      0.97 (2015-01-18)\n             fixed HDR asserts, rewrote HDR rle logic\n      0.96 (2015-01-17)\n             add HDR output\n             fix monochrome BMP\n      0.95 (2014-08-17)\n             add monochrome TGA output\n      0.94 (2014-05-31)\n             rename private functions to avoid conflicts with stb_image.h\n      0.93 (2014-05-27)\n             warning fixes\n      0.92 (2010-08-01)\n             casts to unsigned char to fix warnings\n      0.91 (2010-07-17)\n             first public release\n      0.90   first internal release\n*/\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "External/stb/stb_sprintf.h",
    "content": "// stb_sprintf - v1.09 - public domain snprintf() implementation\n// originally by Jeff Roberts / RAD Game Tools, 2015/10/20\n// http://github.com/nothings/stb\n//\n// allowed types:  sc uidBboXx p AaGgEef n\n// lengths      :  hh h ll j z t I64 I32 I\n//\n// Contributors:\n//    Fabian \"ryg\" Giesen (reformatting)\n//\n// Contributors (bugfixes):\n//    github:d26435\n//    github:trex78\n//    github:account-login\n//    Jari Komppa (SI suffixes)\n//    Rohit Nirmal\n//    Marcin Wojdyr\n//    Leonard Ritter\n//    Stefano Zanotti\n//    Adam Allison\n//    Arvid Gerstmann\n//    Markus Kolb\n//\n// LICENSE:\n//\n//   See end of file for license information.\n\n#ifndef STB_SPRINTF_H_INCLUDE\n#define STB_SPRINTF_H_INCLUDE\n\n/*\nSingle file sprintf replacement.\n\nOriginally written by Jeff Roberts at RAD Game Tools - 2015/10/20.\nHereby placed in public domain.\n\nThis is a full sprintf replacement that supports everything that\nthe C runtime sprintfs support, including float/double, 64-bit integers,\nhex floats, field parameters (%*.*d stuff), length reads backs, etc.\n\nWhy would you need this if sprintf already exists?  Well, first off,\nit's *much* faster (see below). It's also much smaller than the CRT\nversions code-space-wise. We've also added some simple improvements\nthat are super handy (commas in thousands, callbacks at buffer full,\nfor example). Finally, the format strings for MSVC and GCC differ\nfor 64-bit integers (among other small things), so this lets you use\nthe same format strings in cross platform code.\n\nIt uses the standard single file trick of being both the header file\nand the source itself. If you just include it normally, you just get\nthe header file function definitions. To get the code, you include\nit from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first.\n\nIt only uses va_args macros from the C runtime to do it's work. It\ndoes cast doubles to S64s and shifts and divides U64s, which does\ndrag in CRT code on most platforms.\n\nIt compiles to roughly 8K with float support, and 4K without.\nAs a comparison, when using MSVC static libs, calling sprintf drags\nin 16K.\n\nAPI:\n====\nint stbsp_sprintf( char * buf, char const * fmt, ... )\nint stbsp_snprintf( char * buf, int count, char const * fmt, ... )\n  Convert an arg list into a buffer.  stbsp_snprintf always returns\n  a zero-terminated string (unlike regular snprintf).\n\nint stbsp_vsprintf( char * buf, char const * fmt, va_list va )\nint stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va )\n  Convert a va_list arg list into a buffer.  stbsp_vsnprintf always returns\n  a zero-terminated string (unlike regular snprintf).\n\nint stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va )\n    typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len );\n  Convert into a buffer, calling back every STB_SPRINTF_MIN chars.\n  Your callback can then copy the chars out, print them or whatever.\n  This function is actually the workhorse for everything else.\n  The buffer you pass in must hold at least STB_SPRINTF_MIN characters.\n    // you return the next buffer to use or 0 to stop converting\n\nvoid stbsp_set_separators( char comma, char period )\n  Set the comma and period characters to use.\n\nFLOATS/DOUBLES:\n===============\nThis code uses a internal float->ascii conversion method that uses\ndoubles with error correction (double-doubles, for ~105 bits of\nprecision).  This conversion is round-trip perfect - that is, an atof\nof the values output here will give you the bit-exact double back.\n\nOne difference is that our insignificant digits will be different than\nwith MSVC or GCC (but they don't match each other either).  We also\ndon't attempt to find the minimum length matching float (pre-MSVC15\ndoesn't either).\n\nIf you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT\nand you'll save 4K of code space.\n\n64-BIT INTS:\n============\nThis library also supports 64-bit integers and you can use MSVC style or\nGCC style indicators (%I64d or %lld).  It supports the C99 specifiers\nfor size_t and ptr_diff_t (%jd %zd) as well.\n\nEXTRAS:\n=======\nLike some GCCs, for integers and floats, you can use a ' (single quote)\nspecifier and commas will be inserted on the thousands: \"%'d\" on 12345\nwould print 12,345.\n\nFor integers and floats, you can use a \"$\" specifier and the number\nwill be converted to float and then divided to get kilo, mega, giga or\ntera and then printed, so \"%$d\" 1000 is \"1.0 k\", \"%$.2d\" 2536000 is\n\"2.53 M\", etc. For byte values, use two $:s, like \"%$$d\" to turn\n2536000 to \"2.42 Mi\". If you prefer JEDEC suffixes to SI ones, use three\n$:s: \"%$$$d\" -> \"2.42 M\". To remove the space between the number and the\nsuffix, add \"_\" specifier: \"%_$d\" -> \"2.53M\".\n\nIn addition to octal and hexadecimal conversions, you can print\nintegers in binary: \"%b\" for 256 would print 100.\n\nPERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC):\n===================================================================\n\"%d\" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC)\n\"%24d\" across all 32-bit ints (4.5x/4.2x faster)\n\"%x\" across all 32-bit ints (4.5x/3.8x faster)\n\"%08x\" across all 32-bit ints (4.3x/3.8x faster)\n\"%f\" across e-10 to e+10 floats (7.3x/6.0x faster)\n\"%e\" across e-10 to e+10 floats (8.1x/6.0x faster)\n\"%g\" across e-10 to e+10 floats (10.0x/7.1x faster)\n\"%f\" for values near e-300 (7.9x/6.5x faster)\n\"%f\" for values near e+300 (10.0x/9.1x faster)\n\"%e\" for values near e-300 (10.1x/7.0x faster)\n\"%e\" for values near e+300 (9.2x/6.0x faster)\n\"%.320f\" for values near e-300 (12.6x/11.2x faster)\n\"%a\" for random values (8.6x/4.3x faster)\n\"%I64d\" for 64-bits with 32-bit values (4.8x/3.4x faster)\n\"%I64d\" for 64-bits > 32-bit values (4.9x/5.5x faster)\n\"%s%s%s\" for 64 char strings (7.1x/7.3x faster)\n\"...512 char string...\" ( 35.0x/32.5x faster!)\n*/\n\n#if defined(__clang__)\n #if defined(__has_feature) && defined(__has_attribute)\n  #if __has_feature(address_sanitizer)\n   #if __has_attribute(__no_sanitize__)\n    #define STBSP__ASAN __attribute__((__no_sanitize__(\"address\")))\n   #elif __has_attribute(__no_sanitize_address__)\n    #define STBSP__ASAN __attribute__((__no_sanitize_address__))\n   #elif __has_attribute(__no_address_safety_analysis__)\n    #define STBSP__ASAN __attribute__((__no_address_safety_analysis__))\n   #endif\n  #endif\n #endif\n#elif __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)\n #if __SANITIZE_ADDRESS__\n  #define STBSP__ASAN __attribute__((__no_sanitize_address__))\n #endif\n#endif\n\n#ifndef STBSP__ASAN\n#define STBSP__ASAN\n#endif\n\n#ifdef STB_SPRINTF_STATIC\n#define STBSP__PUBLICDEC static\n#define STBSP__PUBLICDEF static STBSP__ASAN\n#else\n#ifdef __cplusplus\n#define STBSP__PUBLICDEC extern \"C\"\n#define STBSP__PUBLICDEF extern \"C\" STBSP__ASAN\n#else\n#define STBSP__PUBLICDEC extern\n#define STBSP__PUBLICDEF STBSP__ASAN\n#endif\n#endif\n\n#include <stdarg.h> // for va_list()\n#include <stddef.h> // size_t, ptrdiff_t\n\n#ifndef STB_SPRINTF_MIN\n#define STB_SPRINTF_MIN 512 // how many characters per callback\n#endif\ntypedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len);\n\n#ifndef STB_SPRINTF_DECORATE\n#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names\n#endif\n\nSTBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va);\nSTBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va);\nSTBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...);\nSTBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...);\n\nSTBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va);\nSTBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char comma, char period);\n\n#endif // STB_SPRINTF_H_INCLUDE\n\n#ifdef STB_SPRINTF_IMPLEMENTATION\n\n#include <stdlib.h> // for va_arg()\n\n#define stbsp__uint32 unsigned int\n#define stbsp__int32 signed int\n\n#ifdef _MSC_VER\n#define stbsp__uint64 unsigned __int64\n#define stbsp__int64 signed __int64\n#else\n#define stbsp__uint64 unsigned long long\n#define stbsp__int64 signed long long\n#endif\n#define stbsp__uint16 unsigned short\n\n#ifndef stbsp__uintptr\n#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64)\n#define stbsp__uintptr stbsp__uint64\n#else\n#define stbsp__uintptr stbsp__uint32\n#endif\n#endif\n\n#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC)\n#if defined(_MSC_VER) && (_MSC_VER < 1900)\n#define STB_SPRINTF_MSVC_MODE\n#endif\n#endif\n\n#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses\n#define STBSP__UNALIGNED(code)\n#else\n#define STBSP__UNALIGNED(code) code\n#endif\n\n#ifndef STB_SPRINTF_NOFLOAT\n// internal float utility functions\nstatic stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits);\nstatic stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value);\n#define STBSP__SPECIAL 0x7000\n#endif\n\nstatic char stbsp__period = '.';\nstatic char stbsp__comma = ',';\nstatic struct\n{\n   short temp; // force next field to be 2-byte aligned\n   char pair[201];\n} stbsp__digitpair =\n{\n  0,\n   \"00010203040506070809101112131415161718192021222324\"\n   \"25262728293031323334353637383940414243444546474849\"\n   \"50515253545556575859606162636465666768697071727374\"\n   \"75767778798081828384858687888990919293949596979899\"\n};\n\nSTBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod)\n{\n   stbsp__period = pperiod;\n   stbsp__comma = pcomma;\n}\n\n#define STBSP__LEFTJUST 1\n#define STBSP__LEADINGPLUS 2\n#define STBSP__LEADINGSPACE 4\n#define STBSP__LEADING_0X 8\n#define STBSP__LEADINGZERO 16\n#define STBSP__INTMAX 32\n#define STBSP__TRIPLET_COMMA 64\n#define STBSP__NEGATIVE 128\n#define STBSP__METRIC_SUFFIX 256\n#define STBSP__HALFWIDTH 512\n#define STBSP__METRIC_NOSPACE 1024\n#define STBSP__METRIC_1024 2048\n#define STBSP__METRIC_JEDEC 4096\n\nstatic void stbsp__lead_sign(stbsp__uint32 fl, char *sign)\n{\n   sign[0] = 0;\n   if (fl & STBSP__NEGATIVE) {\n      sign[0] = 1;\n      sign[1] = '-';\n   } else if (fl & STBSP__LEADINGSPACE) {\n      sign[0] = 1;\n      sign[1] = ' ';\n   } else if (fl & STBSP__LEADINGPLUS) {\n      sign[0] = 1;\n      sign[1] = '+';\n   }\n}\n\nSTBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va)\n{\n   static char hex[] = \"0123456789abcdefxp\";\n   static char hexu[] = \"0123456789ABCDEFXP\";\n   char *bf;\n   char const *f;\n   int tlen = 0;\n\n   bf = buf;\n   f = fmt;\n   for (;;) {\n      stbsp__int32 fw, pr, tz;\n      stbsp__uint32 fl;\n\n      // macros for the callback buffer stuff\n      #define stbsp__chk_cb_bufL(bytes)                        \\\n         {                                                     \\\n            int len = (int)(bf - buf);                         \\\n            if ((len + (bytes)) >= STB_SPRINTF_MIN) {          \\\n               tlen += len;                                    \\\n               if (0 == (bf = buf = callback(buf, user, len))) \\\n                  goto done;                                   \\\n            }                                                  \\\n         }\n      #define stbsp__chk_cb_buf(bytes)    \\\n         {                                \\\n            if (callback) {               \\\n               stbsp__chk_cb_bufL(bytes); \\\n            }                             \\\n         }\n      #define stbsp__flush_cb()                      \\\n         {                                           \\\n            stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \\\n         } // flush if there is even one byte in the buffer\n      #define stbsp__cb_buf_clamp(cl, v)                \\\n         cl = v;                                        \\\n         if (callback) {                                \\\n            int lg = STB_SPRINTF_MIN - (int)(bf - buf); \\\n            if (cl > lg)                                \\\n               cl = lg;                                 \\\n         }\n\n      // fast copy everything up to the next % (or end of string)\n      for (;;) {\n         while (((stbsp__uintptr)f) & 3) {\n         schk1:\n            if (f[0] == '%')\n               goto scandd;\n         schk2:\n            if (f[0] == 0)\n               goto endfmt;\n            stbsp__chk_cb_buf(1);\n            *bf++ = f[0];\n            ++f;\n         }\n         for (;;) {\n            // Check if the next 4 bytes contain %(0x25) or end of string.\n            // Using the 'hasless' trick:\n            // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord\n            stbsp__uint32 v, c;\n            v = *(stbsp__uint32 *)f;\n            c = (~v) & 0x80808080;\n            if (((v ^ 0x25252525) - 0x01010101) & c)\n               goto schk1;\n            if ((v - 0x01010101) & c)\n               goto schk2;\n            if (callback)\n               if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4)\n                  goto schk1;\n            #ifdef STB_SPRINTF_NOUNALIGNED\n                if(((stbsp__uintptr)bf) & 3) {\n                    bf[0] = f[0];\n                    bf[1] = f[1];\n                    bf[2] = f[2];\n                    bf[3] = f[3];\n                } else\n            #endif\n            {\n                *(stbsp__uint32 *)bf = v;\n            }\n            bf += 4;\n            f += 4;\n         }\n      }\n   scandd:\n\n      ++f;\n\n      // ok, we have a percent, read the modifiers first\n      fw = 0;\n      pr = -1;\n      fl = 0;\n      tz = 0;\n\n      // flags\n      for (;;) {\n         switch (f[0]) {\n         // if we have left justify\n         case '-':\n            fl |= STBSP__LEFTJUST;\n            ++f;\n            continue;\n         // if we have leading plus\n         case '+':\n            fl |= STBSP__LEADINGPLUS;\n            ++f;\n            continue;\n         // if we have leading space\n         case ' ':\n            fl |= STBSP__LEADINGSPACE;\n            ++f;\n            continue;\n         // if we have leading 0x\n         case '#':\n            fl |= STBSP__LEADING_0X;\n            ++f;\n            continue;\n         // if we have thousand commas\n         case '\\'':\n            fl |= STBSP__TRIPLET_COMMA;\n            ++f;\n            continue;\n         // if we have kilo marker (none->kilo->kibi->jedec)\n         case '$':\n            if (fl & STBSP__METRIC_SUFFIX) {\n               if (fl & STBSP__METRIC_1024) {\n                  fl |= STBSP__METRIC_JEDEC;\n               } else {\n                  fl |= STBSP__METRIC_1024;\n               }\n            } else {\n               fl |= STBSP__METRIC_SUFFIX;\n            }\n            ++f;\n            continue;\n         // if we don't want space between metric suffix and number\n         case '_':\n            fl |= STBSP__METRIC_NOSPACE;\n            ++f;\n            continue;\n         // if we have leading zero\n         case '0':\n            fl |= STBSP__LEADINGZERO;\n            ++f;\n            goto flags_done;\n         default: goto flags_done;\n         }\n      }\n   flags_done:\n\n      // get the field width\n      if (f[0] == '*') {\n         fw = va_arg(va, stbsp__uint32);\n         ++f;\n      } else {\n         while ((f[0] >= '0') && (f[0] <= '9')) {\n            fw = fw * 10 + f[0] - '0';\n            f++;\n         }\n      }\n      // get the precision\n      if (f[0] == '.') {\n         ++f;\n         if (f[0] == '*') {\n            pr = va_arg(va, stbsp__uint32);\n            ++f;\n         } else {\n            pr = 0;\n            while ((f[0] >= '0') && (f[0] <= '9')) {\n               pr = pr * 10 + f[0] - '0';\n               f++;\n            }\n         }\n      }\n\n      // handle integer size overrides\n      switch (f[0]) {\n      // are we halfwidth?\n      case 'h':\n         fl |= STBSP__HALFWIDTH;\n         ++f;\n         if (f[0] == 'h')\n            ++f;  // QUARTERWIDTH\n         break;\n      // are we 64-bit (unix style)\n      case 'l':\n         fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0);\n         ++f;\n         if (f[0] == 'l') {\n            fl |= STBSP__INTMAX;\n            ++f;\n         }\n         break;\n      // are we 64-bit on intmax? (c99)\n      case 'j':\n         fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0;\n         ++f;\n         break;\n      // are we 64-bit on size_t or ptrdiff_t? (c99)\n      case 'z':\n         fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;\n         ++f;\n         break;\n      case 't':\n         fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;\n         ++f;\n         break;\n      // are we 64-bit (msft style)\n      case 'I':\n         if ((f[1] == '6') && (f[2] == '4')) {\n            fl |= STBSP__INTMAX;\n            f += 3;\n         } else if ((f[1] == '3') && (f[2] == '2')) {\n            f += 3;\n         } else {\n            fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0);\n            ++f;\n         }\n         break;\n      default: break;\n      }\n\n      // handle each replacement\n      switch (f[0]) {\n         #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307\n         char num[STBSP__NUMSZ];\n         char lead[8];\n         char tail[8];\n         char *s;\n         char const *h;\n         stbsp__uint32 l, n, cs;\n         stbsp__uint64 n64;\n#ifndef STB_SPRINTF_NOFLOAT\n         double fv;\n#endif\n         stbsp__int32 dp;\n         char const *sn;\n\n      case 's':\n         // get the string\n         s = va_arg(va, char *);\n         if (s == 0)\n            s = (char *)\"null\";\n         // get the length\n         sn = s;\n         for (;;) {\n            if ((((stbsp__uintptr)sn) & 3) == 0)\n               break;\n         lchk:\n            if (sn[0] == 0)\n               goto ld;\n            ++sn;\n         }\n         n = 0xffffffff;\n         if (pr >= 0) {\n            n = (stbsp__uint32)(sn - s);\n            if (n >= (stbsp__uint32)pr)\n               goto ld;\n            n = ((stbsp__uint32)(pr - n)) >> 2;\n         }\n         while (n) {\n            stbsp__uint32 v = *(stbsp__uint32 *)sn;\n            if ((v - 0x01010101) & (~v) & 0x80808080UL)\n               goto lchk;\n            sn += 4;\n            --n;\n         }\n         goto lchk;\n      ld:\n\n         l = (stbsp__uint32)(sn - s);\n         // clamp to precision\n         if (l > (stbsp__uint32)pr)\n            l = pr;\n         lead[0] = 0;\n         tail[0] = 0;\n         pr = 0;\n         dp = 0;\n         cs = 0;\n         // copy the string in\n         goto scopy;\n\n      case 'c': // char\n         // get the character\n         s = num + STBSP__NUMSZ - 1;\n         *s = (char)va_arg(va, int);\n         l = 1;\n         lead[0] = 0;\n         tail[0] = 0;\n         pr = 0;\n         dp = 0;\n         cs = 0;\n         goto scopy;\n\n      case 'n': // weird write-bytes specifier\n      {\n         int *d = va_arg(va, int *);\n         *d = tlen + (int)(bf - buf);\n      } break;\n\n#ifdef STB_SPRINTF_NOFLOAT\n      case 'A':              // float\n      case 'a':              // hex float\n      case 'G':              // float\n      case 'g':              // float\n      case 'E':              // float\n      case 'e':              // float\n      case 'f':              // float\n         va_arg(va, double); // eat it\n         s = (char *)\"No float\";\n         l = 8;\n         lead[0] = 0;\n         tail[0] = 0;\n         pr = 0;\n         dp = 0;\n         cs = 0;\n         goto scopy;\n#else\n      case 'A': // hex float\n      case 'a': // hex float\n         h = (f[0] == 'A') ? hexu : hex;\n         fv = va_arg(va, double);\n         if (pr == -1)\n            pr = 6; // default is 6\n         // read the double into a string\n         if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv))\n            fl |= STBSP__NEGATIVE;\n\n         s = num + 64;\n\n         stbsp__lead_sign(fl, lead);\n\n         if (dp == -1023)\n            dp = (n64) ? -1022 : 0;\n         else\n            n64 |= (((stbsp__uint64)1) << 52);\n         n64 <<= (64 - 56);\n         if (pr < 15)\n            n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4));\n// add leading chars\n\n#ifdef STB_SPRINTF_MSVC_MODE\n         *s++ = '0';\n         *s++ = 'x';\n#else\n         lead[1 + lead[0]] = '0';\n         lead[2 + lead[0]] = 'x';\n         lead[0] += 2;\n#endif\n         *s++ = h[(n64 >> 60) & 15];\n         n64 <<= 4;\n         if (pr)\n            *s++ = stbsp__period;\n         sn = s;\n\n         // print the bits\n         n = pr;\n         if (n > 13)\n            n = 13;\n         if (pr > (stbsp__int32)n)\n            tz = pr - n;\n         pr = 0;\n         while (n--) {\n            *s++ = h[(n64 >> 60) & 15];\n            n64 <<= 4;\n         }\n\n         // print the expo\n         tail[1] = h[17];\n         if (dp < 0) {\n            tail[2] = '-';\n            dp = -dp;\n         } else\n            tail[2] = '+';\n         n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3));\n         tail[0] = (char)n;\n         for (;;) {\n            tail[n] = '0' + dp % 10;\n            if (n <= 3)\n               break;\n            --n;\n            dp /= 10;\n         }\n\n         dp = (int)(s - sn);\n         l = (int)(s - (num + 64));\n         s = num + 64;\n         cs = 1 + (3 << 24);\n         goto scopy;\n\n      case 'G': // float\n      case 'g': // float\n         h = (f[0] == 'G') ? hexu : hex;\n         fv = va_arg(va, double);\n         if (pr == -1)\n            pr = 6;\n         else if (pr == 0)\n            pr = 1; // default is 6\n         // read the double into a string\n         if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000))\n            fl |= STBSP__NEGATIVE;\n\n         // clamp the precision and delete extra zeros after clamp\n         n = pr;\n         if (l > (stbsp__uint32)pr)\n            l = pr;\n         while ((l > 1) && (pr) && (sn[l - 1] == '0')) {\n            --pr;\n            --l;\n         }\n\n         // should we use %e\n         if ((dp <= -4) || (dp > (stbsp__int32)n)) {\n            if (pr > (stbsp__int32)l)\n               pr = l - 1;\n            else if (pr)\n               --pr; // when using %e, there is one digit before the decimal\n            goto doexpfromg;\n         }\n         // this is the insane action to get the pr to match %g semantics for %f\n         if (dp > 0) {\n            pr = (dp < (stbsp__int32)l) ? l - dp : 0;\n         } else {\n            pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr);\n         }\n         goto dofloatfromg;\n\n      case 'E': // float\n      case 'e': // float\n         h = (f[0] == 'E') ? hexu : hex;\n         fv = va_arg(va, double);\n         if (pr == -1)\n            pr = 6; // default is 6\n         // read the double into a string\n         if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000))\n            fl |= STBSP__NEGATIVE;\n      doexpfromg:\n         tail[0] = 0;\n         stbsp__lead_sign(fl, lead);\n         if (dp == STBSP__SPECIAL) {\n            s = (char *)sn;\n            cs = 0;\n            pr = 0;\n            goto scopy;\n         }\n         s = num + 64;\n         // handle leading chars\n         *s++ = sn[0];\n\n         if (pr)\n            *s++ = stbsp__period;\n\n         // handle after decimal\n         if ((l - 1) > (stbsp__uint32)pr)\n            l = pr + 1;\n         for (n = 1; n < l; n++)\n            *s++ = sn[n];\n         // trailing zeros\n         tz = pr - (l - 1);\n         pr = 0;\n         // dump expo\n         tail[1] = h[0xe];\n         dp -= 1;\n         if (dp < 0) {\n            tail[2] = '-';\n            dp = -dp;\n         } else\n            tail[2] = '+';\n#ifdef STB_SPRINTF_MSVC_MODE\n         n = 5;\n#else\n         n = (dp >= 100) ? 5 : 4;\n#endif\n         tail[0] = (char)n;\n         for (;;) {\n            tail[n] = '0' + dp % 10;\n            if (n <= 3)\n               break;\n            --n;\n            dp /= 10;\n         }\n         cs = 1 + (3 << 24); // how many tens\n         goto flt_lead;\n\n      case 'f': // float\n         fv = va_arg(va, double);\n      doafloat:\n         // do kilos\n         if (fl & STBSP__METRIC_SUFFIX) {\n            double divisor;\n            divisor = 1000.0f;\n            if (fl & STBSP__METRIC_1024)\n               divisor = 1024.0;\n            while (fl < 0x4000000) {\n               if ((fv < divisor) && (fv > -divisor))\n                  break;\n               fv /= divisor;\n               fl += 0x1000000;\n            }\n         }\n         if (pr == -1)\n            pr = 6; // default is 6\n         // read the double into a string\n         if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr))\n            fl |= STBSP__NEGATIVE;\n      dofloatfromg:\n         tail[0] = 0;\n         stbsp__lead_sign(fl, lead);\n         if (dp == STBSP__SPECIAL) {\n            s = (char *)sn;\n            cs = 0;\n            pr = 0;\n            goto scopy;\n         }\n         s = num + 64;\n\n         // handle the three decimal varieties\n         if (dp <= 0) {\n            stbsp__int32 i;\n            // handle 0.000*000xxxx\n            *s++ = '0';\n            if (pr)\n               *s++ = stbsp__period;\n            n = -dp;\n            if ((stbsp__int32)n > pr)\n               n = pr;\n            i = n;\n            while (i) {\n               if ((((stbsp__uintptr)s) & 3) == 0)\n                  break;\n               *s++ = '0';\n               --i;\n            }\n            while (i >= 4) {\n               *(stbsp__uint32 *)s = 0x30303030;\n               s += 4;\n               i -= 4;\n            }\n            while (i) {\n               *s++ = '0';\n               --i;\n            }\n            if ((stbsp__int32)(l + n) > pr)\n               l = pr - n;\n            i = l;\n            while (i) {\n               *s++ = *sn++;\n               --i;\n            }\n            tz = pr - (n + l);\n            cs = 1 + (3 << 24); // how many tens did we write (for commas below)\n         } else {\n            cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0;\n            if ((stbsp__uint32)dp >= l) {\n               // handle xxxx000*000.0\n               n = 0;\n               for (;;) {\n                  if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {\n                     cs = 0;\n                     *s++ = stbsp__comma;\n                  } else {\n                     *s++ = sn[n];\n                     ++n;\n                     if (n >= l)\n                        break;\n                  }\n               }\n               if (n < (stbsp__uint32)dp) {\n                  n = dp - n;\n                  if ((fl & STBSP__TRIPLET_COMMA) == 0) {\n                     while (n) {\n                        if ((((stbsp__uintptr)s) & 3) == 0)\n                           break;\n                        *s++ = '0';\n                        --n;\n                     }\n                     while (n >= 4) {\n                        *(stbsp__uint32 *)s = 0x30303030;\n                        s += 4;\n                        n -= 4;\n                     }\n                  }\n                  while (n) {\n                     if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {\n                        cs = 0;\n                        *s++ = stbsp__comma;\n                     } else {\n                        *s++ = '0';\n                        --n;\n                     }\n                  }\n               }\n               cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens\n               if (pr) {\n                  *s++ = stbsp__period;\n                  tz = pr;\n               }\n            } else {\n               // handle xxxxx.xxxx000*000\n               n = 0;\n               for (;;) {\n                  if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {\n                     cs = 0;\n                     *s++ = stbsp__comma;\n                  } else {\n                     *s++ = sn[n];\n                     ++n;\n                     if (n >= (stbsp__uint32)dp)\n                        break;\n                  }\n               }\n               cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens\n               if (pr)\n                  *s++ = stbsp__period;\n               if ((l - dp) > (stbsp__uint32)pr)\n                  l = pr + dp;\n               while (n < l) {\n                  *s++ = sn[n];\n                  ++n;\n               }\n               tz = pr - (l - dp);\n            }\n         }\n         pr = 0;\n\n         // handle k,m,g,t\n         if (fl & STBSP__METRIC_SUFFIX) {\n            char idx;\n            idx = 1;\n            if (fl & STBSP__METRIC_NOSPACE)\n               idx = 0;\n            tail[0] = idx;\n            tail[1] = ' ';\n            {\n               if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'.\n                  if (fl & STBSP__METRIC_1024)\n                     tail[idx + 1] = \"_KMGT\"[fl >> 24];\n                  else\n                     tail[idx + 1] = \"_kMGT\"[fl >> 24];\n                  idx++;\n                  // If printing kibits and not in jedec, add the 'i'.\n                  if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) {\n                     tail[idx + 1] = 'i';\n                     idx++;\n                  }\n                  tail[0] = idx;\n               }\n            }\n         };\n\n      flt_lead:\n         // get the length that we copied\n         l = (stbsp__uint32)(s - (num + 64));\n         s = num + 64;\n         goto scopy;\n#endif\n\n      case 'B': // upper binary\n      case 'b': // lower binary\n         h = (f[0] == 'B') ? hexu : hex;\n         lead[0] = 0;\n         if (fl & STBSP__LEADING_0X) {\n            lead[0] = 2;\n            lead[1] = '0';\n            lead[2] = h[0xb];\n         }\n         l = (8 << 4) | (1 << 8);\n         goto radixnum;\n\n      case 'o': // octal\n         h = hexu;\n         lead[0] = 0;\n         if (fl & STBSP__LEADING_0X) {\n            lead[0] = 1;\n            lead[1] = '0';\n         }\n         l = (3 << 4) | (3 << 8);\n         goto radixnum;\n\n      case 'p': // pointer\n         fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0;\n         pr = sizeof(void *) * 2;\n         fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros\n                                    // fall through - to X\n\n      case 'X': // upper hex\n      case 'x': // lower hex\n         h = (f[0] == 'X') ? hexu : hex;\n         l = (4 << 4) | (4 << 8);\n         lead[0] = 0;\n         if (fl & STBSP__LEADING_0X) {\n            lead[0] = 2;\n            lead[1] = '0';\n            lead[2] = h[16];\n         }\n      radixnum:\n         // get the number\n         if (fl & STBSP__INTMAX)\n            n64 = va_arg(va, stbsp__uint64);\n         else\n            n64 = va_arg(va, stbsp__uint32);\n\n         s = num + STBSP__NUMSZ;\n         dp = 0;\n         // clear tail, and clear leading if value is zero\n         tail[0] = 0;\n         if (n64 == 0) {\n            lead[0] = 0;\n            if (pr == 0) {\n               l = 0;\n               cs = (((l >> 4) & 15)) << 24;\n               goto scopy;\n            }\n         }\n         // convert to string\n         for (;;) {\n            *--s = h[n64 & ((1 << (l >> 8)) - 1)];\n            n64 >>= (l >> 8);\n            if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr)))\n               break;\n            if (fl & STBSP__TRIPLET_COMMA) {\n               ++l;\n               if ((l & 15) == ((l >> 4) & 15)) {\n                  l &= ~15;\n                  *--s = stbsp__comma;\n               }\n            }\n         };\n         // get the tens and the comma pos\n         cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24);\n         // get the length that we copied\n         l = (stbsp__uint32)((num + STBSP__NUMSZ) - s);\n         // copy it\n         goto scopy;\n\n      case 'u': // unsigned\n      case 'i':\n      case 'd': // integer\n         // get the integer and abs it\n         if (fl & STBSP__INTMAX) {\n            stbsp__int64 i64 = va_arg(va, stbsp__int64);\n            n64 = (stbsp__uint64)i64;\n            if ((f[0] != 'u') && (i64 < 0)) {\n               n64 = (stbsp__uint64)-i64;\n               fl |= STBSP__NEGATIVE;\n            }\n         } else {\n            stbsp__int32 i = va_arg(va, stbsp__int32);\n            n64 = (stbsp__uint32)i;\n            if ((f[0] != 'u') && (i < 0)) {\n               n64 = (stbsp__uint32)-i;\n               fl |= STBSP__NEGATIVE;\n            }\n         }\n\n#ifndef STB_SPRINTF_NOFLOAT\n         if (fl & STBSP__METRIC_SUFFIX) {\n            if (n64 < 1024)\n               pr = 0;\n            else if (pr == -1)\n               pr = 1;\n            fv = (double)(stbsp__int64)n64;\n            goto doafloat;\n         }\n#endif\n\n         // convert to string\n         s = num + STBSP__NUMSZ;\n         l = 0;\n\n         for (;;) {\n            // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators)\n            char *o = s - 8;\n            if (n64 >= 100000000) {\n               n = (stbsp__uint32)(n64 % 100000000);\n               n64 /= 100000000;\n            } else {\n               n = (stbsp__uint32)n64;\n               n64 = 0;\n            }\n            if ((fl & STBSP__TRIPLET_COMMA) == 0) {\n               do {\n                  s -= 2;\n                  *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2];\n                  n /= 100;\n               } while (n);\n            }\n            while (n) {\n               if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) {\n                  l = 0;\n                  *--s = stbsp__comma;\n                  --o;\n               } else {\n                  *--s = (char)(n % 10) + '0';\n                  n /= 10;\n               }\n            }\n            if (n64 == 0) {\n               if ((s[0] == '0') && (s != (num + STBSP__NUMSZ)))\n                  ++s;\n               break;\n            }\n            while (s != o)\n               if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) {\n                  l = 0;\n                  *--s = stbsp__comma;\n                  --o;\n               } else {\n                  *--s = '0';\n               }\n         }\n\n         tail[0] = 0;\n         stbsp__lead_sign(fl, lead);\n\n         // get the length that we copied\n         l = (stbsp__uint32)((num + STBSP__NUMSZ) - s);\n         if (l == 0) {\n            *--s = '0';\n            l = 1;\n         }\n         cs = l + (3 << 24);\n         if (pr < 0)\n            pr = 0;\n\n      scopy:\n         // get fw=leading/trailing space, pr=leading zeros\n         if (pr < (stbsp__int32)l)\n            pr = l;\n         n = pr + lead[0] + tail[0] + tz;\n         if (fw < (stbsp__int32)n)\n            fw = n;\n         fw -= n;\n         pr -= l;\n\n         // handle right justify and leading zeros\n         if ((fl & STBSP__LEFTJUST) == 0) {\n            if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr\n            {\n               pr = (fw > pr) ? fw : pr;\n               fw = 0;\n            } else {\n               fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas\n            }\n         }\n\n         // copy the spaces and/or zeros\n         if (fw + pr) {\n            stbsp__int32 i;\n            stbsp__uint32 c;\n\n            // copy leading spaces (or when doing %8.4d stuff)\n            if ((fl & STBSP__LEFTJUST) == 0)\n               while (fw > 0) {\n                  stbsp__cb_buf_clamp(i, fw);\n                  fw -= i;\n                  while (i) {\n                     if ((((stbsp__uintptr)bf) & 3) == 0)\n                        break;\n                     *bf++ = ' ';\n                     --i;\n                  }\n                  while (i >= 4) {\n                     *(stbsp__uint32 *)bf = 0x20202020;\n                     bf += 4;\n                     i -= 4;\n                  }\n                  while (i) {\n                     *bf++ = ' ';\n                     --i;\n                  }\n                  stbsp__chk_cb_buf(1);\n               }\n\n            // copy leader\n            sn = lead + 1;\n            while (lead[0]) {\n               stbsp__cb_buf_clamp(i, lead[0]);\n               lead[0] -= (char)i;\n               while (i) {\n                  *bf++ = *sn++;\n                  --i;\n               }\n               stbsp__chk_cb_buf(1);\n            }\n\n            // copy leading zeros\n            c = cs >> 24;\n            cs &= 0xffffff;\n            cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0;\n            while (pr > 0) {\n               stbsp__cb_buf_clamp(i, pr);\n               pr -= i;\n               if ((fl & STBSP__TRIPLET_COMMA) == 0) {\n                  while (i) {\n                     if ((((stbsp__uintptr)bf) & 3) == 0)\n                        break;\n                     *bf++ = '0';\n                     --i;\n                  }\n                  while (i >= 4) {\n                     *(stbsp__uint32 *)bf = 0x30303030;\n                     bf += 4;\n                     i -= 4;\n                  }\n               }\n               while (i) {\n                  if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) {\n                     cs = 0;\n                     *bf++ = stbsp__comma;\n                  } else\n                     *bf++ = '0';\n                  --i;\n               }\n               stbsp__chk_cb_buf(1);\n            }\n         }\n\n         // copy leader if there is still one\n         sn = lead + 1;\n         while (lead[0]) {\n            stbsp__int32 i;\n            stbsp__cb_buf_clamp(i, lead[0]);\n            lead[0] -= (char)i;\n            while (i) {\n               *bf++ = *sn++;\n               --i;\n            }\n            stbsp__chk_cb_buf(1);\n         }\n\n         // copy the string\n         n = l;\n         while (n) {\n            stbsp__int32 i;\n            stbsp__cb_buf_clamp(i, n);\n            n -= i;\n            STBSP__UNALIGNED(while (i >= 4) {\n               *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s;\n               bf += 4;\n               s += 4;\n               i -= 4;\n            })\n            while (i) {\n               *bf++ = *s++;\n               --i;\n            }\n            stbsp__chk_cb_buf(1);\n         }\n\n         // copy trailing zeros\n         while (tz) {\n            stbsp__int32 i;\n            stbsp__cb_buf_clamp(i, tz);\n            tz -= i;\n            while (i) {\n               if ((((stbsp__uintptr)bf) & 3) == 0)\n                  break;\n               *bf++ = '0';\n               --i;\n            }\n            while (i >= 4) {\n               *(stbsp__uint32 *)bf = 0x30303030;\n               bf += 4;\n               i -= 4;\n            }\n            while (i) {\n               *bf++ = '0';\n               --i;\n            }\n            stbsp__chk_cb_buf(1);\n         }\n\n         // copy tail if there is one\n         sn = tail + 1;\n         while (tail[0]) {\n            stbsp__int32 i;\n            stbsp__cb_buf_clamp(i, tail[0]);\n            tail[0] -= (char)i;\n            while (i) {\n               *bf++ = *sn++;\n               --i;\n            }\n            stbsp__chk_cb_buf(1);\n         }\n\n         // handle the left justify\n         if (fl & STBSP__LEFTJUST)\n            if (fw > 0) {\n               while (fw) {\n                  stbsp__int32 i;\n                  stbsp__cb_buf_clamp(i, fw);\n                  fw -= i;\n                  while (i) {\n                     if ((((stbsp__uintptr)bf) & 3) == 0)\n                        break;\n                     *bf++ = ' ';\n                     --i;\n                  }\n                  while (i >= 4) {\n                     *(stbsp__uint32 *)bf = 0x20202020;\n                     bf += 4;\n                     i -= 4;\n                  }\n                  while (i--)\n                     *bf++ = ' ';\n                  stbsp__chk_cb_buf(1);\n               }\n            }\n         break;\n\n      default: // unknown, just copy code\n         s = num + STBSP__NUMSZ - 1;\n         *s = f[0];\n         l = 1;\n         fw = fl = 0;\n         lead[0] = 0;\n         tail[0] = 0;\n         pr = 0;\n         dp = 0;\n         cs = 0;\n         goto scopy;\n      }\n      ++f;\n   }\nendfmt:\n\n   if (!callback)\n      *bf = 0;\n   else\n      stbsp__flush_cb();\n\ndone:\n   return tlen + (int)(bf - buf);\n}\n\n// cleanup\n#undef STBSP__LEFTJUST\n#undef STBSP__LEADINGPLUS\n#undef STBSP__LEADINGSPACE\n#undef STBSP__LEADING_0X\n#undef STBSP__LEADINGZERO\n#undef STBSP__INTMAX\n#undef STBSP__TRIPLET_COMMA\n#undef STBSP__NEGATIVE\n#undef STBSP__METRIC_SUFFIX\n#undef STBSP__NUMSZ\n#undef stbsp__chk_cb_bufL\n#undef stbsp__chk_cb_buf\n#undef stbsp__flush_cb\n#undef stbsp__cb_buf_clamp\n\n// ============================================================================\n//   wrapper functions\n\nSTBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...)\n{\n   int result;\n   va_list va;\n   va_start(va, fmt);\n   result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va);\n   va_end(va);\n   return result;\n}\n\ntypedef struct stbsp__context {\n   char *buf;\n   int count;\n   int length;\n   char tmp[STB_SPRINTF_MIN];\n} stbsp__context;\n\nstatic char *stbsp__clamp_callback(const char *buf, void *user, int len)\n{\n   stbsp__context *c = (stbsp__context *)user;\n   c->length += len;\n\n   if (len > c->count)\n      len = c->count;\n\n   if (len) {\n      if (buf != c->buf) {\n         const char *s, *se;\n         char *d;\n         d = c->buf;\n         s = buf;\n         se = buf + len;\n         do {\n            *d++ = *s++;\n         } while (s < se);\n      }\n      c->buf += len;\n      c->count -= len;\n   }\n\n   if (c->count <= 0)\n      return c->tmp;\n   return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can\n}\n\nstatic char * stbsp__count_clamp_callback( const char * buf, void * user, int len )\n{\n   stbsp__context * c = (stbsp__context*)user;\n   (void) sizeof(buf);\n\n   c->length += len;\n   return c->tmp; // go direct into buffer if you can\n}\n\nSTBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va )\n{\n   stbsp__context c;\n\n   if ( (count == 0) && !buf )\n   {\n      c.length = 0;\n\n      STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va );\n   }\n   else\n   {\n      int l;\n\n      c.buf = buf;\n      c.count = count;\n      c.length = 0;\n\n      STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va );\n\n      // zero-terminate\n      l = (int)( c.buf - buf );\n      if ( l >= count ) // should never be greater, only equal (or less) than count\n         l = count - 1;\n      buf[l] = 0;\n   }\n\n   return c.length;\n}\n\nSTBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...)\n{\n   int result;\n   va_list va;\n   va_start(va, fmt);\n\n   result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va);\n   va_end(va);\n\n   return result;\n}\n\nSTBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va)\n{\n   return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va);\n}\n\n// =======================================================================\n//   low level float utility functions\n\n#ifndef STB_SPRINTF_NOFLOAT\n\n// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox)\n#define STBSP__COPYFP(dest, src)                   \\\n   {                                               \\\n      int cn;                                      \\\n      for (cn = 0; cn < 8; cn++)                   \\\n         ((char *)&dest)[cn] = ((char *)&src)[cn]; \\\n   }\n\n// get float info\nstatic stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value)\n{\n   double d;\n   stbsp__int64 b = 0;\n\n   // load value and round at the frac_digits\n   d = value;\n\n   STBSP__COPYFP(b, d);\n\n   *bits = b & ((((stbsp__uint64)1) << 52) - 1);\n   *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023);\n\n   return (stbsp__int32)((stbsp__uint64) b >> 63);\n}\n\nstatic double const stbsp__bot[23] = {\n   1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011,\n   1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022\n};\nstatic double const stbsp__negbot[22] = {\n   1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011,\n   1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022\n};\nstatic double const stbsp__negboterr[22] = {\n   -5.551115123125783e-018,  -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023,\n   4.5251888174113739e-024,  -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028,  2.0113352370744385e-029,\n   -3.0373745563400371e-030, 1.1806906454401013e-032,  -7.7705399876661076e-032, 2.0902213275965398e-033,  -7.1542424054621921e-034, -7.1542424054621926e-035,\n   2.4754073164739869e-036,  5.4846728545790429e-037,  9.2462547772103625e-038,  -4.8596774326570872e-039\n};\nstatic double const stbsp__top[13] = {\n   1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299\n};\nstatic double const stbsp__negtop[13] = {\n   1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299\n};\nstatic double const stbsp__toperr[13] = {\n   8388608,\n   6.8601809640529717e+028,\n   -7.253143638152921e+052,\n   -4.3377296974619174e+075,\n   -1.5559416129466825e+098,\n   -3.2841562489204913e+121,\n   -3.7745893248228135e+144,\n   -1.7356668416969134e+167,\n   -3.8893577551088374e+190,\n   -9.9566444326005119e+213,\n   6.3641293062232429e+236,\n   -5.2069140800249813e+259,\n   -5.2504760255204387e+282\n};\nstatic double const stbsp__negtoperr[13] = {\n   3.9565301985100693e-040,  -2.299904345391321e-063,  3.6506201437945798e-086,  1.1875228833981544e-109,\n   -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178,  -5.7778912386589953e-201,\n   7.4997100559334532e-224,  -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293,\n   8.0970921678014997e-317\n};\n\n#if defined(_MSC_VER) && (_MSC_VER <= 1200)\nstatic stbsp__uint64 const stbsp__powten[20] = {\n   1,\n   10,\n   100,\n   1000,\n   10000,\n   100000,\n   1000000,\n   10000000,\n   100000000,\n   1000000000,\n   10000000000,\n   100000000000,\n   1000000000000,\n   10000000000000,\n   100000000000000,\n   1000000000000000,\n   10000000000000000,\n   100000000000000000,\n   1000000000000000000,\n   10000000000000000000U\n};\n#define stbsp__tento19th ((stbsp__uint64)1000000000000000000)\n#else\nstatic stbsp__uint64 const stbsp__powten[20] = {\n   1,\n   10,\n   100,\n   1000,\n   10000,\n   100000,\n   1000000,\n   10000000,\n   100000000,\n   1000000000,\n   10000000000ULL,\n   100000000000ULL,\n   1000000000000ULL,\n   10000000000000ULL,\n   100000000000000ULL,\n   1000000000000000ULL,\n   10000000000000000ULL,\n   100000000000000000ULL,\n   1000000000000000000ULL,\n   10000000000000000000ULL\n};\n#define stbsp__tento19th (1000000000000000000ULL)\n#endif\n\n#define stbsp__ddmulthi(oh, ol, xh, yh)                            \\\n   {                                                               \\\n      double ahi = 0, alo, bhi = 0, blo;                           \\\n      stbsp__int64 bt;                                             \\\n      oh = xh * yh;                                                \\\n      STBSP__COPYFP(bt, xh);                                       \\\n      bt &= ((~(stbsp__uint64)0) << 27);                           \\\n      STBSP__COPYFP(ahi, bt);                                      \\\n      alo = xh - ahi;                                              \\\n      STBSP__COPYFP(bt, yh);                                       \\\n      bt &= ((~(stbsp__uint64)0) << 27);                           \\\n      STBSP__COPYFP(bhi, bt);                                      \\\n      blo = yh - bhi;                                              \\\n      ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \\\n   }\n\n#define stbsp__ddtoS64(ob, xh, xl)          \\\n   {                                        \\\n      double ahi = 0, alo, vh, t;           \\\n      ob = (stbsp__int64)ph;                \\\n      vh = (double)ob;                      \\\n      ahi = (xh - vh);                      \\\n      t = (ahi - xh);                       \\\n      alo = (xh - (ahi - t)) - (vh + t);    \\\n      ob += (stbsp__int64)(ahi + alo + xl); \\\n   }\n\n#define stbsp__ddrenorm(oh, ol) \\\n   {                            \\\n      double s;                 \\\n      s = oh + ol;              \\\n      ol = ol - (s - oh);       \\\n      oh = s;                   \\\n   }\n\n#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh);\n\n#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl);\n\nstatic void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350\n{\n   double ph, pl;\n   if ((power >= 0) && (power <= 22)) {\n      stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]);\n   } else {\n      stbsp__int32 e, et, eb;\n      double p2h, p2l;\n\n      e = power;\n      if (power < 0)\n         e = -e;\n      et = (e * 0x2c9) >> 14; /* %23 */\n      if (et > 13)\n         et = 13;\n      eb = e - (et * 23);\n\n      ph = d;\n      pl = 0.0;\n      if (power < 0) {\n         if (eb) {\n            --eb;\n            stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]);\n            stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]);\n         }\n         if (et) {\n            stbsp__ddrenorm(ph, pl);\n            --et;\n            stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]);\n            stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]);\n            ph = p2h;\n            pl = p2l;\n         }\n      } else {\n         if (eb) {\n            e = eb;\n            if (eb > 22)\n               eb = 22;\n            e -= eb;\n            stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]);\n            if (e) {\n               stbsp__ddrenorm(ph, pl);\n               stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]);\n               stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl);\n               ph = p2h;\n               pl = p2l;\n            }\n         }\n         if (et) {\n            stbsp__ddrenorm(ph, pl);\n            --et;\n            stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]);\n            stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]);\n            ph = p2h;\n            pl = p2l;\n         }\n      }\n   }\n   stbsp__ddrenorm(ph, pl);\n   *ohi = ph;\n   *olo = pl;\n}\n\n// given a float value, returns the significant bits in bits, and the position of the\n//   decimal point in decimal_pos.  +/-INF and NAN are specified by special values\n//   returned in the decimal_pos parameter.\n// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000\nstatic stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits)\n{\n   double d;\n   stbsp__int64 bits = 0;\n   stbsp__int32 expo, e, ng, tens;\n\n   d = value;\n   STBSP__COPYFP(bits, d);\n   expo = (stbsp__int32)((bits >> 52) & 2047);\n   ng = (stbsp__int32)((stbsp__uint64) bits >> 63);\n   if (ng)\n      d = -d;\n\n   if (expo == 2047) // is nan or inf?\n   {\n      *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? \"NaN\" : \"Inf\";\n      *decimal_pos = STBSP__SPECIAL;\n      *len = 3;\n      return ng;\n   }\n\n   if (expo == 0) // is zero or denormal\n   {\n      if (((stbsp__uint64) bits << 1) == 0) // do zero\n      {\n         *decimal_pos = 1;\n         *start = out;\n         out[0] = '0';\n         *len = 1;\n         return ng;\n      }\n      // find the right expo for denormals\n      {\n         stbsp__int64 v = ((stbsp__uint64)1) << 51;\n         while ((bits & v) == 0) {\n            --expo;\n            v >>= 1;\n         }\n      }\n   }\n\n   // find the decimal exponent as well as the decimal bits of the value\n   {\n      double ph, pl;\n\n      // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046\n      tens = expo - 1023;\n      tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1);\n\n      // move the significant bits into position and stick them into an int\n      stbsp__raise_to_power10(&ph, &pl, d, 18 - tens);\n\n      // get full as much precision from double-double as possible\n      stbsp__ddtoS64(bits, ph, pl);\n\n      // check if we undershot\n      if (((stbsp__uint64)bits) >= stbsp__tento19th)\n         ++tens;\n   }\n\n   // now do the rounding in integer land\n   frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits);\n   if ((frac_digits < 24)) {\n      stbsp__uint32 dg = 1;\n      if ((stbsp__uint64)bits >= stbsp__powten[9])\n         dg = 10;\n      while ((stbsp__uint64)bits >= stbsp__powten[dg]) {\n         ++dg;\n         if (dg == 20)\n            goto noround;\n      }\n      if (frac_digits < dg) {\n         stbsp__uint64 r;\n         // add 0.5 at the right position and round\n         e = dg - frac_digits;\n         if ((stbsp__uint32)e >= 24)\n            goto noround;\n         r = stbsp__powten[e];\n         bits = bits + (r / 2);\n         if ((stbsp__uint64)bits >= stbsp__powten[dg])\n            ++tens;\n         bits /= r;\n      }\n   noround:;\n   }\n\n   // kill long trailing runs of zeros\n   if (bits) {\n      stbsp__uint32 n;\n      for (;;) {\n         if (bits <= 0xffffffff)\n            break;\n         if (bits % 1000)\n            goto donez;\n         bits /= 1000;\n      }\n      n = (stbsp__uint32)bits;\n      while ((n % 1000) == 0)\n         n /= 1000;\n      bits = n;\n   donez:;\n   }\n\n   // convert to string\n   out += 64;\n   e = 0;\n   for (;;) {\n      stbsp__uint32 n;\n      char *o = out - 8;\n      // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned)\n      if (bits >= 100000000) {\n         n = (stbsp__uint32)(bits % 100000000);\n         bits /= 100000000;\n      } else {\n         n = (stbsp__uint32)bits;\n         bits = 0;\n      }\n      while (n) {\n         out -= 2;\n         *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2];\n         n /= 100;\n         e += 2;\n      }\n      if (bits == 0) {\n         if ((e) && (out[0] == '0')) {\n            ++out;\n            --e;\n         }\n         break;\n      }\n      while (out != o) {\n         *--out = '0';\n         ++e;\n      }\n   }\n\n   *decimal_pos = tens;\n   *start = out;\n   *len = e;\n   return ng;\n}\n\n#undef stbsp__ddmulthi\n#undef stbsp__ddrenorm\n#undef stbsp__ddmultlo\n#undef stbsp__ddmultlos\n#undef STBSP__SPECIAL\n#undef STBSP__COPYFP\n\n#endif // STB_SPRINTF_NOFLOAT\n\n// clean up\n#undef stbsp__uint16\n#undef stbsp__uint32\n#undef stbsp__int32\n#undef stbsp__uint64\n#undef stbsp__int64\n#undef STBSP__UNALIGNED\n\n#endif // STB_SPRINTF_IMPLEMENTATION\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2023-2024 Ali Behnoudfar\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# ZetaRay\n\n[![MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![build-and-test](https://github.com/alipbcs/ZetaRay/actions/workflows/build.yml/badge.svg)](https://github.com/alipbcs/ZetaRay/actions/workflows/build.yml)\n\nA hobby real-time Direct3D 12 path tracer. Mainly developed for learning and experimenting with the latest research in real-time rendering. \n\nTo achieve real-time frame rates, this renderer utilizes recent developments such as hardware-accelerated ray tracing (DXR), advanced sampling (ReSTIR), and smart upscaling (AMD FSR2).\n\n<div align=\"center\">\n  <img src=\"Assets/Images/8.png?raw=true\" alt=\"Sponza\" style=\"zoom:60%\"/>\n  <p style=\"text-align: center;\"><i>Subway Station</i> based on the NYC R46 subway, rendered by ZetaRay. <i>(<a href=\"https://sketchfab.com/3d-models/free-subway-station-r46-subway-ae5aadde1c6f48a19b32b309417a669b\">Scene</a> by <a href=\"https://sketchfab.com/Xlay3D\">Alex Murias</a>.)</i></p>\n</div>\n\n## Highlight Features\n\n - ReSTIR DI for many-light sampling from emissive meshes, sun, and sky [[4](#references)]. Sampling efficiency is increased by\n   - Power sampling using the alias method\n   - A world-space voxel grid with stochastic light reservoirs per voxel [[5](#references)]\n - Indirect lighting methods include:\n    1. Unidirectional path tracer\n    2. ReSTIR GI [[1](#references)]: A variant of ReSTIR effective for diffuse and moderately glossy surfaces, but less effective for highly glossy surfaces.\n    3. ReSTIR PT [[6](#references)]: A more advanced variant of ReSTIR with significantly better quality for highly glossy surfaces compared to ReSTIR GI.\n - Ray differentials for texture MIP selection\n - Physically-based surface shading model inspired by OpenPBR [[7](#references)]\n - Single scattering sky and atmosphere [[2, 3](#references)]\n - Render graph for automatic resource barrier placement and multi-threaded GPU command list recording and submission ([more details below](#render-graph))\n - AMD FSR2 upscaling\n - Temporal anti-aliasing (TAA)\n - Auto exposure using luminance histogram\n - glTF scene loading with the metalness-roughness workflow. Following extensions are also supported:\n   - KHR_materials_emissive_strength\n   - KHR_materials_ior\n   - KHR_materials_transmission\n   - KHR_materials_clearcoat\n\n### Render Graph\n\nGraphics APIs such as Vulkan and Direct3D 12 require resource barriers to be placed manually by the programmer. These barriers control synchronization, memory visibility, and additionally for textures, resource layout. As program complexity grows, manual placement can lead to issues such as:\n   - Becoming highly error-prone and limiting extensibility and prototyping.\n   - GPU command buffers can be recorded in multiple threads; correct usage and prevention of data-race issues may be hard to achieve.\n\nFurthermore, using multiple command buffers requires a correct submission order—e.g., command list A writes to a resource that is read by command list B, so A has to be submitted before B. \n\nA render graph can help with all of the above; by analyzing resource dependencies, a directed acyclic graph (DAG) is formed from which submission order is derived and barriers are automatically placed. A visualization is shown below.\n\n<div align=\"center\">\n  <img src=\"Assets/Images/6.png?raw=true\" alt=\"Render graph\" style=\"zoom:50%\"/>\n  <p style=\"text-align: center;\"><i>A sample frame render graph.</i></p>\n</div>\n\n### Sample Editor\n\nThe main sample application ([`Source/ZetaLab`](./Source/ZetaLab/)) provides a light editor experience with the following features:\n - Load glTF scenes ([note the preprocessing step below](#build))\n - Change object transformations (translation, rotation, and scaling) using a 3D gizmo\n - Modify material properties\n - Move light sources (sun and sky or emissives) and change their intensity, color, etc.\n - Renderer options, such as the number of light bounces, texture filtering, ReSTIR parameters, camera settings (pinhole or thin lens, FOV, f-stop), tonemapper, and more\n - GPU performance metrics:\n   - Frametime graph\n   - Frametime for individual shaders using hardware timestamp queries\n   - VRAM usage\n - Hot-reload shaders\n\n## Requirements\n\n1. GPU with hardware-accelerated ray tracing support (Nvidia RTX 2000 series or later, AMD RX 6000 series or later)\n2. Windows 10 1909 or later\n3. [Visual Studio 2019 or later](https://visualstudio.microsoft.com/downloads/). Builds with both MSVC and ClangCL toolsets.\n4. [CMake 3.21 or later](https://cmake.org/download/)\n\n## Build\n\nStandard CMake. In the project directory, run:\n\n```bash\n> mkdir build\n> cd build\n> cmake ..\n```\n\nBefore running the project, glTF scenes need to be preprocessed first by generating mipmaps and converting textures to DDS format. A command-line utility app ([`Tools/BCnCompressglTF`](./Tools/BCnCompressglTF/)) is provided for this purpose. It can be used as follows:\n\n```bash\n> cd bin\n> BCnCompressglTF <path-to-gltf>\n```\nThe outputs are:\n1. The converted glTF scene file in the same directory with a `_zeta` suffix (e.g., `myscene.gltf` -> `myscene_zeta.gltf`) \n2. The compressed textures in the `<path-to-gltf-directory>/compressed` directory.\n\nFor convenience, a preprocessed Cornell Box scene is provided ([`Assets/CornellBox/cornell.gltf`](./Assets/CornellBox/cornell9.gltf)). After building the project, you can run it as follows:\n```bash\n> cd bin\n> ZetaLab ../Assets/CornellBox/cornell.gltf\n```\n\nCurrently, Unicode paths are not supported. Support is planned for a future release.\n\n## Screenshots\n\n<div align=\"center\">\n  <img src=\"Assets/Images/12.png?raw=true\" alt=\"Subway Station\" style=\"zoom:50%\"/>\n  <p style=\"text-align: center;\"><i>Subway Station. (<a href=\"https://sketchfab.com/3d-models/free-subway-station-r46-subway-ae5aadde1c6f48a19b32b309417a669b\">Scene</a> by <a href=\"https://sketchfab.com/Xlay3D\">Alex Murias</a>.)</i></p>\n\n  </br>\n\n  <img src=\"Assets/Images/13.png?raw=true\" alt=\"Classroom\" style=\"zoom:50%\"/>\n  <p style=\"text-align: center;\"><i>Modified Blender 'Agent 327 Barbershop'. (Original Scene from <a href=\"https://www.blender.org/download/demo-files/\">Blender demo files</a>.)</i></p>\n\n  </br>\n\n  <img src=\"Assets/Images/2.png?raw=true\" alt=\"Classroom\" style=\"zoom:50%\"/>\n  <p style=\"text-align: center;\"><i>Modified Blender 'Classroom'. (<a href=\"https://www.blender.org/download/demo-files/\">Original Scene</a> by Christophe Seux.)</i></p>\n\n  </br>\n\n  <img src=\"Assets/Images/3.png?raw=true\" alt=\"Country Kitchen\" style=\"zoom:50%\"/>\n  <p style=\"text-align: center;\"><i>Country Kitchen. (<a href=\"https://blendswap.com/blend/5156\">Scene</a> by <a href=\"https://blendswap.com/profile/1574\">Jay-Artist</a>.)</i></p>\n\n  </br>\n\n  <img src=\"Assets/Images/5.png?raw=true\" alt=\"Bistro\" style=\"zoom:50%\"/>\n  <p style=\"text-align: center;\"><i>Amazon Lumberyard Bistro. (Scene from <a href=\"http://developer.nvidia.com/orca/amazon-lumberyard-bistro\">Open Research Content Archive (ORCA)</a>.)</i></p>\n\n  </br>\n\n  <img src=\"Assets/Images/11.png?raw=true\" alt=\"Dining Room\" style=\"zoom:50%\"/>\n  <p style=\"text-align: center;\"><i>Dining Room. (<a href=\"https://blendswap.com/blend/18762\">Scene</a> by <a href=\"https://blendswap.com/profile/543714\">MaTTeSr</a>.)</i></p>\n\n  </br>\n\n  <img src=\"Assets/Images/7.png?raw=true\" alt=\"San Miguel\" style=\"zoom:50%\"/>\n  <p style=\"text-align: center;\"><i>San Miguel 2.0. (Scene from <a href=\"https://blendswap.com/blend/18762\">Morgan McGuire's Computer Graphics Archive</a>.)</i></p>\n\n  </br>\n\n  <img src=\"Assets/Images/4.jpg?raw=true\" alt=\"San Miguel\" style=\"zoom:50%\"/>\n  <p style=\"text-align: center;\"><i>San Miguel 2.0. (Scene from <a href=\"https://casual-effects.com/data\">Morgan McGuire's Computer Graphics Archive</a>.)</i></p>\n\n  </br>\n\n  <img src=\"Assets/Images/9.png?raw=true\" alt=\"Junk Shop\" style=\"zoom:50%\"/>\n  <p style=\"text-align: center;\"><i>Modified Blender 2.81 Splash Screen. (<a href=\"https://cloud.blender.org/p/gallery/5dd6d7044441651fa3decb56\">Original scene</a> by <a href=\"http://www.aendom.com/\">Alex Treviño</a>, <a href=\"https://sketchfab.com/3d-models/ported-hair-e8eb76ad3c8f46f8aee7ceb076f05972\">hair model</a> by <a href=\"https://sketchfab.com/bbb59149\">bbb59149</a>.)</i></p>\n\n</div>\n\n## References\n\n[**1**] Y. Ouyang, S. Liu, M. Kettunen, M. Pharr and J. Pantaleoni, \"ReSTIR GI: Path Resampling for Real-Time Path Tracing,\" *Computer Graphics Forum*, 2021.\n\n[**2**] S. Hillaire, \"A Scalable and Production Ready Sky and Atmosphere Rendering Technique,\" *Computer Graphics Forum*, 2020.\n\n[**3**] MinimalAtmosphere, [https://github.com/Fewes/MinimalAtmosphere](https://github.com/Fewes/MinimalAtmosphere)\n\n[**4**] B. Bitterli, C. Wyman, M. Pharr, P. Shirley, A. Lefohn and W. Jarosz, \"Spatiotemporal reservoir resampling for real-time ray tracing with \ndynamic direct lighting,\" *ACM Transactions on Graphics*, 2020.\n\n[**5**] J. Boksansky, P. Jukarainen, and C. Wyman, \"Rendering Many Lights With Grid-Based Reservoirs,\" in Ray Tracing Gems 2, 2021.\n\n[**6**] D. Lin, M. Kettunen, B. Bitterli, J. Pantaleoni, C. Yuksel and C. Wyman, \"Generalized Resampled Importance Sampling: Foundations of ReSTIR,\" *ACM Transactions on Graphics*, 2022.\n\n[**7**] OpenPBR Surface, [https://github.com/AcademySoftwareFoundation/OpenPBR](https://github.com/AcademySoftwareFoundation/OpenPBR)\n\n## External Libraries\n\n- [AMD FSR 2](https://github.com/GPUOpen-Effects/FidelityFX-FSR2)\n- [cgltf](https://github.com/jkuhlmann/cgltf)\n- [Dear ImGui](https://github.com/ocornut/imgui)\n- [doctest](https://github.com/doctest/doctest)\n- [FastDelegate](https://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible)\n- [ImGuizmo](https://github.com/CedricGuillemet/ImGuizmo)\n- [ImPlot](https://github.com/epezent/implot)\n- [imnodes](https://github.com/Nelarius/imnodes)\n- [moodycamel::ConcurrentQueue](https://github.com/cameron314/concurrentqueue)\n- [stb](https://github.com/nothings/stb)\n- [xxHash](https://github.com/Cyan4973/xxHash)\n\n## License\n\nMIT License—see [`LICENSE`](./LICENSE) for more details."
  },
  {
    "path": "Source/CMakeLists.txt",
    "content": "add_subdirectory(ZetaCore)\nadd_subdirectory(ZetaRenderPass)\nadd_subdirectory(ZetaRenderer)\nadd_subdirectory(ZetaLab)"
  },
  {
    "path": "Source/ZetaCore/App/App.h",
    "content": "#pragma once\n\n#include \"../Support/Memory.h\"\n#ifndef NDEBUG\n#include \"../Utility/Error.h\"\n#endif\n#include \"FastDelegate/FastDelegate.h\"\n\nnamespace ZetaRay::Support\n{\n    struct TaskSet;\n    struct alignas(64) Task;\n    struct ParamVariant;\n    struct Stat;\n\n    static constexpr int MAX_NUM_THREADS = 16;\n    inline thread_local int g_threadIdx = -1;\n}\n\nnamespace ZetaRay::App\n{\n    struct FrameAllocator;\n}\n\nnamespace ZetaRay::Util\n{\n    template<typename T, Support::AllocatorType Allocator>\n    class Vector;\n\n    template<typename T>\n    struct RWSynchronizedView;\n\n    template<typename T>\n    struct Span;\n\n    template<typename T>\n    struct MutableSpan;\n\n    template<typename T>\n    struct SynchronizedSpan;\n\n    template<typename T>\n    struct SynchronizedMutableSpan;\n\n    struct StrView;\n}\n\nnamespace ZetaRay::App\n{\n    struct Timer;\n}\n\nnamespace ZetaRay::Core\n{\n    class RendererCore;\n}\n\nnamespace ZetaRay::Scene\n{\n    class SceneCore;\n    class Camera;\n}\n\nnamespace ZetaRay::Scene::Renderer\n{\n    struct Interface;\n}\n\nnamespace ZetaRay::App\n{\n    static constexpr int FRAME_ALLOCATOR_MAX_ALLOCATION_SIZE = 512 * 1024;\n\n    struct ShaderReloadHandler\n    {\n        ShaderReloadHandler() = default;\n        ShaderReloadHandler(const char* name, fastdelegate::FastDelegate0<> dlg);\n\n        static constexpr int MAX_LEN = 32;\n        static constexpr uint64_t INVALID_ID = UINT64_MAX;\n\n        uint64_t ID = INVALID_ID;\n        char Name[MAX_LEN];\n        fastdelegate::FastDelegate0<> Dlg;\n    };\n\n    struct LogMessage\n    {\n        enum MsgType\n        {\n            INFO,\n            WARNING,\n            COUNT\n        };\n\n        LogMessage() = default;\n        LogMessage(const char* msg, MsgType t);\n\n        char* Msg;\n        MsgType Type;\n    };\n\n    struct CpuInfo\n    {\n        int NumPhysicalCores;\n        int NumLogicalCores;\n    };\n\n    enum class THREAD_PRIORITY\n    {\n        NORMAL,\n        BACKGROUND\n    };\n\n    CpuInfo GetProcessorInfo();\n    void SetThreadPriority(void* handle, THREAD_PRIORITY priority);\n    void SetThreadDesc(void* handle, wchar_t* buffer);\n\n    void Init(Scene::Renderer::Interface& rendererInterface, \n        const char* name = nullptr);\n    void InitBasic();\n    void ShutdownBasic();\n    int Run();\n    void Abort();\n\n    void* AllocateFrameAllocator(size_t size, \n        size_t alignment = alignof(std::max_align_t));\n\n    int RegisterTask();\n    void TaskFinalizedCallback(int handle, int indegree);\n    void WaitForAdjacentHeadNodes(int handle);\n    void SignalAdjacentTailNodes(Util::Span<int> taskIDs);\n\n    // Submits task to priority thread pool\n    void Submit(Support::Task&& t);\n    void Submit(Support::TaskSet&& ts);\n    void SubmitBackground(Support::Task&& t);\n    void FlushWorkerThreadPool();\n    void FlushAllThreadPools();\n\n    Core::RendererCore& GetRenderer();\n    Scene::SceneCore& GetScene();\n    const Scene::Camera& GetCamera();\n    int GetNumWorkerThreads();\n    int GetNumBackgroundThreads();\n    uint32_t GetDPI();\n    float GetDPIScaling();\n    float GetUpscalingFactor();\n    void SetUpscaleFactor(float f);\n    bool IsFullScreen();\n    const App::Timer& GetTimer();\n\n    void AddParam(Support::ParamVariant& p);\n    void TryAddParam(Support::ParamVariant& p);\n    void RemoveParam(const char* group, const char* subgroup, const char* name);\n    Util::SynchronizedMutableSpan<Support::ParamVariant> GetParams();\n\n    void AddShaderReloadHandler(const char* name, fastdelegate::FastDelegate0<> dlg);\n    void RemoveShaderReloadHandler(const char* name);\n    Util::SynchronizedMutableSpan<ShaderReloadHandler> GetShaderReloadHandlers();\n\n    // These could be implemented as templated functions, but that would require the \n    // implementation to be in the header, which would then expose some heavy \n    // headers to the rest of the code base (App.h is included almost everywhere).\n    void AddFrameStat(const char* group, const char* name, int i);\n    void AddFrameStat(const char* group, const char* name, uint32_t u);\n    void AddFrameStat(const char* group, const char* name, float f);\n    void AddFrameStat(const char* group, const char* name, uint64_t f);\n    void AddFrameStat(const char* group, const char* name, uint32_t num, \n        uint32_t total);\n    Util::SynchronizedSpan<Support::Stat> GetStats();\n    Util::Span<float> GetFrameTimeHistory();\n\n    const char* GetPSOCacheDir();\n    const char* GetCompileShadersDir();\n    const char* GetAssetDir();\n    const char* GetDXCPath();\n    const char* GetToolsDir();\n    const char* GetRenderPassDir();\n\n    void LockStdOut();\n    void UnlockStdOut();\n\n    void Log(const char* msg, LogMessage::MsgType t);\n    Util::RWSynchronizedView<Util::Vector<App::LogMessage, Support::SystemAllocator>> GetLogs();\n    // Note: not thread safe.\n    void CopyToClipboard(Util::StrView data);\n\n    struct FrameAllocator\n    {\n        ZetaInline void* AllocateAligned(size_t size, size_t alignment)\n        {\n            return App::AllocateFrameAllocator(size, alignment);\n        }\n\n        ZetaInline void FreeAligned(void* mem, size_t size, \n            size_t alignment) {}\n    };\n\n    struct OneTimeFrameAllocatorWithFallback\n    {\n        ZetaInline void* AllocateAligned(size_t size, size_t alignment = alignof(std::max_align_t))\n        {\n#ifndef NDEBUG\n            Assert(m_numAllocs++ == 0, \"This allocator can't be used more than once.\");\n#endif\n            if (size + alignment - 1 < App::FRAME_ALLOCATOR_MAX_ALLOCATION_SIZE)\n                return App::AllocateFrameAllocator(size, alignment);\n\n            m_usedFallback = true;\n            return _aligned_malloc(size, alignment);\n        }\n\n        ZetaInline void FreeAligned(void* mem, size_t size, size_t alignment = alignof(std::max_align_t))\n        {\n            if(m_usedFallback)\n                _aligned_free(mem);\n        }\n\n    private:\n#ifndef NDEBUG\n        int m_numAllocs = 0;\n#endif\n        bool m_usedFallback = false;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/App/CMakeLists.txt",
    "content": "set(APP_DIR \"${ZETA_CORE_DIR}/App\")\nset(APP_SRC\n\t\"${APP_DIR}/ZetaRay.h\"\n    \"${APP_DIR}/App.h\"\n    \"${APP_DIR}/Filesystem.h\"\n    \"${APP_DIR}/Path.h\"\n    \"${APP_DIR}/Common.h\"\n    \"${APP_DIR}/Log.h\"\n    \"${APP_DIR}/Timer.h\")\nset(APP_SRC ${APP_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaCore/App/Common.h",
    "content": "#pragma once\n\n#include \"../Utility/Span.h\"\n\nnamespace ZetaRay::App::Common\n{\n    namespace CPU_Intrinsic\n    {\n        constexpr uint16_t SSE3 = 0x1;\n        constexpr uint16_t SSE4 = 0x2;\n        constexpr uint16_t AVX = 0x4;\n        constexpr uint16_t AVX2 = 0x8;\n        constexpr uint16_t F16C = 0x10;\n        constexpr uint16_t BMI1 = 0x20;\n    };\n\n    int WideToCharStr(const wchar_t* wideStr, Util::MutableSpan<char> str);\n    int CharToWideStrLen(const char* str);\n    int CharToWideStr(const char* str, Util::MutableSpan<wchar_t> wideStr);\n\n    uint32_t CheckIntrinsicSupport();\n}"
  },
  {
    "path": "Source/ZetaCore/App/Filesystem.h",
    "content": "#pragma once\n\n#include \"../Utility/Span.h\"\n#include \"../Support/MemoryArena.h\"\n\nnamespace ZetaRay::App::Filesystem\n{\n    // using a templated function for the allocator would be the obvious choice here, but unfortunately\n    // that requires moving the implementation to the header file and exposing Windows.h to the whole codebase\n    void LoadFromFile(const char* path, Util::Vector<uint8_t, Support::SystemAllocator>& fileData);\n    void LoadFromFile(const char* path, Util::Vector<uint8_t, Support::ArenaAllocator>& fileData);\n    void WriteToFile(const char* path, uint8_t* data, uint32_t sizeInBytes);\n    void RemoveFile(const char* path);\n    bool Exists(const char* path);\n    size_t GetFileSize(const char* path);\n    void CreateDirectoryIfNotExists(const char* path);\n    bool Copy(const char* srcPath, const char* dstPath, bool overwrite = false);\n    bool IsDirectory(const char* path);\n}"
  },
  {
    "path": "Source/ZetaCore/App/Log.h",
    "content": "#pragma once\n\n#include \"App.h\"\n#include \"../Utility/Error.h\"\n\n#ifndef NDEBUG\n#define LOG_CONSOLE(formatStr, ...)          \\\n{                                            \\\n    ZetaRay::App::LockStdOut();              \\\n    printf(formatStr, __VA_ARGS__);          \\\n    ZetaRay::App::UnlockStdOut();            \\\n}\n#else\n#define LOG(formatStr, ...)        ((void)0)\n#endif\n\n#define LOG_UI(TYPE, formatStr, ...) LOG_UI_##TYPE(formatStr, __VA_ARGS__)\n\n#define LOG_UI_INFO(formatStr, ...)                     \\\n{                                                       \\\n    StackStr(msg, n_, formatStr, __VA_ARGS__);          \\\n    App::Log(msg, App::LogMessage::INFO);               \\\n}\n\n#define LOG_UI_WARNING(formatStr, ...)                  \\\n{                                                       \\\n    StackStr(msg, n_, formatStr, __VA_ARGS__);          \\\n    App::Log(msg, App::LogMessage::WARNING);            \\\n}\n"
  },
  {
    "path": "Source/ZetaCore/App/Path.h",
    "content": "#include \"../App/Filesystem.h\"\n\nnamespace ZetaRay::App::Filesystem\n{\n    template<Support::AllocatorType Allocator, uint32_t InlineStorageLength>\n    struct FilePath\n    {\n        explicit FilePath(const Allocator& a = Allocator())\n            : m_path(a)\n        {}\n        explicit FilePath(Util::StrView str, const Allocator& a = Allocator())\n            : m_path(a)\n        {\n            const size_t n = str.size();\n            m_path.resize(n + 1);   // + 1 for '\\0'\n\n            if (n)\n                memcpy(m_path.data(), str.data(), n);\n\n            m_path[n] = '\\0';\n        }\n        FilePath(const FilePath&) = delete;\n        FilePath& operator=(const FilePath&) = delete;\n\n        ZetaInline bool IsEmpty() const { return m_path.empty(); }\n        ZetaInline void Resize(size_t n) { m_path.resize(n); };\n        ZetaInline char* Get() { return m_path.begin(); }\n        ZetaInline const char* Get() const { return m_path.begin(); }\n        ZetaInline Util::StrView GetView() const { return Util::StrView(m_path.begin(), m_path.size()); }\n        ZetaInline size_t Length() const { return m_path.size(); }\n        ZetaInline bool HasInlineStorage() const { return m_path.has_inline_storage(); }\n\n        void Reset(Util::StrView str)\n        {\n            if (!str.empty())\n            {\n                const size_t n = str.size();\n                m_path.resize(n + 1);   // + 1 for '\\0'\n                memcpy(m_path.data(), str.data(), n);\n                m_path[n] = '\\0';\n            }\n        }\n\n        FilePath<Allocator, InlineStorageLength>& Append(Util::StrView str, bool useBackslash = true)\n        {\n            if (str.empty())\n                return *this;\n\n            // don't read uninitialized memory\n            // (Note: underlying path storage's size and the actual string length may not match)\n            const size_t curr = m_path.empty() ? 0 : strlen(m_path.data());\n\n            size_t additionLen = str.size();\n            Util::SmallVector<char, Support::SystemAllocator, InlineStorageLength> toAppend;\n            toAppend.resize(additionLen + 1);\n\n            if (curr)\n            {\n                toAppend[0] = useBackslash ? '\\\\' : '/';\n                memcpy(toAppend.data() + 1, str.data(), additionLen);\n                additionLen++;\n            }\n            else\n                memcpy(toAppend.data(), str.data(), additionLen);\n\n            const size_t newSize = curr + additionLen + 1;\n            m_path.resize(newSize);\n\n            memcpy(m_path.begin() + curr, toAppend.data(), additionLen);\n            m_path[curr + additionLen] = '\\0';\n\n            return *this;\n        }\n\n        FilePath<Allocator, InlineStorageLength>& ToParent()\n        {\n            const size_t len = strlen(m_path.data());\n\n            char* beg = m_path.begin();\n            char* curr = beg + len;\n\n            while (curr >= beg && *curr != '\\\\' && *curr != '/')\n                curr--;\n\n            if (*curr == '\\\\' || *curr == '/')\n                *curr = '\\0';\n            else\n            {\n                m_path.resize(3);\n\n                m_path[0] = '.';\n                m_path[1] = '.';\n                m_path[2] = '\\0';\n            }\n\n            return *this;\n        }\n\n        FilePath<Allocator, InlineStorageLength>& Directory()\n        {\n            if (Filesystem::IsDirectory(m_path.data()))\n                return *this;\n\n            const size_t len = strlen(m_path.data());\n            char* beg = m_path.begin();\n            char* curr = beg + len;\n\n            while (curr >= beg && *curr != '\\\\' && *curr != '/')\n                curr--;\n\n            if (*curr == '\\\\' || *curr == '/')\n                *curr = '\\0';\n            else\n            {\n                m_path.resize(2);\n                m_path[0] = '.';\n                m_path[1] = '\\0';\n            }\n\n            return *this;\n        }\n\n        void Stem(Util::MutableSpan<char> buff, size_t* outStrLen = nullptr) const\n        {\n            const size_t len = strlen(m_path.begin());\n\n            char* beg = const_cast<char*>(m_path.begin());\n            char* curr = beg + len - 1;\n\n            size_t start = size_t(-1);\n            size_t end = size_t(-1);\n            char* firstDot = nullptr;\n\n            // figure out the first ., e.g. a.b.c -> a\n            while (curr >= beg && *curr != '\\\\' && *curr != '/')\n            {\n                if (*curr == '.')\n                    firstDot = curr;\n\n                curr--;\n            }\n\n            firstDot = firstDot ? firstDot : beg + len;\n            end = firstDot - beg;\n            start = curr - beg + 1;\n\n            size_t s = end - start + 1;\n            //Check(buff.size() >= s, \"provided buffer is too small\");\n\n            if (s > 1)\n                memcpy(buff.data(), beg + start, Math::Min(s - 1, buff.size() - 1));\n\n            buff.data()[s - 1] = '\\0';\n\n            if (outStrLen)\n                *outStrLen = s - 1;\n        }\n\n        void Extension(Util::MutableSpan<char> buff, size_t* outStrLen = nullptr) const\n        {\n            const size_t len = strlen(m_path.begin());\n\n            char* beg = const_cast<char*>(m_path.begin());\n            char* curr = beg + len - 1;\n\n            size_t start = size_t(-1);\n            size_t end = size_t(-1);\n\n            // figure out the first ., e.g. a.b.c -> a\n            while (curr >= beg && *curr != '.')\n                curr--;\n\n            if (curr < beg)\n            {\n                if (outStrLen)\n                    *outStrLen = 0;\n\n                return;\n            }\n\n            size_t s = beg + len - 1 - curr;\n            Check(buff.size() >= s + 1, \"Provided buffer is too small.\");\n\n            if (s > 1)\n                memcpy(buff.data(), curr + 1, s);\n\n            buff.data()[s] = '\\0';\n\n            if (outStrLen)\n                *outStrLen = s;\n        }\n\n        void ConvertToBackslashes()\n        {\n            const size_t len = strlen(m_path.begin());\n            char* srcData = m_path.begin();\n\n            for (size_t i = 0; i < len; i++)\n            {\n                if (srcData[i] == '/')\n                    srcData[i] = '\\\\';\n            }\n        }\n\n        void ConvertToForwardSlashes()\n        {\n            const size_t len = strlen(m_path.begin());\n            char* srcData = m_path.begin();\n\n            for (size_t i = 0; i < len; i++)\n            {\n                if (srcData[i] == '\\\\')\n                    srcData[i] = '/';\n            }\n        }\n\n    private:\n        Util::SmallVector<char, Allocator, InlineStorageLength> m_path;\n    };\n\n    using Path = FilePath<Support::SystemAllocator, 128>;\n}"
  },
  {
    "path": "Source/ZetaCore/App/Timer.h",
    "content": "#pragma once\n\n#include \"../Utility/Error.h\"\n\nnamespace ZetaRay::App\n{\n    struct Timer\n    {\n        Timer();\n        ~Timer() = default;\n\n        // Returns elapsed time since the last time Tick() was called\n        ZetaInline double GetElapsedTime() const { return m_delta; }\n\n        // Get total number of updates since start of the program\n        ZetaInline uint64_t GetTotalFrameCount() const { return m_frameCount; }\n        ZetaInline int GetFramesPerSecond() const { return m_fps; }\n        ZetaInline int64_t GetCounterFreq() const { return m_counterFreqSec; }\n\n        void Start();\n        void Resume();\n        void Pause();\n        void Tick();\n\n        // Get total time since the start of the program.\n        ZetaInline double GetTotalTime() const\n        {\n            int64_t numCounts;\n\n            if (!m_paused)\n                numCounts = ((m_last - m_start) - m_totalPausedCounts);\n            else\n                numCounts = ((m_pauseCount - m_start) - m_totalPausedCounts);\n\n            return (double)numCounts / m_counterFreqSec;\n        }\n\n    private:\n        // frequency of the counter. Units are counts/sec\n        int64_t m_counterFreqSec;\n\n        // last queried count\n        int64_t m_last;\n\n        // app start count\n        int64_t m_start;\n\n        // track duration of time when the app was stopped\n        int64_t m_pauseCount = 0;\n        int64_t m_totalPausedCounts = 0;\n        bool m_paused = false;\n\n        // number of frames rendered since the program started\n        uint64_t m_frameCount = 0;\n\n        // total number of counts since the program started\n        //double m_totalTime = 0.0;\n\n        // frames per-second\n        int64_t m_framesInLastSecond = 0;\n        int64_t m_numCountsInLastSecond = 0;\n        int m_fps = 0;\n\n        // counts since the last update\n        int64_t m_elapsedCounts;\n        // time passed since the last update\n        double m_delta;\n    };\n\n    struct DeltaTimer\n    {\n        DeltaTimer();\n\n        void Start();\n        void End();\n        double DeltaMilli();\n        double DeltaMicro();\n        double DeltaNano();\n        double MinDeltaGt0()\n        {\n            double d0 = DeltaMilli();\n            if (d0 > 0)\n                return d0;\n\n            double d1 = DeltaMicro();\n            if (d1 > 0)\n                return d1;\n\n            return DeltaNano();\n        }\n\n    private:\n        // Counter frequency. Units are counts/sec.\n        int64_t m_counterFreqSec;\n        int64_t m_start = 0;\n        int64_t m_end = 0;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/App/ZetaRay.h",
    "content": "#pragma once\n\n#define _HAS_EXCEPTIONS 0\n\n#include <cstdint>\n\n// Ref: https://www.foonathan.net/2020/09/move-forward/\n#define ZetaMove(x) static_cast<std::remove_reference_t<decltype(x)>&&>(x)\n#define ZetaForward(x) static_cast<decltype(x)&&>(x)\n\n#define ZetaInline __forceinline\n#define ZetaArrayLen(x) sizeof(x) / sizeof(x[0])\n\n#define uint8 uint8_t\n#define uint16 uint16_t\n#define uint32 uint32_t\n#define uint64 uint64_t\n#define int8 int8_t\n#define int16 int16_t\n#define int32 int32_t\n#define int64 int64_t"
  },
  {
    "path": "Source/ZetaCore/CMakeLists.txt",
    "content": "include(\"${CMAKE_INCLUDE_DIR}/Copy.cmake\")\ninclude(\"${CMAKE_INCLUDE_DIR}/SetupAgilitySDK.cmake\")\ninclude(\"${CMAKE_INCLUDE_DIR}/SetupWinPIX.cmake\")\ninclude(\"${CMAKE_INCLUDE_DIR}/SetupxxHash.cmake\")\ninclude(\"${CMAKE_INCLUDE_DIR}/Setupcgltf.cmake\")\ninclude(\"${CMAKE_INCLUDE_DIR}/SetupImGui.cmake\")\n\nadd_subdirectory(App)\nadd_subdirectory(Core)\nadd_subdirectory(Math)\nadd_subdirectory(Model)\nadd_subdirectory(RayTracing)\nadd_subdirectory(Scene)\nadd_subdirectory(Support)\nadd_subdirectory(Utility)\nadd_subdirectory(Win32)\n\nset(CORE_SRC\n    ${APP_SRC}\n    ${CORE_SRC}\n    ${MATH_SRC}\n    ${MODEL_SRC}\n    ${RT_SRC}\n    ${SCENE_SRC}\n    ${SUPPORT_SRC}\n    ${UTIL_SRC}\n    ${WIN32_SRC})\n\n# \n# ImGui\n# \nSetupImGui()\nset(IMGUI_DIR \"${EXTERNAL_DIR}/ImGui\")\nset(IMGUI_SRC \"${IMGUI_DIR}/imgui.cpp\"\n    \"${IMGUI_DIR}/imconfig.h\"\n    \"${IMGUI_DIR}/imgui_draw.cpp\"\n    \"${IMGUI_DIR}/imgui_tables.cpp\"\n    \"${IMGUI_DIR}/imgui_widgets.cpp\"\n    \"${IMGUI_DIR}/imnodes.cpp\"\n    \"${IMGUI_DIR}/implot.cpp\"\n    \"${IMGUI_DIR}/implot_items.cpp\"\n    \"${IMGUI_DIR}/ImGuizmo.cpp\")\n\n# natvis\nset(NATVIS_SRC \"${TOOLS_DIR}/Natvis/Container.natvis\"\n    \"${TOOLS_DIR}/Natvis/imgui.natvis\"\n    \"${TOOLS_DIR}/Natvis/App.natvis\")\n\nsource_group(TREE \"${ZETA_CORE_DIR}\" FILES ${CORE_SRC})\nsource_group(TREE \"${TOOLS_DIR}/Natvis\" PREFIX \"Natvis\" FILES ${NATVIS_SRC})\nsource_group(TREE \"${EXTERNAL_DIR}\" PREFIX \"External\" FILES ${IMGUI_SRC})\n\n# build ZetaCore as a static library\nadd_library(ZetaCore STATIC ${CORE_SRC} ${IMGUI_SRC} ${NATVIS_SRC})\ntarget_include_directories(ZetaCore PUBLIC \"${EXTERNAL_DIR}\" PRIVATE \"${ZETA_CORE_DIR}\" \"${IMGUI_DIR}\" AFTER)\nset_target_properties(ZetaCore PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\n\n# \n# WinPixEventRuntime\n# \nSetupWinPIX()\nadd_library(WinPixEventRuntimeLib SHARED IMPORTED GLOBAL)\nset_target_properties(WinPixEventRuntimeLib PROPERTIES IMPORTED_IMPLIB \"${EXTERNAL_DIR}/WinPixEventRuntime/WinPixEventRuntime.lib\")\n\n# \n# xxHash\n# \nSetupxxHash()\n\n# \n# cgltf\n# \nSetupcgltf()\n\n# custom command that copies the dll to the runtime directory\nset(WINPIXEVENT_DLL_PATH \"${EXTERNAL_DIR}/WinPixEventRuntime/WinPixEventRuntime.dll\")\nCopy(\"${WINPIXEVENT_DLL_PATH}\" \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\" CopyWinPixDLL)\nadd_dependencies(WinPixEventRuntimeLib CopyWinPixDLL)\n\n# \n# DirectX Agility SDK\n# \nSetupAgilitySDK(AGILITY_SDK_VER)\nadd_library(DX12AgilitySDK INTERFACE)\nset(DX12AgilitySDK_BIN\n    \"${EXTERNAL_DIR}/D3D12/${AGILITY_SDK_VER}/D3D12Core.dll\"\n    \"${EXTERNAL_DIR}/D3D12/${AGILITY_SDK_VER}/d3d12SDKLayers.dll\")\n\nCopy(\"${DX12AgilitySDK_BIN}\" \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/D3D12/\" CopyDX12AgilitySDKBins)\nadd_dependencies(DX12AgilitySDK CopyDX12AgilitySDKBins)\n\n# Font\nadd_library(FONT INTERFACE)\nset(FONT_LIB \"${ASSET_DIR}/Font/Font.dll\")\n\n# custom command that copies the dlls into the runtime directory\nCopy(\"${FONT_LIB}\" \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/\" CopyFontDLL)\nadd_dependencies(FONT CopyFontDLL)\n\n# \n# link against all the external libraries\n# \nset(LIBS d3d12 dxgi dxguid DX12AgilitySDK WinPixEventRuntimeLib FONT)\ntarget_link_libraries(ZetaCore debug ${LIBS} dbghelp)\ntarget_link_libraries(ZetaCore optimized ${LIBS})\n"
  },
  {
    "path": "Source/ZetaCore/Core/CMakeLists.txt",
    "content": "set(CORE_DIR \"${ZETA_CORE_DIR}/Core\")\nset(CORE_SRC\n    \"${CORE_DIR}/CommandList.cpp\"\n    \"${CORE_DIR}/CommandList.h\"\n    \"${CORE_DIR}/CommandQueue.cpp\"\n    \"${CORE_DIR}/CommandQueue.h\"\n    \"${CORE_DIR}/Config.h\"\n    \"${CORE_DIR}/dds.h\"\n    \"${CORE_DIR}/DescriptorHeap.cpp\"\n    \"${CORE_DIR}/DescriptorHeap.h\"\n    \"${CORE_DIR}/Device.cpp\"\n    \"${CORE_DIR}/Device.h\"\n    \"${CORE_DIR}/Direct3DUtil.cpp\"\n    \"${CORE_DIR}/Direct3DUtil.h\"\n    \"${CORE_DIR}/GpuMemory.cpp\"\n    \"${CORE_DIR}/GpuMemory.h\"\n    \"${CORE_DIR}/GpuTimer.cpp\"\n    \"${CORE_DIR}/GpuTimer.h\"\n    \"${CORE_DIR}/HLSLCompat.h\"\n    \"${CORE_DIR}/Material.h\"\n    \"${CORE_DIR}/PipelineStateLibrary.cpp\"\n    \"${CORE_DIR}/PipelineStateLibrary.h\"\n    \"${CORE_DIR}/RendererCore.cpp\"\n    \"${CORE_DIR}/RendererCore.h\"\n    \"${CORE_DIR}/RenderGraph.cpp\"\n    \"${CORE_DIR}/RenderGraph.h\"\n    \"${CORE_DIR}/RootSignature.cpp\"\n    \"${CORE_DIR}/RootSignature.h\"\n    \"${CORE_DIR}/SharedShaderResources.cpp\"\n    \"${CORE_DIR}/SharedShaderResources.h\"\n    \"${CORE_DIR}/Vertex.h\")\nset(CORE_SRC ${CORE_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaCore/Core/CommandList.cpp",
    "content": "#include \"CommandList.h\"\n#include \"RendererCore.h\"\n\nusing namespace ZetaRay::Core;\n\n//--------------------------------------------------------------------------------------\n// CommandContext\n//--------------------------------------------------------------------------------------\n\nCommandList::CommandList(D3D12_COMMAND_LIST_TYPE t, ID3D12CommandAllocator* cmdAlloc)\n    : m_cmdAllocator(cmdAlloc),\n    m_type(t)\n{\n    auto* device = App::GetRenderer().GetDevice();\n\n    ID3D12GraphicsCommandList* cmdList = nullptr;\n    CheckHR(device->CreateCommandList(0, t, m_cmdAllocator, nullptr, IID_PPV_ARGS(&cmdList)));\n    CheckHR(cmdList->QueryInterface(IID_PPV_ARGS(m_cmdList.GetAddressOf())));\n    Assert(cmdList->Release() == 1, \"bug\");\n}\n\nvoid CommandList::Reset(ID3D12CommandAllocator* cmdAlloc)\n{\n    Assert(m_cmdList && !m_cmdAllocator, \"bug\");\n    m_cmdAllocator = cmdAlloc;\n    CheckHR(m_cmdList->Reset(m_cmdAllocator, nullptr));\n\n    // D3D specs: \"There is a new ordering constraint between SetDescriptorHeaps and \n    // SetGraphicsRootSignature or SetComputeRootSignature. SetDescriptorHeaps must be \n    // called, passing the corresponding heaps, before a call to SetGraphicsRootSignature \n    // or SetComputeRootSignature that uses either CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED or \n    // SAMPLER_HEAP_DIRECTLY_INDEXED flags.\"\n    auto& renderer = App::GetRenderer();\n    ID3D12DescriptorHeap* heaps[] = {\n        renderer.GetGpuDescriptorHeap().GetHeap(),\n        renderer.GetSamplerDescriptorHeap()\n    };\n    m_cmdList->SetDescriptorHeaps(ZetaArrayLen(heaps), heaps);\n}\n"
  },
  {
    "path": "Source/ZetaCore/Core/CommandList.h",
    "content": "#pragma once\n\n#include \"Direct3DUtil.h\"\n#include \"RootSignature.h\"\n#include \"../Utility/Error.h\"\n#define USE_PIX\n#include <WinPixEventRuntime/pix3.h>\n\nnamespace ZetaRay::Core\n{\n    //--------------------------------------------------------------------------------------\n    // CommandList\n    //--------------------------------------------------------------------------------------\n\n    class CommandList\n    {\n        friend struct CommandQueue;\n\n    public:\n        ~CommandList() = default;\n\n        CommandList(const CommandList&) = delete;\n        CommandList& operator=(const CommandList&) = delete;\n\n        void Reset(ID3D12CommandAllocator* cmdAlloc);\n        ZetaInline D3D12_COMMAND_LIST_TYPE GetType() const { return m_type; }\n\n        ZetaInline void PIXBeginEvent(const char* s)\n        {\n            ::PIXBeginEvent(m_cmdList.Get(), PIX_COLOR_DEFAULT, s);\n        }\n\n        ZetaInline void PIXEndEvent()\n        {\n            ::PIXEndEvent(m_cmdList.Get());\n        }\n\n        ZetaInline void SetName(const char* s)\n        {\n            m_cmdList->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)strlen(s), s);\n        }\n\n        ZetaInline ID3D12GraphicsCommandList7* Get()\n        {\n            return m_cmdList.Get();\n        }\n\n    protected:\n        CommandList(D3D12_COMMAND_LIST_TYPE t, ID3D12CommandAllocator* cmdAlloc);\n\n        D3D12_COMMAND_LIST_TYPE m_type;\n        ComPtr<ID3D12GraphicsCommandList7> m_cmdList;\n        ID3D12CommandAllocator* m_cmdAllocator = nullptr;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // CopyContext\n    //--------------------------------------------------------------------------------------\n\n    class CopyCmdList : public CommandList\n    {\n    public:\n        CopyCmdList(D3D12_COMMAND_LIST_TYPE t, ID3D12CommandAllocator* cmdAlloc)\n            : CommandList(t, cmdAlloc)\n        {}\n\n        ZetaInline void ResourceBarrier(ID3D12Resource* res, D3D12_RESOURCE_STATES oldState, D3D12_RESOURCE_STATES newState,\n            UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES)\n        {\n            Assert(oldState != newState, \"Invalid barrier states\");\n            auto barrier = Direct3DUtil::TransitionBarrier(res, oldState, newState, subresource);\n            m_cmdList->ResourceBarrier(1, &barrier);\n        }\n\n        ZetaInline void ResourceBarrier(D3D12_RESOURCE_BARRIER* barriers, UINT numBarriers)\n        {\n            m_cmdList->ResourceBarrier(numBarriers, barriers);\n        }\n\n        ZetaInline void ResourceBarrier(D3D12_BUFFER_BARRIER& barrier)\n        {\n            const auto barrierGroup = Direct3DUtil::BarrierGroup(&barrier, 1);\n            m_cmdList->Barrier(1, &barrierGroup);\n        }\n\n        ZetaInline void ResourceBarrier(D3D12_BUFFER_BARRIER* barriers, UINT numBarriers)\n        {\n            const auto barrierGroup = Direct3DUtil::BarrierGroup(barriers, numBarriers);\n            m_cmdList->Barrier(1, &barrierGroup);\n        }\n\n        ZetaInline void ResourceBarrier(D3D12_TEXTURE_BARRIER& barrier)\n        {\n            const auto barrierGroup = Direct3DUtil::BarrierGroup(&barrier, 1);\n            m_cmdList->Barrier(1, &barrierGroup);\n        }\n\n        ZetaInline void ResourceBarrier(D3D12_TEXTURE_BARRIER* barriers, UINT numBarriers)\n        {\n            const auto barrierGroup = Direct3DUtil::BarrierGroup(barriers, numBarriers);\n            m_cmdList->Barrier(1, &barrierGroup);\n        }\n\n        ZetaInline void ResourceBarrier(D3D12_BARRIER_GROUP* barrierGroups, UINT numBarrierGroups)\n        {\n            m_cmdList->Barrier(numBarrierGroups, barrierGroups);\n        }\n\n        ZetaInline void UAVBarrier(ID3D12Resource* res)\n        {\n            D3D12_RESOURCE_BARRIER barriers[1];\n            barriers[0] = Direct3DUtil::UAVBarrier(res);\n            m_cmdList->ResourceBarrier(1, barriers);\n        }\n\n        ZetaInline void UAVBarrier(UINT numBarriers, D3D12_RESOURCE_BARRIER* barriers)\n        {\n            m_cmdList->ResourceBarrier(numBarriers, barriers);\n        }\n\n        ZetaInline void CopyResource(ID3D12Resource* dstResource, ID3D12Resource* srcResource)\n        {\n            m_cmdList->CopyResource(dstResource, srcResource);\n        }\n\n        ZetaInline void CopyBufferRegion(ID3D12Resource* dstBuffer, UINT64 dstOffset, ID3D12Resource* srcBuffer,\n            UINT64 srcOffset, UINT64 numBytes)\n        {\n            m_cmdList->CopyBufferRegion(dstBuffer, dstOffset, srcBuffer, srcOffset, numBytes);\n        }\n\n        ZetaInline void CopyTextureRegion(const D3D12_TEXTURE_COPY_LOCATION* dst,\n            UINT dstX,\n            UINT dstY,\n            UINT dstZ,\n            const D3D12_TEXTURE_COPY_LOCATION* src,\n            const D3D12_BOX* srcBox)\n        {\n            m_cmdList->CopyTextureRegion(dst, dstX, dstY, dstZ, src, srcBox);\n        }\n    };\n\n    //--------------------------------------------------------------------------------------\n    // ComputeContext\n    //--------------------------------------------------------------------------------------\n\n    class ComputeCmdList : public CopyCmdList\n    {\n    public:\n        ComputeCmdList(D3D12_COMMAND_LIST_TYPE t, ID3D12CommandAllocator* cmdAlloc)\n            : CopyCmdList(t, cmdAlloc)\n        {}\n\n        ZetaInline void BeginQuery(ID3D12QueryHeap* queryHeap, D3D12_QUERY_TYPE type, UINT index)\n        {\n            m_cmdList->BeginQuery(queryHeap, type, index);\n        }\n\n        ZetaInline void ResolveQueryData(ID3D12QueryHeap* queryHeap,\n            D3D12_QUERY_TYPE type,\n            UINT startIndex,\n            UINT numQueries,\n            ID3D12Resource* destinationBuffer,\n            UINT64 alignedDestinationBufferOffset)\n        {\n            m_cmdList->ResolveQueryData(queryHeap, type, startIndex, numQueries, destinationBuffer, alignedDestinationBufferOffset);\n        }\n\n        ZetaInline void EndQuery(ID3D12QueryHeap* queryHeap, D3D12_QUERY_TYPE type, UINT index)\n        {\n            m_cmdList->EndQuery(queryHeap, type, index);\n        }\n\n        ZetaInline void ClearUnorderedAccessViewFloat(D3D12_GPU_DESCRIPTOR_HANDLE viewGPUHandleInCurrentHeap,\n            D3D12_CPU_DESCRIPTOR_HANDLE viewCPUHandle,\n            ID3D12Resource* resource,\n            float clearX = 0.0f, float clearY = 0.0f, float clearZ = 0.0f, float ClearW = 0.0f,\n            UINT numRects = 0,\n            const D3D12_RECT* rects = nullptr)\n        {\n            FLOAT values[4] = { clearX, clearY, clearZ, ClearW };\n\n            m_cmdList->ClearUnorderedAccessViewFloat(\n                viewGPUHandleInCurrentHeap,\n                viewCPUHandle,\n                resource,\n                values,\n                numRects,\n                rects);\n        }\n\n        ZetaInline void ClearUnorderedAccessViewUint(D3D12_GPU_DESCRIPTOR_HANDLE viewGPUHandleInCurrentHeap,\n            D3D12_CPU_DESCRIPTOR_HANDLE viewCPUHandle,\n            ID3D12Resource* resource,\n            UINT clearX = 0, UINT clearY = 0, UINT clearZ = 0, UINT clearW = 0,\n            UINT numRects = 0,\n            const D3D12_RECT* rects = nullptr)\n        {\n            UINT values[4] = { clearX, clearY, clearZ, clearW };\n\n            m_cmdList->ClearUnorderedAccessViewUint(viewGPUHandleInCurrentHeap,\n                viewCPUHandle,\n                resource,\n                values,\n                numRects,\n                rects);\n        }\n\n        ZetaInline void SetRootSignature(RootSignature& rootSig, ID3D12RootSignature* rootSigObj)\n        {\n            rootSig.Begin();\n            Assert(rootSigObj, \"rootSigObj was NULL\");\n            m_cmdList->SetComputeRootSignature(rootSigObj);\n        }\n\n        ZetaInline void SetRootSignature(ID3D12RootSignature* rootSigObj)\n        {\n            Assert(rootSigObj, \"rootSigObj was NULL\");\n            m_cmdList->SetComputeRootSignature(rootSigObj);\n        }\n\n        ZetaInline void SetRootConstantBufferView(UINT rootParameterIndex, D3D12_GPU_VIRTUAL_ADDRESS bufferLocation)\n        {\n            m_cmdList->SetComputeRootConstantBufferView(rootParameterIndex, bufferLocation);\n        }\n\n        ZetaInline void SetRootShaderResourceView(UINT rootParameterIndex, D3D12_GPU_VIRTUAL_ADDRESS bufferLocation)\n        {\n            m_cmdList->SetComputeRootShaderResourceView(rootParameterIndex, bufferLocation);\n        }\n\n        ZetaInline void SetRootDescriptorTable(UINT rootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor)\n        {\n            m_cmdList->SetComputeRootDescriptorTable(rootParameterIndex, baseDescriptor);\n        }\n\n        ZetaInline void SetRootUnorderedAccessView(UINT rootParameterIndex, D3D12_GPU_VIRTUAL_ADDRESS bufferLocation)\n        {\n            m_cmdList->SetComputeRootUnorderedAccessView(rootParameterIndex, bufferLocation);\n        }\n\n        ZetaInline void SetRoot32BitConstants(UINT rootParameterIndex,\n            UINT num32BitValuesToSet,\n            const void* srcData,\n            UINT destOffsetIn32BitValues)\n        {\n            m_cmdList->SetComputeRoot32BitConstants(rootParameterIndex, num32BitValuesToSet, srcData, destOffsetIn32BitValues);\n        }\n\n        ZetaInline void SetPipelineState(ID3D12PipelineState* pipelineState)\n        {\n            Assert(pipelineState, \"pipelineState was NULL\");\n            m_cmdList->SetPipelineState(pipelineState);\n        }\n\n        ZetaInline void SetPipelineState1(ID3D12StateObject* rtPSO)\n        {\n            Assert(rtPSO, \"rtPSO was NULL\");\n            m_cmdList->SetPipelineState1(rtPSO);\n        }\n\n        ZetaInline void Dispatch(UINT threadGroupCountX, UINT threadGroupCountY, UINT threadGroupCountZ)\n        {\n            m_cmdList->Dispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ);\n        }\n\n        ZetaInline void SetPredication(ID3D12Resource* buffer, UINT64 bufferOffset, D3D12_PREDICATION_OP op)\n        {\n            m_cmdList->SetPredication(buffer, bufferOffset, op);\n        }\n\n        ZetaInline void BuildRaytracingAccelerationStructure(const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC* desc,\n            UINT numPostbuildInfoDescs,\n            const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC* postbuildInfoDescs)\n        {\n            m_cmdList->BuildRaytracingAccelerationStructure(desc, numPostbuildInfoDescs, postbuildInfoDescs);\n        }\n\n        ZetaInline void CompactAccelerationStructure(D3D12_GPU_VIRTUAL_ADDRESS dest, D3D12_GPU_VIRTUAL_ADDRESS src)\n        {\n            m_cmdList->CopyRaytracingAccelerationStructure(dest, src, D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_COMPACT);\n        }\n\n        ZetaInline void CopyAccelerationStructure(D3D12_GPU_VIRTUAL_ADDRESS dest, D3D12_GPU_VIRTUAL_ADDRESS src)\n        {\n            m_cmdList->CopyRaytracingAccelerationStructure(dest, src, D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_CLONE);\n        }\n\n        ZetaInline void ExecuteIndirect(ID3D12CommandSignature* cmdSig,\n            UINT maxCmdCount,\n            ID3D12Resource* argBuffer,\n            UINT64 argBufferOffset,\n            ID3D12Resource* countBuffer,\n            UINT64 countBufferOffset)\n        {\n            m_cmdList->ExecuteIndirect(cmdSig, maxCmdCount, argBuffer, argBufferOffset, countBuffer, countBufferOffset);\n        }\n\n        ZetaInline void DispatchRays(D3D12_GPU_VIRTUAL_ADDRESS rayGenAddr, UINT64 rayGenSizeInBytes,\n            D3D12_GPU_VIRTUAL_ADDRESS missTableAddr, UINT64 missTableSizeInBytes, UINT64 missTableStrideInBytes,\n            D3D12_GPU_VIRTUAL_ADDRESS hitTableAddr, UINT64 hitTableSizeInBytes, UINT64 hitTableStrideInBytes,\n            UINT width,\n            UINT height,\n            UINT depth = 1)\n        {\n            D3D12_DISPATCH_RAYS_DESC desc;\n            desc.RayGenerationShaderRecord.StartAddress = rayGenAddr;\n            desc.RayGenerationShaderRecord.SizeInBytes = rayGenSizeInBytes;\n            desc.MissShaderTable.StartAddress = missTableAddr;\n            desc.MissShaderTable.SizeInBytes = missTableSizeInBytes;\n            desc.MissShaderTable.StrideInBytes = missTableStrideInBytes;\n            desc.HitGroupTable.StartAddress = hitTableAddr;\n            desc.HitGroupTable.SizeInBytes = hitTableSizeInBytes;\n            desc.HitGroupTable.StrideInBytes = hitTableStrideInBytes;\n            desc.CallableShaderTable.StartAddress = 0;\n            desc.CallableShaderTable.SizeInBytes = 0;\n            desc.CallableShaderTable.StrideInBytes = 0;\n            desc.Width = width;\n            desc.Height = height;\n            desc.Depth = depth;\n\n            m_cmdList->DispatchRays(&desc);\n        }\n    };\n\n    //--------------------------------------------------------------------------------------\n    // GraphicsContext\n    //--------------------------------------------------------------------------------------\n\n    class GraphicsCmdList final : public ComputeCmdList\n    {\n    public:\n        explicit GraphicsCmdList(ID3D12CommandAllocator* cmdAlloc)\n            : ComputeCmdList(D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc)\n        {}\n\n        ZetaInline void SetRootSignature(RootSignature& rootSig, ID3D12RootSignature* rootSigObj)\n        {\n            rootSig.Begin();\n            Assert(rootSigObj, \"rootSigObj was NULL\");\n            m_cmdList->SetGraphicsRootSignature(rootSigObj);\n        }\n\n        ZetaInline void SetRootConstantBufferView(UINT rootParameterIndex, D3D12_GPU_VIRTUAL_ADDRESS bufferLocation)\n        {\n            m_cmdList->SetGraphicsRootConstantBufferView(rootParameterIndex, bufferLocation);\n        }\n\n        ZetaInline void SetRootShaderResourceView(UINT rootParameterIndex, D3D12_GPU_VIRTUAL_ADDRESS bufferLocation)\n        {\n            m_cmdList->SetGraphicsRootShaderResourceView(rootParameterIndex, bufferLocation);\n        }\n\n        ZetaInline void SetRootDescriptorTable(UINT rootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor)\n        {\n            m_cmdList->SetGraphicsRootDescriptorTable(rootParameterIndex, baseDescriptor);\n        }\n\n        ZetaInline void SetRootUnorderedAccessView(UINT rootParameterIndex, D3D12_GPU_VIRTUAL_ADDRESS bufferLocation)\n        {\n            m_cmdList->SetGraphicsRootUnorderedAccessView(rootParameterIndex, bufferLocation);\n        }\n\n        ZetaInline void SetRoot32BitConstants(UINT rootParameterIndex,\n            UINT num32BitValuesToSet,\n            const void* srcData,\n            UINT destOffsetIn32BitValues)\n        {\n            m_cmdList->SetGraphicsRoot32BitConstants(rootParameterIndex, num32BitValuesToSet, srcData, destOffsetIn32BitValues);\n        }\n\n        void ClearDepthStencilView(D3D12_CPU_DESCRIPTOR_HANDLE depthStencilView,\n            D3D12_CLEAR_FLAGS clearFlags,\n            FLOAT depth = 1.0f, UINT8 stencil = 0,\n            UINT numRects = 0, const D3D12_RECT* rects = nullptr)\n        {\n            m_cmdList->ClearDepthStencilView(depthStencilView, clearFlags, depth, stencil, numRects, rects);\n        }\n\n        ZetaInline void ClearRenderTargetView(D3D12_CPU_DESCRIPTOR_HANDLE renderTargetView,\n            float r, float g, float b, float a,\n            UINT numRects = 0, const D3D12_RECT* rects = nullptr)\n        {\n            FLOAT rgb[4] = { r, g, b, a };\n            m_cmdList->ClearRenderTargetView(renderTargetView, rgb, numRects, rects);\n        }\n\n        ZetaInline void IASetPrimitiveTopology(D3D12_PRIMITIVE_TOPOLOGY primitiveTopology)\n        {\n            m_cmdList->IASetPrimitiveTopology(primitiveTopology);\n        }\n\n        ZetaInline void IASetVertexAndIndexBuffers(const D3D12_VERTEX_BUFFER_VIEW& vbv,\n            const D3D12_INDEX_BUFFER_VIEW& ibv,\n            UINT startSlot = 0)\n        {\n            m_cmdList->IASetVertexBuffers(startSlot, 1, &vbv);\n            m_cmdList->IASetIndexBuffer(&ibv);\n        }\n\n        ZetaInline void IASetIndexBuffer(const D3D12_INDEX_BUFFER_VIEW& ibv)\n        {\n            m_cmdList->IASetIndexBuffer(&ibv);\n        }\n\n        ZetaInline void DrawInstanced(UINT vertexCountPerInstance,\n            UINT instanceCount,\n            UINT startVertexLocation,\n            UINT startInstanceLocation)\n        {\n            m_cmdList->DrawInstanced(vertexCountPerInstance, instanceCount, startVertexLocation, startInstanceLocation);\n        }\n\n        ZetaInline void DrawIndexedInstanced(UINT indexCountPerInstance,\n            UINT instanceCount,\n            UINT startIndexLocation,\n            INT  baseVertexLocation,\n            UINT startInstanceLocation)\n        {\n            m_cmdList->DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation);\n        }\n\n        ZetaInline void OMSetRenderTargets(UINT numRenderTargetDescriptors, \n            const D3D12_CPU_DESCRIPTOR_HANDLE* renderTargetDescriptors,\n            BOOL RTsSingleHandleToDescriptorRange, \n            const D3D12_CPU_DESCRIPTOR_HANDLE* depthStencilDescriptor)\n        {\n            m_cmdList->OMSetRenderTargets(numRenderTargetDescriptors, renderTargetDescriptors, RTsSingleHandleToDescriptorRange, depthStencilDescriptor);\n        }\n\n        ZetaInline void RSSetViewports(UINT num, const D3D12_VIEWPORT* viewports)\n        {\n            m_cmdList->RSSetViewports(num, viewports);\n        }\n\n        ZetaInline void RSSetViewportsScissorsRects(int num, const D3D12_VIEWPORT* viewports, const D3D12_RECT* rects = nullptr)\n        {\n            m_cmdList->RSSetViewports(num, viewports);\n\n            if (rects)\n                m_cmdList->RSSetScissorRects(num, rects);\n        }\n\n        ZetaInline void RSSetScissorRects(UINT numRects, const D3D12_RECT* rects)\n        {\n            m_cmdList->RSSetScissorRects(numRects, rects);\n        }\n\n        ZetaInline void OMSetBlendFactor(float blendFactorR, float blendFactorG, float blendFactorB, float blendFactorW)\n        {\n            FLOAT rgb[4] = { blendFactorR, blendFactorG, blendFactorB, blendFactorW };\n            m_cmdList->OMSetBlendFactor(rgb);\n        }\n\n        ZetaInline void SetPredication(ID3D12Resource* buffer, UINT64 bufferOffset, D3D12_PREDICATION_OP op)\n        {\n            m_cmdList->SetPredication(buffer, bufferOffset, op);\n        }\n    };\n}\n\n"
  },
  {
    "path": "Source/ZetaCore/Core/CommandQueue.cpp",
    "content": "#include \"CommandQueue.h\"\n#include \"RendererCore.h\"\n#include \"CommandList.h\"\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\n\n//--------------------------------------------------------------------------------------\n// CommandQueue\n//--------------------------------------------------------------------------------------\n\nCommandQueue::CommandQueue(D3D12_COMMAND_LIST_TYPE type)\n    : m_type(type)\n{}\n\nCommandQueue::~CommandQueue()\n{\n    if (m_initialized)\n    {\n        WaitForIdle();\n\n        CommandList* ctx;\n        while (m_contextPool.try_dequeue(ctx))\n            delete ctx;\n\n        if (m_event)\n            CloseHandle(m_event);\n\n        for (auto& it : m_cmdAllocPool)\n            it.CmdAlloc->Release();\n    }\n}\n\nvoid CommandQueue::Init()\n{\n    auto* device = App::GetRenderer().GetDevice();\n\n    D3D12_COMMAND_QUEUE_DESC queueDesc{};\n    queueDesc.Type = m_type;\n    queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;\n    CheckHR(device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(m_cmdQueue.GetAddressOf())));\n    CheckHR(device->CreateFence(m_lastCompletedFenceVal, D3D12_FENCE_FLAG_NONE,\n        IID_PPV_ARGS(m_fence.GetAddressOf())));\n\n    m_event = CreateEventA(nullptr, false, false, nullptr);\n    CheckWin32(m_event);\n\n    m_cmdAllocPool.reserve(32);\n    m_initialized = true;\n}\n\nuint64_t CommandQueue::ExecuteCommandList(CommandList* context)\n{\n    CheckHR(context->m_cmdList->Close());\n\n    ID3D12GraphicsCommandList* contexts[1] = { context->m_cmdList.Get() };\n    m_cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList**)context->m_cmdList.GetAddressOf());\n\n    ReleaseCommandAllocator(context->m_cmdAllocator, m_nextFenceValue);\n    context->m_cmdAllocator = nullptr;\n    App::GetRenderer().ReleaseCmdList(context);\n    uint64_t ret;\n\n    {\n        std::unique_lock lock(m_fenceMtx);\n        m_cmdQueue->Signal(m_fence.Get(), m_nextFenceValue);\n        m_lastCompletedFenceVal = Math::Max(m_lastCompletedFenceVal, m_fence->GetCompletedValue());\n\n        ret = m_nextFenceValue++;\n    }\n\n    return ret;\n}\n\nID3D12CommandAllocator* CommandQueue::GetCommandAllocator()\n{\n    // Try to reuse\n    {\n        ReleasedCmdAlloc cmdAlloc{};\n        bool found = false;\n\n        {\n            std::unique_lock lock(m_poolMtx);\n\n            // only need to compare against the smallest fence in the pool\n            if (!m_cmdAllocPool.empty() && m_cmdAllocPool[0].FenceToWaitFor <= m_lastCompletedFenceVal)\n            {\n                cmdAlloc = m_cmdAllocPool[0];\n                m_cmdAllocPool.erase_at_index(0);\n\n                std::make_heap(m_cmdAllocPool.begin(), m_cmdAllocPool.end(),\n                    [](const ReleasedCmdAlloc& lhs, const ReleasedCmdAlloc& rhs)\n                    {\n                        return lhs.FenceToWaitFor > rhs.FenceToWaitFor;\n                    });\n\n                found = true;\n            }\n        }\n\n        if (found)\n        {\n            CheckHR(cmdAlloc.CmdAlloc->Reset());\n            return cmdAlloc.CmdAlloc;\n        }\n    }\n\n    // Create a new one\n    auto* device = App::GetRenderer().GetDevice();\n    ID3D12CommandAllocator* cmdAlloc;\n    CheckHR(device->CreateCommandAllocator(m_type, IID_PPV_ARGS(&cmdAlloc)));\n\n    return cmdAlloc;\n}\n\nvoid CommandQueue::ReleaseCommandAllocator(ID3D12CommandAllocator* cmdAllocator, \n    uint64_t fenceValueToWaitFor)\n{\n    std::unique_lock lock(m_poolMtx);\n    m_cmdAllocPool.push_back(ReleasedCmdAlloc{ \n        .CmdAlloc = cmdAllocator, \n        .FenceToWaitFor = fenceValueToWaitFor });\n}\n\nCommandList* CommandQueue::GetCommandList()\n{\n    auto* cmdAlloc = GetCommandAllocator();\n    CommandList* ctx;\n\n    if (m_contextPool.try_dequeue(ctx))\n    {\n        ctx->Reset(cmdAlloc);\n        return ctx;\n    }\n\n    CommandList* context = new(std::nothrow) CommandList(m_type, cmdAlloc);\n\n    return context;\n}\n\nvoid CommandQueue::ReleaseCommandList(CommandList* context)\n{\n    m_contextPool.enqueue(context);\n}\n\nvoid CommandQueue::WaitForFenceCPU(uint64_t fenceValue)\n{\n    if (m_fence->GetCompletedValue() < fenceValue)\n    {\n        // Reminder: SetEventOnCompletion() is thread safe\n        CheckHR(m_fence->SetEventOnCompletion(fenceValue, m_event));\n        WaitForSingleObject(m_event, INFINITE);\n\n        //std::unique_lock lock(m_fenceMtx);\n        //m_lastCompletedFenceVal = Math::Max(m_lastCompletedFenceVal, fenceValue);\n    }\n}\n\nvoid CommandQueue::WaitForIdle()\n{\n    {\n        std::unique_lock lock(m_fenceMtx);\n        CheckHR(m_cmdQueue->Signal(m_fence.Get(), m_nextFenceValue++));\n    }\n\n    WaitForFenceCPU(m_nextFenceValue - 1);\n}\n\nbool CommandQueue::IsFenceComplete(uint64_t fenceValue)\n{\n    if (m_lastCompletedFenceVal < fenceValue)\n        m_lastCompletedFenceVal = Math::Max(m_lastCompletedFenceVal, m_fence->GetCompletedValue());\n\n    return m_lastCompletedFenceVal >= fenceValue;\n}\n"
  },
  {
    "path": "Source/ZetaCore/Core/CommandQueue.h",
    "content": "#pragma once\n\n#include \"../Core/Device.h\"\n#include \"../Utility/SmallVector.h\"\n#include \"../App/App.h\"\n#include <shared_mutex>\n#include <concurrentqueue/concurrentqueue.h>\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n\n    struct CommandQueue\n    {\n        explicit CommandQueue(D3D12_COMMAND_LIST_TYPE type);\n        ~CommandQueue();\n        CommandQueue(const CommandQueue&) = delete;\n        CommandQueue& operator=(const CommandQueue&) = delete;\n\n        void Init();\n        ZetaInline ID3D12CommandQueue* GetCommandQueue() { return m_cmdQueue.Get(); }\n        CommandList* GetCommandList();\n\n        // Returns the command allocator for future reuse (once the specified fence value\n        // has passed on this command queue)\n        void ReleaseCommandAllocator(ID3D12CommandAllocator* cmdAlloc, uint64_t fenceValueToWaitFor);\n\n        // Releases command list back to the pool of available ones (command lists can be safely reused \n        // after submission, unlike command allocator)\n        void ReleaseCommandList(CommandList* context);\n\n        // Waits (CPU side) for the given fence to reach the specified value on this command queue (blocking)\n        void WaitForFenceCPU(uint64_t fenceValue);\n\n        uint64_t ExecuteCommandList(CommandList* context);\n        void WaitForIdle();\n        bool IsFenceComplete(uint64_t fenceValue);\n\n    public:\n        ID3D12CommandAllocator* GetCommandAllocator();\n\n        D3D12_COMMAND_LIST_TYPE m_type;\n        ComPtr<ID3D12CommandQueue> m_cmdQueue;\n        ComPtr<ID3D12Fence> m_fence;\n        uint64_t m_lastCompletedFenceVal = 0;\n        uint64_t m_nextFenceValue = 1;\n        HANDLE m_event;\n        std::shared_mutex m_poolMtx;\n        std::shared_mutex m_fenceMtx;\n        bool m_initialized = false;\n\n        struct ReleasedCmdAlloc\n        {\n            ID3D12CommandAllocator* CmdAlloc;\n            uint64_t FenceToWaitFor;\n        };\n\n        Util::SmallVector<ReleasedCmdAlloc, Support::SystemAllocator, 8> m_cmdAllocPool;\n\n        struct MyTraits : public moodycamel::ConcurrentQueueDefaultTraits\n        {\n            static const size_t BLOCK_SIZE = 512;\n        };\n\n        moodycamel::ConcurrentQueue<CommandList*, MyTraits> m_contextPool;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Core/Config.h",
    "content": "#pragma once\n\n#include \"Device.h\"\n\nnamespace ZetaRay::Core::Constants\n{\n    static constexpr int NUM_BACK_BUFFERS = 3;\n    static constexpr DXGI_FORMAT BACK_BUFFER_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;\n\n    static constexpr int NUM_CBV_SRV_UAV_DESC_HEAP_GPU_DESCRIPTORS = 4096;\n    static constexpr int NUM_CBV_SRV_UAV_DESC_HEAP_CPU_DESCRIPTORS = 128;\n    static constexpr int NUM_RTV_DESC_HEAP_DESCRIPTORS = 32;\n    static constexpr int NUM_DSV_DESC_HEAP_DESCRIPTORS = 8;\n    static constexpr int MAX_SWAPCHAIN_FRAME_LATENCY = 2;\n\n    static constexpr D3D12_RESOURCE_STATES VALID_BUFFER_STATES =\n        D3D12_RESOURCE_STATE_COMMON |\n        D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER |\n        D3D12_RESOURCE_STATE_INDEX_BUFFER |\n        D3D12_RESOURCE_STATE_UNORDERED_ACCESS |\n        D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE |\n        D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE |\n        D3D12_RESOURCE_STATE_COPY_DEST |\n        D3D12_RESOURCE_STATE_COPY_SOURCE |\n        D3D12_RESOURCE_STATE_RESOLVE_DEST |\n        D3D12_RESOURCE_STATE_RESOLVE_SOURCE |\n        D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE |\n        D3D12_RESOURCE_STATE_PREDICATION;\n\n    static constexpr D3D12_RESOURCE_STATES READ_STATES =\n        D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER |\n        D3D12_RESOURCE_STATE_INDEX_BUFFER |\n        D3D12_RESOURCE_STATE_DEPTH_READ |\n        D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT |\n        D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE |\n        D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE |\n        D3D12_RESOURCE_STATE_UNORDERED_ACCESS |\n        D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE |\n        D3D12_RESOURCE_STATE_COPY_DEST |\n        D3D12_RESOURCE_STATE_COPY_SOURCE;\n\n    static constexpr D3D12_RESOURCE_STATES WRITE_STATES =\n        D3D12_RESOURCE_STATE_RENDER_TARGET |\n        D3D12_RESOURCE_STATE_DEPTH_WRITE |\n        D3D12_RESOURCE_STATE_UNORDERED_ACCESS |\n        D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE |\n        D3D12_RESOURCE_STATE_COPY_DEST |\n        D3D12_RESOURCE_STATE_COPY_SOURCE;\n\n    static constexpr D3D12_RESOURCE_STATES VALID_COMPUTE_QUEUE_STATES =\n        D3D12_RESOURCE_STATE_UNORDERED_ACCESS |\n        D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE |\n        D3D12_RESOURCE_STATE_COPY_DEST |\n        D3D12_RESOURCE_STATE_COPY_SOURCE |\n        D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE;\n\n    static constexpr D3D12_RESOURCE_STATES INVALID_COMPUTE_STATES =\n        ~VALID_COMPUTE_QUEUE_STATES;\n}"
  },
  {
    "path": "Source/ZetaCore/Core/DescriptorHeap.cpp",
    "content": "#include \"DescriptorHeap.h\"\n#include \"RendererCore.h\"\n#include \"../Utility/Error.h\"\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\n\n//--------------------------------------------------------------------------------------\n// DescriptorTable\n//--------------------------------------------------------------------------------------\n\nDescriptorTable::DescriptorTable(D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,\n    D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle,\n    uint32_t numDesc, \n    uint32_t descSize,\n    DescriptorHeap* heap,\n    uint32_t internalVal)\n    : m_descHeap(heap),\n    m_baseCpuHandle(cpuHandle),\n    m_baseGpuHandle(gpuHandle),\n    m_numDescriptors(numDesc),\n    m_descriptorSize(descSize),\n    m_internal(internalVal)\n{}\n\nDescriptorTable::~DescriptorTable()\n{\n    Reset();\n}\n\nDescriptorTable::DescriptorTable(DescriptorTable&& other)\n    : m_descHeap(other.m_descHeap),\n    m_baseCpuHandle(other.m_baseCpuHandle),\n    m_baseGpuHandle(other.m_baseGpuHandle),\n    m_numDescriptors(other.m_numDescriptors),\n    m_descriptorSize(other.m_descriptorSize),\n    m_internal(other.m_internal)\n{\n    other.m_descHeap = nullptr;\n    other.m_baseCpuHandle.ptr = 0;\n    other.m_baseGpuHandle.ptr = 0;\n    other.m_numDescriptors = 0;\n    other.m_descriptorSize = 0;\n    other.m_internal = UINT32_MAX;\n}\n\nDescriptorTable& DescriptorTable::operator=(DescriptorTable&& other)\n{\n    if (this == &other)\n        return *this;\n\n    std::swap(m_descHeap, other.m_descHeap);\n    std::swap(m_baseCpuHandle, other.m_baseCpuHandle);\n    std::swap(m_baseGpuHandle, other.m_baseGpuHandle);\n    std::swap(m_numDescriptors, other.m_numDescriptors);\n    std::swap(m_descriptorSize, other.m_descriptorSize);\n    std::swap(m_internal, other.m_internal);\n\n    return *this;\n}\n\n// TODO needs more testing\nvoid DescriptorTable::Reset()\n{\n    if (m_baseCpuHandle.ptr)\n        m_descHeap->Release(ZetaMove(*this));\n\n    m_descHeap = nullptr;\n    m_baseCpuHandle.ptr = 0;\n    m_baseGpuHandle.ptr = 0;\n    m_numDescriptors = 0;\n    m_descriptorSize = 0;\n    m_internal = UINT32_MAX;\n}\n\n//--------------------------------------------------------------------------------------\n// DescriptorHeap\n//--------------------------------------------------------------------------------------\n\nDescriptorHeap::DescriptorHeap(uint32_t blockSize)\n#ifndef NDEBUG\n    : m_blockSize(blockSize),\n    m_numLists((uint32_t)log2f((float)blockSize) + 1)\n#else\n    : m_blockSize(blockSize)\n#endif\n{\n    Assert(Math::IsPow2(blockSize), \"Block size must be a power of two.\");\n\n    // Initialize blocks\n    for (uint32_t i = 0; i < MAX_NUM_LISTS; i++)\n        m_heads[i].Head = UINT32_MAX;\n}\n\nvoid DescriptorHeap::Init(D3D12_DESCRIPTOR_HEAP_TYPE heapType, uint32_t numDescriptors, \n    bool isShaderVisible)\n{\n    Assert(!isShaderVisible || heapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,\n        \"Shader-visible heap type must be D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV.\");\n    Assert(!isShaderVisible || numDescriptors <= 1'000'000,\n        \"GPU resource heap can't contain more than 1'000'000 elements\");\n    Assert(numDescriptors >= m_blockSize, \"#descriptors=%u is invalid for block size of %u.\", \n        numDescriptors, m_blockSize);\n\n    m_totalHeapSize = numDescriptors;\n    m_isShaderVisible = isShaderVisible;\n\n    D3D12_DESCRIPTOR_HEAP_DESC desc;\n    desc.Type = heapType;\n    desc.NumDescriptors = numDescriptors;\n    desc.Flags = isShaderVisible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : \n        D3D12_DESCRIPTOR_HEAP_FLAG_NONE;\n    desc.NodeMask = 0;\n\n    auto* device = App::GetRenderer().GetDevice();\n    CheckHR(device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(m_heap.GetAddressOf())));\n\n    m_descriptorSize = device->GetDescriptorHandleIncrementSize(heapType);\n    m_baseCPUHandle = m_heap->GetCPUDescriptorHandleForHeapStart();\n    m_freeDescCount = numDescriptors;\n\n    if (isShaderVisible)\n        m_baseGPUHandle = m_heap->GetGPUDescriptorHandleForHeapStart();\n\n    CheckHR(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(m_fence.GetAddressOf())));\n}\n\nbool DescriptorHeap::AllocateNewBlock(uint32_t listIdx)\n{\n    Assert(m_heads[listIdx].Entries.empty(), \"This linked list must be empty.\");\n\n    uint32_t nextHeapIdx = m_nextHeapIdx;\n    uint32_t blockSize = m_blockSize;\n\n    if (m_nextHeapIdx >= m_totalHeapSize)\n    {\n        if(m_releasedBlocks.empty())\n            return false;\n\n        auto b = m_releasedBlocks.back();\n        m_releasedBlocks.pop_back();\n\n        nextHeapIdx = b.Offset;\n        blockSize = b.Count;\n    }\n\n    const int descTableSize = DescTableSizeFromListIndex(listIdx);\n    const int numDescTablesInBlock = blockSize / descTableSize;\n    m_heads[listIdx].Entries.resize(numDescTablesInBlock);\n    int currEntry = 0;\n\n    for (int i = 0; i < (int)blockSize; i += descTableSize)\n    {\n        Entry e{ .HeapOffset = nextHeapIdx + i,\n            .Next = (currEntry != numDescTablesInBlock - 1) ? \n            (uint32_t)(currEntry + 1) : UINT32_MAX };\n\n        m_heads[listIdx].Entries[currEntry++] = e;\n    }\n\n    // Once this index reaches the end, it should stay there\n    m_nextHeapIdx = Math::Min(m_nextHeapIdx + m_blockSize, m_totalHeapSize);\n    m_heads[listIdx].Head = 0;\n\n    return true;\n}\n\nDescriptorTable DescriptorHeap::Allocate(uint32_t count)\n{\n    Assert(count && count <= m_totalHeapSize, \"Invalid allocation count.\");\n    uint32_t heapOffset;\n    uint32_t arrayOffset;\n\n    AcquireSRWLockExclusive(&m_lock);\n\n    if (count > m_blockSize)\n    {\n        Assert(m_nextHeapIdx + count < m_totalHeapSize, \"Out of free space in descriptor heap.\");\n\n        heapOffset = m_nextHeapIdx;\n        arrayOffset = UINT32_MAX;\n        m_nextHeapIdx += count;\n\n        m_freeDescCount -= count;\n    }\n    else\n    {\n        uint32_t listIdx = ListIndexFromDescTableSize(count);\n        Assert(listIdx < m_numLists, \"Unvalid list index.\");\n\n        bool success = true;\n\n        // build a new linked list\n        if (m_heads[listIdx].Head == UINT32_MAX)\n        {\n            m_heads[listIdx].Entries.clear();\n            success = AllocateNewBlock(listIdx);\n        }\n\n        // Try to allocate from existing linked lists with a larger block size\n        // TODO alternatively, chunks from smaller block sizes can be coalesced together\n        if (!success)\n        {\n            // TODO instead of returning a larger block directly, break it into chunks (with size\n            // of each equal to the best fit for this request), insert those chunks into the current\n            // (empty) list and then return the head\n            while (m_heads[listIdx].Head == UINT32_MAX)\n            {\n                listIdx++;\n                Assert(listIdx < m_numLists, \"Out of free space in the descriptor heap.\");\n            }\n        }\n\n        // Pop from the linked list\n        const uint32_t currHeadIdx = m_heads[listIdx].Head;\n        Entry e = m_heads[listIdx].Entries[currHeadIdx];\n\n        // Set the new head\n        const uint32_t nextHeadIdx = e.Next;\n        m_heads[listIdx].Entries[currHeadIdx].Next = UINT32_MAX;\n        m_heads[listIdx].Head = nextHeadIdx;\n\n        heapOffset = e.HeapOffset;\n        arrayOffset = currHeadIdx;\n\n        m_freeDescCount -= DescTableSizeFromListIndex(listIdx);\n    }\n\n    ReleaseSRWLockExclusive(&m_lock);\n\n    D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle{ .ptr = \n        m_baseCPUHandle.ptr + heapOffset * m_descriptorSize };\n\n    D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = m_isShaderVisible ?\n        D3D12_GPU_DESCRIPTOR_HANDLE{ .ptr = m_baseGPUHandle.ptr + heapOffset * m_descriptorSize } :\n        D3D12_GPU_DESCRIPTOR_HANDLE{ .ptr = 0 };\n\n    return DescriptorTable(cpuHandle,\n        gpuHandle,\n        count,\n        m_descriptorSize,\n        this,\n        arrayOffset);\n}\n\nvoid DescriptorHeap::Release(DescriptorTable&& table)\n{\n    const uint32_t offset = \n        (uint32_t)((table.m_baseCpuHandle.ptr - m_baseCPUHandle.ptr) / m_descriptorSize);\n\n    AcquireSRWLockExclusive(&m_lock);\n    m_pending.emplace_back(m_nextFenceVal, offset, table.m_numDescriptors, table.m_internal);\n    ReleaseSRWLockExclusive(&m_lock);\n}\n\nvoid DescriptorHeap::Recycle()\n{\n    if (m_pending.empty())\n        return;\n\n    // TODO Is it necessary to signal the compute queue?\n    if(m_isShaderVisible)\n        App::GetRenderer().SignalDirectQueue(m_fence.Get(), m_nextFenceVal++);\n\n    const uint64_t completedFenceVal = m_fence->GetCompletedValue();\n\n    for (PendingDescTable* currPending = m_pending.begin(); currPending != m_pending.end(); )\n    {\n        auto [releaseFence, offset, numDescs, internalVal] = *currPending;\n\n        Assert(offset < m_totalHeapSize, \"invalid offset\");\n        Assert(numDescs < m_totalHeapSize, \"invalid #descs\");\n\n        // Not safe to release just yet\n        if (m_isShaderVisible && completedFenceVal < releaseFence)\n        {\n            currPending++;\n            continue;\n        }\n\n        if (numDescs <= m_blockSize)\n        {\n            const int listIdx = ListIndexFromDescTableSize(numDescs);\n            const uint32_t currHead = m_heads[listIdx].Head;\n\n            Entry e{ .HeapOffset = offset, .Next = currHead };\n\n            // When a single Entry ping pongs between allocation and release and there hasn't been\n            // any other allocations/releases in the meantime, the corresponding Entries array continues \n            // to grow indefinitely. To avoid that, attempt to reuse the previous array position instead\n            // of appending to the end. Note that when a new block is added, SmallVector is cleared first \n            // and unbounded growth is avoided.\n            if (internalVal != UINT32_MAX && internalVal < m_heads[listIdx].Entries.size() &&\n                m_heads[listIdx].Entries[internalVal].HeapOffset == offset)\n            {\n                Assert(m_heads[listIdx].Entries[internalVal].Next == UINT32_MAX, \n                    \"These must match.\");\n\n                m_heads[listIdx].Entries[internalVal] = e;\n                m_heads[listIdx].Head = internalVal;\n            }\n            else\n            {\n                m_heads[listIdx].Head = (uint32_t)m_heads[listIdx].Entries.size();\n                m_heads[listIdx].Entries.push_back(e);\n            }\n\n            m_freeDescCount += DescTableSizeFromListIndex(listIdx);\n        }\n        else\n        {\n            ReleasedLargeBlock b{ .Offset = offset, .Count = numDescs };\n            m_releasedBlocks.push_back(b);\n        }\n\n        currPending = m_pending.erase(*currPending);\n    }\n}\n"
  },
  {
    "path": "Source/ZetaCore/Core/DescriptorHeap.h",
    "content": "#pragma once\n\n#include \"../Utility/SmallVector.h\"\n#include \"Device.h\"\n\nnamespace ZetaRay::Core\n{\n    struct DescriptorTable;\n\n    struct DescriptorHeap\n    {\n        explicit DescriptorHeap(uint32_t BlockSize = MAX_BLOCK_SIZE);\n        ~DescriptorHeap() = default;\n\n        DescriptorHeap(const DescriptorHeap&) = delete;\n        DescriptorHeap& operator=(const DescriptorHeap&) = delete;\n\n        void Init(D3D12_DESCRIPTOR_HEAP_TYPE heapType, uint32_t numDescriptors, bool isShaderVisible);\n        DescriptorTable Allocate(uint32_t count);\n        void Release(DescriptorTable&& descTable);\n        void Recycle();\n\n        ZetaInline bool IsShaderVisible() const { return m_isShaderVisible; }\n        ZetaInline uint32_t GetDescriptorSize() const { return m_descriptorSize; }\n        ZetaInline uint32_t GetNumFreeDescriptors() const { return m_freeDescCount; }\n        ZetaInline uint64_t GetBaseGpuHandle() const { return m_baseGPUHandle.ptr; }\n        ZetaInline ID3D12DescriptorHeap* GetHeap() { return m_heap.Get(); }\n        ZetaInline uint32_t GetHeapSize() { return m_totalHeapSize; }\n\n    private:\n        static const uint32_t MAX_BLOCK_SIZE = 1024;\n        static const uint32_t MAX_NUM_LISTS = 11;\n        static_assert(1 << (MAX_NUM_LISTS - 1) == MAX_BLOCK_SIZE, \"These must match.\");\n\n        struct PendingDescTable\n        {\n            PendingDescTable() = default;\n            PendingDescTable(uint64_t fence, uint32_t offset, uint32_t count, uint32_t internalVal)\n                : ReleaseFence(fence),\n                Offset(offset),\n                Count(count),\n                Internal(internalVal)\n            {}\n\n            uint64_t ReleaseFence;\n            uint32_t Offset;\n            uint32_t Count;\n            uint32_t Internal;\n        };\n\n        struct Entry\n        {\n            uint32_t HeapOffset;\n            uint32_t Next;\n        };\n\n        struct Block\n        {\n            Block() = default;\n            Block(Block&&) = delete;\n            Block& operator=(Block&&) = delete;\n\n            uint32_t Head;\n            Util::SmallVector<Entry> Entries;\n        };\n\n        struct ReleasedLargeBlock\n        {\n            uint32_t Offset;\n            uint32_t Count;\n        };\n\n        ZetaInline uint32_t DescTableSizeFromListIndex(uint32_t x) const\n        {\n            return 1 << x;\n        }\n\n        ZetaInline uint32_t ListIndexFromDescTableSize(uint32_t x)\n        {\n            size_t s = Math::NextPow2(x);\n            unsigned long idx;\n            _BitScanForward64(&idx, s);\n\n            return idx;\n        }\n\n        bool AllocateNewBlock(uint32_t listIdx);\n\n        SRWLOCK m_lock = SRWLOCK_INIT;\n\n        ComPtr<ID3D12DescriptorHeap> m_heap;\n        D3D12_CPU_DESCRIPTOR_HANDLE m_baseCPUHandle;\n        D3D12_GPU_DESCRIPTOR_HANDLE m_baseGPUHandle;\n        bool m_isShaderVisible;\n        ComPtr<ID3D12Fence> m_fence;\n        uint64_t m_nextFenceVal = 1;\n        uint32_t m_descriptorSize = 0;\n        uint32_t m_totalHeapSize = 0;\n        uint32_t m_freeDescCount = 0;\n\n        Util::SmallVector<PendingDescTable> m_pending;\n\n        // Segregated free lists\n        const uint32_t m_blockSize;\n        Block m_heads[MAX_NUM_LISTS];\n#ifndef NDEBUG\n        const uint32_t m_numLists;\n#endif\n\n        uint32_t m_nextHeapIdx = 0;\n        Util::SmallVector<ReleasedLargeBlock> m_releasedBlocks;\n    };\n\n    // A contiguous range of descriptors that are allocated from one DescriptorHeap\n    struct DescriptorTable\n    {\n        friend struct DescriptorHeap;\n\n        DescriptorTable() = default;\n        DescriptorTable(D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,\n            D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle,\n            uint32_t numDesc,\n            uint32_t descSize,\n            DescriptorHeap* heap,\n            uint32_t internal);\n        ~DescriptorTable();\n\n        DescriptorTable(DescriptorTable&& other);\n        DescriptorTable& operator=(DescriptorTable&& other);\n\n        void Reset();\n        ZetaInline bool IsEmpty() const { return m_numDescriptors == 0; }\n\n        ZetaInline D3D12_CPU_DESCRIPTOR_HANDLE CPUHandle(uint32_t offset) const\n        {\n            Assert(offset < m_numDescriptors, \"Descriptor offset is out of bounds.\");\n            return D3D12_CPU_DESCRIPTOR_HANDLE{ .ptr = m_baseCpuHandle.ptr + offset * m_descriptorSize };\n        }\n\n        ZetaInline D3D12_GPU_DESCRIPTOR_HANDLE GPUHandle(uint32_t offset) const\n        {\n            Assert(offset < m_numDescriptors, \"Descriptor offset is out of bounds.\");\n            Assert(m_descHeap->IsShaderVisible(), \"This descriptor doesn't belong to a shader-visible heap.\");\n            return D3D12_GPU_DESCRIPTOR_HANDLE{ .ptr = m_baseGpuHandle.ptr + offset * m_descriptorSize };\n        }\n\n        ZetaInline uint32_t GetNumDescriptors() const { return m_numDescriptors; };\n\n        // Offset to the beginning of this desc. table in the GPU descriptor heap\n        ZetaInline uint32_t GPUDescriptorHeapIndex(uint32_t offset = 0) const\n        {\n            Assert(m_descHeap->IsShaderVisible(), \"Descriptor table is not shader-visible.\");\n            Assert(offset < m_numDescriptors, \"Descriptor offset is out of bounds.\");\n            uint32_t idx = (uint32_t)((m_baseGpuHandle.ptr - m_descHeap->GetBaseGpuHandle()) / m_descriptorSize);\n\n            return idx + offset;\n        }\n\n    private:\n        DescriptorHeap* m_descHeap = nullptr;    // DescriptorHeap from which this table was allocated\n\n        D3D12_CPU_DESCRIPTOR_HANDLE m_baseCpuHandle = { 0 };\n        D3D12_GPU_DESCRIPTOR_HANDLE m_baseGpuHandle = { 0 };\n\n        uint32_t m_numDescriptors = 0;\n        uint32_t m_descriptorSize = 0;\n        uint32_t m_internal = UINT32_MAX;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Core/Device.cpp",
    "content": "#include \"Device.h\"\n#include \"Config.h\"\n#include \"../App/Common.h\"\n\n// PIX crashes & NSight doesn't work when the debug layer is enabled\n//#define DIREC3D_DEBUG_LAYER\n\n// To ensure stable GPU frequency for performance testing. Requires developer mode to be enabled.\n//#define STABLE_GPU_POWER_STATE\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::App;\n\nvoid DeviceObjects::InitializeAdapter()\n{\n#if !defined(NDEBUG) && defined(DIREC3D_DEBUG_LAYER)\n    {\n        ComPtr<ID3D12Debug> debugController;\n        CheckHR(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)));\n        debugController->EnableDebugLayer();\n\n        ComPtr<IDXGIInfoQueue> dxgiInfoQueue;\n        if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiInfoQueue))))\n        {\n            IDXGIFactory2* dxgiFactory2;\n            CheckHR(CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, IID_PPV_ARGS(&dxgiFactory2)));\n            CheckHR(dxgiFactory2->QueryInterface(IID_PPV_ARGS(m_dxgiFactory.GetAddressOf())));\n            dxgiFactory2->Release();\n        }\n\n        //ComPtr<ID3D12DeviceRemovedExtendedDataSettings1> pDredSettings;\n        //CheckHR(D3D12GetDebugInterface(IID_PPV_ARGS(&pDredSettings)));\n\n        // Turn on AutoBreadcrumbs and Page Fault reporting\n        //pDredSettings->SetAutoBreadcrumbsEnablement(D3D12_DRED_ENABLEMENT_FORCED_ON);\n        //pDredSettings->SetPageFaultEnablement(D3D12_DRED_ENABLEMENT_FORCED_ON);\n    }\n#else\n    CheckHR(CreateDXGIFactory1(IID_PPV_ARGS(&m_dxgiFactory)));\n#endif\n\n    IDXGIAdapter* dxgiAdapter;\n    CheckHR(m_dxgiFactory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, \n        IID_PPV_ARGS(&dxgiAdapter)));\n    CheckHR(dxgiAdapter->QueryInterface(IID_PPV_ARGS(m_dxgiAdapter.GetAddressOf())));\n    dxgiAdapter->Release();\n\n    DXGI_ADAPTER_DESC2 desc;\n    CheckHR(m_dxgiAdapter->GetDesc2(&desc));\n\n    Common::WideToCharStr(desc.Description, m_deviceName);\n}\n\nvoid DeviceObjects::CreateDevice(bool checkFeatureSupport)\n{\n    ID3D12Device* device;\n\n    CheckHR(D3D12CreateDevice(m_dxgiAdapter.Get(), D3D_FEATURE_LEVEL_12_2, \n        IID_PPV_ARGS(&device)));\n    CheckHR(device->QueryInterface(IID_PPV_ARGS(m_device.GetAddressOf())));\n    device->Release();\n\n#if !defined(NDEBUG) && defined(DIREC3D_DEBUG_LAYER)\n    ID3D12InfoQueue* infoQueue;\n    CheckHR(m_device->QueryInterface(&infoQueue));\n\n    infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);\n    infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);\n    //infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, true);\n\n    D3D12_MESSAGE_ID filteredMsgs[] = \n    { \n        D3D12_MESSAGE_ID_LOADPIPELINE_NAMENOTFOUND,\n        //D3D12_MESSAGE_ID_LOADPIPELINE_INVALIDDESC,\n        D3D12_MESSAGE_ID_CREATEPIPELINELIBRARY_DRIVERVERSIONMISMATCH,\n        //D3D12_MESSAGE_ID_CREATEPIPELINELIBRARY_INVALIDLIBRARYBLOB,\n        //D3D12_MESSAGE_ID_RESOLVE_QUERY_INVALID_QUERY_STATE,\n        //D3D12_MESSAGE_ID_EXECUTECOMMANDLISTS_GPU_WRITTEN_READBACK_RESOURCE_MAPPED\n    };\n\n    D3D12_INFO_QUEUE_FILTER filter{};\n    filter.DenyList.NumIDs = sizeof(filteredMsgs);\n    filter.DenyList.pIDList = filteredMsgs;\n    infoQueue->AddStorageFilterEntries(&filter);\n\n    infoQueue->Release();\n\n#endif\n\n    if (!checkFeatureSupport)\n        return;\n\n#ifdef STABLE_GPU_POWER_STATE\n    CheckHR(device->SetStablePowerState(true));\n#endif\n\n    // Hardware-accelerated RT\n    D3D12_FEATURE_DATA_D3D12_OPTIONS5 feature;\n    CheckHR(m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, \n        &feature, sizeof(feature)));\n    Check(feature.RaytracingTier >= D3D12_RAYTRACING_TIER_1_1,\n        \"Raytracing Tier 1.1 is not supported.\");\n\n    // Shader model 6.6\n    D3D12_FEATURE_DATA_SHADER_MODEL sm;\n    sm.HighestShaderModel = D3D_SHADER_MODEL::D3D_SHADER_MODEL_6_6;\n    CheckHR(m_device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &sm, \n        sizeof(sm)));\n    Check(sm.HighestShaderModel == D3D_SHADER_MODEL::D3D_SHADER_MODEL_6_6, \n        \"Shader Model 6.6 is not supported.\");\n\n    // Tearing\n    CheckHR(m_dxgiFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, \n        &m_tearingSupport, sizeof(DXGI_FEATURE)));\n    if (m_tearingSupport)\n        m_swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;\n\n    // fp16\n    D3D12_FEATURE_DATA_D3D12_OPTIONS4 options4;\n    CheckHR(m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4, \n        &options4, sizeof(options4)));\n    Check(options4.Native16BitShaderOpsSupported, \"Native fp16 is not supported.\");\n\n    // Wave intrinsics\n    D3D12_FEATURE_DATA_D3D12_OPTIONS1 options1;\n    CheckHR(m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS1, \n        &options1, sizeof(options1)));\n    Check(options1.WaveOps, \"Wave intrinsics are not supported.\");\n    Check(options1.WaveLaneCountMin >= 32, \"Wave lane count of at least 32 is required.\");\n\n    // Enhanced barriers\n    D3D12_FEATURE_DATA_D3D12_OPTIONS12 options12{};\n    CheckHR(m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS12, \n        &options12, sizeof(options12)));\n    Check(options12.EnhancedBarriersSupported, \"Enhanced barriers are not supported.\");\n\n    // RGBE support\n    D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupport{};\n    formatSupport.Format = DXGI_FORMAT_R9G9B9E5_SHAREDEXP;\n    CheckHR(m_device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, \n        &formatSupport, sizeof(formatSupport)));\n\n    if (formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW\n        & D3D12_FORMAT_SUPPORT1_SHADER_LOAD)\n        m_rgbeSupport = true;\n}\n\nvoid DeviceObjects::CreateSwapChain(ID3D12CommandQueue* directQueue, HWND hwnd, int w, \n    int h, int numBuffers, DXGI_FORMAT format, int maxLatency)\n{\n    DXGI_SWAP_CHAIN_DESC1 desc{};\n    desc.Width = w;\n    desc.Height = h;\n    desc.Format = format;\n    desc.Stereo = false;\n    desc.SampleDesc.Count = 1;\n    desc.SampleDesc.Quality = 0;\n    desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;\n    desc.BufferCount = numBuffers;\n    desc.Scaling = DXGI_SCALING_NONE;\n    desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;\n    desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;\n    desc.Flags = m_swapChainFlags;\n\n    IDXGISwapChain1* swapChain;\n    CheckHR(m_dxgiFactory->CreateSwapChainForHwnd(directQueue, hwnd, &desc, \n        nullptr, nullptr, &swapChain));\n    CheckHR(swapChain->QueryInterface(IID_PPV_ARGS(m_dxgiSwapChain.GetAddressOf())));\n    swapChain->Release();\n\n    CheckHR(m_dxgiSwapChain->SetMaximumFrameLatency(maxLatency));\n    m_frameLatencyWaitableObj = m_dxgiSwapChain->GetFrameLatencyWaitableObject();\n}\n\nvoid DeviceObjects::ResizeSwapChain(int w, int h, int maxLatency)\n{\n    CheckHR(m_dxgiSwapChain->ResizeBuffers(0, w, h, DXGI_FORMAT_UNKNOWN, m_swapChainFlags));\n    //CheckHR(m_dxgiSwapChain->SetMaximumFrameLatency(maxLatency));\n}\n"
  },
  {
    "path": "Source/ZetaCore/Core/Device.h",
    "content": "#pragma once\n\n#include \"../App/ZetaRay.h\"\n#include \"../Win32/Win32.h\"\n#include <D3D12/1.615.0/d3d12.h>\n#include <D3D12/1.615.0/dxgiformat.h>\n#include <dxgi1_6.h>\n\n#ifndef NDEBUG \n#include <dxgidebug.h>\n#endif\n\n#include <wrl/client.h>\n\nusing Microsoft::WRL::ComPtr;\n\n#ifndef NDEBUG  \n#ifndef CheckHR\n#define CheckHR(x)                                                                          \\\n    {                                                                                       \\\n        HRESULT hr_ = (x);                                                                  \\\n        if (FAILED(hr_))                                                                    \\\n        {                                                                                   \\\n            char buff_[64];                                                                 \\\n            stbsp_snprintf(buff_, 256, \"HRESULT: %x\\n%s: %d\", hr_, __FILE__,  __LINE__);    \\\n            MessageBoxA(nullptr, buff_, \"Fatal Error\", MB_ICONERROR | MB_OK);               \\\n            __debugbreak();                                                                 \\\n        }                                                                                   \\\n    }\n#endif\n#else\n#ifndef CheckHR\n#define CheckHR(x)                                                                          \\\n    {                                                                                       \\\n        HRESULT hr_ = (x);                                                                  \\\n        if (FAILED(hr_))                                                                    \\\n        {                                                                                   \\\n            char buff_[64];                                                                 \\\n            stbsp_snprintf(buff_, 256, \"HRESULT: %x\\n%s: %d\", hr_, __FILE__,  __LINE__);    \\\n            MessageBoxA(nullptr, buff_, \"Fatal Error\", MB_ICONERROR | MB_OK);               \\\n            exit(EXIT_FAILURE);                                                             \\\n        }                                                                                   \\\n    }\n#endif\n#endif\n\n#ifndef NDEBUG  \n#ifndef SET_D3D_OBJ_NAME\n#define SET_D3D_OBJ_NAME(pObj, str)                                                                 \\\n    {                                                                                               \\\n        HRESULT hr = pObj->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)strlen(str), str);       \\\n        if(FAILED(hr))                                                                              \\\n        {                                                                                           \\\n            char msg[128];                                                                          \\\n            FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,                                              \\\n                nullptr,                                                                            \\\n                hr,                                                                                 \\\n                MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),                                          \\\n                msg,                                                                                \\\n                sizeof(msg),                                                                        \\\n                nullptr);                                                                           \\\n                                                                                                    \\\n            char buff[256];                                                                         \\\n            stbsp_snprintf(buff, 256, \"HRESULT: %s \\n%s: %d\", msg, __FILE__,  __LINE__);            \\\n            MessageBoxA(nullptr, buff, \"Fatal Error\", MB_ICONERROR | MB_OK);                        \\\n            __debugbreak();                                                                         \\\n        }                                                                                           \\\n    }\n#endif\n#else\n#ifndef SET_D3D_OBJ_NAME\n#define SET_D3D_OBJ_NAME(pObj, str)\n#endif\n#endif\n\nnamespace ZetaRay::Core\n{\n    class DeviceObjects\n    {\n    public:\n        void InitializeAdapter();\n        void CreateDevice(bool checkFeatureSupport);\n        void CreateSwapChain(ID3D12CommandQueue* directQueue, HWND hwnd, int w, int h, int numBuffers,\n            DXGI_FORMAT format, int maxLatency);\n        void ResizeSwapChain(int w, int h, int maxLatency);\n\n        ComPtr<IDXGIFactory6> m_dxgiFactory;\n        ComPtr<IDXGIAdapter3> m_dxgiAdapter;\n        ComPtr<ID3D12Device10> m_device;\n        ComPtr<IDXGISwapChain3> m_dxgiSwapChain;\n\n        bool m_tearingSupport = false;\n        bool m_rgbeSupport = false;\n        //UINT m_swapChainFlags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;\n        UINT m_swapChainFlags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;\n        HANDLE m_frameLatencyWaitableObj;\n\n        char m_deviceName[64] = { '\\0' };\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Core/Direct3DUtil.cpp",
    "content": "#include \"Direct3DUtil.h\"\n#include \"dds.h\"\n#include \"RendererCore.h\"\n#include \"../Support/MemoryArena.h\"\n#include <xxHash/xxhash.h>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Core::Direct3DUtil;\nusing namespace ZetaRay::Support;\n\n#define ISBITMASK( r,g,b,a ) ( ddpf.RBitMask == r && ddpf.GBitMask == g && ddpf.BBitMask == b && ddpf.ABitMask == a )\n\nnamespace\n{\n    ZetaInline void AdjustPlaneResource(DXGI_FORMAT fmt,\n        size_t height,\n        size_t slicePlane,\n        D3D12_SUBRESOURCE_DATA& res)\n    {\n        switch (fmt)\n        {\n        case DXGI_FORMAT_NV12:\n        case DXGI_FORMAT_P010:\n        case DXGI_FORMAT_P016:\n            if (!slicePlane)\n            {\n                // Plane 0\n                res.SlicePitch = res.RowPitch * height;\n            }\n            else\n            {\n                // Plane 1\n                res.pData = static_cast<const uint8_t*>(res.pData) + res.RowPitch * height;\n                res.SlicePitch = res.RowPitch * ((height + 1) >> 1);\n            }\n            break;\n\n        case DXGI_FORMAT_NV11:\n            if (!slicePlane)\n            {\n                // Plane 0\n                res.SlicePitch = res.RowPitch * height;\n            }\n            else\n            {\n                // Plane 1\n                res.pData = static_cast<const uint8_t*>(res.pData) + res.RowPitch * height;\n                res.RowPitch = (res.RowPitch >> 1);\n                res.SlicePitch = res.RowPitch * height;\n            }\n            break;\n\n        default:\n            break;\n        }\n    }\n\n    ZetaInline bool IsDepthStencil(DXGI_FORMAT fmt)\n    {\n        switch (fmt)\n        {\n        case DXGI_FORMAT_R32G8X24_TYPELESS:\n        case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:\n        case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:\n        case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:\n        case DXGI_FORMAT_D32_FLOAT:\n        case DXGI_FORMAT_R24G8_TYPELESS:\n        case DXGI_FORMAT_D24_UNORM_S8_UINT:\n        case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:\n        case DXGI_FORMAT_X24_TYPELESS_G8_UINT:\n        case DXGI_FORMAT_D16_UNORM:\n            return true;\n\n        default:\n            return false;\n        }\n    }\n\n    ZetaInline UINT8 D3D12GetFormatPlaneCount(ID3D12Device* pDevice, DXGI_FORMAT Format)\n    {\n        D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = { Format, 0 };\n        if (FAILED(pDevice->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, sizeof(formatInfo))))\n            return 0;\n\n        return formatInfo.PlaneCount;\n    }\n\n    ZetaInline DXGI_FORMAT GetDXGIFormat(const DDS_PIXELFORMAT& ddpf)\n    {\n        if (ddpf.flags & DDS_RGB)\n        {\n            // Note that sRGB formats are written using the \"DX10\" extended header\n\n            switch (ddpf.RGBBitCount)\n            {\n            case 32:\n                if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000))\n                    return DXGI_FORMAT_R8G8B8A8_UNORM;\n\n                if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000))\n                    return DXGI_FORMAT_B8G8R8A8_UNORM;\n\n                if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000))\n                    return DXGI_FORMAT_B8G8R8X8_UNORM;\n\n                // No DXGI format maps to ISBITMASK(0x000000ff,0x0000ff00,0x00ff0000,0x00000000) aka D3DFMT_X8B8G8R8\n\n                // Note that many common DDS reader/writers (including D3DX) swap the\n                // the RED/BLUE masks for 10:10:10:2 formats. We assume\n                // below that the 'backwards' header mask is being used since it is most\n                // likely written by D3DX. The more robust solution is to use the 'DX10'\n                // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly\n\n                // For 'correct' writers, this should be 0x000003ff,0x000ffc00,0x3ff00000 for RGB data\n                if (ISBITMASK(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000))\n                    return DXGI_FORMAT_R10G10B10A2_UNORM;\n\n                // No DXGI format maps to ISBITMASK(0x000003ff,0x000ffc00,0x3ff00000,0xc0000000) aka D3DFMT_A2R10G10B10\n\n                if (ISBITMASK(0x0000ffff, 0xffff0000, 0x00000000, 0x00000000))\n                    return DXGI_FORMAT_R16G16_UNORM;\n\n                if (ISBITMASK(0xffffffff, 0x00000000, 0x00000000, 0x00000000))\n                {\n                    // Only 32-bit color channel format in D3D9 was R32F\n                    return DXGI_FORMAT_R32_FLOAT; // D3DX writes this out as a FourCC of 114\n                }\n                break;\n\n            case 24:\n                // No 24bpp DXGI formats aka D3DFMT_R8G8B8\n                break;\n\n            case 16:\n                if (ISBITMASK(0x7c00, 0x03e0, 0x001f, 0x8000))\n                    return DXGI_FORMAT_B5G5R5A1_UNORM;\n                if (ISBITMASK(0xf800, 0x07e0, 0x001f, 0x0000))\n                    return DXGI_FORMAT_B5G6R5_UNORM;\n\n                // No DXGI format maps to ISBITMASK(0x7c00,0x03e0,0x001f,0x0000) aka D3DFMT_X1R5G5B5\n\n                if (ISBITMASK(0x0f00, 0x00f0, 0x000f, 0xf000))\n                    return DXGI_FORMAT_B4G4R4A4_UNORM;\n\n                // No DXGI format maps to ISBITMASK(0x0f00,0x00f0,0x000f,0x0000) aka D3DFMT_X4R4G4B4\n\n                // No 3:3:2, 3:3:2:8, or paletted DXGI formats aka D3DFMT_A8R3G3B2, D3DFMT_R3G3B2, D3DFMT_P8, D3DFMT_A8P8, etc.\n                break;\n            }\n        }\n        else if (ddpf.flags & DDS_LUMINANCE)\n        {\n            if (8 == ddpf.RGBBitCount)\n            {\n                if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x00000000))\n                    return DXGI_FORMAT_R8_UNORM; // D3DX10/11 writes this out as DX10 extension\n\n                // No DXGI format maps to ISBITMASK(0x0f,0x00,0x00,0xf0) aka D3DFMT_A4L4\n\n                if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x0000ff00))\n                    return DXGI_FORMAT_R8G8_UNORM; // Some DDS writers assume the bitcount should be 8 instead of 16\n            }\n\n            if (16 == ddpf.RGBBitCount)\n            {\n                if (ISBITMASK(0x0000ffff, 0x00000000, 0x00000000, 0x00000000))\n                    return DXGI_FORMAT_R16_UNORM; // D3DX10/11 writes this out as DX10 extension\n                if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x0000ff00))\n                    return DXGI_FORMAT_R8G8_UNORM; // D3DX10/11 writes this out as DX10 extension\n            }\n        }\n        else if (ddpf.flags & DDS_ALPHA)\n        {\n            if (8 == ddpf.RGBBitCount)\n                return DXGI_FORMAT_A8_UNORM;\n        }\n        else if (ddpf.flags & DDS_BUMPDUDV)\n        {\n            if (16 == ddpf.RGBBitCount)\n            {\n                if (ISBITMASK(0x00ff, 0xff00, 0x0000, 0x0000))\n                    return DXGI_FORMAT_R8G8_SNORM; // D3DX10/11 writes this out as DX10 extension\n            }\n\n            if (32 == ddpf.RGBBitCount)\n            {\n                if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000))\n                    return DXGI_FORMAT_R8G8B8A8_SNORM; // D3DX10/11 writes this out as DX10 extension\n                if (ISBITMASK(0x0000ffff, 0xffff0000, 0x00000000, 0x00000000))\n                    return DXGI_FORMAT_R16G16_SNORM; // D3DX10/11 writes this out as DX10 extension\n\n                // No DXGI format maps to ISBITMASK(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000) aka D3DFMT_A2W10V10U10\n            }\n        }\n        else if (ddpf.flags & DDS_FOURCC)\n        {\n            if (MAKEFOURCC('D', 'X', 'T', '1') == ddpf.fourCC)\n                return DXGI_FORMAT_BC1_UNORM;\n            if (MAKEFOURCC('D', 'X', 'T', '3') == ddpf.fourCC)\n                return DXGI_FORMAT_BC2_UNORM;\n            if (MAKEFOURCC('D', 'X', 'T', '5') == ddpf.fourCC)\n                return DXGI_FORMAT_BC3_UNORM;\n\n            // While pre-multiplied alpha isn't directly supported by the DXGI formats,\n            // they are basically the same as these BC formats so they can be mapped\n            if (MAKEFOURCC('D', 'X', 'T', '2') == ddpf.fourCC)\n                return DXGI_FORMAT_BC2_UNORM;\n            if (MAKEFOURCC('D', 'X', 'T', '4') == ddpf.fourCC)\n                return DXGI_FORMAT_BC3_UNORM;\n\n            if (MAKEFOURCC('A', 'T', 'I', '1') == ddpf.fourCC)\n                return DXGI_FORMAT_BC4_UNORM;\n            if (MAKEFOURCC('B', 'C', '4', 'U') == ddpf.fourCC)\n                return DXGI_FORMAT_BC4_UNORM;\n            if (MAKEFOURCC('B', 'C', '4', 'S') == ddpf.fourCC)\n                return DXGI_FORMAT_BC4_SNORM;\n\n            if (MAKEFOURCC('A', 'T', 'I', '2') == ddpf.fourCC)\n                return DXGI_FORMAT_BC5_UNORM;\n            if (MAKEFOURCC('B', 'C', '5', 'U') == ddpf.fourCC)\n                return DXGI_FORMAT_BC5_UNORM;\n            if (MAKEFOURCC('B', 'C', '5', 'S') == ddpf.fourCC)\n                return DXGI_FORMAT_BC5_SNORM;\n\n            // BC6H and BC7 are written using the \"DX10\" extended header\n\n            if (MAKEFOURCC('R', 'G', 'B', 'G') == ddpf.fourCC)\n                return DXGI_FORMAT_R8G8_B8G8_UNORM;\n            if (MAKEFOURCC('G', 'R', 'G', 'B') == ddpf.fourCC)\n                return DXGI_FORMAT_G8R8_G8B8_UNORM;\n\n            if (MAKEFOURCC('Y', 'U', 'Y', '2') == ddpf.fourCC)\n                return DXGI_FORMAT_YUY2;\n\n            // Check for D3DFORMAT enums being set here\n            switch (ddpf.fourCC)\n            {\n            case 36: // D3DFMT_A16B16G16R16\n                return DXGI_FORMAT_R16G16B16A16_UNORM;\n\n            case 110: // D3DFMT_Q16W16V16U16\n                return DXGI_FORMAT_R16G16B16A16_SNORM;\n\n            case 111: // D3DFMT_R16F\n                return DXGI_FORMAT_R16_FLOAT;\n\n            case 112: // D3DFMT_G16R16F\n                return DXGI_FORMAT_R16G16_FLOAT;\n\n            case 113: // D3DFMT_A16B16G16R16F\n                return DXGI_FORMAT_R16G16B16A16_FLOAT;\n\n            case 114: // D3DFMT_R32F\n                return DXGI_FORMAT_R32_FLOAT;\n\n            case 115: // D3DFMT_G32R32F\n                return DXGI_FORMAT_R32G32_FLOAT;\n\n            case 116: // D3DFMT_A32B32G32R32F\n                return DXGI_FORMAT_R32G32B32A32_FLOAT;\n            }\n        }\n\n        return DXGI_FORMAT_UNKNOWN;\n    }\n\n    HRESULT FillInitData(size_t width, size_t height, size_t depth, size_t mipCount,\n        size_t arraySize, size_t numberOfPlanes, DXGI_FORMAT format, size_t maxsize, \n        size_t bitSize, const uint8_t* bitData, size_t& twidth, size_t& theight, \n        size_t& tdepth, size_t& skipMip, uint32_t& numSubresources,\n        MutableSpan<D3D12_SUBRESOURCE_DATA> subresources)\n    {\n        skipMip = 0;\n        twidth = 0;\n        theight = 0;\n        tdepth = 0;\n        numSubresources = 0;\n\n        size_t NumBytes = 0;\n        size_t RowBytes = 0;\n        const uint8_t* pEndBits = bitData + bitSize;\n        uint32_t currIdx = 0;\n\n        for (size_t p = 0; p < numberOfPlanes; ++p)\n        {\n            const uint8_t* pSrcBits = bitData;\n\n            for (size_t j = 0; j < arraySize; j++)\n            {\n                size_t w = width;\n                size_t h = height;\n                size_t d = depth;\n                for (size_t i = 0; i < mipCount; i++)\n                {\n                    HRESULT hr = GetSurfaceInfo(w, h, format, &NumBytes, &RowBytes, nullptr);\n                    if (FAILED(hr))\n                        return hr;\n\n                    if (NumBytes > UINT32_MAX || RowBytes > UINT32_MAX)\n                        return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);\n\n                    if ((mipCount <= 1) || !maxsize || (w <= maxsize && h <= maxsize && d <= maxsize))\n                    {\n                        if (!twidth)\n                        {\n                            twidth = w;\n                            theight = h;\n                            tdepth = d;\n                        }\n\n                        D3D12_SUBRESOURCE_DATA res =\n                        {\n                            pSrcBits,\n                            static_cast<LONG_PTR>(RowBytes),\n                            static_cast<LONG_PTR>(NumBytes)\n                        };\n\n                        AdjustPlaneResource(format, h, p, res);\n\n                        subresources[currIdx++] = res;\n                    }\n                    else if (!j)\n                    {\n                        // Count number of skipped mipmaps (first item only)\n                        ++skipMip;\n                    }\n\n                    if (pSrcBits + (NumBytes * d) > pEndBits)\n                        return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);\n\n                    pSrcBits += NumBytes * d;\n\n                    w = w >> 1;\n                    h = h >> 1;\n                    d = d >> 1;\n                    if (w == 0)\n                        w = 1;\n                    if (h == 0)\n                        h = 1;\n                    if (d == 0)\n                        d = 1;\n                }\n            }\n        }\n\n        numSubresources = currIdx;\n        return currIdx == 0 ? E_FAIL : S_OK;\n    }\n\n    void FillSubresourceData(const DDS_HEADER* header, MutableSpan<D3D12_SUBRESOURCE_DATA> subresources,\n        const uint8_t* bitData, size_t bitSize, uint32_t& width, uint32_t& height, uint32_t& depth, \n        uint16_t& mipCount, uint32_t& numSubresources, DXGI_FORMAT& format)\n    {\n        auto* device = App::GetRenderer().GetDevice();\n\n        width = header->width;\n        height = header->height;\n        depth = header->depth;\n\n        mipCount = (uint16_t)header->mipMapCount;\n        if (0 == mipCount)\n            mipCount = 1;\n\n        // Bound sizes (for security purposes we don't trust DDS file metadata larger than the Direct3D hardware requirements)\n        Check(mipCount <= D3D12_REQ_MIP_LEVELS, \"Not supported\");\n\n        D3D12_RESOURCE_DIMENSION resDim = D3D12_RESOURCE_DIMENSION_UNKNOWN;\n        UINT arraySize = 1;\n        format = DXGI_FORMAT_UNKNOWN;\n        bool isCubeMap = false;\n\n        if ((header->ddspf.flags & DDS_FOURCC) && (MAKEFOURCC('D', 'X', '1', '0') == header->ddspf.fourCC))\n        {\n            auto d3d10ext = reinterpret_cast<const DDS_HEADER_DXT10*>(reinterpret_cast<const char*>(header) +\n                sizeof(DDS_HEADER));\n\n            arraySize = d3d10ext->arraySize;\n            Check(arraySize != 0, \"Invalid Data\");\n\n            switch (d3d10ext->dxgiFormat)\n            {\n            case DXGI_FORMAT_AI44:\n            case DXGI_FORMAT_IA44:\n            case DXGI_FORMAT_P8:\n            case DXGI_FORMAT_A8P8:\n                Check(false, \"DDSTextureLoader does not support video textures. Consider using DirectXTex instead\");\n                break;\n\n            default:\n                Check(BitsPerPixel(d3d10ext->dxgiFormat) != 0, \n                    \"Unknown DXGI format %u\", static_cast<uint32_t>(d3d10ext->dxgiFormat));              \n            }\n\n            format = d3d10ext->dxgiFormat;\n\n            switch (d3d10ext->resourceDimension)\n            {\n            case D3D12_RESOURCE_DIMENSION_TEXTURE1D:\n                // D3DX writes 1D textures with a fixed Height of 1\n                Check(!(header->flags & DDS_HEIGHT) || height == 1, \"Invalid data\");\n\n                height = depth = 1;\n                break;\n\n            case D3D12_RESOURCE_DIMENSION_TEXTURE2D:\n                if (d3d10ext->miscFlag & 0x4 /* RESOURCE_MISC_TEXTURECUBE */)\n                {\n                    arraySize *= 6;\n                    isCubeMap = true;\n                }\n                depth = 1;\n                break;\n\n            case D3D12_RESOURCE_DIMENSION_TEXTURE3D:\n                Check(header->flags & DDS_HEADER_FLAGS_VOLUME, \"Invalid data\");\n                Check(arraySize <= 1, \"Not supported\");\n\n                break;\n\n            default:\n                Check(false, \"Not supported\");\n            }\n\n            resDim = static_cast<D3D12_RESOURCE_DIMENSION>(d3d10ext->resourceDimension);\n        }\n        else\n        {\n            format = GetDXGIFormat(header->ddspf);\n            Check(format != DXGI_FORMAT_UNKNOWN, \"Not supported\");\n\n            if (header->flags & DDS_HEADER_FLAGS_VOLUME)\n                resDim = D3D12_RESOURCE_DIMENSION_TEXTURE3D;\n            else\n            {\n                if (header->caps2 & DDS_CUBEMAP)\n                {\n                    // We require all six faces to be defined\n                    Check((header->caps2 & DDS_CUBEMAP_ALLFACES) == DDS_CUBEMAP_ALLFACES, \"Not supported\");\n\n                    arraySize = 6;\n                    isCubeMap = true;\n                }\n\n                depth = 1;\n                resDim = D3D12_RESOURCE_DIMENSION_TEXTURE2D;\n\n                // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture\n            }\n\n            Assert(BitsPerPixel(format) != 0, \"\");\n        }\n\n        switch (resDim)\n        {\n        case D3D12_RESOURCE_DIMENSION_TEXTURE1D:\n            Check(arraySize <= D3D12_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION &&\n                width <= D3D12_REQ_TEXTURE1D_U_DIMENSION, \"Not supported\");\n            break;\n\n        case D3D12_RESOURCE_DIMENSION_TEXTURE2D:\n            if (isCubeMap)\n            {\n                // This is the right bound because we set arraySize to (NumCubes*6) above\n                Check(arraySize <= D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION &&\n                    width <= D3D12_REQ_TEXTURECUBE_DIMENSION &&\n                    height <= D3D12_REQ_TEXTURECUBE_DIMENSION,\n                    \"Not supported\");\n            }\n            else\n                Check(arraySize <= D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION &&\n                    width <= D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION &&\n                    height <= D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION,\n                    \"Not supported\");\n\n            break;\n\n        case D3D12_RESOURCE_DIMENSION_TEXTURE3D:\n            Check(arraySize <= 1 &&\n                width <= D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION &&\n                height <= D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION &&\n                depth <= D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,\n                \"Not supported\");\n            break;\n\n        default:\n            Check(false, \"Not supported\");\n        }\n\n        UINT numberOfPlanes = D3D12GetFormatPlaneCount(device, format);\n        Check(numberOfPlanes, \"Invalid arg\");\n\n        // DirectX 12 uses planes for stencil, DirectX 11 does not\n        Check(numberOfPlanes <= 1 || !IsDepthStencil(format), \"Invalid arg\");\n\n        //if (outIsCubeMap != nullptr)\n        //{\n        //    *outIsCubeMap = isCubeMap;\n        //}\n\n        // Create the texture\n        size_t maxNumSubresources = (resDim == D3D12_RESOURCE_DIMENSION_TEXTURE3D)\n            ? 1 : arraySize;\n        maxNumSubresources *= mipCount;\n        maxNumSubresources *= numberOfPlanes;\n\n        Check(maxNumSubresources <= D3D12_REQ_SUBRESOURCES, \"Invalid arg\");\n        Check(subresources.size() >= maxNumSubresources, \"Insufficient space in subresource array.\");\n\n        size_t skipMip = 0;\n        size_t twidth = 0;\n        size_t theight = 0;\n        size_t tdepth = 0;\n        size_t maxsize = 0;\n\n        CheckHR(FillInitData(width, height, depth, mipCount, arraySize,\n            numberOfPlanes, format, maxsize, bitSize, bitData,\n            twidth, theight, tdepth, skipMip, numSubresources, \n            subresources));\n    }\n\n    LOAD_DDS_RESULT LoadTextureDataFromFile(const char* fileName, ArenaAllocator allocator,\n        const DDS_HEADER** header, const uint8_t** bitData, size_t* bitSize)\n    {\n        Assert(header && bitData && bitSize, \"invalid args.\");\n\n        // open the file\n        HANDLE hFile = CreateFileA(fileName,\n            GENERIC_READ,\n            FILE_SHARE_READ,\n            nullptr,\n            OPEN_EXISTING,\n            FILE_ATTRIBUTE_NORMAL,\n            nullptr);\n\n        if (hFile == INVALID_HANDLE_VALUE)\n        {\n            if (GetLastError() == ERROR_FILE_NOT_FOUND)\n                return LOAD_DDS_RESULT::FILE_NOT_FOUND;\n\n            return LOAD_DDS_RESULT::UNKNOWN;\n        }\n\n        // Get the file size\n        FILE_STANDARD_INFO fileInfo;\n        if (!GetFileInformationByHandleEx(hFile, FileStandardInfo, &fileInfo, sizeof(fileInfo)))\n        {\n            CloseHandle(hFile);\n            CheckWin32(false);\n            return LOAD_DDS_RESULT::UNKNOWN;\n        }\n\n        // File is too big for 32-bit allocation, so reject read\n        if (fileInfo.EndOfFile.HighPart > 0)\n        {\n            CloseHandle(hFile);\n            return LOAD_DDS_RESULT::FILE_TOO_BIG;\n        }\n\n        // Need at least enough data to fill the header and magic number to be a valid DDS\n        if (fileInfo.EndOfFile.LowPart < (sizeof(DDS_HEADER) + sizeof(uint32_t)))\n        {\n            CloseHandle(hFile);\n            return LOAD_DDS_RESULT::INVALID_DDS;\n        }\n\n        // create enough space for the file data\n        //ddsData.reset(new (std::nothrow) uint8_t[fileInfo.EndOfFile.LowPart]);\n        void* ddsData = allocator.AllocateAligned(fileInfo.EndOfFile.LowPart);\n        if (!ddsData)\n        {\n            CloseHandle(hFile);\n            return LOAD_DDS_RESULT::MEM_ALLOC_FAILED;\n        }\n\n        // read the data in\n        DWORD BytesRead = 0;\n        if (!ReadFile(hFile, ddsData, fileInfo.EndOfFile.LowPart, &BytesRead, nullptr))\n        {\n            CheckWin32(false);\n            CloseHandle(hFile);\n            return LOAD_DDS_RESULT::UNKNOWN;\n        }\n\n        if (BytesRead < fileInfo.EndOfFile.LowPart)\n        {\n            CloseHandle(hFile);\n            return LOAD_DDS_RESULT::UNKNOWN;\n        }\n\n        // DDS files always start with the same magic number (\"DDS \")\n        uint32_t dwMagicNumber = *reinterpret_cast<const uint32_t*>(ddsData);\n        if (dwMagicNumber != DDS_MAGIC)\n        {\n            CloseHandle(hFile);\n            return LOAD_DDS_RESULT::INVALID_DDS_HEADER;\n        }\n\n        auto hdr = reinterpret_cast<const DDS_HEADER*>(reinterpret_cast<uintptr_t>(ddsData) + sizeof(uint32_t));\n\n        // Verify header to validate DDS file\n        if (hdr->size != sizeof(DDS_HEADER) || hdr->ddspf.size != sizeof(DDS_PIXELFORMAT))\n        {\n            CloseHandle(hFile);\n            return LOAD_DDS_RESULT::INVALID_DDS_HEADER;\n        }\n\n        // Check for DX10 extension\n        bool bDXT10Header = false;\n        if ((hdr->ddspf.flags & DDS_FOURCC) &&\n            (MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC))\n        {\n            // Must be long enough for both headers and magic value\n            if (fileInfo.EndOfFile.LowPart < (sizeof(DDS_HEADER) + sizeof(uint32_t) + sizeof(DDS_HEADER_DXT10)))\n            {\n                CloseHandle(hFile);\n                return LOAD_DDS_RESULT::INVALID_DDS_HEADER;\n            }\n\n            bDXT10Header = true;\n        }\n\n        // setup the pointers in the process request\n        *header = hdr;\n        ptrdiff_t offset = sizeof(uint32_t) + sizeof(DDS_HEADER) + (bDXT10Header ? sizeof(DDS_HEADER_DXT10) : 0);\n        *bitData = reinterpret_cast<uint8_t*>(ddsData) + offset;\n        *bitSize = fileInfo.EndOfFile.LowPart - offset;\n\n        CloseHandle(hFile);\n\n        return LOAD_DDS_RESULT::SUCCESS;\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// Direct3DUtil\n//--------------------------------------------------------------------------------------\n\nD3D12_RESOURCE_ALLOCATION_INFO Direct3DUtil::AllocationInfo(D3D12_RESOURCE_DESC& desc)\n{\n    auto* device = App::GetRenderer().GetDevice();\n    return device->GetResourceAllocationInfo(0, 1, &desc);\n}\n\nD3D12_RESOURCE_ALLOCATION_INFO Direct3DUtil::AllocationInfo(Span<D3D12_RESOURCE_DESC1> descs, \n    MutableSpan<D3D12_RESOURCE_ALLOCATION_INFO1> infos)\n{\n    Assert(descs.size() == infos.size(), \"Must have the same length.\");\n\n    auto* device = App::GetRenderer().GetDevice();\n    return device->GetResourceAllocationInfo2(0, (UINT)descs.size(), descs.data(), infos.data());\n}\n\nsize_t Direct3DUtil::BitsPerPixel(DXGI_FORMAT fmt)\n{\n    switch (fmt)\n    {\n    case DXGI_FORMAT_R32G32B32A32_TYPELESS:\n    case DXGI_FORMAT_R32G32B32A32_FLOAT:\n    case DXGI_FORMAT_R32G32B32A32_UINT:\n    case DXGI_FORMAT_R32G32B32A32_SINT:\n        return 128;\n\n    case DXGI_FORMAT_R32G32B32_TYPELESS:\n    case DXGI_FORMAT_R32G32B32_FLOAT:\n    case DXGI_FORMAT_R32G32B32_UINT:\n    case DXGI_FORMAT_R32G32B32_SINT:\n        return 96;\n\n    case DXGI_FORMAT_R16G16B16A16_TYPELESS:\n    case DXGI_FORMAT_R16G16B16A16_FLOAT:\n    case DXGI_FORMAT_R16G16B16A16_UNORM:\n    case DXGI_FORMAT_R16G16B16A16_UINT:\n    case DXGI_FORMAT_R16G16B16A16_SNORM:\n    case DXGI_FORMAT_R16G16B16A16_SINT:\n    case DXGI_FORMAT_R32G32_TYPELESS:\n    case DXGI_FORMAT_R32G32_FLOAT:\n    case DXGI_FORMAT_R32G32_UINT:\n    case DXGI_FORMAT_R32G32_SINT:\n    case DXGI_FORMAT_R32G8X24_TYPELESS:\n    case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:\n    case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:\n    case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:\n    case DXGI_FORMAT_Y416:\n    case DXGI_FORMAT_Y210:\n    case DXGI_FORMAT_Y216:\n        return 64;\n\n    case DXGI_FORMAT_R10G10B10A2_TYPELESS:\n    case DXGI_FORMAT_R10G10B10A2_UNORM:\n    case DXGI_FORMAT_R10G10B10A2_UINT:\n    case DXGI_FORMAT_R11G11B10_FLOAT:\n    case DXGI_FORMAT_R8G8B8A8_TYPELESS:\n    case DXGI_FORMAT_R8G8B8A8_UNORM:\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n    case DXGI_FORMAT_R8G8B8A8_UINT:\n    case DXGI_FORMAT_R8G8B8A8_SNORM:\n    case DXGI_FORMAT_R8G8B8A8_SINT:\n    case DXGI_FORMAT_R16G16_TYPELESS:\n    case DXGI_FORMAT_R16G16_FLOAT:\n    case DXGI_FORMAT_R16G16_UNORM:\n    case DXGI_FORMAT_R16G16_UINT:\n    case DXGI_FORMAT_R16G16_SNORM:\n    case DXGI_FORMAT_R16G16_SINT:\n    case DXGI_FORMAT_R32_TYPELESS:\n    case DXGI_FORMAT_D32_FLOAT:\n    case DXGI_FORMAT_R32_FLOAT:\n    case DXGI_FORMAT_R32_UINT:\n    case DXGI_FORMAT_R32_SINT:\n    case DXGI_FORMAT_R24G8_TYPELESS:\n    case DXGI_FORMAT_D24_UNORM_S8_UINT:\n    case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:\n    case DXGI_FORMAT_X24_TYPELESS_G8_UINT:\n    case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:\n    case DXGI_FORMAT_R8G8_B8G8_UNORM:\n    case DXGI_FORMAT_G8R8_G8B8_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_UNORM:\n    case DXGI_FORMAT_B8G8R8X8_UNORM:\n    case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_TYPELESS:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8X8_TYPELESS:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n    case DXGI_FORMAT_AYUV:\n    case DXGI_FORMAT_Y410:\n    case DXGI_FORMAT_YUY2:\n        return 32;\n\n    case DXGI_FORMAT_P010:\n    case DXGI_FORMAT_P016:\n        return 24;\n\n    case DXGI_FORMAT_R8G8_TYPELESS:\n    case DXGI_FORMAT_R8G8_UNORM:\n    case DXGI_FORMAT_R8G8_UINT:\n    case DXGI_FORMAT_R8G8_SNORM:\n    case DXGI_FORMAT_R8G8_SINT:\n    case DXGI_FORMAT_R16_TYPELESS:\n    case DXGI_FORMAT_R16_FLOAT:\n    case DXGI_FORMAT_D16_UNORM:\n    case DXGI_FORMAT_R16_UNORM:\n    case DXGI_FORMAT_R16_UINT:\n    case DXGI_FORMAT_R16_SNORM:\n    case DXGI_FORMAT_R16_SINT:\n    case DXGI_FORMAT_B5G6R5_UNORM:\n    case DXGI_FORMAT_B5G5R5A1_UNORM:\n    case DXGI_FORMAT_A8P8:\n    case DXGI_FORMAT_B4G4R4A4_UNORM:\n        return 16;\n\n    case DXGI_FORMAT_NV12:\n    case DXGI_FORMAT_420_OPAQUE:\n    case DXGI_FORMAT_NV11:\n        return 12;\n\n    case DXGI_FORMAT_R8_TYPELESS:\n    case DXGI_FORMAT_R8_UNORM:\n    case DXGI_FORMAT_R8_UINT:\n    case DXGI_FORMAT_R8_SNORM:\n    case DXGI_FORMAT_R8_SINT:\n    case DXGI_FORMAT_A8_UNORM:\n    case DXGI_FORMAT_AI44:\n    case DXGI_FORMAT_IA44:\n    case DXGI_FORMAT_P8:\n        return 8;\n\n    case DXGI_FORMAT_R1_UNORM:\n        return 1;\n\n    case DXGI_FORMAT_BC1_TYPELESS:\n    case DXGI_FORMAT_BC1_UNORM:\n    case DXGI_FORMAT_BC1_UNORM_SRGB:\n    case DXGI_FORMAT_BC4_TYPELESS:\n    case DXGI_FORMAT_BC4_UNORM:\n    case DXGI_FORMAT_BC4_SNORM:\n        return 4;\n\n    case DXGI_FORMAT_BC2_TYPELESS:\n    case DXGI_FORMAT_BC2_UNORM:\n    case DXGI_FORMAT_BC2_UNORM_SRGB:\n    case DXGI_FORMAT_BC3_TYPELESS:\n    case DXGI_FORMAT_BC3_UNORM:\n    case DXGI_FORMAT_BC3_UNORM_SRGB:\n    case DXGI_FORMAT_BC5_TYPELESS:\n    case DXGI_FORMAT_BC5_UNORM:\n    case DXGI_FORMAT_BC5_SNORM:\n    case DXGI_FORMAT_BC6H_TYPELESS:\n    case DXGI_FORMAT_BC6H_UF16:\n    case DXGI_FORMAT_BC6H_SF16:\n    case DXGI_FORMAT_BC7_TYPELESS:\n    case DXGI_FORMAT_BC7_UNORM:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n        return 8;\n\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10)\n\n    case DXGI_FORMAT_V408:\n        return 24;\n\n    case DXGI_FORMAT_P208:\n    case DXGI_FORMAT_V208:\n        return 16;\n\n#endif // (_WIN32_WINNT >= _WIN32_WINNT_WIN10)\n\n    default:\n        return 0;\n    }\n}\n\nHRESULT Direct3DUtil::GetSurfaceInfo(size_t width,\n    size_t height,\n    DXGI_FORMAT fmt,\n    size_t* outNumBytes,\n    size_t* outRowBytes,\n    size_t* outNumRows)\n{\n    uint64_t numBytes = 0;\n    uint64_t rowBytes = 0;\n    uint64_t numRows = 0;\n\n    bool bc = false;\n    bool packed = false;\n    bool planar = false;\n    size_t bpe = 0;\n\n    switch (fmt)\n    {\n    case DXGI_FORMAT_BC1_TYPELESS:\n    case DXGI_FORMAT_BC1_UNORM:\n    case DXGI_FORMAT_BC1_UNORM_SRGB:\n    case DXGI_FORMAT_BC4_TYPELESS:\n    case DXGI_FORMAT_BC4_UNORM:\n    case DXGI_FORMAT_BC4_SNORM:\n        bc = true;\n        bpe = 8;\n        break;\n\n    case DXGI_FORMAT_BC2_TYPELESS:\n    case DXGI_FORMAT_BC2_UNORM:\n    case DXGI_FORMAT_BC2_UNORM_SRGB:\n    case DXGI_FORMAT_BC3_TYPELESS:\n    case DXGI_FORMAT_BC3_UNORM:\n    case DXGI_FORMAT_BC3_UNORM_SRGB:\n    case DXGI_FORMAT_BC5_TYPELESS:\n    case DXGI_FORMAT_BC5_UNORM:\n    case DXGI_FORMAT_BC5_SNORM:\n    case DXGI_FORMAT_BC6H_TYPELESS:\n    case DXGI_FORMAT_BC6H_UF16:\n    case DXGI_FORMAT_BC6H_SF16:\n    case DXGI_FORMAT_BC7_TYPELESS:\n    case DXGI_FORMAT_BC7_UNORM:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n        bc = true;\n        bpe = 16;\n        break;\n\n    case DXGI_FORMAT_R8G8_B8G8_UNORM:\n    case DXGI_FORMAT_G8R8_G8B8_UNORM:\n    case DXGI_FORMAT_YUY2:\n        packed = true;\n        bpe = 4;\n        break;\n\n    case DXGI_FORMAT_Y210:\n    case DXGI_FORMAT_Y216:\n        packed = true;\n        bpe = 8;\n        break;\n\n    case DXGI_FORMAT_NV12:\n    case DXGI_FORMAT_420_OPAQUE:\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10)\n    case DXGI_FORMAT_P208:\n#endif\n        planar = true;\n        bpe = 2;\n        break;\n\n    case DXGI_FORMAT_P010:\n    case DXGI_FORMAT_P016:\n        planar = true;\n        bpe = 4;\n        break;\n\n    default:\n        break;\n    }\n\n    if (bc)\n    {\n        uint64_t numBlocksWide = 0;\n        if (width > 0)\n        {\n            numBlocksWide = Math::Max<uint64_t>(1u, (uint64_t(width) + 3u) / 4u);\n        }\n        uint64_t numBlocksHigh = 0;\n        if (height > 0)\n        {\n            numBlocksHigh = Math::Max<uint64_t>(1u, (uint64_t(height) + 3u) / 4u);\n        }\n        rowBytes = numBlocksWide * bpe;\n        numRows = numBlocksHigh;\n        numBytes = rowBytes * numBlocksHigh;\n    }\n    else if (packed)\n    {\n        rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;\n        numRows = uint64_t(height);\n        numBytes = rowBytes * height;\n    }\n    else if (fmt == DXGI_FORMAT_NV11)\n    {\n        rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u;\n        numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data\n        numBytes = rowBytes * numRows;\n    }\n    else if (planar)\n    {\n        rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe;\n        numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1);\n        numRows = height + ((uint64_t(height) + 1u) >> 1);\n    }\n    else\n    {\n        size_t bpp = BitsPerPixel(fmt);\n        if (!bpp)\n            return E_INVALIDARG;\n\n        rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte\n        numRows = uint64_t(height);\n        numBytes = rowBytes * height;\n    }\n\n    static_assert(sizeof(size_t) == 8, \"Not a 64-bit platform!\");\n\n    if (outNumBytes)\n        *outNumBytes = static_cast<size_t>(numBytes);\n    if (outRowBytes)\n        *outRowBytes = static_cast<size_t>(rowBytes);\n    if (outNumRows)\n        *outNumRows = static_cast<size_t>(numRows);\n\n    return S_OK;\n}\n\nUINT64 Direct3DUtil::GetRequiredIntermediateSize(ID3D12Resource* destinationResource, \n    UINT firstSubresource, UINT numSubresources)\n{\n    auto desc = destinationResource->GetDesc();\n    UINT64 requiredSize = 0;\n\n    ID3D12Device* device = App::GetRenderer().GetDevice();\n    device->GetCopyableFootprints(&desc, firstSubresource, numSubresources, 0, nullptr, \n        nullptr, nullptr, &requiredSize);\n\n    return requiredSize;\n}\n\nLOAD_DDS_RESULT Direct3DUtil::LoadDDSFromFile(const char* path,\n    MutableSpan<D3D12_SUBRESOURCE_DATA> subresources,\n    DXGI_FORMAT& format, \n    ArenaAllocator allocator,\n    uint32_t& width, \n    uint32_t& height, \n    uint32_t& depth, \n    uint16_t& mipCount,\n    uint32_t& numSubresources)\n{\n    // ddsData is populated with the file contents\n    // bitData offsets into ddsData where the data starts\n\n    const DDS_HEADER* header = nullptr;\n    const uint8_t* bitData = nullptr;\n    size_t bitSize = 0;\n\n    auto res = LoadTextureDataFromFile(path, allocator, &header, &bitData, &bitSize);\n    if (res != LOAD_DDS_RESULT::SUCCESS)\n        return res;\n\n    FillSubresourceData(header, subresources, bitData, bitSize, width, height, \n        depth, mipCount, numSubresources, format);\n\n    return LOAD_DDS_RESULT::SUCCESS;\n}\n\nD3D12_GRAPHICS_PIPELINE_STATE_DESC Direct3DUtil::GetPSODesc(const D3D12_INPUT_LAYOUT_DESC* inputLayout,\n    int numRenderTargets, \n    DXGI_FORMAT* rtvFormats, \n    DXGI_FORMAT dsvFormat, \n    D3D12_DEPTH_STENCIL_DESC* depthStencilDesc, \n    D3D12_RASTERIZER_DESC* rasterizerDesc, \n    D3D12_BLEND_DESC* blendDesc, \n    D3D12_PRIMITIVE_TOPOLOGY_TYPE primitiveTopology)\n{\n    //DXGI_FORMAT unknownFormats[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = { DXGI_FORMAT_UNKNOWN };\n\n    Assert(numRenderTargets <= D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT,\n        \"Invalid number of render targets.\");\n\n    D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};\n    psoDesc.BlendState = blendDesc ? *blendDesc : DefaultBlendDesc();\n    psoDesc.RasterizerState = rasterizerDesc ? *rasterizerDesc : DefaultRasterizerDesc();\n    psoDesc.DepthStencilState = depthStencilDesc ? *depthStencilDesc : DefaultDepthStencilDesc();\n    psoDesc.NumRenderTargets = numRenderTargets;\n    memcpy(psoDesc.RTVFormats, rtvFormats, sizeof(DXGI_FORMAT) * numRenderTargets);\n    psoDesc.DSVFormat = dsvFormat;\n    psoDesc.PrimitiveTopologyType = primitiveTopology;\n    psoDesc.SampleMask = UINT_MAX;\n    psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;\n    psoDesc.SampleDesc.Count = 1;\n    psoDesc.NodeMask = 0;\n\n    if(inputLayout)\n        psoDesc.InputLayout = *inputLayout;\n\n    return psoDesc;\n}\n\nuint64_t Direct3DUtil::GetPSODescHash(D3D12_GRAPHICS_PIPELINE_STATE_DESC& desc)\n{\n    // Exclude pointers\n    constexpr int offset1 = offsetof(D3D12_GRAPHICS_PIPELINE_STATE_DESC, BlendState);\n    constexpr int offset2 = offsetof(D3D12_GRAPHICS_PIPELINE_STATE_DESC, NodeMask);\n    constexpr int range = offset2 - offset1;\n\n    uint8_t* start = reinterpret_cast<uint8_t*>(&desc) + offset1;\n\n    return XXH3_64bits(start, range);\n}\n\nvoid Direct3DUtil::CreateGraphicsPSO(D3D12_GRAPHICS_PIPELINE_STATE_DESC& psDesc,\n    ID3D12RootSignature* rootSignature, const D3D12_SHADER_BYTECODE* vertexShader, \n    const D3D12_SHADER_BYTECODE* pixelShader, const D3D12_SHADER_BYTECODE* hullShader, \n    const D3D12_SHADER_BYTECODE* domainShader, ID3D12PipelineState** pipelineState)\n{\n    psDesc.pRootSignature = rootSignature;\n\n    psDesc.VS = *vertexShader;\n    psDesc.PS = *pixelShader;\n\n    if (hullShader)\n    {\n        psDesc.HS = *hullShader;\n        psDesc.DS = *domainShader;\n    }\n\n    auto* device = App::GetRenderer().GetDevice();\n    CheckHR(device->CreateGraphicsPipelineState(&psDesc, IID_PPV_ARGS(pipelineState)));\n}\n\nvoid Direct3DUtil::CreateBufferSRV(const Buffer& buff, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n    UINT stride, UINT numElements)\n{\n    auto* res = const_cast<Buffer&>(buff).Resource();\n    Assert(res, \"Buffer hasn't been initialized.\");\n\n    D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc{};\n    srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;\n    srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;\n    srvDesc.Format = DXGI_FORMAT_UNKNOWN;\n    srvDesc.Buffer.NumElements = numElements;\n    srvDesc.Buffer.StructureByteStride = stride;\n\n    auto* device = App::GetRenderer().GetDevice();\n    device->CreateShaderResourceView(res, &srvDesc, cpuHandle);\n}\n\nvoid Direct3DUtil::CreateBufferUAV(const Buffer& buff, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n    UINT stride, UINT numElements)\n{\n    auto* res = const_cast<Buffer&>(buff).Resource();\n    Assert(res, \"Buffer hasn't been initialized.\");\n\n    D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc{};\n    uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;\n    uavDesc.Format = DXGI_FORMAT_UNKNOWN;\n    uavDesc.Buffer.NumElements = numElements;\n    uavDesc.Buffer.StructureByteStride = stride;\n\n    auto* device = App::GetRenderer().GetDevice();\n    device->CreateUnorderedAccessView(res, nullptr, &uavDesc, cpuHandle);\n}\n\nvoid Direct3DUtil::CreateRawBufferUAV(const Buffer& buff, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n    UINT stride, UINT numElements)\n{\n    auto* res = const_cast<Buffer&>(buff).Resource();\n    Assert(res, \"Buffer hasn't been initialized.\");\n    Assert((stride & (4 - 1)) == 0, \"Stride must be a multiple of 4.\");\n\n    const uint32_t byteWidth = stride * numElements;\n\n    D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc{};\n    uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;\n    uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;\n    uavDesc.Buffer.NumElements = byteWidth >> 2;    // should be equal to number of 4-byte (unsigned) integers\n    uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;\n\n    auto* device = App::GetRenderer().GetDevice();\n    device->CreateUnorderedAccessView(res, nullptr, &uavDesc, cpuHandle);\n}\n\nvoid Direct3DUtil::CreateTexture2DSRV(ID3D12Resource* res, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n    DXGI_FORMAT f, float minLODClamp, UINT mostDetailedMip, UINT planeSlice)\n{\n    Assert(cpuHandle.ptr != 0, \"Uninitialized D3D12_CPU_DESCRIPTOR_HANDLE.\");\n    auto* device = App::GetRenderer().GetDevice();\n    Assert(res, \"Attempting to create SRV for NULL texture.\");\n    auto desc = res->GetDesc();\n\n    D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc{};\n    srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;\n    srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;\n    srvDesc.Texture2D.MostDetailedMip = mostDetailedMip;\n    srvDesc.Texture2D.PlaneSlice = planeSlice;\n    srvDesc.Texture2D.ResourceMinLODClamp = minLODClamp;\n    srvDesc.Texture2D.MipLevels = desc.MipLevels;\n    srvDesc.Format = f == DXGI_FORMAT_UNKNOWN ? desc.Format : f;\n\n    device->CreateShaderResourceView(res, &srvDesc, cpuHandle);\n}\n\nvoid Direct3DUtil::CreateTexture2DSRV(const Texture& t, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n    DXGI_FORMAT f, float minLODClamp, UINT mostDetailedMip, UINT planeSlice)\n{\n    Assert(cpuHandle.ptr != 0, \"Uninitialized D3D12_CPU_DESCRIPTOR_HANDLE.\");\n    auto* device = App::GetRenderer().GetDevice();\n    auto* res = const_cast<Texture&>(t).Resource();\n    Assert(res, \"Attempting to create SRV for NULL texture.\");\n    auto desc = res->GetDesc();\n\n    D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc{};\n    srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;\n    srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;\n    srvDesc.Texture2D.MostDetailedMip = mostDetailedMip;\n    srvDesc.Texture2D.PlaneSlice = planeSlice;\n    srvDesc.Texture2D.ResourceMinLODClamp = minLODClamp;\n    srvDesc.Texture2D.MipLevels = desc.MipLevels;\n    srvDesc.Format = f == DXGI_FORMAT_UNKNOWN ? desc.Format : f;\n    \n    device->CreateShaderResourceView(res, &srvDesc, cpuHandle);\n}\n\nvoid Direct3DUtil::CreateTexture3DSRV(const Texture& t, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n    DXGI_FORMAT f, float minLODClamp, UINT mostDetailedMip, UINT planeSlice)\n{\n    Assert(cpuHandle.ptr != 0, \"Uninitialized D3D12_CPU_DESCRIPTOR_HANDLE.\");\n    auto* device = App::GetRenderer().GetDevice();\n    auto* res = const_cast<Texture&>(t).Resource();\n    auto desc = res->GetDesc();\n\n    D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc{};\n    srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;\n    srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;\n    srvDesc.Texture3D.MipLevels = desc.MipLevels;\n    srvDesc.Texture3D.MostDetailedMip = mostDetailedMip;\n    srvDesc.Texture3D.ResourceMinLODClamp = minLODClamp;\n    srvDesc.Format = f == DXGI_FORMAT_UNKNOWN ? desc.Format : f;\n\n    device->CreateShaderResourceView(res, &srvDesc, cpuHandle);\n}\n\nvoid Direct3DUtil::CreateRTV(const Texture& t, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, DXGI_FORMAT f, \n    UINT mipSlice, UINT planeSlice)\n{\n    Assert(cpuHandle.ptr != 0, \"Uninitialized D3D12_CPU_DESCRIPTOR_HANDLE.\");\n    auto* device = App::GetRenderer().GetDevice();\n    auto* res = const_cast<Texture&>(t).Resource();\n    auto desc = res->GetDesc();\n\n    D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;\n    rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;\n    rtvDesc.Texture2D.MipSlice = mipSlice;\n    rtvDesc.Texture2D.PlaneSlice = planeSlice;\n    rtvDesc.Format = f == DXGI_FORMAT_UNKNOWN ? desc.Format : f;\n\n    device->CreateRenderTargetView(res, &rtvDesc, cpuHandle);\n}\n\nvoid Direct3DUtil::CreateTexture2DUAV(const Texture& t, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n    DXGI_FORMAT f, UINT mipSlice, UINT planeSlice)\n{\n    Assert(cpuHandle.ptr != 0, \"Uninitialized D3D12_CPU_DESCRIPTOR_HANDLE.\");\n    auto* device = App::GetRenderer().GetDevice();\n    auto* res = const_cast<Texture&>(t).Resource();\n    auto desc = res->GetDesc();\n\n    D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc{};\n    uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;\n    uavDesc.Texture2D.MipSlice = mipSlice;\n    uavDesc.Texture2D.PlaneSlice = planeSlice;\n    uavDesc.Format = f == DXGI_FORMAT_UNKNOWN ? desc.Format : f;\n\n    device->CreateUnorderedAccessView(res, nullptr, &uavDesc, cpuHandle);\n}\n\nvoid Direct3DUtil::CreateTexture3DUAV(const Texture& t, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n    DXGI_FORMAT f, UINT mipSlice, UINT numSlices, UINT firstSliceIdx)\n{\n    Assert(cpuHandle.ptr != 0, \"Uninitialized D3D12_CPU_DESCRIPTOR_HANDLE.\");\n    auto* device = App::GetRenderer().GetDevice();\n    auto* res = const_cast<Texture&>(t).Resource();\n    auto desc = res->GetDesc();\n\n    D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc{};\n    uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;\n    uavDesc.Texture3D.MipSlice = mipSlice;\n    uavDesc.Texture3D.WSize = numSlices > 0 ? numSlices : desc.DepthOrArraySize;\n    uavDesc.Texture3D.FirstWSlice = firstSliceIdx;\n    uavDesc.Format = f == DXGI_FORMAT_UNKNOWN ? desc.Format : f;\n\n    device->CreateUnorderedAccessView(res, nullptr, &uavDesc, cpuHandle);\n}\n"
  },
  {
    "path": "Source/ZetaCore/Core/Direct3DUtil.h",
    "content": "// Ref: Some of the following functions are from DirectXTK12 (MIT License):\n// https://github.com/microsoft/DirectXTK12\n\n#pragma once\n\n#include \"Device.h\"\n#include \"../App/App.h\"\n\nnamespace ZetaRay::App\n{\n    struct PoolAllocator;\n}\n\nnamespace ZetaRay::Util\n{\n    template<typename T, Support::AllocatorType Allocator>\n    class Vector;\n}\n\nnamespace ZetaRay::Core::GpuMemory\n{\n    struct Texture;\n    struct Buffer;\n}\n\nnamespace ZetaRay::Support\n{\n    struct ArenaAllocator;\n}\n\nnamespace ZetaRay::Core::Direct3DUtil\n{\n    enum class LOAD_DDS_RESULT\n    {\n        SUCCESS,\n        FILE_NOT_FOUND,\n        INVALID_DDS,\n        INVALID_DDS_HEADER,\n        MEM_ALLOC_FAILED,\n        FILE_TOO_BIG,\n        UNKNOWN,\n        COUNT\n    };\n\n    struct DDS_HEADER;\n\n    inline D3D12_HEAP_PROPERTIES UploadHeapProp()\n    {\n        D3D12_HEAP_PROPERTIES uploadHeap{\n            .Type = D3D12_HEAP_TYPE_UPLOAD,\n            .CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN,\n            .MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN,\n            .CreationNodeMask = 1,\n            .VisibleNodeMask = 1 };\n\n        return uploadHeap;\n    }\n\n    inline D3D12_HEAP_PROPERTIES DefaultHeapProp()\n    {\n        D3D12_HEAP_PROPERTIES defaultHeap{\n            .Type = D3D12_HEAP_TYPE_DEFAULT,\n            .CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN,\n            .MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN,\n            .CreationNodeMask = 1,\n            .VisibleNodeMask = 1 };\n\n        return defaultHeap;\n    }\n\n    inline D3D12_HEAP_PROPERTIES ReadbackHeapProp()\n    {\n        D3D12_HEAP_PROPERTIES defaultHeap{\n            .Type = D3D12_HEAP_TYPE_READBACK,\n            .CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN,\n            .MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN,\n            .CreationNodeMask = 1,\n            .VisibleNodeMask = 1 };\n\n        return defaultHeap;\n    }\n\n    inline D3D12_RESOURCE_DESC BufferResourceDesc(UINT64 w,\n        D3D12_RESOURCE_FLAGS f = D3D12_RESOURCE_FLAG_NONE)\n    {\n        D3D12_RESOURCE_DESC bufferDesc;\n\n        bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;\n        bufferDesc.Alignment = 0;\n        bufferDesc.Width = w;\n        bufferDesc.Height = 1;\n        bufferDesc.DepthOrArraySize = 1;\n        bufferDesc.MipLevels = 1;\n        bufferDesc.Format = DXGI_FORMAT_UNKNOWN;\n        bufferDesc.SampleDesc.Count = 1;\n        bufferDesc.SampleDesc.Quality = 0;\n        bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;\n        bufferDesc.Flags = f;\n\n        return bufferDesc;\n    }\n\n    inline D3D12_RESOURCE_DESC1 BufferResourceDesc1(UINT64 w,\n        D3D12_RESOURCE_FLAGS f = D3D12_RESOURCE_FLAG_NONE)\n    {\n        D3D12_RESOURCE_DESC1 bufferDesc;\n\n        bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;\n        bufferDesc.Alignment = 0;\n        bufferDesc.Width = w;\n        bufferDesc.Height = 1;\n        bufferDesc.DepthOrArraySize = 1;\n        bufferDesc.MipLevels = 1;\n        bufferDesc.Format = DXGI_FORMAT_UNKNOWN;\n        bufferDesc.SampleDesc.Count = 1;\n        bufferDesc.SampleDesc.Quality = 0;\n        bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;\n        bufferDesc.Flags = f;\n\n        return bufferDesc;\n    }\n\n    inline D3D12_RESOURCE_DESC Tex1D(DXGI_FORMAT format, UINT64 width,\n        uint16_t arraySize = 1, uint16_t mipLevels = 1,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0)\n    {\n        D3D12_RESOURCE_DESC tex1DDesc;\n\n        tex1DDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D;\n        tex1DDesc.Format = format;\n        tex1DDesc.Alignment = alignment;\n        tex1DDesc.Width = width;\n        tex1DDesc.Height = 1;\n        tex1DDesc.MipLevels = mipLevels;\n        tex1DDesc.DepthOrArraySize = arraySize;\n        tex1DDesc.Flags = flags;\n        tex1DDesc.Layout = layout;\n        tex1DDesc.SampleDesc.Count = 1;\n        tex1DDesc.SampleDesc.Quality = 0;\n\n        return tex1DDesc;\n    }\n\n    inline D3D12_RESOURCE_DESC Tex2D(DXGI_FORMAT format, UINT64 width, UINT height,\n        uint16_t arraySize = 1, uint16_t mipLevels = 1,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0)\n    {\n        D3D12_RESOURCE_DESC tex2DDesc;\n\n        tex2DDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;\n        tex2DDesc.Format = format;\n        tex2DDesc.Alignment = alignment;\n        tex2DDesc.Width = width;\n        tex2DDesc.Height = height;\n        tex2DDesc.MipLevels = mipLevels;\n        tex2DDesc.DepthOrArraySize = arraySize;\n        tex2DDesc.Flags = flags;\n        tex2DDesc.Layout = layout;\n        tex2DDesc.SampleDesc.Count = 1;\n        tex2DDesc.SampleDesc.Quality = 0;\n\n        return tex2DDesc;\n    }\n\n    inline D3D12_RESOURCE_DESC1 Tex2D1(DXGI_FORMAT format, UINT64 width, UINT height,\n        uint16_t arraySize = 1, uint16_t mipLevels = 1,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0)\n    {\n        D3D12_RESOURCE_DESC1 tex2DDesc;\n\n        tex2DDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;\n        tex2DDesc.Format = format;\n        tex2DDesc.Alignment = alignment;\n        tex2DDesc.Width = width;\n        tex2DDesc.Height = height;\n        tex2DDesc.MipLevels = mipLevels;\n        tex2DDesc.DepthOrArraySize = arraySize;\n        tex2DDesc.Flags = flags;\n        tex2DDesc.Layout = layout;\n        tex2DDesc.SampleDesc.Count = 1;\n        tex2DDesc.SampleDesc.Quality = 0;\n        tex2DDesc.SamplerFeedbackMipRegion.Width = 0;\n        tex2DDesc.SamplerFeedbackMipRegion.Height = 0;\n        tex2DDesc.SamplerFeedbackMipRegion.Depth = 0;\n\n        return tex2DDesc;\n    }\n\n    inline D3D12_RESOURCE_DESC Tex3D(DXGI_FORMAT format, UINT64 width, UINT height,\n        uint16_t depth = 1, uint16_t mipLevels = 1,\n        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,\n        D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,\n        UINT64 alignment = 0)\n    {\n        D3D12_RESOURCE_DESC tex2DDesc;\n\n        tex2DDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;\n        tex2DDesc.Format = format;\n        tex2DDesc.Alignment = alignment;\n        tex2DDesc.Width = width;\n        tex2DDesc.Height = height;\n        tex2DDesc.MipLevels = mipLevels;\n        tex2DDesc.DepthOrArraySize = depth;\n        tex2DDesc.Flags = flags;\n        tex2DDesc.Layout = layout;\n        tex2DDesc.SampleDesc.Count = 1;\n        tex2DDesc.SampleDesc.Quality = 0;\n\n        return tex2DDesc;\n    }\n\n    D3D12_RESOURCE_ALLOCATION_INFO AllocationInfo(D3D12_RESOURCE_DESC& desc);\n    D3D12_RESOURCE_ALLOCATION_INFO AllocationInfo(Util::Span<D3D12_RESOURCE_DESC1> descs, \n        Util::MutableSpan<D3D12_RESOURCE_ALLOCATION_INFO1> infos);\n\n    inline D3D12_RESOURCE_BARRIER TransitionBarrier(ID3D12Resource* res,\n        D3D12_RESOURCE_STATES before,\n        D3D12_RESOURCE_STATES after,\n        UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,\n        D3D12_RESOURCE_BARRIER_FLAGS flags = D3D12_RESOURCE_BARRIER_FLAG_NONE)\n    {\n        D3D12_RESOURCE_BARRIER barrier{};\n\n        barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n        barrier.Transition.pResource = res;\n        barrier.Transition.StateBefore = before;\n        barrier.Transition.StateAfter = after;\n        barrier.Transition.Subresource = subresource;\n        barrier.Flags = flags;\n\n        return barrier;\n    }\n\n    inline D3D12_BUFFER_BARRIER BufferBarrier(ID3D12Resource* res,\n        D3D12_BARRIER_SYNC syncBefore,\n        D3D12_BARRIER_SYNC syncAfter,\n        D3D12_BARRIER_ACCESS accessBefore,\n        D3D12_BARRIER_ACCESS accessAfter)\n    {\n        return D3D12_BUFFER_BARRIER{ .SyncBefore = syncBefore,\n            .SyncAfter = syncAfter,\n            .AccessBefore = accessBefore,\n            .AccessAfter = accessAfter,\n            .pResource = res,\n            .Offset = 0,\n            .Size = UINT64_MAX };\n    }\n\n    inline D3D12_TEXTURE_BARRIER TextureBarrier(ID3D12Resource* res,\n        D3D12_BARRIER_SYNC syncBefore,\n        D3D12_BARRIER_SYNC syncAfter,\n        D3D12_BARRIER_LAYOUT layoutBefore,\n        D3D12_BARRIER_LAYOUT layoutAfter,\n        D3D12_BARRIER_ACCESS accessBefore,\n        D3D12_BARRIER_ACCESS accessAfter,\n        UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES)\n    {\n        D3D12_BARRIER_SUBRESOURCE_RANGE range;\n        range.NumMipLevels = 0;\n        range.IndexOrFirstMipLevel = subresource;\n\n        D3D12_TEXTURE_BARRIER barrier;\n        barrier.pResource = res;\n        barrier.SyncBefore = syncBefore;\n        barrier.SyncAfter = syncAfter;\n        barrier.AccessBefore = accessBefore;\n        barrier.AccessAfter = accessAfter;\n        barrier.LayoutBefore = layoutBefore;\n        barrier.LayoutAfter = layoutAfter;\n        barrier.Subresources.NumMipLevels = 0;\n        barrier.Subresources.IndexOrFirstMipLevel = subresource;\n        barrier.Flags = D3D12_TEXTURE_BARRIER_FLAG_NONE;\n        \n        return barrier;\n    }\n\n    inline D3D12_BARRIER_GROUP BarrierGroup(D3D12_BUFFER_BARRIER& barrier)\n    {\n        D3D12_BARRIER_GROUP group;\n        group.Type = D3D12_BARRIER_TYPE_BUFFER;\n        group.NumBarriers = 1;\n        group.pBufferBarriers = &barrier;\n\n        return group;\n    }\n\n    inline D3D12_BARRIER_GROUP BarrierGroup(D3D12_BUFFER_BARRIER* barriers, uint32_t numBarriers)\n    {\n        D3D12_BARRIER_GROUP group;\n        group.Type = D3D12_BARRIER_TYPE_BUFFER;\n        group.NumBarriers = numBarriers;\n        group.pBufferBarriers = barriers;\n\n        return group;\n    }    \n\n    inline D3D12_BARRIER_GROUP BarrierGroup(D3D12_TEXTURE_BARRIER& barrier)\n    {\n        D3D12_BARRIER_GROUP group;\n        group.Type = D3D12_BARRIER_TYPE_TEXTURE;\n        group.NumBarriers = 1;\n        group.pTextureBarriers = &barrier;\n\n        return group;\n    }\n\n    inline D3D12_BARRIER_GROUP BarrierGroup(D3D12_TEXTURE_BARRIER* barriers, uint32_t numBarriers)\n    {\n        D3D12_BARRIER_GROUP group;\n        group.Type = D3D12_BARRIER_TYPE_TEXTURE;\n        group.NumBarriers = numBarriers;\n        group.pTextureBarriers = barriers;\n\n        return group;\n    }\n\n    inline D3D12_RESOURCE_BARRIER UAVBarrier(ID3D12Resource* res)\n    {\n        D3D12_RESOURCE_BARRIER barrier{};\n\n        barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;\n        barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;\n        barrier.UAV.pResource = res;\n\n        return barrier;\n    }\n\n    // Convenience methods for common texture barriers\n    inline D3D12_TEXTURE_BARRIER TextureBarrier_SrvToUavNoSync(ID3D12Resource* res,\n        bool directQueue = true,\n        UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES)\n    {\n        D3D12_BARRIER_SUBRESOURCE_RANGE range;\n        range.NumMipLevels = 0;\n        range.IndexOrFirstMipLevel = subresource;\n\n        D3D12_TEXTURE_BARRIER barrier;\n        barrier.pResource = res;\n        barrier.SyncBefore = D3D12_BARRIER_SYNC_NONE;\n        barrier.SyncAfter = D3D12_BARRIER_SYNC_COMPUTE_SHADING;\n        // D3D12_BARRIER_SYNC_NONE is always paired with D3D12_BARRIER_ACCESS_NO_ACCESS\n        barrier.AccessBefore = D3D12_BARRIER_ACCESS_NO_ACCESS;\n        barrier.AccessAfter = D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;\n        barrier.LayoutBefore = directQueue ?\n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE :\n            D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE;\n        // UAV access must be paired with D3D12_BARRIER_LAYOUT_QUEUE_UNORDERED_ACCESS\n        barrier.LayoutAfter = directQueue ?\n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS :\n            D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS;\n        barrier.Subresources.NumMipLevels = 0;\n        barrier.Subresources.IndexOrFirstMipLevel = subresource;\n        barrier.Flags = D3D12_TEXTURE_BARRIER_FLAG_NONE;\n\n        return barrier;\n    }\n\n    inline D3D12_TEXTURE_BARRIER TextureBarrier_SrvToUavWithSync(ID3D12Resource* res,\n        bool directQueue = true,\n        UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES)\n    {\n        D3D12_BARRIER_SUBRESOURCE_RANGE range;\n        range.NumMipLevels = 0;\n        range.IndexOrFirstMipLevel = subresource;\n\n        D3D12_TEXTURE_BARRIER barrier;\n        barrier.pResource = res;\n        barrier.SyncBefore = D3D12_BARRIER_SYNC_COMPUTE_SHADING;\n        barrier.SyncAfter = D3D12_BARRIER_SYNC_COMPUTE_SHADING;\n        barrier.AccessBefore = D3D12_BARRIER_ACCESS_SHADER_RESOURCE;\n        barrier.AccessAfter = D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;\n        barrier.LayoutBefore = directQueue ? \n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE:\n            D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE;\n        // UAV access must be paired with D3D12_BARRIER_LAYOUT_QUEUE_UNORDERED_ACCESS\n        barrier.LayoutAfter = directQueue ? \n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS:\n            D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS;\n        barrier.Subresources.NumMipLevels = 0;\n        barrier.Subresources.IndexOrFirstMipLevel = subresource;\n        barrier.Flags = D3D12_TEXTURE_BARRIER_FLAG_NONE;\n\n        return barrier;\n    }\n\n    inline D3D12_TEXTURE_BARRIER TextureBarrier_UavToSrvNoSync(ID3D12Resource* res,\n        bool directQueue = true,\n        UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES)\n    {\n        D3D12_BARRIER_SUBRESOURCE_RANGE range;\n        range.NumMipLevels = 0;\n        range.IndexOrFirstMipLevel = subresource;\n\n        D3D12_TEXTURE_BARRIER barrier;\n        barrier.pResource = res;\n        barrier.SyncBefore = D3D12_BARRIER_SYNC_NONE;\n        barrier.SyncAfter = D3D12_BARRIER_SYNC_COMPUTE_SHADING;\n        // D3D12_BARRIER_SYNC_NONE is always paired with D3D12_BARRIER_ACCESS_NO_ACCESS\n        barrier.AccessBefore = D3D12_BARRIER_ACCESS_NO_ACCESS;\n        barrier.AccessAfter = D3D12_BARRIER_ACCESS_SHADER_RESOURCE;\n        // UAV access must be paired with D3D12_BARRIER_LAYOUT_QUEUE_UNORDERED_ACCESS\n        barrier.LayoutBefore = directQueue ?\n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS :\n            D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS;\n        barrier.LayoutAfter = directQueue ?\n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE :\n            D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE;\n        barrier.Subresources.NumMipLevels = 0;\n        barrier.Subresources.IndexOrFirstMipLevel = subresource;\n        barrier.Flags = D3D12_TEXTURE_BARRIER_FLAG_NONE;\n\n        return barrier;\n    }    \n    \n    inline D3D12_TEXTURE_BARRIER TextureBarrier_UavToSrvWithSync(ID3D12Resource* res,\n        bool directQueue = true,\n        UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES)\n    {\n        D3D12_BARRIER_SUBRESOURCE_RANGE range;\n        range.NumMipLevels = 0;\n        range.IndexOrFirstMipLevel = subresource;\n\n        D3D12_TEXTURE_BARRIER barrier;\n        barrier.pResource = res;\n        barrier.SyncBefore = D3D12_BARRIER_SYNC_COMPUTE_SHADING;\n        barrier.SyncAfter = D3D12_BARRIER_SYNC_COMPUTE_SHADING;\n        barrier.AccessBefore = D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;\n        barrier.AccessAfter = D3D12_BARRIER_ACCESS_SHADER_RESOURCE;\n        // UAV access must be paired with D3D12_BARRIER_LAYOUT_QUEUE_UNORDERED_ACCESS\n        barrier.LayoutBefore = directQueue ?\n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS :\n            D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS;\n        barrier.LayoutAfter = directQueue ?\n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE :\n            D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE;\n        barrier.Subresources.NumMipLevels = 0;\n        barrier.Subresources.IndexOrFirstMipLevel = subresource;\n        barrier.Flags = D3D12_TEXTURE_BARRIER_FLAG_NONE;\n\n        return barrier;\n    }\n\n    inline D3D12_TEXTURE_BARRIER UAVBarrier1(ID3D12Resource* res,\n        bool directQueue = true,\n        UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES)\n    {\n        D3D12_BARRIER_SUBRESOURCE_RANGE range;\n        range.NumMipLevels = 0;\n        range.IndexOrFirstMipLevel = subresource;\n\n        D3D12_TEXTURE_BARRIER barrier;\n        barrier.pResource = res;\n        barrier.SyncBefore = D3D12_BARRIER_SYNC_COMPUTE_SHADING;\n        barrier.SyncAfter = D3D12_BARRIER_SYNC_COMPUTE_SHADING;\n        barrier.AccessBefore = D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;\n        barrier.AccessAfter = D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;\n        barrier.LayoutBefore = directQueue ?\n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS :\n            D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS;\n        barrier.LayoutAfter = directQueue ?\n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS :\n            D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS;\n        barrier.Subresources.NumMipLevels = 0;\n        barrier.Subresources.IndexOrFirstMipLevel = subresource;\n        barrier.Flags = D3D12_TEXTURE_BARRIER_FLAG_NONE;\n\n        return barrier;\n    }\n\n    // Return the BPP for a particular format\n    size_t BitsPerPixel(DXGI_FORMAT fmt);\n\n    // Get surface information for a particular format\n    HRESULT GetSurfaceInfo(size_t width,\n        size_t height,\n        DXGI_FORMAT fmt,\n        size_t* outNumBytes,\n        size_t* outRowBytes,\n        size_t* outNumRows);\n\n    // Returns required size of a buffer to be used for data upload\n    UINT64 GetRequiredIntermediateSize(ID3D12Resource* destinationResource, UINT firstSubresource,\n        UINT numSubresources);\n\n    inline D3D12_BLEND_DESC DefaultBlendDesc()\n    {\n        D3D12_BLEND_DESC desc{};\n        desc.AlphaToCoverageEnable = false;\n        desc.IndependentBlendEnable = false;\n\n        D3D12_RENDER_TARGET_BLEND_DESC rtBlendDesc{};\n        rtBlendDesc.BlendEnable = false;\n        rtBlendDesc.LogicOpEnable = false;\n        rtBlendDesc.SrcBlend = D3D12_BLEND_ONE;\n        rtBlendDesc.DestBlend = D3D12_BLEND_ZERO;\n        rtBlendDesc.BlendOp = D3D12_BLEND_OP_ADD;\n        rtBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE;\n        rtBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO;\n        rtBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_ADD;\n        rtBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP;\n        rtBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;\n\n        for (int i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)\n            desc.RenderTarget[i] = rtBlendDesc;\n\n        return desc;\n    }\n\n    inline D3D12_RASTERIZER_DESC DefaultRasterizerDesc()\n    {\n        D3D12_RASTERIZER_DESC desc{};\n\n        desc.FillMode = D3D12_FILL_MODE_SOLID;\n        desc.CullMode = D3D12_CULL_MODE_BACK;\n        desc.FrontCounterClockwise = false;\n        desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;\n        desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;\n        desc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;\n        desc.DepthClipEnable = true;\n        desc.MultisampleEnable = false;\n        desc.AntialiasedLineEnable = false;\n        desc.ForcedSampleCount = 0;\n        desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;\n\n        return desc;\n    }\n\n    inline D3D12_DEPTH_STENCIL_DESC DefaultDepthStencilDesc()\n    {\n        D3D12_DEPTH_STENCIL_DESC desc{};\n        desc.DepthEnable = true;\n        desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;\n        desc.DepthFunc = D3D12_COMPARISON_FUNC_LESS;\n        desc.StencilEnable = false;\n        desc.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;\n        desc.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;\n\n        D3D12_DEPTH_STENCILOP_DESC defaultStencilOp{};\n        defaultStencilOp.StencilFailOp = D3D12_STENCIL_OP_KEEP;\n        defaultStencilOp.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;\n        defaultStencilOp.StencilPassOp = D3D12_STENCIL_OP_KEEP;\n        defaultStencilOp.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;\n\n        desc.FrontFace = defaultStencilOp;\n        desc.BackFace = defaultStencilOp;\n\n        return desc;\n    }\n\n    inline constexpr DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt)\n    {\n        switch (fmt)\n        {\n        case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n            return DXGI_FORMAT_R8G8B8A8_UNORM;\n        case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n            return DXGI_FORMAT_B8G8R8A8_UNORM;\n        case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n            return DXGI_FORMAT_B8G8R8X8_UNORM;\n        default:\n            return fmt;\n        }\n    }\n\n    LOAD_DDS_RESULT LoadDDSFromFile(const char* path,\n        Util::MutableSpan<D3D12_SUBRESOURCE_DATA> subresources,\n        DXGI_FORMAT& format,\n        Support::ArenaAllocator allocator,\n        uint32_t& width,\n        uint32_t& height,\n        uint32_t& depth,\n        uint16_t& mipCount,\n        uint32_t& numSubresources);\n\n    D3D12_GRAPHICS_PIPELINE_STATE_DESC GetPSODesc(const D3D12_INPUT_LAYOUT_DESC* inputLayout,\n        int numRenderTargets,\n        DXGI_FORMAT* rtvFormats,\n        DXGI_FORMAT dsvFormat = DXGI_FORMAT_UNKNOWN,\n        D3D12_DEPTH_STENCIL_DESC* depthStencilDesc = nullptr,\n        D3D12_RASTERIZER_DESC* rasterizerDesc = nullptr,\n        D3D12_BLEND_DESC* blendDesc = nullptr,\n        D3D12_PRIMITIVE_TOPOLOGY_TYPE primitiveTopology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);\n\n    uint64_t GetPSODescHash(D3D12_GRAPHICS_PIPELINE_STATE_DESC& desc);\n\n    void CreateGraphicsPSO(D3D12_GRAPHICS_PIPELINE_STATE_DESC& psDesc,\n        ID3D12RootSignature* rootSignature,\n        const D3D12_SHADER_BYTECODE* vertexShader,\n        const D3D12_SHADER_BYTECODE* pixelShader,\n        const D3D12_SHADER_BYTECODE* hullShader,\n        const D3D12_SHADER_BYTECODE* domainShader,\n        ID3D12PipelineState** pPipelineState);\n\n    void CreateBufferSRV(const GpuMemory::Buffer& buff, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,\n        UINT stride, UINT numElements);\n    void CreateBufferUAV(const GpuMemory::Buffer& buff, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,\n        UINT stride, UINT numElements);\n    void CreateRawBufferUAV(const GpuMemory::Buffer& buff, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle,\n        UINT stride, UINT numElements);\n    void CreateTexture2DSRV(ID3D12Resource* t, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n        DXGI_FORMAT f = DXGI_FORMAT_UNKNOWN, float minLODClamp = 0.0f, \n        UINT mostDetailedMip = 0, UINT planeSlice = 0);\n    void CreateTexture2DSRV(const GpuMemory::Texture& t, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n        DXGI_FORMAT f = DXGI_FORMAT_UNKNOWN, float minLODClamp = 0.0f, \n        UINT mostDetailedMip = 0, UINT planeSlice = 0);\n    void CreateTexture3DSRV(const GpuMemory::Texture& t, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n        DXGI_FORMAT f = DXGI_FORMAT_UNKNOWN, float minLODClamp = 0.0f, UINT mostDetailedMip = 0, \n        UINT planeSlice = 0);\n    void CreateTexture2DUAV(const GpuMemory::Texture& t, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n        DXGI_FORMAT f = DXGI_FORMAT_UNKNOWN, UINT mipSlice = 0, UINT planeSlice = 0);\n    void CreateTexture3DUAV(const GpuMemory::Texture& t, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n        DXGI_FORMAT f = DXGI_FORMAT_UNKNOWN, UINT mipSlice = 0, UINT numSlices = 0, \n        UINT firstSliceIdx = 0);\n    void CreateRTV(const GpuMemory::Texture& t, D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle, \n        DXGI_FORMAT f = DXGI_FORMAT_UNKNOWN, UINT mipSlice = 0, UINT planeSlice = 0);\n}"
  },
  {
    "path": "Source/ZetaCore/Core/GpuMemory.cpp",
    "content": "#include \"../App/Timer.h\"\n#include \"RendererCore.h\"\n#include \"CommandList.h\"\n#include \"../Support/Task.h\"\n#include \"../App/Filesystem.h\"\n#include \"../Utility/Utility.h\"\n#include <thread>\n#include <algorithm>\n#include <bit>\n#include <xxHash/xxhash.h>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::App;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Core::Direct3DUtil;\nusing namespace ZetaRay::Core::GpuMemory;\n\nnamespace\n{\n    //--------------------------------------------------------------------------------------\n    // ResourceUploadBatch\n    //--------------------------------------------------------------------------------------\n\n    struct ResourceUploadBatch\n    {\n        ResourceUploadBatch()\n            : m_arena(4 * 1096),\n            m_scratchResources(m_arena)\n        {}\n        ~ResourceUploadBatch() = default;\n\n        ResourceUploadBatch(ResourceUploadBatch&& other) = delete;\n        ResourceUploadBatch& operator=(ResourceUploadBatch&& other) = delete;\n\n        void Begin()\n        {\n            Assert(!m_inBeginEndBlock, \"Can't Begin: already in a Begin-End block.\");\n            m_inBeginEndBlock = true;\n            m_hasWorkThisFrame = false;\n        }\n\n        // Works by:\n        // 1. Allocates an intermediate upload heap buffer whose size is calculated by \n        //    GetCopyableFootprints()\n        // 2. Maps the intermediate buffer\n        // 3. Copies all subresources to upload heap buffer\n        // 4. Records a CopyTextureRegion call to default heap texture for each subresource on \n        //    the command list\n        void UploadTexture(UploadHeapArena& arena, ID3D12Resource* texture, \n            Span<D3D12_SUBRESOURCE_DATA> subResData,\n            int firstSubresourceIndex = 0, \n            D3D12_RESOURCE_STATES postCopyState = D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE)\n        {\n            Assert(m_inBeginEndBlock, \"Not in begin-end block.\");\n            Assert(texture, \"Texture was NULL.\");\n\n            if (!m_directCmdList)\n            {\n                m_directCmdList = App::GetRenderer().GetGraphicsCmdList();\n#ifndef NDEBUG\n                m_directCmdList->SetName(\"ResourceUploadBatch\");\n#endif\n            }\n\n            constexpr int MAX_NUM_SUBRESOURCES = 13;\n            Assert(MAX_NUM_SUBRESOURCES >= subResData.size(), \n                \"MAX_NUM_SUBRESOURCES is too small.\");\n\n            D3D12_PLACED_SUBRESOURCE_FOOTPRINT subresLayout[MAX_NUM_SUBRESOURCES];\n            UINT subresNumRows[MAX_NUM_SUBRESOURCES];\n            UINT64 subresRowSize[MAX_NUM_SUBRESOURCES];\n\n            const auto destDesc = texture->GetDesc();\n            Assert(destDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER, \n                \"This function is for uploading textures.\");\n\n            // Required size of an intermediate buffer that is to be used to initialize \n            // this resource\n            UINT64 totalSize;\n            auto* device = App::GetRenderer().GetDevice();\n            device->GetCopyableFootprints(&destDesc,   // resource description\n                firstSubresourceIndex,                 // index of the first subresource\n                (uint32_t)subResData.size(),           // number of subresources\n                0,                                     // offset to the resource\n                subresLayout,                          // description and placement of each subresource\n                subresNumRows,                         // number of rows for each subresource\n                subresRowSize,                         // unpadded size of a row of each subresource\n                &totalSize);\n\n            const auto uploadBuffer = arena.SubAllocate((uint32_t)totalSize);\n\n            CopyTextureFromUploadBuffer(uploadBuffer.Res, uploadBuffer.Mapped, \n                uploadBuffer.Offset, texture, (uint32_t)subResData.size(), \n                firstSubresourceIndex, subResData, subresLayout, subresNumRows, \n                subresRowSize, postCopyState);\n\n            m_hasWorkThisFrame = true;\n        }\n\n        void UploadTexture(ID3D12Resource* texture, Span<D3D12_SUBRESOURCE_DATA> subResData, \n            int firstSubresourceIndex = 0,\n            D3D12_RESOURCE_STATES postCopyState = D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE)\n        {\n            Assert(m_inBeginEndBlock, \"Not in begin-end block.\");\n            Assert(texture, \"Texture was NULL.\");\n\n            if (!m_directCmdList)\n            {\n                m_directCmdList = App::GetRenderer().GetGraphicsCmdList();\n#ifndef NDEBUG\n                m_directCmdList->SetName(\"ResourceUploadBatch\");\n#endif\n            }\n\n            constexpr int MAX_NUM_SUBRESOURCES = 12;\n            Assert(MAX_NUM_SUBRESOURCES >= subResData.size(), \n                \"MAX_NUM_SUBRESOURCES is too small.\");\n\n            D3D12_PLACED_SUBRESOURCE_FOOTPRINT subresLayout[MAX_NUM_SUBRESOURCES];\n            UINT subresNumRows[MAX_NUM_SUBRESOURCES];\n            UINT64 subresRowSize[MAX_NUM_SUBRESOURCES];\n\n            const auto destDesc = texture->GetDesc();\n            Assert(destDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER, \n                \"This function is for uploading textures.\");\n\n            auto* device = App::GetRenderer().GetDevice();\n            UINT64 totalSize;\n            device->GetCopyableFootprints(&destDesc,    // resource description\n                firstSubresourceIndex,                  // index of the first subresource\n                (uint32_t)subResData.size(),            // number of subresources\n                0,                                      // offset to the resource\n                subresLayout,                           // description and placement of each subresource\n                subresNumRows,                          // number of rows for each subresource\n                subresRowSize,                          // unpadded size of a row of each subresource\n                &totalSize);\n\n            UploadHeapBuffer uploadBuffer = GpuMemory::GetUploadHeapBuffer((uint32_t)totalSize);\n\n            CopyTextureFromUploadBuffer(uploadBuffer.Resource(), \n                uploadBuffer.MappedMemory(), uploadBuffer.Offset(), texture, \n                (uint32_t)subResData.size(), firstSubresourceIndex, subResData, \n                subresLayout, subresNumRows, subresRowSize, postCopyState);\n\n            // Preserve the upload buffer for as long as GPU is using it \n            m_scratchResources.push_back(ZetaMove(uploadBuffer));\n\n            m_hasWorkThisFrame = true;\n        }\n\n        void UploadBuffer(ID3D12Resource* buffer, void* data, uint32_t sizeInBytes, \n            uint32_t destOffset = 0, bool forceSeparate = false)\n        {\n            Assert(m_inBeginEndBlock, \"Not in begin-end block.\");\n            Assert(buffer, \"Buffer was NULL.\");\n\n            if (!m_directCmdList)\n            {\n                m_directCmdList = App::GetRenderer().GetGraphicsCmdList();\n#ifndef NDEBUG\n                m_directCmdList->SetName(\"ResourceUploadBatch\");\n#endif\n            }\n\n            // Note: GetCopyableFootprints() returns the padded size for a standalone \n            // resource, here we might be suballocating from a larger buffer.\n            UploadHeapBuffer uploadBuffer = GpuMemory::GetUploadHeapBuffer(sizeInBytes, 4, forceSeparate);\n            uploadBuffer.Copy(0, sizeInBytes, data);\n\n            // Note: can't use CopyResource() since the UploadHeap might not have the \n            // exact same size as the destination resource due to subresource allocations.\n\n            m_directCmdList->CopyBufferRegion(buffer,\n                destOffset,\n                uploadBuffer.Resource(),\n                uploadBuffer.Offset(),\n                sizeInBytes);\n\n            // Preserve the upload buffer for as long as GPU is using it \n            m_scratchResources.push_back(ZetaMove(uploadBuffer));\n\n            m_hasWorkThisFrame = true;\n        }\n\n        void UploadTexture(ID3D12Resource* dstResource, uint8_t* pixels, \n            D3D12_RESOURCE_STATES postCopyState)\n        {\n            Assert(m_inBeginEndBlock, \"Not in begin-end block.\");\n\n            if (!m_directCmdList)\n            {\n                m_directCmdList = App::GetRenderer().GetGraphicsCmdList();\n#ifndef NDEBUG\n                m_directCmdList->SetName(\"ResourceUploadBatch\");\n#endif\n            }\n\n            const auto desc = dstResource->GetDesc();\n            Assert(desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D, \n                \"This function is for uploading 2D textures.\");\n\n            const uint32_t numBytesPerPixel = (uint32_t)Direct3DUtil::BitsPerPixel(desc.Format) >> 3;\n            const UINT rowSizeInBytes = (uint32_t)desc.Width * numBytesPerPixel;\n            const UINT rowPitch = Math::AlignUp(rowSizeInBytes, \n                (uint32_t)D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);\n            const UINT uploadSize = desc.Height * rowPitch;\n\n            UploadHeapBuffer uploadBuffer = GpuMemory::GetUploadHeapBuffer(uploadSize);\n\n            for (int y = 0; y < (int)desc.Height; y++)\n                uploadBuffer.Copy(y * rowPitch, rowSizeInBytes, pixels + y * rowSizeInBytes);\n\n            D3D12_TEXTURE_COPY_LOCATION srcLocation = {};\n            srcLocation.pResource = uploadBuffer.Resource();\n            srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;\n            srcLocation.PlacedFootprint.Offset = uploadBuffer.Offset();\n            srcLocation.PlacedFootprint.Footprint.Format = desc.Format;\n            srcLocation.PlacedFootprint.Footprint.Width = (UINT)desc.Width;\n            srcLocation.PlacedFootprint.Footprint.Height = (UINT)desc.Height;\n            srcLocation.PlacedFootprint.Footprint.Depth = 1;\n            srcLocation.PlacedFootprint.Footprint.RowPitch = rowPitch;\n\n            D3D12_TEXTURE_COPY_LOCATION dstLocation = {};\n            dstLocation.pResource = dstResource;\n            dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;\n            dstLocation.SubresourceIndex = 0;\n\n            m_directCmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, \n                nullptr);\n\n            if (postCopyState != D3D12_RESOURCE_STATE_COPY_DEST)\n            {\n                m_directCmdList->ResourceBarrier(dstResource, D3D12_RESOURCE_STATE_COPY_DEST, \n                    postCopyState);\n            }\n\n            // Preserve the upload buffer for as long as GPU is using it \n            m_scratchResources.push_back(ZetaMove(uploadBuffer));\n\n            m_hasWorkThisFrame = true;\n        }\n\n        // Submits all the uploads\n        // No more uploads can happen after this call until Begin is called again.\n        uint64_t End()\n        {\n            Assert(m_inBeginEndBlock, \"Not in begin-end block.\");\n            uint64_t ret = 0;\n\n            if (m_hasWorkThisFrame)\n            {\n                ret = App::GetRenderer().ExecuteCmdList(m_directCmdList);\n                m_directCmdList = nullptr;\n            }\n\n            m_inBeginEndBlock = false;\n\n            return ret;\n        }\n\n        void Recycle()\n        {\n            //m_scratchResources.free_memory();\n            //m_arena.Reset();\n            m_scratchResources.clear();\n        }\n\n    private:\n        void CopyTextureFromUploadBuffer(ID3D12Resource* uploadBuffer, void* mapped, \n            uint32_t uploadBuffOffsetInBytes, ID3D12Resource* texture, int numSubresources, \n            int firstSubresourceIndex, Span<D3D12_SUBRESOURCE_DATA> subResData, \n            Span<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> subresLayout, Span<UINT> subresNumRows, \n            Span<UINT64> subresRowSize, D3D12_RESOURCE_STATES postCopyState)\n        {\n            // Notes:\n            // \n            // 1.\n            //   subresRowSize[i]: #bytes to copy for each row (unpadded)\n            //   subresLayout[i].Footprint.RowPitch: padded size in bytes of each row\n            //\n            // 2. As buffers have a 64 KB alignment, GetCopyableFootprints() returns the padded \n            //    size. Using subresRowSize[0] as the copy size could lead to access violations \n            //    since size of the data pointed to by subresData is probably smaller.\n\n            // For each subresource in destination\n            for (int i = 0; i < numSubresources; i++)\n            {\n                size_t destOffset = subresLayout[i].Offset;\n                const size_t destSubresSlicePitch = subresLayout[i].Footprint.RowPitch * subresNumRows[i];\n\n                // For each slice of that subresource\n                for (int slice = 0; slice < (int)subresLayout[i].Footprint.Depth; slice++)\n                {\n                    const uintptr_t sourceSubres = reinterpret_cast<uintptr_t>(\n                        subResData[i].pData) + subResData[i].SlicePitch * slice;\n\n                    // For each row of that subresource slice\n                    for (int row = 0; row < (int)subresNumRows[i]; row++)\n                    {\n                        const uintptr_t dest = reinterpret_cast<uintptr_t>(mapped) +\n                            uploadBuffOffsetInBytes +\n                            destOffset +\n                            row * subresLayout[i].Footprint.RowPitch;\n\n                        const uintptr_t src = sourceSubres + subResData[i].RowPitch * row;\n\n                        memcpy(reinterpret_cast<void*>(dest),\n                            reinterpret_cast<void*>(src),\n                            subresRowSize[i]);\n                    }\n\n                    destOffset += destSubresSlicePitch;\n                }\n            }\n\n            for (int i = 0; i < numSubresources; i++)\n            {\n                D3D12_TEXTURE_COPY_LOCATION dst{};\n                dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;\n                dst.pResource = texture;\n                dst.SubresourceIndex = firstSubresourceIndex + i;\n\n                D3D12_TEXTURE_COPY_LOCATION src{};\n                src.pResource = uploadBuffer;\n                src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;\n                src.PlacedFootprint = subresLayout[i];\n                src.PlacedFootprint.Offset += uploadBuffOffsetInBytes;\n\n                m_directCmdList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);\n            }\n\n            if (postCopyState != D3D12_RESOURCE_STATE_COPY_DEST)\n            {\n                m_directCmdList->ResourceBarrier(texture, D3D12_RESOURCE_STATE_COPY_DEST, \n                    postCopyState);\n            }\n        }\n\n        // Scratch resources need to stay alive while GPU is using them\n        MemoryArena m_arena;\n        SmallVector<UploadHeapBuffer, Support::ArenaAllocator> m_scratchResources;\n\n        GraphicsCmdList* m_directCmdList = nullptr;\n        bool m_inBeginEndBlock = false;\n        bool m_hasWorkThisFrame = false;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // GpuMemoryImplData\n    //--------------------------------------------------------------------------------------\n\n    struct GpuMemoryImplData\n    {\n        // Requests are attempted to be suballocated from a shared upload heap of the following \n        // size. If unsuccessful, a new upload heap is created.\n        static constexpr uint32_t UPLOAD_HEAP_SIZE = uint32_t(9 * 1024 * 1024);\n        static constexpr uint32_t MAX_NUM_UPLOAD_HEAP_ALLOCS = 128;\n\n        struct PendingResource\n        {\n            ZetaInline bool IsUploadHeapBuffer() const\n            {\n                return !Allocation.IsEmpty();\n            }\n\n            ID3D12Pageable* Res;\n            uint64_t ReleaseFence;\n            void* MappedMemory = nullptr;\n            OffsetAllocator::Allocation Allocation = OffsetAllocator::Allocation::Empty();\n        };\n\n        OffsetAllocator m_uploadHeapAllocator;\n        ComPtr<ID3D12Resource> m_uploadHeap;\n        void* m_uploadHeapMapped;\n        SRWLOCK m_uploadHeapLock = SRWLOCK_INIT;\n\n        Util::SmallVector<PendingResource> m_toRelease;\n        SRWLOCK m_pendingResourceLock = SRWLOCK_INIT;\n\n        ComPtr<ID3D12Fence> m_fenceDirect;\n        ComPtr<ID3D12Fence> m_fenceCompute;\n        uint64_t m_nextFenceVal = 1;    // no need to be atomic\n\n        ResourceUploadBatch m_uploaders[MAX_NUM_THREADS];\n    };\n\n    GpuMemoryImplData* g_data = nullptr;\n}\n\n//--------------------------------------------------------------------------------------\n// UploadHeapBuffer\n//--------------------------------------------------------------------------------------\n\nUploadHeapBuffer::UploadHeapBuffer(ID3D12Resource* r, void* mapped, \n    const Support::OffsetAllocator::Allocation& alloc)\n    : m_resource(r),\n    m_mappedMemory(mapped),\n    m_allocation(alloc)\n{}\n\nUploadHeapBuffer::~UploadHeapBuffer()\n{\n    Reset();\n}\n\nUploadHeapBuffer::UploadHeapBuffer(UploadHeapBuffer&& other)\n    : m_resource(other.m_resource),\n    m_mappedMemory(other.m_mappedMemory),\n    m_allocation(other.m_allocation)\n{\n    other.m_resource = nullptr;\n    other.m_mappedMemory = nullptr;\n    other.m_allocation = OffsetAllocator::Allocation::Empty();\n}\n\nUploadHeapBuffer& UploadHeapBuffer::operator=(UploadHeapBuffer&& other)\n{\n    if (this == &other)\n        return *this;\n\n    Reset();\n\n    m_resource = other.m_resource;\n    m_mappedMemory = other.m_mappedMemory;\n    m_allocation = other.m_allocation;\n\n    other.m_resource = nullptr;\n    other.m_mappedMemory = nullptr;\n    other.m_allocation = OffsetAllocator::Allocation::Empty();\n\n    return *this;\n}\n\nvoid UploadHeapBuffer::Reset()\n{\n    if (m_resource)\n        GpuMemory::ReleaseUploadHeapBuffer(*this);\n\n    m_resource = nullptr;\n    m_mappedMemory = nullptr;\n    m_allocation = OffsetAllocator::Allocation::Empty();\n}\n\nvoid UploadHeapBuffer::Copy(uint32_t offset, uint32_t numBytesToCopy, void* data)\n{\n    Assert(offset + numBytesToCopy <= m_allocation.Size, \n        \"Copy destination region was out-of-bound.\");\n    memcpy(reinterpret_cast<uint8_t*>(m_mappedMemory) + m_allocation.Offset + offset, \n        data, numBytesToCopy);\n}\n\n//--------------------------------------------------------------------------------------\n// UploadHeapArena\n//--------------------------------------------------------------------------------------\n\nUploadHeapArena::UploadHeapArena(uint32_t sizeInBytes)\n    : m_size(Math::AlignUp(sizeInBytes, (uint32_t)D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT))\n{}\n\nUploadHeapArena::~UploadHeapArena()\n{\n    if (!m_blocks.empty())\n        GpuMemory::ReleaseUploadHeapArena(*this);\n}\n\nUploadHeapArena::UploadHeapArena(UploadHeapArena&& other)\n    : m_size(other.m_size)\n{\n    m_blocks.swap(other.m_blocks);\n    other.m_size = 0;\n}\n\nUploadHeapArena::Allocation UploadHeapArena::SubAllocate(uint32_t size, uint32_t alignment)\n{\n    Check(size <= m_size, \"allocations larger than %u MB are not supported.\", m_size / (1024 * 1024));\n\n    for (auto& block : m_blocks)\n    {\n        const uint32_t newOffset = (uint32_t)Math::AlignUp(block.Offset, alignment);\n\n        if (newOffset + size <= m_size)\n        {\n            block.Offset = newOffset + size;\n\n            return Allocation{ .Res = block.Res,\n                .Mapped = block.Mapped,\n                .Offset = newOffset };\n        }\n    }\n\n    D3D12_HEAP_PROPERTIES uploadHeap = Direct3DUtil::UploadHeapProp();\n    D3D12_RESOURCE_DESC bufferDesc = Direct3DUtil::BufferResourceDesc(m_size);\n\n    auto* device = App::GetRenderer().GetDevice();\n\n    ID3D12Resource* res;\n    CheckHR(device->CreateCommittedResource(&uploadHeap,\n        D3D12_HEAP_FLAG_CREATE_NOT_ZEROED,\n        &bufferDesc,\n        D3D12_RESOURCE_STATE_GENERIC_READ,\n        nullptr,\n        IID_PPV_ARGS(&res)));\n\n    SET_D3D_OBJ_NAME(res, \"UploadHeapArena\");\n\n    // From MS docs:\n    // \"Resources on D3D12_HEAP_TYPE_UPLOAD heaps can be persistently mapped, meaning Map \n    // can be called once, immediately after resource creation. Unmap never needs to be called, \n    // but the address returned from Map must no longer be used after the last reference to the \n    // resource is released. When using persistent map, the application must ensure the CPU finishes \n    // writing data into memory before the GPU executes a command list that reads the memory.\"\n    void* mapped;\n    CheckHR(res->Map(0, nullptr, &mapped));\n\n    Block newBlock{ .Res = res,\n        .Offset = size,\n        .Mapped = mapped };\n\n    m_blocks.push_front(ZetaMove(newBlock));\n\n    return Allocation{ .Res = res,\n        .Mapped = mapped };\n}\n\n//--------------------------------------------------------------------------------------\n// Buffer\n//--------------------------------------------------------------------------------------\n\nBuffer::Buffer(const char* p, ID3D12Resource* r, RESOURCE_HEAP_TYPE heapType)\n    : m_resource(r),\n    m_ID(XXH3_64_To_32(XXH3_64bits(p, strlen(p)))),\n    m_heapType(heapType)\n{\n    SET_D3D_OBJ_NAME(m_resource, p);\n}\n\nBuffer::~Buffer()\n{\n    Reset();\n}\n\nBuffer::Buffer(Buffer&& other)\n    : m_resource(other.m_resource),\n    m_ID(other.m_ID),\n    m_heapType(other.m_heapType)\n{\n    other.m_resource = nullptr;\n    other.m_ID = INVALID_ID;\n}\n\nBuffer& Buffer::operator=(Buffer&& other)\n{\n    if (this == &other)\n        return *this;\n\n    Reset();\n\n    m_resource = other.m_resource;\n    m_ID = other.m_ID;\n\n    other.m_resource = nullptr;\n    other.m_ID = INVALID_ID;\n    m_heapType = other.m_heapType;\n\n    return *this;\n}\n\nvoid Buffer::Reset(bool waitForGpu)\n{\n    if (m_resource)\n    {\n        if (waitForGpu && (m_heapType == RESOURCE_HEAP_TYPE::COMMITTED))\n            GpuMemory::ReleaseDefaultHeapBuffer(*this);\n        else\n        {\n            auto newRefCount = m_resource->Release();\n            Assert(newRefCount == 0, \"unexpected ref count -- expected 0, actual %u.\", \n                newRefCount);\n        }\n    }\n\n    m_ID = INVALID_ID;\n    m_resource = nullptr;\n}\n\n//--------------------------------------------------------------------------------------\n// ReadbackHeapBuffer\n//--------------------------------------------------------------------------------------\n\nReadbackHeapBuffer::ReadbackHeapBuffer(ID3D12Resource* r)\n    : m_resource(r)\n{}\n\nReadbackHeapBuffer::~ReadbackHeapBuffer()\n{\n    Reset();\n}\n\nReadbackHeapBuffer::ReadbackHeapBuffer(ReadbackHeapBuffer&& other)\n    : m_resource(std::exchange(other.m_resource, nullptr)),\n    m_mappedMemory(std::exchange(other.m_mappedMemory, nullptr))\n{}\n\nReadbackHeapBuffer& ReadbackHeapBuffer::operator=(ReadbackHeapBuffer&& other)\n{\n    if (this == &other)\n        return *this;\n\n    Reset();\n\n    m_resource = other.m_resource;\n    m_mappedMemory = other.m_mappedMemory;\n    other.m_mappedMemory = nullptr;\n    other.m_resource = nullptr;\n\n    return *this;\n}\n\nvoid ReadbackHeapBuffer::Reset(bool waitForGpu)\n{\n    if (m_resource)\n    {\n        if (waitForGpu)\n            GpuMemory::ReleaseReadbackHeapBuffer(*this);\n        else\n        {\n            auto newRefCount = m_resource->Release();\n            Assert(newRefCount == 0, \"unexpected ref count -- expected 0, actual %u.\", \n                newRefCount);\n        }\n    }\n\n    m_resource = nullptr;\n    m_mappedMemory = nullptr;\n}\n\nvoid ReadbackHeapBuffer::Map()\n{\n    if (m_mappedMemory)\n        return;\n\n    // Buffers have only one subresource\n    CheckHR(m_resource->Map(0, nullptr, &m_mappedMemory));\n}\n\nvoid ReadbackHeapBuffer::Unmap()\n{\n    if (!m_mappedMemory)\n        return;\n\n    m_resource->Unmap(0, nullptr);\n    m_mappedMemory = nullptr;\n}\n\n//--------------------------------------------------------------------------------------\n// Texture\n//--------------------------------------------------------------------------------------\n\nTexture::Texture(const char* name, ID3D12Resource* res, RESOURCE_HEAP_TYPE heapType)\n    : m_resource(res),\n    m_ID(XXH3_64_To_32(XXH3_64bits(name, strlen(name)))),\n    m_heapType(heapType)\n{\n    SET_D3D_OBJ_NAME(m_resource, name);\n}\n\nTexture::Texture(ID_TYPE id, ID3D12Resource* res, RESOURCE_HEAP_TYPE heapType,\n    const char* dbgName)\n    : m_resource(res),\n    m_ID(id),\n    m_heapType(heapType)\n{\n    Assert(id != INVALID_ID, \"Invalid ID.\");\n\n    if (m_resource)\n    {\n        StackStr(name, N, \"Tex2D_%u\", id);\n        SET_D3D_OBJ_NAME(m_resource, dbgName ? dbgName : name);\n    }\n}\n\nTexture::~Texture()\n{\n    Reset();\n}\n\nTexture::Texture(Texture&& other)\n    : m_resource(other.m_resource),\n    m_ID(other.m_ID),\n    m_heapType(other.m_heapType)\n{\n    other.m_resource = nullptr;\n    other.m_ID = INVALID_ID;\n}\n\nTexture& Texture::operator=(Texture&& other)\n{\n    if (this == &other)\n        return *this;\n\n    Reset();\n\n    m_resource = other.m_resource;\n    m_ID = other.m_ID;\n    m_heapType = other.m_heapType;\n\n    other.m_resource = nullptr;\n    other.m_ID = INVALID_ID;\n\n    return *this;\n}\n\nvoid Texture::Reset(bool waitForGpu, bool checkRefCount)\n{\n    if (m_resource)\n    {\n        if (waitForGpu && (m_heapType == RESOURCE_HEAP_TYPE::COMMITTED))\n            GpuMemory::ReleaseTexture(*this);\n        else\n        {\n            auto newRefCount = m_resource->Release();\n            Assert(!checkRefCount || newRefCount == 0, \"unexpected ref count -- expected 0, actual %u.\", \n                newRefCount);\n        }\n    }\n\n    m_resource = nullptr;\n    m_ID = INVALID_ID;\n}\n\n//--------------------------------------------------------------------------------------\n// ResourceHeap\n//--------------------------------------------------------------------------------------\n\nResourceHeap::ResourceHeap(ID3D12Heap* heap)\n    : m_heap(heap)\n{}\n\nResourceHeap::~ResourceHeap()\n{\n    Reset();\n}\n\nResourceHeap::ResourceHeap(ResourceHeap&& other)\n    : m_heap(other.m_heap)\n{\n    other.m_heap = nullptr;\n}\n\nResourceHeap& ResourceHeap::operator=(ResourceHeap&& other)\n{\n    if (this == &other)\n        return *this;\n\n    Reset();\n\n    m_heap = other.m_heap;\n    other.m_heap = nullptr;\n\n    return *this;\n}\n\nvoid ResourceHeap::Reset()\n{\n    if (m_heap)\n        GpuMemory::ReleaseResourceHeap(*this);\n\n    m_heap = nullptr;\n}\n\n//--------------------------------------------------------------------------------------\n// GpuMemory\n//--------------------------------------------------------------------------------------\n\nvoid GpuMemory::Init()\n{\n    Assert(!g_data, \"attempting to double initialize.\");\n    g_data = new GpuMemoryImplData;\n\n    g_data->m_uploadHeapAllocator.Init(GpuMemoryImplData::UPLOAD_HEAP_SIZE, \n        GpuMemoryImplData::MAX_NUM_UPLOAD_HEAP_ALLOCS);\n\n    D3D12_HEAP_PROPERTIES uploadHeap = Direct3DUtil::UploadHeapProp();\n    D3D12_RESOURCE_DESC bufferDesc = Direct3DUtil::BufferResourceDesc(\n        GpuMemoryImplData::UPLOAD_HEAP_SIZE);\n\n    auto* device = App::GetRenderer().GetDevice();\n    CheckHR(device->CreateCommittedResource(&uploadHeap,\n        D3D12_HEAP_FLAG_CREATE_NOT_ZEROED,\n        &bufferDesc,\n        D3D12_RESOURCE_STATE_GENERIC_READ,\n        nullptr,\n        IID_PPV_ARGS(g_data->m_uploadHeap.GetAddressOf())));\n\n    SET_D3D_OBJ_NAME(g_data->m_uploadHeap, \"UploadHeap\");\n    CheckHR(g_data->m_uploadHeap->Map(0, nullptr, &g_data->m_uploadHeapMapped));\n\n    CheckHR(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(\n        g_data->m_fenceDirect.GetAddressOf())));\n    CheckHR(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(\n        g_data->m_fenceCompute.GetAddressOf())));\n}\n\nvoid GpuMemory::BeginFrame()\n{\n    const int numThreads = App::GetNumWorkerThreads();\n\n    for (int i = 0; i < numThreads; i++)\n        g_data->m_uploaders[i].Begin();\n}\n\nvoid GpuMemory::SubmitResourceCopies()\n{\n    const int numThreads = App::GetNumWorkerThreads();\n    uint64_t maxFenceVal = 0;\n\n    for (int i = 0; i < numThreads; i++)\n    {\n        auto f = g_data->m_uploaders[i].End();\n        maxFenceVal = Math::Max(maxFenceVal, f);\n    }\n\n    if (maxFenceVal != 0)\n    {\n        // Compute queue needs to wait for direct queue\n        App::GetRenderer().WaitForDirectQueueOnComputeQueue(maxFenceVal);\n    }\n}\n\nvoid GpuMemory::Recycle()\n{\n    auto& renderer = App::GetRenderer();\n    renderer.SignalDirectQueue(g_data->m_fenceDirect.Get(), g_data->m_nextFenceVal);\n    renderer.SignalComputeQueue(g_data->m_fenceCompute.Get(), g_data->m_nextFenceVal);\n\n    for (int i = 0; i < App::GetNumWorkerThreads(); i++)\n        g_data->m_uploaders[i].Recycle();\n\n    const uint64_t completedFenceValDir = g_data->m_fenceDirect->GetCompletedValue();\n    const uint64_t completedFenceValCompute = g_data->m_fenceCompute->GetCompletedValue();\n\n    SmallVector<GpuMemoryImplData::PendingResource> toDelete;\n\n    {\n        const auto* first = std::partition(g_data->m_toRelease.begin(), g_data->m_toRelease.end(),\n            [completedFenceValDir, completedFenceValCompute](const GpuMemoryImplData::PendingResource& res)\n            {\n                return res.ReleaseFence > completedFenceValDir || \n                    res.ReleaseFence > completedFenceValCompute;\n            });\n\n        const auto numToDelete = g_data->m_toRelease.end() - first;\n        toDelete.append_range(first, g_data->m_toRelease.end(), true);\n        g_data->m_toRelease.pop_back(numToDelete);\n    }\n\n    // No need to synchronize -- this happens at the end of each frame and resource deletion\n    // won't happen until next frame's update, which happens strictly after recycling has finished\n\n    {\n        // Release the upload heap buffers here rather than on a background thread with the others\n        // to avoid synchronization\n        const auto* first = std::partition(toDelete.begin(), toDelete.end(),\n            [](const GpuMemoryImplData::PendingResource& res)\n            {\n                return !res.IsUploadHeapBuffer();\n            });\n\n        const auto numUploadBuffers = toDelete.end() - first;\n\n        for (auto it = first; it < toDelete.end(); it++)\n        {\n            Assert(!it->Allocation.IsEmpty(), \"unexpected result.\");\n            Assert(it->MappedMemory == g_data->m_uploadHeapMapped, \"unexpected result.\");\n            g_data->m_uploadHeapAllocator.Free(it->Allocation);\n        }\n\n        toDelete.pop_back(numUploadBuffers);\n    }\n\n    if (!toDelete.empty())\n    {\n        Task t(\"Releasing resources\", TASK_PRIORITY::BACKGROUND, [ToDelete = ZetaMove(toDelete)]()\n            {\n                for (auto& r : ToDelete)\n                {\n                    Assert(r.Res, \"unexpected - attempting to release null resource.\");\n                    Assert(!r.IsUploadHeapBuffer(), \n                        \"unexpected - small upload heap buffers shouldn't be released on a background thread.\");\n\n                    if (r.MappedMemory)\n                        static_cast<ID3D12Resource*>(r.Res)->Unmap(0, nullptr);\n\n                    auto newRefCount = r.Res->Release();\n                    Assert(newRefCount == 0, \"unexpected ref count -- expected 0, actual %u.\", \n                        newRefCount);\n                }\n            });\n\n        App::SubmitBackground(ZetaMove(t));\n    }\n\n    g_data->m_nextFenceVal++;\n}\n\nvoid GpuMemory::Shutdown()\n{\n    Assert(g_data, \"g_data shouldn't be null.\");\n    delete g_data;\n    g_data = nullptr;\n}\n\nUploadHeapBuffer GpuMemory::GetUploadHeapBuffer(uint32_t sizeInBytes, uint32_t alignment, \n    bool forceSeparate)\n{\n    if (!forceSeparate && sizeInBytes <= GpuMemoryImplData::UPLOAD_HEAP_SIZE)\n    {\n        AcquireSRWLockExclusive(&g_data->m_uploadHeapLock);\n        const auto alloc = g_data->m_uploadHeapAllocator.Allocate(sizeInBytes, alignment);\n        ReleaseSRWLockExclusive(&g_data->m_uploadHeapLock);\n\n        if (alloc.IsEmpty())\n        {\n            StackStr(msg, n, \n                \"Failed to allocate %u MB from the shared upload heap - creating a separate allocation...\",\n                sizeInBytes / (1024 * 1024));\n            App::Log(msg, LogMessage::MsgType::WARNING);\n\n            return GetUploadHeapBuffer(sizeInBytes, alignment, true);\n        }\n\n        return UploadHeapBuffer(g_data->m_uploadHeap.Get(),\n            g_data->m_uploadHeapMapped,\n            alloc);\n    }\n    else\n    {\n        D3D12_HEAP_PROPERTIES uploadHeap = Direct3DUtil::UploadHeapProp();\n        const uint32_t alignedSize = Math::AlignUp(sizeInBytes, \n            (uint32_t)D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);\n        D3D12_RESOURCE_DESC bufferDesc = Direct3DUtil::BufferResourceDesc(alignedSize);\n\n        auto* device = App::GetRenderer().GetDevice();\n        ID3D12Resource* buffer;\n        CheckHR(device->CreateCommittedResource(&uploadHeap,\n            D3D12_HEAP_FLAG_CREATE_NOT_ZEROED,\n            &bufferDesc,\n            D3D12_RESOURCE_STATE_GENERIC_READ,\n            nullptr,\n            IID_PPV_ARGS(&buffer)));\n\n        SET_D3D_OBJ_NAME(buffer, \"UploadHeap\");\n\n        void* mapped;\n        CheckHR(buffer->Map(0, nullptr, &mapped));\n\n        OffsetAllocator::Allocation alloc = OffsetAllocator::Allocation::Empty();\n        alloc.Size = alignedSize;\n\n        return UploadHeapBuffer(buffer, mapped, alloc);\n    }\n}\n\nvoid GpuMemory::ReleaseUploadHeapBuffer(UploadHeapBuffer& buffer)\n{\n    Assert(g_data, \"Releasing GPU resources when GPU memory system has shut down.\");\n\n    AcquireSRWLockExclusive(&g_data->m_pendingResourceLock);\n\n    g_data->m_toRelease.emplace_back(\n        GpuMemoryImplData::PendingResource{ .Res = buffer.Resource(),\n            .ReleaseFence = g_data->m_nextFenceVal,\n            .MappedMemory = buffer.MappedMemory(),\n            .Allocation = buffer.Allocation() });\n\n    ReleaseSRWLockExclusive(&g_data->m_pendingResourceLock);\n}\n\nvoid GpuMemory::ReleaseUploadHeapArena(UploadHeapArena& arena)\n{\n    Assert(g_data, \"Releasing GPU resources when GPU memory system has shut down.\");\n\n    auto blocks = arena.Blocks();\n\n    if (blocks.empty())\n        return;\n\n    AcquireSRWLockExclusive(&g_data->m_pendingResourceLock);\n\n    for (auto& block : blocks)\n    {\n        Assert(block.Mapped, \"Mapped memory can't be NULL.\");\n\n        g_data->m_toRelease.emplace_back(\n            GpuMemoryImplData::PendingResource{ .Res = block.Res,\n                .ReleaseFence = g_data->m_nextFenceVal,\n                .MappedMemory = block.Mapped });\n    }\n\n    ReleaseSRWLockExclusive(&g_data->m_pendingResourceLock);\n}\n\nReadbackHeapBuffer GpuMemory::GetReadbackHeapBuffer(uint32_t sizeInBytes)\n{\n    auto* device = App::GetRenderer().GetDevice();\n\n    D3D12_HEAP_PROPERTIES readbackHeap = Direct3DUtil::ReadbackHeapProp();\n    D3D12_RESOURCE_DESC desc = Direct3DUtil::BufferResourceDesc(sizeInBytes);\n\n    ID3D12Resource* buffer;\n\n    CheckHR(device->CreateCommittedResource(&readbackHeap, D3D12_HEAP_FLAG_NONE,\n        &desc, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&buffer)));\n\n#ifndef NDEBUG\n    buffer->SetName(L\"Readback\");\n#endif\n\n    return ReadbackHeapBuffer(buffer);\n}\n\nvoid GpuMemory::ReleaseReadbackHeapBuffer(ReadbackHeapBuffer& buffer)\n{\n    Assert(g_data, \"Releasing GPU resources when GPU memory system has shut down.\");\n    Assert(buffer.IsInitialized() || !buffer.IsMapped(), \n        \"Non-null mapped memory for null resource.\");\n\n    AcquireSRWLockExclusive(&g_data->m_pendingResourceLock);\n\n    g_data->m_toRelease.emplace_back(\n        GpuMemoryImplData::PendingResource{ .Res = buffer.Resource(),\n            .ReleaseFence = g_data->m_nextFenceVal,\n            .MappedMemory = buffer.MappedMemory() });\n\n    ReleaseSRWLockExclusive(&g_data->m_pendingResourceLock);\n}\n\nBuffer GpuMemory::GetDefaultHeapBuffer(const char* name, uint32_t sizeInBytes,\n    D3D12_RESOURCE_STATES initState, bool allowUAV, bool initToZero)\n{\n    const D3D12_RESOURCE_FLAGS f = allowUAV ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : \n        D3D12_RESOURCE_FLAG_NONE;\n\n    const D3D12_HEAP_PROPERTIES heapDesc = Direct3DUtil::DefaultHeapProp();\n    const D3D12_RESOURCE_DESC bufferDesc = Direct3DUtil::BufferResourceDesc(sizeInBytes, f);\n\n    D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;\n    if (!initToZero)\n        heapFlags = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;\n\n    auto* device = App::GetRenderer().GetDevice();\n    ID3D12Resource* r;\n    CheckHR(device->CreateCommittedResource(&heapDesc,\n        heapFlags,\n        &bufferDesc,\n        initState,\n        nullptr,\n        IID_PPV_ARGS(&r)));\n\n    return Buffer(name, r, RESOURCE_HEAP_TYPE::COMMITTED);\n}\n\nBuffer GpuMemory::GetDefaultHeapBuffer(const char* name, uint32_t sizeInBytes,\n    bool isRtAs, bool allowUAV, bool initToZero)\n{\n    D3D12_RESOURCE_FLAGS f = allowUAV ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : \n        D3D12_RESOURCE_FLAG_NONE;\n    if (isRtAs)\n        f |= D3D12_RESOURCE_FLAG_RAYTRACING_ACCELERATION_STRUCTURE;\n\n    const D3D12_HEAP_PROPERTIES heapDesc = Direct3DUtil::DefaultHeapProp();\n    const D3D12_RESOURCE_DESC1 bufferDesc = Direct3DUtil::BufferResourceDesc1(sizeInBytes, f);\n\n    D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;\n    if (!initToZero)\n        heapFlags = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;\n\n    auto* device = App::GetRenderer().GetDevice();\n    ID3D12Resource* r;\n    CheckHR(device->CreateCommittedResource3(&heapDesc,\n        heapFlags,\n        &bufferDesc,\n        D3D12_BARRIER_LAYOUT_UNDEFINED,\n        nullptr,\n        nullptr,\n        0,\n        nullptr,\n        IID_PPV_ARGS(&r)));\n\n    return Buffer(name, r, RESOURCE_HEAP_TYPE::COMMITTED);\n}\n\nBuffer GpuMemory::GetPlacedHeapBuffer(const char* name, uint32_t sizeInBytes, ID3D12Heap* heap,\n    uint64_t offsetInBytes, bool allowUAV, bool isRtAs)\n{\n    D3D12_RESOURCE_FLAGS f = allowUAV ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : \n        D3D12_RESOURCE_FLAG_NONE;\n    if (isRtAs)\n        f |= D3D12_RESOURCE_FLAG_RAYTRACING_ACCELERATION_STRUCTURE;\n    const D3D12_RESOURCE_DESC1 bufferDesc = Direct3DUtil::BufferResourceDesc1(sizeInBytes, f);\n\n    auto* device = App::GetRenderer().GetDevice();\n    ID3D12Resource* r;\n    CheckHR(device->CreatePlacedResource2(heap,\n        offsetInBytes,\n        &bufferDesc,\n        D3D12_BARRIER_LAYOUT_UNDEFINED,\n        nullptr,\n        0,\n        nullptr,\n        IID_PPV_ARGS(&r)));\n\n    return Buffer(name, r, RESOURCE_HEAP_TYPE::PLACED);\n}\n\nBuffer GpuMemory::GetDefaultHeapBufferAndInit(const char* name, uint32_t sizeInBytes, \n    bool allowUAV, MemoryRegion initData, bool forceSeparateUploadBuffer)\n{\n    Assert(initData.SizeInBytes <= sizeInBytes, \"Size of initialization data exceeded resource size.\");\n\n    auto buffer = GpuMemory::GetDefaultHeapBuffer(name,\n        sizeInBytes,\n        D3D12_RESOURCE_STATE_COMMON,\n        allowUAV,\n        false);\n\n    g_data->m_uploaders[g_threadIdx].UploadBuffer(buffer.Resource(), initData.Data,\n        (uint32)initData.SizeInBytes, 0, forceSeparateUploadBuffer);\n\n    return buffer;\n}\n\nBuffer GpuMemory::GetPlacedHeapBufferAndInit(const char* name, uint32_t sizeInBytes, \n    ID3D12Heap* heap, uint64_t offsetInBytes, bool allowUAV, MemoryRegion initData, \n    bool forceSeparateUploadBuffer)\n{\n    Assert(initData.SizeInBytes <= sizeInBytes, \"Size of initialization data exceeded resource size.\");\n\n    auto buffer = GpuMemory::GetPlacedHeapBuffer(name,\n        sizeInBytes,\n        heap,\n        offsetInBytes,\n        allowUAV,\n        false);\n\n    g_data->m_uploaders[g_threadIdx].UploadBuffer(buffer.Resource(), initData.Data,\n        (uint32)initData.SizeInBytes, 0, forceSeparateUploadBuffer);\n\n    return buffer;\n}\n\nvoid GpuMemory::UploadToDefaultHeapBuffer(Buffer& buffer, uint32_t sizeInBytes, \n    MemoryRegion sourceData, uint32_t destOffsetInBytes)\n{\n    Assert(sourceData.SizeInBytes >= sizeInBytes, \"Out-of-bound memory access of source data.\");\n\n    g_data->m_uploaders[g_threadIdx].UploadBuffer(buffer.Resource(), sourceData.Data, sizeInBytes,\n        destOffsetInBytes);\n}\n\nResourceHeap GpuMemory::GetResourceHeap(uint64_t sizeInBytes, uint64_t alignment, \n    bool createZeroed)\n{\n    D3D12_HEAP_DESC heapDesc;\n    heapDesc.SizeInBytes = Math::AlignUp(sizeInBytes, alignment);\n    heapDesc.Alignment = alignment;\n    heapDesc.Properties = Direct3DUtil::DefaultHeapProp();\n    heapDesc.Flags = !createZeroed ? D3D12_HEAP_FLAG_CREATE_NOT_ZEROED : D3D12_HEAP_FLAG_NONE;\n\n    ID3D12Heap* heap;\n    auto* device = App::GetRenderer().GetDevice();\n    CheckHR(device->CreateHeap(&heapDesc, IID_PPV_ARGS(&heap)));\n\n    return ResourceHeap(heap);\n}\n\nvoid GpuMemory::ReleaseDefaultHeapBuffer(Buffer& buffer)\n{\n    Assert(g_data, \"Releasing GPU resources when GPU memory system has shut down.\");\n\n    AcquireSRWLockExclusive(&g_data->m_pendingResourceLock);\n\n    g_data->m_toRelease.emplace_back(\n        GpuMemoryImplData::PendingResource{ .Res = buffer.Resource(),\n            .ReleaseFence = g_data->m_nextFenceVal });\n\n    ReleaseSRWLockExclusive(&g_data->m_pendingResourceLock);\n}\n\nvoid GpuMemory::ReleaseTexture(Texture& texture)\n{\n    Assert(g_data, \"Releasing GPU resources when GPU memory system has shut down.\");\n\n    AcquireSRWLockExclusive(&g_data->m_pendingResourceLock);\n\n    g_data->m_toRelease.emplace_back(\n        GpuMemoryImplData::PendingResource{ .Res = texture.Resource(),\n            .ReleaseFence = g_data->m_nextFenceVal });\n\n    ReleaseSRWLockExclusive(&g_data->m_pendingResourceLock);\n}\n\nvoid GpuMemory::ReleaseResourceHeap(ResourceHeap& heap)\n{\n    Assert(g_data, \"Releasing GPU resources when GPU memory system has shut down.\");\n\n    AcquireSRWLockExclusive(&g_data->m_pendingResourceLock);\n\n    g_data->m_toRelease.emplace_back(\n        GpuMemoryImplData::PendingResource{ .Res = heap.Heap(),\n            .ReleaseFence = g_data->m_nextFenceVal });\n\n    ReleaseSRWLockExclusive(&g_data->m_pendingResourceLock);\n}\n\nTexture GpuMemory::GetTexture2D(const char* name, uint64_t width, uint32_t height, DXGI_FORMAT format,\n    D3D12_RESOURCE_STATES initialState, uint32_t flags, uint16_t mipLevels, D3D12_CLEAR_VALUE* clearVal)\n{\n    Texture::ID_TYPE id = XXH3_64_To_32(XXH3_64bits(name, strlen(name)));\n    return GetTexture2D(id, width, height, format, initialState, flags, mipLevels, clearVal, name);\n}\n\nTexture GpuMemory::GetTexture2D(Texture::ID_TYPE id, uint64_t width, uint32_t height, DXGI_FORMAT format,\n    D3D12_RESOURCE_STATES initialState, uint32_t flags, uint16_t mipLevels, D3D12_CLEAR_VALUE* clearVal,\n    const char* dbgName)\n{\n    Assert(width < D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION, \"Invalid width.\");\n    Assert(height < D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION, \"Invalid height.\");\n    Assert(mipLevels <= D3D12_REQ_MIP_LEVELS, \"Invalid number of mip levels.\");\n    Assert(((flags & TEXTURE_FLAGS::ALLOW_RENDER_TARGET) & (flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL)) == 0,\n        \"Texture can't be used as both Render Target and Depth Stencil.\");\n    Assert(((flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL) & (flags & TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS)) == 0,\n        \"A Depth-Stencil texture can't be used for unordered access.\");\n\n    D3D12_RESOURCE_FLAGS resFlags = D3D12_RESOURCE_FLAG_NONE;\n\n    if (flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL & ~D3D12_RESOURCE_FLAG_NONE);\n    if (flags & TEXTURE_FLAGS::ALLOW_RENDER_TARGET)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET & ~D3D12_RESOURCE_FLAG_NONE);\n    if (flags & TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS & ~D3D12_RESOURCE_FLAG_NONE);\n\n    D3D12_HEAP_PROPERTIES defaultHeap = Direct3DUtil::DefaultHeapProp();\n    D3D12_RESOURCE_DESC desc = Direct3DUtil::Tex2D(format, width, height, 1, mipLevels, resFlags);\n\n    D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;\n    if ((flags & TEXTURE_FLAGS::INIT_TO_ZERO) == 0)\n        heapFlags = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;\n\n    auto* device = App::GetRenderer().GetDevice();\n    ID3D12Resource* texture;\n    CheckHR(device->CreateCommittedResource(&defaultHeap,\n        heapFlags,\n        &desc,\n        initialState,\n        clearVal,\n        IID_PPV_ARGS(&texture)));\n\n    return Texture(id, texture, RESOURCE_HEAP_TYPE::COMMITTED, dbgName);\n}\n\nTexture GpuMemory::GetPlacedTexture2D(const char* name, uint64_t width, uint32_t height, \n    DXGI_FORMAT format, ID3D12Heap* heap, uint64_t offsetInBytes, D3D12_RESOURCE_STATES initialState, \n    uint32_t flags, uint16_t mipLevels, D3D12_CLEAR_VALUE* clearVal)\n{\n    Assert(width < D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION, \"Invalid width.\");\n    Assert(height < D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION, \"Invalid height.\");\n    Assert(mipLevels <= D3D12_REQ_MIP_LEVELS, \"Invalid number of mip levels.\");\n    Assert(((flags & TEXTURE_FLAGS::ALLOW_RENDER_TARGET) & (flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL)) == 0,\n        \"Texture can't be used as both Render Target and Depth Stencil.\");\n    Assert(((flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL) & (flags & TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS)) == 0,\n        \"A Depth-Stencil texture can't be used for unordered access.\");\n\n    D3D12_RESOURCE_FLAGS resFlags = D3D12_RESOURCE_FLAG_NONE;\n\n    if (flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL & ~D3D12_RESOURCE_FLAG_NONE);\n    if (flags & TEXTURE_FLAGS::ALLOW_RENDER_TARGET)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET & ~D3D12_RESOURCE_FLAG_NONE);\n    if (flags & TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS & ~D3D12_RESOURCE_FLAG_NONE);\n\n    D3D12_RESOURCE_DESC desc = Direct3DUtil::Tex2D(format, width, height, 1, mipLevels, resFlags);\n    ID3D12Resource* texture;\n    auto* device = App::GetRenderer().GetDevice();\n    CheckHR(device->CreatePlacedResource(heap,\n        offsetInBytes,\n        &desc,\n        initialState,\n        clearVal,\n        IID_PPV_ARGS(&texture)));\n\n    return Texture(name, texture, RESOURCE_HEAP_TYPE::PLACED);\n}\n\nTexture GpuMemory::GetPlacedTexture2D(const char* name, uint64_t width, uint32_t height,\n    DXGI_FORMAT format, ID3D12Heap* heap, uint64_t offsetInBytes, D3D12_BARRIER_LAYOUT initialLayout,\n    uint32_t flags, uint16_t mipLevels, D3D12_CLEAR_VALUE* clearVal)\n{\n    Assert(width < D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION, \"Invalid width.\");\n    Assert(height < D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION, \"Invalid height.\");\n    Assert(mipLevels <= D3D12_REQ_MIP_LEVELS, \"Invalid number of mip levels.\");\n    Assert(((flags & TEXTURE_FLAGS::ALLOW_RENDER_TARGET) & (flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL)) == 0,\n        \"Texture can't be used as both Render Target and Depth Stencil.\");\n    Assert(((flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL) & (flags & TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS)) == 0,\n        \"A Depth-Stencil texture can't be used for unordered access.\");\n\n    D3D12_RESOURCE_FLAGS resFlags = D3D12_RESOURCE_FLAG_NONE;\n\n    if (flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL & ~D3D12_RESOURCE_FLAG_NONE);\n    if (flags & TEXTURE_FLAGS::ALLOW_RENDER_TARGET)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET & ~D3D12_RESOURCE_FLAG_NONE);\n    if (flags & TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS & ~D3D12_RESOURCE_FLAG_NONE);\n\n    D3D12_RESOURCE_DESC1 desc = Direct3DUtil::Tex2D1(format, width, height, 1, mipLevels, resFlags);\n    ID3D12Resource* texture;\n    auto* device = App::GetRenderer().GetDevice();\n    CheckHR(device->CreatePlacedResource2(heap,\n        offsetInBytes,\n        &desc,\n        initialLayout,\n        clearVal,\n        0,\n        nullptr,\n        IID_PPV_ARGS(&texture)));\n\n    return Texture(name, texture, RESOURCE_HEAP_TYPE::PLACED);\n}\n\nTexture GpuMemory::GetTexture2D(const char* name, uint64_t width, uint32_t height, DXGI_FORMAT format,\n    D3D12_BARRIER_LAYOUT initialLayout, uint32_t flags, uint16_t mipLevels, D3D12_CLEAR_VALUE* clearVal)\n{\n    Texture::ID_TYPE id = XXH3_64_To_32(XXH3_64bits(name, strlen(name)));\n    return GetTexture2D(id, width, height, format, initialLayout, flags, mipLevels, clearVal, name);\n}\n\nTexture GpuMemory::GetTexture2D(Texture::ID_TYPE id, uint64_t width, uint32_t height, DXGI_FORMAT format,\n    D3D12_BARRIER_LAYOUT initialLayout, uint32_t flags, uint16_t mipLevels, D3D12_CLEAR_VALUE* clearVal,\n    const char* dbgName)\n{\n    Assert(width < D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION, \"Invalid width.\");\n    Assert(height < D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION, \"Invalid height.\");\n    Assert(mipLevels <= D3D12_REQ_MIP_LEVELS, \"Invalid number of mip levels.\");\n    Assert(((flags & TEXTURE_FLAGS::ALLOW_RENDER_TARGET) & (flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL)) == 0,\n        \"Texture can't be used as both Render Target and Depth Stencil.\");\n    Assert(((flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL) & (flags & TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS)) == 0,\n        \"A Depth-Stencil texture can't be used for unordered access.\");\n\n    D3D12_RESOURCE_FLAGS resFlags = D3D12_RESOURCE_FLAG_NONE;\n\n    if (flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL & ~D3D12_RESOURCE_FLAG_NONE);\n    if (flags & TEXTURE_FLAGS::ALLOW_RENDER_TARGET)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET & ~D3D12_RESOURCE_FLAG_NONE);\n    if (flags & TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS & ~D3D12_RESOURCE_FLAG_NONE);\n\n    D3D12_HEAP_PROPERTIES defaultHeap = Direct3DUtil::DefaultHeapProp();\n    D3D12_RESOURCE_DESC1 desc = Direct3DUtil::Tex2D1(format, width, height, 1, mipLevels, resFlags);\n\n    D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;\n    if ((flags & TEXTURE_FLAGS::INIT_TO_ZERO) == 0)\n        heapFlags = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;\n\n    ID3D12Resource* texture;\n    auto* device = App::GetRenderer().GetDevice();\n    CheckHR(device->CreateCommittedResource3(&defaultHeap,\n        heapFlags,\n        &desc,\n        initialLayout,\n        clearVal,\n        nullptr,\n        0,\n        nullptr,\n        IID_PPV_ARGS(&texture)));\n\n    return Texture(id, texture, RESOURCE_HEAP_TYPE::COMMITTED, dbgName);\n}\n\nTexture GpuMemory::GetTexture3D(const char* name, uint64_t width, uint32_t height, uint16_t depth,\n    DXGI_FORMAT format, D3D12_RESOURCE_STATES initialState, uint32_t flags, uint16_t mipLevels)\n{\n    Assert(width < D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION, \"Invalid width.\");\n    Assert(height < D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION, \"Invalid height.\");\n    Assert(depth < D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION, \"Invalid depth.\");\n    Assert(mipLevels <= D3D12_REQ_MIP_LEVELS, \"Invalid number of mip levels.\");\n    Assert(!(flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL), \"3D Texture can't be used as Depth Stencil.\");\n\n    D3D12_RESOURCE_FLAGS resFlags = D3D12_RESOURCE_FLAG_NONE;\n\n    if (flags & TEXTURE_FLAGS::ALLOW_RENDER_TARGET)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET & ~D3D12_RESOURCE_FLAG_NONE);\n    if (flags & TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS)\n        resFlags |= (D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS & ~D3D12_RESOURCE_FLAG_NONE);\n\n    D3D12_HEAP_PROPERTIES defaultHeap = Direct3DUtil::DefaultHeapProp();\n    D3D12_RESOURCE_DESC desc = Direct3DUtil::Tex3D(format, width, height, depth, mipLevels, resFlags);\n\n    D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;\n    if ((flags & TEXTURE_FLAGS::INIT_TO_ZERO) == 0)\n        heapFlags = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;\n\n    ID3D12Resource* texture;\n    auto* device = App::GetRenderer().GetDevice();\n    CheckHR(device->CreateCommittedResource(&defaultHeap,\n        heapFlags,\n        &desc,\n        initialState,\n        nullptr,\n        IID_PPV_ARGS(&texture)));\n\n    return Texture(name, texture, RESOURCE_HEAP_TYPE::COMMITTED);\n}\n\nLOAD_DDS_RESULT GpuMemory::GetTexture2DFromDisk(const char* texPath, Texture::ID_TYPE ID,\n    Texture& tex)\n{\n    D3D12_SUBRESOURCE_DATA subresources[DDS_Data::MAX_NUM_SUBRESOURCES];\n    uint32_t width;\n    uint32_t height;\n    uint32_t depth;\n    uint16_t mipCount;\n    uint32_t numSubresources;\n    DXGI_FORMAT format;\n    MemoryArena ma;\n    const auto errCode = Direct3DUtil::LoadDDSFromFile(texPath, subresources, \n        format, ArenaAllocator(ma), width, height, depth, mipCount, numSubresources);\n\n    if (errCode != LOAD_DDS_RESULT::SUCCESS)\n        return errCode;\n\n    tex = GetTexture2D(ID, width, height, format, D3D12_RESOURCE_STATE_COPY_DEST, 0, mipCount);\n\n    g_data->m_uploaders[g_threadIdx].UploadTexture(tex.Resource(), Span(subresources, numSubresources));\n\n    return LOAD_DDS_RESULT::SUCCESS;\n}\n\nLOAD_DDS_RESULT GpuMemory::GetTexture2DFromDisk(const char* texPath,\n    Texture::ID_TYPE ID, Texture& tex, UploadHeapArena& heapArena, ArenaAllocator allocator)\n{\n    D3D12_SUBRESOURCE_DATA subresources[DDS_Data::MAX_NUM_SUBRESOURCES];\n    uint32_t width;\n    uint32_t height;\n    uint32_t depth;\n    uint16_t mipCount;\n    uint32_t numSubresources;\n    DXGI_FORMAT format;\n    const auto errCode = Direct3DUtil::LoadDDSFromFile(texPath, subresources, \n        format, allocator, width, height, depth, mipCount, numSubresources);\n\n    if (errCode != LOAD_DDS_RESULT::SUCCESS)\n        return errCode;\n\n    tex = GetTexture2D(ID, width, height, format, D3D12_RESOURCE_STATE_COPY_DEST, 0, mipCount);\n\n    g_data->m_uploaders[g_threadIdx].UploadTexture(heapArena, tex.Resource(),\n        Span(subresources, numSubresources));\n\n    return LOAD_DDS_RESULT::SUCCESS;\n}\n\nLOAD_DDS_RESULT GpuMemory::GetDDSDataFromDisk(const char* texPath,\n    DDS_Data& dds, UploadHeapArena& heapArena, Support::ArenaAllocator allocator)\n{\n    return Direct3DUtil::LoadDDSFromFile(texPath, dds.subresources, \n        dds.format, allocator, dds.width, dds.height, dds.depth, dds.mipCount, \n        dds.numSubresources);\n}\n\nLOAD_DDS_RESULT GpuMemory::GetTexture3DFromDisk(const char* texPath, Texture& tex)\n{\n    // TODO MAX_NUM_SUBRESOURCES is not enough for 3D textures with mipmaps, though \n    // currently not needed\n    D3D12_SUBRESOURCE_DATA subresources[DDS_Data::MAX_NUM_SUBRESOURCES];\n    uint32_t width;\n    uint32_t height;\n    uint32_t depth;\n    uint16_t mipCount;\n    uint32_t numSubresources;\n    DXGI_FORMAT format;\n    MemoryArena ma;\n    const auto errCode = Direct3DUtil::LoadDDSFromFile(texPath, subresources, \n        format, ArenaAllocator(ma), width, height, depth, mipCount, numSubresources);\n\n    if (errCode != LOAD_DDS_RESULT::SUCCESS)\n        return errCode;\n\n    tex = GetTexture3D(texPath, width, height, (uint16_t)depth, format, \n        D3D12_RESOURCE_STATE_COPY_DEST, 0, mipCount);\n\n    g_data->m_uploaders[g_threadIdx].UploadTexture(tex.Resource(), Span(subresources, numSubresources),\n        0, D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n    return LOAD_DDS_RESULT::SUCCESS;\n}\n\nTexture GpuMemory::GetPlacedTexture2DAndInit(Texture::ID_TYPE ID, const D3D12_RESOURCE_DESC1& desc,\n    ID3D12Heap* heap, uint64_t offsetInBytes, UploadHeapArena& heapArena,\n    Span<D3D12_SUBRESOURCE_DATA> subresources, const char* dbgName)\n{\n    ID3D12Resource* texture;\n    auto* device = App::GetRenderer().GetDevice();\n    CheckHR(device->CreatePlacedResource1(heap,\n        offsetInBytes,\n        &desc,\n        D3D12_RESOURCE_STATE_COPY_DEST,\n        nullptr,\n        IID_PPV_ARGS(&texture)));\n\n    g_data->m_uploaders[g_threadIdx].UploadTexture(heapArena, texture, subresources);\n\n    return Texture(ID, texture, RESOURCE_HEAP_TYPE::PLACED, dbgName);\n}\n\nTexture GpuMemory::GetTexture2DAndInit(const char* name, uint64_t width, uint32_t height, \n    DXGI_FORMAT format, D3D12_RESOURCE_STATES postCopyState, uint8_t* pixels, uint32_t flags)\n{\n    Texture t = GetTexture2D(name, width, height, format, D3D12_RESOURCE_STATE_COPY_DEST, flags);\n\n    g_data->m_uploaders[g_threadIdx].UploadTexture(t.Resource(), pixels, postCopyState);\n\n    return t;\n}\n"
  },
  {
    "path": "Source/ZetaCore/Core/GpuMemory.h",
    "content": "#pragma once\n\n#include \"Direct3DUtil.h\"\n#include \"../Utility/Span.h\"\n#include \"../Support/OffsetAllocator.h\"\n\nnamespace ZetaRay::Core::GpuMemory\n{\n    //\n    // Types\n    //\n\n    enum TEXTURE_FLAGS\n    {\n        NONE = 0,\n        ALLOW_RENDER_TARGET = 1 << 0,\n        ALLOW_DEPTH_STENCIL = 1 << 1,\n        ALLOW_UNORDERED_ACCESS = 1 << 2,\n        INIT_TO_ZERO = 1 << 3\n    };\n\n    enum class RESOURCE_HEAP_TYPE\n    {\n        COMMITTED,\n        PLACED,\n        COUNT\n    };\n\n    template<int N = 1>\n    struct PlacedResourceList\n    {\n        void PushBuffer(uint32_t sizeInBytes, bool allowUAV, bool isRtAs)\n        {\n            D3D12_RESOURCE_FLAGS f = allowUAV ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : \n                D3D12_RESOURCE_FLAG_NONE;\n            if (isRtAs)\n                f |= D3D12_RESOURCE_FLAG_RAYTRACING_ACCELERATION_STRUCTURE;\n\n            D3D12_RESOURCE_DESC1 desc = Direct3DUtil::BufferResourceDesc1(sizeInBytes, f);\n            m_descs.push_back(desc);\n\n            //m_size = Math::AlignUp(m_size, (uint64_t)D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);\n            //m_size += sizeInBytes;\n        }\n        void PushTex2D(DXGI_FORMAT format, uint64_t width, uint32_t height, uint32_t flags = TEXTURE_FLAGS::NONE)\n        {\n            D3D12_RESOURCE_FLAGS f = D3D12_RESOURCE_FLAG_NONE;\n\n            if (flags & TEXTURE_FLAGS::ALLOW_DEPTH_STENCIL)\n                f |= (D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL & ~D3D12_RESOURCE_FLAG_NONE);\n            if (flags & TEXTURE_FLAGS::ALLOW_RENDER_TARGET)\n                f |= (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET & ~D3D12_RESOURCE_FLAG_NONE);\n            if (flags & TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS)\n                f |= (D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS & ~D3D12_RESOURCE_FLAG_NONE);\n\n            auto desc = Direct3DUtil::Tex2D1(format, width, height, 1, 1, f);\n            m_descs.push_back(desc);\n        }\n        void End()\n        {\n            m_infos.resize(N);\n            D3D12_RESOURCE_ALLOCATION_INFO info = Direct3DUtil::AllocationInfo(m_descs, m_infos);\n            m_size = info.SizeInBytes;\n        }\n        ZetaInline uint64_t TotalSizeInBytes() const { return m_size; }\n        ZetaInline Util::Span<D3D12_RESOURCE_ALLOCATION_INFO1> AllocInfos() const { return m_infos; }\n\n    private:\n        Util::SmallVector<D3D12_RESOURCE_DESC1, Support::SystemAllocator, N> m_descs;\n        Util::SmallVector<D3D12_RESOURCE_ALLOCATION_INFO1, Support::SystemAllocator, N> m_infos;\n        uint64_t m_size = 0;\n    };\n\n    struct UploadHeapBuffer\n    {\n        UploadHeapBuffer() = default;\n        UploadHeapBuffer(ID3D12Resource* r, void* mapped, const Support::OffsetAllocator::Allocation& alloc = \n            Support::OffsetAllocator::Allocation::Empty());\n        ~UploadHeapBuffer();\n        UploadHeapBuffer(UploadHeapBuffer&& other);\n        UploadHeapBuffer& operator=(UploadHeapBuffer&& other);\n\n        void Reset();\n        ZetaInline bool IsInitialized() const { return m_resource != nullptr; }\n        ZetaInline ID3D12Resource* Resource() { return m_resource; }\n        ZetaInline D3D12_GPU_VIRTUAL_ADDRESS GpuVA() const { return m_resource->GetGPUVirtualAddress() + m_allocation.Offset; }\n        ZetaInline void* MappedMemory() { return m_mappedMemory; }\n        ZetaInline const Support::OffsetAllocator::Allocation& Allocation() const { return m_allocation; }\n        ZetaInline uint32_t Offset() const { return m_allocation.Offset; }\n        void Copy(uint32_t offset, uint32_t numBytesToCopy, void* data);\n\n    private:\n        ID3D12Resource* m_resource = nullptr;\n        void* m_mappedMemory = nullptr;\n        Support::OffsetAllocator::Allocation m_allocation = Support::OffsetAllocator::Allocation::Empty();\n    };\n\n    struct UploadHeapArena\n    {\n        struct Allocation\n        {\n            ID3D12Resource* Res;\n            void* Mapped;\n            uint32_t Offset = 0;\n        };\n\n        struct Block\n        {\n            ID3D12Resource* Res;\n            uint32_t Offset;\n            void* Mapped;\n        };\n\n        explicit UploadHeapArena(uint32_t sizeInBytes);\n        ~UploadHeapArena();\n        UploadHeapArena(UploadHeapArena&& rhs);\n\n        Util::Span<Block> Blocks() { return m_blocks; }\n        Allocation SubAllocate(uint32_t size, uint32_t alignment = 1);\n\n    private:\n        Util::SmallVector<Block, Support::SystemAllocator, 4> m_blocks;\n        uint32_t m_size;\n    };\n\n    struct ReadbackHeapBuffer\n    {\n        ReadbackHeapBuffer() = default;\n        explicit ReadbackHeapBuffer(ID3D12Resource* r);\n        ~ReadbackHeapBuffer();\n        ReadbackHeapBuffer(ReadbackHeapBuffer&&);\n        ReadbackHeapBuffer& operator=(ReadbackHeapBuffer&&);\n\n        ZetaInline bool IsInitialized() { return m_resource != nullptr; }\n        void Reset(bool waitForGPU = true);\n        ZetaInline D3D12_GPU_VIRTUAL_ADDRESS GpuVA() const\n        {\n            Assert(m_resource, \"ReadbackHeapBuffer hasn't been initialized.\");\n            return m_resource->GetGPUVirtualAddress();\n        }\n        ZetaInline ID3D12Resource* Resource()\n        {\n            Assert(m_resource, \"ReadbackHeapBuffer hasn't been initialized.\");\n            return m_resource;\n        }\n        ZetaInline D3D12_RESOURCE_DESC Desc() const\n        {\n            Assert(m_resource, \"ReadbackHeapBuffer hasn't been initialized.\");\n            return m_resource->GetDesc();\n        }\n\n        // From MS Docs:\n        // \"Resources on D3D12_HEAP_TYPE_READBACK heaps do not support persistent map. Map and Unmap must \n        // be called between CPU and GPU accesses to the same memory address on some system architectures, \n        // when the page caching behavior is write-back.\"\n        void Map();\n        void Unmap();\n        ZetaInline bool IsMapped() const { return m_mappedMemory != nullptr; }\n        ZetaInline void* MappedMemory()\n        {\n            //Assert(m_mappedMemory, \"Resource is not mapped.\");\n            return m_mappedMemory;\n        }\n\n    private:\n        ID3D12Resource* m_resource = nullptr;\n        void* m_mappedMemory = nullptr;\n    };\n\n    struct Buffer\n    {\n        using ID_TYPE = uint32_t;\n        static constexpr ID_TYPE INVALID_ID = UINT32_MAX;\n\n        Buffer() = default;\n        Buffer(const char* p, ID3D12Resource* r, RESOURCE_HEAP_TYPE heapType);\n        ~Buffer();\n        Buffer(Buffer&&);\n        Buffer& operator=(Buffer&&);\n\n        void Reset(bool waitForGpu = true);\n        ZetaInline bool IsInitialized() const { return m_resource != nullptr; }\n        ZetaInline D3D12_GPU_VIRTUAL_ADDRESS GpuVA() const\n        {\n            Assert(m_resource, \"Buffer hasn't been initialized.\");\n            return m_resource->GetGPUVirtualAddress();\n        }\n        ZetaInline ID3D12Resource* Resource()\n        {\n            Assert(m_resource, \"Buffer hasn't been initialized.\");\n            return m_resource;\n        }\n        ZetaInline D3D12_RESOURCE_DESC Desc() const\n        {\n            Assert(m_resource, \"Buffer hasn't been initialized.\");\n            return m_resource->GetDesc();\n        }\n        ZetaInline ID_TYPE ID() const\n        {\n            Assert(m_resource, \"Buffer hasn't been initialized.\");\n            return m_ID;\n        }\n\n    private:\n        ID3D12Resource* m_resource = nullptr;\n        ID_TYPE m_ID = INVALID_ID;\n        RESOURCE_HEAP_TYPE m_heapType;\n    };\n\n    struct Texture\n    {\n        using ID_TYPE = uint32_t;\n        static constexpr ID_TYPE INVALID_ID = UINT32_MAX;\n\n        Texture() = default;\n        Texture(const char* name, ID3D12Resource* res, RESOURCE_HEAP_TYPE heapType);\n        Texture(ID_TYPE id, ID3D12Resource* res, RESOURCE_HEAP_TYPE heapType,\n            const char* dbgName = nullptr);\n        ~Texture();\n        Texture(Texture&&);\n        Texture& operator=(Texture&&);\n\n        void Reset(bool waitForGpu = true, bool checkRefCount = true);\n        ZetaInline bool IsInitialized() const { return m_ID != INVALID_ID; }\n        ZetaInline ID3D12Resource* Resource()\n        {\n            Assert(m_resource, \"Texture hasn't been initialized.\");\n            return m_resource;\n        }\n        ZetaInline ID_TYPE ID() const { return m_ID; }\n        ZetaInline D3D12_RESOURCE_DESC Desc() const\n        {\n            Assert(m_resource, \"Texture hasn't been initialized.\");\n            return m_resource->GetDesc();\n        }\n        ZetaInline RESOURCE_HEAP_TYPE HeapType() const\n        {\n            Assert(m_resource, \"Texture hasn't been initialized.\");\n            return m_heapType;\n        }\n        // Note: No GpuVa() method - from MS docs: \"ID3D12Resource::GetGPUVirtualAddress() \n        // is only useful for buffer resources, it will return zero for all texture resources.\"\n\n    private:\n        ID3D12Resource* m_resource = nullptr;\n        ID_TYPE m_ID = INVALID_ID;\n        RESOURCE_HEAP_TYPE m_heapType;\n    };\n\n    struct ResourceHeap\n    {\n        ResourceHeap() = default;\n        explicit ResourceHeap(ID3D12Heap* heap);\n        ~ResourceHeap();\n        ResourceHeap(ResourceHeap&&);\n        ResourceHeap& operator=(ResourceHeap&&);\n\n        void Reset();\n        ZetaInline bool IsInitialized() const { return m_heap; }\n        ZetaInline ID3D12Heap* Heap()\n        {\n            Assert(m_heap, \"Heap hasn't been initialized.\");\n            return m_heap;\n        }\n\n    private:\n        ID3D12Heap* m_heap = nullptr;\n    };\n\n    //\n    // API\n    //\n\n    void Init();\n    void BeginFrame();\n    void SubmitResourceCopies();\n    void Recycle();\n    // Assumes GPU synchronization has been performed\n    void Shutdown();\n\n    UploadHeapBuffer GetUploadHeapBuffer(uint32_t sizeInBytes, uint32_t alignment = 4, \n        bool forceSeparate = false);\n    void ReleaseUploadHeapBuffer(UploadHeapBuffer& buffer);\n    void ReleaseUploadHeapArena(UploadHeapArena& arena);\n\n    ReadbackHeapBuffer GetReadbackHeapBuffer(uint32_t sizeInBytes);\n    void ReleaseReadbackHeapBuffer(ReadbackHeapBuffer& buffer);\n\n    Buffer GetDefaultHeapBuffer(const char* name, uint32_t sizeInBytes,\n        D3D12_RESOURCE_STATES initialState, bool allowUAV, bool initToZero = false);\n    Buffer GetDefaultHeapBuffer(const char* name, uint32_t sizeInBytes,\n        bool isRtAs, bool allowUAV, bool initToZero = false);\n    Buffer GetPlacedHeapBuffer(const char* name, uint32_t sizeInBytes,\n        ID3D12Heap* heap, uint64_t offsetInBytes, bool allowUAV, bool isRtAs);\n    Buffer GetDefaultHeapBufferAndInit(const char* name,\n        uint32_t sizeInBytes,\n        bool allowUAV, \n        Util::MemoryRegion initData,\n        bool forceSeparateUploadBuffer = false);    \n    Buffer GetPlacedHeapBufferAndInit(const char* name,\n        uint32_t sizeInBytes,\n        ID3D12Heap* heap,\n        uint64_t offsetInBytes,\n        bool allowUAV,\n        Util::MemoryRegion initData,\n        bool forceSeparateUploadBuffer = false);\n    void UploadToDefaultHeapBuffer(Buffer& buffer, uint32_t sizeInBytes, \n        Util::MemoryRegion sourceData, uint32_t destOffsetInBytes = 0);\n    ResourceHeap GetResourceHeap(uint64_t sizeInBytes, \n        uint64_t alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,\n        bool createZeroed = false);\n    void ReleaseDefaultHeapBuffer(Buffer& buffer);\n    void ReleaseTexture(Texture& textue);\n    void ReleaseResourceHeap(ResourceHeap& heap);\n\n    Texture GetTexture2D(const char* name, uint64_t width, uint32_t height, DXGI_FORMAT format,\n        D3D12_RESOURCE_STATES initialState, uint32_t flags = 0, uint16_t mipLevels = 1,\n        D3D12_CLEAR_VALUE* clearVal = nullptr);\n    Texture GetTexture2D(Texture::ID_TYPE id, uint64_t width, uint32_t height, DXGI_FORMAT format,\n        D3D12_RESOURCE_STATES initialState, uint32_t flags = 0, uint16_t mipLevels = 1,\n        D3D12_CLEAR_VALUE* clearVal = nullptr, const char* dbgName = nullptr);\n    Texture GetPlacedTexture2D(const char* name, uint64_t width, uint32_t height, DXGI_FORMAT format,\n        ID3D12Heap* heap, uint64_t offsetInBytes, D3D12_RESOURCE_STATES initialState, uint32_t flags = 0,\n        uint16_t mipLevels = 1, D3D12_CLEAR_VALUE* clearVal = nullptr);\n    Texture GetPlacedTexture2D(const char* name, uint64_t width, uint32_t height, DXGI_FORMAT format,\n        ID3D12Heap* heap, uint64_t offsetInBytes, D3D12_BARRIER_LAYOUT initialLayout, uint32_t flags = 0,\n        uint16_t mipLevels = 1, D3D12_CLEAR_VALUE* clearVal = nullptr);\n    Texture GetTexture2D(const char* name, uint64_t width, uint32_t height, DXGI_FORMAT format,\n        D3D12_BARRIER_LAYOUT initialLayout, uint32_t flags = 0, uint16_t mipLevels = 1,\n        D3D12_CLEAR_VALUE* clearVal = nullptr);\n    Texture GetTexture2D(Texture::ID_TYPE id, uint64_t width, uint32_t height, DXGI_FORMAT format,\n        D3D12_BARRIER_LAYOUT initialLayout, uint32_t flags = 0, uint16_t mipLevels = 1,\n        D3D12_CLEAR_VALUE* clearVal = nullptr, const char* dbgName = nullptr);\n    Texture GetTexture3D(const char* name, uint64_t width, uint32_t height, uint16_t depth,\n        DXGI_FORMAT format, D3D12_RESOURCE_STATES initialState,\n        uint32_t flags = 0, uint16_t mipLevels = 1);\n\n    struct DDS_Data\n    {\n        // Up to 4k for 2D textures\n        static constexpr int MAX_NUM_SUBRESOURCES = 13;\n\n        D3D12_SUBRESOURCE_DATA subresources[MAX_NUM_SUBRESOURCES];\n        Texture::ID_TYPE ID;\n        uint32_t width;\n        uint32_t height;\n        uint32_t depth;\n        uint32_t numSubresources;\n        DXGI_FORMAT format;\n        uint16_t mipCount;\n    };\n\n    Core::Direct3DUtil::LOAD_DDS_RESULT GetTexture2DFromDisk(const char* texPath,\n        Texture::ID_TYPE ID, Texture& tex);\n    Core::Direct3DUtil::LOAD_DDS_RESULT GetTexture2DFromDisk(const char* texPath,\n        Texture::ID_TYPE ID, Texture& tex, UploadHeapArena& heapArena, Support::ArenaAllocator allocator);\n    Core::Direct3DUtil::LOAD_DDS_RESULT GetDDSDataFromDisk(const char* texPath,\n        DDS_Data& dds, UploadHeapArena& heapArena, Support::ArenaAllocator allocator);\n    Core::Direct3DUtil::LOAD_DDS_RESULT GetTexture3DFromDisk(const char* texPath,\n        Texture& tex);\n    Texture GetTexture2DAndInit(const char* name, uint64_t width, uint32_t height, DXGI_FORMAT format,\n        D3D12_RESOURCE_STATES initialState, uint8_t* pixels, uint32_t flags = 0);\n    Texture GetPlacedTexture2DAndInit(Texture::ID_TYPE ID, const D3D12_RESOURCE_DESC1& desc,\n        ID3D12Heap* heap, uint64_t offsetInBytes, UploadHeapArena& heapArena,\n        Util::Span<D3D12_SUBRESOURCE_DATA> subresources, const char* dbgName = nullptr);\n}"
  },
  {
    "path": "Source/ZetaCore/Core/GpuTimer.cpp",
    "content": "#include \"RendererCore.h\"\n#include \"CommandList.h\"\n#include \"../App/Timer.h\"\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Util;\n\nvoid GpuTimer::Init()\n{\n    auto& renderer = App::GetRenderer();\n\n    m_directQueueFreq = renderer.GetCommandQueueTimeStampFrequency(D3D12_COMMAND_LIST_TYPE_DIRECT);\n    m_computeQueueFreq = renderer.GetCommandQueueTimeStampFrequency(D3D12_COMMAND_LIST_TYPE_COMPUTE);\n\n    // ticks/s to ticks/ms\n    m_directQueueFreq /= 1000;\n    m_computeQueueFreq /= 1000;\n\n    D3D12_QUERY_HEAP_DESC desc{};\n    desc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP;\n    desc.Count = MAX_NUM_QUERIES * 2 * Constants::NUM_BACK_BUFFERS;\n    desc.NodeMask = 0;\n\n    auto* device = renderer.GetDevice();\n    CheckHR(device->CreateQueryHeap(&desc, IID_PPV_ARGS(m_queryHeap.GetAddressOf())));\n\n    for (int i = 0; i < ZetaArrayLen(m_timings); i++)\n        m_timings[i].resize(MAX_NUM_QUERIES);\n\n    m_readbackBuff = GpuMemory::GetReadbackHeapBuffer(sizeof(uint64_t) * desc.Count);\n\n#ifndef NDEBUG\n    m_readbackBuff.Resource()->SetName(L\"Timing_Buffer\");\n#endif\n\n    CheckHR(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(m_fence.GetAddressOf())));\n}\n\nvoid GpuTimer::Shutdown()\n{\n    m_readbackBuff.Reset(false);\n}\n\nSpan<GpuTimer::Timing> GpuTimer::GetFrameTimings()\n{\n    if (App::GetTimer().GetTotalFrameCount() < 2)\n        return Span(reinterpret_cast<Timing*>(NULL), 0);\n\n    return Span(m_timings[Constants::NUM_BACK_BUFFERS].data(), \n        m_queryCounts[Constants::NUM_BACK_BUFFERS]);\n}\n\nvoid GpuTimer::BeginFrame()\n{\n    Assert(m_frameQueryCount.load(std::memory_order_relaxed) == 0,\n        \"Attempting to begin a new frame while GpuTimer::Resolve() hasn't been called for the previous frame.\");\n\n    if (App::GetTimer().GetTotalFrameCount() >= 1)\n    {\n        // At this point, previous frame's queries have been submitted\n        m_fenceVals[m_currFrameIdx] = m_nextFenceVal;\n        // Advance the frame index\n        m_currFrameIdx = m_currFrameIdx < Constants::NUM_BACK_BUFFERS - 1 ? \n            m_currFrameIdx + 1 : 0;\n\n        App::GetRenderer().SignalDirectQueue(m_fence.Get(), m_nextFenceVal++);\n\n        // Are there been newly resolved timings?\n        bool newData = false;\n        const uint64_t completed = m_fence->GetCompletedValue();\n        const int oldNextCompletedFrameIdx = m_nextCompletedFrameIdx;\n\n        do\n        {\n            if (completed < m_fenceVals[m_nextCompletedFrameIdx])\n                break;\n\n            m_nextCompletedFrameIdx = m_nextCompletedFrameIdx < Constants::NUM_BACK_BUFFERS - 1 ? \n                m_nextCompletedFrameIdx + 1 : 0;\n            newData = true;\n        } while (m_nextCompletedFrameIdx != oldNextCompletedFrameIdx);\n\n        if (newData)\n        {\n            // Undo the last add\n            const int lastCompletedFrameIdx = m_nextCompletedFrameIdx > 0 ? \n                m_nextCompletedFrameIdx - 1 : Constants::NUM_BACK_BUFFERS - 1;\n\n            m_readbackBuff.Map();\n            uint8_t* data = reinterpret_cast<uint8_t*>(m_readbackBuff.MappedMemory());\n\n            for (int i = 0; i < m_queryCounts[lastCompletedFrameIdx]; i++)\n            {\n                uint8_t* currPtr = data + sizeof(uint64_t) * i * 2;\n                uint64_t beg, end;\n\n                memcpy(&beg, currPtr, sizeof(uint64_t));\n                memcpy(&end, currPtr + sizeof(uint64_t), sizeof(uint64_t));\n\n                uint64_t freq = \n                    m_timings[lastCompletedFrameIdx][i].ExecutionQueue == D3D12_COMMAND_LIST_TYPE_DIRECT ?\n                    m_directQueueFreq : m_computeQueueFreq;\n                m_timings[lastCompletedFrameIdx][i].Delta = (end - beg) / (double)freq;\n            }\n\n            m_readbackBuff.Unmap();\n\n            if (m_queryCounts[lastCompletedFrameIdx])\n            {\n                m_timings[Constants::NUM_BACK_BUFFERS].clear();\n                m_timings[Constants::NUM_BACK_BUFFERS].append_range(\n                    m_timings[lastCompletedFrameIdx].begin(),\n                    m_timings[lastCompletedFrameIdx].end(), true);\n\n                std::sort(m_timings[Constants::NUM_BACK_BUFFERS].begin(), \n                    m_timings[Constants::NUM_BACK_BUFFERS].begin() + m_queryCounts[lastCompletedFrameIdx],\n                    [](const Timing& t0, const Timing& t1)\n                    {\n                        return strcmp(t0.Name, t1.Name) < 0;\n                    });\n            }\n\n            m_queryCounts[Constants::NUM_BACK_BUFFERS] = m_queryCounts[lastCompletedFrameIdx];\n        }\n    }\n\n    //for (int i = 0; i < MAX_NUM_QUERIES; i++)\n    //    m_timings[m_currFrameIdx][i].Reset();\n}\n\nuint32_t GpuTimer::BeginQuery(ComputeCmdList& cmdList, const char* name)\n{\n    const uint32_t queryIdx = m_frameQueryCount.fetch_add(1, std::memory_order_relaxed);\n    Assert(queryIdx < MAX_NUM_QUERIES, \"Number of queries exceeded maximum allowed.\");\n\n    const auto n = Math::Min(Timing::MAX_NAME_LENGTH - 1, (int)strlen(name));\n    memcpy(&m_timings[m_currFrameIdx][queryIdx].Name, name, n);\n    m_timings[m_currFrameIdx][queryIdx].Name[n] = '\\0';\n    m_timings[m_currFrameIdx][queryIdx].Delta = 0.0;\n    m_timings[m_currFrameIdx][queryIdx].ExecutionQueue = cmdList.GetType();\n\n    const uint32_t heapIdx = MAX_NUM_QUERIES * 2 * m_currFrameIdx + queryIdx * 2;\n    Assert((heapIdx & 0x1) == 0, \"Invalid query index.\");\n    cmdList.EndQuery(m_queryHeap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, heapIdx);\n\n    return heapIdx;\n}\n\nvoid GpuTimer::EndQuery(ComputeCmdList& cmdList, uint32_t begHeapIdx)\n{\n    Assert(((begHeapIdx & 0x1) == 0) && (begHeapIdx >= MAX_NUM_QUERIES * 2 * m_currFrameIdx), \n        \"Invalid query index.\");\n    const uint32_t endHeapIdx = begHeapIdx + 1;\n    Assert(endHeapIdx < MAX_NUM_QUERIES * 2 * Constants::NUM_BACK_BUFFERS, \n        \"Invalid query index.\");\n\n    cmdList.EndQuery(m_queryHeap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, endHeapIdx);\n}\n\nvoid GpuTimer::EndFrame(ComputeCmdList& cmdList)\n{\n    Assert(!m_readbackBuff.IsMapped(), \n        \"Readback buffer shouldn't be mapped while in use by the GPU.\");\n    const int queryCount = m_frameQueryCount.load(std::memory_order_acquire);\n    m_queryCounts[m_currFrameIdx] = queryCount;\n\n    if (queryCount == 0)\n        return;\n\n    uint32_t heapStartIdx = m_currFrameIdx * MAX_NUM_QUERIES * 2;\n    uint64_t bufferOffsetBeg = heapStartIdx * sizeof(uint64_t);\n\n    cmdList.PIXBeginEvent(\"GpuTimer\");\n\n    cmdList.ResolveQueryData(m_queryHeap.Get(), \n        D3D12_QUERY_TYPE_TIMESTAMP, \n        heapStartIdx, \n        queryCount * 2,\n        m_readbackBuff.Resource(), \n        bufferOffsetBeg);\n\n    cmdList.PIXEndEvent();\n\n    m_frameQueryCount.store(0, std::memory_order_relaxed);\n}\n"
  },
  {
    "path": "Source/ZetaCore/Core/GpuTimer.h",
    "content": "#pragma once\n\n#include <Core/Config.h>\n#include \"GpuMemory.h\"\n#include <atomic>\n\nnamespace ZetaRay::Core\n{\n    class ComputeCmdList;\n\n    struct GpuTimer\n    {\n        struct alignas(32) Timing\n        {\n            static constexpr int MAX_NAME_LENGTH = 32;\n\n            char Name[MAX_NAME_LENGTH];\n            double Delta;\n            D3D12_COMMAND_LIST_TYPE ExecutionQueue;\n        };\n\n        GpuTimer() = default;\n        ~GpuTimer() = default;\n\n        GpuTimer(GpuTimer&&) = delete;\n        GpuTimer& operator=(GpuTimer&&) = delete;\n\n        void Init();\n        void Shutdown();\n        Util::Span<Timing> GetFrameTimings();\n\n        // Call before recording commands for a particular command list\n        uint32_t BeginQuery(ComputeCmdList& cmdList, const char* name);\n\n        // Call after all commands for a particular command list are recorded\n        void EndQuery(ComputeCmdList& cmdList, uint32_t idx);\n\n        // Call before rendering this frame\n        void BeginFrame();\n\n        // Call after all rendering commands for this frame have been submitted\n        void EndFrame(ComputeCmdList& cmdList);\n\n    private:\n        static constexpr uint32_t MAX_NUM_QUERIES = 32;\n\n        ComPtr<ID3D12QueryHeap> m_queryHeap;\n        GpuMemory::ReadbackHeapBuffer m_readbackBuff;\n\n        Util::SmallVector<Timing, Support::SystemAllocator, MAX_NUM_QUERIES> m_timings[Constants::NUM_BACK_BUFFERS + 1];\n        int m_queryCounts[Constants::NUM_BACK_BUFFERS + 1] = { 0 };\n        std::atomic<int32_t> m_frameQueryCount;\n\n        UINT64 m_directQueueFreq;\n        UINT64 m_computeQueueFreq;\n\n        int m_currFrameIdx = 0;\n        int m_nextCompletedFrameIdx = 0;\n        uint64_t m_fenceVals[Constants::NUM_BACK_BUFFERS] = { 0 };\n        uint64_t m_nextFenceVal = 1;\n        ComPtr<ID3D12Fence> m_fence;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Core/HLSLCompat.h",
    "content": "#ifndef HLSL_COMPAT\n#define HLSL_COMPAT\n\n#ifdef __cplusplus\n    #include <cstdint>\n    #include \"../Math/Matrix.h\"\n\n    #define float2_ ZetaRay::Math::float2\n    #define float3_ ZetaRay::Math::float3\n    #define float4_ ZetaRay::Math::float4\n    #define float3x3_ ZetaRay::Math::float3x3\n    #define float3x4_ ZetaRay::Math::float3x4\n    #define float4x4_ ZetaRay::Math::float4x4a\n    #define half_ ZetaRay::Math::half\n    #define half2_ ZetaRay::Math::half2\n    #define half3_ ZetaRay::Math::half3\n    #define half4_ ZetaRay::Math::half4\n    #define unorm2_ ZetaRay::Math::unorm2\n    #define unorm3_ ZetaRay::Math::unorm3\n    #define unorm4_ ZetaRay::Math::unorm4\n\n    #define IN_PARAM(t) t&\n    #define OUT_PARAM(t) t&\n    #define row_major\n    #define CONST const\n\n    #define IS_CB_FLAG_SET(cb, flag) ((cb.Flags & (flag)) == (flag))\n    #define SET_CB_FLAG(cb, flag, val) (cb.Flags = (cb.Flags & ~(flag)) | ((val) * (flag)))\n#else\n    #define float2_ float2\n    #define float3_ float3\n    #define float4_ float4\n    #define float3x3_ float3x3\n    #define float3x3_ float3x3\n    #define float3x4_ float3x4\n    #define float4x3_ float4x3\n    #define float4x4_ float4x4\n    #define half_ half\n    #define half2_ half2\n    #define half3_ half3\n    #define half4_ half4\n    #define unorm2_ uint16_t2\n    #define unorm3_ uint16_t3\n    #define unorm4_ uint16_t4\n    #define uint16 uint16_t\n    #define uint32 uint32_t\n    #define int16 int16_t\n    #define int32 int32_t\n\n    #define IN_PARAM(t) in t\n    #define OUT_PARAM(t) out t\n    #define CONST\n    #define constexpr const\n\n    #define IS_CB_FLAG_SET(flag) ((g_local.Flags & flag) == flag)\n#endif\n\n#endif // HLSL_COMPAT"
  },
  {
    "path": "Source/ZetaCore/Core/Material.h",
    "content": "#ifndef MATERIAL_H\n#define MATERIAL_H\n\n#include \"HLSLCompat.h\"\n\n// Metallic is treated as a binary parameter - everything with a lower \"metalness\" \n// value is considered dielectric.\n#define MIN_METALNESS_METAL 0.9\n// Transmission weight is also treated as binary - everything with a lower\n// weight is considered opaque.\n#define MIN_SPEC_TR_TRANSMISSIVE 0.9\n\n#define MIN_IOR 1.0f\n#define MAX_IOR 2.5f\n#define DEFAULT_ETA_MAT 1.5f\n#define DEFAULT_ETA_COAT 1.6f\n#define ETA_AIR 1.0f\n\n#ifdef __cplusplus\n#include \"../Math/Color.h\"\n#else\n#include \"../../ZetaRenderPass/Common/Math.hlsli\"\n#endif\n\n#ifdef __cplusplus\nnamespace ZetaRay\n{\n#endif\n    struct Material\n    {\n        enum FLAG_BITS\n        {\n            METALLIC = 24,\n            DOUBLE_SIDED = 25,\n            TRANSMISSIVE = 26,\n            ALPHA_1 = 27,\n            ALPHA_2 = 28,\n            THIN_WALLED = 29\n        };\n\n        static const uint32_t NUM_MATERIAL_BITS = 16;\n        static const uint32_t NUM_TEXTURE_BITS = NUM_MATERIAL_BITS;\n        // Reserve largest value for invalid materials\n        static const uint32_t INVALID_ID = (1u << NUM_MATERIAL_BITS) - 1;\n        static const uint32_t MAX_NUM_MATERIALS = (1u << NUM_MATERIAL_BITS) - 1;\n        static const uint32_t MAX_NUM_TEXTURES = MAX_NUM_MATERIALS;\n        static const uint32_t MATERIAL_MASK = (1u << NUM_MATERIAL_BITS) - 1;\n        static const uint32_t TEXTURE_MASK = (1u << NUM_MATERIAL_BITS) - 1;\n        static const uint32_t LOWER_16_BITS_MASK = 0xffff;\n        static const uint32_t LOWER_24_BITS_MASK = 0xffffff;\n        static const uint32_t UPPER_8_BITS_MASK = 0xff000000;\n        static const uint32_t UPPER_16_BITS_MASK = 0xffff0000;\n        // Excludes bits [16-24)\n        static const uint32_t ONES_COMP_BITS_16_24 = 0xff00ffff;\n\n#ifdef __cplusplus\n\n        enum class ALPHA_MODE : uint8_t\n        {\n            // \"OPAQUE\" is defined in wingdi.h!\n            OPAQUE_ = 0,\n            // Output is either fully opaque or fully transparent depending on the alpha value\n            MASK,\n            // [Not supported] Alpha value is used to composite source and destination areas\n            BLEND,\n            COUNT\n        };\n\n        Material()\n        {\n            memset(this, 0, sizeof(Material));\n\n            SetBaseColorFactor(Math::float4(1.0f, 1.0f, 1.0f, 1.0f));\n            SetMetallic(0.0f);\n            SetSpecularRoughness(0.3f);\n            SetSpecularIOR(1.5f);\n            SetTransmission(0.0f);\n            SetEmissiveFactor(Math::float3(0));\n            SetEmissiveStrength(1.0f);\n            SetCoatWeight(0.0f);\n            SetCoatColor(Math::float3(0.8f));\n            SetCoatRoughness(0.0f);\n            SetCoatIOR(DEFAULT_ETA_COAT);\n            SetNormalScale(1.0f);\n            SetAlphaMode(ALPHA_MODE::OPAQUE_);\n            SetAlphaCutoff(0.5f);\n            SetDoubleSided(false);\n            SetThinWalled(false);\n            SetBaseColorTex(INVALID_ID);\n            SetNormalTex(INVALID_ID);\n            SetMetallicRoughnessTex(INVALID_ID);\n            SetEmissiveTex(INVALID_ID);\n        }\n\n        // For Set*Tex() calls, passing INVALID_ID (= MAX_NUM_TEXTURES) is valid\n        ZetaInline void SetBaseColorTex(uint32_t idx)\n        {\n            Assert(idx <= MAX_NUM_TEXTURES, \"Invalid texture index.\");\n            BaseColorTex_Subsurf_CoatWeight = idx |\n                (BaseColorTex_Subsurf_CoatWeight & UPPER_16_BITS_MASK);\n        }\n\n        ZetaInline void SetNormalTex(uint32_t idx)\n        {\n            Assert(idx <= MAX_NUM_TEXTURES, \"Invalid texture index.\");\n            NormalTex_TrDepth = idx | \n                (NormalTex_TrDepth & UPPER_16_BITS_MASK);\n        }\n\n        ZetaInline void SetMetallicRoughnessTex(uint32_t idx)\n        {\n            Assert(idx <= MAX_NUM_TEXTURES, \"Invalid texture index.\");\n            MRTex_SpecRoughness_CoatRoughness = idx | \n                (MRTex_SpecRoughness_CoatRoughness & UPPER_16_BITS_MASK);\n        }\n\n        ZetaInline void SetEmissiveTex(uint32_t idx)\n        {\n            Assert(idx <= MAX_NUM_TEXTURES, \"Invalid texture index.\");\n            EmissiveTex_AlphaCutoff_CoatIOR = idx |\n                (EmissiveTex_AlphaCutoff_CoatIOR & UPPER_16_BITS_MASK);\n        }\n\n        ZetaInline void SetBaseColorFactor(const Math::float3& color)\n        {\n            BaseColorFactor = Float3ToRGB8(color) | (BaseColorFactor & UPPER_8_BITS_MASK);\n        }\n\n        ZetaInline void SetBaseColorFactor(const Math::float4& color)\n        {\n            BaseColorFactor = Float4ToRGBA8(color);\n        }\n\n        ZetaInline void SetSpecularRoughness(float r)\n        {\n            MRTex_SpecRoughness_CoatRoughness = \n                (MRTex_SpecRoughness_CoatRoughness & ONES_COMP_BITS_16_24) |\n                (Math::FloatToUNorm8(r) << NUM_TEXTURE_BITS);\n        }\n\n        ZetaInline void SetCoatRoughness(float r)\n        {\n            MRTex_SpecRoughness_CoatRoughness = \n                (MRTex_SpecRoughness_CoatRoughness & LOWER_24_BITS_MASK) |\n                (Math::FloatToUNorm8(r) << (NUM_TEXTURE_BITS + 8));\n        }\n\n        ZetaInline void SetAlphaCutoff(float c)\n        {\n            EmissiveTex_AlphaCutoff_CoatIOR = \n                (EmissiveTex_AlphaCutoff_CoatIOR & ONES_COMP_BITS_16_24) |\n                (Math::FloatToUNorm8(c) << NUM_TEXTURE_BITS);\n        }\n\n        ZetaInline void SetCoatIOR(float ior)\n        {\n            Assert(ior >= MIN_IOR && ior < MAX_IOR, \"IOR is assumed to be in the range [1, 2.5).\");\n            float normalized = (ior - MIN_IOR) / (MAX_IOR - MIN_IOR);\n\n            EmissiveTex_AlphaCutoff_CoatIOR =\n                (EmissiveTex_AlphaCutoff_CoatIOR & LOWER_24_BITS_MASK) |\n                (Math::FloatToUNorm8(normalized) << (NUM_TEXTURE_BITS + 8));\n        }\n\n        ZetaInline void SetNormalScale(float s)\n        {\n            EmissiveFactor_NormalScale = (EmissiveFactor_NormalScale & LOWER_24_BITS_MASK) |\n                (Math::FloatToUNorm8(s) << 24);\n        }\n\n        ZetaInline void SetEmissiveFactor(Math::float3 color)\n        {\n            EmissiveFactor_NormalScale = Math::Float3ToRGB8(color) | \n                (EmissiveFactor_NormalScale & UPPER_8_BITS_MASK);\n        }\n\n        ZetaInline void SetEmissiveStrength(float s)\n        {\n            Math::half h(s);\n            EmissiveStrength_IOR = uint32_t(h.x) | (EmissiveStrength_IOR & UPPER_16_BITS_MASK);\n        }\n\n        ZetaInline void SetSpecularIOR(float ior)\n        {\n            Assert(ior >= MIN_IOR && ior < MAX_IOR, \"IOR is assumed to be in the range [1, 2.5).\");\n            float normalized = (ior - MIN_IOR) / (MAX_IOR - MIN_IOR);\n\n            EmissiveStrength_IOR = (EmissiveStrength_IOR & LOWER_16_BITS_MASK) | \n                (Math::FloatToUNorm16(normalized) << 16);\n        }\n\n        ZetaInline void SetSubsurface(float s)\n        {\n            BaseColorTex_Subsurf_CoatWeight = \n                (BaseColorTex_Subsurf_CoatWeight & ONES_COMP_BITS_16_24) |\n                (Math::FloatToUNorm8(s) << NUM_TEXTURE_BITS);\n        }\n\n        ZetaInline void SetCoatWeight(float w)\n        {\n            BaseColorTex_Subsurf_CoatWeight =\n                (BaseColorTex_Subsurf_CoatWeight & LOWER_24_BITS_MASK) |\n                (Math::FloatToUNorm8(w) << (NUM_TEXTURE_BITS + 8));\n        }\n\n        ZetaInline void SetTransmissionDepth(float depth)\n        {\n            Math::half dh(depth);\n            NormalTex_TrDepth = (NormalTex_TrDepth & TEXTURE_MASK) |\n                (uint32(dh.x) << NUM_TEXTURE_BITS);\n        }\n\n        ZetaInline void SetCoatColor(const Math::float3& color)\n        {\n            CoatColor_Flags = Float3ToRGB8(color) | (CoatColor_Flags & UPPER_8_BITS_MASK);\n        }\n\n        ZetaInline void SetAlphaMode(ALPHA_MODE mode)\n        {\n            // Clear two alpha bits\n            CoatColor_Flags &= ~(0x3 << FLAG_BITS::ALPHA_1);\n            CoatColor_Flags |= (uint32_t)(mode) << FLAG_BITS::ALPHA_1;\n        }\n\n        ZetaInline void SetDoubleSided(bool b)\n        {\n            if (b)\n                CoatColor_Flags |= (1 << FLAG_BITS::DOUBLE_SIDED);\n            else\n                CoatColor_Flags &= ~(1 << FLAG_BITS::DOUBLE_SIDED);\n        }\n\n        ZetaInline void SetTransmission(float t)\n        {\n            bool transmissive = t >= MIN_SPEC_TR_TRANSMISSIVE;\n            if (transmissive)\n                CoatColor_Flags |= (1 << FLAG_BITS::TRANSMISSIVE);\n            else\n                CoatColor_Flags &= ~(1 << FLAG_BITS::TRANSMISSIVE);\n        }\n\n        ZetaInline void SetMetallic(float m)\n        {\n            bool metallic = m >= MIN_METALNESS_METAL;\n            if (metallic)\n                CoatColor_Flags |= (1 << FLAG_BITS::METALLIC);\n            else\n                CoatColor_Flags &= ~(1 << FLAG_BITS::METALLIC);\n        }\n\n        ZetaInline void SetThinWalled(bool b)\n        {\n            if (b)\n                CoatColor_Flags |= (1 << FLAG_BITS::THIN_WALLED);\n            else\n                CoatColor_Flags &= ~(1 << FLAG_BITS::THIN_WALLED);\n        }\n\n        bool Emissive() const\n        {\n            if (GetEmissiveTex() != INVALID_ID)\n                return true;\n\n            Math::float3 f = GetEmissiveFactor();\n            return f.dot(f) > 0;\n        }\n#endif\n        bool DoubleSided() CONST\n        {\n            return CoatColor_Flags & (1u << FLAG_BITS::DOUBLE_SIDED);\n        }\n\n        bool Metallic() CONST\n        {\n            return CoatColor_Flags & (1u << FLAG_BITS::METALLIC);\n        }\n\n        bool Transmissive() CONST\n        {\n            return CoatColor_Flags & (1u << FLAG_BITS::TRANSMISSIVE);\n        }\n\n        bool ThinWalled() CONST\n        {\n            return CoatColor_Flags & (1u << FLAG_BITS::THIN_WALLED);\n        }\n\n        float3_ GetBaseColorFactor() CONST\n        {\n            return Math::UnpackRGB8(BaseColorFactor);\n        }\n\n        float3_ GetCoatColor() CONST\n        {\n            return Math::UnpackRGB8(CoatColor_Flags);\n        }\n\n        float3_ GetEmissiveFactor() CONST\n        {\n            return Math::UnpackRGB8(EmissiveFactor_NormalScale);\n        }\n\n        float GetNormalScale() CONST\n        {\n            return Math::UNorm8ToFloat(EmissiveFactor_NormalScale >> 24);\n        }\n\n        uint32_t GetBaseColorTex() CONST\n        {\n            return BaseColorTex_Subsurf_CoatWeight & TEXTURE_MASK;\n        }\n\n        uint32_t GetNormalTex() CONST\n        {\n            return NormalTex_TrDepth & TEXTURE_MASK;\n        }\n\n        uint32_t GetMetallicRoughnessTex() CONST\n        {\n            return MRTex_SpecRoughness_CoatRoughness & TEXTURE_MASK;\n        }\n\n        uint32_t GetEmissiveTex() CONST\n        {\n            return EmissiveTex_AlphaCutoff_CoatIOR & TEXTURE_MASK;\n        }\n\n        float GetAlphaCutoff() CONST\n        {\n            uint32_t bits16To24 = (EmissiveTex_AlphaCutoff_CoatIOR >> NUM_MATERIAL_BITS) & 0xff;\n#ifdef __cplusplus\n            return Math::UNorm8ToFloat((uint8_t)bits16To24);\n#else\n            return Math::UNorm8ToFloat(bits16To24);\n#endif\n        }\n\n        float GetCoatIOR() CONST\n        {\n            uint32_t bits24To32 = (EmissiveTex_AlphaCutoff_CoatIOR >> (NUM_MATERIAL_BITS + 8)) & 0xff;\n#ifdef __cplusplus\n            return std::fmaf(1.5f / float(((1 << 8) - 1)), (float)bits24To32, MIN_IOR);\n#else\n            return mad(1.5f / float(((1 << 8) - 1)), (float)bits24To32, MIN_IOR);\n#endif\n        }\n\n        float GetSpecularRoughness() CONST\n        {\n            uint32_t bits16To24 = (MRTex_SpecRoughness_CoatRoughness >> NUM_MATERIAL_BITS) & 0xff;\n#ifdef __cplusplus\n            return Math::UNorm8ToFloat((uint8_t)bits16To24);\n#else\n            return Math::UNorm8ToFloat(bits16To24);\n#endif\n        }\n\n        float GetCoatRoughness() CONST\n        {\n            uint32_t bits24To32 = (MRTex_SpecRoughness_CoatRoughness >> (NUM_MATERIAL_BITS + 8)) & 0xff;\n#ifdef __cplusplus\n            return Math::UNorm8ToFloat((uint8_t)bits24To32);\n#else\n            return Math::UNorm8ToFloat(bits24To32);\n#endif\n        }\n\n        half_ GetEmissiveStrength() CONST\n        {\n#ifdef __cplusplus\n            return Math::half::asfloat16(uint16_t(EmissiveStrength_IOR & LOWER_16_BITS_MASK));\n#else\n            return asfloat16(uint16_t(EmissiveStrength_IOR & LOWER_16_BITS_MASK));\n#endif\n        }\n\n        float GetSpecularIOR() CONST\n        {\n            uint16_t encoded = uint16_t(EmissiveStrength_IOR >> 16);\n#ifdef __cplusplus\n            return std::fmaf(1.5f / float(((1 << 16) - 1)), encoded, MIN_IOR);\n#else\n            return mad(1.5f / float(((1 << 16) - 1)), encoded, MIN_IOR);\n#endif\n        }\n\n        half_ GetTransmissionDepth()\n        {\n            uint16_t upper16Bits = uint16_t(NormalTex_TrDepth >> NUM_TEXTURE_BITS);\n#ifdef __cplusplus\n            return Math::half::asfloat16(upper16Bits);\n#else\n            return asfloat16(upper16Bits);\n#endif\n        }\n\n        float GetSubsurface() CONST\n        {\n            uint32_t bits16To24 = (BaseColorTex_Subsurf_CoatWeight >> NUM_MATERIAL_BITS) & 0xff;\n#ifdef __cplusplus\n            return Math::UNorm8ToFloat((uint8_t)bits16To24);\n#else\n            return Math::UNorm8ToFloat(bits16To24);\n#endif\n        }\n\n        float GetCoatWeight() CONST\n        {\n            uint32_t bits24To32 = (BaseColorTex_Subsurf_CoatWeight >> (NUM_MATERIAL_BITS + 8)) & 0xff;\n#ifdef __cplusplus\n            return Math::UNorm8ToFloat((uint8_t)bits24To32);\n#else\n            return Math::UNorm8ToFloat(bits24To32);\n#endif\n        }\n\n        uint32_t BaseColorFactor;\n        uint32_t BaseColorTex_Subsurf_CoatWeight;\n        uint32_t NormalTex_TrDepth;\n        // MR stands for metallic roughness\n        uint32_t MRTex_SpecRoughness_CoatRoughness;\n        uint32_t EmissiveFactor_NormalScale;\n        uint32_t EmissiveStrength_IOR;\n        uint32_t EmissiveTex_AlphaCutoff_CoatIOR;\n\n        uint32_t CoatColor_Flags;\n    };\n#ifdef __cplusplus\n}\n#endif\n\n#ifndef __cplusplus\n#define BASE_COLOR_MAP Texture2D<float4>\n#define NORMAL_MAP Texture2D<float2>\n#define METALLIC_ROUGHNESS_MAP Texture2D<float2>\n#define EMISSIVE_MAP Texture2D<float3>\n#endif\n\n#endif"
  },
  {
    "path": "Source/ZetaCore/Core/PipelineStateLibrary.cpp",
    "content": "#include \"PipelineStateLibrary.h\"\n#include \"RendererCore.h\"\n#include \"../App/Log.h\"\n#include <App/Common.h>\n#include <App/Timer.h>\n#include <Support/Task.h>\n#include <Scene/SceneCore.h>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::App;\nusing namespace ZetaRay::Support;\n\n#define LOGGING 1\n\nnamespace\n{\n    ZetaInline void InitPipe(HANDLE& readPipe, HANDLE& writePipe)\n    {\n        SECURITY_ATTRIBUTES saAttr;\n        saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);\n        saAttr.bInheritHandle = true;\n        saAttr.lpSecurityDescriptor = nullptr;\n\n        CheckWin32(CreatePipe(&readPipe, &writePipe, &saAttr, 0));\n        CheckWin32(SetHandleInformation(readPipe, HANDLE_FLAG_INHERIT, 0));\n    }\n\n    ZetaInline void ReleasePipe(HANDLE readPipe, HANDLE writePipe)\n    {\n        CloseHandle(writePipe);\n\n        constexpr int MAX_TO_READ = 1024;\n        void* buffer = App::AllocateFrameAllocator(MAX_TO_READ, alignof(char));\n        DWORD numToRead;\n        if (ReadFile(readPipe, buffer, MAX_TO_READ, &numToRead, nullptr))\n        {\n            if (numToRead)\n            {\n                reinterpret_cast<char*>(buffer)[numToRead] = '\\0';\n                App::Log(reinterpret_cast<char*>(buffer), App::LogMessage::WARNING);\n            }\n        }\n\n        CloseHandle(readPipe);\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// PipelineStateLibrary\n//--------------------------------------------------------------------------------------\n\nPipelineStateLibrary::PipelineStateLibrary(MutableSpan<ID3D12PipelineState*> psoCache)\n    : m_compiledPSOs(psoCache)\n{}\n\nPipelineStateLibrary::~PipelineStateLibrary()\n{\n    ClearAndFlushToDisk();\n}\n\nvoid PipelineStateLibrary::Init(const char* name)\n{\n    StackStr(filename, n, \"%s.cache\", name);\n    m_psoLibPath1.Reset(App::GetPSOCacheDir());\n    m_psoLibPath1.Append(filename);\n\n    m_foundOnDisk = Filesystem::Exists(m_psoLibPath1.Get()) && \n        Filesystem::GetFileSize(m_psoLibPath1.Get()) > 0;\n\n    // PSO cache exists on disk, reload it\n    if (m_foundOnDisk)\n    {\n        Filesystem::LoadFromFile(m_psoLibPath1.Get(), m_cachedBlob);\n\n        auto* device = App::GetRenderer().GetDevice();\n        HRESULT hr = device->CreatePipelineLibrary(m_cachedBlob.data(), m_cachedBlob.size(),\n            IID_PPV_ARGS(m_psoLibrary.GetAddressOf()));\n\n        if (FAILED(hr))\n        {\n            if (hr == E_INVALIDARG)\n                LOG_UI_INFO(\"PSO cache %s is corrupted.\\n\", m_psoLibPath1.Get());\n\n            if (hr == D3D12_ERROR_DRIVER_VERSION_MISMATCH)\n                LOG_UI_INFO(\"PSO cache %s has driver mismatch.\\n\", m_psoLibPath1.Get());\n\n            if (hr == D3D12_ERROR_ADAPTER_NOT_FOUND)\n                LOG_UI_INFO(\"PSO cache %s was created using a different hardware than the one being used right now.\\n\", m_psoLibPath1.Get());\n\n            Check(hr == E_INVALIDARG || hr == D3D12_ERROR_DRIVER_VERSION_MISMATCH || hr == D3D12_ERROR_ADAPTER_NOT_FOUND,\n                \"CreatePipelineLibrary() failed with HRESULT %d\", hr);\n\n            ResetToEmptyPsoLib();\n        }\n    }\n    else\n        ResetToEmptyPsoLib();\n}\n\nvoid PipelineStateLibrary::Reset()\n{\n    ClearAndFlushToDisk();\n    m_psoWasReset = false;\n\n    m_cachedBlob.free_memory();\n    memset(m_compiledPSOs.data(), 0, m_compiledPSOs.size() * sizeof(ID3D12PipelineState*));\n}\n\nvoid PipelineStateLibrary::ResetToEmptyPsoLib()\n{\n    // Avoid resetting twice\n    if (!m_psoWasReset)\n    {\n        auto* device = App::GetRenderer().GetDevice();\n        CheckHR(device->CreatePipelineLibrary(nullptr, 0, \n            IID_PPV_ARGS(m_psoLibrary.ReleaseAndGetAddressOf())));\n\n        m_psoWasReset = true;\n    }\n\n    m_needsRebuild.store(true, std::memory_order_relaxed);\n}\n\nvoid PipelineStateLibrary::ClearAndFlushToDisk()\n{\n    // Needed when:\n    //  1. Cached library was invalid (e.g. driver mismatch)\n    //  2. One of the PSOs didn't match (e.g. modification after library was written to disk)\n    //  3. Shader hot-reload\n    if (m_needsRebuild.load(std::memory_order_relaxed))\n    {\n        // Create an empty PSO and release the existing one\n        ResetToEmptyPsoLib();\n\n        if (m_foundOnDisk)\n        {\n            Filesystem::RemoveFile(m_psoLibPath1.Get());\n            m_cachedBlob.free_memory();\n            m_foundOnDisk = false;\n        }\n\n        // Store all the compiled PSOs in the new library\n        for (int idx = 0; idx < (int)m_compiledPSOs.size(); idx++)\n        {\n            if (!m_compiledPSOs[idx])\n                continue;\n\n            wchar_t nameWide[8];\n            StackStr(name, n, \"%d\", idx);\n            Common::CharToWideStr(name, nameWide);\n\n            CheckHR(m_psoLibrary->StorePipeline(nameWide, m_compiledPSOs[idx]));\n        }\n\n        m_needsRebuild.store(false, std::memory_order_relaxed);\n    }\n\n    if (m_psoLibrary)\n    {\n        if (!m_foundOnDisk)\n        {\n            const size_t serializedSize = m_psoLibrary->GetSerializedSize();\n            Assert(serializedSize > 0, \"Serialized size was invalid.\");\n            uint8_t* psoLib = (uint8_t*)malloc(serializedSize);\n\n            CheckHR(m_psoLibrary->Serialize(psoLib, serializedSize));\n            Filesystem::WriteToFile(m_psoLibPath1.Get(), psoLib, (uint32_t)serializedSize);\n\n            free(psoLib);\n        }\n\n        m_psoLibrary = nullptr;\n    }\n\n    for (auto pso : m_compiledPSOs)\n    {\n        // Note: PSO array is zero initialized, so PSOs that were never compiled\n        // are just NULL.\n        if(pso)\n            pso->Release();\n    }\n}\n\nvoid PipelineStateLibrary::Reload(uint64_t idx, ID3D12RootSignature* rootSig, \n    const char* pathToHlsl, bool flushGpu)\n{\n    Filesystem::Path hlsl(App::GetRenderPassDir());\n    hlsl.Append(pathToHlsl);\n    Assert(Filesystem::Exists(hlsl.Get()), \"Path doesn't exist: %s\", hlsl.Get());\n\n    char filename[MAX_PATH];\n    hlsl.Stem(filename);\n\n    StackStr(csoFilename, N, \"%s_cs.cso\", filename);\n    Filesystem::Path csoPath(App::GetCompileShadersDir());\n    csoPath.Append(csoFilename);\n\n#if !defined(NDEBUG) && defined(HAS_DEBUG_SHADERS)\n    StackStr(cmdLine, n, \"%s -T cs_6_7 -Fo %s -E main -Zi -Od -all_resources_bound -nologo -enable-16bit-types -Qembed_debug -Qstrip_reflect -WX -HV 202x %s\", App::GetDXCPath(), csoPath.Get(), hlsl.Get());\n#else\n    StackStr(cmdLine, n, \"%s -T cs_6_7 -Fo %s -E main -all_resources_bound -nologo -enable-16bit-types -Qstrip_reflect -WX -HV 202x %s\", App::GetDXCPath(), csoPath.Get(), hlsl.Get());\n#endif\n\n#if LOGGING == 1\n    App::DeltaTimer timer;\n    timer.Start();\n#endif\n\n    HANDLE readPipe;\n    HANDLE writePipe;\n    InitPipe(readPipe, writePipe);\n\n    PROCESS_INFORMATION pi;\n    STARTUPINFO si{};\n    si.cb = sizeof(si);\n    si.hStdOutput = writePipe;\n    si.hStdError = writePipe;\n    si.dwFlags = STARTF_USESTDHANDLES;\n    CheckWin32(CreateProcessA(nullptr, cmdLine, nullptr, nullptr, true, CREATE_NO_WINDOW, \n        nullptr, nullptr, &si, &pi));\n\n    WaitForSingleObject(pi.hProcess, INFINITE);\n    CloseHandle(pi.hThread);\n    CloseHandle(pi.hProcess);\n\n    ReleasePipe(readPipe, writePipe);\n\n    // Recreate the PSO\n    SmallVector<uint8_t> bytecode;\n    Filesystem::LoadFromFile(csoPath.Get(), bytecode);\n\n    D3D12_COMPUTE_PIPELINE_STATE_DESC desc{};\n    desc.pRootSignature = rootSig;\n    desc.CS.BytecodeLength = bytecode.size();\n    desc.CS.pShaderBytecode = bytecode.data();\n\n    auto* device = App::GetRenderer().GetDevice();\n    ID3D12PipelineState* pso = nullptr;\n    CheckHR(device->CreateComputePipelineState(&desc, IID_PPV_ARGS(&pso)));\n\n#if LOGGING == 1\n    timer.End();\n    LOG_UI_INFO(\"Reloaded shader %s in %u [ms].\", pathToHlsl, (uint32_t)timer.DeltaMilli());\n#endif\n\n    m_needsRebuild.store(true, std::memory_order_relaxed);\n\n    ID3D12PipelineState* oldPSO = m_compiledPSOs[idx];\n    Assert(oldPSO, \"Reload was called for a shader that hasn't been loaded yet.\");\n\n    // GPU has to be finished with the old PSO before it can be released\n    if (flushGpu)\n    {\n        App::GetRenderer().FlushAllCommandQueues();\n        oldPSO->Release();\n    }\n    else\n    {\n        // Wait on a background thread for GPU\n        Task t(\"WaitForGpu\", TASK_PRIORITY::BACKGROUND, [oldPSO]()\n            {\n                auto& renderer = App::GetRenderer();\n\n                ComPtr<ID3D12Fence> fence;\n                CheckHR(renderer.GetDevice()->CreateFence(0, D3D12_FENCE_FLAG_NONE, \n                    IID_PPV_ARGS(fence.GetAddressOf())));\n\n                const uint64_t fenceToWaitFor = 1;\n                renderer.SignalDirectQueue(fence.Get(), fenceToWaitFor);\n\n                HANDLE fenceEvent = CreateEventA(nullptr, false, false, nullptr);\n                CheckWin32(fenceEvent);\n\n                CheckHR(fence->SetEventOnCompletion(fenceToWaitFor, fenceEvent));\n                WaitForSingleObject(fenceEvent, INFINITE);\n\n                CloseHandle(fenceEvent);\n\n                oldPSO->Release();\n            });\n\n        App::SubmitBackground(ZetaMove(t));\n    }\n\n    // Replace the old PSO\n    m_compiledPSOs[idx] = pso;\n    \n    App::GetScene().SceneModified();\n}\n\nID3D12PipelineState* PipelineStateLibrary::CompileGraphicsPSO(uint32_t idx,\n    D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc, ID3D12RootSignature* rootSig,\n    const char* pathToCompiledVS,\n    const char* pathToCompiledPS)\n{\n    SmallVector<uint8_t> vsBytecode;\n    SmallVector<uint8_t> psBytecode;\n\n    {\n        Filesystem::Path pVs(App::GetCompileShadersDir());\n        pVs.Append(pathToCompiledVS);\n        Filesystem::LoadFromFile(pVs.Get(), vsBytecode);\n    }\n\n    {\n        Filesystem::Path pPs(App::GetCompileShadersDir());\n        pPs.Append(pathToCompiledPS);\n        Filesystem::LoadFromFile(pPs.Get(), psBytecode);\n    }\n\n    psoDesc.VS.BytecodeLength = vsBytecode.size();\n    psoDesc.VS.pShaderBytecode = vsBytecode.data();\n    psoDesc.PS.BytecodeLength = psBytecode.size();\n    psoDesc.PS.pShaderBytecode = psBytecode.data();\n    psoDesc.pRootSignature = rootSig;\n\n    wchar_t nameWide[8];\n    StackStr(name, n, \"%u\", idx);\n    Common::CharToWideStr(name, nameWide);\n\n    ID3D12PipelineState* pso = nullptr;\n    HRESULT hr = m_psoWasReset ? E_INVALIDARG :\n        m_psoLibrary->LoadGraphicsPipeline(nameWide, &psoDesc, IID_PPV_ARGS(&pso));\n\n    if (hr == E_INVALIDARG)\n    {\n        m_needsRebuild.store(true, std::memory_order_relaxed);\n\n        auto* device = App::GetRenderer().GetDevice();\n        CheckHR(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pso)));\n    }\n\n    Assert(m_compiledPSOs[idx] == nullptr, \"It's assumed that every PSO is loaded at most one time.\");\n    m_compiledPSOs[idx] = pso;\n\n    return pso;\n}\n\nID3D12PipelineState* PipelineStateLibrary::CompileComputePSO(uint32_t idx, \n    ID3D12RootSignature* rootSig, const char* pathToCompiledCS)\n{\n    Filesystem::Path pCs(App::GetCompileShadersDir());\n    pCs.Append(pathToCompiledCS);\n\n    SmallVector<uint8_t> bytecode;\n    Filesystem::LoadFromFile(pCs.Get(), bytecode);\n\n    D3D12_COMPUTE_PIPELINE_STATE_DESC desc{};\n    desc.pRootSignature = rootSig;\n    desc.CS.BytecodeLength = bytecode.size();\n    desc.CS.pShaderBytecode = bytecode.data();\n\n    wchar_t nameWide[8];\n    StackStr(name, n, \"%u\", idx);\n    Common::CharToWideStr(name, nameWide);\n\n    ID3D12PipelineState* pso = nullptr;\n    HRESULT hr = m_psoWasReset ? E_INVALIDARG :\n        m_psoLibrary->LoadComputePipeline(nameWide, &desc, IID_PPV_ARGS(&pso));\n\n    if (hr == E_INVALIDARG)\n    {\n        m_needsRebuild.store(true, std::memory_order_relaxed);\n\n#if LOGGING == 1\n        App::DeltaTimer timer;\n        timer.Start();\n#endif\n\n        auto* device = App::GetRenderer().GetDevice();\n        CheckHR(device->CreateComputePipelineState(&desc, IID_PPV_ARGS(&pso)));\n\n#if LOGGING == 1\n        timer.End();\n        LOG_UI_INFO(\"Compiled shader %s in %u [ms].\", pathToCompiledCS, (uint32_t)timer.DeltaMilli());\n#endif\n    }\n\n    Assert(m_compiledPSOs[idx] == nullptr, \"It's assumed that every PSO is loaded at most one time.\");\n    m_compiledPSOs[idx] = pso;\n\n    return pso;\n}\n\nID3D12PipelineState* PipelineStateLibrary::CompileComputePSO_MT(uint32_t idx, \n    ID3D12RootSignature* rootSig, const char* pathToCompiledCS)\n{\n    Filesystem::Path pCs(App::GetCompileShadersDir());\n    pCs.Append(pathToCompiledCS);\n\n    SmallVector<uint8_t> bytecode;\n    Filesystem::LoadFromFile(pCs.Get(), bytecode);\n\n    D3D12_COMPUTE_PIPELINE_STATE_DESC desc{};\n    desc.pRootSignature = rootSig;\n    desc.CS.BytecodeLength = bytecode.size();\n    desc.CS.pShaderBytecode = bytecode.data();\n\n    wchar_t nameWide[8];\n    StackStr(name, n, \"%u\", idx);\n    Common::CharToWideStr(name, nameWide);\n\n    // MS docs: \"The pipeline library is thread-safe to use, and will internally synchronize \n    // as necessary, with one exception: multiple threads loading the same PSO (via LoadComputePipeline, \n    // LoadGraphicsPipeline, or LoadPipeline) should synchronize themselves, as this act may modify \n    // the state of that pipeline within the library in a non-thread-safe manner.\"\n    ID3D12PipelineState* pso = nullptr;\n    HRESULT hr = m_psoWasReset ? E_INVALIDARG :\n        m_psoLibrary->LoadComputePipeline(nameWide, &desc, IID_PPV_ARGS(&pso));\n\n    // A PSO with the specified name doesn’t exist, or the input desc doesn’t match the data in\n    // the library. Compile the PSO and then store it in the library for next time.\n    if (hr == E_INVALIDARG)\n    {\n        // If some PSO is modified or not found, then the PSO library needs to be recreated.\n        m_needsRebuild.store(true, std::memory_order_relaxed);\n\n        auto* device = App::GetRenderer().GetDevice();\n#if LOGGING == 1\n        App::DeltaTimer timer;\n        timer.Start();\n#endif\n        CheckHR(device->CreateComputePipelineState(&desc, IID_PPV_ARGS(&pso)));\n\n#if LOGGING == 1\n        timer.End();\n        LOG_UI_INFO(\"Compiled shader %s in %u [ms].\", pathToCompiledCS, (uint32_t)timer.DeltaMilli());\n#endif\n    }\n\n    AcquireSRWLockExclusive(&m_mapLock);\n    Assert(m_compiledPSOs[idx] == nullptr, \"It's assumed that every PSO is loaded at most one time.\");\n    m_compiledPSOs[idx] = pso;\n    ReleaseSRWLockExclusive(&m_mapLock);\n\n    return pso;\n}\n\nID3D12PipelineState* PipelineStateLibrary::CompileComputePSO(uint32_t idx, \n    ID3D12RootSignature* rootSig, Span<const uint8_t> compiledBlob)\n{\n    D3D12_COMPUTE_PIPELINE_STATE_DESC desc{};\n    desc.pRootSignature = rootSig;\n    desc.CS.BytecodeLength = compiledBlob.size();\n    desc.CS.pShaderBytecode = compiledBlob.data();\n\n    wchar_t nameWide[8];\n    StackStr(name, n, \"%u\", idx);\n    Common::CharToWideStr(name, nameWide);\n\n    ID3D12PipelineState* pso = nullptr;\n    HRESULT hr = m_psoWasReset ? E_INVALIDARG : \n        m_psoLibrary->LoadComputePipeline(nameWide, &desc, IID_PPV_ARGS(&pso));\n\n    if (hr == E_INVALIDARG)\n    {\n        m_needsRebuild.store(true, std::memory_order_relaxed);\n\n        auto* device = App::GetRenderer().GetDevice();\n        CheckHR(device->CreateComputePipelineState(&desc, IID_PPV_ARGS(&pso)));\n    }\n\n    Assert(m_compiledPSOs[idx] == nullptr, \"It's assumed that every PSO is loaded at most one time.\");\n    m_compiledPSOs[idx] = pso;\n\n    return pso;\n}\n"
  },
  {
    "path": "Source/ZetaCore/Core/PipelineStateLibrary.h",
    "content": "#pragma once\n\n#include \"../Core/Device.h\"\n#include \"../App/Path.h\"\n#include <atomic>\n\nnamespace ZetaRay::Core\n{\n    class PipelineStateLibrary\n    {\n    public:\n        explicit PipelineStateLibrary(Util::MutableSpan<ID3D12PipelineState*> psoCache);\n        ~PipelineStateLibrary();\n\n        PipelineStateLibrary(PipelineStateLibrary&&) = delete;\n        PipelineStateLibrary& operator=(PipelineStateLibrary&&) = delete;\n\n        void Init(const char* name);\n        void Reset();\n        void Reload(uint64_t idx, ID3D12RootSignature* rootSig, const char* pathToHlsl, \n            bool flushGpu = false);\n\n        ID3D12PipelineState* CompileGraphicsPSO(uint32_t idx,\n            D3D12_GRAPHICS_PIPELINE_STATE_DESC& psoDesc,\n            ID3D12RootSignature* rootSig,\n            const char* pathToCompiledVS,\n            const char* pathToCompiledPS);\n        ID3D12PipelineState* CompileComputePSO(uint32_t idx,\n            ID3D12RootSignature* rootSig,\n            const char* pathToCompiledCS);\n        ID3D12PipelineState* CompileComputePSO_MT(uint32_t idx,\n            ID3D12RootSignature* rootSig,\n            const char* pathToCompiledCS);\n        ID3D12PipelineState* CompileComputePSO(uint32_t idx,\n            ID3D12RootSignature* rootSig,\n            Util::Span<const uint8_t> compiledBlob);\n\n        ZetaInline ID3D12PipelineState* GetPSO(uint32_t idx)\n        {\n            return m_compiledPSOs[idx];\n        }\n\n    private:\n        void ResetToEmptyPsoLib();\n        void ClearAndFlushToDisk();\n\n        App::Filesystem::Path m_psoLibPath1;\n        ComPtr<ID3D12PipelineLibrary> m_psoLibrary;\n        Util::MutableSpan<ID3D12PipelineState*> m_compiledPSOs;\n        Util::SmallVector<uint8_t> m_cachedBlob;\n\n        SRWLOCK m_mapLock = SRWLOCK_INIT;\n        std::atomic_bool m_needsRebuild = false;\n        bool m_foundOnDisk = false;\n        bool m_psoWasReset = false;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Core/RenderGraph.cpp",
    "content": "// Some of the ideas in this implementation were inspired by the following: \n// https://levelup.gitconnected.com/organizing-gpu-work-with-directed-acyclic-graphs-f3fd5f2c2af3\n\n#include \"RenderGraph.h\"\n#include \"RendererCore.h\"\n#include \"CommandList.h\"\n#include \"../Support/Task.h\"\n#include \"../App/Timer.h\"\n#include \"../Utility/Utility.h\"\n#include <algorithm>\n#include <xxHash/xxhash.h>\n#include <ImGui/imnodes.h>\n\n#ifndef NDEBUG\n#include \"../App/Log.h\"\n#include <string>\n#endif\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::Direct3DUtil;\n\nnamespace\n{\n    const char* GetResStateName(D3D12_RESOURCE_STATES s)\n    {\n        switch (s)\n        {\n        case D3D12_RESOURCE_STATE_COMMON:\n            return \"COMMON_OR_PRESENT\";\n        case D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER:\n            return \"VERTEX_AND_CONSTANT_BUFFER\";\n        case D3D12_RESOURCE_STATE_INDEX_BUFFER:\n            return \"INDEX_BUFFER\";\n        case D3D12_RESOURCE_STATE_RENDER_TARGET:\n            return \"RENDER_TARGET\";\n        case D3D12_RESOURCE_STATE_UNORDERED_ACCESS:\n            return \"UNORDERED_ACCESS\";\n        case D3D12_RESOURCE_STATE_DEPTH_WRITE:\n            return \"DEPTH_WRITE\";\n        case D3D12_RESOURCE_STATE_DEPTH_READ:\n            return \"DEPTH_READ\";\n        case D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE:\n            return \"NON_PIXEL_SHADER_RESOURCE\";\n        case D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE:\n            return \"PIXEL_SHADER_RESOURCE\";\n        case D3D12_RESOURCE_STATE_COPY_DEST:\n            return \"COPY_DEST\";\n        case D3D12_RESOURCE_STATE_COPY_SOURCE:\n            return \"COPY_SOURCE\";\n        case D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE:\n            return \"RAYTRACING_ACCELERATION_STRUCTURE\";\n        case D3D12_RESOURCE_STATE_GENERIC_READ:\n            return \"GENERIC_READ\";\n        case D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE:\n            return \"ALL_SHADER_RESOURCE\";\n        default:\n            return \"UNKNOWN\";\n        }\n    }\n\n    struct Edge\n    {\n        int E0;\n        int E1;\n    };\n}\n\n//--------------------------------------------------------------------------------------\n// AggregateRenderNode\n//--------------------------------------------------------------------------------------\n\nvoid RenderGraph::AggregateRenderNode::Append(const RenderNode& node, int mappedGpeDepIdx, \n    bool forceSeparate)\n{\n    Assert(IsAsyncCompute == (node.Type == RENDER_NODE_TYPE::ASYNC_COMPUTE), \n        \"All the nodes in an AggregateRenderNode must have the same type.\");\n    Assert(Dlgs.empty() || node.NodeBatchIdx == BatchIdx, \n        \"All the nodes in an AggregateRenderNode must have the same batch index.\");\n    Assert(!forceSeparate || Dlgs.empty(), \n        \"Aggregate nodes with forceSeparate flag can't have more than one task.\");\n    Assert(!node.HasUnsupportedBarrier || node.Type == RENDER_NODE_TYPE::ASYNC_COMPUTE, \n        \"Invalid condition.\");\n\n    Barriers.append_range(node.Barriers.begin(), node.Barriers.end());\n    Dlgs.push_back(node.Dlg);\n    BatchIdx = node.NodeBatchIdx;\n    ForceSeparate = forceSeparate;\n    GpuDepIdx.Val = Math::Max(GpuDepIdx.Val, mappedGpeDepIdx);\n    HasUnsupportedBarrier = !HasUnsupportedBarrier ? node.HasUnsupportedBarrier : true;\n\n    int base = Dlgs.size() > 1 ? (int)strlen(Name) : 0;\n\n    if (base)\n    {\n        Name[base] = '_';\n        base++;\n    }\n\n    int numBytesToCopy = Math::Min(MAX_NAME_LENGTH - base - 1, (int)strlen(node.Name));\n    Assert(numBytesToCopy, \"bug\");\n\n    memcpy(Name + base, node.Name, numBytesToCopy);\n    Name[base + numBytesToCopy] = '\\0';\n}\n\n//--------------------------------------------------------------------------------------\n// RenderGraph\n//--------------------------------------------------------------------------------------\n\nvoid RenderGraph::Shutdown()\n{\n    m_frameResources.free_memory();\n\n    for (int i = 0; i < MAX_NUM_RENDER_PASSES; i++)\n    {\n        m_renderNodes[i].Inputs.free_memory();\n        m_renderNodes[i].Outputs.free_memory();\n        m_renderNodes[i].Barriers.free_memory();\n    }\n}\n\nvoid RenderGraph::Reset()\n{\n    //m_frameResources.clear();\n    m_frameResources.resize(MAX_NUM_RESOURCES);\n\n    // Sort the frame resources so that window-dependent ones come after window-independent ones\n    auto it = std::partition(m_frameResources.begin(), m_frameResources.begin() + m_prevFramesNumResources,\n        [](ResourceMetadata& res)\n        {\n            return res.IsWindowSizeDependent == false;\n        });\n\n    const size_t numRemaining = it - m_frameResources.begin();\n\n    for (size_t i = numRemaining; i < m_prevFramesNumResources; i++)\n        m_frameResources[i].Reset();\n\n    std::sort(m_frameResources.begin(), m_frameResources.begin() + numRemaining,\n        [](ResourceMetadata& lhs, ResourceMetadata& rhs)\n        {\n            return lhs.ID < rhs.ID;\n        });\n\n    m_prevFramesNumResources = (int)numRemaining;\n    m_lastResIdx = (int)numRemaining;\n\n    // Reset the render nodes\n    const int numNodes = m_currRenderPassIdx.load(std::memory_order_relaxed);\n\n    for (int currNode = 0; currNode < numNodes; currNode++)\n        m_renderNodes[currNode].Reset();\n\n    m_aggregateNodes.free_memory();\n    m_currRenderPassIdx.store(0, std::memory_order_relaxed);\n}\n\nvoid RenderGraph::RemoveResource(uint64_t path)\n{\n    Assert(!m_inBeginEndBlock, \"Invalid call.\");\n    const int pos = FindFrameResource(path, 0, m_prevFramesNumResources - 1);\n\n    if (pos != -1)\n    {\n        m_lastResIdx.fetch_sub(1, std::memory_order_relaxed);\n        m_frameResources[pos].Reset();\n\n        // Insertion sort\n        for (int i = pos; i < m_prevFramesNumResources; i++)\n            m_frameResources[i] = ZetaMove(m_frameResources[i + 1]);\n    }\n}\n\nvoid RenderGraph::RemoveResources(Util::Span<uint64_t> paths)\n{\n    Assert(!m_inBeginEndBlock, \"Invalid call.\");\n    int numRemoved = 0;\n\n    for (auto p : paths)\n    {\n        int pos = FindFrameResource(p, 0, m_prevFramesNumResources - 1);\n\n        if (pos != -1)\n        {\n            m_frameResources[pos].Reset();\n            numRemoved++;\n        }\n    }\n\n    std::sort(m_frameResources.begin(), m_frameResources.begin() + m_prevFramesNumResources,\n        [](ResourceMetadata& lhs, ResourceMetadata& rhs)\n        {\n            return lhs.ID < rhs.ID;\n        });\n\n    m_lastResIdx.fetch_sub(numRemoved, std::memory_order_relaxed);\n}\n\nvoid RenderGraph::BeginFrame()\n{\n    Assert(!m_inBeginEndBlock && !m_inPreRegister, \"Invalid call.\");\n    m_prevFramesNumResources = m_lastResIdx.load(std::memory_order_relaxed);\n\n    const int numNodes = m_currRenderPassIdx.load(std::memory_order_relaxed);\n    //m_numPassesPrevFrame = numNodes;\n    m_currRenderPassIdx.store(0, std::memory_order_relaxed);\n\n    // Reset the producers\n    for (auto& rm : m_frameResources)\n    {\n        rm.CurrProdIdx.store(0, std::memory_order_relaxed);\n\n        for (int i = 0; i < MAX_NUM_PRODUCERS; i++)\n            rm.Producers[i].Val = INVALID_NODE_HANDLE;\n    }\n\n    // Reset the render nodes\n    for (int currNode = 0; currNode < MAX_NUM_RENDER_PASSES; currNode++)\n        m_renderNodes[currNode].Reset();\n\n    m_aggregateNodes.free_memory();\n    m_inBeginEndBlock = true;\n    m_inPreRegister = true;\n}\n\nint RenderGraph::FindFrameResource(uint64_t key, int beg, int end)\n{\n    if (end - beg == 0)\n        return -1;\n\n    end = (end == -1) ? m_lastResIdx.load(std::memory_order_relaxed) - 1 : end;\n    auto idx = BinarySearch(Span(m_frameResources), key, \n        [](const ResourceMetadata& r) {return r.ID; }, beg, end);\n    return (int)idx;\n}\n\nRenderNodeHandle RenderGraph::RegisterRenderPass(const char* name, RENDER_NODE_TYPE t, \n    fastdelegate::FastDelegate1<CommandList&> dlg, bool forceSeparateCmdList)\n{\n    Assert(m_inBeginEndBlock && m_inPreRegister, \"Invalid call.\");\n    int h = m_currRenderPassIdx.fetch_add(1, std::memory_order_relaxed);\n    Assert(h < MAX_NUM_RENDER_PASSES, \"Number of render passes exceeded MAX_NUM_RENDER_PASSES\");\n\n    m_renderNodes[h].Reset(name, t, dlg, forceSeparateCmdList);\n\n    return RenderNodeHandle(h);\n}\n\nvoid RenderGraph::RegisterResource(ID3D12Resource* res, uint64_t path, \n    D3D12_RESOURCE_STATES initState, bool isWindowSizeDependent)\n{\n    Assert(m_inBeginEndBlock && m_inPreRegister, \"Invalid call.\");\n    Assert(res == nullptr || path > DUMMY_RES::COUNT, \n        \"resource path ID can't take special value %llu\", path);\n\n    const int prevPos = FindFrameResource(path, 0, m_prevFramesNumResources - 1);\n\n    // Existing resource\n    if (prevPos != -1)\n    {\n        if(m_frameResources[prevPos].Res != res)\n            m_frameResources[prevPos].Reset(path, res, initState, isWindowSizeDependent);\n\n        return;\n    }\n\n    // New resource\n    int pos = m_lastResIdx.fetch_add(1, std::memory_order_relaxed);\n    Assert(pos < MAX_NUM_RESOURCES, \"Number of resources exceeded MAX_NUM_RESOURCES\");\n\n    m_frameResources[pos].Reset(path, res, initState, isWindowSizeDependent);\n}\n\nvoid RenderGraph::MoveToPostRegister()\n{\n    Assert(m_inBeginEndBlock && m_inPreRegister, \"Invalid call.\");\n    const int numResources = m_lastResIdx.load(std::memory_order_relaxed);\n\n    // Sort the frame resources so that binary search can be performed\n    std::sort(m_frameResources.begin(), m_frameResources.begin() + numResources,\n        [](ResourceMetadata& lhs, ResourceMetadata& rhs)\n        {\n            return lhs.ID < rhs.ID;\n        });\n\n#ifndef NDEBUG\n    for (int i = 0; i < numResources - 1; i++)\n    {\n        if (m_frameResources[i].ID == m_frameResources[i + 1].ID)\n        {\n            char name[64] = { '\\0' };\n            UINT n = sizeof(name);\n            m_frameResources[i].Res->GetPrivateData(WKPDID_D3DDebugObjectName, &n, name);\n\n            Assert(false, \"Duplicate entries for resource %s.\", name);\n        }\n    }\n#endif\n\n    m_inPreRegister = false;\n}\n\nvoid RenderGraph::AddInput(RenderNodeHandle h, uint64_t pathID, \n    D3D12_RESOURCE_STATES expectedState)\n{\n    Assert(m_inBeginEndBlock && !m_inPreRegister, \"Invalid call.\");\n    Assert(h.IsValid(), \"Invalid handle\");\n    Assert(h.Val < m_currRenderPassIdx.load(std::memory_order_relaxed), \"Invalid handle\");\n    Assert(expectedState & Constants::READ_STATES, \"Invalid read state.\");\n\n    // Defer checking for invalid states until later on\n    m_renderNodes[h.Val].Inputs.emplace_back(pathID, expectedState);\n}\n\nvoid RenderGraph::AddOutput(RenderNodeHandle h, uint64_t pathID, \n    D3D12_RESOURCE_STATES expectedState)\n{\n    Assert(m_inBeginEndBlock && !m_inPreRegister, \"Invalid call.\");\n    Assert(h.IsValid(), \"Invalid handle\");\n    Assert(h.Val < m_currRenderPassIdx.load(std::memory_order_relaxed), \"Invalid handle\");\n    Assert(expectedState & Constants::WRITE_STATES, \"Invalid write state.\");\n    Assert(m_renderNodes[h.Val].Type != RENDER_NODE_TYPE::ASYNC_COMPUTE || \n        !(expectedState & Constants::INVALID_COMPUTE_STATES),\n        \"state transition to %u is not supported on an async-compute command list.\", \n        expectedState);\n\n    m_renderNodes[h.Val].Outputs.emplace_back(pathID, expectedState);\n\n    const size_t idx = FindFrameResource(pathID);\n    Assert(idx != size_t(-1), \"Invalid resource path %llu.\", pathID);\n\n    const int prodIdx = m_frameResources[idx].CurrProdIdx.fetch_add(1, std::memory_order_relaxed);\n    Assert(prodIdx < MAX_NUM_PRODUCERS, \n        \"Number of producers for each resource can't exceed MAX_NUM_PRODUCERS\");\n//    Assert(prodIdx == 0 || m_renderNodes[m_frameResources[idx].Producers[prodIdx - 1].Val].Type == m_renderNodes[h.Val].Type,\n//        \"All the producers need to have the same type.\");\n\n    m_frameResources[idx].Producers[prodIdx] = h;\n}\n\nvoid RenderGraph::Build(TaskSet& ts)\n{\n    Assert(m_inBeginEndBlock && !m_inPreRegister, \"Invalid call.\");\n    m_inBeginEndBlock = false;\n\n    const int numNodes = m_currRenderPassIdx.load(std::memory_order_relaxed);\n    Assert(numNodes > 0, \"no render nodes\");\n\n    for (int i = 0; i < numNodes; i++)\n        m_renderNodes[i].Indegree = (int16)m_renderNodes[i].Inputs.size();\n\n    SmallVector<RenderNodeHandle, App::FrameAllocator> adjacentTailNodes[MAX_NUM_RENDER_PASSES];\n\n    // Add the graph edges. For each input of node N, add an edge from \n    // that input's producer node (previously populated by AddOutput) to N\n    for (int currNode = 0; currNode < numNodes; currNode++)\n    {\n        RenderNode& node = m_renderNodes[currNode];\n\n        for (Dependency& input : node.Inputs)\n        {\n            const size_t idx = FindFrameResource(input.ResID);\n            Assert(idx != size_t(-1), \"Resource ID %u was not found.\", input.ResID);\n\n            const int16 numProducers = m_frameResources[idx].CurrProdIdx.load(std::memory_order_relaxed);\n\n            // Null resources or resources that were produced in prior frames\n            if (numProducers == 0)\n            {\n                node.Indegree--;\n                Assert(node.Indegree >= 0, \"Invalid indegree for node %s.\", node.Name);\n            }\n            // Each producer needs to decrement the dependency counter\n            else\n                node.Indegree += numProducers - 1;    // -1 to avoid double counting\n\n            for (int prod = 0; prod < numProducers; prod++)\n            {\n                const int prodHandle = m_frameResources[idx].Producers[prod].Val;\n\n                // Workaround for when resource is set as both input and output for some node, otherwise there'd be a cycle\n                if (currNode == prodHandle)\n                {\n                    node.Indegree--;\n\n                    const int numOutputs = (int)node.Outputs.size();\n                    Assert(numOutputs > 0, \"invalid graph.\");\n\n                    // For pass P, resource R is ping ponged between input & output and may appear as both \n                    // an input and output of P, with possibly different states. Since barriers are executed \"prior\" \n                    // to recording, this scenario can't be handled. As a workaround, the render graph takes cares of \n                    // transitioning R into its input state, while further transitions (ping-ponging) for R inside P \n                    // must be handled manually. R's state must be restored to its input state, otherwise actual state \n                    // and render graph's state go out of sync.\n                    for (int i = 0; i < numOutputs; i++)\n                    {\n                        if (node.Outputs[i].ResID == input.ResID)\n                        {\n                            node.OutputMask |= (1 << i);\n                            break;\n                        }\n                    }\n                }\n                else\n                    adjacentTailNodes[prodHandle].push_back(RenderNodeHandle(currNode));\n            }\n        }\n    }\n\n    Sort(adjacentTailNodes);\n\n    // At this point \"m_frameResources[_].Producers\" is invalid since \"m_renderNodes\" \n    // was sorted. \"mapping\" must be used instead.\n    InsertResourceBarriers();\n    JoinRenderNodes();\n    MergeSmallNodes();\n    BuildTaskGraph(ts);\n\n#ifndef NDEBUG\n    //Log();\n#endif\n}\n\nvoid RenderGraph::BuildTaskGraph(Support::TaskSet& ts)\n{\n    // Task-level dependency cases:\n    // \n    // 1. From nodes with batchIdx i to nodes with batchIdx i + 1\n    // 2. From gpuDep(node) to node\n\n    // GPU dependency & unsupported barriers:\n    // \n    //  - If C has an unsupported barrier, add a barrier Task T immediately before\n    // the tasks from batch index B where B = C.batchIdx\n    //  - Remove C's GPU dependency (if any), then add a GPU dependency from T to C\n\n    for (int i = 0; i < m_aggregateNodes.size(); i++)\n    {\n        m_aggregateNodes[i].TaskH = ts.EmplaceTask(m_aggregateNodes[i].Name, [this, i]()\n            {\n                auto& renderer = App::GetRenderer();\n\n                ComputeCmdList* cmdList = nullptr;\n                AggregateRenderNode& aggregateNode = m_aggregateNodes[i];\n\n                if (aggregateNode.MergeStart)\n                {\n                    Assert(m_mergedCmdLists[aggregateNode.MergedCmdListIdx] == nullptr, \n                        \"Merged command list should be initially NULL.\");\n                    m_mergedCmdLists[aggregateNode.MergedCmdListIdx] = \n                        static_cast<ComputeCmdList*>(renderer.GetGraphicsCmdList());;\n                    cmdList = m_mergedCmdLists[aggregateNode.MergedCmdListIdx];\n                }\n                else if (aggregateNode.MergedCmdListIdx != -1)\n                {\n                    cmdList = m_mergedCmdLists[aggregateNode.MergedCmdListIdx];\n                    Assert(cmdList, \"Merged command list should've been initializeda at this point.\");\n                }\n                else\n                {\n                    if (!aggregateNode.IsAsyncCompute)\n                        cmdList = static_cast<ComputeCmdList*>(renderer.GetGraphicsCmdList());\n                    else\n                        cmdList = renderer.GetComputeCmdList();\n                }\n\n#ifndef NDEBUG\n                cmdList->SetName(aggregateNode.Name);\n#endif\n\n                if (aggregateNode.HasUnsupportedBarrier)\n                {\n                    CommandList* barrierCmdList = renderer.GetGraphicsCmdList();\n                    GraphicsCmdList& directCmdList = static_cast<GraphicsCmdList&>(*barrierCmdList);\n#ifndef NDEBUG\n                    directCmdList.SetName(\"Barrier\");\n#endif\n                    directCmdList.ResourceBarrier(aggregateNode.Barriers.data(), \n                        (UINT)aggregateNode.Barriers.size());\n                    uint64_t f = renderer.ExecuteCmdList(barrierCmdList);\n\n                    renderer.WaitForDirectQueueOnComputeQueue(f);\n                }\n                else if (!aggregateNode.Barriers.empty())\n                {\n                    cmdList->ResourceBarrier(aggregateNode.Barriers.begin(), \n                        (UINT)aggregateNode.Barriers.size());\n                }\n\n                // Record\n                for(auto dlg : aggregateNode.Dlgs)\n                    dlg(*cmdList);\n\n                // Wait for possible GPU fence\n                if (!aggregateNode.HasUnsupportedBarrier && aggregateNode.GpuDepIdx.Val != -1)\n                {\n                    uint64_t f = m_aggregateNodes[aggregateNode.GpuDepIdx.Val].CompletionFence;\n                    Assert(f != UINT64_MAX, \"GPU hasn't finished executing.\");\n\n                    if (aggregateNode.IsAsyncCompute)\n                        renderer.WaitForDirectQueueOnComputeQueue(f);\n                    else\n                        renderer.WaitForComputeQueueOnDirectQueue(f);\n                }\n\n                if (aggregateNode.IsLast)\n                {\n                    auto& gpuTimer = renderer.GetGpuTimer();\n                    gpuTimer.EndFrame(*cmdList);\n                }\n\n                // submit\n                if (aggregateNode.MergedCmdListIdx == -1 || aggregateNode.MergeEnd)\n                {\n                    aggregateNode.CompletionFence = renderer.ExecuteCmdList(cmdList);\n\n                    if (aggregateNode.MergeEnd)\n                    {\n                        m_mergedCmdLists[aggregateNode.MergedCmdListIdx] = nullptr;\n\n                        int curr = i - 1;\n                        while (m_aggregateNodes[curr].MergedCmdListIdx == aggregateNode.MergedCmdListIdx)\n                        {\n                            m_aggregateNodes[curr].CompletionFence = aggregateNode.CompletionFence;\n                            curr--;\n                        }\n                    }\n                }\n\n                if (m_submissionWaitObj && aggregateNode.IsLast)\n                {\n                    m_submissionWaitObj->Notify();\n                    m_submissionWaitObj = nullptr;\n                }\n            });\n    }\n\n    for (int i = 0; i < (int)m_aggregateNodes.size() - 1; i++)\n    {\n        const int currBatchIdx = m_aggregateNodes[i].BatchIdx;\n\n        for (int j = i + 1; j < (int)m_aggregateNodes.size(); j++)\n        {\n            const int nextBatchIdx = m_aggregateNodes[j].BatchIdx;\n\n            if (nextBatchIdx > currBatchIdx + 1)\n                break;\n\n            if (nextBatchIdx == currBatchIdx + 1)\n                ts.AddOutgoingEdge(m_aggregateNodes[i].TaskH, m_aggregateNodes[j].TaskH);\n\n            if(nextBatchIdx == currBatchIdx && m_aggregateNodes[j].ForceSeparate)\n                ts.AddOutgoingEdge(m_aggregateNodes[i].TaskH, m_aggregateNodes[j].TaskH);\n        }\n    }\n}\n\nvoid RenderGraph::Sort(Span<SmallVector<RenderNodeHandle, App::FrameAllocator>> adjacentTailNodes)\n{\n    const int numNodes = m_currRenderPassIdx.load(std::memory_order_relaxed);\n    RenderNodeHandle sorted[MAX_NUM_RENDER_PASSES];\n    int currIdx = 0;\n\n    // Move all the nodes with zero indegree to sorted\n    for (int currNode = 0; currNode < numNodes; currNode++)\n    {\n        RenderNode& node = m_renderNodes[currNode];\n\n        if (node.Indegree == 0)\n        {\n            // when batchIdx is zero there are no dependencies\n            sorted[currIdx++] = RenderNodeHandle(currNode);\n            node.NodeBatchIdx = 0;\n        }\n    }\n\n    Assert(currIdx > 0, \"Graph is not a DAG- no node with 0 dependencies.\");\n\n    // Topological sort\n    for (int currNode = 0; currNode < numNodes; currNode++)\n    {\n        Assert(sorted[currNode].IsValid(), \"invalid handle\");\n        const int currHandle = sorted[currNode].Val;\n\n        for (RenderNodeHandle adjacent : adjacentTailNodes[currHandle])\n        {\n            if (--m_renderNodes[adjacent.Val].Indegree == 0)\n                sorted[currIdx++] = adjacent;\n        }\n    }\n\n    Assert(numNodes == currIdx, \"Graph is not a DAG\");\n\n    // Length of the longest path for every node in DAG\n    for (int i = 0; i < numNodes; i++)\n    {\n        RenderNodeHandle currHandle = sorted[i];\n\n        for (RenderNodeHandle adjacent : adjacentTailNodes[currHandle.Val])\n        {\n            m_renderNodes[adjacent.Val].NodeBatchIdx = Math::Max(\n                m_renderNodes[currHandle.Val].NodeBatchIdx + 1,\n                m_renderNodes[adjacent.Val].NodeBatchIdx);\n        }\n    }\n\n    std::sort(sorted, sorted + numNodes, \n        [this](const RenderNodeHandle& lhs, const RenderNodeHandle& rhs)\n        {\n            return m_renderNodes[lhs.Val].NodeBatchIdx < m_renderNodes[rhs.Val].NodeBatchIdx;\n        });\n\n    // Producer Handle to sorted array index mapping.\n    // Producer handles were specified using the unsorted index. This maps those\n    // to sorted order as subsequent processing uses the sorted one:\n    // \n    //        original: [0, 1, 2, 3, 4, 5]\n    //        sorted:   [3, 2, 1, 4, 0, 5]\n    //        mapping:  [4, 2, 1, 0, 3, 5]\n    //\n    // e.g. Producer handle 0 is now located at mapping[0] = 4\n    for (int currNode = 0; currNode < numNodes; currNode++)\n        m_mapping[sorted[currNode].Val] = RenderNodeHandle(currNode);\n\n    // Shuffle\n    RenderNode tempRenderNodes[MAX_NUM_RENDER_PASSES];\n\n    for (int currNode = 0; currNode < numNodes; currNode++)\n        tempRenderNodes[currNode] = ZetaMove(m_renderNodes[sorted[currNode].Val]);\n\n    for (int currNode = 0; currNode < numNodes; currNode++)\n        m_renderNodes[currNode] = ZetaMove(tempRenderNodes[currNode]);\n\n    // TODO can be avoided\n//    std::sort(m_renderNodes, m_renderNodes + numNodes, [this](const RenderNode& lhs, const RenderNode& rhs)\n//        {\n//            return lhs.BatchIdx < rhs.BatchIdx;\n//        });\n}\n\nvoid RenderGraph::InsertResourceBarriers()\n{\n    const int numNodes = m_currRenderPassIdx.load(std::memory_order_relaxed);\n\n    // Using ordering imposed by sorted, largest index of the node on the Direct/Compute queue with which \n    // a compute/Direct node has already synced (see case b below). Note that this is an index into \"sorted\"\n    // not a Handle\n    int lastDirQueueHandle = 0;\n    int lastComputeQueueHandle = 0;\n\n    // Helper to return last*Idx based on the node type\n    auto getLastSyncedIdx = [&lastDirQueueHandle, &lastComputeQueueHandle](RENDER_NODE_TYPE t)\n    {\n        return t == RENDER_NODE_TYPE::ASYNC_COMPUTE ? &lastDirQueueHandle : \n            &lastComputeQueueHandle;\n    };\n\n    // Workflow:\n    // \n    // 1. For each input resource R:\n    // \n    //     - if R.state != expected --> add a barrier (e.g. RTV to SRV)\n    //     - if stateBefore(== R.state) is unsupported --> set hasUnsupportedBarriers\n    //     - if producer is on a different queue, add a gpu sync, but only if an earlier\n    //       task hasn't synced already (see cases below)\n    //\n    // 2. For each output resource R:\n    // \n    //         - if R.state != expected --> add a barrier (e.g. SRV to UAV)\n    //         - if stateBefore(== R.state) is unsupported --> set hasUnsupportedBarriers\n\n    // Iterate by execution order (i.e. sorted by batch index)\n    for (int currNode = 0; currNode < numNodes; currNode++)\n    {\n        RenderNode& node = m_renderNodes[currNode];\n        const bool isAsyncCompute = node.Type == RENDER_NODE_TYPE::ASYNC_COMPUTE;\n        RenderNodeHandle largestProducerSortedHandle;    // i.e. index in sorted (execution) order\n\n        //\n        // Inputs\n        //\n        for (Dependency& currInputRes : node.Inputs)\n        {\n            if (currInputRes.ResID < DUMMY_RES::COUNT)\n                continue;\n\n            const size_t inputFrameResIdx = FindFrameResource(currInputRes.ResID);\n            Assert(inputFrameResIdx != size_t(-1), \"Resource %llu was not found.\", currInputRes.ResID);\n            const D3D12_RESOURCE_STATES inputResState = m_frameResources[inputFrameResIdx].State;\n\n            if (!(inputResState & currInputRes.ExpectedState))\n            {\n                // Unsupported stateAfter should've been caught earlier\n                node.HasUnsupportedBarrier = node.HasUnsupportedBarrier || \n                    (isAsyncCompute && (inputResState & Constants::INVALID_COMPUTE_STATES));\n                node.Barriers.push_back(TransitionBarrier(m_frameResources[inputFrameResIdx].Res,\n                    inputResState,\n                    currInputRes.ExpectedState));\n\n                // Update resource state\n                m_frameResources[inputFrameResIdx].State = currInputRes.ExpectedState;\n            }\n\n            // If the input producer is on a different command queue, a GPU cross-queue sync is required.\n            // (numbers correspond to index in the execution order)\n            // \n            // Cases:\n            //\n            // a. 5 only needs to sync with 4 and 7.\n            //\n            //        Queue1      1------> 3 ------> 5\n            //                                       |\n            //                    |--------|----------\n            //        Queue2      2 -----> 4 ------> 6\n            //\n            //           \n            // b. since 4 has synced with 1, 6 no longer needs to sync with 1.\n            //\n            //        Queue1      1------> 2 -----> 3\n            //                    |-----------------\n            //                    |                 |\n            //        Queue2      4 -----> 5 -----> 6\n\n            // Find the largest producer batch index (case a)\n            const int numProducers = m_frameResources[inputFrameResIdx].CurrProdIdx.load(std::memory_order_relaxed);\n            //Assert(m_frameResources[inputFrameResIdx].Res == nullptr || \n            //    numProducers > 0, \"No producer for resource %llu\", m_frameResources[inputFrameResIdx].ID);\n\n            for (int i = 0; i < numProducers; i++)\n            {\n                RenderNodeHandle unsortedHandle = m_frameResources[inputFrameResIdx].Producers[i];\n                RenderNodeHandle sortedHandle = m_mapping[unsortedHandle.Val];\n                const bool producerOnDifferentQueue = \n                    (isAsyncCompute && m_renderNodes[sortedHandle.Val].Type != RENDER_NODE_TYPE::ASYNC_COMPUTE) ||\n                    (!isAsyncCompute && m_renderNodes[sortedHandle.Val].Type == RENDER_NODE_TYPE::ASYNC_COMPUTE);\n\n                if (producerOnDifferentQueue)\n                {\n                    Assert(m_renderNodes[sortedHandle.Val].NodeBatchIdx < node.NodeBatchIdx, \"Invalid graph\");\n                    // case a\n                    largestProducerSortedHandle.Val = Math::Max(largestProducerSortedHandle.Val, sortedHandle.Val);\n                }\n            }\n        }\n\n        // Case b\n        if (largestProducerSortedHandle.Val != -1 && *getLastSyncedIdx(node.Type) < largestProducerSortedHandle.Val)\n        {\n            *getLastSyncedIdx(node.Type) = largestProducerSortedHandle.Val;\n            node.GpuDepSourceIdx = largestProducerSortedHandle;\n        }\n\n        //\n        // Outputs\n        //\n        int i = 0;\n\n        for (Dependency& currOutputRes : node.Outputs)\n        {\n            if (currOutputRes.ResID < DUMMY_RES::COUNT)\n                continue;\n\n            const bool skipBarrier = ((1 << i++) & node.OutputMask);\n\n            const size_t outputFrameResIdx = FindFrameResource(currOutputRes.ResID);\n            Assert(outputFrameResIdx != size_t(-1), \"Resource %llu was not found.\", currOutputRes.ResID);\n            const D3D12_RESOURCE_STATES outputResState = m_frameResources[outputFrameResIdx].State;\n\n            if (!skipBarrier && !(m_frameResources[outputFrameResIdx].State & currOutputRes.ExpectedState))\n            {\n                // Unsupported resourceAfter should've been caught earlier\n                node.HasUnsupportedBarrier = node.HasUnsupportedBarrier || \n                    (isAsyncCompute && (outputResState & Constants::INVALID_COMPUTE_STATES));\n                node.Barriers.push_back(TransitionBarrier(m_frameResources[outputFrameResIdx].Res,\n                    outputResState,\n                    currOutputRes.ExpectedState));\n            }\n\n            // Update the resource state\n            m_frameResources[outputFrameResIdx].State = currOutputRes.ExpectedState;\n        }\n    }\n\n    // Temporary solution; assumes that \"someone\" will transition backbuffer to Present state\n    int idx = FindFrameResource(App::GetRenderer().GetCurrentBackBuffer().ID());\n    //Assert(idx != -1, \"Current backbuffer was not found in frame resources\");\n    if(idx != -1)\n        m_frameResources[idx].State = D3D12_RESOURCE_STATE_PRESENT;\n}\n\nvoid RenderGraph::JoinRenderNodes()\n{\n    const int numNodes = m_currRenderPassIdx.load(std::memory_order_relaxed);\n    m_aggregateNodes.reserve(numNodes);\n\n    int currBatchIdx = 0;\n    SmallVector<int, App::FrameAllocator, 16> nonAsyncComputeNodes;\n    SmallVector<int, App::FrameAllocator, 16> asyncComputeNodes;\n\n    auto insertAggRndrNode = [this, &nonAsyncComputeNodes, &asyncComputeNodes]()\n    {\n        Assert(!nonAsyncComputeNodes.empty() || !asyncComputeNodes.empty(), \"bug\");\n\n        if (!asyncComputeNodes.empty())\n        {\n            m_aggregateNodes.emplace_back(true);\n\n            bool hasGpuFence = false;\n            bool hasUnsupportedBarrier = false;\n\n            for (auto n : asyncComputeNodes)\n            {\n                const int gpuDep = m_renderNodes[n].GpuDepSourceIdx.Val;\n\n                hasGpuFence = hasGpuFence || (gpuDep != -1);\n                hasUnsupportedBarrier = hasUnsupportedBarrier || m_renderNodes[n].HasUnsupportedBarrier;\n\n                const int mappedGpuDepIdx = gpuDep == -1 ? -1 : m_renderNodes[gpuDep].AggNodeIdx;\n                Assert(gpuDep == -1 || mappedGpuDepIdx != -1, \n                    \"Aggregate node of GPU dependency should come before the dependent node.\");\n\n                m_aggregateNodes.back().Append(m_renderNodes[n], mappedGpuDepIdx);\n                m_renderNodes[n].AggNodeIdx = (int16)m_aggregateNodes.size() - 1;\n            }\n\n            // If there's an async. compute task in this batch that has unsupported barriers,\n            // then that task's going to sync with the direct queue immediately before execution,\n            // which supersedes any other GPU fence in this joined node.\n            m_aggregateNodes.back().GpuDepIdx = hasGpuFence && hasUnsupportedBarrier ?\n                RenderNodeHandle(-1) :\n                m_aggregateNodes.back().GpuDepIdx;\n        }\n\n        if (!nonAsyncComputeNodes.empty())\n        {\n            m_aggregateNodes.emplace_back(false);\n\n            for (auto n : nonAsyncComputeNodes)\n            {\n                const int gpuDep = m_renderNodes[n].GpuDepSourceIdx.Val;\n                // Map from node index to aggregate node index\n                const int mappedGpuDepIdx = gpuDep == -1 ? -1 : m_renderNodes[gpuDep].AggNodeIdx;\n                Assert(gpuDep == -1 || mappedGpuDepIdx != -1, \n                    \"Aggregate node of GPU dependency should come before the dependent node.\");\n\n                m_aggregateNodes.back().Append(m_renderNodes[n], mappedGpuDepIdx);\n                m_renderNodes[n].AggNodeIdx = (int16)m_aggregateNodes.size() - 1;\n            }\n        }\n    };\n\n    for (int currNode = 0; currNode < numNodes; currNode++)\n    {\n        if (m_renderNodes[currNode].NodeBatchIdx != currBatchIdx)\n        {\n            // When the previous batch contained a single pass that forced a separate \n            // command list, the corresponding aggregate node for that batch has a single\n            // pass and was added in the previous iteration. Since there weren't any\n            // other passes in that batch, the nodes array are empty.\n            if (!nonAsyncComputeNodes.empty() || !asyncComputeNodes.empty())\n            {\n                insertAggRndrNode();\n                nonAsyncComputeNodes.clear();\n                asyncComputeNodes.clear();\n            }\n\n            currBatchIdx = m_renderNodes[currNode].NodeBatchIdx;\n        }\n\n        if (m_renderNodes[currNode].ForceSeparateCmdList)\n        {\n            m_aggregateNodes.emplace_back(m_renderNodes[currNode].Type == RENDER_NODE_TYPE::ASYNC_COMPUTE);\n\n            const int gpuDep = m_renderNodes[currNode].GpuDepSourceIdx.Val;\n            const int mappedGpuDepIdx = gpuDep == -1 ? -1 : m_renderNodes[gpuDep].AggNodeIdx;\n            Assert(gpuDep == -1 || mappedGpuDepIdx != -1, \n                \"GPU dependency aggregate node should come before the dependent node.\");\n\n            m_aggregateNodes.back().Append(m_renderNodes[currNode], mappedGpuDepIdx, true);\n            m_renderNodes[currNode].AggNodeIdx = (int16)m_aggregateNodes.size() - 1;\n\n            continue;\n        }\n\n        if (m_renderNodes[currNode].Type == RENDER_NODE_TYPE::ASYNC_COMPUTE)\n            asyncComputeNodes.push_back(currNode);\n        else\n            nonAsyncComputeNodes.push_back(currNode);\n    }\n\n    insertAggRndrNode();\n\n    m_aggregateNodes.back().IsLast = true;\n}\n\nvoid RenderGraph::MergeSmallNodes()\n{\n    int currOffset = -1;\n    int cmdListIdx = 0;\n    int currCount = 0;\n\n    for (int nodeIdx = 0; nodeIdx < (int)m_aggregateNodes.size(); nodeIdx++)\n    {\n        auto& node = m_aggregateNodes[nodeIdx];\n\n        if (!node.IsAsyncCompute && !node.ForceSeparate && (node.Dlgs.size() == 1))\n        {\n            node.MergeStart = (currOffset == -1) ? true : false;\n            node.MergedCmdListIdx = cmdListIdx;\n            currOffset = (currOffset == -1) ? nodeIdx : currOffset;\n            currCount++;\n        }\n        else\n        {\n            if (currCount)\n            {\n                auto& prev = m_aggregateNodes[nodeIdx - 1];\n                \n                if (currCount == 1)\n                {\n                    Assert(prev.MergeStart && prev.MergedCmdListIdx != -1, \"bug\");\n\n                    prev.MergeStart = false;\n                    prev.MergedCmdListIdx--;\n                }\n                else\n                {\n                    prev.MergeEnd = true;\n                    cmdListIdx++;\n                }\n            }\n\n            currCount = 0;\n            currOffset = -1;\n        }\n    }\n\n    if (currCount)\n    {\n        auto& prev = m_aggregateNodes.back();\n\n        if (currCount == 1)\n        {\n            Assert(prev.MergeStart && prev.MergedCmdListIdx != -1, \"bug\");\n\n            prev.MergeStart = false;\n            prev.MergedCmdListIdx--;\n        }\n        else\n        {\n            prev.MergeEnd = true;\n            cmdListIdx++;\n        }\n    }\n\n    if (cmdListIdx)\n        m_mergedCmdLists.resize(cmdListIdx, nullptr);\n\n    //for (int i = 0; i < (int)m_aggregateNodes.size(); i++)\n    //{\n    //    const auto& node = m_aggregateNodes[i];\n    //    if (node.MergeStart)\n    //    {\n    //        printf(\"Merge:\\n\\t\");\n    //        while (i < (int)m_aggregateNodes.size())\n    //        {\n    //            if (m_aggregateNodes[i].MergeEnd)\n    //                break;\n    //            printf(\"%s (%d), \", m_aggregateNodes[i].Name, m_aggregateNodes[i].MergeCmdListIdx);\n    //            i++;\n    //        }\n    //    }\n    //}\n\n#ifndef NDEBUG\n    bool inMerged = false;\n    currCount = 0;\n\n    for (int i = 0; i < (int)m_aggregateNodes.size(); i++)\n    {\n        if(inMerged)\n            Assert(!m_aggregateNodes[i].MergeStart, \"RenderGraph: merge validation failed.\");\n\n        if(!inMerged)\n            Assert(!m_aggregateNodes[i].MergeEnd, \"RenderGraph: merge validation failed.\");\n\n        if (m_aggregateNodes[i].MergeStart)\n            inMerged = true;\n\n        if (inMerged)\n            currCount++;\n\n        if (m_aggregateNodes[i].MergeEnd)\n        {\n            Assert(!m_aggregateNodes[i].MergeStart, \"RenderGraph: merge validation failed.\");\n            Assert(inMerged, \"RenderGraph: merge validation failed.\");\n            Assert(currCount > 1, \"RenderGraph: merge validation failed.\");\n\n            inMerged = false;\n            currCount = 0;\n        }\n    }\n#endif\n}\n\nuint64_t RenderGraph::GetCompletionFence(RenderNodeHandle h)\n{\n    Assert(h.IsValid(), \"invalid handle.\");\n    Assert(!m_inBeginEndBlock, \"invalid call.\");\n    Assert(!m_inPreRegister, \"invalid call.\");\n\n    auto mappedIdx = m_mapping[h.Val];\n    Assert(mappedIdx.IsValid(), \"invalid mapped index\");\n\n    auto aggNodeIdx = m_renderNodes[mappedIdx.Val].AggNodeIdx;\n    Assert(aggNodeIdx != -1, \"render graph hasn't been built yet.\");\n    // TODO fix\n    Assert(m_aggregateNodes[aggNodeIdx].MergedCmdListIdx == -1, \n        \"Completion fence for merged command lists is currently unsupported.\");\n    auto fence = m_aggregateNodes[aggNodeIdx].CompletionFence;\n    //Assert(fence != -1, \"render node hasn't been submitted yet.\");\n\n    return fence;\n}\n\nvoid RenderGraph::SetFrameSubmissionWaitObj(Support::WaitObject& waitObj)\n{\n    m_submissionWaitObj = &waitObj;\n}\n\nuint64_t RenderGraph::GetFrameCompletionFence()\n{\n    Assert(!m_inBeginEndBlock, \"Invalid call.\");\n    Assert(!m_inPreRegister, \"Invalid call.\");\n\n    return m_aggregateNodes.back().CompletionFence;\n}\n\nvoid RenderGraph::DebugDrawGraph()\n{\n    const int numNodes = m_currRenderPassIdx.load(std::memory_order_relaxed);\n    const bool needsReorder = m_numPassesLastTimeDrawn != numNodes;\n\n    ImNodes::BeginNodeEditor();\n\n    ImNodes::PushColorStyle(ImNodesCol_TitleBarSelected, IM_COL32(81, 48, 204, 255));\n\n    int batchSize[MAX_NUM_RENDER_PASSES];\n    memset(batchSize, 0, sizeof(int) * MAX_NUM_RENDER_PASSES);\n\n    int currBatchIdx = 0;\n\n    // Compute batch sizes\n    {\n        int currBatchSize = 0;\n\n        for (int currNode = 0; currNode < numNodes; currNode++)\n        {\n            if (m_renderNodes[currNode].NodeBatchIdx != currBatchIdx)\n            {\n                batchSize[currBatchIdx] = currBatchSize;\n\n                currBatchSize = 0;\n                currBatchIdx = m_renderNodes[currNode].NodeBatchIdx;\n            }\n\n            currBatchSize++;\n        }\n\n        Assert(currBatchIdx < MAX_NUM_RENDER_PASSES, \"out-of-bound write\");\n        batchSize[currBatchIdx] = currBatchSize;\n    }\n\n    const int numBatches = currBatchIdx + 1;\n    int currBatchStartPin = 0;\n    int currBatchInputPin = 0;\n    int currBatchOutputPin = 0;\n    currBatchIdx = 0;\n    int idxInBatch = 0;\n    int numBarriersInBatch = 0;\n\n    for (int currNode = 0; currNode < numNodes; currNode++)\n    {\n        if (m_renderNodes[currNode].NodeBatchIdx != currBatchIdx)\n        {\n            const int prevBatchSize = currBatchIdx > 0 ? batchSize[currBatchIdx - 1] : 0;\n            const int currBatchSize = batchSize[currBatchIdx];\n            const int nextBatchSize = currBatchIdx + 1 < numBatches ? batchSize[currBatchIdx + 1] : 0;\n\n            currBatchIdx = m_renderNodes[currNode].NodeBatchIdx;\n            currBatchStartPin += currBatchSize * prevBatchSize + nextBatchSize * currBatchSize;\n\n            currBatchInputPin = 0;\n            currBatchOutputPin = 0;\n            idxInBatch = 0;\n            numBarriersInBatch = 0;\n        }\n\n        Assert(currBatchIdx >= 0 && currBatchIdx < numBatches, \"out-of-bound access\");\n\n        if (m_renderNodes[currNode].Type == RENDER_NODE_TYPE::ASYNC_COMPUTE)\n            ImNodes::PushColorStyle(ImNodesCol_TitleBar, IM_COL32(21, 133, 41, 255));\n        else if(m_aggregateNodes[m_renderNodes[currNode].AggNodeIdx].MergedCmdListIdx != -1)\n            ImNodes::PushColorStyle(ImNodesCol_TitleBar, IM_COL32(15, 51, 109, 255));\n        else\n            ImNodes::PushColorStyle(ImNodesCol_TitleBar, IM_COL32(155, 21, 41, 255));\n\n        ImNodes::BeginNode(currNode);\n\n        ImNodes::BeginNodeTitleBar();\n        ImGui::Text(\"\\t%d. %s, Batch: %d, (GPU dep %d) %s\", currNode, m_renderNodes[currNode].Name,\n            m_renderNodes[currNode].NodeBatchIdx, m_renderNodes[currNode].GpuDepSourceIdx.Val, \n            m_renderNodes[currNode].Type == RENDER_NODE_TYPE::ASYNC_COMPUTE ? \"[Async Compute]\" : \"\");\n        ImNodes::EndNodeTitleBar();\n\n#ifndef NDEBUG\n        if(m_renderNodes[currNode].Barriers.empty())\n            ImGui::Text(\"\");\n        else\n        {\n            for (auto b : m_renderNodes[currNode].Barriers)\n            {\n                char buff[64] = { '\\0' };\n                UINT n = sizeof(buff);\n                CheckHR(b.Transition.pResource->GetPrivateData(WKPDID_D3DDebugObjectName, &n, buff));\n\n                ImGui::Text(\"\\t\\tRes: %s\\n\\tBefore: %s\\nAfter: %s\",\n                    buff,\n                    GetResStateName(b.Transition.StateBefore),\n                    GetResStateName(b.Transition.StateAfter));\n            }\n        }\n#else\n        ImGui::Text(\"\");\n#endif\n\n        const int prevBatchSize = currBatchIdx > 0 ? batchSize[currBatchIdx - 1] : 0;\n        const int currBatchSize = batchSize[currBatchIdx];\n        const int nextBatchSize = currBatchIdx + 1 < numBatches ? batchSize[currBatchIdx + 1] : 0;\n\n        for (int i = 0; i < prevBatchSize; i++)\n        {\n            int p = currBatchStartPin + currBatchInputPin;\n            ImNodes::BeginInputAttribute(p);\n            ImNodes::EndInputAttribute();\n\n            currBatchInputPin++;\n        }\n\n        for (int i = 0; i < nextBatchSize; i++)\n        {\n            int p = currBatchStartPin + currBatchSize * prevBatchSize + currBatchOutputPin;\n            ImNodes::BeginOutputAttribute(p);\n            ImNodes::EndOutputAttribute();\n\n            currBatchOutputPin++;\n        }\n\n        ImNodes::EndNode();\n        ImNodes::PopColorStyle();\n\n        if (needsReorder)\n        {\n            const float x = currBatchIdx * 350.0f;\n#ifndef NDEBUG\n            const float y = 50.0f + idxInBatch++ * 75.0f + numBarriersInBatch * 60.0f;\n#else\n            const float y = 50.0f + idxInBatch++ * 75.0f;\n#endif\n\n            ImNodes::SetNodeEditorSpacePos(currNode, ImVec2(x, y));\n\n            numBarriersInBatch += (int)m_renderNodes[currNode].Barriers.size();\n        }\n            //ImNodes::SetNodeScreenSpacePos(currNode, ImVec2(currBatchIdx * 400.0f, 50.0f + idxInBatch++ * 150.0f));\n            //ImNodes::SetNodeGridSpacePos(currNode, ImVec2(currBatchIdx * 400.0f, 50.0f + idxInBatch++ * 150.0f));\n    }\n\n    currBatchIdx = 0;\n    int currEdge = 0;\n    currBatchStartPin = 0;\n    int batchOutpinStart = 0;\n    int nextBatchInpinStart = batchSize[0] * batchSize[1];\n\n    for (int currNode = 0; currNode < numNodes; currNode++)\n    {\n        if (m_renderNodes[currNode].NodeBatchIdx != currBatchIdx)\n        {\n            currBatchIdx = m_renderNodes[currNode].NodeBatchIdx;\n\n            const int prevPrevBatchSize = currBatchIdx > 1 ? batchSize[currBatchIdx - 2] : 0;\n            const int prevBatchSize = currBatchIdx > 0 ? batchSize[currBatchIdx - 1] : 0;\n            const int currBatchSize = batchSize[currBatchIdx];\n            const int nextBatchSize = currBatchIdx + 1 < numBatches ? batchSize[currBatchIdx + 1] : 0;\n\n            currBatchStartPin += prevPrevBatchSize * prevBatchSize + prevBatchSize * currBatchSize;\n            batchOutpinStart = currBatchStartPin + currBatchSize * prevBatchSize;\n            nextBatchInpinStart = batchOutpinStart + nextBatchSize * currBatchSize;\n\n            idxInBatch = 0;\n        }\n\n        const int prevBatchSize = currBatchIdx > 0 ? batchSize[currBatchIdx - 1] : 0;\n        const int currBatchSize = batchSize[currBatchIdx];\n        const int nextBatchSize = currBatchIdx + 1 < numBatches ? batchSize[currBatchIdx + 1] : 0;\n\n        //const int targetPinStart = batchOutpinStart + nextBatchSize * currBatchSize + idxInBatch;\n\n        for (int i = 0; i < nextBatchSize; i++)\n        {\n            // In between Begin|EndAttribute calls, you can call ImGui\n            // UI functions\n            //ImGui::Text(\"out_%d\", i);\n            const int t = nextBatchInpinStart + i * currBatchSize + idxInBatch;\n            ImNodes::Link(currEdge++, batchOutpinStart++, t);\n        }\n\n        idxInBatch++;\n    }\n\n    ImNodes::PopColorStyle();\n\n    ImNodes::MiniMap(0.3f, ImNodesMiniMapLocation_BottomLeft);\n    ImNodes::EndNodeEditor();\n\n    m_numPassesLastTimeDrawn = numNodes;\n}\n\n#ifndef NDEBUG\nvoid RenderGraph::Log()\n{\n    std::string formattedRenderGraph;\n    formattedRenderGraph.reserve(2048);\n\n    char temp[256];\n    stbsp_snprintf(temp, sizeof(temp), \"\\nRenderGraph for frame %llu, #batches = %d\\n\", \n        App::GetTimer().GetTotalFrameCount(), m_aggregateNodes.size());\n    formattedRenderGraph += temp;\n\n    int currBatch = 0;\n    temp[0] = '\\0';\n\n    for (auto& node : m_aggregateNodes)\n    {\n        stbsp_snprintf(temp, sizeof(temp), \"Batch %d\\n\", currBatch);\n        formattedRenderGraph += temp;\n\n        stbsp_snprintf(temp, sizeof(temp), \"\\t%s (GPU dep %d == %s)\\n\", node.Name, node.GpuDepIdx.Val, \n            node.GpuDepIdx.Val != -1 ? m_aggregateNodes[node.GpuDepIdx.Val].Name : \"None\");\n        formattedRenderGraph += temp;\n\n        for (auto& b : node.Barriers)\n        {\n            char buff[64] = { '\\0' };\n            UINT n = sizeof(buff);\n            CheckHR(b.Transition.pResource->GetPrivateData(WKPDID_D3DDebugObjectName, &n, buff));\n\n            stbsp_snprintf(temp, sizeof(temp), \"\\t\\tRes: %s, Before: %s, After: %s\\n\",\n                buff,\n                GetResStateName(b.Transition.StateBefore),\n                GetResStateName(b.Transition.StateAfter));\n\n            formattedRenderGraph += temp;\n        }\n\n        currBatch++;\n    }\n\n    formattedRenderGraph += '\\n';\n\n#if defined(__clang__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wformat-security\"\n#endif\n    LOG_CONSOLE(formattedRenderGraph.c_str());\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n}\n#endif"
  },
  {
    "path": "Source/ZetaCore/Core/RenderGraph.h",
    "content": "#pragma once\n\n#include \"Direct3DUtil.h\"\n#include \"../Utility/Span.h\"\n#include <FastDelegate/FastDelegate.h>\n#include <atomic>\n\nnamespace ZetaRay::Support\n{\n    struct TaskSet;\n    struct WaitObject;\n}\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n    class ComputeCmdList;\n\n    enum class RENDER_NODE_TYPE : uint8_t\n    {\n        RENDER,\n        COMPUTE,\n        ASYNC_COMPUTE\n    };\n\n    struct RenderNodeHandle\n    {\n        static constexpr int INVALID_HANDLE = -1;\n\n        RenderNodeHandle() = default;\n        explicit RenderNodeHandle(int u)\n            : Val(u)\n        {}\n\n        ZetaInline bool IsValid() const { return Val != INVALID_HANDLE; }\n\n        int Val = INVALID_HANDLE;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // RenderGraph\n    //--------------------------------------------------------------------------------------\n\n    // Workflow:\n    // \n    // 1. BeginFrame()\n    // 2. All render passes for next frame need to register their resources \n    //    (RenderGraph::RegisterResource()) and themselves (RenderGraph::RegisterRenderPass())\n    // 3. MoveToPostRegister()\n    // 4. Each render pass calls RenderNode::AddInput() and RenderNode::AddOutput() for \n    //    every resource that it needs along with the expected state. \n    // 5. Barrier\n    // 6. Build a DAG based on the resource dependencies\n    // 7. Submit command lists to GPU\n\n    class RenderGraph\n    {\n    public:\n        enum DUMMY_RES : uint64_t\n        {\n            RES_0 = 0,\n            RES_1,\n            RES_2,\n            RES_3,\n            COUNT\n        };\n\n        RenderGraph() = default;\n        ~RenderGraph() = default;\n\n        RenderGraph(const RenderGraph&) = delete;\n        RenderGraph& operator=(const RenderGraph&) = delete;\n\n        void Shutdown();\n        void Reset();\n\n        // This should be called at the start of each frame\n        void BeginFrame();\n\n        // Adds a node to the graph\n        RenderNodeHandle RegisterRenderPass(const char* name, RENDER_NODE_TYPE t, \n            fastdelegate::FastDelegate1<CommandList&> dlg,\n            bool forceSeparateCmdList = false);\n\n        // Registers a new resource. This must be called prior to declaring resource \n        // dependencies in each frame.\n        void RegisterResource(ID3D12Resource* res, uint64_t path, \n            D3D12_RESOURCE_STATES initState = D3D12_RESOURCE_STATE_COMMON, \n            bool isWindowSizeDependent = true);\n\n        // Removes given resource (useful for when resources are recreated)\n        // Note: these have to be called prior to BeginFrame()\n        void RemoveResource(uint64_t path);\n        void RemoveResources(Util::Span<uint64_t> paths);\n\n        // Transitions into post-registration. At this point there can be no more Register*() calls.\n        void MoveToPostRegister();\n\n        // Adds an input resource to the RenderNodeHandle\n        void AddInput(RenderNodeHandle h, uint64_t path, \n            D3D12_RESOURCE_STATES expectedState);\n\n        // Adds an output resource to the RenderNodeHandle\n        void AddOutput(RenderNodeHandle h, uint64_t path, \n            D3D12_RESOURCE_STATES expectedState);\n\n        // Builds the graph and submits the rendering tasks with appropriate order\n        void Build(Support::TaskSet& ts);\n\n        // Draws the render graph\n        void DebugDrawGraph();\n\n        // GPU completion fence for given render node. It must've already been submitted.\n        uint64_t GetCompletionFence(RenderNodeHandle h);\n        // GPU completion fence for this frame.\n        uint64_t GetFrameCompletionFence();\n\n        void SetFrameSubmissionWaitObj(Support::WaitObject& waitObj);\n\n    private:\n        static constexpr uint16_t INVALID_NODE_HANDLE = UINT16_MAX;\n        static constexpr int MAX_NUM_RENDER_PASSES = 32;\n        static constexpr int MAX_NUM_RESOURCES = 64;\n        static constexpr int MAX_NUM_PRODUCERS = 5;\n\n        int FindFrameResource(uint64_t key, int beg = 0, int end = -1);\n        void BuildTaskGraph(Support::TaskSet& ts);\n        void Sort(Util::Span<Util::SmallVector<RenderNodeHandle, App::FrameAllocator>> adjacentTailNodes);\n        void InsertResourceBarriers();\n        void JoinRenderNodes();\n        void MergeSmallNodes();\n#ifndef NDEBUG\n        void Log();\n#endif\n\n        //\n        // Frame Resources\n        //\n        struct ResourceMetadata\n        {\n            ResourceMetadata() = default;\n            ResourceMetadata(const ResourceMetadata& other)\n                : ID(other.ID),\n                Res(other.Res),\n                State(other.State),\n                IsWindowSizeDependent(other.IsWindowSizeDependent)\n            {\n                memcpy(Producers, other.Producers, MAX_NUM_PRODUCERS * sizeof(RenderNodeHandle));\n                CurrProdIdx = other.CurrProdIdx.load(std::memory_order_relaxed);\n            }\n            ResourceMetadata& operator=(const ResourceMetadata& rhs)\n            {\n                if (this == &rhs)\n                    return *this;\n\n                ID = rhs.ID;\n                Res = rhs.Res;\n                State = rhs.State;\n                memcpy(Producers, rhs.Producers, MAX_NUM_PRODUCERS * sizeof(RenderNodeHandle));\n                CurrProdIdx = rhs.CurrProdIdx.load(std::memory_order_relaxed);\n                IsWindowSizeDependent = rhs.IsWindowSizeDependent;\n\n                return *this;\n            }\n            void Reset(uint64_t id, ID3D12Resource* r, D3D12_RESOURCE_STATES s, \n                bool isWindowSizeDependent)\n            {\n                Res = r;\n                ID = id;\n                IsWindowSizeDependent = isWindowSizeDependent;\n\n                if(State == D3D12_RESOURCE_STATES(-1))\n                    State = s;\n            }\n            void Reset()\n            {\n                ID = INVALID_ID;\n                Res = nullptr;\n                CurrProdIdx = 0;\n                State = State = D3D12_RESOURCE_STATES(-1);\n\n                for (int i = 0; i < MAX_NUM_PRODUCERS; i++)\n                    Producers[i] = RenderNodeHandle(INVALID_NODE_HANDLE);\n            }\n\n            static constexpr uint64_t INVALID_ID = UINT64_MAX;\n\n            uint64_t ID = INVALID_ID;\n            ID3D12Resource* Res = nullptr;\n            std::atomic_uint16_t CurrProdIdx = 0;\n            RenderNodeHandle Producers[MAX_NUM_PRODUCERS] = { RenderNodeHandle(INVALID_NODE_HANDLE) };\n            D3D12_RESOURCE_STATES State = D3D12_RESOURCE_STATES(-1);\n            bool IsWindowSizeDependent = false;\n        };\n\n        // Make sure this doesn't get reset between frames as some states carry over to the\n        // next frame. Producers should be reset though.\n        Util::SmallVector<ResourceMetadata> m_frameResources;\n        int m_prevFramesNumResources = 0;\n        std::atomic_int32_t m_lastResIdx = 0;\n        std::atomic_int32_t m_currRenderPassIdx = 0;\n        bool m_inBeginEndBlock = false;\n        bool m_inPreRegister = false;\n\n        //\n        // Nodes\n        //\n        struct Dependency\n        {\n            Dependency() = default;\n            Dependency(uint64_t id, D3D12_RESOURCE_STATES s)\n                : ResID(id), ExpectedState(s)\n            {}\n\n            static constexpr uint64_t INVALID_RES_ID = UINT64_MAX;\n            uint64_t ResID = INVALID_RES_ID;\n            D3D12_RESOURCE_STATES ExpectedState;\n        };\n\n        struct RenderNode\n        {\n            void Reset()\n            {\n                Inputs.free_memory();\n                Outputs.free_memory();\n                Barriers.free_memory();\n#if 0\n                Indegree = 0;\n                NodeBatchIdx = -1;\n                HasUnsupportedBarrier = false;\n                GpuDepSourceIdx = RenderNodeHandle(-1);\n                OutputMask = 0;\n                memset(Name, 0, MAX_NAME_LENGTH);\n                AggNodeIdx = -1;\n                ForceSeparateCmdList = false;\n#endif\n            }\n\n            void Reset(const char* name, RENDER_NODE_TYPE t, fastdelegate::FastDelegate1<CommandList&>& dlg, \n                bool forceSeparateCmdList)\n            {\n                Type = t;\n                Dlg = dlg;\n                Indegree = 0;\n                NodeBatchIdx = -1;\n                Inputs.free_memory();\n                Outputs.free_memory();\n                Barriers.free_memory();\n                HasUnsupportedBarrier = false;\n                GpuDepSourceIdx = RenderNodeHandle(-1);\n                OutputMask = 0;\n                AggNodeIdx = -1;\n                ForceSeparateCmdList = forceSeparateCmdList;\n\n                const int n = Math::Min((int)strlen(name), MAX_NAME_LENGTH - 1);\n                memcpy(Name, name, n);\n                Name[n] = '\\0';\n            }\n\n            static constexpr int MAX_NAME_LENGTH = 16;\n\n            fastdelegate::FastDelegate1<CommandList&> Dlg;\n            int NodeBatchIdx = -1;\n            RENDER_NODE_TYPE Type;\n            bool HasUnsupportedBarrier = false;\n            char Name[MAX_NAME_LENGTH];\n            // At most one GPU dependency\n            RenderNodeHandle GpuDepSourceIdx = RenderNodeHandle(-1);\n            uint32_t OutputMask = 0;\n            int16 Indegree = 0;\n            int16 AggNodeIdx = -1;\n            bool ForceSeparateCmdList = false;\n\n            // Due to usage of FrameAllocator, capacity must be set to zero manually\n            // in each frame, otherwise it might reuse previous frame's temp memory.\n            Util::SmallVector<Dependency, App::FrameAllocator, 2> Inputs;\n            Util::SmallVector<Dependency, App::FrameAllocator, 1> Outputs;\n            Util::SmallVector<D3D12_RESOURCE_BARRIER, App::FrameAllocator> Barriers;\n        };\n\n        struct AggregateRenderNode\n        {\n            AggregateRenderNode() = default;\n            explicit AggregateRenderNode(bool isAsyncCompute)\n                : IsAsyncCompute(isAsyncCompute)\n            {}\n\n#if 0\n            void Reset()\n            {\n                Barriers.free_memory();\n                Dlgs.free_memory();\n                HasUnsupportedBarrier = false;\n                CompletionFence = UINT64_MAX;\n                GpuDepIdx = RenderNodeHandle(-1);\n                TaskH = UINT32_MAX;\n                IsAsyncCompute = false;\n                IsLast = false;\n                ForceSeparate = false;\n                memset(Name, 0, MAX_NAME_LENGTH);\n            }\n#endif\n\n            void Append(const RenderNode& node, int mappedGpeDepIdx, bool forceSeparate = false);\n\n            static constexpr int MAX_NAME_LENGTH = 64;\n\n            Util::SmallVector<D3D12_RESOURCE_BARRIER, App::FrameAllocator, 8> Barriers;\n            Util::SmallVector<fastdelegate::FastDelegate1<CommandList&>, App::FrameAllocator, 8> Dlgs;\n            uint64_t CompletionFence = UINT64_MAX;\n            uint32_t TaskH;\n            int BatchIdx = -1;\n            int MergedCmdListIdx = -1;\n            bool MergeStart = false;\n            bool MergeEnd = false;\n            // At most one GPU dependency\n            RenderNodeHandle GpuDepIdx = RenderNodeHandle(-1);\n            char Name[MAX_NAME_LENGTH];\n            bool IsAsyncCompute;\n            bool HasUnsupportedBarrier = false;\n            bool IsLast = false;\n            bool ForceSeparate = false;\n        };\n\n        static_assert(std::is_move_constructible_v<RenderNode>);\n        static_assert(std::is_swappable_v<RenderNode>);\n\n        RenderNode m_renderNodes[MAX_NUM_RENDER_PASSES];\n        RenderNodeHandle m_mapping[MAX_NUM_RENDER_PASSES];\n        Util::SmallVector<AggregateRenderNode, App::FrameAllocator> m_aggregateNodes;\n        Util::SmallVector<ComputeCmdList*, Support::SystemAllocator, 4> m_mergedCmdLists;\n        int m_numPassesLastTimeDrawn = -1;\n        Support::WaitObject* m_submissionWaitObj = nullptr;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Core/RendererCore.cpp",
    "content": "#include \"RendererCore.h\"\n#include \"CommandList.h\"\n#include \"Direct3DUtil.h\"\n#include \"../Support/Task.h\"\n#include \"../Support/Param.h\"\n#include \"../App/Timer.h\"\n#include \"../Assets/Font/IconsFontAwesome6.h\"\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Support;\n\n//--------------------------------------------------------------------------------------\n// RendererCore\n//--------------------------------------------------------------------------------------\n\nRendererCore::RendererCore()\n    : m_cbvSrvUavDescHeapGpu(32),\n    m_cbvSrvUavDescHeapCpu(32),\n    m_rtvDescHeap(8),\n    m_directQueue(D3D12_COMMAND_LIST_TYPE_DIRECT),\n    m_computeQueue(D3D12_COMMAND_LIST_TYPE_COMPUTE)\n{}\n\nRendererCore::~RendererCore()\n{}\n\nvoid RendererCore::Init(HWND hwnd, uint16_t renderWidth, uint16_t renderHeight, \n    uint16_t displayWidth, uint16_t displayHeight)\n{\n    m_hwnd = hwnd;\n\n    m_deviceObjs.InitializeAdapter();\n    m_deviceObjs.CreateDevice(true);\n    InitStaticSamplers();\n\n    CheckHR(m_deviceObjs.m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, \n        IID_PPV_ARGS(m_fence.GetAddressOf())));\n    m_event = CreateEventA(nullptr, false, false, nullptr);\n    CheckWin32(m_event);\n\n    m_renderWidth = renderWidth;\n    m_renderHeight = renderHeight;\n    m_displayWidth = displayWidth;\n    m_displayHeight = displayHeight;\n\n    GpuMemory::Init();\n    GpuMemory::BeginFrame();\n\n    m_cbvSrvUavDescHeapGpu.Init(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,\n        Constants::NUM_CBV_SRV_UAV_DESC_HEAP_GPU_DESCRIPTORS,\n        true);\n    m_cbvSrvUavDescHeapCpu.Init(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,\n        Constants::NUM_CBV_SRV_UAV_DESC_HEAP_CPU_DESCRIPTORS,\n        false);\n    m_rtvDescHeap.Init(D3D12_DESCRIPTOR_HEAP_TYPE_RTV,\n        Constants::NUM_RTV_DESC_HEAP_DESCRIPTORS,\n        false);\n    //m_dsvDescHeap.Init(D3D12_DESCRIPTOR_HEAP_TYPE_DSV,\n    //    Constants::NUM_DSV_DESC_HEAP_DESCRIPTORS,\n    //    false);\n\n    // Reserve descriptor index 0\n    m_reserved = m_cbvSrvUavDescHeapGpu.Allocate(1);\n    Assert(m_reserved.GPUDescriptorHeapIndex() == 0, \"Unexpected GPU descriptor heap index.\");\n\n    m_directQueue.Init();\n    m_computeQueue.Init();\n    //m_copyQueue.Init();\n\n    m_backbuffDescTable = m_rtvDescHeap.Allocate(Constants::NUM_BACK_BUFFERS);\n    //m_depthBuffDescTable = m_dsvDescHeap.Allocate(1);\n\n    ResizeBackBuffers(hwnd);\n\n    m_renderViewport.TopLeftX = 0.0f;\n    m_renderViewport.TopLeftY = 0.0f;\n    m_renderViewport.Width = (float)m_renderWidth;\n    m_renderViewport.Height = (float)m_renderHeight;\n    m_renderViewport.MinDepth = D3D12_MIN_DEPTH;\n    m_renderViewport.MaxDepth = D3D12_MAX_DEPTH;\n\n    m_renderScissor.left = 0;\n    m_renderScissor.top = 0;\n    m_renderScissor.right = m_renderWidth;\n    m_renderScissor.bottom = m_renderHeight;\n\n    if (m_vsyncInterval == 0 && m_deviceObjs.m_tearingSupport)\n    {\n        m_presentFlags |= DXGI_PRESENT_ALLOW_TEARING;\n        //CheckHR(m_deviceObjs.m_dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER));\n    }\n\n    m_gpuTimer.Init();\n\n    ParamVariant p0;\n    p0.InitBool(ICON_FA_FILM \" Renderer\", \"Display\", \"VSync\",\n        fastdelegate::MakeDelegate(this, &RendererCore::SetVSync), m_vsyncInterval > 0);\n    App::AddParam(p0);\n}\n\nvoid RendererCore::InitBasic()\n{\n    m_deviceObjs.InitializeAdapter();\n    m_deviceObjs.CreateDevice(false);\n    InitStaticSamplers();\n}\n\nvoid RendererCore::ResizeBackBuffers(HWND hwnd)\n{\n    // Ff back buffers already exist, resize them\n    if (m_backBuffers[0].IsInitialized())\n    {\n        // GPU is flushed, no need to wait\n        for (int i = 0; i < Constants::NUM_BACK_BUFFERS; i++)\n        {\n            // Don't check ref count for backbuffer COM object as it's 3 rather than 1:\n            // \"DXGI_SWAP_EFFECT_FLIP_DISCARD is valid for a swap chain with more than one back buffer; although \n            // applications have read and write access only to buffer 0\"\n            // Ref: https://learn.microsoft.com/en-us/windows/win32/api/dxgi/ne-dxgi-dxgi_swap_effect\n            m_backBuffers[i].Reset(false, false);\n        }\n\n        m_deviceObjs.ResizeSwapChain(m_displayWidth, m_displayHeight, \n            Constants::MAX_SWAPCHAIN_FRAME_LATENCY);\n    }\n    else\n    {\n        m_deviceObjs.CreateSwapChain(m_directQueue.GetCommandQueue(),\n            hwnd,\n            m_displayWidth, m_displayHeight,\n            Constants::NUM_BACK_BUFFERS,\n            Direct3DUtil::NoSRGB(Constants::BACK_BUFFER_FORMAT),\n            Constants::MAX_SWAPCHAIN_FRAME_LATENCY);\n    }\n\n    m_currBackBuffIdx = (uint16_t)m_deviceObjs.m_dxgiSwapChain->GetCurrentBackBufferIndex();\n\n    // Obtain the back buffers\n    for (int i = 0; i < Constants::NUM_BACK_BUFFERS; i++)\n    {\n        ID3D12Resource* backbuff;\n        CheckHR(m_deviceObjs.m_dxgiSwapChain->GetBuffer(i, IID_PPV_ARGS(&backbuff)));\n\n        StackStr(buff, n, \"Backbuffer_%d\", i);\n        m_backBuffers[i] = ZetaMove(Texture(buff, ZetaMove(backbuff), \n            RESOURCE_HEAP_TYPE::COMMITTED));\n    }\n\n    for (int i = 0; i < Constants::NUM_BACK_BUFFERS; i++)\n    {\n        D3D12_RENDER_TARGET_VIEW_DESC desc{};\n        desc.Format = Constants::BACK_BUFFER_FORMAT;\n        desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;\n\n        m_deviceObjs.m_device->CreateRenderTargetView(m_backBuffers[i].Resource(), \n            &desc, m_backbuffDescTable.CPUHandle(i));\n    }\n\n    m_displayViewport.TopLeftX = 0.0f;\n    m_displayViewport.TopLeftY = 0.0f;\n    m_displayViewport.Width = (float)m_displayWidth;\n    m_displayViewport.Height = (float)m_displayHeight;\n    m_displayViewport.MinDepth = D3D12_MIN_DEPTH;\n    m_displayViewport.MaxDepth = D3D12_MAX_DEPTH;\n\n    m_displayScissor.left = 0;\n    m_displayScissor.top = 0;\n    m_displayScissor.right = m_displayWidth;\n    m_displayScissor.bottom = m_displayHeight;\n}\n\nvoid RendererCore::Shutdown()\n{\n    if (!m_deviceObjs.m_tearingSupport)\n    {\n        // Ref: https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/d3d10-graphics-programming-guide-dxgi\n        // \"You may not release a swap chain in full-screen mode because doing so may create thread contention\"\n        m_deviceObjs.m_dxgiSwapChain->SetFullscreenState(false, nullptr);\n    }\n\n    // GPU has been flushed, no need to sync\n    for (int i = 0; i < Constants::NUM_BACK_BUFFERS; i++)\n        m_backBuffers[i].Reset(false, false);\n\n    // Make sure all GPU resources (texture, buffers, etc) are manually released,\n    // as they normally call the GPU memory subsystem upon destruction, which\n    // is deleted after this point.\n    m_gpuTimer.Shutdown();\n\n    GpuMemory::Shutdown();\n}\n\nvoid RendererCore::OnWindowSizeChanged(HWND hwnd, uint16_t renderWidth, uint16_t renderHeight, \n    uint16_t displayWidth, uint16_t displayHeight)\n{\n    FlushAllCommandQueues();\n\n    const bool resizeNeeded = displayWidth != m_displayWidth || displayHeight != m_displayHeight;\n\n    m_renderWidth = renderWidth;\n    m_renderHeight = renderHeight;\n    m_displayWidth = displayWidth;\n    m_displayHeight = displayHeight;\n\n    if (resizeNeeded)\n    {\n        ResizeBackBuffers(hwnd);\n\n        BOOL fullscreenState;\n        CheckHR(m_deviceObjs.m_dxgiSwapChain->GetFullscreenState(&fullscreenState, nullptr));\n\n        // DXGI_PRESENT_ALLOW_TEARING cannot be enabled in full-screen\n        if (fullscreenState)\n            m_presentFlags &= ~DXGI_PRESENT_ALLOW_TEARING;\n    }\n\n    m_renderViewport.TopLeftX = 0.0f;\n    m_renderViewport.TopLeftY = 0.0f;\n    m_renderViewport.Width = (float)m_renderWidth;\n    m_renderViewport.Height = (float)m_renderHeight;\n    m_renderViewport.MinDepth = D3D12_MIN_DEPTH;\n    m_renderViewport.MaxDepth = D3D12_MAX_DEPTH;\n\n    m_renderScissor.left = 0;\n    m_renderScissor.top = 0;\n    m_renderScissor.right = m_renderWidth;\n    m_renderScissor.bottom = m_renderHeight;\n}\n\nvoid RendererCore::WaitForSwapChainWaitableObject()\n{\n    // Blocks until eariliest queued present is completed\n    WaitForSingleObject(m_deviceObjs.m_frameLatencyWaitableObj, 16);\n}\n\nvoid RendererCore::BeginFrame()\n{\n    if (App::GetTimer().GetTotalFrameCount() > 0)\n        GpuMemory::BeginFrame();\n\n    m_gpuTimer.BeginFrame();\n}\n\nvoid RendererCore::SubmitResourceCopies()\n{\n    GpuMemory::SubmitResourceCopies();\n\n    App::AddFrameStat(\"Renderer\", \"RTV Desc. Heap\", \n        m_rtvDescHeap.GetHeapSize() - m_rtvDescHeap.GetNumFreeDescriptors(), \n        m_rtvDescHeap.GetHeapSize());\n    App::AddFrameStat(\"Renderer\", \"Gpu Desc. Heap\", \n        m_cbvSrvUavDescHeapGpu.GetHeapSize() - m_cbvSrvUavDescHeapGpu.GetNumFreeDescriptors(), \n        m_cbvSrvUavDescHeapGpu.GetHeapSize());\n}\n\nvoid RendererCore::EndFrame(TaskSet& endFrameTS)\n{\n    auto h0 = endFrameTS.EmplaceTask(\"Present\", [this]()\n        {\n            auto hr = m_deviceObjs.m_dxgiSwapChain->Present(m_vsyncInterval, m_presentFlags);\n            if (FAILED(hr))\n            {\n                if (hr == DXGI_ERROR_DEVICE_REMOVED)\n                {\n                    //ComPtr<ID3D12DeviceRemovedExtendedData1> pDred;\n                    //CheckHR(m_deviceObjs.m_device->QueryInterface(IID_PPV_ARGS(&pDred)));\n\n                    //D3D12_DRED_AUTO_BREADCRUMBS_OUTPUT1 DredAutoBreadcrumbsOutput;\n                    //D3D12_DRED_PAGE_FAULT_OUTPUT DredPageFaultOutput;\n                    //CheckHR(pDred->GetAutoBreadcrumbsOutput1(&DredAutoBreadcrumbsOutput));\n                    //CheckHR(pDred->GetPageFaultAllocationOutput(&DredPageFaultOutput));\n                }\n\n                CheckHR(hr);\n            }\n\n            // Schedule a Signal command in the queue.\n            // Set the fence value for the next frame.\n            m_fenceVals[m_currBackBuffIdx] = m_nextFenceVal;\n            CheckHR(m_directQueue.GetCommandQueue()->Signal(m_fence.Get(), m_nextFenceVal++));\n\n            // Update the back buffer index.\n            const uint16_t nextBackBuffidx = (uint16_t)m_deviceObjs.m_dxgiSwapChain->GetCurrentBackBufferIndex();\n            const uint64_t completed = m_fence->GetCompletedValue();\n\n            if (completed < m_fenceVals[nextBackBuffidx])\n            {\n                CheckHR(m_fence->SetEventOnCompletion(m_fenceVals[nextBackBuffidx], m_event));\n                //uint64_t f = App::GetTimer().GetTotalFrameCount();\n                //printf(\"Frame %llu, CPU waiting for GPU...\\n\", f);\n                WaitForSingleObject(m_event, INFINITE);\n            }\n\n            m_currBackBuffIdx = nextBackBuffidx;\n            m_globalDoubleBuffIdx = (m_globalDoubleBuffIdx + 1) & 0x1;\n        });\n\n    auto h1 = endFrameTS.EmplaceTask(\"RecycleGpuMem\", []()\n        {\n            GpuMemory::Recycle();\n        });\n\n    auto h2 = endFrameTS.EmplaceTask(\"RecycleDescHeaps\", [this]()\n        {\n            m_cbvSrvUavDescHeapGpu.Recycle();\n            m_cbvSrvUavDescHeapCpu.Recycle();\n            m_rtvDescHeap.Recycle();\n            //m_dsvDescHeap.Recycle();\n        });\n}\n\nDXGI_OUTPUT_DESC RendererCore::GetOutputMonitorDesc() const\n{\n    ComPtr<IDXGIOutput> pOutput;\n    CheckHR(m_deviceObjs.m_dxgiSwapChain->GetContainingOutput(&pOutput));\n\n    DXGI_OUTPUT_DESC desc;\n    CheckHR(pOutput->GetDesc(&desc));\n\n    return desc;\n}\n\nuint64_t RendererCore::GetCommandQueueTimeStampFrequency(D3D12_COMMAND_LIST_TYPE t) const\n{\n    uint64_t freq = UINT64_MAX;\n\n    switch (t)\n    {\n    case D3D12_COMMAND_LIST_TYPE_DIRECT:\n        CheckHR(m_directQueue.m_cmdQueue->GetTimestampFrequency(&freq));\n        break;\n    case D3D12_COMMAND_LIST_TYPE_COMPUTE:\n        CheckHR(m_computeQueue.m_cmdQueue->GetTimestampFrequency(&freq));\n        break;\n    default:\n        break;\n    }\n\n    return freq;\n}\n\nGraphicsCmdList* RendererCore::GetGraphicsCmdList()\n{\n    CommandList* ctx = m_directQueue.GetCommandList();\n    Assert(ctx->GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT, \"Invalid downcast.\");\n\n    return static_cast<GraphicsCmdList*>(ctx);\n}\n\nComputeCmdList* RendererCore::GetComputeCmdList()\n{\n    CommandList* ctx = m_computeQueue.GetCommandList();\n    Assert(ctx->GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE, \"Invalid downcast.\");\n\n    return static_cast<ComputeCmdList*>(ctx);\n}\n\n// There is another \"CopyContext\" defined in WinBase.h!\n//CopyCmdList* RendererCore::GetCopyCmdList()\n//{\n//    auto* ctx = m_copyQueue->GetCommandList();\n//    Assert(ctx->CommandListType() == D3D12_COMMAND_LIST_TYPE_COPY, \"Invalid downcast.\");\n//\n//    return static_cast<ZetaRay::CopyCmdList*>(ctx);\n//}\n\nvoid RendererCore::ReleaseCmdList(CommandList* ctx)\n{\n    if (ctx->GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT)\n        m_directQueue.ReleaseCommandList(ctx);    \n    else if (ctx->GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE)\n        m_computeQueue.ReleaseCommandList(ctx);\n}\n\nuint64_t RendererCore::ExecuteCmdList(CommandList* ctx)\n{\n    if (ctx->GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT)\n        return m_directQueue.ExecuteCommandList(ctx);\n    else if (ctx->GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE)\n        return m_computeQueue.ExecuteCommandList(ctx);\n\n    return UINT64_MAX;\n}\n\nvoid RendererCore::SignalDirectQueue(ID3D12Fence* f, uint64_t v)\n{\n    auto* cmdQueue = m_directQueue.GetCommandQueue();\n    Assert(cmdQueue, \"cmdQueue was NULL\");\n    cmdQueue->Signal(f, v);\n}\n\nvoid RendererCore::SignalComputeQueue(ID3D12Fence* f, uint64_t v)\n{\n    m_computeQueue.GetCommandQueue()->Signal(f, v);\n}\n\nbool RendererCore::IsDirectQueueFenceComplete(uint64_t fenceValue)\n{\n    return m_directQueue.IsFenceComplete(fenceValue);\n}\n\nbool RendererCore::IsComputeQueueFenceComplete(uint64_t fenceValue)\n{\n    return m_computeQueue.IsFenceComplete(fenceValue);\n}\n\nvoid RendererCore::WaitForDirectQueueFenceCPU(uint64_t fenceValue)\n{\n    m_directQueue.WaitForFenceCPU(fenceValue);\n}\n\nvoid RendererCore::WaitForDirectQueueFenceCPU2(uint64_t fenceValue, HANDLE e)\n{\n    if (m_directQueue.IsFenceComplete(fenceValue))\n        return;\n\n    CheckHR(m_directQueue.m_fence->SetEventOnCompletion(fenceValue, e));\n    WaitForSingleObject(e, INFINITE);\n}\n\nvoid RendererCore::WaitForComputeQueueFenceCPU(uint64_t fenceValue)\n{\n    m_computeQueue.WaitForFenceCPU(fenceValue);\n}\n\nvoid RendererCore::WaitForDirectQueueOnComputeQueue(uint64_t v)\n{\n    // MS Docs:\n    // \"Queues a GPU-side wait, and returns immediately. A GPU-side wait is where \n    // the GPU waits until the specified fence reaches or exceeds the specified value.\"\n    //\n    // command queue waits (during that time no work is executed) until the fence \n    // reaches the requested value\n    CheckHR(m_computeQueue.m_cmdQueue->Wait(m_directQueue.m_fence.Get(), v));\n}\n\nvoid RendererCore::WaitForComputeQueueOnDirectQueue(uint64_t v)\n{\n    CheckHR(m_directQueue.m_cmdQueue->Wait(m_computeQueue.m_fence.Get(), v));\n}\n\nvoid RendererCore::FlushAllCommandQueues()\n{\n    m_directQueue.WaitForIdle();\n    m_computeQueue.WaitForIdle();\n}\n\nvoid RendererCore::InitStaticSamplers()\n{\n    D3D12_STATIC_SAMPLER_DESC mip0;\n    mip0.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;\n    mip0.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    mip0.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    mip0.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    mip0.MipLODBias = 0;\n    mip0.MaxAnisotropy = 0;\n    mip0.ComparisonFunc = D3D12_COMPARISON_FUNC_NONE;\n    mip0.BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE;\n    mip0.MinLOD = 0.0f;\n    mip0.MaxLOD = 0.0f;\n    mip0.ShaderRegister = 0;\n    mip0.RegisterSpace = 0;\n    mip0.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;\n\n    D3D12_STATIC_SAMPLER_DESC pointWrap;\n    pointWrap.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;\n    pointWrap.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    pointWrap.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    pointWrap.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    pointWrap.MipLODBias = 0;\n    pointWrap.MaxAnisotropy = 0;\n    pointWrap.ComparisonFunc = D3D12_COMPARISON_FUNC_NONE;\n    pointWrap.BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE;\n    pointWrap.MinLOD = 0.0f;\n    pointWrap.MaxLOD = D3D12_FLOAT32_MAX;\n    pointWrap.ShaderRegister = 1;\n    pointWrap.RegisterSpace = 0;\n    pointWrap.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;\n\n    D3D12_STATIC_SAMPLER_DESC pointClamp = pointWrap;\n    pointClamp.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;\n    pointClamp.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;\n    pointClamp.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;\n    pointClamp.ShaderRegister = 2;\n\n    D3D12_STATIC_SAMPLER_DESC linearWrap;\n    linearWrap.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;\n    linearWrap.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    linearWrap.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    linearWrap.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    linearWrap.MipLODBias = 0;\n    linearWrap.MaxAnisotropy = 0;\n    linearWrap.ComparisonFunc = D3D12_COMPARISON_FUNC_NONE;\n    linearWrap.BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE;\n    linearWrap.MinLOD = 0.0f;\n    linearWrap.MaxLOD = D3D12_FLOAT32_MAX;\n    linearWrap.ShaderRegister = 3;\n    linearWrap.RegisterSpace = 0;\n    linearWrap.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;\n\n    D3D12_STATIC_SAMPLER_DESC linearClamp = linearWrap;\n    linearClamp.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;\n    linearClamp.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;\n    linearClamp.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;\n    linearClamp.ShaderRegister = 4;\n\n    D3D12_STATIC_SAMPLER_DESC anisotropicWrap;\n    anisotropicWrap.Filter = D3D12_FILTER_ANISOTROPIC;\n    anisotropicWrap.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    anisotropicWrap.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    anisotropicWrap.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    anisotropicWrap.MipLODBias = 0;\n    anisotropicWrap.MaxAnisotropy = 16;\n    anisotropicWrap.ComparisonFunc = D3D12_COMPARISON_FUNC_NONE;\n    anisotropicWrap.BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE;\n    anisotropicWrap.MinLOD = 0.0f;\n    anisotropicWrap.MaxLOD = D3D12_FLOAT32_MAX;\n    anisotropicWrap.ShaderRegister = 5;\n    anisotropicWrap.RegisterSpace = 0;\n    anisotropicWrap.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;\n\n    D3D12_STATIC_SAMPLER_DESC anisotropicWrap2x = anisotropicWrap;\n    anisotropicWrap2x.MaxAnisotropy = 2;\n    anisotropicWrap2x.ShaderRegister = 6;\n\n    D3D12_STATIC_SAMPLER_DESC anisotropicWrap4x = anisotropicWrap;\n    anisotropicWrap4x.MaxAnisotropy = 4;\n    anisotropicWrap4x.ShaderRegister = 7;\n\n    D3D12_STATIC_SAMPLER_DESC imguiSampler;\n    imguiSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;\n    imguiSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    imguiSampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    imguiSampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;\n    imguiSampler.MipLODBias = 0.0f;\n    imguiSampler.MaxAnisotropy = 0;\n    imguiSampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NONE;\n    imguiSampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;\n    imguiSampler.MinLOD = 0.0f;\n    imguiSampler.MaxLOD = 0.0f;\n    imguiSampler.ShaderRegister = 8;\n    imguiSampler.RegisterSpace = 0;\n    imguiSampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;\n\n    m_staticSamplers[0] = mip0;\n    m_staticSamplers[1] = pointWrap;\n    m_staticSamplers[2] = pointClamp;\n    m_staticSamplers[3] = linearWrap;\n    m_staticSamplers[4] = linearClamp;\n    m_staticSamplers[5] = anisotropicWrap;\n    m_staticSamplers[6] = anisotropicWrap2x;\n    m_staticSamplers[7] = anisotropicWrap4x;\n    m_staticSamplers[8] = imguiSampler;\n\n    D3D12_DESCRIPTOR_HEAP_DESC desc;\n    desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;\n    desc.NumDescriptors = ZetaArrayLen(m_staticSamplers);\n    desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;\n    desc.NodeMask = 0;\n\n    auto* device = App::GetRenderer().GetDevice();\n    CheckHR(device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(m_samplerDescHeap.GetAddressOf())));\n\n    const auto descSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);\n    const auto baseCpuHandle = m_samplerDescHeap->GetCPUDescriptorHandleForHeapStart();\n\n    D3D12_SAMPLER_DESC samplerDescs[ZetaArrayLen(m_staticSamplers)];\n    for (int i = 0; i < ZetaArrayLen(m_staticSamplers); i++)\n    {\n        samplerDescs[i].Filter = m_staticSamplers[i].Filter;\n        samplerDescs[i].AddressU = m_staticSamplers[i].AddressU;\n        samplerDescs[i].AddressV = m_staticSamplers[i].AddressV;\n        samplerDescs[i].AddressW = m_staticSamplers[i].AddressW;\n        samplerDescs[i].MipLODBias = m_staticSamplers[i].MipLODBias;\n        samplerDescs[i].MaxAnisotropy = m_staticSamplers[i].MaxAnisotropy;\n        samplerDescs[i].ComparisonFunc = m_staticSamplers[i].ComparisonFunc;\n        samplerDescs[i].MinLOD = m_staticSamplers[i].MinLOD;\n        samplerDescs[i].MaxLOD = m_staticSamplers[i].MaxLOD;\n        samplerDescs[i].BorderColor[0] = 0;\n        samplerDescs[i].BorderColor[1] = 0;\n        samplerDescs[i].BorderColor[2] = 0;\n        samplerDescs[i].BorderColor[3] = 0;\n        \n        D3D12_CPU_DESCRIPTOR_HANDLE handle{\n            .ptr = baseCpuHandle.ptr + i * descSize\n        };\n        device->CreateSampler(&samplerDescs[i], handle);\n    }\n}\n\nvoid RendererCore::SetVSync(const ParamVariant& p)\n{\n    m_vsyncInterval = p.GetBool() ? 1 : 0;\n\n    if (m_vsyncInterval == 0 && m_deviceObjs.m_tearingSupport)\n    {\n        m_presentFlags |= DXGI_PRESENT_ALLOW_TEARING;\n        //CheckHR(m_deviceObjs.m_dxgiFactory->MakeWindowAssociation(m_hwnd, DXGI_MWA_NO_ALT_ENTER));\n    }\n    else\n        m_presentFlags = 0;\n}"
  },
  {
    "path": "Source/ZetaCore/Core/RendererCore.h",
    "content": "#pragma once\n\n#include \"Config.h\"\n#include \"DescriptorHeap.h\"\n#include \"GpuTimer.h\"\n#include \"CommandQueue.h\"\n#include \"SharedShaderResources.h\"\n\nnamespace ZetaRay::Support\n{\n    struct TaskSet;\n    struct ParamVariant;\n}\n\nnamespace ZetaRay::Core\n{\n    struct CommandQueue;\n    class CommandList;\n    class GraphicsCmdList;\n    class ComputeCmdList;\n    class CopyCmdList;\n    class SharedShaderResources;\n\n    class RendererCore\n    {\n    public:\n        RendererCore();\n        ~RendererCore();\n\n        RendererCore(const RendererCore&) = delete;\n        RendererCore& operator=(const RendererCore&) = delete;\n\n        void Init(HWND hwnd, uint16_t renderWidth, uint16_t renderHeight, \n            uint16_t displayWidth, uint16_t displayHeight);\n        void Shutdown();\n        void InitBasic();\n        void ShutdownBasic() {};\n        void OnWindowSizeChanged(HWND hwnd, uint16_t renderWidth, uint16_t renderHeight, \n            uint16_t displayWidth, uint16_t displayHeight);\n        void WaitForSwapChainWaitableObject();\n        void BeginFrame();\n        void SubmitResourceCopies();\n        void EndFrame(Support::TaskSet& endFrameTS);\n\n        ZetaInline ID3D12Device10* GetDevice() { return m_deviceObjs.m_device.Get(); };\n        ZetaInline const char* GetDeviceDescription() { return m_deviceObjs.m_deviceName; }\n        ZetaInline IDXGIAdapter3* GetAdapter() { return m_deviceObjs.m_dxgiAdapter.Get(); }\n        DXGI_OUTPUT_DESC GetOutputMonitorDesc() const;\n        uint64_t GetCommandQueueTimeStampFrequency(D3D12_COMMAND_LIST_TYPE t) const;\n\n        ZetaInline uint16_t GetRenderWidth() const { return m_renderWidth; }\n        ZetaInline uint16_t GetRenderHeight() const { return m_renderHeight; }\n        ZetaInline uint16_t GetDisplayWidth() const { return m_displayWidth; }\n        ZetaInline uint16_t GetDisplayHeight() const { return m_displayHeight; }\n        ZetaInline float GetAspectRatio() const { return (float)m_renderWidth / m_renderHeight; }\n        ZetaInline int GetCurrentBackBufferIndex() const { return m_currBackBuffIdx; }\n        ZetaInline const GpuMemory::Texture& GetCurrentBackBuffer() { return m_backBuffers[m_currBackBuffIdx]; }\n        ZetaInline D3D12_CPU_DESCRIPTOR_HANDLE GetCurrBackBufferRTV() const { return m_backbuffDescTable.CPUHandle(m_currBackBuffIdx); }\n\n        ZetaInline SharedShaderResources& GetSharedShaderResources() { return m_sharedShaderRes; }\n        ZetaInline DescriptorHeap& GetGpuDescriptorHeap() { return m_cbvSrvUavDescHeapGpu; };\n        ZetaInline ID3D12DescriptorHeap* GetSamplerDescriptorHeap() { return m_samplerDescHeap.Get(); };\n        ZetaInline DescriptorHeap& GetCbvSrvUavDescriptorHeapCpu() { return m_cbvSrvUavDescHeapCpu; };\n        ZetaInline DescriptorHeap& GetRtvDescriptorHeap() { return m_rtvDescHeap; };\n        //ZetaInline DescriptorHeap& GetDsvDescriptorHeap() { return m_dsvDescHeap; };\n        ZetaInline GpuTimer& GetGpuTimer() { return m_gpuTimer; }\n\n        GraphicsCmdList* GetGraphicsCmdList();\n        ComputeCmdList* GetComputeCmdList();\n        //CopyCmdList* GetCopyCmdList();\n        void ReleaseCmdList(CommandList* ctx);\n        uint64_t ExecuteCmdList(CommandList* ctx);\n\n        void SignalDirectQueue(ID3D12Fence* f, uint64_t v);\n        void SignalComputeQueue(ID3D12Fence* f, uint64_t v);\n        // void SignalCopyQueue(ID3D12Fence* f, uint64_t v);\n\n        bool IsDirectQueueFenceComplete(uint64_t fenceValue);\n        bool IsComputeQueueFenceComplete(uint64_t fenceValue);\n\n        // Waits (CPU side) for the fence on Direct Queue to reach the \n        // specified value (blocking)\n        void WaitForDirectQueueFenceCPU(uint64_t fenceValue);\n        void WaitForDirectQueueFenceCPU2(uint64_t fenceValue, HANDLE e);\n\n        // Waits (CPU side) for the fence on Direct Queue to reach the \n        // specified value (blocking)\n        void WaitForComputeQueueFenceCPU(uint64_t fenceValue);\n\n        // Issues a GPU-side wait on the Compute Queue for the fence on the \n        // Direct Queue. Corresponding fence\n        // can only be signalled through ExecuteCmdList() calls.\n        void WaitForDirectQueueOnComputeQueue(uint64_t v);\n\n        // Issues a GPU-side wait on the Direct Queue for the Fence on the \n        // Compute Queue. Corresponding fence\n        // can only be signalled through ExecuteCmdList() calls.\n        void WaitForComputeQueueOnDirectQueue(uint64_t v);\n\n        // Issue a GPU-side wait on the Direct/Compute Queue for the Fence \n        // on the copy queue. That fence\n        // can only signalled through ExecuteCmdList() calls.\n        //void WaitForCopyQueueOnDirectQueue(uint64_t v);\n        //void WaitForCopyQueueOnComputeQueue(uint64_t v);\n        void FlushAllCommandQueues();\n\n        ZetaInline D3D12_VIEWPORT GetDisplayViewport() const { return m_displayViewport; }\n        ZetaInline D3D12_RECT GetDisplayScissor() const { return m_displayScissor; }\n        ZetaInline D3D12_VIEWPORT GetRenderViewport() const { return m_renderViewport; }\n        ZetaInline D3D12_RECT GetRenderScissor() const { return m_renderScissor; }\n\n        ZetaInline bool IsRGBESupported() const { return m_deviceObjs.m_rgbeSupport; };\n        ZetaInline bool IsTearingSupported() const { return m_vsyncInterval == 0 && m_deviceObjs.m_tearingSupport; };\n        ZetaInline int GetVSyncInterval() const { return m_vsyncInterval; }\n\n        ZetaInline Util::Span<D3D12_STATIC_SAMPLER_DESC> GetStaticSamplers() { return m_staticSamplers; };\n        ZetaInline int GlobalIdxForDoubleBufferedResources() const { return m_globalDoubleBuffIdx; }\n        ZetaInline const DescriptorTable& ReservedDescTable() const { return m_reserved; }\n\n    private:\n        void ResizeBackBuffers(HWND hwnd);\n        void InitStaticSamplers();\n        void SetVSync(const Support::ParamVariant& p);\n\n        DeviceObjects m_deviceObjs;\n\n        SharedShaderResources m_sharedShaderRes;\n        DescriptorHeap m_cbvSrvUavDescHeapGpu;\n        DescriptorHeap m_cbvSrvUavDescHeapCpu;\n        DescriptorHeap m_rtvDescHeap;\n        ComPtr<ID3D12DescriptorHeap> m_samplerDescHeap;\n        //DescriptorHeap m_dsvDescHeap;\n        CommandQueue m_directQueue;\n        CommandQueue m_computeQueue;\n        //CommandQueue m_copyQueue;\n\n        DescriptorTable m_backbuffDescTable;\n        DescriptorTable m_depthBuffDescTable;\n        DescriptorTable m_reserved;\n\n        HWND m_hwnd;\n        GpuMemory::Texture m_backBuffers[Constants::NUM_BACK_BUFFERS];\n        uint16_t m_currBackBuffIdx = 0;\n        uint16_t m_displayWidth;\n        uint16_t m_displayHeight;\n        uint16_t m_renderWidth;\n        uint16_t m_renderHeight;\n        UINT m_presentFlags = 0;\n        uint16_t m_vsyncInterval = 1;\n        uint16_t m_globalDoubleBuffIdx = 0;\n\n        D3D12_VIEWPORT m_displayViewport;\n        D3D12_RECT m_displayScissor;\n        D3D12_VIEWPORT m_renderViewport;\n        D3D12_RECT m_renderScissor;\n\n        D3D12_STATIC_SAMPLER_DESC m_staticSamplers[9];\n\n        ComPtr<ID3D12Fence> m_fence;\n        uint64_t m_fenceVals[Constants::NUM_BACK_BUFFERS] = { 0 };\n        uint64_t m_nextFenceVal = 1;\n        HANDLE m_event;\n\n        GpuTimer m_gpuTimer;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Core/RootSignature.cpp",
    "content": "#include \"RootSignature.h\"\n#include \"RendererCore.h\"\n#include \"CommandList.h\"\n#include \"SharedShaderResources.h\"\n#include <xxHash/xxhash.h>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Util;\n\nnamespace\n{\n    template <typename T>\n    requires std::same_as<T, GraphicsCmdList> || std::same_as<T, ComputeCmdList>\n    void End_Internal(T& ctx, uint32_t rootCBVBitMap, uint32_t rootSRVBitMap, uint32_t rootUAVBitMap, \n        uint32_t globalsBitMap, uint32_t& modifiedBitMap, uint32_t& modifiedGlobalsBitMap, uint32_t optionalBitMap,\n        int rootConstantsIdx, Span<uint32_t> rootConstants, Span<D3D12_GPU_VIRTUAL_ADDRESS> rootDescriptors,\n        Span<uint64_t> globals)\n    {\n        // Root constants\n        if (rootConstantsIdx != -1 && (modifiedBitMap & (1 << rootConstantsIdx)))\n        {\n            ctx.SetRoot32BitConstants(rootConstantsIdx, (uint32_t)rootConstants.size(), rootConstants.data(), 0);\n            modifiedBitMap ^= (1 << rootConstantsIdx);\n        }\n\n        uint32_t mask;\n        DWORD nextParam;\n\n        // Root CBV\n        mask = rootCBVBitMap;\n        while (_BitScanForward(&nextParam, mask))\n        {\n            mask ^= (1 << nextParam);\n\n            if ((1 << nextParam) & globalsBitMap)\n                continue;\n\n            if ((modifiedBitMap & (1 << nextParam)) == 0)\n                continue;\n\n            modifiedBitMap ^= (1 << nextParam);\n\n            if (rootDescriptors[nextParam] != D3D12_GPU_VIRTUAL_ADDRESS(0))\n                ctx.SetRootConstantBufferView(nextParam, rootDescriptors[nextParam]);\n            else\n                Assert(optionalBitMap & (1 << nextParam), \"Root CBV in parameter %d has not been set\", nextParam);\n        }\n\n        // Root SRV\n        mask = rootSRVBitMap;\n        while (_BitScanForward(&nextParam, mask))\n        {\n            mask ^= (1 << nextParam);\n\n            if ((1 << nextParam) & globalsBitMap)\n                continue;\n\n            if ((modifiedBitMap & (1 << nextParam)) == 0)\n                continue;\n\n            modifiedBitMap ^= (1 << nextParam);\n\n            if (rootDescriptors[nextParam] != D3D12_GPU_VIRTUAL_ADDRESS(0))\n                ctx.SetRootShaderResourceView(nextParam, rootDescriptors[nextParam]);\n            else\n                Assert(optionalBitMap & (1 << nextParam), \"Root SRV in parameter %d has not been set\", nextParam);\n        }\n\n        // Root UAV\n        mask = rootUAVBitMap;\n        while (_BitScanForward(&nextParam, mask))\n        {\n            mask ^= (1 << nextParam);\n\n            if ((1 << nextParam) & globalsBitMap)\n                continue;\n\n            if ((modifiedBitMap & (1 << nextParam)) == 0)\n                continue;\n\n            modifiedBitMap ^= (1 << nextParam);\n\n            if (rootDescriptors[nextParam] != D3D12_GPU_VIRTUAL_ADDRESS(0))\n                ctx.SetRootUnorderedAccessView(nextParam, rootDescriptors[nextParam]);\n            else\n                Assert(optionalBitMap & (1 << nextParam), \"Root UAV in parameter %d has not been set\", nextParam);\n        }\n\n        // Globals\n        SharedShaderResources& shared = App::GetRenderer().GetSharedShaderResources();\n\n        while (_BitScanForward(&nextParam, modifiedGlobalsBitMap))\n        {\n            uint32_t rootBitMap = (1 << nextParam);\n            modifiedGlobalsBitMap ^= rootBitMap;\n\n            if (rootBitMap & rootCBVBitMap)\n            {\n                auto* defaultHeapBuff = shared.GetDefaultHeapBuffer(globals[nextParam]);\n                if (defaultHeapBuff)\n                    ctx.SetRootConstantBufferView(nextParam, defaultHeapBuff->GpuVA());\n                else\n                {\n                    auto* uploadHeapBuff = shared.GetUploadHeapBuffer(globals[nextParam]);\n                    if (uploadHeapBuff)\n                        ctx.SetRootConstantBufferView(nextParam, uploadHeapBuff->GpuVA());\n                    else\n                        Assert(optionalBitMap & (1 << nextParam), \"Global resource in parameter %d was not found.\", nextParam);\n                }\n            }\n            else if (rootBitMap & rootSRVBitMap)\n            {\n                auto* defaultHeapBuff = shared.GetDefaultHeapBuffer(globals[nextParam]);\n                if (defaultHeapBuff)\n                    ctx.SetRootShaderResourceView(nextParam, defaultHeapBuff->GpuVA());\n                else\n                {\n                    auto* uploadHeapBuff = shared.GetUploadHeapBuffer(globals[nextParam]);\n                    if (uploadHeapBuff)\n                        ctx.SetRootShaderResourceView(nextParam, uploadHeapBuff->GpuVA());\n                    else\n                        Assert(optionalBitMap & (1 << nextParam), \"Global resource in parameter %d was not found.\", nextParam);\n                }\n            }\n            else if (rootBitMap & rootUAVBitMap)\n            {\n                // UAV must be a default heap buffer\n                auto* defaultHeapBuff = shared.GetDefaultHeapBuffer(globals[nextParam]);\n                if (defaultHeapBuff)\n                    ctx.SetRootUnorderedAccessView(nextParam, defaultHeapBuff->GpuVA());\n                else\n                    Assert(optionalBitMap & (1 << nextParam), \"Global resource in parameter %d was not found.\", nextParam);\n            }\n            else\n                Assert(false, \"Root global was not found.\");\n        }\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// RootSignature\n//--------------------------------------------------------------------------------------\n\nRootSignature::RootSignature(int nCBV, int nSRV, int nUAV, int nGlobs, int nConsts)\n    : m_numParams(nCBV + nSRV + nUAV + (nConsts > 0)),\n    m_numCBVs(nCBV),\n    m_numSRVs(nSRV),\n    m_numUAVs(nUAV),\n    m_numGlobals(nGlobs),\n    m_numRootConstants(nConsts)\n{\n    Assert((nCBV + nSRV + nUAV) * 2 + nConsts <= 64, \n        \"A maximum of 64 DWORDS can be present at root signature.\");\n    Assert(nCBV + nSRV + nUAV + (nConsts > 0 ? 1 : 0) <= MAX_NUM_PARAMS, \n        \"Number of root parameters can't exceed MAX_NUM_PARAMS.\");\n    Assert(nConsts <= MAX_NUM_ROOT_CONSTANTS, \n        \"Number of root constants can't exceed MAX_NUM_ROOT_CONSTANTS.\");\n}\n\nvoid RootSignature::InitAsConstants(uint32_t rootIdx, uint32_t numDwords, uint32_t registerNum,\n    uint32_t registerSpace, D3D12_SHADER_VISIBILITY visibility)\n{\n    Assert(rootIdx < m_numParams, \"Root index %d is out of bounds.\", rootIdx);\n    Assert(m_numRootConstants == numDwords, \n        \"Given number of root constants doesn't match m_numRootConstants.\");\n\n    m_params[rootIdx].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;\n    m_params[rootIdx].ShaderVisibility = visibility;\n    m_params[rootIdx].Constants.Num32BitValues = numDwords;\n    m_params[rootIdx].Constants.ShaderRegister = registerNum;\n    m_params[rootIdx].Constants.RegisterSpace = registerSpace;\n}\n\nvoid RootSignature::InitAsCBV(uint32_t rootIdx, uint32_t registerNum, uint32_t registerSpace, \n    D3D12_ROOT_DESCRIPTOR_FLAGS flags, const char* id, bool isOptional, D3D12_SHADER_VISIBILITY visibility)\n{\n    Assert(rootIdx < m_numParams, \"Root index %d is out of bounds.\", rootIdx);\n    Assert((m_rootCBVBitMap & (1 << rootIdx)) == 0, \"Root parameter was already set as CBV.\");\n    Assert((m_rootSRVBitMap & (1 << rootIdx)) == 0, \"Root parameter was already set as SRV.\");\n    Assert((m_rootUAVBitMap & (1 << rootIdx)) == 0, \"Root parameter was already set as UAV.\");\n    Assert((m_globalsBitMap & (1 << rootIdx)) == 0, \"Root parameter was already set as Global.\");\n\n    m_params[rootIdx].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;\n    m_params[rootIdx].ShaderVisibility = visibility;\n    m_params[rootIdx].Descriptor.ShaderRegister = registerNum;\n    m_params[rootIdx].Descriptor.RegisterSpace = registerSpace;\n    m_params[rootIdx].Descriptor.Flags = flags;\n\n    m_rootCBVBitMap |= (1 << rootIdx);\n\n    if (id)\n    {\n        m_globals[rootIdx] = XXH3_64bits(id, strlen(id));\n        m_globalsBitMap |= (1 << rootIdx);\n    }\n\n    if (isOptional)\n        m_optionalBitMap |= (1 << rootIdx);\n}\n\nvoid RootSignature::InitAsBufferSRV(uint32_t rootIdx, uint32_t registerNum, uint32_t registerSpace, \n    D3D12_ROOT_DESCRIPTOR_FLAGS flags, const char* id, bool isOptional, D3D12_SHADER_VISIBILITY visibility)\n{\n    Assert(rootIdx < m_numParams, \"Root index %d is out of bounds.\", rootIdx);\n    Assert((m_rootCBVBitMap & (1 << rootIdx)) == 0, \"Root parameter was already set as CBV.\");\n    Assert((m_rootSRVBitMap & (1 << rootIdx)) == 0, \"Root parameter was already set as SRV.\");\n    Assert((m_rootUAVBitMap & (1 << rootIdx)) == 0, \"Root parameter was already set as UAV.\");\n    Assert((m_globalsBitMap & (1 << rootIdx)) == 0, \"Root parameter was already set as Global.\");\n\n    m_params[rootIdx].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;\n    m_params[rootIdx].ShaderVisibility = visibility;\n    m_params[rootIdx].Descriptor.ShaderRegister = registerNum;\n    m_params[rootIdx].Descriptor.RegisterSpace = registerSpace;\n    m_params[rootIdx].Descriptor.Flags = flags;\n\n    m_rootSRVBitMap |= (1 << rootIdx);\n    \n    if (id)\n    {\n        m_globals[rootIdx] = XXH3_64bits(id, strlen(id));\n        m_globalsBitMap |= (1 << rootIdx);\n    }\n\n    if (isOptional)\n        m_optionalBitMap |= (1 << rootIdx);\n}\n\nvoid RootSignature::InitAsBufferUAV(uint32_t rootIdx, uint32_t registerNum, uint32_t registerSpace, \n    D3D12_ROOT_DESCRIPTOR_FLAGS flags, const char* id, bool isOptional, D3D12_SHADER_VISIBILITY visibility)\n{\n    Assert(rootIdx < m_numParams, \"Root index %d is out of bounds.\", rootIdx);\n    Assert((m_rootCBVBitMap & (1 << rootIdx)) == 0, \"Root parameter was already set as CBV.\");\n    Assert((m_rootSRVBitMap & (1 << rootIdx)) == 0, \"Root parameter was already set as SRV.\");\n    Assert((m_rootUAVBitMap & (1 << rootIdx)) == 0, \"Root parameter was already set as UAV.\");\n    Assert((m_globalsBitMap & (1 << rootIdx)) == 0, \"Root parameter was already set as Global.\");\n\n    m_params[rootIdx].ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV;\n    m_params[rootIdx].ShaderVisibility = visibility;\n    m_params[rootIdx].Descriptor.ShaderRegister = registerNum;\n    m_params[rootIdx].Descriptor.RegisterSpace = registerSpace;\n    m_params[rootIdx].Descriptor.Flags = flags;\n\n    m_rootUAVBitMap |= (1 << rootIdx);\n\n    if (id)\n    {\n        m_globals[rootIdx] = XXH3_64bits(id, strlen(id));\n        m_globalsBitMap |= (1 << rootIdx);\n    }\n\n    if (isOptional)\n        m_optionalBitMap |= (1 << rootIdx);\n}\n\nvoid RootSignature::Finalize(const char* name, ComPtr<ID3D12RootSignature>& rootSig, \n    Span<D3D12_STATIC_SAMPLER_DESC> samplers, D3D12_ROOT_SIGNATURE_FLAGS flags)\n{\n    D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootSigDesc{};\n    rootSigDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;\n    rootSigDesc.Desc_1_1.NumParameters = m_numParams;\n    rootSigDesc.Desc_1_1.pParameters = m_params;\n    rootSigDesc.Desc_1_1.NumStaticSamplers = UINT(samplers.size());\n    rootSigDesc.Desc_1_1.pStaticSamplers = samplers.data();\n    rootSigDesc.Desc_1_1.Flags = flags;\n\n    ComPtr<ID3DBlob> pOutBlob, pErrorBlob;\n    HRESULT hr = D3D12SerializeVersionedRootSignature(&rootSigDesc, pOutBlob.GetAddressOf(), \n        pErrorBlob.GetAddressOf());\n\n    if (FAILED(hr))\n    {\n        const char* error = pErrorBlob ? (const char* )pErrorBlob->GetBufferPointer() : \n            \"Unknown error.\";\n        Check(false, \"D3D12SerializeVersionedRootSignature() failed: %s\", error);\n    }\n\n    auto* device = App::GetRenderer().GetDevice();\n    CheckHR(device->CreateRootSignature(0,\n        pOutBlob->GetBufferPointer(),\n        pOutBlob->GetBufferSize(),\n        IID_PPV_ARGS(rootSig.GetAddressOf())));\n\n    Assert(name, \"name was NULL\");\n    rootSig->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)strlen(name), name);\n\n    // Calculate root parameter index for root constants (if any)\n    uint32_t u = (1 << m_numParams) - 1;        // set the first NumParams() bits to 1\n    u &= (m_rootCBVBitMap | m_rootSRVBitMap | m_rootUAVBitMap | m_globalsBitMap);\n\n    DWORD idx;\n    m_rootConstantsIdx = _BitScanForward(&idx, ~u) && (idx < m_numParams) ? (int)idx : -1;\n}\n\nvoid RootSignature::Begin()\n{\n    m_modifiedBitMap = (1 << m_numParams) - 1;\n\n    // Given the assumption that globals don't get destroyed/recreated per draw/dispatch call,\n    // set each global to modified only at the beginning of each frame\n    m_modifiedGlobalsBitMap = m_globalsBitMap;\n\n    memset(m_rootDescriptors, 0, sizeof(D3D12_GPU_VIRTUAL_ADDRESS) * MAX_NUM_PARAMS);\n}\n\nvoid RootSignature::SetRootConstants(uint32_t offset, uint32_t num, const void* data)\n{\n    Assert(offset + num <= m_numRootConstants, \"Out-of-bound write.\");\n    memcpy(&m_rootConstants[offset], data, sizeof(uint32_t) * num);\n\n    m_modifiedBitMap |= (1 << m_rootConstantsIdx);\n}\n\nvoid RootSignature::SetRootCBV(uint32_t rootIdx, D3D12_GPU_VIRTUAL_ADDRESS va)\n{\n    Assert((1 << rootIdx) & m_rootCBVBitMap, \"Root parameter %u was not set as root CBV.\", \n        rootIdx);\n    Assert(!((1 << rootIdx) & m_globalsBitMap), \"Root parameter %u was set as global.\", \n        rootIdx);\n\n    m_rootDescriptors[rootIdx] = va;\n    m_modifiedBitMap |= (1 << rootIdx);\n}\n\nvoid RootSignature::SetRootSRV(uint32_t rootIdx, D3D12_GPU_VIRTUAL_ADDRESS va)\n{\n    Assert((1 << rootIdx) & m_rootSRVBitMap, \"Root parameter %u was not set as root SRV.\", \n        rootIdx);\n    Assert(!((1 << rootIdx) & m_globalsBitMap), \"Root parameter %u was set as global.\", \n        rootIdx);\n\n    m_rootDescriptors[rootIdx] = va;\n    m_modifiedBitMap |= (1 << rootIdx);\n}\n\nvoid RootSignature::SetRootUAV(uint32_t rootIdx, D3D12_GPU_VIRTUAL_ADDRESS va)\n{\n    Assert((1 << rootIdx) & m_rootUAVBitMap, \"Root parameter %u was not set as root UAV.\", \n        rootIdx);\n    Assert(!((1 << rootIdx) & m_globalsBitMap), \"Root parameter %u was set as global.\", \n        rootIdx);\n\n    m_rootDescriptors[rootIdx] = va;\n    m_modifiedBitMap |= (1 << rootIdx);\n}\n\nvoid RootSignature::End(GraphicsCmdList& ctx)\n{\n    End_Internal(ctx, m_rootCBVBitMap, m_rootSRVBitMap, m_rootUAVBitMap, m_globalsBitMap, \n        m_modifiedBitMap, m_modifiedGlobalsBitMap, m_optionalBitMap, m_rootConstantsIdx, \n        Span(m_rootConstants, m_numRootConstants), m_rootDescriptors, m_globals);\n}\n\nvoid RootSignature::End(ComputeCmdList& ctx)\n{\n    End_Internal(ctx, m_rootCBVBitMap, m_rootSRVBitMap, m_rootUAVBitMap, m_globalsBitMap,\n        m_modifiedBitMap, m_modifiedGlobalsBitMap, m_optionalBitMap, m_rootConstantsIdx,\n        Span(m_rootConstants, m_numRootConstants), m_rootDescriptors, m_globals);\n}\n"
  },
  {
    "path": "Source/ZetaCore/Core/RootSignature.h",
    "content": "#pragma once\n\n#include \"Device.h\"\n\nnamespace ZetaRay::Util\n{\n    template<typename T>\n    struct Span;\n}\n\nnamespace ZetaRay::Core\n{\n    class GraphicsCmdList;\n    class ComputeCmdList;\n\n    // All the needed scenarios\n    // \n    // 1. Upload heap buffer (read-only, GENERIC_READ)\n    //        a. constant buffer\n    //            I. local -> root CBV -> Set*RootConstantBufferView(GpuVA)\n    //            II. global -> root CBV (sharedshaderres has the buff and provides GpuVA)\n    // \n    //        b. structured buffer (consider copying to default heap?)\n    //            I. local -> root SRV -> Set*RootShaderResourceView(GpuVA)\n    //                        (UAV is not needed)\n    //            II. global -> root SRV (sharedshaderres has the buff and provides GpuVA)\n    //                        (UAV is not needed)\n    // \n    // 2. Default heap buffer\n    //        a. structured buffer\n    //            I. local -> root SRV -> Set*RootShaderResourceView(GpuVA)\n    //                    |\n    //                     -> root UAV -> Set*RootUnorderedAccessView(GpuVA)\n    // \n    //            II. global -> root SRV (sharedshaderres has the buff and provides GpuVA)\n    //                      |\n    //                       -> root UAV -> Set*RootUnorderedAccessView(GpuVA)\n    //\n    // 3. Texture\n    //        a. local -> create descriptor and store heap idx in a root CBV or a root constant\n    //        b. global -> descriptor table is already created. desc table headp idx goes in a root CBV or a root constant\n    //\n    // In conclusion, root signatures only need root CBV, root SRV, root UAV and root constants.\n    //\n    // ASSUMPTION: globals only change once per-frame, which means they should not change\n    // in-between draw/dispatch calls. Begin() marks them as modified, but once they're set,\n    // they can't be modified again.\n    //\n\n    struct RootSignature\n    {\n        RootSignature(int nCBV, int nSRV, int nUAV, int nGlobs, int nConsts);\n        ~RootSignature() = default;\n\n        RootSignature(const RootSignature&) = delete;\n        RootSignature& operator=(const RootSignature&) = delete;\n\n        void InitAsConstants(uint32_t rootIdx, uint32_t numDwords, uint32_t registerNum,\n            uint32_t registerSpace = 0, D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL);\n\n        void InitAsCBV(uint32_t rootIdx, uint32_t registerNum, uint32_t registerSpace,\n            D3D12_ROOT_DESCRIPTOR_FLAGS flags, const char* id = nullptr, bool isOptional = false,\n            D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL);\n\n        void InitAsBufferSRV(uint32_t rootIdx, uint32_t registerNum, uint32_t registerSpace,\n            D3D12_ROOT_DESCRIPTOR_FLAGS flags, const char* id = nullptr, bool isOptional = false,\n            D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL);\n\n        void InitAsBufferUAV(uint32_t rootIdx, uint32_t registerNum, uint32_t registerSpace,\n            D3D12_ROOT_DESCRIPTOR_FLAGS flags, const char* id = nullptr, bool isOptional = false,\n            D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL);\n\n        void Finalize(const char* name,\n            ComPtr<ID3D12RootSignature>& rootSig,\n            Util::Span<D3D12_STATIC_SAMPLER_DESC> samplers,\n            D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE);\n\n        void Begin();\n\n        void SetRootConstants(uint32_t offset, uint32_t num, const void* data);\n        void SetRootCBV(uint32_t rootIdx, D3D12_GPU_VIRTUAL_ADDRESS va);\n        void SetRootSRV(uint32_t rootIdx, D3D12_GPU_VIRTUAL_ADDRESS va);\n        void SetRootUAV(uint32_t rootIdx, D3D12_GPU_VIRTUAL_ADDRESS va);\n\n        void End(GraphicsCmdList& ctx);\n        void End(ComputeCmdList& ctx);\n\n    private:\n        static constexpr int MAX_NUM_PARAMS = 11;\n        static constexpr int MAX_NUM_ROOT_CONSTANTS = 20;\n\n        const uint32_t m_numParams;\n        const uint32_t m_numCBVs;\n        const uint32_t m_numSRVs;\n        const uint32_t m_numUAVs;\n        const uint32_t m_numGlobals;\n        const uint32_t m_numRootConstants;\n\n        D3D12_ROOT_PARAMETER1 m_params[MAX_NUM_PARAMS];\n\n        // Buffer IDs\n        uint64_t m_globals[MAX_NUM_PARAMS];\n\n        // Bitmaps indicating the type of each root parameter\n        uint32_t m_rootCBVBitMap = 0;\n        uint32_t m_rootSRVBitMap = 0;\n        uint32_t m_rootUAVBitMap = 0;\n\n        // Bitmap indicating which root params are global resources\n        uint32_t m_globalsBitMap = 0;\n        // Bitmap indicating which root params are optional\n        uint32_t m_optionalBitMap = 0;\n\n        // Index of the root constants param (there can be at most one)\n        int m_rootConstantsIdx = -1;\n\n        // Root descriptors\n        D3D12_GPU_VIRTUAL_ADDRESS m_rootDescriptors[MAX_NUM_PARAMS] = { 0 };\n\n        // Root constants data\n        uint32_t m_rootConstants[MAX_NUM_ROOT_CONSTANTS];\n\n        // Ref: https://www.intel.com/content/www/us/en/developer/articles/technical/introduction-to-resource-binding-in-microsoft-directx-12.html\n        // \"All the root parameters like descriptor tables, root descriptors, and root constants \n        // are baked in to a command list and the driver will be versioning them on behalf of the \n        // application. In other words, whenever any of the root parameters change between draw or \n        // dispatch calls, the hardware will update the version number of the root signature. Every \n        // draw / dispatch call gets a unique full set of root parameter states when any argument \n        // changes.\"\n        uint32_t m_modifiedBitMap = 0;\n        uint32_t m_modifiedGlobalsBitMap = 0;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Core/SharedShaderResources.cpp",
    "content": "#include \"SharedShaderResources.h\"\n#include <xxHash/xxhash.h>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\n\n//--------------------------------------------------------------------------------------\n// SharedShaderResources\n//--------------------------------------------------------------------------------------\n\nconst UploadHeapBuffer* SharedShaderResources::GetUploadHeapBuffer(uint64_t id)\n{\n    std::shared_lock<std::shared_mutex> lock(m_uploadHeapMtx);\n    auto buff = m_uploadHeapBuffs.find(id);\n    if(buff)\n        return *buff.value();\n\n    return nullptr;\n}\n\nconst UploadHeapBuffer* SharedShaderResources::GetUploadHeapBuffer(std::string_view id)\n{\n    uint64_t h = XXH3_64bits(id.data(), id.size());\n    return GetUploadHeapBuffer(h);\n}\n\nvoid SharedShaderResources::InsertOrAssignUploadHeapBuffer(std::string_view id, UploadHeapBuffer& buf)\n{\n    uint64_t h = XXH3_64bits(id.data(), id.size());\n    InsertOrAssignUploadHeapBuffer(h, buf);\n}\n\nvoid SharedShaderResources::InsertOrAssignUploadHeapBuffer(uint64_t id, const UploadHeapBuffer& buf)\n{\n    std::unique_lock<std::shared_mutex> lock(m_uploadHeapMtx);\n    m_uploadHeapBuffs[id] = &buf;\n}\n\nconst Buffer* SharedShaderResources::GetDefaultHeapBuffer(uint64_t id)\n{\n    std::shared_lock<std::shared_mutex> lock(m_defaultHeapMtx);\n    auto it = m_defaultHeapBuffs.find(id);\n    if (!it)\n        return nullptr;\n\n    return *it.value();\n}\n\nconst Buffer* SharedShaderResources::GetDefaultHeapBuffer(std::string_view id)\n{\n    uint64_t h = XXH3_64bits(id.data(), id.size());\n    return GetDefaultHeapBuffer(h);\n}\n\nvoid SharedShaderResources::InsertOrAssignDefaultHeapBuffer(uint64_t id, const Buffer& buf)\n{\n    std::unique_lock<std::shared_mutex> lock(m_defaultHeapMtx);\n    m_defaultHeapBuffs[id] = &buf;\n}\n\nvoid SharedShaderResources::InsertOrAssignDefaultHeapBuffer(std::string_view id, const Buffer& buf)\n{\n    uint64_t h = XXH3_64bits(id.data(), id.size());\n    InsertOrAssignDefaultHeapBuffer(h, buf);\n}\n\nvoid SharedShaderResources::RemoveDefaultHeapBuffer(uint64_t id, const Buffer& buf)\n{\n    std::unique_lock<std::shared_mutex> lock(m_defaultHeapMtx);\n    auto numDeleted = m_defaultHeapBuffs.erase(id);\n    Assert(numDeleted == 1, \"Buffer with ID %llu was not found.\", id);\n}\n\nvoid SharedShaderResources::RemoveDefaultHeapBuffer(std::string_view id, const Buffer& buf)\n{\n    uint64_t h = XXH3_64bits(id.data(), id.size());\n    auto numDeleted = m_defaultHeapBuffs.erase(h);\n    Assert(numDeleted == 1, \"Buffer with ID %llu was not found.\", id);\n}\n\nconst DescriptorTable* SharedShaderResources::GetDescriptorTable(uint64_t id)\n{\n    std::shared_lock<std::shared_mutex> lock(m_descTableMtx);\n    if (auto it = m_descTables.find(id); it)\n        return *it.value();\n\n    return nullptr;\n}\n\nconst DescriptorTable* SharedShaderResources::GetDescriptorTable(std::string_view id)\n{\n    uint64_t h = XXH3_64bits(id.data(), id.size());\n    return GetDescriptorTable(h);\n}\n\nvoid SharedShaderResources::InsertOrAssignDescriptorTable(uint64_t id, const DescriptorTable& t)\n{\n    std::unique_lock<std::shared_mutex> lock(m_descTableMtx);\n    m_descTables[id] = &t;\n}\n\nvoid SharedShaderResources::InsertOrAssignDescriptorTable(std::string_view id, const DescriptorTable& t)\n{\n    uint64_t h = XXH3_64bits(id.data(), id.size());\n    InsertOrAssignDescriptorTable(h, t);\n}"
  },
  {
    "path": "Source/ZetaCore/Core/SharedShaderResources.h",
    "content": "#pragma once\n\n#include \"../Utility/HashTable.h\"\n#include <shared_mutex>\n\nnamespace ZetaRay::Core::GpuMemory\n{\n    struct UploadHeapBuffer;\n    struct Buffer;\n}\n\nnamespace ZetaRay::Core\n{\n    struct DescriptorTable;\n\n    // Allows sharing buffers (in upload and default heaps), descriptor tables, and other resources \n    // that are shared between various shaders. Access is synchronized.\n    class SharedShaderResources\n    {\n    public:\n        SharedShaderResources() = default;\n        ~SharedShaderResources() = default;\n\n        SharedShaderResources(SharedShaderResources&&) = delete;\n        SharedShaderResources& operator==(SharedShaderResources&&) = delete;\n        \n        // Upload heap buffers\n        const GpuMemory::UploadHeapBuffer* GetUploadHeapBuffer(uint64_t id);\n        const GpuMemory::UploadHeapBuffer* GetUploadHeapBuffer(std::string_view id);\n        void InsertOrAssignUploadHeapBuffer(uint64_t, const GpuMemory::UploadHeapBuffer& buffer);\n        void InsertOrAssignUploadHeapBuffer(std::string_view id, GpuMemory::UploadHeapBuffer& buffer);\n\n        // Default heap buffers\n        const GpuMemory::Buffer* GetDefaultHeapBuffer(uint64_t id);\n        const GpuMemory::Buffer* GetDefaultHeapBuffer(std::string_view id);\n        void InsertOrAssignDefaultHeapBuffer(uint64_t id, const GpuMemory::Buffer& buffer);\n        void InsertOrAssignDefaultHeapBuffer(std::string_view id, const GpuMemory::Buffer& buffer);\n        void RemoveDefaultHeapBuffer(uint64_t id, const GpuMemory::Buffer& buffer);\n        void RemoveDefaultHeapBuffer(std::string_view id, const GpuMemory::Buffer& buffer);\n\n        // Descriptor tables\n        const DescriptorTable* GetDescriptorTable(uint64_t id);\n        const DescriptorTable* GetDescriptorTable(std::string_view id);\n        void InsertOrAssignDescriptorTable(uint64_t id, const DescriptorTable& table);\n        void InsertOrAssignDescriptorTable(std::string_view id, const DescriptorTable& table);\n\n    private:\n        Util::HashTable<const DescriptorTable*> m_descTables;\n        Util::HashTable<const GpuMemory::UploadHeapBuffer*> m_uploadHeapBuffs;\n        Util::HashTable<const GpuMemory::Buffer*> m_defaultHeapBuffs;\n\n        std::shared_mutex m_descTableMtx;\n        std::shared_mutex m_uploadHeapMtx;\n        std::shared_mutex m_defaultHeapMtx;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Core/Vertex.h",
    "content": "#pragma once\n\n#include \"../Math/OctahedralVector.h\"\n\nnamespace ZetaRay::Core\n{\n    // 28 bytes\n    struct Vertex\n    {\n        Math::float3 Position;\n        Math::float2 TexUV;\n        Math::oct32 Normal;\n        Math::oct32 Tangent;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Core/dds.h",
    "content": "//--------------------------------------------------------------------------------------\n// dds.h\n//\n// This header defines constants and structures that are useful when parsing \n// DDS files.  DDS files were originally designed to use several structures\n// and constants that are native to DirectDraw and are defined in ddraw.h,\n// such as DDSURFACEDESC2 and DDSCAPS2.  This file defines similar \n// (compatible) constants and structures so that one can use DDS files \n// without needing to include ddraw.h.\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#pragma warning(disable : 4324)\n\n#include \"../App/ZetaRay.h\"\n\n#ifndef MAKEFOURCC\n#define MAKEFOURCC(ch0, ch1, ch2, ch3) \\\n                (static_cast<uint32_t>(static_cast<uint8_t>(ch0)) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch1)) << 8) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch2)) << 16) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch3)) << 24))\n#endif /* defined(MAKEFOURCC) */\n\nnamespace ZetaRay::Core::Direct3DUtil\n{\n#pragma pack(push,1)\n    const uint32_t DDS_MAGIC = 0x20534444; // \"DDS \"\n\n    struct DDS_PIXELFORMAT\n    {\n        uint32_t    size;\n        uint32_t    flags;\n        uint32_t    fourCC;\n        uint32_t    RGBBitCount;\n        uint32_t    RBitMask;\n        uint32_t    GBitMask;\n        uint32_t    BBitMask;\n        uint32_t    ABitMask;\n    };\n\n#define DDS_FOURCC      0x00000004  // DDPF_FOURCC\n#define DDS_RGB         0x00000040  // DDPF_RGB\n#define DDS_RGBA        0x00000041  // DDPF_RGB | DDPF_ALPHAPIXELS\n#define DDS_LUMINANCE   0x00020000  // DDPF_LUMINANCE\n#define DDS_LUMINANCEA  0x00020001  // DDPF_LUMINANCE | DDPF_ALPHAPIXELS\n#define DDS_ALPHAPIXELS 0x00000001  // DDPF_ALPHAPIXELS\n#define DDS_ALPHA       0x00000002  // DDPF_ALPHA\n#define DDS_PAL8        0x00000020  // DDPF_PALETTEINDEXED8\n#define DDS_PAL8A       0x00000021  // DDPF_PALETTEINDEXED8 | DDPF_ALPHAPIXELS\n#define DDS_BUMPDUDV    0x00080000  // DDPF_BUMPDUDV\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT1 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','2'), 0, 0, 0, 0, 0 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT3 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_BC4_UNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','U'), 0, 0, 0, 0, 0 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_BC4_SNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_BC5_UNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','U'), 0, 0, 0, 0, 0 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_BC5_SNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','S'), 0, 0, 0, 0, 0 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_R8G8_B8G8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('R','G','B','G'), 0, 0, 0, 0, 0 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_G8R8_G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_YUY2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8R8G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_X8R8G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB,  0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8B8G8R8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_X8B8G8R8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB,  0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_G16R16 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB,  0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_R5G6B5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A1R5G5B5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A4R4G4B4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_R8G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_L8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0,  8, 0xff, 0x00, 0x00, 0x00 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_L16 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 16, 0xffff, 0x0000, 0x0000, 0x0000 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8L8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 16, 0x00ff, 0x0000, 0x0000, 0xff00 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8L8_ALT =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 8, 0x00ff, 0x0000, 0x0000, 0xff00 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_ALPHA, 0, 8, 0x00, 0x00, 0x00, 0xff };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_V8U8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0x0000, 0x0000 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_Q8W8V8U8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };\n\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_V16U16 =\n    { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 };\n\n    // D3DFMT_A2R10G10B10/D3DFMT_A2B10G10R10 should be written using DX10 extension to avoid D3DX 10:10:10:2 reversal issue\n\n    // This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat)\n    extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DX10 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 };\n\n#define DDS_HEADER_FLAGS_TEXTURE        0x00001007  // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT \n#define DDS_HEADER_FLAGS_MIPMAP         0x00020000  // DDSD_MIPMAPCOUNT\n#define DDS_HEADER_FLAGS_VOLUME         0x00800000  // DDSD_DEPTH\n#define DDS_HEADER_FLAGS_PITCH          0x00000008  // DDSD_PITCH\n#define DDS_HEADER_FLAGS_LINEARSIZE     0x00080000  // DDSD_LINEARSIZE\n\n#define DDS_HEIGHT 0x00000002 // DDSD_HEIGHT\n#define DDS_WIDTH  0x00000004 // DDSD_WIDTH\n\n#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE\n#define DDS_SURFACE_FLAGS_MIPMAP  0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP\n#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX\n\n#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX\n#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX\n#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY\n#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY\n#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ\n#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ\n\n#define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\\\n                               DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\\\n                               DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ )\n\n#define DDS_CUBEMAP 0x00000200 // DDSCAPS2_CUBEMAP\n\n#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME\n\n    // Subset here matches D3D10_RESOURCE_DIMENSION and D3D11_RESOURCE_DIMENSION\n    enum DDS_RESOURCE_DIMENSION\n    {\n        DDS_DIMENSION_TEXTURE1D = 2,\n        DDS_DIMENSION_TEXTURE2D = 3,\n        DDS_DIMENSION_TEXTURE3D = 4,\n    };\n\n    // Subset here matches D3D10_RESOURCE_MISC_FLAG and D3D11_RESOURCE_MISC_FLAG\n    enum DDS_RESOURCE_MISC_FLAG\n    {\n        DDS_RESOURCE_MISC_TEXTURECUBE = 0x4L,\n    };\n\n    enum DDS_MISC_FLAGS2\n    {\n        DDS_MISC_FLAGS2_ALPHA_MODE_MASK = 0x7L,\n    };\n\n    struct DDS_HEADER\n    {\n        uint32_t        size;\n        uint32_t        flags;\n        uint32_t        height;\n        uint32_t        width;\n        uint32_t        pitchOrLinearSize;\n        uint32_t        depth; // only if DDS_HEADER_FLAGS_VOLUME is set in flags\n        uint32_t        mipMapCount;\n        uint32_t        reserved1[11];\n        DDS_PIXELFORMAT ddspf;\n        uint32_t        caps;\n        uint32_t        caps2;\n        uint32_t        caps3;\n        uint32_t        caps4;\n        uint32_t        reserved2;\n    };\n\n    struct DDS_HEADER_DXT10\n    {\n        DXGI_FORMAT     dxgiFormat;\n        uint32_t        resourceDimension;\n        uint32_t        miscFlag; // see D3D11_RESOURCE_MISC_FLAG\n        uint32_t        arraySize;\n        uint32_t        miscFlags2; // see DDS_MISC_FLAGS2\n    };\n\n#pragma pack(pop)\n\n    static_assert(sizeof(DDS_HEADER) == 124, \"DDS Header size mismatch\");\n    static_assert(sizeof(DDS_HEADER_DXT10) == 20, \"DDS DX10 Extended Header size mismatch\");\n} // namespace\n"
  },
  {
    "path": "Source/ZetaCore/Math/BVH.cpp",
    "content": "#include \"BVH.h\"\n#include \"../Math/CollisionFuncs.h\"\n#include \"../Utility/Error.h\"\n#include \"../App/Log.h\"\n#include \"../Scene/SceneCommon.h\"\n#include <algorithm>\n\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Math;\n\nnamespace\n{\n    struct alignas(16) Bin\n    {\n        ZetaInline void __vectorcall Extend(v_AABB box)\n        {\n            Box = NumEntries > 0 ? unionAABB(Box, box) : box;\n            NumEntries++;\n        }\n\n        ZetaInline void __vectorcall Extend(Bin bin)\n        {\n            Box = NumEntries > 0 ? unionAABB(Box, bin.Box) : bin.Box;\n            NumEntries += bin.NumEntries;\n        }\n\n        v_AABB Box = v_AABB(float3(0.0f), float3(-FLT_MAX));\n        uint32_t NumEntries = 0;\n    };\n}\n\n//--------------------------------------------------------------------------------------\n// Node\n//--------------------------------------------------------------------------------------\n\nvoid BVH::Node::InitAsLeaf(int base, int count, int parent)\n{\n    Assert(count, \"Invalid count\");\n    Base = base;\n    Count = count;\n//    AABB.Extents = float3(0.0f, 0.0f, 0.0f);\n    RightChild = -1;\n    Parent = parent;\n}\n\nvoid BVH::Node::InitAsInternal(Span<BVH::BVHInput> instances, int base, int count,\n    int right, int parent)\n{\n    Assert(count, \"Invalid count\");\n    Assert(base + count <= instances.size(), \"Invalid base/count.\");\n\n    v_AABB vBox(instances[base].BoundingBox);\n\n    for (int i = base + 1; i < base + count; i++)\n        vBox = unionAABB(vBox, v_AABB(instances[i].BoundingBox));\n\n    BoundingBox = store(vBox);\n    RightChild = right;\n    Parent = parent;\n}\n\n//--------------------------------------------------------------------------------------\n// BVH\n//--------------------------------------------------------------------------------------\n\nBVH::BVH()\n    : m_arena(4 * 1096),\n    m_instances(m_arena),\n    m_nodes(m_arena)\n{}\n\nvoid BVH::Build(Span<BVHInput> instances)\n{\n    if (instances.size() == 0)\n        return;\n\n    //m_instances.swap(instances);\n    m_instances.append_range(instances.begin(), instances.end(), true);\n    Check(m_instances.size() < UINT32_MAX, \"#Instances can't exceed UINT32_MAX.\");\n    const uint32_t numInstances = (uint32_t)m_instances.size();\n\n    // Special case when there's less than MAX_NUM_MODELS_PER_LEAF instances\n    if (m_instances.size() <= MAX_NUM_INSTANCES_PER_LEAF)\n    {\n        m_nodes.resize(1);\n\n        v_AABB vBox(m_instances[0].BoundingBox);\n\n        for (int i = 1; i < m_instances.size(); i++)\n            vBox = unionAABB(vBox, v_AABB(m_instances[i].BoundingBox));\n\n        m_nodes[0].BoundingBox = store(vBox);\n        m_nodes[0].Base = 0;\n        m_nodes[0].Count = (int)m_instances.size();\n        m_nodes[0].RightChild = -1;\n\n        return;\n    }\n\n    // TODO check this computation\n    const uint32_t MAX_NUM_NODES = Math::CeilUnsignedIntDiv(4 * numInstances, MAX_NUM_INSTANCES_PER_LEAF) + 1;\n    m_nodes.resize(MAX_NUM_NODES);\n\n    BuildSubtree(0, numInstances, -1);\n}\n\nint BVH::BuildSubtree(int base, int count, int parent)\n{\n    Assert(count > 0, \"Number of nodes to build a subtree for must be greater than 0.\");\n    const uint32_t currNodeIdx = m_numNodes++;\n    Assert(!m_nodes[currNodeIdx].IsInitialized(), \"invalid index\");\n\n    // Create a leaf node and return\n    if (count <= MAX_NUM_INSTANCES_PER_LEAF)\n    {\n        m_nodes[currNodeIdx].InitAsLeaf(base, count, parent);\n        return currNodeIdx;\n    }\n\n    // Compute union AABB of all centroids\n    __m128 vMinPoint = _mm_set_ps1(FLT_MAX);\n    __m128 vMaxPoint = _mm_set_ps1(-FLT_MAX);\n    // Union AABB of all nodes in this subtree\n    v_AABB vNodeBox(m_instances[base].BoundingBox);\n\n    for (int i = base; i < base + count; i++)\n    {\n        v_AABB vInstanceBox(m_instances[i].BoundingBox);\n\n        vMinPoint = _mm_min_ps(vMinPoint, vInstanceBox.vCenter);\n        vMaxPoint = _mm_max_ps(vMaxPoint, vInstanceBox.vCenter);\n\n        vNodeBox = unionAABB(vNodeBox, v_AABB(m_instances[i].BoundingBox));\n    }\n\n    v_AABB vCentroidAABB;\n    vCentroidAABB.Reset(vMinPoint, vMaxPoint);\n    AABB centroidAABB;\n    centroidAABB = store(vCentroidAABB);\n\n    // All centroids are (almost) the same point, no point in splitting further\n    if (centroidAABB.Extents.x + centroidAABB.Extents.y + centroidAABB.Extents.z <= 1e-5f)\n    {\n        m_nodes[currNodeIdx].InitAsLeaf(base, count, parent);\n        return currNodeIdx;\n    }\n\n    // Axis along which partitioning should be performed\n    const float* extArr = reinterpret_cast<float*>(&centroidAABB.Extents);\n    int splitAxis = 0;\n    float maxExtent = extArr[0];\n\n    // Find the longest axis\n    for (int i = 1; i < 3; i++)\n    {\n        if (extArr[i] > maxExtent)\n        {\n            maxExtent = extArr[i];\n            splitAxis = i;\n        }\n    }\n\n    uint32_t splitCount;\n\n    // Split using SAH\n    if (count >= MIN_NUM_INSTANCES_SPLIT_SAH)\n    {\n        Bin bins[NUM_SAH_BINS];\n        const float leftMostPlane = reinterpret_cast<float*>(&centroidAABB.Center)[splitAxis] - maxExtent;\n        const float rcpStepSize = NUM_SAH_BINS / (2.0f * maxExtent);\n\n        // Assign each instance to one bin\n        for (int i = base; i < base + count; i++)\n        {\n            const float* center = reinterpret_cast<float*>(&m_instances[i].BoundingBox.Center);\n            float numBinWidthsFromLeftMostPlane = (center[splitAxis] - leftMostPlane) * rcpStepSize;\n            int bin = Math::Min((int)numBinWidthsFromLeftMostPlane, (int)NUM_SAH_BINS - 1);\n\n            v_AABB box(m_instances[i].BoundingBox);\n            bins[bin].Extend(box);\n        }\n\n        Assert(bins[0].NumEntries > 0 && bins[NUM_SAH_BINS - 1].NumEntries > 0, \"first & last bin must contain at least 1 instance.\");\n\n        // N bins correspond to N - 1 split planes, e.g. for N = 4\n        //        bin 0 | bin 1 | bin 2 | bin 3 \n        float leftSurfaceArea[NUM_SAH_BINS - 1];\n        float rightSurfaceArea[NUM_SAH_BINS - 1];\n        uint32_t leftCount[NUM_SAH_BINS - 1];\n        uint32_t rightCount[NUM_SAH_BINS - 1];\n\n        {\n            // For each split plane corresponding to each bin, compute surface area of nodes\n            // to its left and right\n            v_AABB currLeftBox = bins[0].Box;\n            v_AABB currRightBox = bins[NUM_SAH_BINS - 1].Box;\n            uint32_t currLeftSum = 0;\n            uint32_t currRightSum = 0;\n\n            for (int plane = 0; plane < NUM_SAH_BINS - 1; plane++)\n            {\n                currLeftSum += bins[plane].NumEntries;\n                leftCount[plane] = currLeftSum;\n\n                currLeftBox = unionAABB(bins[plane].Box, currLeftBox);\n                leftSurfaceArea[plane] = AABBSurfaceArea(currLeftBox);\n                currRightSum += bins[NUM_SAH_BINS - 1 - plane].NumEntries;\n                rightCount[NUM_SAH_BINS - 2 - plane] = currRightSum;\n\n                currRightBox = unionAABB(bins[NUM_SAH_BINS - 1 - plane].Box, currRightBox);\n                rightSurfaceArea[NUM_SAH_BINS - 2 - plane] = AABBSurfaceArea(currRightBox);\n            }\n        }\n\n        int lowestCostPlane = -1;\n        float lowestCost = FLT_MAX;\n        const float parentSurfaceArea = AABBSurfaceArea(vNodeBox);\n\n        // Cost of split along each split plane\n        for (int i = 0; i < NUM_SAH_BINS - 1; i++)\n        {\n            const float splitCost = leftCount[i] * leftSurfaceArea[i] / parentSurfaceArea +\n                rightCount[i] * rightSurfaceArea[i] / parentSurfaceArea;\n\n            if (splitCost < lowestCost)\n            {\n                lowestCost = splitCost;\n                lowestCostPlane = i;\n            }\n        }\n\n        const float noSplitCost = (float)count;\n        if (noSplitCost <= lowestCost)\n        {\n            m_nodes[currNodeIdx].InitAsLeaf(base, count, parent);\n            return currNodeIdx;\n        }\n\n        Assert(lowestCostPlane != -1, \"bug\");\n        const float splitPlane = leftMostPlane + (lowestCostPlane + 1) / rcpStepSize;    // == * StepSize\n\n        auto it = std::partition(m_instances.begin() + base, m_instances.begin() + base + count,\n            [splitPlane, splitAxis](BVHInput& box)\n            {\n                float c = reinterpret_cast<float*>(&box.BoundingBox.Center)[splitAxis];\n                return c <= splitPlane;\n            });\n\n        splitCount = (uint32_t)(it - m_instances.begin() - base);\n        if (splitCount != leftCount[lowestCostPlane])\n            LOG_UI_WARNING(\"BVH::Build(): floating-point imprecision detected.\");\n    }\n    else\n    {\n        // Split into two subtrees such that each subtree has an equal number of nodes (i.e. find the median)\n        const uint32_t countDiv2 = (count >> 1);\n        auto begIt = m_instances.begin() + base;\n        auto midIt = m_instances.begin() + base + countDiv2;\n        auto endIt = m_instances.begin() + base + count;\n        std::nth_element(begIt, midIt, endIt,\n            [splitAxis](BVHInput& b1, BVHInput& b2)\n            {\n                float* box1 = reinterpret_cast<float*>(&b1.BoundingBox);\n                float* box2 = reinterpret_cast<float*>(&b2.BoundingBox);\n                // compare AABB centers along the split axis\n                return box1[splitAxis] < box2[splitAxis];\n            });\n\n        splitCount = countDiv2;\n    }\n\n    Assert(splitCount > 0, \"bug\");\n    uint32_t left = BuildSubtree(base, splitCount, currNodeIdx);\n    uint32_t right = BuildSubtree(base + splitCount, count - splitCount, currNodeIdx);\n    Assert(left == currNodeIdx + 1, \"Index of left child should be equal to current parent's index plus one\");\n\n    m_nodes[currNodeIdx].InitAsInternal(m_instances, base, count, right, parent);\n\n    return currNodeIdx;\n}\n\nint BVH::Find(uint64_t instanceID, const Math::AABB& queryBox, int& nodeIdx)\n{\n    nodeIdx = -1;\n\n    // Using a manual stack, we can return early when a match is found, whereas\n    // with a recursive call, travelling back through the call-chain is required\n    constexpr int STACK_SIZE = 64;\n    int stack[STACK_SIZE];\n    int currStackIdx = 0;\n    stack[currStackIdx] = 0;    // insert root\n\n    v_AABB vBox(queryBox);\n\n    // Can return early if root doesn't intersect or contain the given AABB\n    if(Math::intersectAABBvsAABB(vBox, v_AABB(m_nodes[0].BoundingBox)) == COLLISION_TYPE::DISJOINT)\n        return -1;\n\n    int currNodeIdx = -1;\n\n    while (currStackIdx >= 0)\n    {\n        Assert(currStackIdx < 64, \"Stack size exceeded 64.\");\n\n        currNodeIdx = stack[currStackIdx--];\n        const Node& node = m_nodes[currNodeIdx];\n\n        if (node.IsLeaf())\n        {\n            for (int i = node.Base; i < node.Base + node.Count; i++)\n            {\n                if (m_instances[i].InstanceID == instanceID)\n                {\n                    nodeIdx = currNodeIdx;\n                    return i;\n                }\n            }\n\n            continue;\n        }\n\n        v_AABB vNodeBox(node.BoundingBox);\n\n        if(Math::intersectAABBvsAABB(vNodeBox, vBox) != COLLISION_TYPE::DISJOINT)\n        {\n            // Decide which tree to descend on first\n            v_AABB vLeft(m_nodes[currNodeIdx + 1].BoundingBox);\n            v_AABB vRight(m_nodes[node.RightChild].BoundingBox);\n\n            v_AABB vOverlapLeft = Math::overlapAABB(vBox, vLeft);\n            v_AABB vOverlapRight = Math::overlapAABB(vBox, vRight);\n\n            Math::AABB Left = Math::store(vOverlapLeft);\n            Math::AABB Right = Math::store(vOverlapRight);\n\n            float leftOverlapVolume = m_nodes[currNodeIdx + 1].IsLeaf() ? FLT_MAX : \n                Left.Extents.x * Left.Extents.y * Left.Extents.z;\n            float rightOverlapVolume = m_nodes[node.RightChild].IsLeaf() ? FLT_MAX : \n                Right.Extents.x * Right.Extents.y * Right.Extents.z;\n\n            // Larger overlap with the right subtree, descend through that first\n            if (leftOverlapVolume <= rightOverlapVolume)\n            {\n                stack[++currStackIdx] = currNodeIdx + 1;\n                stack[++currStackIdx] = node.RightChild;\n            }\n            else\n            {\n                stack[++currStackIdx] = node.RightChild;\n                stack[++currStackIdx] = currNodeIdx + 1;\n            }\n        }\n    }\n\n    return currNodeIdx;\n}\n\nvoid BVH::Update(Span<BVHUpdateInput> instances)\n{\n    for (auto& [oldBox, newBox, id] : instances)\n    {\n        // Find the leaf node that contains it\n        int nodeIdx;\n        int instanceIdx = Find(id, oldBox, nodeIdx);\n        Assert(instanceIdx != -1, \"Instance with ID %u was not found.\", id);\n\n        // Update the bounding box\n        Node& node = m_nodes[nodeIdx];\n        m_instances[instanceIdx].BoundingBox = newBox;\n\n        const v_AABB vOldBox(oldBox);\n        const v_AABB vNewBox(newBox);\n\n        Math::COLLISION_TYPE res = Math::intersectAABBvsAABB(vOldBox, vNewBox);\n\n        // If the old AABB contains the new one, keep using the old one\n        if (res != COLLISION_TYPE::CONTAINS)\n        {\n            int currParent = node.Parent;\n\n            // Following the parent indices, keep going up the tree and merge the AABBs. Break once a parent node's\n            // AABB contains the new one\n            while (currParent != -1)\n            {\n                Node& parentNode = m_nodes[currParent];\n\n                v_AABB vParentBox(parentNode.BoundingBox);\n                if (Math::intersectAABBvsAABB(vParentBox, vNewBox) == COLLISION_TYPE::CONTAINS)\n                    break;\n\n                vParentBox = Math::unionAABB(vParentBox, vNewBox);\n                parentNode.BoundingBox = Math::store(vParentBox);\n\n                currParent = m_nodes[currParent].Parent;\n            }\n        }\n\n        // Note: when the new AABB and the old AABB are disjoint, it'd be better to\n        // remove and then reinsert the update Node. That requires modifying the range of\n        // all the leaves, which is expensive\n    }\n}\n\nvoid BVH::Remove(uint64_t ID, const Math::AABB& box)\n{\n    // Find the leaf node that contains it\n    int nodeIdx;\n    const int instanceIdx = Find(ID, box, nodeIdx);\n    Assert(instanceIdx != -1, \"Instance with ID %u was not found.\", ID);\n\n    m_instances[instanceIdx].InstanceID = Scene::INVALID_INSTANCE;\n    m_instances[instanceIdx].BoundingBox.Extents = float3(-1.0f, -1.0f, -1.0f);\n    m_instances[instanceIdx].BoundingBox.Center = float3(0.0f, 0.0f, 0.0f);\n\n    // Swap with the last Instance in this leaf\n    const uint32_t swapIdx = m_nodes[nodeIdx].Base + m_nodes[nodeIdx].Count - 1;\n    std::swap(m_instances[instanceIdx], m_instances[swapIdx]);\n    m_nodes[nodeIdx].Count--;\n}\n\nvoid BVH::DoFrustumCulling(const Math::ViewFrustum& viewFrustum, \n    const Math::float4x4a& viewToWorld, \n    Vector<uint64_t, App::FrameAllocator>& visibleInstanceIDs)\n{\n    // Transform view frustum from view space into world space\n    v_float4x4 vM = load4x4(const_cast<float4x4a&>(viewToWorld));\n    v_ViewFrustum vFrustum(const_cast<ViewFrustum&>(viewFrustum));\n    vFrustum = Math::transform(vM, vFrustum);\n\n    v_AABB vBox(m_nodes[0].BoundingBox);\n\n    // root doesn't intersect camera\n    if (Math::instersectFrustumVsAABB(vFrustum, vBox) == COLLISION_TYPE::DISJOINT)\n        return;\n\n    // Manual stack\n    constexpr int STACK_SIZE = 64;\n    int stack[STACK_SIZE];\n    int currStackIdx = 0;\n\n    // Insert root\n    stack[currStackIdx] = 0;\n    int currNode = -1;\n\n    while (currStackIdx >= 0)\n    {\n        Assert(currStackIdx < 64, \"Stack size exceeded maximum allowed.\");\n\n        currNode = stack[currStackIdx--];\n        const Node& node = m_nodes[currNode];\n\n        if (node.IsLeaf())\n        {\n            for (int i = node.Base; i < node.Base + node.Count; i++)\n            {\n                vBox.Reset(m_instances[i].BoundingBox);\n\n                if (Math::instersectFrustumVsAABB(vFrustum, vBox) != COLLISION_TYPE::DISJOINT)\n                    visibleInstanceIDs.push_back(m_instances[i].InstanceID);\n            }\n        }\n        else\n        {\n            vBox.Reset(node.BoundingBox);\n\n            if (Math::instersectFrustumVsAABB(vFrustum, vBox) != COLLISION_TYPE::DISJOINT)\n            {\n                stack[++currStackIdx] = node.RightChild;\n                stack[++currStackIdx] = currNode + 1;\n            }\n        }\n    }\n}\n\nvoid BVH::DoFrustumCulling(const Math::ViewFrustum& viewFrustum,\n    const Math::float4x4a& viewToWorld,\n    Vector<BVHInput, App::FrameAllocator>& visibleInstanceIDs)\n{\n    // Transform view frustum from view space into world space\n    v_float4x4 vM = load4x4(const_cast<float4x4a&>(viewToWorld));\n    v_ViewFrustum vFrustum(const_cast<ViewFrustum&>(viewFrustum));\n    vFrustum = Math::transform(vM, vFrustum);\n\n    v_AABB vBox(m_nodes[0].BoundingBox);\n\n    // Root doesn't intersect camera\n    if (Math::instersectFrustumVsAABB(vFrustum, vBox) == COLLISION_TYPE::DISJOINT)\n        return;\n\n    // Manual stack\n    constexpr int STACK_SIZE = 64;\n    int stack[STACK_SIZE];\n    int currStackIdx = 0;\n\n    // Insert root\n    stack[currStackIdx] = 0;\n    int currNode = -1;\n\n    while (currStackIdx >= 0)\n    {\n        Assert(currStackIdx < 64, \"Stack size exceeded maximum allowed.\");\n\n        currNode = stack[currStackIdx--];\n        const Node& node = m_nodes[currNode];\n\n        if (node.IsLeaf())\n        {\n            for (int i = node.Base; i < node.Base + node.Count; i++)\n            {\n                vBox.Reset(m_instances[i].BoundingBox);\n\n                if (Math::instersectFrustumVsAABB(vFrustum, vBox) != COLLISION_TYPE::DISJOINT)\n                {\n                    visibleInstanceIDs.emplace_back(BVH::BVHInput{\n                        .BoundingBox = m_instances[i].BoundingBox,\n                        .InstanceID = m_instances[i].InstanceID });\n                }\n            }\n        }\n        else\n        {\n            vBox.Reset(node.BoundingBox);\n\n            if (Math::instersectFrustumVsAABB(vFrustum, vBox) != COLLISION_TYPE::DISJOINT)\n            {\n                stack[++currStackIdx] = node.RightChild;\n                stack[++currStackIdx] = currNode + 1;\n            }\n        }\n    }\n}\n\nuint64_t BVH::CastRay(v_Ray& vRay)\n{\n    v_AABB vBox(m_nodes[0].BoundingBox);\n    float t;\n\n    const __m128 vIsParallel = _mm_cmpge_ps(_mm_set1_ps(FLT_EPSILON), abs(vRay.vDir));\n     const __m128 vDirRcp = _mm_div_ps(_mm_set1_ps(1.0f), vRay.vDir);\n    const __m128 vDirIsPos = _mm_cmpge_ps(vRay.vDir, _mm_setzero_ps());\n\n    // Can return early if ray doesn't intersect root AABB\n    if (!Math::intersectRayVsAABB(vRay, vDirRcp, vDirIsPos, vIsParallel, vBox, t))\n        return Scene::INVALID_INSTANCE;\n\n    // Manual stack\n    constexpr int STACK_SIZE = 64;\n    int stack[STACK_SIZE];\n    int currStackIdx = 0;\n\n    // Insert root\n    stack[currStackIdx] = 0;\n    int currNode = -1;\n    float minT = FLT_MAX;\n    uint64_t closestID = Scene::INVALID_INSTANCE;\n\n    while (currStackIdx >= 0)\n    {\n        Assert(currStackIdx < STACK_SIZE, \"Stack size exceeded 64.\");\n\n        currNode = stack[currStackIdx--];\n        const Node& node = m_nodes[currNode];\n\n        if (node.IsLeaf())\n        {\n            for (int i = node.Base; i < node.Base + node.Count; i++)\n            {\n                vBox.Reset(m_instances[i].BoundingBox);\n\n                if (Math::intersectRayVsAABB(vRay, vDirRcp, vDirIsPos, vIsParallel, vBox, t))\n                {\n                    const bool tLtTmin = t < minT;\n                    minT = tLtTmin ? t : minT;\n                    closestID = tLtTmin ? m_instances[i].InstanceID : closestID;\n                }\n            }\n        }\n        else\n        {\n            const Node& leftChild = m_nodes[currNode + 1];\n            const Node& rightChild = m_nodes[node.RightChild];\n            const v_AABB vLeftBox(leftChild.BoundingBox);\n            const v_AABB vRightBox(rightChild.BoundingBox);\n            float leftT;\n            float rightT;\n\n            const bool hitLeftChild = Math::intersectRayVsAABB(vRay, vDirRcp, vDirIsPos, vIsParallel, vLeftBox, leftT);\n            const bool hitRightChild = Math::intersectRayVsAABB(vRay, vDirRcp, vDirIsPos, vIsParallel, vRightBox, rightT);\n\n            int sortedByT[2] = { currNode + 1, node.RightChild };\n            const int numChildren = hitLeftChild + hitRightChild;\n\n            // Make sure subtree closer to camera is searched first\n            if (numChildren == 2 && leftT < rightT)\n                std::swap(sortedByT[0], sortedByT[1]);\n\n            for (int c = 0; c < numChildren; c++)\n            {\n                // No need to search this subtree as earlier hits are necessarily closer to camera\n                if(sortedByT[c] < minT)\n                    stack[++currStackIdx] = sortedByT[c];\n            }\n        }\n    }\n\n    return closestID;\n}\n\nuint64_t BVH::CastRay(Math::Ray& r)\n{\n    v_Ray vRay(r);\n    return CastRay(vRay);\n}\n"
  },
  {
    "path": "Source/ZetaCore/Math/BVH.h",
    "content": "// References:\n// 1. M. Pharr, W. Jakob, and G. Humphreys, Physically Based Rendering: From theory to implementation, Morgan Kaufmann, 2016.\n// 2. C. Ericson, Real-time Collision Detection, Morgan Kaufmann, 2005.\n\n#pragma once\n\n#include \"../Utility/Span.h\"\n#include \"../Math/CollisionTypes.h\"\n#include \"../Support/MemoryArena.h\"\n#include \"../App/App.h\"\n\nnamespace ZetaRay::Math\n{\n    struct alignas(16) float4x4a;\n\n    class BVH\n    {\n    public:\n        struct alignas(16) BVHInput\n        {\n            Math::AABB BoundingBox;\n            uint64_t InstanceID;\n        };\n\n        struct alignas(16) BVHUpdateInput\n        {\n            Math::AABB OldBox;\n            Math::AABB NewBox;\n            uint64_t InstanceID;\n        };\n\n        BVH();\n        ~BVH() = default;\n\n        BVH(BVH&&) = delete;\n        BVH& operator=(BVH&&) = delete;\n\n        bool IsBuilt() { return m_nodes.size() != 0; }\n        void Build(Util::Span<BVHInput> instances);\n        void Update(Util::Span<BVHUpdateInput> instances);\n        void Remove(uint64_t ID, const Math::AABB& AABB);\n\n        // Returns ID of instances that at least partially overlap the view frustum. Assumes \n        // the view frustum is in view space.\n        void DoFrustumCulling(const Math::ViewFrustum& viewFrustum, \n            const Math::float4x4a& viewToWorld,\n            Util::Vector<uint64_t, App::FrameAllocator>& visibleInstanceIDs);\n\n        // Returns IDs & AABBs of instances that at least partially overlap the view frustum. Assumes \n        // the view frustum is in view space.\n        void DoFrustumCulling(const Math::ViewFrustum& viewFrustum,\n            const Math::float4x4a& viewToWorld,\n            Util::Vector<BVHInput, App::FrameAllocator>& visibleInstanceIDs);\n\n        // Casts a ray into the BVH and returns the closest intersection. Ray is assumed to \n        // be in world space.\n        uint64_t CastRay(Math::Ray& r);\n        uint64_t CastRay(Math::v_Ray& r);\n\n        // Returns AABB that contains the scene\n        Math::AABB GetWorldAABB() \n        {\n            Assert(m_nodes.size() > 0, \"BVH hasn't been built yet.\");\n            return m_nodes[0].BoundingBox; \n        }\n\n    private:\n        // Maximum number of instances that can be included in a leaf node\n        static constexpr uint32_t MAX_NUM_INSTANCES_PER_LEAF = 8;\n        static constexpr uint32_t MIN_NUM_INSTANCES_SPLIT_SAH = 10;\n        static constexpr uint32_t NUM_SAH_BINS = 6;\n\n        struct alignas(64) Node\n        {\n            bool IsInitialized() { return Parent != -1; }\n            void InitAsLeaf(int base, int count, int parent);\n            void InitAsInternal(Util::Span<BVH::BVHInput> instances, int base, int count,\n                int right, int parent);\n            bool IsLeaf() const { return RightChild == -1; }\n\n            // Union AABB of all the child nodes for internal nodes\n            // also used to distinguish between leaf & internal nodes\n            Math::AABB BoundingBox;\n\n            /*\n            union\n            {\n                struct\n                {\n                    int Base;\n                    int Count;\n                } Leaf;\n\n                int RightChild;\n            };\n            */\n\n            // For leaves\n            int Base;\n            int Count;\n\n            // For internal nodes\n            int RightChild;\n\n            int Parent = -1;\n        };\n\n        // Recursively builds a BVH (subtree) for the given range\n        int BuildSubtree(int base, int count, int parent);\n\n        // Finds the leaf node that contains the given instance. Returns -1 otherwise.\n        int Find(uint64_t instanceID, const Math::AABB& AABB, int& modelIdx);\n\n        Support::MemoryArena m_arena;\n\n        // Tree hierarchy is stored as an array\n        Util::SmallVector<Node, Support::ArenaAllocator> m_nodes;\n\n        // Array of inputs to build a BVH for. During BVH build, elements are moved around.\n        Util::SmallVector<BVHInput, Support::ArenaAllocator> m_instances;\n\n        uint32_t m_numNodes = 0;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Math/CMakeLists.txt",
    "content": "set(MATH_DIR \"${ZETA_CORE_DIR}/Math\")\nset(MATH_SRC\n    \"${MATH_DIR}/BVH.cpp\"\n    \"${MATH_DIR}/BVH.h\"\n    \"${MATH_DIR}/CollisionFuncs.h\"\n    \"${MATH_DIR}/CollisionTypes.h\"\n    \"${MATH_DIR}/Common.cpp\"\n    \"${MATH_DIR}/Common.h\"\n    \"${MATH_DIR}/Color.cpp\"\n    \"${MATH_DIR}/Color.h\"\n    \"${MATH_DIR}/Matrix.h\"\n    \"${MATH_DIR}/MatrixFuncs.h\"\n    \"${MATH_DIR}/OctahedralVector.h\"\n    \"${MATH_DIR}/Quaternion.h\"\n    \"${MATH_DIR}/Sampling.cpp\"\n    \"${MATH_DIR}/Sampling.h\"\n    \"${MATH_DIR}/Surface.cpp\"\n    \"${MATH_DIR}/Surface.h\"\n    \"${MATH_DIR}/Vector.h\"\n    \"${MATH_DIR}/VectorFuncs.h\")\nset(MATH_SRC ${MATH_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaCore/Math/CollisionFuncs.h",
    "content": "#pragma once\n\n#include \"CollisionTypes.h\"\n#include \"VectorFuncs.h\"\n#include \"MatrixFuncs.h\"\n\nnamespace ZetaRay::Math\n{\n    //--------------------------------------------------------------------------------------\n    // Functions\n    //--------------------------------------------------------------------------------------\n\n    ZetaInline __m128 __vectorcall distFromPlane(const __m128 point, const __m128 plane)\n    {\n        // plane: n.(p - p0) = 0\n        // dist(p, p0) = proj_n(p - p0) = n.(p - p0)\n        return abs(_mm_dp_ps(point, plane, 0xf));\n    }\n\n    // Computes AABB that encloses the given mesh. Assumes vtxStride - (posOffset + sizeof(float3)) >= sizeof(float)\n    ZetaInline v_AABB __vectorcall compueMeshAABB(const void* data, uint32_t posOffset, uint32_t vtxStride, uint32_t numVertices)\n    {\n        uintptr_t dataPtr = (uintptr_t)data + posOffset;\n        float3* currPos = reinterpret_cast<float3*>(dataPtr);\n\n        __m128 vPos = _mm_loadu_ps(reinterpret_cast<float*>(currPos));\n        __m128 vMin = vPos;\n        __m128 vMax = vPos;\n\n        for (int i = 1; i < (int)numVertices; i++)\n        {\n            currPos = reinterpret_cast<float3*>(dataPtr);\n\n            vPos = _mm_loadu_ps(reinterpret_cast<float*>(currPos));\n            vMin = _mm_min_ps(vPos, vMin);\n            vMax = _mm_max_ps(vPos, vMax);\n\n            dataPtr += vtxStride;\n        }\n\n        const __m128 vOneDivTwo = _mm_set1_ps(0.5f);\n        v_AABB vBox;\n        vBox.vCenter = _mm_mul_ps(_mm_add_ps(vMax, vMin), vOneDivTwo);\n        vBox.vExtents = _mm_mul_ps(_mm_sub_ps(vMax, vMin), vOneDivTwo);\n\n        return vBox;\n    }\n\n    // Returns the union of two AABBs\n    ZetaInline v_AABB __vectorcall unionAABB(const v_AABB vBox1, const v_AABB vBox2)\n    {\n        __m128 vMin1 = _mm_sub_ps(vBox1.vCenter, vBox1.vExtents);\n        __m128 vMax1 = _mm_add_ps(vBox1.vCenter, vBox1.vExtents);\n\n        __m128 vMin2 = _mm_sub_ps(vBox2.vCenter, vBox2.vExtents);\n        __m128 vMax2 = _mm_add_ps(vBox2.vCenter, vBox2.vExtents);\n\n        __m128 vUnionMin = _mm_min_ps(vMin1, vMin2);\n        __m128 vUnionMax = _mm_max_ps(vMax1, vMax2);\n\n        const __m128 vOneDiv2 = _mm_set1_ps(0.5f);\n        v_AABB vRet;\n        vRet.vCenter = _mm_mul_ps(_mm_add_ps(vUnionMin, vUnionMax), vOneDiv2);\n        vRet.vExtents = _mm_mul_ps(_mm_sub_ps(vUnionMax, vUnionMin), vOneDiv2);\n\n        return vRet;\n    }\n\n    ZetaInline float __vectorcall AABBSurfaceArea(v_AABB vBox)\n    {\n        const __m128 vEight = _mm_set1_ps(8.0f);\n        const __m128 vYZX = _mm_shuffle_ps(vBox.vExtents, vBox.vExtents, V_SHUFFLE_XYZW(1, 2, 0, 0));\n        const __m128 vZXY = _mm_shuffle_ps(vBox.vExtents, vBox.vExtents, V_SHUFFLE_XYZW(2, 0, 1, 0));\n\n        __m128 res = _mm_mul_ps(vBox.vExtents, vYZX);\n        res = _mm_fmadd_ps(vBox.vExtents, vZXY, res);\n        res = _mm_fmadd_ps(vYZX, vZXY, res);\n        res = _mm_mul_ps(res, vEight);\n        res = _mm_shuffle_ps(res, res, V_SHUFFLE_XYZW(0, 0, 0, 0));\n\n        return _mm_cvtss_f32(res);\n    }\n\n    // Returns how source \"intersects\" target. Both must be in the same coordinate system\n    ZetaInline COLLISION_TYPE __vectorcall intersectAABBvsAABB(const v_AABB source, const v_AABB target)\n    {\n        __m128 vMinSource = _mm_sub_ps(source.vCenter, source.vExtents);\n        __m128 vMaxSource = _mm_add_ps(source.vCenter, source.vExtents);\n\n        __m128 vMinTarget = _mm_sub_ps(target.vCenter, target.vExtents);\n        __m128 vMaxTarget = _mm_add_ps(target.vCenter, target.vExtents);\n\n        // contains\n        __m128 vTemp0 = _mm_cmpge_ps(vMinTarget, vMinSource);\n        __m128 vTemp1 = _mm_cmpge_ps(vMaxSource, vMaxTarget);\n\n        int contains = _mm_movemask_ps(_mm_and_ps(vTemp0, vTemp1));\n\n        // intersects\n        __m128 vTemp2 = _mm_cmpge_ps(vMaxTarget, vMinSource);\n        __m128 vTemp3 = _mm_cmpge_ps(vMaxSource, vMinTarget);\n\n        int intersects = _mm_movemask_ps(_mm_and_ps(vTemp2, vTemp3));\n\n        return (contains & 0xf) == 0xf ? COLLISION_TYPE::CONTAINS :\n            ((intersects & 0xf) == 0xf ? COLLISION_TYPE::INTERSECTS : COLLISION_TYPE::DISJOINT);\n    }\n\n    // Returns the AABB that results from the intersection of two AABBs\n    ZetaInline v_AABB __vectorcall overlapAABB(const v_AABB vBox1, const v_AABB vBox2)\n    {\n        __m128 vMin1 = _mm_sub_ps(vBox1.vCenter, vBox1.vExtents);\n        __m128 vMax1 = _mm_add_ps(vBox1.vCenter, vBox1.vExtents);\n\n        __m128 vMin2 = _mm_sub_ps(vBox2.vCenter, vBox2.vExtents);\n        __m128 vMax2 = _mm_add_ps(vBox2.vCenter, vBox2.vExtents);\n\n        __m128 vOverlapMin = _mm_min_ps(vMax1, vMax2);\n        __m128 vOverlapMax = _mm_max_ps(vMin1, vMin2);\n\n        const __m128 vOneDiv2 = _mm_set1_ps(0.5f);\n        v_AABB vO;\n        vO.vCenter = _mm_mul_ps(_mm_add_ps(vOverlapMin, vOverlapMax), vOneDiv2);\n        vO.vExtents = _mm_mul_ps(_mm_sub_ps(vOverlapMax, vOverlapMin), vOneDiv2);\n\n        return vO;\n    }\n\n    // Returns whether the given AABB and plane intersect. Both must be in the same coordinate system\n    ZetaInline bool __vectorcall intersectAABBvsPlane(const v_AABB vAABB, const __m128 vPlane)\n    {\n        // Separating-axis theorem, use the plane Normal as the axis\n        __m128 vProjLengthAlongAxis = _mm_dp_ps(vAABB.vExtents, abs(vPlane), 0xf);\n        __m128 vDistFromPlane = distFromPlane(vAABB.vCenter, vPlane);\n        __m128 vIntersects = _mm_cmpge_ps(vProjLengthAlongAxis, vDistFromPlane);\n\n        int r = _mm_movemask_ps(vIntersects);\n        return r & 0xf;\n    }\n\n    // Returns whether the given view frustum contains or intersects the given AABB.\n    // Assumes plane normals of the frustum are already normalized.\n    ZetaInline COLLISION_TYPE __vectorcall instersectFrustumVsAABB(const v_ViewFrustum vFrustum, const v_AABB vBox)\n    {\n        // Separating-axis theorem, use the plane Normal as the axis\n\n        __m128 vEx = _mm_shuffle_ps(vBox.vExtents, vBox.vExtents, V_SHUFFLE_XYZW(0, 0, 0, 0));\n        __m128 vEy = _mm_shuffle_ps(vBox.vExtents, vBox.vExtents, V_SHUFFLE_XYZW(1, 1, 1, 1));\n        __m128 vEz = _mm_shuffle_ps(vBox.vExtents, vBox.vExtents, V_SHUFFLE_XYZW(2, 2, 2, 2));\n\n        // (E.x, E.x, E.x, E.x, E.x, E.x, E.x, E.x)\n        const __m256 vEx256 = _mm256_insertf128_ps(_mm256_castps128_ps256(vEx), vEx, 0x1);\n        // (E.y, E.y, E.y, E.y, E.y, E.y, E.y, E.y)\n        const __m256 vEy256 = _mm256_insertf128_ps(_mm256_castps128_ps256(vEy), vEy, 0x1);\n        // (E.z, E.z, E.z, E.z, E.z, E.z, E.z, E.z)\n        const __m256 vEz256 = _mm256_insertf128_ps(_mm256_castps128_ps256(vEz), vEz, 0x1);\n\n        // Absolute value of the plane normals\n        __m256 vN_x_abs = abs(vFrustum.vN_x);\n        __m256 vN_y_abs = abs(vFrustum.vN_y);\n        __m256 vN_z_abs = abs(vFrustum.vN_z);\n\n        // Projection of farthest corner on the axis\n        __m256 vLargestProjLengthAlongAxis = _mm256_mul_ps(vEx256, vN_x_abs);\n        vLargestProjLengthAlongAxis = _mm256_fmadd_ps(vEy256, vN_y_abs, vLargestProjLengthAlongAxis);\n        vLargestProjLengthAlongAxis = _mm256_fmadd_ps(vEz256, vN_z_abs, vLargestProjLengthAlongAxis);\n\n        __m128 vCy = _mm_shuffle_ps(vBox.vCenter, vBox.vCenter, V_SHUFFLE_XYZW(1, 1, 1, 1));\n        __m128 vCz = _mm_shuffle_ps(vBox.vCenter, vBox.vCenter, V_SHUFFLE_XYZW(2, 2, 2, 2));\n\n        // (C.x, C.x, C.x, C.x, C.x, C.x, C.x, C.x)\n        const __m256 vCx256 = _mm256_broadcastss_ps(vBox.vCenter);\n        // (C.y, C.y, C.y, C.y, C.y, C.y, C.y, C.y)\n        const __m256 vCy256 = _mm256_insertf128_ps(_mm256_castps128_ps256(vCy), vCy, 0x1);\n        // (C.z, C.z, C.z, C.z, C.z, C.z, C.z, C.z)\n        const __m256 vCz256 = _mm256_insertf128_ps(_mm256_castps128_ps256(vCz), vCz, 0x1);\n\n        // Distance of the AABB center from the plane\n        __m256 vCenterDistFromPlane = _mm256_mul_ps(vCx256, vFrustum.vN_x);\n        vCenterDistFromPlane = _mm256_fmadd_ps(vCy256, vFrustum.vN_y, vCenterDistFromPlane);\n        vCenterDistFromPlane = _mm256_fmadd_ps(vCz256, vFrustum.vN_z, vCenterDistFromPlane);\n        vCenterDistFromPlane = _mm256_add_ps(vFrustum.vd, vCenterDistFromPlane);\n\n        // AABB is (at least partially) in the positive half space of the plane. It may or may not intersect the plane\n        __m256 vIntersects1 = _mm256_cmp_ps(vCenterDistFromPlane, _mm256_setzero_ps(), _CMP_GE_OQ);\n        // AABB intersects the plane\n        __m256 vIntersects2 = _mm256_cmp_ps(vLargestProjLengthAlongAxis, abs(vCenterDistFromPlane), _CMP_GE_OQ);\n\n        int r1 = _mm256_movemask_ps(vIntersects1);\n        int r2 = _mm256_movemask_ps(vIntersects2);\n\n        // Must be true for all the planes\n        bool intersects = ((r1 & 0x3f) | (r2 & 0x3f)) == 0x3f;\n\n        return intersects ? COLLISION_TYPE::INTERSECTS : COLLISION_TYPE::DISJOINT;\n    }\n\n    // Returns whether given ray and AABB intersect\n    // When a given Ray is tested against multiple AABBs, a few values that only depend \n    // on that ray can be precomputed to avoid unnecessary recomputation\n    ZetaInline bool __vectorcall intersectRayVsAABB(const v_Ray vRay, const __m128 vDirRcp,\n        const __m128 vDirIsPos, const __m128 vParallelToAxes, const v_AABB& vBox, float& t)\n    {\n        // An AABB can be described as the intersection of three \"slabs\", where a slab\n        // is the (infinite) region of space between two parallel planes.\n        // \n        // A given ray intersects an AABB if and only if some segment of the ray intersects \n        // the three slabs of the AABB at the same time.\n        //\n        // To figure out whether that's the case, the ray is intersected with two planes \n        // conistuting each slab and two intersections are used to update \"farthest entry\" (t0) \n        // and \"nearest exit\" (t1) of all the resulting ray/slab intersection segments. If at \n        // some point t0 becomes greater than t1, then there's no intersection.\n\n        // For better numerical robustness, translate the ray center to origin and do\n        // the same for AABB\n        const __m128 vCenterTranslatedToOrigin = _mm_sub_ps(vBox.vCenter, vRay.vOrigin);\n\n        // (x_min, y_min, z_min)\n        __m128 vMin = _mm_sub_ps(vCenterTranslatedToOrigin, vBox.vExtents);\n        // (x_max, y_max, z_max)\n        __m128 vMax = _mm_add_ps(vCenterTranslatedToOrigin, vBox.vExtents);\n\n        // If ray and AABB are parallel, then the ray origin must be inside the AABB\n        const __m128 vZero = _mm_setzero_ps();\n        const __m128 vOriginOutsideAABB = _mm_or_ps(_mm_cmpge_ps(vZero, vMax), _mm_cmpge_ps(vMin, vZero));\n        const __m128 vResParallel = _mm_and_ps(vParallelToAxes, vOriginOutsideAABB);\n\n        // t = x_min - (o_x, o_y, o_z) / d\n        // t = x_min - (0, 0, 0) / d\n        __m128 vTminTemp = _mm_mul_ps(vMin, vDirRcp);\n        __m128 vTmaxTemp = _mm_mul_ps(vMax, vDirRcp);\n\n        // If x component of ray direction is negative, then the nearest hit with \n        // the (x_min-x_max) slab is with the x = x_max plane and vice versa for the\n        // positive case (y and z cases are similar)\n        __m128 vTmin = _mm_blendv_ps(vTmaxTemp, vTminTemp, vDirIsPos);\n        __m128 vTmax = _mm_blendv_ps(vTminTemp, vTmaxTemp, vDirIsPos);\n        // For parallel planes, the result is NaN - make sure those elements don't impact\n        // the following comparisons\n        vTmax = _mm_blendv_ps(vTmax, _mm_set1_ps(FLT_MAX), vParallelToAxes);\n        vTmin = _mm_blendv_ps(vTmin, _mm_set1_ps(-FLT_MAX), vParallelToAxes);\n\n        __m128 vTFarthestEntry = _mm_shuffle_ps(vTmin, vTmin, V_SHUFFLE_XYZW(0, 0, 0, 0));\n        __m128 vTNearestExit = _mm_shuffle_ps(vTmax, vTmax, V_SHUFFLE_XYZW(0, 0, 0, 0));\n\n        // Find nearest exit among three ray-slab intersections\n        vTNearestExit = _mm_min_ps(vTNearestExit, _mm_shuffle_ps(vTmax, vTmax, V_SHUFFLE_XYZW(1, 1, 1, 1)));\n        vTNearestExit = _mm_min_ps(vTNearestExit, _mm_shuffle_ps(vTmax, vTmax, V_SHUFFLE_XYZW(2, 2, 2, 2)));\n        // If t1 is less than zero, then there's no intersection\n        const __m128 vT1IsNegative = _mm_cmpgt_ps(vZero, vTNearestExit);\n\n        // Find farthest entry among three ray-slab intersections\n        vTFarthestEntry = _mm_max_ps(vTFarthestEntry, _mm_shuffle_ps(vTmin, vTmin, V_SHUFFLE_XYZW(1, 1, 1, 1)));\n        vTFarthestEntry = _mm_max_ps(vTFarthestEntry, _mm_shuffle_ps(vTmin, vTmin, V_SHUFFLE_XYZW(2, 2, 2, 2)));\n\n        const __m128 vResNotParallel = _mm_or_ps(_mm_cmpgt_ps(vTFarthestEntry, vTNearestExit), vT1IsNegative);\n        __m128 vRes = _mm_or_ps(vResNotParallel, vResParallel);\n\n        // https://stackoverflow.com/questions/5526658/intel-sse-why-does-mm-extract-ps-return-int-instead-of-float\n        float t_entry = _mm_cvtss_f32(vTFarthestEntry);\n        float t_exit = _mm_cvtss_f32(vTNearestExit);\n        // When ray is inside the AABB, entry hit is behind the origin, return exit hit instead\n        int rayInsideAABB = (_mm_movemask_ps(vOriginOutsideAABB) & 0x7) == 0;\n        t = !rayInsideAABB ? t_entry : t_exit;\n        int res = _mm_movemask_ps(vRes);\n\n        return (res & 0x7) == 0;\n    }\n\n    ZetaInline bool __vectorcall intersectRayVsAABB(const v_Ray vRay, const v_AABB& vBox, float& t)\n    {\n        const __m128 vDirRcp = _mm_div_ps(_mm_set1_ps(1.0f), vRay.vDir);\n        const __m128 vDirIsPos = _mm_cmpge_ps(vRay.vDir, _mm_setzero_ps());\n        const __m128 vEps = _mm_set1_ps(FLT_EPSILON);\n        const __m128 vParallelToAxes = _mm_cmpge_ps(vEps, abs(vRay.vDir));\n\n        return intersectRayVsAABB(vRay, vDirRcp, vDirIsPos, vParallelToAxes, vBox, t);\n    }\n\n    // Returns whether given ray and triangle formed by vertices v0v1v2 (clockwise order) intersect\n    ZetaInline bool __vectorcall intersectRayVsTriangle(const v_Ray vRay, __m128 v0,\n        __m128 v1, __m128 v2, float& t)\n    {\n        // Closer to (0, 0, 0) provides better precision, so translate ray origin to (0, 0, 0)\n        v0 = _mm_sub_ps(v0, vRay.vOrigin);\n        v1 = _mm_sub_ps(v1, vRay.vOrigin);\n        v2 = _mm_sub_ps(v2, vRay.vOrigin);\n\n        const __m128 vp = _mm_sub_ps(v2, v0);        // v2 - v0\n        const __m128 vq = _mm_sub_ps(v1, v0);        // v1 - v0\n        const __m128 vr = negate(v0);                // ray.Orig - v0\n        const __m128 vMinDir = negate(vRay.vDir);\n\n        // Solve the linear system of equation using the Cramer's rule:\n        //        [v1 - v0, v2 - v0, -d] [v w t]^t = [origin - v0]^t\n        //\n        // v = (origin - v0).((v2 - v0) * d)\n        // w = (origin - v0).(-d * (v2 - v0))\n        // t = (origin - v0).((v1 - v0) * (v2 - v0))\n        //\n        // where v, w are barrycentric coords. of hit position such that:\n        //        v0 + v(v1 - v0) + w(v2 - v0) = hit_pos\n\n        __m128 vRow0 = cross(vp, vMinDir);    // (v2 - v0) * ray.Dir\n        __m128 vRow1 = cross(vMinDir, vq);    // ray.Dir * (v1 - v0)\n        __m128 vRow2 = cross(vq, vp);        // (v1 - v0) * (v2 - v0)\n\n        // Compute determinant\n        __m128 vDet = _mm_dp_ps(vRow2, vMinDir, 0xff);\n\n        //        0  1  2              0  4  8\n        // M =    4  5  6     -->  M = 1  5  9\n        //      8  9  10             2  6  10\n        const __m128 vTemp0 = _mm_shuffle_ps(vRow0, vRow1, V_SHUFFLE_XYZW(0, 1, 0, 1));    // 0  1  4  5\n        const __m128 vTemp1 = _mm_shuffle_ps(vRow0, vRow1, V_SHUFFLE_XYZW(2, 0, 2, 0));    // 2  _  6  _\n\n        vRow0 = _mm_shuffle_ps(vTemp0, vRow2, V_SHUFFLE_XYZW(0, 2, 0, 0));\n        vRow1 = _mm_shuffle_ps(vTemp0, vRow2, V_SHUFFLE_XYZW(1, 3, 1, 0));\n        vRow2 = _mm_shuffle_ps(vTemp1, vRow2, V_SHUFFLE_XYZW(0, 2, 2, 0));\n\n        // (v, w, t, _)\n        __m128 vRes = _mm_mul_ps(_mm_shuffle_ps(vr, vr, V_SHUFFLE_XYZW(0, 0, 0, 0)), vRow0);\n        vRes = _mm_fmadd_ps(_mm_shuffle_ps(vr, vr, V_SHUFFLE_XYZW(1, 1, 1, 0)), vRow1, vRes);\n        vRes = _mm_fmadd_ps(_mm_shuffle_ps(vr, vr, V_SHUFFLE_XYZW(2, 2, 2, 0)), vRow2, vRes);\n\n        vRes = _mm_div_ps(vRes, vDet);\n        __m128 vRayTriParallel = _mm_cmpge_ps(abs(vDet), _mm_set1_ps(FLT_EPSILON));\n        int rayTriParallel = _mm_movemask_ps(vRayTriParallel);\n\n        float4a q = store(vRes);\n        t = q.z;\n\n        bool insideTri = (q.x >= 0) && (q.x <= 1) && (q.y >= 0) && (q.y <= 1) && (q.x + q.y <= 1.0);\n        bool triBehindRay = (t >= 0);\n\n        // Determinant is equal to the dot product of triangle normal and (negative) ray \n        // direction. If it's zero, then the ray was parallel to the triangle. Furthermore,\n        // positive determinat means the ray hit the  triangle's frontface while negative\n        // means ray hit the backfacing side\n\n        return insideTri && triBehindRay && (rayTriParallel & 0xf);\n    }\n\n    // Ref: J. Arvo, \"Transforming axis-aligned bounding boxes,\" Graphics Gems, 1990.\n    ZetaInline v_AABB __vectorcall transform(const v_float4x4 M, const v_AABB& aabb)\n    {\n        // Transform the center\n        v_AABB newAABB;\n        newAABB.vCenter = mul(M, aabb.vCenter);\n\n        // Extents.w = 0, so translation doesn't apply\n        const __m128 vX = _mm_shuffle_ps(aabb.vExtents, aabb.vExtents, V_SHUFFLE_XYZW(0, 0, 0, 0));\n        newAABB.vExtents = _mm_mul_ps(vX, abs(M.vRow[0]));\n\n        const __m128 vY = _mm_shuffle_ps(aabb.vExtents, aabb.vExtents, V_SHUFFLE_XYZW(1, 1, 1, 1));\n        newAABB.vExtents = _mm_fmadd_ps(vY, abs(M.vRow[1]), newAABB.vExtents);\n\n        const __m128 vZ = _mm_shuffle_ps(aabb.vExtents, aabb.vExtents, V_SHUFFLE_XYZW(2, 2, 2, 2));\n        newAABB.vExtents = _mm_fmadd_ps(vZ, abs(M.vRow[2]), newAABB.vExtents);\n\n        return newAABB;\n    }\n\n    // Transforms given view frustum with a transformation matrix\n    ZetaInline v_ViewFrustum __vectorcall transform(const v_float4x4 M, const v_ViewFrustum& vFrustum)\n    {\n        // In general, planes need to be transformed with the inverse-transpose of a given transformation M\n        // (due to the normal vector). For view-to-world transformation, we know that it only consists\n        // of rotations and translations, therefore:\n        //        M = R * T\n        //        M = ((R * T)^-1)^T\n        //        M = (T^-1 * R^-1)^T\n        //        M = (T^-1 * R^T)^T    (rotation matrix is orthogonal, so R^-1 == R^T)\n        //        M = R * (T^-1)^T\n        // \n        // In summary, inverse-transpose of M is the same as M except for the 4th column being:\n        //        [M.row0.Tv, M.row1.Tv, M.row2.Tv, 1]^T\n        // \n        // with Tv = (-T.x, -T.y, -T.z)\n        //\n        const v_float4x4 vMT = transpose(M);\n        const __m128 vTinv = negate(M.vRow[3]);\n\n        __m128 v4th = _mm_mul_ps(vMT.vRow[0], _mm_shuffle_ps(vTinv, vTinv, V_SHUFFLE_XYZW(0, 0, 0, 0)));\n        v4th = _mm_fmadd_ps(vMT.vRow[1], _mm_shuffle_ps(vTinv, vTinv, V_SHUFFLE_XYZW(1, 1, 1, 1)), v4th);\n        v4th = _mm_fmadd_ps(vMT.vRow[2], _mm_shuffle_ps(vTinv, vTinv, V_SHUFFLE_XYZW(2, 2, 2, 2)), v4th);\n\n        v_float4x4 vInvT;\n        vInvT.vRow[0] = _mm_insert_ps(M.vRow[0], v4th, 0x30);\n        vInvT.vRow[1] = _mm_insert_ps(M.vRow[1], v4th, 0x70);\n        vInvT.vRow[2] = _mm_insert_ps(M.vRow[2], v4th, 0xb0);\n        vInvT.vRow[3] = _mm_insert_ps(M.vRow[3], M.vRow[3], 0x7);\n\n        // Transform each of the 6 frustum planes\n        // each plane (n_x, n_y, n_z, d) is transformed such that:\n        //        transformed_plane = (n_x, n_y, n_z, d) * M\n        //\n        //        where M = R * (T^-1)^T\n\n        v_ViewFrustum vRet;\n\n        vRet.vN_x = _mm256_mul_ps(_mm256_broadcastss_ps(vInvT.vRow[0]), vFrustum.vN_x);\n        vRet.vN_x = _mm256_fmadd_ps(_mm256_broadcastss_ps(vInvT.vRow[1]), vFrustum.vN_y, vRet.vN_x);\n        vRet.vN_x = _mm256_fmadd_ps(_mm256_broadcastss_ps(vInvT.vRow[2]), vFrustum.vN_z, vRet.vN_x);\n\n        __m256 vRow0RightShifted = _mm256_broadcastss_ps(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(vInvT.vRow[0]), 4)));\n        __m256 vRow1RightShifted = _mm256_broadcastss_ps(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(vInvT.vRow[1]), 4)));\n        __m256 vRow2RightShifted = _mm256_broadcastss_ps(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(vInvT.vRow[2]), 4)));\n\n        vRet.vN_y = _mm256_mul_ps(vRow0RightShifted, vFrustum.vN_x);\n        vRet.vN_y = _mm256_fmadd_ps(vRow1RightShifted, vFrustum.vN_y, vRet.vN_y);\n        vRet.vN_y = _mm256_fmadd_ps(vRow2RightShifted, vFrustum.vN_z, vRet.vN_y);\n\n        vRow0RightShifted = _mm256_broadcastss_ps(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(vInvT.vRow[0]), 8)));\n        vRow1RightShifted = _mm256_broadcastss_ps(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(vInvT.vRow[1]), 8)));\n        vRow2RightShifted = _mm256_broadcastss_ps(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(vInvT.vRow[2]), 8)));\n\n        vRet.vN_z = _mm256_mul_ps(vRow0RightShifted, vFrustum.vN_x);\n        vRet.vN_z = _mm256_fmadd_ps(vRow1RightShifted, vFrustum.vN_y, vRet.vN_z);\n        vRet.vN_z = _mm256_fmadd_ps(vRow2RightShifted, vFrustum.vN_z, vRet.vN_z);\n\n        vRow0RightShifted = _mm256_broadcastss_ps(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(vInvT.vRow[0]), 12)));\n        vRow1RightShifted = _mm256_broadcastss_ps(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(vInvT.vRow[1]), 12)));\n        vRow2RightShifted = _mm256_broadcastss_ps(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(vInvT.vRow[2]), 12)));\n        __m256 vRow3RightShifted = _mm256_broadcastss_ps(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(vInvT.vRow[3]), 12)));\n\n        vRet.vd = _mm256_mul_ps(_mm256_broadcastss_ps(v4th), vFrustum.vN_x);\n        vRet.vd = _mm256_fmadd_ps(vRow1RightShifted, vFrustum.vN_y, vRet.vd);\n        vRet.vd = _mm256_fmadd_ps(vRow2RightShifted, vFrustum.vN_z, vRet.vd);\n        vRet.vd = _mm256_fmadd_ps(vRow3RightShifted, vFrustum.vd, vRet.vd);\n\n        return vRet;\n    }\n\n    ZetaInline AABB __vectorcall store(v_AABB vBox)\n    {\n        AABB aabb;\n\n        float4 f1;\n        _mm_storeu_ps(reinterpret_cast<float*>(&f1), vBox.vCenter);\n        aabb.Center = float3(f1.x, f1.y, f1.z);\n\n        float4 f2;\n        _mm_storeu_ps(reinterpret_cast<float*>(&f2), vBox.vExtents);\n        aabb.Extents = float3(f2.x, f2.y, f2.z);\n\n        return aabb;\n    }\n}\n"
  },
  {
    "path": "Source/ZetaCore/Math/CollisionTypes.h",
    "content": "#pragma once\n\n#include \"Vector.h\"\n#ifndef NDEBUG\n#include <type_traits>\n#endif\n\nnamespace ZetaRay::Math\n{\n    enum class COLLISION_TYPE\n    {\n        DISJOINT = 0,\n        INTERSECTS = 1,\n        CONTAINS = 2\n    };\n\n    //--------------------------------------------------------------------------------------\n    // Axis-Aligned Bounding Box\n    //--------------------------------------------------------------------------------------\n\n    struct AABB\n    {\n        AABB() = default;\n        AABB(const float3& c, const float3& e)\n            : Center(c),\n            Extents(e)\n        {}\n        static AABB Init()\n        {\n            return AABB(float3(0), float3(-FLT_MAX));\n        }\n\n        float3 Center;\n        float3 Extents;\n    };\n\n    struct v_AABB\n    {\n        v_AABB() = default;\n        explicit v_AABB(const AABB& aabb)\n        {\n            Reset(aabb);\n        }\n        v_AABB(const float3& c, const float3& e)\n        {\n            Reset(c, e);\n        }\n        static v_AABB Init()\n        {\n            return v_AABB(float3(0), float3(-FLT_MAX));\n        }\n        void __vectorcall Reset(const AABB& aabb)\n        {\n            vCenter = _mm_loadu_ps(reinterpret_cast<const float*>(&aabb));\n            vExtents = _mm_loadu_ps(reinterpret_cast<const float*>(&aabb) + 3);\n\n            vExtents = _mm_insert_ps(vExtents, vCenter, 0xc8);\n            // Make sure the 4th element is 1.0f so that translation transforms apply\n            vCenter = _mm_insert_ps(vCenter, _mm_set1_ps(1.0f), 0x30);\n        }\n        void __vectorcall Reset(const float3& center, const float3& extents)\n        {\n            float3& c = const_cast<float3&>(center);\n            float3& e = const_cast<float3&>(extents);\n            vCenter = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double*>(&c)));\n            vCenter = _mm_blend_ps(vCenter, _mm_set1_ps(1.0f), 0x8);\n            vCenter = _mm_insert_ps(vCenter, _mm_load_ss(&c.z), 0x20);\n\n            vExtents = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double*>(&e)));\n            vExtents = _mm_insert_ps(vExtents, _mm_load_ss(&e.z), 0x20);\n        }\n        ZetaInline void __vectorcall Reset(__m128 vMinPoint, __m128 vMaxPoint)\n        {\n            const __m128 vOneDivTwo = _mm_set1_ps(0.5f);\n            vCenter = _mm_mul_ps(_mm_add_ps(vMaxPoint, vMinPoint), vOneDivTwo);\n            // Make sure the 4th element is 1.0f so that translation transforms apply\n            vCenter = _mm_insert_ps(vCenter, _mm_set1_ps(1.0f), 0x30);\n\n            vExtents = _mm_mul_ps(_mm_sub_ps(vMaxPoint, vMinPoint), vOneDivTwo);\n        }\n\n        __m128 vCenter;\n        __m128 vExtents;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // Plane with equation n.(p - p0) = 0, where n is the plane normal and p0 is any point \n    // on its surface\n    //--------------------------------------------------------------------------------------\n\n    struct Plane\n    {\n        Plane() = default;\n        Plane(const float3& n, float d)\n            : Normal(n),\n            d(d)\n        {}\n        Plane(const float3& n, const float3& p0)\n            : Normal(n),\n            d(-(n.x * p0.x + n.y * p0.y + n.z * p0.z))\n        {}\n        static Plane Init()\n        {\n            return Plane(float3(0.0f), 0.0f);\n        }\n\n        float3 Normal;\n        float d;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // View Frustum\n    //--------------------------------------------------------------------------------------\n\n    // In view space, centered at the origin (0, 0, 0), looking down the +z-axis\n    struct alignas(16) ViewFrustum\n    {\n        ViewFrustum() = default;\n        ViewFrustum(float vFOV, float aspectRatio, float nearZ, float farZ)\n        {\n            Assert(vFOV > 0.0f, \"invalid vertical FOV\");\n            Assert(nearZ > 0.0f && farZ > 0.0f && farZ > nearZ, \"invalid near and far planes\");\n            Assert(aspectRatio > 0.0f, \"invalid aspect ratio\");\n            const float projWndDist = 1.0f / tanf(vFOV * 0.5f);\n\n            float3 n;\n            float d;\n\n            // For all the planes, positive half space overlaps inside of the frustum\n\n            // Near plane\n            {\n                n = float3(0.0f, 0.0f, 1.0f);\n                d = -nearZ;\n                Near = Plane(n, d);\n            }\n\n            // Far plane\n            {\n                n = float3(0.0f, 0.0f, -1.0f);\n                d = farZ;\n                Far = Plane(n, d);\n            }\n\n            float l2Norm = 1.0f / sqrtf(projWndDist * projWndDist + 1.0f);\n\n            // Top plane\n            {\n                n = float3(0.0f, -projWndDist, 1.0f);\n                n.y *= l2Norm;\n                n.z *= l2Norm;\n                d = 0.0f;\n                Assert(fabsf(1.0f - (n.y * n.y + n.z * n.z)) < 1e-6f, \"normal vector is not normalized\");\n                Top = Plane(n, d);\n            }\n\n            // Bottom plane\n            {\n                n = float3(0.0f, projWndDist, 1.0f);\n                n.y *= l2Norm;\n                n.z *= l2Norm;\n                d = 0.0f;\n                Assert(fabsf(1.0f - (n.y * n.y + n.z * n.z)) < 1e-6f, \"normal vector is not normalized\");\n                Bottom = Plane(n, d);\n            }\n\n            l2Norm = 1.0f / sqrtf(projWndDist * projWndDist + aspectRatio * aspectRatio);\n\n            // Left plane\n            {\n                n = float3(projWndDist, 0.0f, aspectRatio);\n                n.x *= l2Norm;\n                n.z *= l2Norm;\n                d = 0.0f;\n                Assert(fabsf(1.0f - (n.x * n.x + n.z * n.z)) < 1e-6f, \"normal vector is not normalized\");\n                Left = Plane(n, d);\n            }\n\n            // Right plane\n            {\n                n = float3(-projWndDist, 0.0f, aspectRatio);\n                n.x *= l2Norm;\n                n.z *= l2Norm;\n                d = 0.0f;\n                Assert(fabsf(1.0f - (n.x * n.x + n.z * n.z)) < 1e-6f, \"normal vector is not normalized\");\n                Right = Plane(n, d);\n            }\n        }\n        static ViewFrustum Init()\n        {\n            ViewFrustum ret;\n            ret.Left = Plane(float3(0.0f), 0.0f);\n            ret.Right = Plane(float3(0.0f), 0.0f);\n            ret.Top = Plane(float3(0.0f), 0.0f);\n            ret.Bottom = Plane(float3(0.0f), 0.0f);\n            ret.Near = Plane(float3(0.0f), 0.0f);\n            ret.Far = Plane(float3(0.0f), 0.0f);\n\n            return ret;\n        }\n\n        Plane Left;\n        Plane Right;\n        Plane Top;\n        Plane Bottom;\n        Plane Near;\n        Plane Far;\n    };\n\n    struct v_ViewFrustum\n    {\n        v_ViewFrustum() = default;\n        explicit v_ViewFrustum(ViewFrustum& f)\n        {\n            alignas(32) float N_x[8];\n            alignas(32) float N_y[8];\n            alignas(32) float N_z[8];\n            alignas(32) float d[8];\n\n            N_x[0] = f.Left.Normal.x;\n            N_y[0] = f.Left.Normal.y;\n            N_z[0] = f.Left.Normal.z;\n            d[0] = f.Left.d;\n\n            N_x[1] = f.Right.Normal.x;\n            N_y[1] = f.Right.Normal.y;\n            N_z[1] = f.Right.Normal.z;\n            d[1] = f.Right.d;\n\n            N_x[2] = f.Top.Normal.x;\n            N_y[2] = f.Top.Normal.y;\n            N_z[2] = f.Top.Normal.z;\n            d[2] = f.Top.d;\n\n            N_x[3] = f.Bottom.Normal.x;\n            N_y[3] = f.Bottom.Normal.y;\n            N_z[3] = f.Bottom.Normal.z;\n            d[3] = f.Bottom.d;\n\n            N_x[4] = f.Near.Normal.x;\n            N_y[4] = f.Near.Normal.y;\n            N_z[4] = f.Near.Normal.z;\n            d[4] = f.Near.d;\n\n            N_x[5] = f.Far.Normal.x;\n            N_y[5] = f.Far.Normal.y;\n            N_z[5] = f.Far.Normal.z;\n            d[5] = f.Far.d;\n\n            vN_x = _mm256_load_ps(N_x);\n            vN_y = _mm256_load_ps(N_y);\n            vN_z = _mm256_load_ps(N_z);\n            vd = _mm256_load_ps(d);\n        }\n\n        __m256 vN_x;\n        __m256 vN_y;\n        __m256 vN_z;\n        __m256 vd;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // Ray\n    //--------------------------------------------------------------------------------------\n\n    struct Ray\n    {\n        constexpr Ray() = default;\n        constexpr Ray(const float3& o, const float3& d)\n            : Origin(o),\n            Dir(d)\n        {}\n\n        float3 Origin;\n        float3 Dir;\n    };\n\n    struct v_Ray\n    {\n        v_Ray()\n        {}\n\n        explicit v_Ray(Ray& r)\n        {\n            vOrigin = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double*>(&r.Origin)));\n            vOrigin = _mm_insert_ps(vOrigin, _mm_load_ss(&r.Origin.z), 0x20);\n\n            vDir = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double*>(&r.Dir)));\n            vDir = _mm_insert_ps(vDir, _mm_load_ss(&r.Dir.z), 0x20);\n        }\n\n        v_Ray(float3& origin, float3& dir)\n        {\n            vOrigin = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double*>(&origin)));\n            vOrigin = _mm_insert_ps(vOrigin, _mm_load_ss(&origin.z), 0x20);\n\n            vDir = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double*>(&dir)));\n            vDir = _mm_insert_ps(vDir, _mm_load_ss(&dir.z), 0x20);\n        }\n\n        __m128 vOrigin;\n        __m128 vDir;\n    };\n\n#ifndef NDEBUG\n    static_assert(std::is_trivially_default_constructible_v<AABB>);\n    static_assert(std::is_trivially_default_constructible_v<v_AABB>);\n    static_assert(std::is_trivially_default_constructible_v<Plane>);\n    static_assert(std::is_trivially_default_constructible_v<ViewFrustum>);\n    static_assert(std::is_trivially_default_constructible_v<v_ViewFrustum>); \n#endif\n}"
  },
  {
    "path": "Source/ZetaCore/Math/Color.cpp",
    "content": "#include \"Color.h\"\n#include \"Color.h\"\n#include \"Common.h\"\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Util;\n\nfloat3 Math::sRGBToLinear(const float3& color)\n{\n    float3 linearLo = color / 12.92f;\n    float3 tmp = (color + 0.055f) / 1.055f;\n    float3 linearHi;\n    linearHi.x = powf(Max(tmp.x, 0.0f), 2.4f);\n    linearHi.y = powf(Max(tmp.y, 0.0f), 2.4f);\n    linearHi.z = powf(Max(tmp.z, 0.0f), 2.4f);\n\n    float3 ret;\n    ret.x = color.x <= 0.0404499993f ? linearLo.x : linearHi.x;\n    ret.y = color.y <= 0.0404499993f ? linearLo.y : linearHi.y;\n    ret.z = color.z <= 0.0404499993f ? linearLo.z : linearHi.z;\n\n    return ret;\n}\n\n// Ref: www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/\nfloat3 Math::ColorTemperatureTosRGB(float temperature)\n{\n    float3 ret;\n\n    float tmpKelvin = Min(Max(temperature, 1000.0f), 40000.0f) / 100.0f;\n    if (tmpKelvin <= 66.0f)\n    {\n        ret.x = 255.0f;\n        ret.y = 99.4708025861f * logf(tmpKelvin) - 161.1195681661f;\n    }\n    else\n    {\n        float tmpCalc = tmpKelvin - 60.0f;\n        ret.x = 329.698727446f * pow(tmpCalc, -0.1332047592f);\n        ret.y = 288.1221695283f * pow(tmpCalc, -0.0755148492f);\n    }\n\n    if (tmpKelvin >= 66.0f)\n        ret.z = 255.0f;\n    else if (tmpKelvin <= 19.0f)\n        ret.z = 0.0f;\n    else\n        ret.z = 138.5177312231f * logf(tmpKelvin - 10.0f) - 305.0447927307f;\n\n    ret /= 255.0f;\n    ret.x = Min(Max(ret.x, 0.0f), 1.0f);\n    ret.y = Min(Max(ret.y, 0.0f), 1.0f);\n    ret.z = Min(Max(ret.z, 0.0f), 1.0f);\n\n    return ret;\n}\n"
  },
  {
    "path": "Source/ZetaCore/Math/Color.h",
    "content": "#pragma once\n\n#include \"VectorFuncs.h\"\n\nnamespace ZetaRay::Math\n{\n    ZetaInline uint16_t __vectorcall Float2ToRG8(Math::float2 v)\n    {\n        // Last two elements are set to zero\n        __m128 vRG = Math::loadFloat2(v);\n        vRG = _mm_mul_ps(vRG, _mm_set1_ps(255.0f));\n        // cvtps_epi32 uses the default rounding mode (round to nearest)\n        __m128i vTemp = _mm_cvtps_epi32(vRG);\n        vTemp = _mm_packus_epi32(vTemp, vTemp);\n        vTemp = _mm_packus_epi16(vTemp, vTemp);\n        uint32_t ret = _mm_cvtsi128_si32(vTemp);\n\n        return uint16_t(ret);\n    }\n\n    ZetaInline uint32_t __vectorcall Float3ToRGB8(Math::float3 v)\n    {\n        __m128 vRGB = Math::loadFloat3(v);\n        vRGB = _mm_mul_ps(vRGB, _mm_set1_ps(255.0f));\n        // cvtps_epi32 uses the default rounding mode (round to nearest)\n        __m128i vTemp = _mm_cvtps_epi32(vRGB);\n        // Ref: https://stackoverflow.com/questions/29856006/sse-intrinsics-convert-32-bit-floats-to-unsigned-8-bit-integers\n        vTemp = _mm_packus_epi32(vTemp, vTemp);\n        vTemp = _mm_packus_epi16(vTemp, vTemp);\n        uint32_t ret = _mm_cvtsi128_si32(vTemp);\n\n        return ret;\n    }\n\n    ZetaInline uint32_t __vectorcall Float4ToRGBA8(Math::float4 v)\n    {\n        __m128 vRGBA = Math::loadFloat4(v);\n        vRGBA = _mm_mul_ps(vRGBA, _mm_set1_ps(255.0f));\n        // cvtps_epi32 uses the default rounding mode (round to nearest)\n        __m128i vTemp = _mm_cvtps_epi32(vRGBA);\n        vTemp = _mm_packus_epi32(vTemp, vTemp);\n        vTemp = _mm_packus_epi16(vTemp, vTemp);\n        uint32_t ret = _mm_cvtsi128_si32(vTemp);\n\n        return ret;\n    }\n\n    ZetaInline Math::float3 UnpackRGB8(uint32_t rgb)\n    {\n        Math::float3 ret;\n        ret.x = float(rgb & 0xff) / 255.0f;\n        ret.y = float((rgb >> 8) & 0xff) / 255.0f;\n        ret.z = float((rgb >> 16) & 0xff) / 255.0f;\n\n        return ret;\n    }\n\n    ZetaInline Math::float4 UnpackRGBA8(uint32_t rgba)\n    {\n        Math::float4 ret;\n        ret.x = float(rgba & 0xff) / 255.0f;\n        ret.y = float((rgba >> 8) & 0xff) / 255.0f;\n        ret.z = float((rgba >> 16) & 0xff) / 255.0f;\n        ret.w = float((rgba >> 24) & 0xff) / 255.0f;\n\n        return ret;\n    }\n\n    Math::float3 sRGBToLinear(const Math::float3& color);\n    Math::float3 ColorTemperatureTosRGB(float temperature);\n}"
  },
  {
    "path": "Source/ZetaCore/Math/Common.cpp",
    "content": "#include \"Vector.h\"\n#include \"../Utility/Span.h\"\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Util;\n\nbool Math::SolveQuadratic(float a, float b, float c, float& x1, float& x2)\n{\n    float delta = b * b - 4.0f * a * c;\n\n    if (delta < 0.0f)\n        return false;\n\n    delta = sqrtf(delta);\n\n    // Ref: https://www.pbr-book.org/3ed-2018/Utilities/Mathematical_Routines#Quadratic\n    float q = b < 0 ? -0.5f * (b - delta) : -0.5f * (b + delta);\n\n    x1 = q / a;\n    x2 = c / q;\n\n    return true;\n}\n\nvoid Math::SphericalFromCartesian(const float3& w, float& theta, float& phi)\n{\n    // x = sin(theta) * cos(phi)\n    // y = cos(theta)\n    // z = -sin(theta) * sin(phi)\n    theta = acosf(w.y);                             // [0, PI]\n    // phi is measured clockwise from the x-axis and atan2f uses the sign to figure out the quadrant\n    phi = atan2f(-w.z, w.x);\n    phi = phi < 0.0f ? phi + Math::TWO_PI : phi;    // [0, 2 * PI]\n}\n\nfloat3 Math::SphericalToCartesian(float theta, float phi)\n{\n    // x = sin(theta) * cos(phi)\n    // y = cos(theta)\n    // z = -sin(theta) * sin(phi)\n    float sinTheta = sinf(theta);\n    return float3(sinTheta * cosf(phi), cosf(theta), -sinTheta * sinf(phi));\n}\n\nsize_t Math::SubdivideRangeWithMin(size_t n, size_t maxNumGroups, MutableSpan<size_t> offsets, MutableSpan<size_t> sizes, size_t minNumElems)\n{\n    Assert(offsets.size() >= maxNumGroups, \"out-of-bound access in offsets array.\");\n    Assert(sizes.size() >= maxNumGroups, \"out-of-bound access in sizes array.\");\n\n    if (n == 0)\n        return 0;\n\n    size_t groupSize = Max(n / maxNumGroups, minNumElems);\n    size_t actualNumGroups = Max(n / groupSize, 1llu);\n\n    for (size_t i = 0; i < actualNumGroups; i++)\n    {\n        offsets[i] = i * groupSize;\n        sizes[i] = groupSize;\n    }\n\n    sizes[actualNumGroups - 1] = n - offsets[actualNumGroups - 1];\n    Assert(offsets[actualNumGroups - 1] + sizes[actualNumGroups - 1] == n, \"bug\");\n\n    return actualNumGroups;\n}\n\n// Fast math must be disabled for Kahan summation\n#pragma float_control(precise, on, push)\n\nfloat Math::KahanSum(Span<float> data) \n{\n    const int64_t N = data.size();\n    float sum = 0.0f;\n    float compensation = 0.0;\n\n    // align to 32-byte boundary\n    const float* curr = data.data();\n    while ((reinterpret_cast<uintptr_t>(curr) & 31) != 0)\n    {\n        float corrected = *curr - compensation;\n        float newSum = sum + corrected;\n        compensation = (newSum - sum) - corrected;\n        sum = newSum;\n\n        curr++;\n    }\n\n    // Largest multiple of 16 (each loop iteration loads two avx registers -- 16 floats) that is smaller than N\n    const int64_t startOffset = curr - data.data();\n    int64_t numToSumSIMD = (N - startOffset);\n    numToSumSIMD -= numToSumSIMD & 15;\n\n    const float* end = curr + numToSumSIMD;\n    __m256 vSum = _mm256_setzero_ps();\n    __m256 vCompensation = _mm256_setzero_ps();\n\n    // Unroll two sums in each iteration\n    for (; curr < end; curr += 16)\n    {\n        __m256 V1 = _mm256_load_ps(curr);\n        __m256 V2 = _mm256_load_ps(curr + 8);\n\n        // Essentially each simd lane is doing a separate Kahan summation\n        __m256 vCurr = _mm256_add_ps(V1, V2);\n        __m256 vCorrected = _mm256_sub_ps(vCurr, vCompensation);\n        __m256 vNewSum = _mm256_add_ps(vSum, vCorrected);\n        vCompensation = _mm256_sub_ps(vNewSum, vSum);\n        vCompensation = _mm256_sub_ps(vCompensation, vCorrected);\n\n        vSum = vNewSum;\n    }\n\n    // Sum the different simd lanes\n    alignas(32) float simdSum[8];\n    alignas(32) float simdCompensation[8];\n    _mm256_store_ps(simdSum, vSum);\n    _mm256_store_ps(simdCompensation, vCompensation);\n\n    // Add the simd lanes\n    for (int i = 0; i < 8; i++)\n    {\n        float corrected = simdSum[i] - compensation - simdCompensation[i];\n        float newSum = sum + corrected;\n        compensation = (newSum - sum) - corrected;\n        sum = newSum;\n    }\n\n    // Add the remaining data\n    for (int64_t i = startOffset + numToSumSIMD; i < N; i++)\n    {\n        float corrected = data[i] - compensation;\n        float newSum = sum + corrected;\n        compensation = (newSum - sum) - corrected;\n        sum = newSum;\n    }\n\n    return sum;\n}\n\n#pragma float_control(pop)\n"
  },
  {
    "path": "Source/ZetaCore/Math/Common.h",
    "content": "#pragma once\n\n#include \"../Utility/Error.h\"\n#include <float.h>\n#include <string.h>\n#include <immintrin.h>    // AVX intrinsics\n#include <cmath>\n\nnamespace ZetaRay::Util\n{\n    template<typename T>\n    struct Span;\n\n    template<typename T>\n    struct MutableSpan;\n}\n\nnamespace ZetaRay::Math\n{\n    struct float3;\n}\n\nnamespace ZetaRay::Math\n{\n    static constexpr float PI = 3.141592654f;\n    static constexpr float TWO_PI = 6.283185307f;\n    static constexpr float PI_OVER_2 = 1.570796327f;\n    static constexpr float PI_OVER_4 = 0.7853981635f;\n    static constexpr float ONE_OVER_PI = 0.318309886f;\n    static constexpr float ONE_OVER_2_PI = 0.159154943f;\n    static constexpr float ONE_OVER_4_PI = 0.079577472f;\n\n    // Returns the smallest power of 2 that is larger than x\n    ZetaInline constexpr size_t NextPow2(size_t x)\n    {\n        x--;\n        x |= x >> 1;\n        x |= x >> 2;\n        x |= x >> 4;\n        x |= x >> 8;\n        x |= x >> 16;\n        x |= x >> 32;\n\n        return ++x;\n    }\n\n    // Returns whether x is a power of 2\n    ZetaInline constexpr bool IsPow2(size_t x)\n    {\n        return (x != 0) && ((x & (x - 1)) == 0);\n    }\n\n    // Aligns to nearest largest multiple of alignment\n    ZetaInline constexpr size_t AlignDown(size_t size, size_t alignment)\n    {\n        if (alignment > 0)\n        {\n            //assert(((alignment - 1) & alignment) == 0);\n            size_t mask = alignment - 1;\n            return size & ~mask;\n        }\n\n        return size;\n    }\n\n    // Aligns to nearest smallest multiple of alignment\n    template<typename T>\n    ZetaInline constexpr T AlignUp(T x, T alignment)\n    {\n        if (alignment > 0)\n        {\n            T mask = alignment - 1;\n            return (x + mask) & ~mask;\n        }\n\n        return x;\n    }\n\n    template<typename T>\n    ZetaInline constexpr T Max(T a, T b)\n    {\n        return a < b ? b : a;\n    }\n\n    template<typename T>\n    ZetaInline constexpr T Min(T a, T b)\n    {\n        return a < b ? a : b;\n    }\n\n    ZetaInline bool IsNaN(float f)\n    {\n        // For NaN:\n        //  - sign bit could be 0 or 1\n        //  - all the exponent bits must be 1 and the fraction must be non-zero\n\n        // bit-cast\n        uint32_t temp;\n        memcpy(&temp, &f, sizeof(float));\n\n        return (temp & 0x7fffffff) > 0x7f800000;\n    }\n\n    // Solves quadratic equation a * x^2 + b * x + c = 0\n    bool SolveQuadratic(float a, float b, float c, float& x1, float& x2);\n\n    ZetaInline constexpr float DegreesToRadians(float d)\n    {\n        return d * TWO_PI / 360.0f;\n    }\n\n    ZetaInline constexpr float RadiansToDegrees(float r)\n    {\n        return r * 360.0f * ONE_OVER_2_PI;\n    }\n\n    void SphericalFromCartesian(const Math::float3& w, float& theta, float& phi);\n    Math::float3 SphericalToCartesian(float theta, float phi);\n\n    // Returns x / y, where x and y are unsigned integers\n    template<typename T>\n    ZetaInline constexpr T CeilUnsignedIntDiv(T x, T y)\n    {\n        return 1 + ((x - 1) / y);\n    }\n\n    // For x \\in [0, 2^24] (there may be round-off errors for larger integers)\n    ZetaInline constexpr uint32_t Ceil(float x)\n    {\n        return (static_cast<float>(static_cast<uint32_t>(x)) == x)\n            ? static_cast<uint32_t>(x)\n            : static_cast<uint32_t>(x) + 1;\n    }\n\n    // Subdivides range [0, n) into at most maxNumGroups subsets where each subset has\n    // at least minNumElems elements\n    size_t SubdivideRangeWithMin(size_t n,\n        size_t maxNumGroups,\n        Util::MutableSpan<size_t> offsets,\n        Util::MutableSpan<size_t> sizes,\n        size_t minNumElems = 0);\n\n    // Ref: https://walbourn.github.io/directxmath-f16c-and-fma/\n    ZetaInline float HalfToFloat(uint16_t value)\n    {\n        __m128i V1 = _mm_cvtsi32_si128(static_cast<uint32_t>(value));\n        __m128 V2 = _mm_cvtph_ps(V1);\n        return _mm_cvtss_f32(V2);\n    }\n\n    ZetaInline uint16_t FloatToHalf(float value)\n    {\n        __m128 V1 = _mm_set_ss(value);\n        __m128i V2 = _mm_cvtps_ph(V1, 0);\n        return static_cast<uint16_t>(_mm_cvtsi128_si32(V2));\n    }\n\n    ZetaInline uint8_t FloatToUNorm8(float value)\n    {\n        return (uint8_t)std::fmaf(value, 255.0f, 0.5f);\n    }\n\n    ZetaInline uint16_t FloatToUNorm16(float value)\n    {\n        return (uint16_t)std::fmaf(value, float((1 << 16) - 1), 0.5f);\n    }\n\n    ZetaInline float UNorm8ToFloat(uint8_t value)\n    {\n        return value / 255.0f;\n    }\n\n    ZetaInline float UNorm16ToFloat(uint8_t value)\n    {\n        return value / float((1 << 16) - 1);\n    }\n\n    // A summation algorithm that guards against the worst-case loss of precision when summing\n    // a large sequence of floating-point numbers.\n    float KahanSum(Util::Span<float> data);\n}"
  },
  {
    "path": "Source/ZetaCore/Math/Matrix.h",
    "content": "#pragma once\n\n#include \"Vector.h\"\n#include <math.h>\n\nnamespace ZetaRay::Math\n{\n    struct float4x4a;\n    struct float3x3;\n\n    //--------------------------------------------------------------------------------------\n    // Matrix types\n    //--------------------------------------------------------------------------------------\n\n    struct float4x3\n    {\n        float4x3()\n        {}\n        float4x3(const float3& row0, const float3& row1, const float3& row2, const float3& row3)\n        {\n            m[0] = row0;\n            m[1] = row1;\n            m[2] = row2;\n            m[3] = row3;\n        }\n        explicit float4x3(const float4x4a& M);\n\n        float3 m[4];\n    };\n\n    struct float3x4\n    {\n        float3x4()\n        {}\n        float3x4(const float4& row0, const float4& row1, const float4& row2)\n        {\n            m[0] = row0;\n            m[1] = row1;\n            m[2] = row2;\n        }\n        explicit float3x4(const float4x3& M)\n        {\n            m[0] = float4(M.m[0].x, M.m[1].x, M.m[2].x, M.m[3].x);\n            m[1] = float4(M.m[0].y, M.m[1].y, M.m[2].y, M.m[3].y);\n            m[2] = float4(M.m[0].z, M.m[1].z, M.m[2].z, M.m[3].z);\n        }\n        explicit float3x4(const float4x4a& M);\n\n        float4 m[3];\n    };\n\n    struct alignas(16) float4x4a\n    {\n        float4x4a()\n        {}\n        float4x4a(const float4& row0, const float4& row1, const float4& row2, const float4& row3)\n        {\n            m[0] = row0;\n            m[1] = row1;\n            m[2] = row2;\n            m[3] = row3;\n        }\n        explicit float4x4a(const float* arr)\n        {\n            m[0] = float4a(arr[0], arr[1], arr[2], arr[3]);\n            m[1] = float4a(arr[4], arr[5], arr[6], arr[7]);\n            m[2] = float4a(arr[8], arr[9], arr[10], arr[11]);\n            m[3] = float4a(arr[12], arr[13], arr[14], arr[15]);\n        }\n        explicit float4x4a(const double* arr)\n        {\n            m[0] = float4a((float)arr[0], (float)arr[1], (float)arr[2], (float)arr[3]);\n            m[1] = float4a((float)arr[4], (float)arr[5], (float)arr[6], (float)arr[7]);\n            m[2] = float4a((float)arr[8], (float)arr[9], (float)arr[10], (float)arr[11]);\n            m[3] = float4a((float)arr[12], (float)arr[13], (float)arr[14], (float)arr[15]);\n        }\n        explicit float4x4a(const float4x3& M)\n        {\n            m[0] = float4a(M.m[0], 0.0f);\n            m[1] = float4a(M.m[1], 0.0f);\n            m[2] = float4a(M.m[2], 0.0f);\n            m[3] = float4a(M.m[3], 1.0f);\n        }\n        explicit float4x4a(const float3x3& M);\n\n        float4a m[4];\n    };\n\n    struct float3x3\n    {\n        float3x3()\n        {}\n        float3x3(const float3& row0, const float3& row1, const float3& row2)\n        {\n            m[0] = row0;\n            m[1] = row1;\n            m[2] = row2;\n        }\n        explicit float3x3(const float4x4a& M)\n        {\n            m[0] = float3(M.m[0].x, M.m[0].y, M.m[0].z);\n            m[1] = float3(M.m[1].x, M.m[1].y, M.m[1].z);\n            m[2] = float3(M.m[2].x, M.m[2].y, M.m[2].z);\n        }\n        explicit float3x3(const float4x3& M)\n        {\n            m[0] = float3(M.m[0].x, M.m[0].y, M.m[0].z);\n            m[1] = float3(M.m[1].x, M.m[1].y, M.m[1].z);\n            m[2] = float3(M.m[2].x, M.m[2].y, M.m[2].z);\n        }\n\n        float3 m[3];\n    };\n\n    struct v_float4x4\n    {\n        v_float4x4() = default;\n        v_float4x4(__m128 row0, __m128 row1, __m128 row2, __m128 row3)\n            : vRow{ row0, row1, row2, row3 }\n        {}\n\n        __m128 vRow[4];\n    };\n\n    inline float4x3::float4x3(const float4x4a& M)\n    {\n        m[0] = float3(M.m[0].x, M.m[0].y, M.m[0].z);\n        m[1] = float3(M.m[1].x, M.m[1].y, M.m[1].z);\n        m[2] = float3(M.m[2].x, M.m[2].y, M.m[2].z);\n        m[3] = float3(M.m[3].x, M.m[3].y, M.m[3].z);\n    }\n\n    inline float3x4::float3x4(const float4x4a& M)\n    {\n        m[0] = float4(M.m[0].x, M.m[1].x, M.m[2].x, M.m[3].x);\n        m[1] = float4(M.m[0].y, M.m[1].y, M.m[2].y, M.m[3].y);\n        m[2] = float4(M.m[0].z, M.m[1].z, M.m[2].z, M.m[3].z);\n    }\n\n    inline float4x4a::float4x4a(const float3x3& M)\n    {\n        m[0] = float4(M.m[0].x, M.m[0].y, M.m[0].z, 0);\n        m[1] = float4(M.m[1].x, M.m[1].y, M.m[1].z, 0);\n        m[2] = float4(M.m[2].x, M.m[2].y, M.m[2].z, 0);\n        m[3] = float4(0, 0, 0, 1);\n    }\n\n    struct AffineTransformation\n    {\n        static AffineTransformation GetIdentity()\n        {\n            AffineTransformation M;\n\n            M.Scale = float3(1.0f, 1.0f, 1.0f);\n            M.Rotation = float4(0.0f, 0.0f, 0.0f, 1.0f);\n            M.Translation = float3(0.0f, 0.0f, 0.0f);\n\n            return M;\n        }\n\n        Math::float3 Scale;\n        Math::float4 Rotation;\n        Math::float3 Translation;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Math/MatrixFuncs.h",
    "content": "#pragma once\n\n#include \"Matrix.h\"\n#include \"VectorFuncs.h\"\n\n//--------------------------------------------------------------------------------------\n// Matrix Functions\n//--------------------------------------------------------------------------------------\n\nnamespace ZetaRay::Math\n{\n    ZetaInline v_float4x4 zero()\n    {\n        const __m256 vZero = _mm256_setzero_ps();\n\n        return v_float4x4(_mm_setzero_ps(),\n            _mm_setzero_ps(),\n            _mm_setzero_ps(),\n            _mm_setzero_ps());\n    }\n\n    ZetaInline v_float4x4 identity()\n    {\n        const __m128 vZero = _mm_setzero_ps();\n        const __m128 vOne = _mm_set1_ps(1.0f);\n\n        return v_float4x4(_mm_insert_ps(vZero, vOne, 0x0e),\n            _mm_insert_ps(vZero, vOne, 0x1d),\n            _mm_insert_ps(vZero, vOne, 0x2b),\n            _mm_insert_ps(vZero, vOne, 0x37));\n    }\n\n    ZetaInline v_float4x4 __vectorcall add(const v_float4x4 M1, const v_float4x4& M2)\n    {\n        return v_float4x4(_mm_add_ps(M1.vRow[0], M2.vRow[0]),\n            _mm_add_ps(M1.vRow[1], M2.vRow[1]),\n            _mm_add_ps(M1.vRow[2], M2.vRow[2]),\n            _mm_add_ps(M1.vRow[3], M2.vRow[3]));\n    }\n\n    ZetaInline v_float4x4 __vectorcall sub(const v_float4x4 M1, const v_float4x4& M2)\n    {\n        return v_float4x4(_mm_sub_ps(M1.vRow[0], M2.vRow[0]),\n            _mm_sub_ps(M1.vRow[1], M2.vRow[1]),\n            _mm_sub_ps(M1.vRow[2], M2.vRow[2]),\n            _mm_sub_ps(M1.vRow[3], M2.vRow[3]));\n    }\n\n    ZetaInline v_float4x4 __vectorcall transpose(const v_float4x4 M)\n    {\n        //\n        //        0  1  2  3\n        // M =    4  5  6  7\n        //      8  9  10 11\n        //        12 13 14 15\n        //\n        __m128 vTemp0 = _mm_shuffle_ps(M.vRow[0], M.vRow[1], V_SHUFFLE_XYZW(0, 1, 0, 1));    // 0  1  4  5\n        __m128 vTemp1 = _mm_shuffle_ps(M.vRow[2], M.vRow[3], V_SHUFFLE_XYZW(0, 1, 0, 1));    // 8  9  12 13\n        __m128 vTemp2 = _mm_shuffle_ps(M.vRow[0], M.vRow[1], V_SHUFFLE_XYZW(2, 3, 2, 3));    // 2  3  6  7\n        __m128 vTemp3 = _mm_shuffle_ps(M.vRow[2], M.vRow[3], V_SHUFFLE_XYZW(2, 3, 2, 3));    // 10 11 14 15\n\n        return v_float4x4(_mm_shuffle_ps(vTemp0, vTemp1, 0x88),\n            _mm_shuffle_ps(vTemp0, vTemp1, 0xdd),\n            _mm_shuffle_ps(vTemp2, vTemp3, 0x88),\n            _mm_shuffle_ps(vTemp2, vTemp3, 0xdd));\n    }\n\n    // Transposes the 3x3 submatrix in vM, sets the last element of each row to M[2][3] and\n    // the last row itself to (0, 0, 0, 1).\n    ZetaInline v_float4x4 __vectorcall transpose3x3(const v_float4x4 vM)\n    {\n        //      0  1  2              0  3  6\n        // M =  3  4  5     -->  M = 1  4  7\n        //      6  7  8              2  5  8\n        v_float4x4 ret;\n        const __m128 vOne = _mm_set1_ps(1.0f);\n        const __m128 vZero = _mm_setzero_ps();\n\n        // 0  1  3  4\n        const __m128 vTemp0 = _mm_shuffle_ps(vM.vRow[0], vM.vRow[1], V_SHUFFLE_XYZW(0, 1, 0, 1));\n        // 2  _  5  _\n        const __m128 vTemp1 = _mm_shuffle_ps(vM.vRow[0], vM.vRow[1], V_SHUFFLE_XYZW(2, 0, 2, 0));\n\n        ret.vRow[0] = _mm_shuffle_ps(vTemp0, vM.vRow[2], V_SHUFFLE_XYZW(0, 2, 0, 3));\n        ret.vRow[1] = _mm_shuffle_ps(vTemp0, vM.vRow[2], V_SHUFFLE_XYZW(1, 3, 1, 3));\n        ret.vRow[2] = _mm_shuffle_ps(vTemp1, vM.vRow[2], V_SHUFFLE_XYZW(0, 2, 2, 3));\n        ret.vRow[3] = _mm_insert_ps(vZero, vOne, 0x30);\n\n        return ret;\n    }\n\n    // TODO: Order of arguments may imply computation of M * v, whereas it's v * M.\n    ZetaInline __m128 __vectorcall mul(const v_float4x4 M, const __m128& v)\n    {\n        // (v.x, v.x, v.x, v.x)\n        const __m128 vX = _mm_shuffle_ps(v, v, V_SHUFFLE_XYZW(0, 0, 0, 0));\n        __m128 result = _mm_mul_ps(vX, M.vRow[0]);\n\n        // (v.y, v.y, v.y, v.y)\n        const __m128 vY = _mm_shuffle_ps(v, v, V_SHUFFLE_XYZW(1, 1, 1, 1));\n        result = _mm_fmadd_ps(vY, M.vRow[1], result);\n\n        // (v.z, v.z, v.z, v.z)\n        const __m128 vZ = _mm_shuffle_ps(v, v, V_SHUFFLE_XYZW(2, 2, 2, 2));\n        result = _mm_fmadd_ps(vZ, M.vRow[2], result);\n\n        // (v.w, v.w, v.w, v.w)\n        const __m128 vW = _mm_shuffle_ps(v, v, V_SHUFFLE_XYZW(3, 3, 3, 3));\n        result = _mm_fmadd_ps(vW, M.vRow[3], result);\n\n        return result;\n    }\n\n    ZetaInline v_float4x4 __vectorcall mul(const v_float4x4 M1, const v_float4x4& M2)\n    {\n        v_float4x4 M3;\n\n        // Ref: https://github.com/microsoft/DirectXMath/blob/main/Inc/DirectXMathMatrix.inl\n        __m256 t0 = _mm256_castps128_ps256(M1.vRow[0]);\n        t0 = _mm256_insertf128_ps(t0, M1.vRow[1], 1);\n        __m256 t1 = _mm256_castps128_ps256(M1.vRow[2]);\n        t1 = _mm256_insertf128_ps(t1, M1.vRow[3], 1);\n\n        __m256 u0 = _mm256_castps128_ps256(M2.vRow[0]);\n        u0 = _mm256_insertf128_ps(u0, M2.vRow[1], 1);\n        __m256 u1 = _mm256_castps128_ps256(M2.vRow[2]);\n        u1 = _mm256_insertf128_ps(u1, M2.vRow[3], 1);\n\n        __m256 a0 = _mm256_shuffle_ps(t0, t0, _MM_SHUFFLE(0, 0, 0, 0));\n        __m256 a1 = _mm256_shuffle_ps(t1, t1, _MM_SHUFFLE(0, 0, 0, 0));\n        __m256 b0 = _mm256_permute2f128_ps(u0, u0, 0x00);\n        __m256 c0 = _mm256_mul_ps(a0, b0);\n        __m256 c1 = _mm256_mul_ps(a1, b0);\n\n        a0 = _mm256_shuffle_ps(t0, t0, _MM_SHUFFLE(1, 1, 1, 1));\n        a1 = _mm256_shuffle_ps(t1, t1, _MM_SHUFFLE(1, 1, 1, 1));\n        b0 = _mm256_permute2f128_ps(u0, u0, 0x11);\n        __m256 c2 = _mm256_fmadd_ps(a0, b0, c0);\n        __m256 c3 = _mm256_fmadd_ps(a1, b0, c1);\n\n        a0 = _mm256_shuffle_ps(t0, t0, _MM_SHUFFLE(2, 2, 2, 2));\n        a1 = _mm256_shuffle_ps(t1, t1, _MM_SHUFFLE(2, 2, 2, 2));\n        __m256 b1 = _mm256_permute2f128_ps(u1, u1, 0x00);\n        __m256 c4 = _mm256_mul_ps(a0, b1);\n        __m256 c5 = _mm256_mul_ps(a1, b1);\n\n        a0 = _mm256_shuffle_ps(t0, t0, _MM_SHUFFLE(3, 3, 3, 3));\n        a1 = _mm256_shuffle_ps(t1, t1, _MM_SHUFFLE(3, 3, 3, 3));\n        b1 = _mm256_permute2f128_ps(u1, u1, 0x11);\n        __m256 c6 = _mm256_fmadd_ps(a0, b1, c4);\n        __m256 c7 = _mm256_fmadd_ps(a1, b1, c5);\n\n        t0 = _mm256_add_ps(c2, c6);\n        t1 = _mm256_add_ps(c3, c7);\n\n        M3.vRow[0] = _mm256_castps256_ps128(t0);\n        M3.vRow[1] = _mm256_extractf128_ps(t0, 1);\n        M3.vRow[2] = _mm256_castps256_ps128(t1);\n        M3.vRow[3] = _mm256_extractf128_ps(t1, 1);\n\n        return M3;\n    }\n\n    ZetaInline __m128 __vectorcall det3x3(const v_float4x4 M)\n    {\n        // Given M = [a b c], scalar triple product a.(b x c) gives the determinant\n        const __m128 vRow1xRow2 = cross(M.vRow[1], M.vRow[2]);\n        const __m128 vRow0 = _mm_blend_ps(M.vRow[0], _mm_setzero_ps(), V_BLEND_XYZW(0, 0, 0, 1));\n        const __m128 det = _mm_dp_ps(M.vRow[0], vRow1xRow2, 0xff);\n\n        return det;\n    }\n\n    // TODO this can be done more efficiently\n    // Given a transformation matrix of the following form, returns its inverse,\n    // M = S * R * T,\n    // where S is a scaling, R is a rotation and T is a translation transformation\n    ZetaInline v_float4x4 __vectorcall inverseSRT(const v_float4x4 M)\n    {\n        const __m128 vOne = _mm_set1_ps(1.0f);\n        const __m128 vZero = _mm_setzero_ps();\n\n        //      0  1  2              0  4  8\n        // M =  4  5  6     -->  M = 1  5  9\n        //      8  9  10             2  6  10\n        const __m128 vTemp0 = _mm_shuffle_ps(M.vRow[0], M.vRow[1], \n            V_SHUFFLE_XYZW(0, 1, 0, 1));    // 0  1  4  5\n        const __m128 vTemp1 = _mm_shuffle_ps(M.vRow[0], M.vRow[1], \n            V_SHUFFLE_XYZW(2, 0, 2, 0));    // 2  _  6  _\n\n        // for 3x3 matrix M = [u, v, w] where u,v,w are columns vectors, M^(-1) is given by\n        // M = [a b c]^T\n        // where \n        //        a = (v * w) / u.(v * w)\n        //        b = (w * u) / u.(v * w)\n        //        c = (u * v) / u.(v * w)\n        // \n        // Reminder: determinant of M is equal to scalar triple product:\n        // |u v w| = [u v w] = u.(v * w) == v.(w * u) == w.(u * v)\n\n        //  M = [u v w] -> extract u, v, w\n        const __m128 u = _mm_shuffle_ps(vTemp0, M.vRow[2], V_SHUFFLE_XYZW(0, 2, 0, 0));\n        const __m128 v = _mm_shuffle_ps(vTemp0, M.vRow[2], V_SHUFFLE_XYZW(1, 3, 1, 0));\n        const __m128 w = _mm_shuffle_ps(vTemp1, M.vRow[2], V_SHUFFLE_XYZW(0, 2, 2, 0));\n\n        const __m128 vCrossW = cross(v, w);\n        const __m128 uDotvCrossW = _mm_dp_ps(u, vCrossW, 0xff);\n        const __m128 detRcp = _mm_div_ps(vOne, uDotvCrossW);\n\n        __m128 wCrossu = cross(w, u);\n        __m128 uCrossv = cross(u, v);\n        const __m128 vTinv = _mm_insert_ps(negate(M.vRow[3]), vOne, 0x30);\n\n        v_float4x4 vI;\n        vI.vRow[0] = _mm_insert_ps(_mm_mul_ps(vCrossW, detRcp), vZero, 0x30);\n        vI.vRow[1] = _mm_insert_ps(_mm_mul_ps(wCrossu, detRcp), vZero, 0x30);\n        vI.vRow[2] = _mm_insert_ps(_mm_mul_ps(uCrossv, detRcp), vZero, 0x30);\n\n        vI.vRow[3] = _mm_mul_ps(_mm_shuffle_ps(vTinv, vTinv, V_SHUFFLE_XYZW(0, 0, 0, 0)), vI.vRow[0]);\n        vI.vRow[3] = _mm_fmadd_ps(_mm_shuffle_ps(vTinv, vTinv, V_SHUFFLE_XYZW(1, 1, 1, 1)), vI.vRow[1], vI.vRow[3]);\n        vI.vRow[3] = _mm_fmadd_ps(_mm_shuffle_ps(vTinv, vTinv, V_SHUFFLE_XYZW(2, 2, 2, 2)), vI.vRow[2], vI.vRow[3]);\n        vI.vRow[3] = _mm_insert_ps(vI.vRow[3], vOne, 0x30);\n\n        return vI;\n    }\n\n    ZetaInline v_float4x4 __vectorcall scale(float sx, float sy, float sz)\n    {\n        float4a f(sx, sy, sz, 1.0f);\n\n        const __m128 vZero = _mm_setzero_ps();\n        const __m128 vS = _mm_load_ps(reinterpret_cast<float*>(&f));\n\n        return v_float4x4(_mm_blend_ps(vZero, vS, V_BLEND_XYZW(1, 0, 0, 0)),\n            _mm_blend_ps(vZero, vS, V_BLEND_XYZW(0, 1, 0, 0)),\n            _mm_blend_ps(vZero, vS, V_BLEND_XYZW(0, 0, 1, 0)),\n            _mm_blend_ps(vZero, vS, V_BLEND_XYZW(0, 0, 0, 1)));\n    }\n\n    ZetaInline v_float4x4 __vectorcall scale(float4a s)\n    {\n        s.w = 1.0f;\n        const __m128 vZero = _mm_setzero_ps();\n        const __m128 vS = _mm_load_ps(reinterpret_cast<float*>(&s));\n\n        return v_float4x4(_mm_blend_ps(vZero, vS, V_BLEND_XYZW(1, 0, 0, 0)),\n            _mm_blend_ps(vZero, vS, V_BLEND_XYZW(0, 1, 0, 0)),\n            _mm_blend_ps(vZero, vS, V_BLEND_XYZW(0, 0, 1, 0)),\n            _mm_blend_ps(vZero, vS, V_BLEND_XYZW(0, 0, 0, 1)));\n    }\n\n    ZetaInline v_float4x4 __vectorcall scale(const __m128 vS)\n    {\n        const __m128 vZero = _mm_setzero_ps();\n\n        return v_float4x4(_mm_blend_ps(vZero, vS, V_BLEND_XYZW(1, 0, 0, 0)),\n            _mm_blend_ps(vZero, vS, V_BLEND_XYZW(0, 1, 0, 0)),\n            _mm_blend_ps(vZero, vS, V_BLEND_XYZW(0, 0, 1, 0)),\n            _mm_blend_ps(vZero, _mm_set1_ps(1.0f), V_BLEND_XYZW(0, 0, 0, 1)));\n    }\n\n    ZetaInline v_float4x4 __vectorcall rotate(const __m128 vN, float angle)\n    {\n        const float c = cosf(angle);\n        const float s = sinf(angle);\n\n        const __m128 vC = _mm_set1_ps(c);\n        const __m128 v1subC = _mm_set1_ps(1.0f - c);\n        const __m128 vS = _mm_set1_ps(s);\n\n        __m128 vYZX = _mm_shuffle_ps(vN, vN, V_SHUFFLE_XYZW(1, 2, 0, 0));\n        __m128 vTemp0 = _mm_mul_ps(vN, vN);\n        vTemp0 = _mm_mul_ps(vTemp0, v1subC);    // ((1 - c)x^2, (1 - c)y^2, (1 - c)z^2)\n        __m128 vTemp1 = _mm_mul_ps(vN, vYZX);\n        vTemp1 = _mm_mul_ps(vTemp1, v1subC);    // ((1 - c)xy, (1 - c)yz, (1 - c)xz)\n        __m128 vTemp2 = _mm_mul_ps(vN, vS);     // (sx, sy, sz)\n        __m128 vTemp3 = _mm_shuffle_ps(vTemp2, vTemp2, V_SHUFFLE_XYZW(2, 0, 1, 0));\n\n        vTemp2 = _mm_sub_ps(vTemp1, vTemp3);    // ((1 - c)xy - sz, (1 - c)yz - sx, (1 - c)xz - sy)\n        vTemp3 = _mm_add_ps(vTemp1, vTemp3);    // ((1 - c)xy + sz, (1 - c)yz + sx, (1 - c)xz + sy)\n        vTemp0 = _mm_add_ps(vTemp0, vC);        // (c + (1 - c)x^2, c + (1 - c)y^2, c + (1 - c)z^2)\n        vTemp1 = _mm_add_ps(vC, v1subC);\n\n        v_float4x4 vR;\n        vR.vRow[0] = _mm_insert_ps(_mm_shuffle_ps(vTemp3, vTemp2, V_SHUFFLE_XYZW(0, 0, 2, 2)), \n            vTemp0, 0x8);\n        vR.vRow[1] = _mm_insert_ps(_mm_shuffle_ps(vTemp2, vTemp3, V_SHUFFLE_XYZW(0, 0, 1, 1)), \n            vTemp0, 0x58);\n        vR.vRow[2] = _mm_insert_ps(_mm_insert_ps(vTemp0, vTemp3, 0x8a), vTemp2, 0x58);\n        vR.vRow[3] = _mm_insert_ps(vTemp1, vTemp1, 0x7);\n\n        return vR;\n    }\n\n    ZetaInline v_float4x4 __vectorcall rotateX(float angle)\n    {\n        v_float4x4 vR;\n\n        const float c = cosf(angle);\n        const float s = sinf(angle);\n        const __m128 vZero = _mm_setzero_ps();\n        const __m128 vOne = _mm_set1_ps(1.0f);\n        const __m128 vC = _mm_broadcast_ss(&c);\n        const __m128 vS = _mm_broadcast_ss(&s);\n        const __m128 vMinusS = negate(vS);\n\n        vR.vRow[0] = _mm_insert_ps(vZero, vOne, 0x0);\n        vR.vRow[1] = _mm_insert_ps(vC, vS, 0x29);\n        vR.vRow[2] = _mm_insert_ps(vC, vMinusS, 0x19);\n        vR.vRow[3] = _mm_insert_ps(vZero, vOne, 0x30);\n\n        return vR;\n    }\n\n    ZetaInline v_float4x4 __vectorcall rotateY(float angle)\n    {\n        v_float4x4 vR;\n\n        const float c = cosf(angle);\n        const float s = sinf(angle);\n        const __m128 vZero = _mm_setzero_ps();\n        const __m128 vOne = _mm_set1_ps(1.0f);\n        const __m128 vC = _mm_broadcast_ss(&c);\n        const __m128 vS = _mm_broadcast_ss(&s);\n        const __m128 vMinusS = negate(vS);\n\n        vR.vRow[0] = _mm_insert_ps(vC, vMinusS, 0x2a);\n        vR.vRow[1] = _mm_insert_ps(vZero, vOne, 0x10);\n        vR.vRow[2] = _mm_insert_ps(vC, vS, 0xa);\n        vR.vRow[3] = _mm_insert_ps(vZero, vOne, 0x30);\n\n        return vR;\n    }\n\n    ZetaInline v_float4x4 __vectorcall rotateZ(float angle)\n    {\n        v_float4x4 vR;\n\n        const float c = cosf(angle);\n        const float s = sinf(angle);\n        const __m128 vZero = _mm_setzero_ps();\n        const __m128 vOne = _mm_set1_ps(1.0f);\n        const __m128 vC = _mm_broadcast_ss(&c);\n        const __m128 vS = _mm_broadcast_ss(&s);\n        const __m128 vMinusS = negate(vS);\n\n        vR.vRow[0] = _mm_insert_ps(vC, vS, 0x1c);\n        vR.vRow[1] = _mm_insert_ps(vC, vMinusS, 0xc);\n        vR.vRow[2] = _mm_insert_ps(vZero, vOne, 0x20);\n        vR.vRow[3] = _mm_insert_ps(vZero, vOne, 0x30);\n\n        return vR;\n    }\n\n    // Returns a rotation matrix from the given unit quaternion\n    ZetaInline v_float4x4 __vectorcall rotationMatFromQuat(const __m128 vQ)\n    {\n        // (q1^2, q2^2, q3^2, q4^2)\n        const __m128 vQ2 = _mm_mul_ps(vQ, vQ);\n        const __m128 vMin2 = _mm_set1_ps(-2.0f);\n        const __m128 v2 = _mm_set1_ps(2.0f);\n        const __m128 vOne = _mm_set1_ps(1.0f);\n\n        // (q3^2, q3^2, q2^2, _)\n        __m128 vTemp0 = _mm_shuffle_ps(vQ2, vQ2, V_SHUFFLE_XYZW(2, 2, 1, 0));\n\n        // (q1^2 + q3^2, q2^2 + q3^2, q1^2 + q2^2, _)\n        __m128 vTemp1 = _mm_add_ps(_mm_shuffle_ps(vQ2, vQ2, V_SHUFFLE_XYZW(0, 1, 0, 0)), vTemp0);\n\n        // (1 - 2 * q1^2 - 2 * q3^2, 1 - 2 * q2^2 - 2 * q3^2, 1 - 2 *q1^2 - 2 * q2^2, _)\n        const __m128 vDiag = _mm_fmadd_ps(vTemp1, vMin2, vOne);\n\n        // (2q1q4, 2q2q4, 2q1q3, 2q3q4)\n        __m128 vTemp3 = _mm_mul_ps(vQ, _mm_shuffle_ps(vQ, vQ, V_SHUFFLE_XYZW(3, 3, 0, 2)));\n        vTemp3 = _mm_mul_ps(vTemp3, v2);\n        // (2q1q2, 2q2q3, 2q3q4, 2q1q3)\n        __m128 vTemp2 = _mm_mul_ps(vQ, _mm_shuffle_ps(vQ, vQ, V_SHUFFLE_XYZW(1, 2, 3, 0)));\n        vTemp2 = _mm_mul_ps(vTemp2, v2);\n        vTemp2 = _mm_insert_ps(vTemp2, vTemp3, 0xb0);\n\n        // (2q1q2, 2q1q3, 2q2q3, 2q1q2)\n        __m128 vTemp4 = _mm_shuffle_ps(vTemp2, vTemp2, V_SHUFFLE_XYZW(0, 3, 1, 0));\n        // (2q3q4, 2q2q4, 2q1q4, 2q3q4)\n        __m128 vTemp5 = _mm_shuffle_ps(vTemp3, vTemp3, V_SHUFFLE_XYZW(3, 1, 0, 3));\n\n        // (2q1q2 + 2q3q4, 2q1q3 - 2q2q4, 2q2q3 + 2q1q4, 2q1q2 - 2q3q4)\n        vTemp0 = _mm_addsub_ps(vTemp4, negate(vTemp5));\n\n        // (2q1q3, 2q2q3, _, _)\n        __m128 vTemp6 = _mm_shuffle_ps(vTemp2, vTemp2, V_SHUFFLE_XYZW(3, 1, 0, 0));\n        // (2q2q4, 2q1q4, _, _)\n        __m128 vTemp7 = _mm_shuffle_ps(vTemp3, vTemp3, V_SHUFFLE_XYZW(1, 0, 0, 0));\n\n        // (2q1q3 + 2q2q4, 2q2q3 - 2q1q4, _, _)\n        vTemp1 = _mm_addsub_ps(vTemp6, negate(vTemp7));\n\n        v_float4x4 vR;\n        vR.vRow[0] = _mm_insert_ps(_mm_shuffle_ps(vTemp0, vTemp0, V_SHUFFLE_XYZW(0, 0, 1, 0)),\n            vDiag, 0x48);\n        vR.vRow[1] = _mm_insert_ps(_mm_shuffle_ps(vTemp0, vTemp0, V_SHUFFLE_XYZW(3, 0, 2, 0)),\n            vDiag, 0x18);\n        vR.vRow[2] = _mm_insert_ps(vTemp1, vDiag, 0xa8);\n        vR.vRow[3] = _mm_insert_ps(vOne, vOne, 0xf7);\n\n        return vR;\n    }\n\n    // Ref: https://math.stackexchange.com/questions/893984/conversion-of-rotation-matrix-to-quaternion\n    // \"Converting a Rotation Matrix to a Quaternion\", Mike Day, Insomniac Games.\n    ZetaInline float4 __vectorcall quaternionFromRotationMat1(const v_float4x4 vM)\n    {\n        float4a row0 = store(vM.vRow[0]);\n        float4a row1 = store(vM.vRow[1]);\n        float4a row2 = store(vM.vRow[2]);\n\n        float t[4];\n        float4 q[4];\n\n        t[0] = 1 + row0.x - row1.y - row2.z;\n        t[1] = 1 - row0.x + row1.y - row2.z;\n        t[2] = 1 - row0.x - row1.y + row2.z;\n        t[3] = 1 + row0.x + row1.y + row2.z;\n\n        q[0] = float4(t[0], row0.y + row1.x, row2.x + row0.z, row1.z - row2.y);\n        q[1] = float4(row0.y + row1.x, t[1], row1.z + row2.y, row2.x - row0.z);\n        q[2] = float4(row2.x + row0.z, row1.z + row2.y, t[2], row0.y - row1.x);\n        q[3] = float4(row1.z - row2.y, row2.x - row0.z, row0.y - row1.x, t[3]);\n\n        int i = (row2.z >= 0) * (2 + (row0.x >= -row1.y)) + (row2.z < 0) * (row1.y >= row0.x);\n        float t_i = t[i];\n        float4 q_i = q[i];\n        q_i *= 0.5f / sqrtf(t_i);\n        // Helps with accumulation of floating-point errors\n        q_i.normalize();\n\n        return q_i;\n    }\n\n    ZetaInline v_float4x4 __vectorcall translate(float x, float y, float z)\n    {\n        const __m128 vZero = _mm_setzero_ps();\n        const __m128 vOne = _mm_set_ps1(1.0f);\n        const __m128 vT = _mm_setr_ps(x, y, z, 0.0f);\n\n        return v_float4x4(_mm_blend_ps(vZero, vOne, V_BLEND_XYZW(1, 0, 0, 0)),\n            _mm_blend_ps(vZero, vOne, V_BLEND_XYZW(0, 1, 0, 0)),\n            _mm_blend_ps(vZero, vOne, V_BLEND_XYZW(0, 0, 1, 0)),\n            _mm_blend_ps(vT, vOne, V_BLEND_XYZW(0, 0, 0, 1)));\n    }\n\n    ZetaInline v_float4x4 __vectorcall translate(float4a t)\n    {\n        const __m128 vZero = _mm_setzero_ps();\n        const __m128 vOne = _mm_set_ps1(1.0f);\n        const __m128 vT = _mm_load_ps(reinterpret_cast<float*>(&t));\n\n        return v_float4x4(_mm_blend_ps(vZero, vOne, V_BLEND_XYZW(1, 0, 0, 0)),\n            _mm_blend_ps(vZero, vOne, V_BLEND_XYZW(0, 1, 0, 0)),\n            _mm_blend_ps(vZero, vOne, V_BLEND_XYZW(0, 0, 1, 0)),\n            _mm_blend_ps(vT, vOne, V_BLEND_XYZW(0, 0, 0, 1)));\n    }\n\n    ZetaInline v_float4x4 __vectorcall affineTransformation(const v_float4x4 vR, float3& s, float3& t)\n    {\n        v_float4x4 vSRT;\n\n        // Since scale matrix is diagonal, matrix multiplication has a simple form\n        const __m128 vS = loadFloat3(s);    // vS[3] = 0\n        vSRT.vRow[0] = _mm_mul_ps(_mm_shuffle_ps(vS, vS, V_SHUFFLE_XYZW(0, 0, 0, 3)), vR.vRow[0]);\n        vSRT.vRow[1] = _mm_mul_ps(_mm_shuffle_ps(vS, vS, V_SHUFFLE_XYZW(1, 1, 1, 3)), vR.vRow[1]);\n        vSRT.vRow[2] = _mm_mul_ps(_mm_shuffle_ps(vS, vS, V_SHUFFLE_XYZW(2, 2, 2, 3)), vR.vRow[2]);\n\n        vSRT.vRow[3] = loadFloat3(t);\n\n        // SRT_{3,3} = 1.0\n        const __m128 vOne = _mm_set_ps1(1.0f);\n        vSRT.vRow[3] = _mm_blend_ps(vSRT.vRow[3], vOne, V_BLEND_XYZW(0, 0, 0, 1));\n\n        return vSRT;\n    }\n\n    ZetaInline v_float4x4 __vectorcall affineTransformation(float3& s, float4& q, float3& t)\n    {\n        v_float4x4 vR = rotationMatFromQuat(loadFloat4(q));\n        return affineTransformation(vR, s, t);\n    }\n\n    ZetaInline v_float4x4 __vectorcall affineTransformation(const __m128 vS, const __m128 vQ, const __m128 vT)\n    {\n        v_float4x4 vSRT;\n        v_float4x4 vR = rotationMatFromQuat(vQ);\n\n        // Since scale matrix is diagonal, matrix multiplication has a simple form\n        vSRT.vRow[0] = _mm_mul_ps(_mm_shuffle_ps(vS, vS, V_SHUFFLE_XYZW(0, 0, 0, 0)), vR.vRow[0]);    // vR.vRow[0].w = 0\n        vSRT.vRow[1] = _mm_mul_ps(_mm_shuffle_ps(vS, vS, V_SHUFFLE_XYZW(1, 1, 1, 0)), vR.vRow[1]);    // vR.vRow[1].w = 0\n        vSRT.vRow[2] = _mm_mul_ps(_mm_shuffle_ps(vS, vS, V_SHUFFLE_XYZW(2, 2, 2, 0)), vR.vRow[2]);    // vR.vRow[2].w = 0\n\n        // M_{3,3} = 1.0\n        const __m128 vOne = _mm_set_ps1(1.0f);\n        vSRT.vRow[3] = _mm_blend_ps(vT, vOne, V_BLEND_XYZW(0, 0, 0, 1));\n\n        return vSRT;\n    }\n\n    // Note: doesn't support negative scaling\n    ZetaInline void __vectorcall decomposeTRS(const v_float4x4 vM, float3& s, float4& r, float3& t)\n    {\n        // Given the transformation matrix M = TRS, M is easily decomposed into T and RS. That just leaves the\n        // RS part.\n        __m128 vT = _mm_insert_ps(vM.vRow[0], vM.vRow[0], 0xce);    // (m03, 0, 0, 0)\n        vT = _mm_insert_ps(vT, vM.vRow[1], 0xd0);                   // (m03, m13, 0, 0)\n        vT = _mm_insert_ps(vT, vM.vRow[2], 0xe0);                   // (m03, m13, m23, 0)\n        t = storeFloat3(vT);\n\n        // Columns of linear transformation matrices are the transformations of (orthogonal) standard basis \n        // vectors; for RS, columns of R are the rotated standard basis vectors and diagonal entries of S \n        // their corresponding length.\n        // \n        // Given the Singular value decompoistion of A = U E V^T, columns of U are the orthonormal transformation\n        // of standard basis vectors (i.e. R), diagonal elements of E their lengths (scale factors) and rows \n        // of V^T are the standard basis vectors (whose transforms are the columns of U -- AV = UE). While singular \n        // values are unique, U & V aren't, but in this case knowing the singular values is enough.\n        // \n        // To compute the singular values, compute the eigenvalues of M^T M, whose square roots are the singular \n        // values and therefore the scale factors. Now that we know S, R can solved for as follows:\n        //\n        //        RS = R * S\n        //        RS * S^-1 = R\n        //\n        // where S^-1 is a diagonal matrix with diagonal entries (1/s_x, 1/s_y, 1/s_z).\n\n        // M^T M = (RS)^T RS = S^T R^T R S = S^T S = S^2\n        const __m128 vZero = _mm_setzero_ps();\n        const __m128 vOne = _mm_set1_ps(1.0f);\n        v_float4x4 vM3x3 = vM;\n        vM3x3.vRow[3] = _mm_insert_ps(vZero, vOne, 0x30);    // M[3] = (0, 0, 0, 1)\n\n        v_float4x4 vM3x3T = transpose(vM3x3);\n        v_float4x4 vMTxM = mul(vM3x3T, vM3x3);\n\n        // Eigenvalues of diagonal matrices are the diagonal entries\n        __m128 vS = _mm_blend_ps(vMTxM.vRow[0], vMTxM.vRow[1], V_BLEND_XYZW(0, 1, 0, 0)); // (s_x^2, s_y^2, _, 0)\n        vS = _mm_blend_ps(vS, vMTxM.vRow[2], V_BLEND_XYZW(0, 0, 1, 0));                   // (s_x^2, s_y^2, s_z^2, 0)\n        vS = _mm_blend_ps(vS, vOne, V_BLEND_XYZW(0, 0, 0, 1));                            // (s_x^2, s_y^2, s_z^2, 1)\n\n        // Singular values are the square roots of eigenvalues\n        vS = _mm_sqrt_ps(vS);\n        s = storeFloat3(vS);\n\n        // Solve for R\n        __m128 vInvSDiag = _mm_div_ps(vOne, vS);\n        v_float4x4 vSinv = scale(vInvSDiag);\n        // R = RS * S^-1\n        v_float4x4 vR = mul(vM3x3, vSinv);\n\n        // Other routines expect \"row\" matrices\n        vR = transpose3x3(vR);\n        r = quaternionFromRotationMat1(vR);\n    }\n\n    // Note: doesn't support negative scaling\n    ZetaInline v_float4x4 __vectorcall decomposeSRT(const v_float4x4 vM, float4a& s, float4a& t)\n    {\n        // Refer to notes in decomposeTRS for explanation\n\n        __m128 vT = vM.vRow[3];\n        const __m128 vZero = _mm_setzero_ps();\n        vT = _mm_blend_ps(vT, vZero, V_BLEND_XYZW(0, 0, 0, 1));\n        t = store(vT);\n\n        v_float4x4 vM3x3 = vM;\n        const __m128 vOne = _mm_set1_ps(1.0f);\n        vM3x3.vRow[3] = _mm_insert_ps(vZero, vOne, 0x30);    // M[3] = (0, 0, 0, 1)\n\n        // For \"row\" matrices, square roots of eigenvalues of MM^T are the singular values\n        // M M^T = (SR)(SR)^T = S R R^T S^T = S S^T = S^2\n        const v_float4x4 vM3x3T = transpose3x3(vM3x3);\n        const v_float4x4 vMxMT = mul(vM3x3, vM3x3T);\n\n        // Eigenvalues of diagonal matrices are the diagonal entries\n        __m128 vS = _mm_blend_ps(vMxMT.vRow[0], vMxMT.vRow[1], V_BLEND_XYZW(0, 1, 0, 0)); // (s_x^2, s_y^2, _, 0)\n        vS = _mm_blend_ps(vS, vMxMT.vRow[2], V_BLEND_XYZW(0, 0, 1, 0));                   // (s_x^2, s_y^2, s_z^2, 0)\n        vS = _mm_blend_ps(vS, vOne, V_BLEND_XYZW(0, 0, 0, 1));                            // (s_x^2, s_y^2, s_z^2, 1)\n\n        // Singular values are the square roots of eigenvalues\n        vS = _mm_sqrt_ps(vS);\n        s = store(vS);\n\n        // R = S^-1 * SR\n        const __m128 vInvS = _mm_div_ps(vOne, vS);\n#if 0\n        const v_float4x4 vSinv = scale(vInvS);\n        const v_float4x4 vR = mul(vSinv, vM3x3);\n#else\n        // Since S^-1 is diagonal, matrix multiplication has a simpler form\n        v_float4x4 vR;\n        vR.vRow[0] = _mm_mul_ps(_mm_shuffle_ps(vInvS, vInvS, V_SHUFFLE_XYZW(0, 0, 0, 3)), vM3x3.vRow[0]);\n        vR.vRow[1] = _mm_mul_ps(_mm_shuffle_ps(vInvS, vInvS, V_SHUFFLE_XYZW(1, 1, 1, 3)), vM3x3.vRow[1]);\n        vR.vRow[2] = _mm_mul_ps(_mm_shuffle_ps(vInvS, vInvS, V_SHUFFLE_XYZW(2, 2, 2, 3)), vM3x3.vRow[2]);\n        vR.vRow[3] = _mm_insert_ps(vZero, vOne, 0x30);    // M[3] = (0, 0, 0, 1)\n#endif\n\n        return vR;\n    }\n\n    ZetaInline void __vectorcall decomposeSRT(const v_float4x4 vM, float4a& s, float4a& r, float4a& t)\n    {\n        const v_float4x4 vR = decomposeSRT(vM, s, t);\n        r = quaternionFromRotationMat1(vR);\n    }\n\n    ZetaInline v_float4x4 __vectorcall inverseAndDecomposeSRT(const v_float4x4 vM, float4a& s,\n        float4a& r, float4a& t)\n    {\n        __m128 vT = vM.vRow[3];\n        const __m128 vZero = _mm_setzero_ps();\n        vT = _mm_blend_ps(vT, vZero, V_BLEND_XYZW(0, 0, 0, 1));\n        t = store(vT);\n\n        v_float4x4 vM3x3 = vM;\n        const __m128 vOne = _mm_set1_ps(1.0f);\n        vM3x3.vRow[3] = _mm_insert_ps(vZero, vOne, 0x30);    // M[3] = (0, 0, 0, 1)\n\n        // For \"row\" matrices, square roots of eigenvalues of MM^T are the singular values\n        // M M^T = (SR)(SR)^T = S R R^T S^T = S S^T = S^2\n        const v_float4x4 vM3x3T = transpose3x3(vM3x3);\n        const v_float4x4 vMxMT = mul(vM3x3, vM3x3T);\n\n        // Eigenvalues of diagonal matrices are the diagonal entries\n        __m128 vS = _mm_blend_ps(vMxMT.vRow[0], vMxMT.vRow[1], V_BLEND_XYZW(0, 1, 0, 0)); // (s_x^2, s_y^2, _, 0)\n        vS = _mm_blend_ps(vS, vMxMT.vRow[2], V_BLEND_XYZW(0, 0, 1, 0));                   // (s_x^2, s_y^2, s_z^2, 0)\n        vS = _mm_blend_ps(vS, vOne, V_BLEND_XYZW(0, 0, 0, 1));                            // (s_x^2, s_y^2, s_z^2, 1)\n\n        // Singular values are the square roots of eigenvalues\n        vS = _mm_sqrt_ps(vS);\n        s = store(vS);\n\n        // R = S^-1 * SR\n        const __m128 vInvSDiag = _mm_div_ps(vOne, vS);\n        const v_float4x4 vSinv = scale(vInvSDiag);\n        const v_float4x4 vR = mul(vSinv, vM3x3);\n        r = quaternionFromRotationMat1(vR);\n\n        v_float4x4 vInv = mul(transpose(vR), vSinv);\n        vInv.vRow[3] = mul(vInv, negate(vT));\n        // Set entry (3, 3) to 1\n        vInv.vRow[3] = _mm_insert_ps(vInv.vRow[3], vOne, 0x30);\n\n        return vInv;\n    }\n\n    ZetaInline v_float4x4 __vectorcall lookAtLH(float4a cameraPos, float4a focus, float4a up)\n    {\n        v_float4x4 vM = identity();\n\n        // Builds a coordinate system uvw, where w is aligned with the camera direction\n        __m128 vCamPos = _mm_load_ps(reinterpret_cast<float*>(&cameraPos));\n        __m128 vFocus = _mm_load_ps(reinterpret_cast<float*>(&focus));\n        __m128 vUp = _mm_load_ps(reinterpret_cast<float*>(&up));\n\n        __m128 vW = _mm_sub_ps(vFocus, vCamPos);\n        vW = normalize(vW);\n        __m128 vU = cross(vUp, vW);\n        vU = normalize(vU);\n        __m128 vV = cross(vW, vU);    // no need to normalize as ||vV|| = 1\n\n        vM.vRow[0] = vU;\n        vM.vRow[1] = vV;\n        vM.vRow[2] = vW;\n        vM = transpose(vM);\n\n        __m128 vTemp = _mm_mul_ps(_mm_shuffle_ps(vCamPos, vCamPos, V_SHUFFLE_XYZW(0, 0, 0, 0)), vM.vRow[0]);\n        vTemp = _mm_fmadd_ps(_mm_shuffle_ps(vCamPos, vCamPos, V_SHUFFLE_XYZW(1, 1, 1, 0)), vM.vRow[1], vTemp);\n        vTemp = _mm_fmadd_ps(_mm_shuffle_ps(vCamPos, vCamPos, V_SHUFFLE_XYZW(2, 2, 2, 0)), vM.vRow[2], vTemp);\n\n        vM.vRow[3] = _mm_insert_ps(negate(vTemp), vM.vRow[3], 0xf0);\n\n        return vM;\n    }\n\n    ZetaInline v_float4x4 __vectorcall lookToLH(float4a cameraPos, float4a viewDir, float4a up)\n    {\n        v_float4x4 vM = identity();\n\n        // Builds a coordinate system uvw, where w is aligned with the camera direction\n        __m128 vCamPos = _mm_load_ps(reinterpret_cast<float*>(&cameraPos));\n        __m128 vUp = _mm_load_ps(reinterpret_cast<float*>(&up));\n        __m128 vW = _mm_load_ps(reinterpret_cast<float*>(&viewDir));\n\n        vW = normalize(vW);\n        __m128 vU = cross(vUp, vW);\n        vU = normalize(vU);\n        __m128 vV = cross(vW, vU);    // no need to normalize as ||vV|| = 1\n\n        vM.vRow[0] = vU;\n        vM.vRow[1] = vV;\n        vM.vRow[2] = vW;\n        vM = transpose(vM);\n\n        __m128 vTemp = _mm_mul_ps(_mm_shuffle_ps(vCamPos, vCamPos, V_SHUFFLE_XYZW(0, 0, 0, 0)), vM.vRow[0]);\n        vTemp = _mm_fmadd_ps(_mm_shuffle_ps(vCamPos, vCamPos, V_SHUFFLE_XYZW(1, 1, 1, 0)), vM.vRow[1], vTemp);\n        vTemp = _mm_fmadd_ps(_mm_shuffle_ps(vCamPos, vCamPos, V_SHUFFLE_XYZW(2, 2, 2, 0)), vM.vRow[2], vTemp);\n\n        vM.vRow[3] = _mm_insert_ps(negate(vTemp), vM.vRow[3], 0xf0);\n\n        return vM;\n    }\n\n    ZetaInline v_float4x4 __vectorcall perspective(float aspectRatio, float vFOV, float nearZ, float farZ)\n    {\n        v_float4x4 P;\n\n        float t = 1.0f / tanf(0.5f * vFOV);\n        float fSubn = farZ / (farZ - nearZ);\n\n        __m128 vTemp = _mm_setr_ps(t / aspectRatio, t, fSubn, -nearZ * fSubn);\n        const __m128 vOne = _mm_set1_ps(1.0f);\n        P.vRow[0] = _mm_insert_ps(vTemp, vTemp, 0xe);\n        P.vRow[1] = _mm_insert_ps(vTemp, vTemp, 0xd);\n        P.vRow[2] = _mm_insert_ps(vTemp, vOne, 0x33);\n        P.vRow[3] = _mm_insert_ps(vTemp, vTemp, 0xeb);\n\n        return P;\n    }\n\n    ZetaInline v_float4x4 __vectorcall perspectiveReverseZ(float aspectRatio, float vFOV, float nearZ)\n    {\n        v_float4x4 P;\n\n        float t = 1.0f / tanf(0.5f * vFOV);\n\n        __m128 vTemp = _mm_setr_ps(t / aspectRatio, t, 0.0f, nearZ);\n        const __m128 vOne = _mm_set1_ps(1.0f);\n        P.vRow[0] = _mm_insert_ps(vTemp, vTemp, 0xe);\n        P.vRow[1] = _mm_insert_ps(vTemp, vTemp, 0xd);\n        P.vRow[2] = _mm_insert_ps(vTemp, vOne, 0x33);\n        P.vRow[3] = _mm_insert_ps(vTemp, vTemp, 0xeb);\n\n        return P;\n    }\n\n    ZetaInline v_float4x4 __vectorcall perspectiveReverseZ(float aspectRatio, float vFOV, float nearZ,\n        float farZ)\n    {\n        v_float4x4 P;\n\n        float t = 1.0f / tanf(0.5f * vFOV);\n        float q = nearZ / (farZ - nearZ);\n\n        __m128 vTemp = _mm_setr_ps(t / aspectRatio, t, -nearZ / (farZ - nearZ), q * farZ);\n        const __m128 vOne = _mm_set1_ps(1.0f);\n        P.vRow[0] = _mm_insert_ps(vTemp, vTemp, 0xe);\n        P.vRow[1] = _mm_insert_ps(vTemp, vTemp, 0xd);\n        P.vRow[2] = _mm_insert_ps(vTemp, vOne, 0x33);\n        P.vRow[3] = _mm_insert_ps(vTemp, vTemp, 0xeb);\n\n        return P;\n    }\n\n    ZetaInline bool __vectorcall equal(v_float4x4 vM1, v_float4x4 vM2)\n    {\n        const __m256 vEps = _mm256_set1_ps(FLT_EPSILON);\n\n        const __m256 vTemp1 = _mm256_insertf128_ps(_mm256_castps128_ps256(vM1.vRow[0]), vM1.vRow[1], 0x1);\n        const __m256 vTemp2 = _mm256_insertf128_ps(_mm256_castps128_ps256(vM1.vRow[2]), vM1.vRow[3], 0x1);\n        const __m256 vTemp3 = _mm256_insertf128_ps(_mm256_castps128_ps256(vM2.vRow[0]), vM2.vRow[1], 0x1);\n        const __m256 vTemp4 = _mm256_insertf128_ps(_mm256_castps128_ps256(vM2.vRow[2]), vM2.vRow[3], 0x1);\n\n        const __m256 vRes1 = _mm256_cmp_ps(vEps, abs(_mm256_sub_ps(vTemp1, vTemp3)), _CMP_GE_OQ);\n        const __m256 vRes2 = _mm256_cmp_ps(vEps, abs(_mm256_sub_ps(vTemp2, vTemp4)), _CMP_GE_OQ);\n\n        int r1 = _mm256_movemask_ps(vRes1);\n        int r2 = _mm256_movemask_ps(vRes2);\n\n        return (r1 & r2) == 0xff;\n    }\n\n    ZetaInline v_float4x4 __vectorcall load4x4(float4x4a M)\n    {\n        v_float4x4 vM;\n\n        vM.vRow[0] = _mm_load_ps(reinterpret_cast<float*>(&M.m[0]));\n        vM.vRow[1] = _mm_load_ps(reinterpret_cast<float*>(&M.m[1]));\n        vM.vRow[2] = _mm_load_ps(reinterpret_cast<float*>(&M.m[2]));\n        vM.vRow[3] = _mm_load_ps(reinterpret_cast<float*>(&M.m[3]));\n\n        return vM;\n    }\n\n    ZetaInline v_float4x4 __vectorcall load3x3(float3x3 M)\n    {\n        v_float4x4 vM;\n        float4x4a temp(M);\n\n        vM.vRow[0] = _mm_load_ps(reinterpret_cast<float*>(&temp.m[0]));\n        vM.vRow[1] = _mm_load_ps(reinterpret_cast<float*>(&temp.m[1]));\n        vM.vRow[2] = _mm_load_ps(reinterpret_cast<float*>(&temp.m[2]));\n        vM.vRow[3] = _mm_load_ps(reinterpret_cast<float*>(&temp.m[3]));\n\n        return vM;\n    }\n\n    ZetaInline v_float4x4 __vectorcall load4x3(float4x3 M)\n    {\n        v_float4x4 vM;\n        float4x4a temp(M);\n\n        vM.vRow[0] = _mm_load_ps(reinterpret_cast<float*>(&temp.m[0]));\n        vM.vRow[1] = _mm_load_ps(reinterpret_cast<float*>(&temp.m[1]));\n        vM.vRow[2] = _mm_load_ps(reinterpret_cast<float*>(&temp.m[2]));\n        vM.vRow[3] = _mm_load_ps(reinterpret_cast<float*>(&temp.m[3]));\n\n        return vM;\n    }\n\n    ZetaInline float4x4a __vectorcall store(v_float4x4 M)\n    {\n        float4x4a m;\n\n        _mm_store_ps(reinterpret_cast<float*>(&m.m[0]), M.vRow[0]);\n        _mm_store_ps(reinterpret_cast<float*>(&m.m[1]), M.vRow[1]);\n        _mm_store_ps(reinterpret_cast<float*>(&m.m[2]), M.vRow[2]);\n        _mm_store_ps(reinterpret_cast<float*>(&m.m[3]), M.vRow[3]);\n\n        return m;\n    }\n}"
  },
  {
    "path": "Source/ZetaCore/Math/OctahedralVector.h",
    "content": "#pragma once\n\n#include \"VectorFuncs.h\"\n\nnamespace ZetaRay::Math\n{\n    // 3D unit vector encoded using octahedral encoding with two 16-bit UNORMs\n    struct oct32\n    {\n        constexpr oct32() = default;\n        explicit oct32(float3 u)\n        {\n            __m128 vU = loadFloat3(u);\n            vU = encode_octahedral(vU);\n            v = unorm2::FromNormalized(vU);\n        }\n\n        oct32(float x, float y, float z)\n        {\n            float4a f(x, y, z, 0);\n            __m128 vU = load(f);\n            vU = encode_octahedral(vU);\n            v = unorm2::FromNormalized(vU);\n        }\n\n        float3 decode()\n        {\n            __m128 vV = loadUNorm2(v);\n            __m128 vTwo = _mm_set1_ps(2.0f);\n            __m128 vMinOne = _mm_set1_ps(-1.0f);\n            // [0, 1] -> [-1, 1] \n            vV = _mm_fmadd_ps(vV, vTwo, vMinOne);\n            vV = decode_octahedral(vV);\n\n            return storeFloat3(vV);\n        }\n\n        unorm2 v;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Math/Quaternion.h",
    "content": "#pragma once\n\n#include \"VectorFuncs.h\"\n#include \"Matrix.h\"\n\nnamespace ZetaRay::Math\n{\n    // Returns a roations quaternion that can be used to rotate about axis n by angle theta. n\n    // is assumed to be normalized.\n    ZetaInline __m128 __vectorcall rotationQuaternion(float3 n, float theta)\n    {\n        const float s = sinf(0.5f * theta);\n        const float c = cosf(0.5f * theta);\n\n        // Reminder: sign of cos(theta) won't be taken into account by the following:\n        // const float c = sqrtf(1.0f - s * s);\n\n        float4a axis(n, 1.0f);\n        float4a sc(s, s, s, c);\n\n        __m128 vAxis = _mm_load_ps(reinterpret_cast<float*>(&axis));\n        __m128 vSC = _mm_load_ps(reinterpret_cast<float*>(&sc));\n        __m128 vQ = _mm_mul_ps(vAxis, vSC);\n\n        return vQ;\n    }\n\n    ZetaInline __m128 __vectorcall quaternionToAxisAngle(__m128 vQuat)\n    {\n        float4a quat = store(vQuat);\n        float theta = 2.0f * acosf(quat.w);\n\n        __m128 vAxisAngle = normalize(_mm_insert_ps(vQuat, vQuat, 0x8));\n        vAxisAngle = _mm_insert_ps(vAxisAngle, _mm_set1_ps(theta), 0x30);\n\n        return vAxisAngle;\n    }\n\n    ZetaInline void __vectorcall quaternionToAxisAngle(__m128 vQuat, float3& axis, float& angle)\n    {\n        float4a quat = store(vQuat);\n        angle = 2.0f * acosf(quat.w);\n        axis = float3(quat.x, quat.y, quat.z);\n        axis.normalize();\n    }\n\n    ZetaInline void __vectorcall quaternionToAxisAngle(const float4a& quat, float3& axis, float& angle)\n    {\n        angle = 2.0f * acosf(quat.w);\n        axis = float3(quat.x, quat.y, quat.z);\n        axis.normalize();\n    }\n\n    // Multiplies two quaternions\n    ZetaInline __m128 __vectorcall mulQuat(const __m128 vP, const __m128 vQ)\n    {\n        // p = (p1, p2, p3, p4)\n        // q = (q1, q2, q3, q4)\n        // \n        //                       [ p4  p3 -p2 -p1]\n        //    pq = [q1 q2 q3 q4] [-p3  p4  p1 -p2]\n        //                       [p2  -p1  p4 -p3]\n        //                       [p1   p2  p3  p4]\n\n        const __m128 vMinP = negate(vP);\n\n        // (p1, -p1, p2, -p2)\n        const __m128 vTemp0 = _mm_unpacklo_ps(vP, vMinP);\n        // (-p3, p3, -p4, p4)\n        const __m128 vTemp1 = _mm_unpackhi_ps(vMinP, vP);\n\n        __m128 result = _mm_mul_ps(_mm_shuffle_ps(vQ, vQ, V_SHUFFLE_XYZW(3, 3, 3, 3)), vP);\n        const __m128 vRow0 = _mm_shuffle_ps(vP, vMinP, V_SHUFFLE_XYZW(3, 2, 1, 0));\n        result = _mm_fmadd_ps(_mm_shuffle_ps(vQ, vQ, V_SHUFFLE_XYZW(0, 0, 0, 0)), vRow0, result);\n        const __m128 vRow1 = _mm_shuffle_ps(vTemp1, vTemp0, V_SHUFFLE_XYZW(0, 3, 0, 2));\n        result = _mm_fmadd_ps(_mm_shuffle_ps(vQ, vQ, V_SHUFFLE_XYZW(1, 1, 1, 1)), vRow1, result);\n        const __m128 vRow2 = _mm_shuffle_ps(vTemp0, vTemp1, V_SHUFFLE_XYZW(2, 1, 3, 0));\n        result = _mm_fmadd_ps(_mm_shuffle_ps(vQ, vQ, V_SHUFFLE_XYZW(2, 2, 2, 2)), vRow2, result);\n\n        return result;\n    }\n\n    ZetaInline __m128 __vectorcall slerp(const __m128 vQ1, const __m128 vQ2, float t)\n    {\n        // Rotation by unit quaternions q or -q gives the same result, with the difference\n        // that q rotates about axis n by angle theta, whereas -q rotates about angle -n by\n        // angle 2 * pi - theta. Dot product of two quaternions can be used to check if they are\n        // on the same hemisphere. If on opposite hemispheres, negate one of them.\n        const __m128 vOne = _mm_set1_ps(1.0f);\n        const __m128 vT = _mm_set1_ps(t);\n        __m128 vCosTheta = _mm_dp_ps(vQ1, vQ2, 0xff);\n        const __m128 vOnSameHemisphere = _mm_cmpgt_ps(vCosTheta, _mm_setzero_ps());\n        vCosTheta = _mm_blendv_ps(negate(vCosTheta), vCosTheta, vOnSameHemisphere);\n\n        __m128 vSinTheta = _mm_sub_ps(vOne, _mm_mul_ps(vCosTheta, vCosTheta));\n        vSinTheta = _mm_sqrt_ps(vSinTheta);\n\n        __m128 vTheta = acos(vCosTheta);\n        __m128 vSinArgs = _mm_insert_ps(_mm_sub_ps(vOne, vT), vT, 0x50);\n        vSinArgs = _mm_mul_ps(vSinArgs, vTheta);\n        __m128 vSin = sin(vSinArgs);\n\n        __m128 vResSlerp = _mm_mul_ps(vQ1, _mm_shuffle_ps(vSin, vSin, V_SHUFFLE_XYZW(0, 0, 0, 0)));\n        __m128 vS2 = _mm_shuffle_ps(vSin, vSin, V_SHUFFLE_XYZW(1, 1, 1, 1));\n\n        vS2 = _mm_blendv_ps(negate(vS2), vS2, vOnSameHemisphere);\n        vResSlerp = _mm_fmadd_ps(vQ2, vS2, vResSlerp);\n        vResSlerp = _mm_div_ps(vResSlerp, vSinTheta);\n\n        // If theta is near zero, use linear interpolation followed by normalization,\n        // otherwise, there might be a divide-by-zero.\n        const __m128 vOneMinEps = _mm_set1_ps(1.0f - FLT_EPSILON);\n        const __m128 vIsThetaNearZero = _mm_cmpgt_ps(vCosTheta, vOneMinEps);\n        const __m128 vResLerp = normalizeFast(lerp(vQ1, vQ2, t));\n\n        __m128 vRes = _mm_blendv_ps(vResSlerp, vResLerp, vIsThetaNearZero);\n\n        return vRes;\n    }\n\n    /* TODO\n    // pitch: angle of rotation around the x-axis (radians)\n    // yaw: angle of rotation around the y-axis (radians)\n    // roll: angle of rotation around the z-axis (radians)\n    // order is roll, pitch, then yaw\n    ZetaInline __m128 __vectorcall rotationQuatFromRollPitchYaw(float pitch, float yaw, float roll)\n    {\n        // roll:\n        //        n = (0, 0, 1) -> q_r = (0, 0, sin(r/2), cos(r/2)\n        // pitch:\n        //        n = (1, 0, 0) -> q_p = (sin(p/2), 0, 0, cos(p/2)\n        // yaw:\n        //        n = (0, 1, 0) -> q_y = (0, sin(y/2), 0, cos(y/2)\n    }\n    */\n}"
  },
  {
    "path": "Source/ZetaCore/Math/Sampling.cpp",
    "content": "#include \"Sampling.h\"\n#include <Utility/RNG.h>\n#include <cmath>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Math;\n\n//--------------------------------------------------------------------------------------\n// Sampling\n//--------------------------------------------------------------------------------------\n\nvoid Math::AliasTable_Normalize(MutableSpan<float> weights)\n{\n    // Compute the sum of weights\n    const int64_t N = weights.size();\n    const float sum = Math::KahanSum(weights);\n    Assert(!IsNaN(sum), \"sum of weights was NaN.\");\n\n    // Multiply each probability by N so that mean becomes 1 instead of 1 / N\n    const float sumRcp = N / sum;\n\n    // Align to 32 bytes\n    float* curr = weights.data();\n    while ((reinterpret_cast<uintptr_t>(curr) & 31) != 0)\n    {\n        *curr *= sumRcp;\n        curr++;\n    }\n\n    const int64_t startOffset = curr - weights.data();\n\n    // Largest multiple of 8 that is smaller than N\n    int64_t numToSumSIMD = N - startOffset;\n    numToSumSIMD -= numToSumSIMD & 7;\n\n    const float* end = curr + numToSumSIMD;\n    __m256 vSumRcp = _mm256_broadcast_ss(&sumRcp);\n\n    for (; curr < end; curr += 8)\n    {\n        __m256 V = _mm256_load_ps(curr);\n        V = _mm256_mul_ps(V, vSumRcp);\n\n        _mm256_store_ps(curr, V);\n    }\n\n    for (int64_t i = startOffset + numToSumSIMD; i < N; i++)\n        weights[i] *= sumRcp;\n}\n\nvoid Math::AliasTable_Build(MutableSpan<float> probs, MutableSpan<AliasTableEntry> table)\n{\n    const int64_t N = probs.size();\n    const float oneDivN = 1.0f / N;\n    AliasTable_Normalize(probs);\n\n    for (int64_t i = 0; i < N; i++)\n        table[i].P_Orig = probs[i] * oneDivN;\n\n    // Maintain an index buffer since original ordering of elements must be preserved\n    SmallVector<uint32_t> larger;\n    larger.reserve(N);\n\n    SmallVector<uint32_t> smaller;\n    smaller.reserve(N);\n\n    for (int64_t i = 0; i < N; i++)\n    {\n        if (probs[i] < 1.0f)\n            smaller.push_back((uint32_t)i);\n        else\n            larger.push_back((uint32_t)i);\n    }\n\n#ifndef NDEBUG\n    int64_t numInsertions = 0;\n#endif\n\n    // In each iteration, pick two probabilities such that one is smaller than 1.0 and the other larger \n    // than 1.0. Use the latter to bring up the former to 1.0.\n    while (!smaller.empty() && !larger.empty())\n    {\n        const uint32_t smallerIdx = smaller.back();\n        smaller.pop_back();\n        const float smallerProb = probs[smallerIdx];\n\n        const uint32_t largerIdx = larger.back();\n        float largerProb = probs[largerIdx];\n        Assert(largerProb >= 1.0f, \"should be >= 1.0\");\n\n        auto& e = table[smallerIdx];\n        Assert(e.Alias == UINT32_MAX, \"Every element must be inserted exactly one time.\");\n        e.Alias = largerIdx;\n        e.P_Curr = smallerProb;\n\n        // = largerProb - (1.0f - smallerProb);\n        largerProb = (smallerProb + largerProb) - 1.0f;\n        probs[largerIdx] = largerProb;\n\n        if (largerProb < 1.0f)\n        {\n            larger.pop_back();\n            smaller.push_back(largerIdx);\n        }\n\n#ifndef NDEBUG\n        numInsertions++;\n#endif\n    }\n\n    while (!larger.empty())\n    {\n        size_t idx = larger.back();\n        larger.pop_back();\n        Assert(fabsf(1.0f - probs[idx]) <= 0.1f, \"This should be ~1.0.\");\n\n        // Alias should point to itself\n        table[idx].Alias = (uint32_t)idx;\n        table[idx].P_Curr = 1.0f;\n\n#ifndef NDEBUG\n        numInsertions++;\n#endif\n    }\n\n    while (!smaller.empty())\n    {\n        size_t idx = smaller.back();\n        smaller.pop_back();\n        Assert(fabsf(1.0f - probs[idx]) <= 0.1f, \"This should be ~1.0.\");\n\n        // Alias should point to itself\n        table[idx].Alias = (uint32_t)idx;\n        table[idx].P_Curr = 1.0f;\n\n#ifndef NDEBUG\n        numInsertions++;\n#endif\n    }\n\n    Assert(numInsertions == N, \"Some elements were not inserted.\");\n}\n\nuint32_t Math::SampleAliasTable(Span<AliasTableEntry> table, RNG& rng, float& pdf)\n{\n    uint32_t idx = rng.UniformUintBounded((uint32_t)table.size());\n    AliasTableEntry s = table[idx];\n\n    if (rng.Uniform() < s.P_Curr)\n    {\n        pdf = s.P_Orig;\n        return idx;\n    }\n\n    pdf = table[s.Alias].P_Orig;\n    return s.Alias;\n}\n\nfloat Math::Halton(int i, int b)\n{\n    float f = 1.0f;\n    float r = 0.0f;\n    float bf = (float)b;\n\n    while (i > 0)\n    {\n        f /= bf;\n        r = r + f * (float)(i % b);\n        i = (int)((float)i / bf);\n    }\n\n    return r;\n}\n\nfloat3 Math::UniformSampleSphere(float2 u)\n{\n    float z = 1 - 2 * u.x;\n    float r = std::sqrt(Math::Max(0.0f, 1.0f - z * z));\n    float phi = 2 * Math::PI * u.y;\n\n    return float3(r * std::cos(phi), r * std::sin(phi), z);\n}\n"
  },
  {
    "path": "Source/ZetaCore/Math/Sampling.h",
    "content": "#pragma once\n\n#include <Utility/Span.h>\n#include <Math/Vector.h>\n\nnamespace ZetaRay::Util\n{\n    struct RNG;\n}\n\nnamespace ZetaRay::Math\n{\n    // Generates i'th index of the Halton low-discrepancy sequence for base b \n    float Halton(int i, int b);\n\n    Math::float3 UniformSampleSphere(const Math::float2 u);\n\n    struct AliasTableEntry\n    {\n        float P_Curr = 0.0f;\n        float P_Orig = 0.0f;\n        uint32_t Alias = UINT32_MAX;\n    };\n\n    // Alias Table\n    // Ref: https://www.keithschwarz.com/darts-dice-coins/\n\n    // Normalizes the given set of weights so that they sum to N where N is the size of sample space\n    void AliasTable_Normalize(Util::MutableSpan<float> weights);\n    // Generates an alias table for the given distribution.\n    void AliasTable_Build(Util::MutableSpan<float> weights, Util::MutableSpan<AliasTableEntry> table);\n    // Draws sample from the given alias table\n    uint32_t SampleAliasTable(Util::Span<AliasTableEntry> table, Util::RNG& rng, float& pdf);\n}\n"
  },
  {
    "path": "Source/ZetaCore/Math/Surface.cpp",
    "content": "#include \"Surface.h\"\n#include \"../App/Log.h\"\n#include <Math/VectorFuncs.h>\n\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Math;\n\n//--------------------------------------------------------------------------------------\n// Surfaces\n//--------------------------------------------------------------------------------------\n\nvoid ZetaRay::Math::ComputeMeshTangentVectors(MutableSpan<Vertex> vertices, Span<uint32_t> indices, bool rhsIndices)\n{\n    float3* tangents = new float3[vertices.size()];\n    memset(tangents, 0, sizeof(float3) * vertices.size());\n\n//    for (auto& v : vertices)\n//        v.Tangent = half3(0.0f, 0.0f, 0.0f);\n\n    // Given triangle with vertices v0, v1, v2 (in clockwise order) and corresponding texture coords\n    // (u0, v0), (u1, v1) and (u2, v2) we have:\n    // \n    //    p1 - p0 = (u1 - u0) * T + (v1 - v0) * B\n    //    p2 - p0 = (u2 - u0) * T + (v2 - v0) * B\n    //\n    // In matrix form:\n    // \n    //         [ u1 - u0  u2 - u0 ]\n    // [T B] * |                  | = [p1 - p0  p2 - p0]\n    //         [ v1 - v0  v2 - v0 ]\n    //\n    // This linear system is solved with:\n    // \n    // |     |              |                  |                                    \n    // | T B | = 1 / D    * | p1 - p0  p2 - p0 |  *  | v2 - v0  u0 - u2 |\n    // |     |              |                  |     | v0 - v1  u1 - u0 |           \n    //\n    // where D = (u1 - u0) * (v2 - v0) - (u2 - u0) * (v1 - v0)\n\n    uint32_t numCollinearTris = 0;\n\n    for (size_t i = 0; i < indices.size(); i += 3)\n    {\n        uint32_t i0 = indices[i];\n        uint32_t i1 = indices[i + 1];\n        uint32_t i2 = indices[i + 2];\n\n        // swap i1 & i2\n        if (rhsIndices)\n        {\n            uint32_t temp = i1;\n            i1 = i2;\n            i2 = temp;\n        }\n\n        float2 uv0 = vertices[i0].TexUV;\n        float3 pos0 = vertices[i0].Position;\n\n        float2 uv1 = vertices[i1].TexUV;\n        float3 pos1 = vertices[i1].Position;\n\n        float2 uv2 = vertices[i2].TexUV;\n        float3 pos2 = vertices[i2].Position;\n\n        float2 uv1Minuv0 = uv1 - uv0;\n        float2 uv2Minuv0 = uv2 - uv0;\n\n        float det = uv1Minuv0.x * uv2Minuv0.y - uv1Minuv0.y * uv2Minuv0.x;\n        if (det == 0)\n        {\n            numCollinearTris++;\n            continue;\n        }\n\n        float oneDivDet = 1.0f / det;\n\n        float3 p1Minp0 = pos1 - pos0;\n        float3 p2Minp0 = pos2 - pos0;\n\n        float3 T(p1Minp0.x * uv2Minuv0.y + p2Minp0.x * -uv1Minuv0.y,\n                 p1Minp0.y * uv2Minuv0.y + p2Minp0.y * -uv1Minuv0.y,\n                 p1Minp0.z * uv2Minuv0.y + p2Minp0.z * -uv1Minuv0.y);\n\n        T *= oneDivDet;\n\n        tangents[i0] += T;\n        tangents[i1] += T;\n        tangents[i2] += T;\n    }\n\n    // Gram-Schmidt Orthonormalization\n    // Assumes vertex normala are normalized\n    for(size_t i = 0; i < vertices.size(); i++)\n    {\n        float3 n = vertices[i].Normal.decode();\n        float3 tangProjectedOnNormal = n.dot(tangents[i]) * n;\n        tangents[i] -= tangProjectedOnNormal;\n        tangents[i].normalize();\n\n        vertices[i].Tangent = oct32(tangents[i]);\n    }\n\n    if (numCollinearTris)\n    {\n        LOG_UI_WARNING(\"Mesh had %u/%u collinear triangles, vertex tangents might be missing.\\n\",\n            numCollinearTris, (uint32_t)indices.size() / 3);\n    }\n\n    delete[] tangents;\n}\n"
  },
  {
    "path": "Source/ZetaCore/Math/Surface.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n#include \"../Core/Vertex.h\"\n#include \"../Utility/Span.h\"\n\nnamespace ZetaRay::Math\n{\n    void ComputeMeshTangentVectors(Util::MutableSpan<Core::Vertex> vertices, Util::Span<uint32_t> indices,\n        bool rhsIndices = false);\n\n    // Returns barrycentric coordinates (u, v, w) of point p relative to triangle v0v1v2 (ordered clockwise)\n    // such that p = V0 + v(V1 - V0) + w(V2 - V0) or alternatively,\n    //           p = uV0 + vV1 + wV2\n    ZetaInline __m128 __vectorcall computeBarryCoords(const __m128 v0, const __m128 v1, const __m128 v2, const __m128 p)\n    {\n        const __m128 v1Minv0 = _mm_sub_ps(v1, v0);  // s\n        const __m128 v2Minv0 = _mm_sub_ps(v2, v0);  // t\n        const __m128 pMinv0 = _mm_sub_ps(p, v0);    // q\n        const __m128 vOne = _mm_set1_ps(1.0f);\n\n        //        | q.s  t.s|                | s.s  q.s|\n        //        | q.t  t.t|                | s.t  q.t|\n        // v = -------------       w = -------------\n        //        | s.s  t.s|                | s.s  t.t|\n        //        | s.t  t.t|                | s.t  t.t|\n\n        // (s_x, s_x, t_x, _)\n        __m128 vTemp0 = _mm_shuffle_ps(v1Minv0, v2Minv0, V_SHUFFLE_XYZW(0, 0, 0, 0));\n        // (s_y, s_y, t_y, _)\n        __m128 vTemp2 = _mm_shuffle_ps(v1Minv0, v2Minv0, V_SHUFFLE_XYZW(1, 1, 1, 1));\n        // (s_x, t_x, t_x, _)\n        __m128 vTemp1 = _mm_shuffle_ps(vTemp0, vTemp0, V_SHUFFLE_XYZW(0, 2, 2, 0));\n        __m128 vDots = _mm_mul_ps(vTemp0, vTemp1);\n\n        // (s_y, t_y, t_y, _)\n        __m128 vTemp3 = _mm_shuffle_ps(vTemp2, vTemp2, V_SHUFFLE_XYZW(0, 2, 2, 0));\n        __m128 vTemp4 = _mm_shuffle_ps(v1Minv0, v2Minv0, V_SHUFFLE_XYZW(2, 2, 2, 2));\n        vDots = _mm_fmadd_ps(vTemp2, vTemp3, vDots);\n\n        // (s_z, s_z, t_z, _)\n        __m128 vTemp5 = _mm_shuffle_ps(vTemp4, vTemp4, V_SHUFFLE_XYZW(0, 2, 2, 0));\n        // vDots = (s.s, s.t, t.t, _)\n        vDots = _mm_fmadd_ps(vTemp4, vTemp5, vDots);\n\n        vTemp0 = _mm_shuffle_ps(pMinv0, pMinv0, V_SHUFFLE_XYZW(0, 0, 1, 1));\n        vTemp1 = _mm_shuffle_ps(pMinv0, pMinv0, V_SHUFFLE_XYZW(2, 2, 2, 2));\n        // (qx, qx, qy, qy, qz, qz, _, _)\n        __m256 vTemp6 = _mm256_insertf128_ps(_mm256_castps128_ps256(vTemp0), vTemp1, 0x1);\n\n        vTemp2 = _mm_unpacklo_ps(v1Minv0, v2Minv0);\n        vTemp3 = _mm_unpackhi_ps(v1Minv0, v2Minv0);\n        // (sx, tx, sy, ty, sz, tz, _, _)\n        __m256 vTemp7 = _mm256_insertf128_ps(_mm256_castps128_ps256(vTemp2), vTemp3, 0x1);\n\n        // (qx * sx, qx * tx, qy * sy, qy * ty, qz * sz, qz * tz, _, _)\n        vTemp6 = _mm256_mul_ps(vTemp6, vTemp7);\n        vTemp4 = _mm256_extractf128_ps(vTemp6, 0);\n        vTemp5 = _mm256_extractf128_ps(vTemp6, 1);\n\n        vTemp4 = _mm_add_ps(vTemp4, _mm_shuffle_ps(vTemp4, vTemp4, V_SHUFFLE_XYZW(2, 3, 2, 3)));\n        // (q.s, q.t, _, _)\n        const __m128 vRhs = _mm_add_ps(vTemp4, vTemp5);\n\n        // (q.t, q.s, s.t, _)\n        vTemp2 = _mm_shuffle_ps(vRhs, vDots, V_SHUFFLE_XYZW(1, 0, 1, 0));\n        // (s.t, s.t, s.t, _)\n        vTemp3 = _mm_shuffle_ps(vDots, vDots, V_SHUFFLE_XYZW(1, 1, 1, 0));\n        vTemp4 = _mm_mul_ps(vTemp2, vTemp3);\n\n        // (q.s, q.t, s.s, _)\n        vTemp0 = _mm_shuffle_ps(vRhs, vDots, V_SHUFFLE_XYZW(0, 1, 0, 0));\n        // (t.t, s.s, t.t, _)\n        vTemp1 = _mm_shuffle_ps(vDots, vDots, V_SHUFFLE_XYZW(2, 0, 2, 0));\n        vTemp4 = _mm_fmsub_ps(vTemp0, vTemp1, vTemp4);\n\n        const __m128 vDetRcp = _mm_rcp_ps(_mm_shuffle_ps(vTemp4, vTemp4, V_SHUFFLE_XYZW(2, 2, 2, 2)));\n        vTemp4 = _mm_mul_ps(vTemp4, vDetRcp);\n\n        vTemp2 = _mm_add_ps(vTemp4, _mm_shuffle_ps(vTemp4, vTemp4, V_SHUFFLE_XYZW(1, 1, 1, 1)));\n        vTemp2 = _mm_sub_ps(vOne, vTemp2);\n\n        // the remaining barry coordinate is equal to 1 - v - w\n        vTemp4 = _mm_insert_ps(_mm_shuffle_ps(vTemp4, vTemp4, V_SHUFFLE_XYZW(0, 0, 1, 0)), vTemp2, 0x0);\n\n        return vTemp4;\n    }\n\n    // Finds the axis with the largest span\n    //static int FindAxisWithMaximumExtent(const DirectX::XMFLOAT3& vec)\n    //{\n    //    const float EPS = 1e-5;\n    //    Check(vec.x + vec.y + vec.z > EPS, \"Degenerate input vector\", SEVERITY::FATAL);\n\n    //    bool xGTy = abs(vec.x) > abs(vec.y);\n    //    bool xGTz = abs(vec.x) > abs(vec.z);\n    //    bool yGTz = abs(vec.y) > abs(vec.z);\n\n    //    bool maxIsX = xGTy && xGTz;\n    //    bool maxIsY = (!xGTy && yGTz);\n    //    bool maxIsZ = (!xGTz && !yGTz);\n\n    //    return maxIsX ? 0 : (maxIsY ? 1 : 2);\n    //}\n}"
  },
  {
    "path": "Source/ZetaCore/Math/Vector.h",
    "content": "#pragma once\n\n#include \"Common.h\"\n\n#define V_SHUFFLE_XYZW(fp0, fp1, fp2, fp3) (((fp3) << 6) | ((fp2) << 4) | ((fp1) << 2) | ((fp0)))\n#define V_BLEND_XYZW(fp0, fp1, fp2, fp3) (((fp3) << 3) | ((fp2) << 2) | ((fp1) << 1) | ((fp0)))\n\nnamespace ZetaRay::Math\n{\n    struct half2;\n    struct half3;\n    struct half4;\n    struct alignas(16) float4a;\n\n    struct float2\n    {\n        constexpr float2() = default;\n        constexpr explicit float2(float x)\n            : x(x),\n            y(x)\n        {}\n        constexpr float2(float x, float y)\n            : x(x),\n            y(y)\n        {}\n        float2(const half2& h);\n\n        constexpr float2& operator+=(const float2& other)\n        {\n            x += other.x;\n            y += other.y;\n\n            return *this;\n        }\n        constexpr float2& operator-=(const float2& other)\n        {\n            x -= other.x;\n            y -= other.y;\n\n            return *this;\n        }\n        constexpr float2& operator*=(float f)\n        {\n            x *= f;\n            y *= f;\n\n            return *this;\n        }\n        constexpr float2& operator*=(float2 f)\n        {\n            x *= f.x;\n            y *= f.y;\n\n            return *this;\n        }\n        constexpr float2& operator/=(float2 f)\n        {\n            x /= f.x;\n            y /= f.y;\n\n            return *this;\n        }\n        constexpr float2& operator/=(float f)\n        {\n            x /= f;\n            y /= f;\n\n            return *this;\n        }\n\n        constexpr float dot(const float2& other) const\n        {\n            return x * other.x + y * other.y;\n        }\n\n        float length() const\n        {\n            return sqrtf(dot(*this));\n        }\n\n        void normalize()\n        {\n            float norm = length();\n            if (norm <= FLT_EPSILON)\n                return;\n            float oneDivNorm = 1.0f / norm;\n\n            x *= oneDivNorm;\n            y *= oneDivNorm;\n        }\n\n        float x;\n        float y;\n    };\n\n    struct float3\n    {\n        constexpr float3() = default;\n        constexpr explicit float3(float x)\n            : x(x),\n            y(x),\n            z(x)\n        {}\n        constexpr float3(float x, float y, float z)\n            : x(x),\n            y(y),\n            z(z)\n        {}\n        constexpr float3(const float2& xy, float z = 0.0f)\n            : x(xy.x),\n            y(xy.y),\n            z(z)\n        {}\n        explicit float3(const half3& h);\n\n        constexpr float3& operator+=(const float3& other)\n        {\n            x += other.x;\n            y += other.y;\n            z += other.z;\n\n            return *this;\n        }\n        constexpr float3& operator-=(const float3& other)\n        {\n            x -= other.x;\n            y -= other.y;\n            z -= other.z;\n\n            return *this;\n        }\n        constexpr float3& operator*=(float3 f)\n        {\n            x *= f.x;\n            y *= f.y;\n            z *= f.z;\n\n            return *this;\n        }\n        constexpr float3& operator*=(float f)\n        {\n            x *= f;\n            y *= f;\n            z *= f;\n\n            return *this;\n        }\n        constexpr float3& operator/=(float3 f)\n        {\n            x /= f.x;\n            y /= f.y;\n            z /= f.z;\n\n            return *this;\n        }\n        constexpr float3& operator/=(float f)\n        {\n            x /= f;\n            y /= f;\n            z /= f;\n\n            return *this;\n        }\n        constexpr float2 xy() const\n        {\n            return float2(x, y);\n        }\n        constexpr float2 yz() const\n        {\n            return float2(y, z);\n        }\n\n        float length() const\n        {\n            return sqrtf(dot(*this));\n        }\n\n        constexpr float dot(const float3& other) const\n        {\n            return x * other.x + y * other.y + z * other.z;\n        }\n\n        constexpr float3 cross(const float3 other) const\n        {\n            return float3(y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x);\n        }\n\n        void normalize()\n        {\n            float norm = length();\n            if (norm <= FLT_EPSILON)\n                return;\n            float oneDivNorm = 1.0f / norm;\n\n            x *= oneDivNorm;\n            y *= oneDivNorm;\n            z *= oneDivNorm;\n        }\n\n        float x;\n        float y;\n        float z;\n    };\n\n    struct float4\n    {\n        constexpr float4() = default;\n        constexpr explicit float4(float f)\n            : x(f),\n            y(f),\n            z(f),\n            w(f)\n        {}\n        constexpr float4(float fx, float fy, float fz, float fw)\n            : x(fx),\n            y(fy),\n            z(fz),\n            w(fw)\n        {}\n        constexpr float4(const float3& xyz, float fw = 0.0f)\n            : x(xyz.x),\n            y(xyz.y),\n            z(xyz.z),\n            w(fw)\n        {}\n        constexpr float4(const float2& xy, const float2& zw)\n            : x(xy.x),\n            y(xy.y),\n            z(zw.x),\n            w(zw.y)\n        {}\n        float4(const half4& h);\n        float4(const float4a& f);\n\n        constexpr float4& operator+=(const float4& other)\n        {\n            x += other.x;\n            y += other.y;\n            z += other.z;\n            w += other.w;\n\n            return *this;\n        }\n        constexpr float4& operator-=(const float4& other)\n        {\n            x -= other.x;\n            y -= other.y;\n            z -= other.z;\n            w -= other.w;\n\n            return *this;\n        }\n        constexpr float4& operator*=(float4 f)\n        {\n            x *= f.x;\n            y *= f.y;\n            z *= f.z;\n            w *= f.w;\n\n            return *this;\n        }\n        constexpr float4& operator*=(float f)\n        {\n            x *= f;\n            y *= f;\n            z *= f;\n            w *= f;\n\n            return *this;\n        }\n        constexpr float4& operator/=(float4 f)\n        {\n            x /= f.x;\n            y /= f.y;\n            z /= f.z;\n            w /= f.w;\n\n            return *this;\n        }\n        constexpr float4& operator/=(float f)\n        {\n            x /= f;\n            y /= f;\n            z /= f;\n            w /= f;\n\n            return *this;\n        }\n        constexpr float2 xy() const\n        {\n            return float2(x, y);\n        }\n        constexpr float2 yz() const\n        {\n            return float2(y, z);\n        }\n        constexpr float2 zw() const\n        {\n            return float2(z, w);\n        }\n        constexpr float3 xyz() const\n        {\n            return float3(x, y, z);\n        }\n        constexpr float3 yzw() const\n        {\n            return float3(y, z, w);\n        }\n\n        float length() const\n        {\n            __m128 vV = _mm_loadu_ps(&this->x);\n            __m128 vLength = _mm_dp_ps(vV, vV, 0xff);\n            vLength = _mm_sqrt_ps(vLength);\n\n            return _mm_cvtss_f32(vLength);\n        }\n\n        constexpr float dot(const float4& other) const\n        {\n            return x * other.x + y * other.y + z * other.z + w * other.w;\n        }\n\n        void normalize()\n        {\n            float norm = length();\n            Assert(norm > 1e-7, \"Divide-by-zero.\");\n            float oneDivNorm = 1.0f / norm;\n\n            x *= oneDivNorm;\n            y *= oneDivNorm;\n            z *= oneDivNorm;\n            w *= oneDivNorm;\n        }\n\n        float x;\n        float y;\n        float z;\n        float w;\n    };\n\n    struct alignas(16) float4a\n    {\n        float4a() = default;\n        constexpr explicit float4a(float f)\n            : x(f),\n            y(f),\n            z(f),\n            w(f)\n        {}\n        constexpr float4a(float fx, float fy, float fz, float fw)\n            : x(fx),\n            y(fy),\n            z(fz),\n            w(fw)\n        {}\n        constexpr float4a(float4 f)\n            : x(f.x),\n            y(f.y),\n            z(f.z),\n            w(f.w)\n        {}\n        constexpr float4a(float3 f, float w = 0.0f)\n            : x(f.x),\n            y(f.y),\n            z(f.z),\n            w(w)\n        {}\n        constexpr float2 xy() const\n        {\n            return float2(x, y);\n        }\n        constexpr float2 yz() const\n        {\n            return float2(y, z);\n        }\n        constexpr float2 zw() const\n        {\n            return float2(z, w);\n        }\n        constexpr float3 xyz() const\n        {\n            return float3(x, y, z);\n        }\n        constexpr float3 yzw() const\n        {\n            return float3(y, z, w);\n        }\n\n        float x;\n        float y;\n        float z;\n        float w;\n    };\n\n    struct half\n    {\n        half() = default;\n        explicit half(float f)\n            : x(FloatToHalf(f))\n        {}\n\n        static half asfloat16(uint16_t v)\n        {\n            half h;\n            h.x = v;\n\n            return h;\n        }\n\n        uint16_t x;\n    };\n\n    struct half2\n    {\n        half2() = default;\n        explicit half2(float f)\n        {\n            uint16_t h = FloatToHalf(f);\n            x = h;\n            y = h;\n        }\n\n        half2(float fx, float fy)\n        {\n            float2 f(fx, fy);\n\n            // &f does not need to be aligned and the last two elements are set to 0\n            __m128 vF = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double*>(&f)));\n            __m128i vH = _mm_cvtps_ph(vF, 0);\n\n            // Doesn't violate strict aliasing: https://stackoverflow.com/questions/13257166/print-a-m128i-variable\n            alignas(16) uint16_t v[8];\n            _mm_store_si128((__m128i*)v, vH);\n\n            x = v[0];\n            y = v[1];\n        }\n\n        explicit half2(const float2& f)\n        {\n            // &f does not need to be aligned and the last two elements are set to 0\n            __m128 vF = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double*>(&(const_cast<float2&>(f)))));\n            __m128i vH = _mm_cvtps_ph(vF, 0);\n\n            // Doesn't violate strict aliasing: https://stackoverflow.com/questions/13257166/print-a-m128i-variable\n            alignas(16) uint16_t v[8];\n            _mm_store_si128((__m128i*)v, vH);\n\n            x = v[0];\n            y = v[1];\n        }\n\n        uint16_t x;\n        uint16_t y;\n    };\n\n    struct half3\n    {\n        half3() = default;\n        explicit half3(float f)\n        {\n            uint16_t h = FloatToHalf(f);\n            x = h;\n            y = h;\n            z = h;\n        }\n\n        half3(float fx, float fy, float fz)\n        {\n            float4a f(fx, fy, fz, 0);\n            __m128 vF = _mm_load_ps(reinterpret_cast<float*>(&f));\n            __m128i vH = _mm_cvtps_ph(vF, 0);\n\n            // Doesn't violate strict aliasing: https://stackoverflow.com/questions/13257166/print-a-m128i-variable\n            alignas(16) uint16_t v[8];\n            _mm_store_si128((__m128i*)v, vH);\n\n            x = v[0];\n            y = v[1];\n            z = v[2];\n        }\n\n        explicit half3(const float3& f)\n        {\n            // &v does not need to be aligned and the last two elements are set to 0\n            __m128 vXY = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double*>(&(const_cast<float3&>(f)))));\n            // &v.z does not need to be aligned\n            __m128 vZ = _mm_load_ss(&f.z);\n            __m128 vF = _mm_insert_ps(vXY, vZ, 0x20);\n\n            __m128i vH = _mm_cvtps_ph(vF, 0);\n\n            // Doesn't violate strict aliasing: https://stackoverflow.com/questions/13257166/print-a-m128i-variable\n            alignas(16) uint16_t v[8];\n            _mm_store_si128((__m128i*)v, vH);\n\n            x = v[0];\n            y = v[1];\n            z = v[2];\n        }\n\n        explicit half3(const float4a& f)\n        {\n            __m128 vF = _mm_load_ps(reinterpret_cast<float*>(&(const_cast<float4a&>(f))));\n            __m128i vH = _mm_cvtps_ph(vF, 0);\n\n            // Doesn't violate strict aliasing: https://stackoverflow.com/questions/13257166/print-a-m128i-variable\n            alignas(16) uint16_t v[8];\n            _mm_store_si128((__m128i*)v, vH);\n\n            x = v[0];\n            y = v[1];\n            z = v[2];\n        }\n\n        uint16_t x;\n        uint16_t y;\n        uint16_t z;\n    };\n\n    struct half4\n    {\n        half4() = default;\n        explicit half4(float f)\n        {\n            uint16_t h = FloatToHalf(f);\n            x = h;\n            y = h;\n            z = h;\n            w = h;\n        }\n\n        half4(float fx, float fy, float fz, float fw)\n        {\n            float4a f(fx, fy, fz, fw);\n            __m128 vF = _mm_load_ps(reinterpret_cast<float*>(&f));\n            __m128i vH = _mm_cvtps_ph(vF, 0);\n\n            // Doesn't violate strict aliasing: https://stackoverflow.com/questions/13257166/print-a-m128i-variable\n            alignas(16) uint16_t v[8];\n            _mm_store_si128((__m128i*)v, vH);\n\n            x = v[0];\n            y = v[1];\n            z = v[2];\n            w = v[3];\n        }\n\n        explicit half4(const float4& f)\n        {\n            __m128 vF = _mm_loadu_ps(reinterpret_cast<float*>(&(const_cast<float4&>(f))));\n            __m128i vH = _mm_cvtps_ph(vF, 0);\n\n            // Doesn't violate strict aliasing: https://stackoverflow.com/questions/13257166/print-a-m128i-variable\n            alignas(16) uint16_t v[8];\n            _mm_store_si128((__m128i*)v, vH);\n\n            x = v[0];\n            y = v[1];\n            z = v[2];\n            w = v[3];\n        }\n\n        uint16_t x;\n        uint16_t y;\n        uint16_t z;\n        uint16_t w;\n    };\n\n    struct uint3\n    {\n        uint3() = default;\n        constexpr explicit uint3(uint32_t x)\n            : x(x),\n            y(x),\n            z(x)\n        {}\n        constexpr uint3(uint32_t e0, uint32_t e1, uint32_t e2)\n            : x(e0), y(e1), z(e2)\n        {}\n\n        uint32_t x;\n        uint32_t y;\n        uint32_t z;\n    };\n\n    struct unorm2\n    {\n        unorm2() = default;\n        explicit unorm2(uint16_t u)\n            : x(u),\n            y(u)\n        {}\n        unorm2(uint16_t u, uint16_t v)\n            : x(u),\n            y(v)\n        {}\n\n        // Encodes float2 in [-1, 1]\n        static unorm2 FromNormalized(float2 u)\n        {\n            unorm2 ret;\n\n            __m128 vV = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double*>(&u)));\n            __m128 vHalf = _mm_set1_ps(0.5f);\n            // [-1, 1] -> [0, 1] \n            vV = _mm_fmadd_ps(vV, vHalf, vHalf);\n\n            __m128 vMax = _mm_set1_ps((1 << 16) - 1);\n            __m128 vTemp = _mm_mul_ps(vV, vMax);\n            // cvtps_epi32 uses the default rounding mode (round to nearest)\n            __m128i vEncoded = _mm_cvtps_epi32(vTemp);\n\n            // Doesn't violate strict aliasing: https://stackoverflow.com/questions/13257166/print-a-m128i-variable\n            alignas(16) uint32_t a[4];\n            _mm_store_si128(reinterpret_cast<__m128i*>(a), vEncoded);\n\n            ret.x = static_cast<uint16_t>(a[0]);\n            ret.y = static_cast<uint16_t>(a[1]);\n\n            return ret;\n        }\n\n        // Encodes float2 in [-1, 1]\n        static unorm2 FromNormalized(__m128 vV)\n        {\n            unorm2 ret;\n\n            __m128 vHalf = _mm_set1_ps(0.5f);\n            // [-1, 1] -> [0, 1] \n            vV = _mm_fmadd_ps(vV, vHalf, vHalf);\n\n            __m128 vMax = _mm_set1_ps((1 << 16) - 1);\n            __m128 vTemp = _mm_mul_ps(vV, vMax);\n            // cvtps_epi32 uses the default rounding mode (round to nearest)\n            __m128i vEncoded = _mm_cvtps_epi32(vTemp);\n\n            // Doesn't violate strict aliasing: https://stackoverflow.com/questions/13257166/print-a-m128i-variable\n            alignas(16) uint32_t a[4];\n            _mm_store_si128(reinterpret_cast<__m128i*>(a), vEncoded);\n\n            ret.x = static_cast<uint16_t>(a[0]);\n            ret.y = static_cast<uint16_t>(a[1]);\n\n            return ret;\n        }\n\n        uint16_t x;\n        uint16_t y;\n    };\n\n    struct unorm3\n    {\n        unorm3() = default;\n        explicit unorm3(uint16_t u)\n            : x(u),\n            y(u),\n            z(u)\n        {}\n        unorm3(uint16_t u0, uint16_t u1, uint16_t u2)\n            : x(u0),\n            y(u1),\n            z(u2)\n        {}\n\n        // Encodes float3 in [-1, 1]\n        static unorm3 FromNormalized(float u0, float u1, float u2)\n        {\n            unorm3 ret;\n\n            float4a v(u0, u1, u2, 0);\n            __m128 vV = _mm_load_ps(reinterpret_cast<float*>(&v));\n            __m128 vHalf = _mm_set1_ps(0.5f);\n            // [-1, 1] -> [0, 1]\n            vV = _mm_fmadd_ps(vV, vHalf, vHalf);\n\n            __m128 vMax = _mm_set1_ps((1 << 16) - 1);\n            __m128 vTemp = _mm_mul_ps(vV, vMax);\n            // cvtps_epi32 uses the default rounding mode (round to nearest)\n            __m128i vEncoded = _mm_cvtps_epi32(vTemp);\n\n            // Doesn't violate strict aliasing: https://stackoverflow.com/questions/13257166/print-a-m128i-variable\n            alignas(16) uint32_t a[4];\n            _mm_store_si128(reinterpret_cast<__m128i*>(a), vEncoded);\n\n            ret.x = static_cast<uint16_t>(a[0]);\n            ret.y = static_cast<uint16_t>(a[1]);\n            ret.z = static_cast<uint16_t>(a[2]);\n\n            return ret;\n        }\n\n        // Encodes float3 in [-1, 1]\n        static unorm3 FromNormalized(float3 v)\n        {\n            unorm3 ret;\n\n            __m128 vXY = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double*>(&v)));\n            // &v.z does not need to be aligned\n            __m128 vZ = _mm_load_ss(&v.z);\n            __m128 vV = _mm_insert_ps(vXY, vZ, 0x20);\n            __m128 vHalf = _mm_set1_ps(0.5f);\n            // [-1, 1] -> [0, 1]\n            vV = _mm_fmadd_ps(vV, vHalf, vHalf);\n\n            __m128 vMax = _mm_set1_ps((1 << 16) - 1);\n            __m128 vTemp = _mm_mul_ps(vV, vMax);\n            // cvtps_epi32 uses the default rounding mode (round to nearest)\n            __m128i vEncoded = _mm_cvtps_epi32(vTemp);\n\n            // Doesn't violate strict aliasing: https://stackoverflow.com/questions/13257166/print-a-m128i-variable\n            alignas(16) uint32_t a[4];\n            _mm_store_si128(reinterpret_cast<__m128i*>(a), vEncoded);\n\n            ret.x = static_cast<uint16_t>(a[0]);\n            ret.y = static_cast<uint16_t>(a[1]);\n            ret.z = static_cast<uint16_t>(a[2]);\n\n            return ret;\n        }\n\n        uint16_t x;\n        uint16_t y;\n        uint16_t z;\n    };\n\n    struct unorm4\n    {\n        unorm4() = default;\n        explicit unorm4(uint16_t u)\n            : x(u),\n            y(u),\n            z(u),\n            w(u)\n        {}\n        unorm4(uint16_t u0, uint16_t u1, uint16_t u2, uint16_t u3)\n            : x(u0),\n            y(u1),\n            z(u2),\n            w(u3)\n        {}\n\n        // Encodes float4 in [-1, 1]\n        static unorm4 FromNormalized(float4a& v)\n        {\n            unorm4 ret;\n            \n            __m128 vV = _mm_load_ps(reinterpret_cast<float*>(&v));\n            __m128 vHalf = _mm_set1_ps(0.5f);\n            // [-1, 1] -> [0, 1]\n            vV = _mm_fmadd_ps(vV, vHalf, vHalf);\n\n            __m128 vMax = _mm_set1_ps((1 << 16) - 1);\n            __m128 vTemp = _mm_mul_ps(vV, vMax);\n            // cvtps_epi32 uses the default rounding mode (round to nearest)\n            __m128i vEncoded = _mm_cvtps_epi32(vTemp);\n\n            // Doesn't violate strict aliasing: https://stackoverflow.com/questions/13257166/print-a-m128i-variable\n            alignas(16) uint32_t a[4];\n            _mm_store_si128(reinterpret_cast<__m128i*>(a), vEncoded);\n\n            ret.x = static_cast<uint16_t>(a[0]);\n            ret.y = static_cast<uint16_t>(a[1]);\n            ret.z = static_cast<uint16_t>(a[2]);\n            ret.w = static_cast<uint16_t>(a[3]);\n\n            return ret;\n        }\n\n        uint16_t x;\n        uint16_t y;\n        uint16_t z;\n        uint16_t w;\n    };\n\n    inline float2::float2(const half2& h)\n        : x(HalfToFloat(h.x)),\n        y(HalfToFloat(h.y))\n    {}\n\n    inline float3::float3(const half3& h)\n        : x(HalfToFloat(h.x)),\n        y(HalfToFloat(h.y)),\n        z(HalfToFloat(h.z))\n    {}\n\n    inline float4::float4(const half4& h)\n        : x(HalfToFloat(h.x)),\n        y(HalfToFloat(h.y)),\n        z(HalfToFloat(h.z)),\n        w(HalfToFloat(h.w))\n    {}\n\n    inline float4::float4(const float4a& f)\n        : x(f.x),\n        y(f.y),\n        z(f.z),\n        w(f.w)\n    {}\n\n    //--------------------------------------------------------------------------------------\n    // Operator Overloading\n    //--------------------------------------------------------------------------------------\n\n    ZetaInline constexpr float2 operator+(const float2& v1, const float2& v0)\n    {\n        return float2(v1.x + v0.x, v1.y + v0.y);\n    }\n\n    ZetaInline constexpr float2 operator+(const float2& v0, float f)\n    {\n        return float2(v0.x + f, v0.y + f);\n    }\n    \n    ZetaInline constexpr float2 operator+(float f, const float2& v0)\n    {\n        return float2(v0.x + f, v0.y + f);\n    }\n\n    ZetaInline constexpr float2 operator*(const float2& v0, const float2& v1)\n    {\n        return float2(v0.x * v1.x, v0.y * v1.y);\n    }\n\n    ZetaInline constexpr float2 operator*(const float2& v0, float f)\n    {\n        return float2(v0.x * f, v0.y * f);\n    }\n\n    ZetaInline constexpr float2 operator*(float f, const float2& v0)\n    {\n        return float2(v0.x * f, v0.y * f);\n    }\n\n    ZetaInline constexpr float2 operator/(const float2& v0, const float2& v1)\n    {\n        return float2(v0.x / v1.x, v0.y / v1.y);\n    }\n\n    ZetaInline constexpr float2 operator/(const float2& v0, float f)\n    {\n        return float2(v0.x / f, v0.y / f);\n    }\n\n    ZetaInline constexpr float2 operator/(float f, const float2& v0)\n    {\n        return float2(f / v0.x, f / v0.y);\n    }\n\n    ZetaInline constexpr float2 operator-(const float2& v1, const float2& v0)\n    {\n        return float2(v1.x - v0.x, v1.y - v0.y);\n    }\n\n    ZetaInline constexpr float2 operator-(const float2& v0, float f)\n    {\n        return float2(v0.x - f, v0.y - f);\n    }\n\n    ZetaInline constexpr float2 operator-(float f, const float2& v0)\n    {\n        return float2(f - v0.x, f - v0.y);\n    }\n\n    ZetaInline constexpr float2 operator-(const float2& v0)\n    {\n        return float2(-v0.x, -v0.y);\n    }\n\n    ZetaInline constexpr float3 operator+(const float3& v0, const float3& v1)\n    {\n        return float3(v0.x + v1.x, v0.y + v1.y, v0.z + v1.z);\n    }\n\n    ZetaInline constexpr float3 operator+(const float3& v0, float f)\n    {\n        return float3(v0.x + f, v0.y + f, v0.z + f);\n    }\n\n    ZetaInline constexpr float3 operator+(float f, const float3& v0)\n    {\n        return float3(v0.x + f, v0.y + f, v0.z + f);\n    }\n\n    ZetaInline constexpr float3 operator-(const float3& v1, const float3& v0)\n    {\n        return float3(v1.x - v0.x, v1.y - v0.y, v1.z - v0.z);\n    }\n\n    ZetaInline constexpr float3 operator-(const float3& v0, float f)\n    {\n        return float3(v0.x - f, v0.y - f, v0.z - f);\n    }\n\n    ZetaInline constexpr float3 operator-(float f, const float3& v0)\n    {\n        return float3(f - v0.x, f - v0.y, f - v0.z);\n    }\n\n    ZetaInline constexpr float3 operator-(const float3& v0)\n    {\n        return float3(-v0.x, -v0.y, -v0.z);\n    }\n\n    ZetaInline constexpr float3 operator*(const float3& v0, const float3& v1)\n    {\n        return float3(v0.x * v1.x, v0.y * v1.y, v0.z * v1.z);\n    }\n\n    ZetaInline constexpr float3 operator*(const float3& v0, float f)\n    {\n        return float3(v0.x * f, v0.y * f, v0.z * f);\n    }\n\n    ZetaInline constexpr float3 operator*(float f, const float3& v0)\n    {\n        return float3(v0.x * f, v0.y * f, v0.z * f);\n    }\n\n    ZetaInline constexpr float3 operator/(const float3& v0, const float3& v1)\n    {\n        return float3(v0.x / v1.x, v0.y / v1.y, v0.z / v1.z);\n    }\n\n    ZetaInline constexpr float3 operator/(const float3& v0, float f)\n    {\n        return float3(v0.x / f, v0.y / f, v0.z / f);\n    }\n\n    ZetaInline constexpr float3 operator/(float f, const float3& v0)\n    {\n        return float3(f / v0.x, f / v0.y, f / v0.z);\n    }\n\n    ZetaInline constexpr float4 operator+(const float4& v0, const float4& v1)\n    {\n        return float4(v0.x + v1.x, v0.y + v1.y, v0.z + v1.z, v0.w + v1.w);\n    }\n\n    ZetaInline constexpr float4 operator+(const float4& v0, float f)\n    {\n        return float4(v0.x + f, v0.y + f, v0.z + f, v0.w + f);\n    }\n\n    ZetaInline constexpr float4 operator+(float f, const float4& v0)\n    {\n        return float4(v0.x + f, v0.y + f, v0.z + f, v0.w + f);\n    }\n\n    ZetaInline constexpr float4 operator-(const float4& v1, const float4& v0)\n    {\n        return float4(v1.x - v0.x, v1.y - v0.y, v1.z - v0.z, v1.w - v0.w);\n    }\n\n    ZetaInline constexpr float4 operator-(const float4& v0, float f)\n    {\n        return float4(v0.x - f, v0.y - f, v0.z - f, v0.w - f);\n    }\n\n    ZetaInline constexpr float4 operator-(float f, const float4& v0)\n    {\n        return float4(f - v0.x, f - v0.y, f - v0.z, f - v0.w);\n    }\n\n    ZetaInline constexpr float4 operator-(const float4& v0)\n    {\n        return float4(-v0.x, -v0.y, -v0.z, -v0.w);\n    }\n\n    ZetaInline constexpr float4 operator*(const float4& v0, const float4& v1)\n    {\n        return float4(v0.x * v1.x, v0.y * v1.y, v0.z * v1.z, v0.w * v1.w);\n    }\n\n    ZetaInline constexpr float4 operator*(const float4& v0, float f)\n    {\n        return float4(v0.x * f, v0.y * f, v0.z * f, v0.w * f);\n    }\n\n    ZetaInline constexpr float4 operator*(float f, const float4& v0)\n    {\n        return float4(v0.x * f, v0.y * f, v0.z * f, v0.w * f);\n    }\n\n    ZetaInline constexpr float4 operator/(const float4& v0, const float4& v1)\n    {\n        return float4(v0.x / v1.x, v0.y / v1.y, v0.z / v1.z, v0.w / v1.w);\n    }\n\n    ZetaInline constexpr float4 operator/(const float4& v0, float f)\n    {\n        return float4(v0.x / f, v0.y / f, v0.z / f, v0.w / f);\n    }\n\n    ZetaInline constexpr float4 operator/(float f, const float4& v0)\n    {\n        return float4(f / v0.x, f / v0.y, f / v0.z, f / v0.w);\n    }\n\n    ZetaInline constexpr uint3 operator+(uint3 v, uint32_t m)\n    {\n        return uint3(v.x + m, v.y + m, v.z + m);\n    }\n\n    ZetaInline constexpr uint3 operator*(uint3 v, uint32_t m)\n    {\n        return uint3(v.x * m, v.y * m, v.z * m);\n    }\n\n    ZetaInline constexpr uint3 operator>>(uint3 v, uint32_t m)\n    {\n        return uint3(v.x >> m, v.y >> m, v.z >> m);\n    }\n\n    ZetaInline constexpr uint3 operator^(uint3 v, uint3 m)\n    {\n        return uint3(v.x ^ m.x, v.y ^ m.y, v.z ^ m.z);\n    }\n}"
  },
  {
    "path": "Source/ZetaCore/Math/VectorFuncs.h",
    "content": "#pragma once\n\n#include \"Vector.h\"\n\n//--------------------------------------------------------------------------------------\n// Vector Functions\n//--------------------------------------------------------------------------------------\n\nnamespace ZetaRay::Math\n{\n    ZetaInline __m128 __vectorcall abs(const __m128 v)\n    {\n        // All bits are 0 except for the sign bit\n        const __m128 vMinusZero = _mm_set1_ps(-0.0f);\n\n        // Set the sign bit to 0\n        return _mm_andnot_ps(vMinusZero, v);\n    }\n\n    ZetaInline __m256 __vectorcall abs(const __m256 v)\n    {\n        // All bits are 0 except for the sign bit\n        const __m256 vMinusZero = _mm256_set1_ps(-0.0f);\n\n        // Set the sign bit to 0\n        return _mm256_andnot_ps(vMinusZero, v);\n    }\n\n    ZetaInline __m128 __vectorcall negate(const __m128 v)\n    {\n        // All bits are 0 except for the sign bit\n        const __m128 vMinusZero = _mm_set1_ps(-0.0f);\n\n        // Set the sign bit to 0\n        return _mm_xor_ps(vMinusZero, v);\n    }\n\n    // Returns v1 + t * (v2 - v1)\n    ZetaInline __m128 __vectorcall lerp(const __m128 v0, const __m128 v1, float t)\n    {\n        __m128 vT = _mm_broadcast_ss(&t);\n        // fma(t, v1, fma(-t, v0, v0));\n        __m128 vInterpolated = _mm_fmadd_ps(vT, v1, _mm_fnmadd_ps(vT, v0, v0));\n\n        return vInterpolated;\n    }\n\n    ZetaInline __m128 __vectorcall lerp(const __m128 v0, const __m128 v1, __m128 vT)\n    {\n        // fma(t, v1, fma(-t, v0, v0));\n        __m128 vInterpolated = _mm_fmadd_ps(vT, v1, _mm_fnmadd_ps(vT, v0, v0));\n\n        return vInterpolated;\n    }\n\n    ZetaInline __m128 __vectorcall length(const __m128 v)\n    {\n        __m128 vNorm2 = _mm_dp_ps(v, v, 0xff);\n        __m128 vNorm = _mm_sqrt_ps(vNorm2);\n\n        return vNorm;\n    }\n\n    ZetaInline __m128 __vectorcall normalize(const __m128 v)\n    {\n        __m128 vNorm2 = _mm_dp_ps(v, v, 0xff);\n        __m128 vN = _mm_div_ps(v, _mm_sqrt_ps(vNorm2));\n\n        return vN;\n    }\n\n    ZetaInline __m128 __vectorcall normalizeFast(const __m128 v)\n    {\n        __m128 vNorm2 = _mm_dp_ps(v, v, 0xff);\n        __m128 vN = _mm_mul_ps(v, _mm_rsqrt_ps(vNorm2));\n\n        return vN;\n    }\n\n    ZetaInline bool __vectorcall equal(const __m128 v1, const __m128 v2)\n    {\n        const __m128 vEps = _mm_set1_ps(FLT_EPSILON);\n        __m128 vRes = _mm_cmpgt_ps(vEps, abs(_mm_sub_ps(v1, v2)));\n        int r = _mm_movemask_ps(vRes);\n\n        return r == 0;\n    }\n\n    ZetaInline __m128 __vectorcall cross(const __m128 v1, const __m128 v2)\n    {\n        __m128 vTmp0 = _mm_shuffle_ps(v1, v1, 0x9);     // yzx\n        __m128 vTmp1 = _mm_shuffle_ps(v2, v2, 0x12);    // zxy\n\n        __m128 uCrossv = _mm_mul_ps(vTmp0, vTmp1);\n\n        vTmp0 = _mm_shuffle_ps(v1, v1, 0x12);   // zxy\n        vTmp1 = _mm_shuffle_ps(v2, v2, 0x9);    // yzx\n\n        uCrossv = _mm_sub_ps(uCrossv, _mm_mul_ps(vTmp0, vTmp1));\n\n        // zero out the last element\n        return _mm_blend_ps(uCrossv, _mm_setzero_ps(), 0x8);\n    }\n\n    ZetaInline __m128 __vectorcall saturate(__m128 v)\n    {\n        __m128 vOne = _mm_set1_ps(1.0f);\n        __m128 vS = _mm_max_ps(v, _mm_setzero_ps());\n        vS = _mm_min_ps(vS, vOne);\n\n        return vS;\n    }\n\n    ZetaInline __m128 __vectorcall sign(__m128 v)\n    {\n        __m128 vOnePos = _mm_set1_ps(1.0f);\n        __m128 vOneNeg = _mm_set1_ps(-1.0f);\n        __m128 vSign = _mm_blendv_ps(vOneNeg, vOnePos, _mm_cmpge_ps(v, _mm_setzero_ps()));\n\n        return vSign;\n    }\n\n    // Returns v.x + v.y + v.z in the 1st element of output.\n    // Note: Assumes fourth of element of v is zero.\n    ZetaInline __m128 __vectorcall hadd_float3(__m128 v)\n    {\n        __m128 vZ = _mm_movehl_ps(v, v);\n        __m128 vT = _mm_add_ps(v, vZ);\n        __m128 vSum = _mm_add_ss(vT, _mm_shuffle_ps(v, v, V_SHUFFLE_XYZW(1, 0, 0, 0)));\n\n        return vSum;\n    }\n\n    ZetaInline __m128 __vectorcall encode_octahedral(__m128 v)\n    {\n        __m128 vAbs = abs(v);\n        vAbs = hadd_float3(vAbs);\n        vAbs = _mm_shuffle_ps(vAbs, vAbs, V_SHUFFLE_XYZW(0, 0, 0, 0));\n        __m128 vEncodedPosZ = _mm_div_ps(v, vAbs);\n\n        __m128 vOne = _mm_set1_ps(1.0f);\n        __m128 vSign = sign(v);\n        __m128 vEncoded_yx = abs(_mm_shuffle_ps(vEncodedPosZ, vEncodedPosZ, V_SHUFFLE_XYZW(1, 0, 0, 0)));\n        __m128 vEncodedNegZ = _mm_sub_ps(vOne, vEncoded_yx);\n        vEncodedNegZ = _mm_mul_ps(vEncodedNegZ, vSign);\n\n        __m128 vZ = _mm_shuffle_ps(v, v, V_SHUFFLE_XYZW(2, 2, 2, 2));\n        __m128 vZLe0 = _mm_cmple_ps(vZ, _mm_setzero_ps());\n        // v.z <= 0.0 ? 1.0 - abs(v.yx) * SignNotZero(v) : v\n        __m128 vEncoded = _mm_blendv_ps(vEncodedPosZ, vEncodedNegZ, vZLe0);\n\n        return vEncoded;\n    }\n\n    ZetaInline __m128 __vectorcall decode_octahedral(__m128 u)\n    {\n        __m128 vAbs = abs(u);\n        vAbs = _mm_add_ps(vAbs, _mm_shuffle_ps(vAbs, vAbs, V_SHUFFLE_XYZW(1, 0, 0, 0)));\n\n        __m128 vOne = _mm_set1_ps(1.0f);\n        // First two elements are now equal to |u.x| + |u.y|\n        __m128 vZ = _mm_sub_ps(vOne, vAbs);\n\n        __m128 vPosT = saturate(negate(vZ));\n        __m128 vNegT = negate(vPosT);\n        __m128 vGt0 = _mm_cmpge_ps(u, _mm_setzero_ps());\n        __m128 vDecoded = _mm_blendv_ps(vPosT, vNegT, vGt0);\n        vDecoded = _mm_add_ps(u, vDecoded);\n        // Copy z and zero out the last element\n        vDecoded = _mm_insert_ps(vDecoded, vZ, 0x28);\n        vDecoded = normalize(vDecoded);\n\n        return vDecoded;\n    }\n\n    // Following is ported from DirectXMath (MIT License).\n    ZetaInline __m128 __vectorcall acos(const __m128 V)\n    {\n        __m128 nonnegative = _mm_cmpge_ps(V, _mm_setzero_ps());\n        __m128 mvalue = _mm_sub_ps(_mm_setzero_ps(), V);\n        __m128 x = _mm_max_ps(V, mvalue);  // |V|\n\n        // Compute (1-|V|), clamp to zero to avoid sqrt of negative number.\n        __m128 oneMValue = _mm_sub_ps(_mm_set1_ps(1.0f), x);\n        __m128 clampOneMValue = _mm_max_ps(_mm_setzero_ps(), oneMValue);\n        __m128 root = _mm_sqrt_ps(clampOneMValue);  // sqrt(1-|V|)\n\n        // Compute polynomial approximation\n        const __m128 AC1 = _mm_setr_ps(0.0308918810f, -0.0170881256f, 0.0066700901f, -0.0012624911f);\n        __m128 vConstants = _mm_shuffle_ps(AC1, AC1, _MM_SHUFFLE(3, 3, 3, 3));\n        __m128 t0 = _mm_mul_ps(vConstants, x);\n\n        vConstants = _mm_shuffle_ps(AC1, AC1, _MM_SHUFFLE(2, 2, 2, 2));\n        t0 = _mm_add_ps(t0, vConstants);\n        t0 = _mm_mul_ps(t0, x);\n\n        vConstants = _mm_shuffle_ps(AC1, AC1, _MM_SHUFFLE(1, 1, 1, 1));\n        t0 = _mm_add_ps(t0, vConstants);\n        t0 = _mm_mul_ps(t0, x);\n\n        vConstants = _mm_shuffle_ps(AC1, AC1, _MM_SHUFFLE(0, 0, 0, 0));\n        t0 = _mm_add_ps(t0, vConstants);\n        t0 = _mm_mul_ps(t0, x);\n\n        const __m128 AC0 = _mm_setr_ps(1.5707963050f, -0.2145988016f, +0.0889789874f, -0.0501743046f);\n        vConstants = _mm_shuffle_ps(AC0, AC0, _MM_SHUFFLE(3, 3, 3, 3));\n        t0 = _mm_add_ps(t0, vConstants);\n        t0 = _mm_mul_ps(t0, x);\n\n        vConstants = _mm_shuffle_ps(AC0, AC0, _MM_SHUFFLE(2, 2, 2, 2));\n        t0 = _mm_add_ps(t0, vConstants);\n        t0 = _mm_mul_ps(t0, x);\n\n        vConstants = _mm_shuffle_ps(AC0, AC0, _MM_SHUFFLE(1, 1, 1, 1));\n        t0 = _mm_add_ps(t0, vConstants);\n        t0 = _mm_mul_ps(t0, x);\n\n        vConstants = _mm_shuffle_ps(AC0, AC0, _MM_SHUFFLE(0, 0, 0, 0));\n        t0 = _mm_add_ps(t0, vConstants);\n        t0 = _mm_mul_ps(t0, root);\n\n        __m128 t1 = _mm_sub_ps(_mm_set1_ps(PI), t0);\n        t0 = _mm_and_ps(nonnegative, t0);\n        t1 = _mm_andnot_ps(nonnegative, t1);\n        t0 = _mm_or_ps(t0, t1);\n\n        return t0;\n    }\n\n    // Following is ported from DirectXMath (MIT License).\n    // vTheta must be in -XM_PI <= theta < XM_PI\n    ZetaInline __m128 __vectorcall sin(__m128 vTheta)\n    {\n#ifndef NDEBUG\n        __m128 vM1 = _mm_cmpge_ps(vTheta, _mm_set1_ps(-PI));\n        __m128 vM2 = _mm_cmpgt_ps(_mm_set1_ps(PI), vTheta);\n        __m128 vIsThetaValid = _mm_and_ps(vM1, vM2);\n\n        //int valid = _mm_movemask_ps(vIsThetaValid);\n        //Assert(valid == 0xf, \"Invalid theta value\");\n#endif\n\n        // Map in [-pi/2,pi/2] with sin(y) = sin(x).\n        __m128 sign = _mm_and_ps(vTheta, _mm_set1_ps(-0.0f));\n        __m128 c = _mm_or_ps(_mm_set1_ps(PI), sign);  // pi when x >= 0, -pi when x < 0\n        __m128 absx = _mm_andnot_ps(sign, vTheta);  // |x|\n        __m128 rflx = _mm_sub_ps(c, vTheta);\n        __m128 comp = _mm_cmple_ps(absx, _mm_set1_ps(PI_OVER_2));\n        __m128 select0 = _mm_and_ps(comp, vTheta);\n        __m128 select1 = _mm_andnot_ps(comp, rflx);\n        vTheta = _mm_or_ps(select0, select1);\n\n        __m128 x2 = _mm_mul_ps(vTheta, vTheta);\n\n        // Compute polynomial approximation\n        const __m128 SC1 = _mm_setr_ps(-2.3889859e-08f, -0.16665852f, +0.0083139502f, -0.00018524670f);\n        __m128 vConstants = _mm_shuffle_ps(SC1, SC1, _MM_SHUFFLE(0, 0, 0, 0));\n        __m128 Result = _mm_mul_ps(vConstants, x2);\n\n        const __m128 SC0 = _mm_setr_ps(-0.16666667f, +0.0083333310f, -0.00019840874f, +2.7525562e-06f);\n        vConstants = _mm_shuffle_ps(SC0, SC0, _MM_SHUFFLE(3, 3, 3, 3));\n        Result = _mm_add_ps(Result, vConstants);\n        Result = _mm_mul_ps(Result, x2);\n\n        vConstants = _mm_shuffle_ps(SC0, SC0, _MM_SHUFFLE(2, 2, 2, 2));\n        Result = _mm_add_ps(Result, vConstants);\n        Result = _mm_mul_ps(Result, x2);\n\n        vConstants = _mm_shuffle_ps(SC0, SC0, _MM_SHUFFLE(1, 1, 1, 1));\n        Result = _mm_add_ps(Result, vConstants);\n        Result = _mm_mul_ps(Result, x2);\n\n        vConstants = _mm_shuffle_ps(SC0, SC0, _MM_SHUFFLE(0, 0, 0, 0));\n        Result = _mm_add_ps(Result, vConstants);\n        Result = _mm_mul_ps(Result, x2);\n        Result = _mm_add_ps(Result, _mm_set1_ps(1.0f));\n        Result = _mm_mul_ps(Result, vTheta);\n\n        return Result;\n    }\n\n    ZetaInline float4a __vectorcall store(__m128 v)\n    {\n        float4a f;\n        _mm_store_ps(reinterpret_cast<float*>(&f), v);\n\n        return f;\n    }\n\n    ZetaInline float3 __vectorcall storeFloat3(__m128 v)\n    {\n        float3 f;\n        f.x = _mm_cvtss_f32(v);\n        f.y = _mm_cvtss_f32(_mm_shuffle_ps(v, v, V_SHUFFLE_XYZW(1, 0, 0, 0)));\n        f.z = _mm_cvtss_f32(_mm_shuffle_ps(v, v, V_SHUFFLE_XYZW(2, 0, 0, 0)));\n\n        return f;\n    }\n\n    ZetaInline float4 __vectorcall storeFloat4(__m128 v)\n    {\n        float4 f;\n        f.x = _mm_cvtss_f32(v);\n        f.y = _mm_cvtss_f32(_mm_shuffle_ps(v, v, V_SHUFFLE_XYZW(1, 0, 0, 0)));\n        f.z = _mm_cvtss_f32(_mm_shuffle_ps(v, v, V_SHUFFLE_XYZW(2, 0, 0, 0)));\n        f.w = _mm_cvtss_f32(_mm_shuffle_ps(v, v, V_SHUFFLE_XYZW(3, 0, 0, 0)));\n\n        return f;\n    }\n\n    ZetaInline __m128 __vectorcall load(float4a& v)\n    {\n        __m128 vV = _mm_load_ps(reinterpret_cast<float*>(&v));\n\n        return vV;\n    }\n\n    ZetaInline __m128 __vectorcall loadFloat2(float2& v)\n    {\n        // &v does not need to be aligned and the last two elements are set to 0\n        __m128 xy = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double*>(&v)));\n        return xy;\n    }\n\n    ZetaInline __m128 __vectorcall loadFloat3(float3& v)\n    {\n        // &v does not need to be aligned and the last two elements are set to 0\n        __m128 xy = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double*>(&v)));\n        // &v.z does not need to be aligned\n        __m128 z = _mm_load_ss(&v.z);\n        return _mm_insert_ps(xy, z, 0x20);\n    }\n\n    ZetaInline __m128 __vectorcall loadFloat4(float4& v)\n    {\n        return _mm_loadu_ps(reinterpret_cast<float*>(&v));\n    }\n\n    ZetaInline __m128 __vectorcall loadUNorm2(unorm2& v)\n    {\n        alignas(16) uint32_t unpacked[4] = { uint32_t(v.x), uint32_t(v.y), 0, 0 };\n\n        __m128 vV = _mm_cvtepi32_ps(_mm_load_si128(reinterpret_cast<__m128i*>(unpacked)));\n        vV = _mm_div_ps(vV, _mm_set1_ps((1 << 16) - 1));\n\n        return vV;\n    }\n}\n"
  },
  {
    "path": "Source/ZetaCore/Model/CMakeLists.txt",
    "content": "set(MODEL_DIR \"${ZETA_CORE_DIR}/Model\")\nset(MODEL_SRC\n    \"${MODEL_DIR}/glTF.cpp\"\n    \"${MODEL_DIR}/glTF.h\"\n    \"${MODEL_DIR}/glTFAsset.h\"\n    \"${MODEL_DIR}/Mesh.cpp\"\n    \"${MODEL_DIR}/Mesh.h\")\nset(MODEL_SRC ${MODEL_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaCore/Model/Mesh.cpp",
    "content": "#include \"Mesh.h\"\n#include \"../Math/Surface.h\"\n#include \"../Math/MatrixFuncs.h\"\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Model;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Math;\n\n//--------------------------------------------------------------------------------------\n// PrimitiveMesh\n//--------------------------------------------------------------------------------------\n\nvoid PrimitiveMesh::ComputeGrid(Util::Vector<Vertex>& vertices, Vector<uint32_t>& indices,\n    float width, float depth, uint32_t m, uint32_t n)\n{\n    vertices.clear();\n    indices.clear();\n\n    uint32_t vertexCount = m * n;\n    uint32_t faceCount = (m - 1) * (n - 1) * 2;\n\n    //\n    // Create the vertices.\n    //\n\n    float halfWidth = 0.5f * width;\n    float halfDepth = 0.5f * depth;\n\n    float dx = width / (n - 1);\n    float dz = depth / (m - 1);\n\n    float du = 1.0f / (n - 1);\n    float dv = 1.0f / (m - 1);\n\n    vertices.resize(vertexCount);\n    for (uint32_t i = 0; i < m; ++i)\n    {\n        float z = halfDepth - i * dz;\n        for (uint32_t j = 0; j < n; ++j)\n        {\n            float x = -halfWidth + j * dx;\n\n            vertices[i * n + j].Position = float3(x, 0.0f, z);\n            vertices[i * n + j].Normal = oct32(0.0f, 1.0f, 0.0f);\n            vertices[i * n + j].Tangent = oct32(1.0f, 0.0f, 0.0f);\n\n            // Stretch texture over grid.\n            vertices[i * n + j].TexUV.x = j * du;\n            vertices[i * n + j].TexUV.y = i * dv;\n        }\n    }\n\n    //\n    // Create the indices.\n    //\n\n    indices.resize(faceCount * 3); // 3 indices per face\n\n    // Iterate over each quad and compute indices.\n    uint32_t k = 0;\n    for (uint32_t i = 0; i < m - 1; ++i)\n    {\n        for (uint32_t j = 0; j < n - 1; ++j)\n        {\n            indices[k] = i * n + j;\n            indices[k + 1] = i * n + j + 1;\n            indices[k + 2] = (i + 1) * n + j;\n\n            indices[k + 3] = (i + 1) * n + j;\n            indices[k + 4] = i * n + j + 1;\n            indices[k + 5] = (i + 1) * n + j + 1;\n\n            k += 6; // next quad\n        }\n    }\n}\n\nvoid PrimitiveMesh::ComputeSphere(Vector<Vertex>& vertices, Vector<uint32_t>& indices,\n    float diameter, size_t tessellation)\n{\n    Assert(tessellation >= 3, \"tesselation parameter out of range\");\n\n    vertices.clear();\n    indices.clear();\n\n    size_t verticalSegments = tessellation;\n    size_t horizontalSegments = tessellation * 2;\n\n    float radius = diameter / 2;\n\n    // Create rings of vertices at progressively higher latitudes.\n    for (size_t i = 0; i <= verticalSegments; i++)\n    {\n        float v = 1 - float(i) / verticalSegments;\n\n        float latitude = (i * Math::PI / verticalSegments) - Math::PI_OVER_2;\n        float dy, dxz;\n\n        //XMScalarSinCos(&dy, &dxz, latitude);\n        dy = sinf(latitude);\n        dxz = cosf(latitude);\n\n        // Create a single ring of vertices at this latitude.\n        for (size_t j = 0; j <= horizontalSegments; j++)\n        {\n            float u = float(j) / horizontalSegments;\n\n            float longitude = j * Math::TWO_PI / horizontalSegments;\n            float dx, dz;\n\n            //XMScalarSinCos(&dx, &dz, longitude);\n            dx = sinf(longitude);\n            dz = cosf(longitude);\n\n            dx *= dxz;\n            dz *= dxz;\n\n            float3 normal(dx, dy, dz);\n            float2 textureCoordinate(u, v);\n            float3 tangent(0.0f, 0.0f, 0.0f);\n\n            vertices.emplace_back(normal * radius, textureCoordinate, oct32(normal), oct32(tangent));\n        }\n    }\n\n    // Fill the index buffer with triangles joining each pair of latitude rings.\n    size_t stride = horizontalSegments + 1;\n\n    for (size_t i = 0; i < verticalSegments; i++)\n    {\n        for (size_t j = 0; j <= horizontalSegments; j++)\n        {\n            size_t nextI = i + 1;\n            size_t nextJ = (j + 1) % stride;\n\n            indices.push_back((uint32_t)(i * stride + j));\n            indices.push_back((uint32_t)(i * stride + nextJ));\n            indices.push_back((uint32_t)(nextI * stride + j));\n\n            indices.push_back((uint32_t)(i * stride + nextJ));\n            indices.push_back((uint32_t)(nextI * stride + nextJ));\n            indices.push_back((uint32_t)(nextI * stride + j));\n        }\n    }\n\n    // compute the tangents\n    ComputeMeshTangentVectors(vertices, indices);\n}\n\nvoid PrimitiveMesh::ComputeCylinder(Vector<Vertex>& vertices, Vector<uint32_t>& indices,\n    float bottomRadius, float topRadius, float height, uint32_t sliceCount, uint32_t stackCount)\n{\n    vertices.clear();\n    indices.clear();\n\n    float stackHeight = height / stackCount;\n\n    // Amount to increment radius as we move up each stack level from bottom to top.\n    float radiusStep = (topRadius - bottomRadius) / stackCount;\n\n    uint32_t ringCount = stackCount + 1;\n\n    // Compute vertices for each stack ring starting at the bottom and moving up.\n    for (uint32_t i = 0; i < ringCount; ++i)\n    {\n        float y = -0.5f * height + i * stackHeight;\n        float r = bottomRadius + i * radiusStep;\n\n        // vertices of ring\n        float dTheta = Math::TWO_PI / sliceCount;\n        for (uint32_t j = 0; j <= sliceCount; ++j)\n        {\n            float c = cosf(j * dTheta);\n            float s = sinf(j * dTheta);\n\n            float3 pos(r * c, y, r * s);\n            float2 uv((float)j / sliceCount, 1.0f - (float)i / stackCount);\n\n            // Cylinder can be parameterized as follows, where we introduce v\n            // parameter that goes in the same direction as the v tex-coord\n            // so that the bitangent goes in the same direction as the v tex-coord.\n            //   Let r0 be the bottom radius and let r1 be the top radius.\n            //   y(v) = h - hv for v in [0,1].\n            //   r(v) = r1 + (r0-r1)v\n            //\n            //   x(t, v) = r(v)*cos(t)\n            //   y(t, v) = h - hv\n            //   z(t, v) = r(v)*sin(t)\n            // \n            //  dx/dt = -r(v)*sin(t)\n            //  dy/dt = 0\n            //  dz/dt = +r(v)*cos(t)\n            //\n            //  dx/dv = (r0-r1)*cos(t)\n            //  dy/dv = -h\n            //  dz/dv = (r0-r1)*sin(t)\n\n            // This is unit length.\n            float3 tangent(-s, 0.0f, c);\n\n            float dr = bottomRadius - topRadius;\n            float3 bitangent(dr * c, -height, dr * s);\n\n            float3 normal = tangent.cross(bitangent);\n            normal.normalize();\n\n            vertices.emplace_back(pos, uv, oct32(normal), oct32(tangent));\n        }\n    }\n\n    // Add one because we duplicate the first and last vertex per ring\n    // since the texture coordinates are different.\n    uint32_t ringVertexCount = sliceCount + 1;\n\n    // Compute indices for each stack.\n    for (uint32_t i = 0; i < stackCount; ++i)\n    {\n        for (uint32_t j = 0; j < sliceCount; ++j)\n        {\n            indices.push_back(i * ringVertexCount + j);\n            indices.push_back((i + 1) * ringVertexCount + j);\n            indices.push_back((i + 1) * ringVertexCount + j + 1);\n\n            indices.push_back(i * ringVertexCount + j);\n            indices.push_back((i + 1) * ringVertexCount + j + 1);\n            indices.push_back(i * ringVertexCount + j + 1);\n        }\n    }\n\n    // \n    // Build top cap.\n    //\n\n    uint32_t baseIndex = (uint32_t)vertices.size();\n\n    float y = 0.5f * height;\n    float dTheta = Math::TWO_PI / sliceCount;\n\n    // Duplicate cap ring vertices because the texture coordinates and normals differ.\n    for (uint32_t i = 0; i <= sliceCount; ++i)\n    {\n        float x = topRadius * cosf(i * dTheta);\n        float z = topRadius * sinf(i * dTheta);\n\n        // Scale down by the height to try and make top cap texture coord area\n        // proportional to base.\n        float u = x / height + 0.5f;\n        float v = z / height + 0.5f;\n\n        vertices.emplace_back(float3(x, y, z), float2(u, v), oct32(0.0f, 1.0f, 0.0f), oct32(1.0f, 0.0f, 0.0f));\n    }\n\n    // Cap center vertex.\n    vertices.emplace_back(float3(0.0f, y, 0.0f), float2(0.5f, 0.5f), oct32(0.0f, 1.0f, 0.0f), oct32(1.0f, 0.0f, 0.0f));\n\n    // Index of center vertex.\n    uint32_t centerIndex = (uint32_t)vertices.size() - 1;\n\n    for (uint32_t i = 0; i < sliceCount; ++i)\n    {\n        indices.push_back(centerIndex);\n        indices.push_back(baseIndex + i + 1);\n        indices.push_back(baseIndex + i);\n    }\n\n    // \n    // Build bottom cap.\n    //\n\n    baseIndex = (uint32_t)vertices.size();\n    y = -0.5f * height;\n\n    // vertices of ring\n    dTheta = Math::TWO_PI / sliceCount;\n    for (uint32_t i = 0; i <= sliceCount; ++i)\n    {\n        float x = bottomRadius * cosf(i * dTheta);\n        float z = bottomRadius * sinf(i * dTheta);\n\n        // Scale down by the height to try and make top cap texture coord area\n        // proportional to base.\n        float u = x / height + 0.5f;\n        float v = z / height + 0.5f;\n\n        vertices.emplace_back(float3(x, y, z), float2(u, v), oct32(0.0f, -1.0f, 0.0f), oct32(1.0f, 0.0f, 0.0f));\n    }\n\n    // Cap center vertex.\n    vertices.emplace_back(float3(0.0f, y, 0.0f), float2(0.5f, 0.5f), oct32(0.0f, -1.0f, 0.0f), oct32(1.0f, 0.0f, 0.0f));\n\n    // Cache the index of center vertex.\n    centerIndex = (uint32_t)vertices.size() - 1;\n\n    for (uint32_t i = 0; i < sliceCount; ++i)\n    {\n        indices.push_back(centerIndex);\n        indices.push_back(baseIndex + i);\n        indices.push_back(baseIndex + i + 1);\n    }\n}\n\nvoid PrimitiveMesh::ComputeCone(Vector<Vertex>& vertices, Vector<uint32_t>& indices,\n    float diameter, float height, size_t tessellation)\n{\n    Assert(tessellation >= 3, \"tesselation parameter out of range\");\n\n    vertices.clear();\n    indices.clear();\n\n    height /= 2;\n\n    float3 topOffset(0.0f, height, 0.0f);\n\n    float radius = diameter / 2;\n    size_t stride = tessellation + 1;\n\n    // Create a ring of triangles around the outside of the cone.\n    for (size_t i = 0; i <= tessellation; i++)\n    {\n        float angle = i * Math::TWO_PI / tessellation;\n\n        float3 circlevec(sinf(angle), 0, cosf(angle));\n        float3 sideOffset = circlevec * radius;\n\n        float u = float(i) / tessellation;\n\n        float3 pt = sideOffset - topOffset;\n\n        angle = (i * Math::TWO_PI / tessellation) + Math::PI_OVER_2;\n        float3 t(sinf(angle), 0.0f, cosf(angle));\n\n        float3 normal = t.cross(topOffset - pt);\n        normal.normalize();\n\n        // Duplicate the top vertex for distinct normals\n        vertices.emplace_back(topOffset, float2(0.0f, 0.0f), oct32(normal), oct32(0.0f, 0.0f, 0.0f));\n        vertices.emplace_back(pt, float2(u, 1.0f), oct32(normal), oct32(0.0f, 0.0f, 0.0f));\n\n        indices.push_back((uint32_t)(i * 2));\n        indices.push_back((uint32_t)((i * 2 + 3) % (stride * 2)));\n        indices.push_back((uint32_t)((i * 2 + 1) % (stride * 2)));\n    }\n\n    // Create flat triangle fan caps to seal the bottom.\n    //CreateCylinderCap(vertices, indices, tessellation, height, radius, false);\n\n    // Create cap indices.\n    for (size_t i = 0; i < tessellation - 2; i++)\n    {\n        size_t i1 = (i + 1) % tessellation;\n        size_t i2 = (i + 2) % tessellation;\n\n        size_t vbase = vertices.size();\n        indices.push_back((uint32_t)vbase);\n        indices.push_back((uint32_t)(vbase + i1));\n        indices.push_back((uint32_t)(vbase + i2));\n    }\n\n    // Which end of the cylinder is this?\n    float3 normal(0.0f, -1.0f, 0.0f);\n    float2 textureScale(0.5f, -0.5f);\n\n    // Create cap vertices.\n    for (size_t i = 0; i < tessellation; i++)\n    {\n        float angle = i * Math::TWO_PI / tessellation;\n        float3 circleVector(sinf(angle), 0.0f, cosf(angle));\n\n        float3 position = (circleVector * radius) + (normal * height);\n        float2 textureCoordinate = float2(circleVector.x, circleVector.y) * textureScale + float2(0.5f, 0.5f);\n\n        vertices.emplace_back(position, textureCoordinate, oct32(normal), oct32(0.0f, 0.0f, 0.0f));\n    }\n\n    // compute the tangents\n    ComputeMeshTangentVectors(vertices, indices);\n}\n\nvoid PrimitiveMesh::ComputeTorus(Vector<Vertex>& vertices, Vector<uint32_t>& indices,\n    float diameter, float thickness, size_t tessellation)\n{\n    vertices.clear();\n    indices.clear();\n\n    Assert(tessellation >= 3, \"tesselation parameter out of range\");\n\n    size_t stride = tessellation + 1;\n\n    // First we loop around the main ring of the torus.\n    for (size_t i = 0; i <= tessellation; i++)\n    {\n        float u = float(i) / tessellation;\n\n        float outerAngle = i * Math::TWO_PI / tessellation - Math::PI_OVER_2;\n\n        // Create a transform matrix that will align geometry to\n        // slice perpendicularly though the current ring position.\n        //XMMATRIX transform = XMMatrixTranslation(diameter / 2, 0, 0) * XMMatrixRotationY(outerAngle);\n        v_float4x4 vTransform = mul(translate(float4a(diameter / 2, 0.0f, 0.0f, 0.0f)), rotateY(outerAngle));\n\n        // Now we loop along the other axis, around the side of the tube.\n        for (size_t j = 0; j <= tessellation; j++)\n        {\n            float v = 1 - float(j) / tessellation;\n\n            float innerAngle = j * Math::TWO_PI / tessellation + Math::PI;\n\n            // Create a vertex.\n            float4a normal(cosf(innerAngle), sinf(innerAngle), 0.0f, 0.0f);\n            float thicknessDiv2 = (thickness / 2);\n            float4a position(normal.x * thicknessDiv2, normal.y * thicknessDiv2, normal.z * thicknessDiv2, 1.0f);\n            float2 textureCoordinate(u, v);\n\n            //position = XMVector3Transform(position, transform);\n            __m128 vPos = _mm_load_ps(reinterpret_cast<float*>(&position));\n            vPos = mul(vTransform, vPos);\n            _mm_store_ps(reinterpret_cast<float*>(&position), vPos);\n\n            //normal = XMVector3TransformNormal(normal, transform);\n            __m128 vN = _mm_load_ps(reinterpret_cast<float*>(&normal));\n            vN = mul(vTransform, vN);\n            vN = normalize(vN);\n            _mm_store_ps(reinterpret_cast<float*>(&normal), vN);\n\n            vertices.emplace_back(float3(position.x, position.y, position.z), textureCoordinate, \n                oct32(normal.x, normal.y, normal.z), oct32(0.0f, 0.0f, 0.0f));\n\n            // And create indices for two triangles.\n            size_t nextI = (i + 1) % stride;\n            size_t nextJ = (j + 1) % stride;\n\n            indices.push_back((uint32_t)(i * stride + j));\n            indices.push_back((uint32_t)(i * stride + nextJ));\n            indices.push_back((uint32_t)(nextI * stride + j));\n\n            indices.push_back((uint32_t)(i * stride + nextJ));\n            indices.push_back((uint32_t)(nextI * stride + nextJ));\n            indices.push_back((uint32_t)(nextI * stride + j));\n        }\n    }\n\n    // compute the tangents\n    ComputeMeshTangentVectors(vertices, indices);\n}\n\nnamespace\n{\n    const float3 TeapotControlPoints[] =\n    {\n        { 0, 0.345f, -0.05f },\n        { -0.028f, 0.345f, -0.05f },\n        { -0.05f, 0.345f, -0.028f },\n        { -0.05f, 0.345f, -0 },\n        { 0, 0.3028125f, -0.334375f },\n        { -0.18725f, 0.3028125f, -0.334375f },\n        { -0.334375f, 0.3028125f, -0.18725f },\n        { -0.334375f, 0.3028125f, -0 },\n        { 0, 0.3028125f, -0.359375f },\n        { -0.20125f, 0.3028125f, -0.359375f },\n        { -0.359375f, 0.3028125f, -0.20125f },\n        { -0.359375f, 0.3028125f, -0 },\n        { 0, 0.27f, -0.375f },\n        { -0.21f, 0.27f, -0.375f },\n        { -0.375f, 0.27f, -0.21f },\n        { -0.375f, 0.27f, -0 },\n        { 0, 0.13875f, -0.4375f },\n        { -0.245f, 0.13875f, -0.4375f },\n        { -0.4375f, 0.13875f, -0.245f },\n        { -0.4375f, 0.13875f, -0 },\n        { 0, 0.007499993f, -0.5f },\n        { -0.28f, 0.007499993f, -0.5f },\n        { -0.5f, 0.007499993f, -0.28f },\n        { -0.5f, 0.007499993f, -0 },\n        { 0, -0.105f, -0.5f },\n        { -0.28f, -0.105f, -0.5f },\n        { -0.5f, -0.105f, -0.28f },\n        { -0.5f, -0.105f, -0 },\n        { 0, -0.105f, 0.5f },\n        { 0, -0.2175f, -0.5f },\n        { -0.28f, -0.2175f, -0.5f },\n        { -0.5f, -0.2175f, -0.28f },\n        { -0.5f, -0.2175f, -0 },\n        { 0, -0.27375f, -0.375f },\n        { -0.21f, -0.27375f, -0.375f },\n        { -0.375f, -0.27375f, -0.21f },\n        { -0.375f, -0.27375f, -0 },\n        { 0, -0.2925f, -0.375f },\n        { -0.21f, -0.2925f, -0.375f },\n        { -0.375f, -0.2925f, -0.21f },\n        { -0.375f, -0.2925f, -0 },\n        { 0, 0.17625f, 0.4f },\n        { -0.075f, 0.17625f, 0.4f },\n        { -0.075f, 0.2325f, 0.375f },\n        { 0, 0.2325f, 0.375f },\n        { 0, 0.17625f, 0.575f },\n        { -0.075f, 0.17625f, 0.575f },\n        { -0.075f, 0.2325f, 0.625f },\n        { 0, 0.2325f, 0.625f },\n        { 0, 0.17625f, 0.675f },\n        { -0.075f, 0.17625f, 0.675f },\n        { -0.075f, 0.2325f, 0.75f },\n        { 0, 0.2325f, 0.75f },\n        { 0, 0.12f, 0.675f },\n        { -0.075f, 0.12f, 0.675f },\n        { -0.075f, 0.12f, 0.75f },\n        { 0, 0.12f, 0.75f },\n        { 0, 0.06375f, 0.675f },\n        { -0.075f, 0.06375f, 0.675f },\n        { -0.075f, 0.007499993f, 0.75f },\n        { 0, 0.007499993f, 0.75f },\n        { 0, -0.04875001f, 0.625f },\n        { -0.075f, -0.04875001f, 0.625f },\n        { -0.075f, -0.09562501f, 0.6625f },\n        { 0, -0.09562501f, 0.6625f },\n        { -0.075f, -0.105f, 0.5f },\n        { -0.075f, -0.18f, 0.475f },\n        { 0, -0.18f, 0.475f },\n        { 0, 0.02624997f, -0.425f },\n        { -0.165f, 0.02624997f, -0.425f },\n        { -0.165f, -0.18f, -0.425f },\n        { 0, -0.18f, -0.425f },\n        { 0, 0.02624997f, -0.65f },\n        { -0.165f, 0.02624997f, -0.65f },\n        { -0.165f, -0.12375f, -0.775f },\n        { 0, -0.12375f, -0.775f },\n        { 0, 0.195f, -0.575f },\n        { -0.0625f, 0.195f, -0.575f },\n        { -0.0625f, 0.17625f, -0.6f },\n        { 0, 0.17625f, -0.6f },\n        { 0, 0.27f, -0.675f },\n        { -0.0625f, 0.27f, -0.675f },\n        { -0.0625f, 0.27f, -0.825f },\n        { 0, 0.27f, -0.825f },\n        { 0, 0.28875f, -0.7f },\n        { -0.0625f, 0.28875f, -0.7f },\n        { -0.0625f, 0.2934375f, -0.88125f },\n        { 0, 0.2934375f, -0.88125f },\n        { 0, 0.28875f, -0.725f },\n        { -0.0375f, 0.28875f, -0.725f },\n        { -0.0375f, 0.298125f, -0.8625f },\n        { 0, 0.298125f, -0.8625f },\n        { 0, 0.27f, -0.7f },\n        { -0.0375f, 0.27f, -0.7f },\n        { -0.0375f, 0.27f, -0.8f },\n        { 0, 0.27f, -0.8f },\n        { 0, 0.4575f, -0 },\n        { 0, 0.4575f, -0.2f },\n        { -0.1125f, 0.4575f, -0.2f },\n        { -0.2f, 0.4575f, -0.1125f },\n        { -0.2f, 0.4575f, -0 },\n        { 0, 0.3825f, -0 },\n        { 0, 0.27f, -0.35f },\n        { -0.196f, 0.27f, -0.35f },\n        { -0.35f, 0.27f, -0.196f },\n        { -0.35f, 0.27f, -0 },\n        { 0, 0.3075f, -0.1f },\n        { -0.056f, 0.3075f, -0.1f },\n        { -0.1f, 0.3075f, -0.056f },\n        { -0.1f, 0.3075f, -0 },\n        { 0, 0.3075f, -0.325f },\n        { -0.182f, 0.3075f, -0.325f },\n        { -0.325f, 0.3075f, -0.182f },\n        { -0.325f, 0.3075f, -0 },\n        { 0, 0.27f, -0.325f },\n        { -0.182f, 0.27f, -0.325f },\n        { -0.325f, 0.27f, -0.182f },\n        { -0.325f, 0.27f, -0 },\n        { 0, -0.33f, -0 },\n        { -0.1995f, -0.33f, -0.35625f },\n        { 0, -0.31125f, -0.375f },\n        { 0, -0.33f, -0.35625f },\n        { -0.35625f, -0.33f, -0.1995f },\n        { -0.375f, -0.31125f, -0 },\n        { -0.35625f, -0.33f, -0 },\n        { -0.21f, -0.31125f, -0.375f },\n        { -0.375f, -0.31125f, -0.21f },\n    };\n\n    struct TeapotPatch\n    {\n        bool mirrorZ;\n        int indices[16];\n    };\n\n    const TeapotPatch TeapotPatches[] =\n    {\n        // Rim.\n        { true, { 102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },\n\n        // Body.\n        { true, { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 } },\n        { true, { 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 } },\n\n        // Lid.\n        { true, { 96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, 101, 0, 1, 2, 3 } },\n        { true, { 0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117 } },\n\n        // Handle.\n        { false, { 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56 } },\n        { false, { 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 28, 65, 66, 67 } },\n\n        // Spout.\n        { false, { 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83 } },\n        { false, { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95 } },\n\n        // Bottom.\n        { true, { 118, 118, 118, 118, 124, 122, 119, 121, 123, 126, 125, 120, 40, 39, 38, 37 } },\n    };\n\n    float3 CubicInterpolate(float3 p1, float3 p2, float3 p3, float3 p4, float t)\n    {\n        float T0 = (1 - t) * (1 - t) * (1 - t);\n        float T1 = 3 * t * (1 - t) * (1 - t);\n        float T2 = 3 * t * t * (1 - t);\n        float T3 = t * t * t;\n\n        float3 result = p1 * T0 + p2 * T1 + p3 * T2 + p4 * T3;\n\n        return result;\n    }\n\n    float3 CubicTangent(float3 p1, float3 p2, float3 p3, float3 p4, float t)\n    {\n        return p1 * (-1 + 2 * t - t * t) +\n            p2 * (1 - 4 * t + 3 * t * t) +\n            p3 * (2 * t - 3 * t * t) +\n            p4 * (t * t);\n    }\n\n    void CreatePatchVertices(Vector<Vertex>& vertices, float3 patch[16],\n        size_t tessellation, bool isMirrored)\n    {\n        for (size_t i = 0; i <= tessellation; i++)\n        {\n            float u = float(i) / tessellation;\n\n            for (size_t j = 0; j <= tessellation; j++)\n            {\n                float v = float(j) / tessellation;\n\n                // Perform four horizontal bezier interpolations\n                // between the control points of this patch.\n                float3 p1 = CubicInterpolate(patch[0], patch[1], patch[2], patch[3], u);\n                float3 p2 = CubicInterpolate(patch[4], patch[5], patch[6], patch[7], u);\n                float3 p3 = CubicInterpolate(patch[8], patch[9], patch[10], patch[11], u);\n                float3 p4 = CubicInterpolate(patch[12], patch[13], patch[14], patch[15], u);\n\n                // Perform a vertical interpolation between the results of the\n                // previous horizontal interpolations, to compute the position.\n                float3 position = CubicInterpolate(p1, p2, p3, p4, v);\n\n                // Perform another four bezier interpolations between the control\n                // points, but this time vertically rather than horizontally.\n                float3 q1 = CubicInterpolate(patch[0], patch[4], patch[8], patch[12], v);\n                float3 q2 = CubicInterpolate(patch[1], patch[5], patch[9], patch[13], v);\n                float3 q3 = CubicInterpolate(patch[2], patch[6], patch[10], patch[14], v);\n                float3 q4 = CubicInterpolate(patch[3], patch[7], patch[11], patch[15], v);\n\n                // Compute vertical and horizontal tangent vectors.\n                float3 tangent1 = CubicTangent(p1, p2, p3, p4, v);\n                float3 tangent2 = CubicTangent(q1, q2, q3, q4, u);\n\n                // Cross the two tangent vectors to compute the normal.\n                float3 normal = tangent1.cross(tangent2);\n\n                //if (!XMVector3NearEqual(normal, XMVectorZero(), g_XMEpsilon))\n                if (fabsf(normal.x) > FLT_EPSILON || fabsf(normal.y) > FLT_EPSILON || fabsf(normal.z) > FLT_EPSILON)\n                {\n                    normal.normalize();\n\n                    // If this patch is mirrored, we must invert the normal.\n                    if (isMirrored)\n                    {\n                        normal = -normal;\n                    }\n                }\n                else\n                {\n                    // In a tidy and well constructed bezier patch, the preceding\n                    // normal computation will always work. But the classic teapot\n                    // model is not tidy or well constructed! At the top and bottom\n                    // of the teapot, it contains degenerate geometry where a patch\n                    // has several control points in the same place, which causes\n                    // the tangent computation to fail and produce a zero normal.\n                    // We 'fix' these cases by just hard-coding a normal that points\n                    // either straight up or straight down, depending on whether we\n                    // are on the top or bottom of the teapot. This is not a robust\n                    // solution for all possible degenerate bezier patches, but hey,\n                    // it's good enough to make the teapot work correctly!\n\n                    // { 0.0f, 1.0f, 0.0f, 0.0f }\n                    // { 0.0f, -1.0f, 0.0f, 0.0f }\n                    //normal = XMVectorSelect(g_XMIdentityR1, g_XMNegIdentityR1, XMVectorLess(position, XMVectorZero()));\n\n                    if (position.y < 0.0f)\n                        normal = float3(0.0f, -1.0f, 0.0f);\n                    else\n                        normal = float3(0.0f, 1.0f, 0.0f);\n                }\n\n                // Compute the texture coordinate.\n                float mirroredU = isMirrored ? 1 - u : u;\n                float2 textureCoordinate(mirroredU, v);\n\n                // Output this vertex.\n                vertices.emplace_back(position, textureCoordinate, oct32(-normal), oct32(0.0f, 0.0f, 0.0f));\n            }\n        }\n    }\n\n    void CreatePatchIndices(Vector<uint32_t>& indices, size_t vbase, size_t tessellation, bool isMirrored)\n    {\n        size_t stride = tessellation + 1;\n\n        for (size_t i = 0; i < tessellation; i++)\n        {\n            for (size_t j = 0; j < tessellation; j++)\n            {\n                // Make a list of six index values (two triangles).\n                size_t indexVals[6] =\n                {\n                    // [had to reorder the indices from 0, 1, 2 to 0, 2, 1]\n                    i * stride + j,\n                    (i + 1) * stride + j + 1,\n                    (i + 1) * stride + j,\n\n                    // [had to reorder the indices from 0, 1, 2 to 0, 2, 1]\n                    i * stride + j,\n                    i * stride + j + 1,\n                    (i + 1) * stride + j + 1,\n                };\n\n                // If this patch is mirrored, reverse indices to fix the winding order.\n                //if (isMirrored)\n                //{\n                //    std::reverse(indices.begin(), indices.end());\n                //}\n\n                // Output these index values.\n                if (!isMirrored)\n                {\n                    for (int k = 0; k < 6; k++)\n                        indices.push_back((uint32_t)(vbase + indexVals[k]));\n                }\n                else\n                {\n                    for (int k = 5; k >= 0; k--)\n                        indices.push_back((uint32_t)(vbase + indexVals[k]));\n                }\n            }\n        }\n    }\n\n    // Tessellates the specified bezier patch.\n    void TessellatePatch(Vector<Vertex>& vertices, Vector<uint32_t>& indices,\n        const TeapotPatch& patch, size_t tessellation, float3 scale, bool isMirrored)\n    {\n        // Look up the 16 control points for this patch.\n        float3 controlPoints[16];\n\n        for (int i = 0; i < 16; i++)\n        {\n            controlPoints[i] = TeapotControlPoints[patch.indices[i]] * scale;\n        }\n\n        // Create the index data.\n        size_t vbase = vertices.size();\n        CreatePatchIndices(indices, vbase, tessellation, isMirrored);\n\n        // Create the vertex data.\n        CreatePatchVertices(vertices, controlPoints, tessellation, isMirrored);\n    }\n}\n\nvoid PrimitiveMesh::ComputeTeapot(Vector<Vertex>& vertices, Vector<uint32_t>& indices,\n    float size, size_t tessellation)\n{\n    vertices.clear();\n    indices.clear();\n\n    Assert(tessellation >= 1, \"tesselation parameter out of range\");\n\n    float3 scaleNegateX = size * float3(-1.0f, 1.0f, 1.0f);\n    float3 scaleNegateZ = size * float3(1.0f, 1.0f, -1.0f);\n    float3 scaleNegateXZ = size * float3(-1.0f, 1.0f, -1.0f);\n\n    for (size_t i = 0; i < sizeof(TeapotPatches) / sizeof(TeapotPatch); i++)\n    {\n        TeapotPatch const& patch = TeapotPatches[i];\n\n        // Because the teapot is symmetrical from left to right, we only store\n        // data for one side, then tessellate each patch twice, mirroring in X.\n        TessellatePatch(vertices, indices, patch, tessellation, float3(size, size, size), false);\n        TessellatePatch(vertices, indices, patch, tessellation, scaleNegateX, true);\n\n        if (patch.mirrorZ)\n        {\n            // Some parts of the teapot (the body, lid, and rim, but not the\n            // handle or spout) are also symmetrical from front to back, so\n            // we tessellate them four times, mirroring in Z as well as X.\n            TessellatePatch(vertices, indices, patch, tessellation, scaleNegateZ, true);\n            TessellatePatch(vertices, indices, patch, tessellation, scaleNegateXZ, false);\n        }\n    }\n}\n"
  },
  {
    "path": "Source/ZetaCore/Model/Mesh.h",
    "content": "#pragma once\n\n#include \"../Math/CollisionFuncs.h\"\n#include \"../Core/Vertex.h\"\n#include \"../Utility/Span.h\"\n\nnamespace ZetaRay::Model\n{\n    enum class RT_MESH_MODE\n    {\n        // Slow build time but fastest possible trace time\n        STATIC = 0,\n\n        // Dynamic mesh that only needs to update its world transform and doesn't need rebuilds\n        DYNAMIC_NO_REBUILD,\n\n        // Dynamic mesh that needs rebuild (due to e.g. change in number of vertices or topology)\n        //DYNAMIC_REBUILD,\n    };\n\n    struct TriangleMesh\n    {\n        TriangleMesh() = default;\n        TriangleMesh(Util::Span<Core::Vertex> vertices,\n            uint32_t vtxBuffStartOffset,\n            uint32_t idxBuffStartOffset,\n            uint32_t numIndices,\n            uint32_t matID)\n            : m_numVertices((uint32_t)vertices.size()),\n            m_numIndices(numIndices),\n            m_materialID(matID),\n            m_vtxBuffStartOffset(vtxBuffStartOffset),\n            m_idxBuffStartOffset(idxBuffStartOffset)\n        {\n            Assert(vertices.size() < UINT_MAX, \"Number of vertices exceeded maximum allowed.\");\n\n            Math::v_AABB vBox = Math::compueMeshAABB(vertices.data(), offsetof(Core::Vertex, Position),\n                sizeof(Core::Vertex), m_numVertices);\n            m_AABB = Math::store(vBox);\n        }\n\n        uint32_t m_vtxBuffStartOffset;\n        uint32_t m_idxBuffStartOffset;\n        uint32_t m_materialID;\n        uint32_t m_numVertices;\n        uint32_t m_numIndices;\n        Math::AABB m_AABB;\n    };\n\n    static_assert(std::is_trivially_default_constructible_v<TriangleMesh>);\n\n    // Ref: DirectXTK12 library (MIT License), available from:\n    // https://github.com/microsoft/DirectXTK12\n    namespace PrimitiveMesh\n    {\n        void ComputeSphere(Util::Vector<Core::Vertex, Support::SystemAllocator>& vertices, \n            Util::Vector<uint32_t, Support::SystemAllocator>& indices,\n            float diameter, size_t tessellation);\n        void ComputeCylinder(Util::Vector<Core::Vertex, Support::SystemAllocator>& vertices, \n            Util::Vector<uint32_t, Support::SystemAllocator>& indices,\n            float bottomRadius, float topRadius, float height, uint32_t sliceCount, uint32_t stackCount);\n        void ComputeCone(Util::Vector<Core::Vertex, Support::SystemAllocator>& vertices, \n            Util::Vector<uint32_t, Support::SystemAllocator>& indices,\n            float diameter, float height, size_t tessellation);\n        void ComputeTorus(Util::Vector<Core::Vertex, Support::SystemAllocator>& vertices, \n            Util::Vector<uint32_t, Support::SystemAllocator>& indices,\n            float diameter, float thickness, size_t tessellation);\n        void ComputeTeapot(Util::Vector<Core::Vertex, Support::SystemAllocator>& vertices, \n            Util::Vector<uint32_t, Support::SystemAllocator>& indices,\n            float size, size_t tessellation);\n        void ComputeGrid(Util::Vector<Core::Vertex, Support::SystemAllocator>& vertices, \n            Util::Vector<uint32_t, Support::SystemAllocator>& indices,\n            float width, float depth, uint32_t m, uint32_t n);\n    }\n}\n"
  },
  {
    "path": "Source/ZetaCore/Model/glTF.cpp",
    "content": "#include \"glTF.h\"\n#include \"../Math/MatrixFuncs.h\"\n#include \"../Math/Surface.h\"\n#include \"../Math/Quaternion.h\"\n#include \"../Scene/SceneCore.h\"\n#include \"../Support/Task.h\"\n#include \"../App/Log.h\"\n#include \"../Utility/Utility.h\"\n#include <algorithm>\n\n#define CGLTF_IMPLEMENTATION\n#include <cgltf/cgltf.h>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Model;\nusing namespace ZetaRay::App;\nusing namespace ZetaRay::Model::glTF::Asset;\nusing namespace ZetaRay::Core::Direct3DUtil;\n\n#define CHECK_QUATERNION_VALID 0\n\n//--------------------------------------------------------------------------------------\n// glTF\n//--------------------------------------------------------------------------------------\n\nnamespace\n{\n    ZetaInline const char* GetErrorMsg(cgltf_result r)\n    {\n        switch (r)\n        {\n        case cgltf_result_data_too_short:\n            return \"cgltf_result_data_too_short\";\n        case cgltf_result_unknown_format:\n            return \"cgltf_result_unknown_format\";\n        case cgltf_result_invalid_json:\n            return \"cgltf_result_invalid_json\";\n        case cgltf_result_invalid_gltf:\n            return \"cgltf_result_invalid_gltf\";\n        case cgltf_result_invalid_options:\n            return \"cgltf_result_invalid_options\";\n        case cgltf_result_file_not_found:\n            return \"cgltf_result_file_not_found\";\n        case cgltf_result_io_error:\n            return \"cgltf_result_io_error\";\n        case cgltf_result_out_of_memory:\n            return \"cgltf_result_out_of_memory\";\n        case cgltf_result_legacy_gltf:\n            return \"cgltf_result_legacy_gltf\";\n        default:\n            return \"unknown error\";\n        }\n    }\n\n#ifndef Checkgltf\n#define Checkgltf(expr)                                                                                                           \\\n    {                                                                                                                             \\\n        cgltf_result r = (expr);                                                                                                  \\\n        if (r != cgltf_result_success)                                                                                            \\\n        {                                                                                                                         \\\n            char buff_[256];                                                                                                      \\\n            int n_ = stbsp_snprintf(buff_, 256, \"cgltf call failed at %s: %d\\nError: %s\", __FILE__, __LINE__, GetErrorMsg(r));    \\\n            ZetaRay::Util::ReportError(\"Fatal Error\", buff_);                                                                     \\\n            ZetaRay::Util::DebugBreak();                                                                                          \\\n        }                                                                                                                         \\\n    }\n#endif\n\n    ZetaInline Texture::ID_TYPE IDFromTexturePath(const Filesystem::Path& texPath)\n    {\n        return XXH3_64_To_32(XXH3_64bits(texPath.Get(), texPath.Length()));\n    }\n\n    // Remember every emissive mesh primitive\n    struct EmissiveMeshPrim\n    {\n        uint64_t MeshID;\n        uint32_t BaseVtxOffset;\n        uint32_t BaseIdxOffset;\n        uint32_t NumIndices;\n        int MaterialIdx;\n    };\n\n    struct ThreadContext\n    {\n        const App::Filesystem::Path* glTFPath;\n        uint32_t SceneID;\n        cgltf_data* Model;\n\n        SmallVector<Vertex> Vertices;\n        SmallVector<uint32_t> Indices;\n        SmallVector<Mesh> Meshes;\n        // All unique textures that need to be loaded from disk\n        SmallVector<Texture> DDSImages;\n        SmallVector<EmissiveMeshPrim> EmissiveMeshPrims;\n        SmallVector<EmissiveInstance> EmissiveInstances;\n        SmallVector<RT::EmissiveTriangle> RTEmissives;\n\n        int NumMeshWorkers;\n        int NumImgWorkers;\n        size_t* MeshThreadOffsets;\n        size_t* MeshThreadSizes;\n        size_t* ImgThreadOffsets;\n        size_t* ImgThreadSizes;\n        uint32_t* EmissiveMeshPrimCountPerWorker;\n\n        std::atomic_uint32_t CurrVtxOffset = 0;\n        std::atomic_uint32_t CurrIdxOffset = 0;\n        std::atomic_uint32_t CurrMeshPrimOffset = 0;\n        int NumEmissiveMeshPrims = 0;\n        int NumEmissiveInstances = 0;\n        uint32_t NumEmissiveTris = 0;\n    };\n\n    void ResetEmissiveSubsets(MutableSpan<EmissiveMeshPrim> subsets)\n    {\n        if (subsets.empty())\n            return;\n\n        const int numTotalBytes = (int)subsets.size() * sizeof(EmissiveMeshPrim);\n        const int numSimdBytes = numTotalBytes >> 5;\n        const int numRemainingBytes = numTotalBytes & 31;\n        int numToSetManually = numRemainingBytes > 0 ? Math::CeilUnsignedIntDiv(numRemainingBytes, \n            (int)sizeof(EmissiveMeshPrim)) : 0;\n\n        uintptr_t ptr = reinterpret_cast<uintptr_t>(subsets.data());\n        __m256i vVal = _mm256_set1_epi64x(Scene::INVALID_MESH);\n\n        for (int i = 0; i < numSimdBytes; i++)\n        {\n            _mm256_storeu_si256((__m256i*) ptr, vVal);\n            ptr += 32;\n        }\n\n        for (int i = 0; i < numToSetManually; i++)\n            subsets[subsets.size() - 1 - i].MeshID = Scene::INVALID_MESH;\n    }\n\n    void ProcessPositions(const cgltf_data& model, const cgltf_accessor& accessor, \n        MutableSpan<Vertex> vertices, uint32_t baseOffset)\n    {\n        Check(accessor.type == cgltf_type_vec3, \"Invalid type for POSITION attribute.\");\n        Check(accessor.component_type == cgltf_component_type_r_32f,\n            \"Invalid component type for POSITION attribute.\");\n\n        const cgltf_buffer_view& bufferView = *accessor.buffer_view;\n        Check(accessor.stride == sizeof(float3), \"Invalid stride for POSITION attribute.\");\n\n        const cgltf_buffer& buffer = *bufferView.buffer;\n        const float3* start = reinterpret_cast<float3*>(reinterpret_cast<uintptr_t>(\n            buffer.data) + bufferView.offset + accessor.offset);\n\n        for (size_t i = 0; i < accessor.count; i++)\n        {\n            const float3* curr = start + i;\n\n            // glTF uses a right-handed coordinate system with +Y as up\n            vertices[baseOffset + i].Position = float3(curr->x, curr->y, -curr->z);\n        }\n    }\n\n    void ProcessNormals(const cgltf_data& model, const cgltf_accessor& accessor, \n        MutableSpan<Vertex> vertices, uint32_t baseOffset)\n    {\n        Check(accessor.type == cgltf_type_vec3, \"Invalid type for NORMAL attribute.\");\n        Check(accessor.component_type == cgltf_component_type_r_32f,\n            \"Invalid component type for NORMAL attribute.\");\n\n        const cgltf_buffer_view& bufferView = *accessor.buffer_view;\n        Check(accessor.stride == sizeof(float3), \"Invalid stride for NORMAL attribute.\");\n\n        const cgltf_buffer& buffer = *bufferView.buffer;\n        const float3* start = reinterpret_cast<float3*>(reinterpret_cast<uintptr_t>(\n            buffer.data) + bufferView.offset + accessor.offset);\n\n        for (size_t i = 0; i < accessor.count; i++)\n        {\n            const float3* curr = start + i;\n\n            // glTF uses a right-handed coordinate system with +Y as up\n            vertices[baseOffset + i].Normal = oct32(curr->x, curr->y, -curr->z);\n        }\n    }\n\n    void ProcessTexCoords(const cgltf_data& model, const cgltf_accessor& accessor, \n        MutableSpan<Vertex> vertices, uint32_t baseOffset)\n    {\n        Check(accessor.type == cgltf_type_vec2, \"Invalid type for TEXCOORD_0 attribute.\");\n        Check(accessor.component_type == cgltf_component_type_r_32f,\n            \"Invalid component type for TEXCOORD_0 attribute.\");\n\n        const cgltf_buffer_view& bufferView = *accessor.buffer_view;\n        Check(accessor.stride == sizeof(float2), \"Invalid stride for TEXCOORD_0 attribute.\");\n\n        const cgltf_buffer& buffer = *bufferView.buffer;\n        const float2* start = reinterpret_cast<float2*>(reinterpret_cast<uintptr_t>(\n            buffer.data) + bufferView.offset + accessor.offset);\n\n        for (size_t i = 0; i < accessor.count; i++)\n        {\n            const float2* curr = start + i;\n            vertices[baseOffset + i].TexUV = float2(curr->x, curr->y);\n        }\n    }\n\n    void ProcessTangents(const cgltf_data& model, const cgltf_accessor& accessor, \n        MutableSpan<Vertex> vertices, uint32_t baseOffset)\n    {\n        Check(accessor.type == cgltf_type_vec4, \"Invalid type for TANGENT attribute.\");\n        Check(accessor.component_type == cgltf_component_type_r_32f,\n            \"Invalid component type for TANGENT attribute.\");\n\n        const cgltf_buffer_view& bufferView = *accessor.buffer_view;\n\n        const cgltf_buffer& buffer = *bufferView.buffer;\n        const float4* start = reinterpret_cast<float4*>(reinterpret_cast<uintptr_t>(\n            buffer.data) + bufferView.offset + accessor.offset);\n\n        for (size_t i = 0; i < accessor.count; i++)\n        {\n            const float4* curr = start + i;\n\n            // glTF uses a right-handed coordinate system with +Y as up\n            vertices[baseOffset + i].Tangent = oct32(curr->x, curr->y, -curr->z);\n        }\n    }\n\n    void ProcessIndices(const cgltf_data& model, const cgltf_accessor& accessor, \n        MutableSpan<uint32_t> indices, uint32_t baseOffset)\n    {\n        Check(accessor.type == cgltf_type_scalar, \"Invalid index type.\");\n        Check(accessor.stride != -1, \"Invalid index stride.\");\n        Check(accessor.count % 3 == 0, \"Invalid number of indices.\");\n\n        const cgltf_buffer_view& bufferView = *accessor.buffer_view;\n        const cgltf_buffer& buffer = *bufferView.buffer;\n\n        // Populate the mesh indices\n        uint8_t* curr = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(buffer.data) + bufferView.offset + accessor.offset);\n        const size_t numFaces = accessor.count / 3;\n        const size_t indexStrideInBytes = accessor.stride;\n        size_t currIdxOffset = 0;\n\n        for (size_t face = 0; face < numFaces; face++)\n        {\n            uint32_t i0 = 0;\n            uint32_t i1 = 0;\n            uint32_t i2 = 0;\n\n            memcpy(&i0, curr, indexStrideInBytes);\n            curr += indexStrideInBytes;\n            memcpy(&i1, curr, indexStrideInBytes);\n            curr += indexStrideInBytes;\n            memcpy(&i2, curr, indexStrideInBytes);\n            curr += indexStrideInBytes;\n\n            // Use clockwise ordering\n            indices[baseOffset + currIdxOffset++] = i0;\n            indices[baseOffset + currIdxOffset++] = i2;\n            indices[baseOffset + currIdxOffset++] = i1;\n        }\n    }\n\n    void ProcessMeshes(const cgltf_data& model, uint32_t sceneID, size_t offset, size_t size,\n        MutableSpan<Vertex> vertices, std::atomic_uint32_t& vertexCounter,\n        MutableSpan<uint32_t> indices, std::atomic_uint32_t& idxCounter,\n        MutableSpan<Mesh> meshes, std::atomic_uint32_t& meshCounter,\n        MutableSpan<EmissiveMeshPrim> emissivesPrims, uint32_t& emissivePrimCount)\n    {\n        SceneCore& scene = App::GetScene();\n        uint32_t totalPrims = 0;\n        uint32_t totalVertices = 0;\n        uint32_t totalIndices = 0;\n        int numEmissiveMeshPrims = 0;\n\n        // Count total number of primitives, vertices, and indices.\n        for (size_t meshIdx = offset; meshIdx != offset + size; meshIdx++)\n        {\n            Assert(meshIdx < model.meshes_count, \"Out-of-bound access\");\n            const cgltf_mesh& mesh = model.meshes[meshIdx];\n\n            for (int primIdx = 0; primIdx < mesh.primitives_count; primIdx++)\n            {\n                const cgltf_primitive& prim = mesh.primitives[primIdx];\n\n                Check(prim.indices->count > 0, \"Index buffer is required.\");\n                Check(prim.type == cgltf_primitive_type_triangles, \"Non-triangle meshes are not supported.\");\n\n                int posIt = -1;\n\n                for (int attrib = 0; attrib < prim.attributes_count; attrib++)\n                {\n                    if (strcmp(prim.attributes[attrib].name, \"POSITION\") == 0)\n                    {\n                        posIt = attrib;\n                        break;\n                    }\n                }\n\n                Check(posIt != -1, \"POSITION was not found in the vertex attributes.\");\n\n                const cgltf_accessor& accessor = *prim.attributes[posIt].data;\n                const uint32_t numVertices = (uint32_t)accessor.count;\n                totalVertices += numVertices;\n\n                const uint32_t numIndices = (uint32_t)prim.indices->count;\n                totalIndices += numIndices;\n            }\n\n            totalPrims += (uint32_t)mesh.primitives_count;\n        }\n\n        // (sub)allocate\n        const uint32_t workerBaseVtxOffset = vertexCounter.fetch_add(totalVertices, std::memory_order_relaxed);\n        const uint32_t workerBaseIdxOffset = idxCounter.fetch_add(totalIndices, std::memory_order_relaxed);\n        const uint32_t workerPrimBaseOffset = meshCounter.fetch_add(totalPrims, std::memory_order_relaxed);\n        const uint32_t workerBaseEmissiveOffset = workerPrimBaseOffset;\n\n        uint32_t currVtxOffset = workerBaseVtxOffset;\n        uint32_t currIdxOffset = workerBaseIdxOffset;\n        uint32_t currMeshPrimOffset = workerPrimBaseOffset;\n\n        // Now iterate again and populate the buffers\n        for (size_t meshIdx = offset; meshIdx != offset + size; meshIdx++)\n        {\n            const cgltf_mesh& mesh = model.meshes[meshIdx];\n\n            for (int primIdx = 0; primIdx < mesh.primitives_count; primIdx++)\n            {\n                const cgltf_primitive& prim = mesh.primitives[primIdx];\n\n                int posIt = -1;\n                int normalIt = -1;\n                int texIt = -1;\n                int tangentIt = -1;\n\n                for (int attrib = 0; attrib < prim.attributes_count; attrib++)\n                {\n                    if (strcmp(prim.attributes[attrib].name, \"POSITION\") == 0)\n                        posIt = attrib;\n                    else if (strcmp(prim.attributes[attrib].name, \"NORMAL\") == 0)\n                        normalIt = attrib;\n                    else if (strcmp(prim.attributes[attrib].name, \"TEXCOORD_0\") == 0)\n                        texIt = attrib;\n                    else if (strcmp(prim.attributes[attrib].name, \"TANGENT\") == 0)\n                        tangentIt = attrib;\n                }\n\n                Check(normalIt != -1, \"NORMAL was not found in the vertex attributes.\");\n\n                // Populate the vertex attributes\n                const cgltf_accessor& accessor = *prim.attributes[posIt].data;\n                const uint32_t numVertices = (uint32_t)accessor.count;\n\n                const cgltf_buffer_view& bufferView = *prim.indices->buffer_view;\n                const uint32_t numIndices = (uint32_t)prim.indices->count;\n\n                // POSITION\n                ProcessPositions(model, *prim.attributes[posIt].data, vertices, currVtxOffset);\n\n                // NORMAL\n                ProcessNormals(model, *prim.attributes[normalIt].data, vertices, currVtxOffset);\n\n                // indices\n                ProcessIndices(model, *prim.indices, indices, currIdxOffset);\n\n                // TEXCOORD_0\n                if (texIt != -1)\n                {\n                    ProcessTexCoords(model, *prim.attributes[texIt].data, vertices, currVtxOffset);\n\n                    // If vertex tangents aren't present, compute them. Make sure the computation \n                    // happens after vertex and index processing.\n                    if (tangentIt != -1)\n                        ProcessTangents(model, *prim.attributes[tangentIt].data, vertices, currVtxOffset);\n                    else if(prim.material->normal_texture.texture)\n                    {\n                        Math::ComputeMeshTangentVectors(MutableSpan(vertices.begin() + currVtxOffset, numVertices),\n                            Span(indices.begin() + currIdxOffset, numIndices),\n                            false);\n                    }\n                }\n\n                meshes[currMeshPrimOffset++] = Mesh\n                    {\n                        .SceneID = sceneID,\n                        .glTFMaterialIdx = prim.material ? (int)(prim.material - model.materials) : -1,\n                        .MeshIdx = (int)meshIdx,\n                        .MeshPrimIdx = primIdx,\n                        .BaseVtxOffset = currVtxOffset,\n                        .BaseIdxOffset = currIdxOffset,\n                        .NumVertices = numVertices,\n                        .NumIndices = numIndices\n                    };\n\n                // Remember every mesh with an emissive material assigned to it.\n                if (prim.material)\n                {\n                    float emissiveFactDot1 = prim.material->emissive_factor[0] + \n                        prim.material->emissive_factor[1] + \n                        prim.material->emissive_factor[2];\n\n                    if ((emissiveFactDot1 > 0 || prim.material->has_emissive_strength || \n                        prim.material->emissive_texture.texture))\n                    {\n                        const uint64_t meshID = Scene::MeshID(sceneID, (int)meshIdx, primIdx);\n\n                        emissivesPrims[workerBaseEmissiveOffset + numEmissiveMeshPrims++] = EmissiveMeshPrim\n                            {\n                                .MeshID = meshID,\n                                .BaseVtxOffset = currVtxOffset,\n                                .BaseIdxOffset = currIdxOffset,\n                                .NumIndices = numIndices,\n                                .MaterialIdx = (int)(prim.material - model.materials)\n                            };\n                    }\n                }\n\n                currVtxOffset += numVertices;\n                currIdxOffset += numIndices;\n            }\n        }\n\n        emissivePrimCount = numEmissiveMeshPrims;\n    }\n\n    void LoadDDSImages(uint32_t sceneID, const Filesystem::Path& modelDir, const cgltf_data& model,\n        size_t offset, size_t num, MutableSpan<Texture> ddsImages)\n    {\n        // For loading DDS data from disk\n        MemoryArena memArena(64 * 1024 * 1024);\n        // For uploading texture to GPU \n        UploadHeapArena heapArena(64 * 1024 * 1024);\n\n        // Since constructor is not called\n        static_assert(std::is_trivially_default_constructible_v<DDS_Data>,\n            \"DDS_Data is not trivially-default-constructible.\");\n        DDS_Data* ddsTextures = reinterpret_cast<DDS_Data*>(memArena.AllocateAligned(\n            num * sizeof(DDS_Data)));\n        bool hasInvalid = false;\n\n        // Two passes:\n        // 1. Load DDS data from disk\n        // 2. Allocate a heap large enough for all the textures, then create a placed \n        //    texture for each\n\n        for (size_t m = offset; m != offset + num; m++)\n        {\n            const cgltf_image& image = model.images[m];\n            const size_t idx = m - offset;\n            Check(image.uri, \"Image has no URI.\");\n\n            Filesystem::Path path(modelDir.GetView());\n            path.Append(image.uri);\n\n            char ext[8];\n            path.Extension(ext);\n            if (strcmp(ext, \"dds\") != 0)\n            {\n                LOG_UI_WARNING(\n                    \"Texture in path %s either hasn't been converted to DDS format or is not referenced by any materials. Skipping...\\n\",\n                    path.Get());\n\n                ddsTextures[idx].ID = Texture::INVALID_ID;\n                hasInvalid = true;\n\n                continue;\n            }\n\n            ddsTextures[idx].ID = IDFromTexturePath(path);\n            auto err = GpuMemory::GetDDSDataFromDisk(path.Get(), ddsTextures[idx], heapArena,\n                ArenaAllocator(memArena));\n\n            Check(err == LOAD_DDS_RESULT::SUCCESS, \"Error loading DDS texture from path %s: %d\", path.Get(), err);\n        }\n\n        size_t numValid = num;\n        if (hasInvalid)\n        {\n            DDS_Data* firstInvalid = std::partition(ddsTextures, ddsTextures + num,\n                [](const DDS_Data& dds) {return dds.ID != Texture::INVALID_ID; });\n            numValid = firstInvalid - ddsTextures;\n        }\n\n        if (!numValid)\n            return;\n\n        D3D12_RESOURCE_DESC1* texDescs = reinterpret_cast<D3D12_RESOURCE_DESC1*>(memArena.AllocateAligned(\n            numValid * sizeof(D3D12_RESOURCE_DESC1)));\n        D3D12_RESOURCE_ALLOCATION_INFO1* allocInfos = reinterpret_cast<D3D12_RESOURCE_ALLOCATION_INFO1*>(memArena.AllocateAligned(\n            numValid * sizeof(D3D12_RESOURCE_ALLOCATION_INFO1)));\n\n        for (size_t i = 0; i < numValid; i++)\n        {\n            texDescs[i] = Direct3DUtil::Tex2D1(ddsTextures[i].format, ddsTextures[i].width, \n                ddsTextures[i].height, 1, ddsTextures[i].mipCount);\n        }\n\n        D3D12_RESOURCE_ALLOCATION_INFO info = Direct3DUtil::AllocationInfo(Span(texDescs, numValid),\n            MutableSpan(allocInfos, numValid));\n        auto heap = GpuMemory::GetResourceHeap(info.SizeInBytes);\n\n        // Invalid texture were default-constructed to have INVALID_ID\n        for (size_t i = 0; i < numValid; i++)\n        {\n            Texture tex = GpuMemory::GetPlacedTexture2DAndInit(ddsTextures[i].ID, \n                texDescs[i], heap.Heap(), allocInfos[i].Offset, heapArena, \n                Span(ddsTextures[i].subresources, ddsTextures[i].numSubresources));\n\n            // Order of textures is not important\n            ddsImages[offset + i] = ZetaMove(tex);\n        }\n\n        App::GetScene().AddTextureHeap(ZetaMove(heap));\n    }\n\n    void ProcessMaterials(uint32_t sceneID, const Filesystem::Path& modelDir, const cgltf_data& model,\n        int offset, int size, MutableSpan<Texture> ddsImages)\n    {\n        auto getAlphaMode = [](cgltf_alpha_mode m)\n            {\n                switch (m)\n                {\n                case cgltf_alpha_mode_opaque:\n                    return Material::ALPHA_MODE::OPAQUE_;\n                case cgltf_alpha_mode_mask:\n                    return Material::ALPHA_MODE::MASK;\n                case cgltf_alpha_mode_blend:\n                    return Material::ALPHA_MODE::BLEND;\n                default:\n                    break;\n                }\n\n                Assert(false, \"invalid alpha mode.\");\n                return Material::ALPHA_MODE::OPAQUE_;\n            };\n\n        for (int m = offset; m != offset + size; m++)\n        {\n            const auto& mat = model.materials[m];\n            Check(mat.has_pbr_metallic_roughness, \"Material is not supported.\");\n\n            glTF::Asset::MaterialDesc desc;\n            desc.ID = Scene::MaterialID(sceneID, m);\n            desc.AlphaMode = getAlphaMode(mat.alpha_mode);\n            desc.AlphaCutoff = (float)mat.alpha_cutoff;\n            desc.DoubleSided = mat.double_sided;\n\n            // Base Color map\n            {\n                const cgltf_texture_view& baseColView = mat.pbr_metallic_roughness.base_color_texture;\n                if (baseColView.texture)\n                {\n                    Check(baseColView.texture->image, \"textureView doesn't point to any image.\");\n\n                    Filesystem::Path path(modelDir.GetView());\n                    path.Append(baseColView.texture->image->uri);\n                    desc.BaseColorTexID = IDFromTexturePath(path);\n                }\n\n                auto& f = mat.pbr_metallic_roughness.base_color_factor;\n                desc.BaseColorFactor = float4(f[0], f[1], f[2], f[3]);\n            }\n\n            // Normal map\n            {\n                const cgltf_texture_view& normalView = mat.normal_texture;\n                if (normalView.texture)\n                {\n                    Check(normalView.texture->image, \"textureView doesn't point to any image.\");\n\n                    Filesystem::Path path(modelDir.GetView());\n                    path.Append(normalView.texture->image->uri);\n                    desc.NormalTexID = IDFromTexturePath(path);\n\n                    desc.NormalScale = (float)mat.normal_texture.scale;\n                }\n            }\n\n            // Metallic-Roughness map\n            {\n                const cgltf_texture_view& metallicRoughnessView = mat.pbr_metallic_roughness.metallic_roughness_texture;\n                if (metallicRoughnessView.texture)\n                {\n                    Check(metallicRoughnessView.texture->image, \n                        \"textureView doesn't point to any image.\");\n\n                    Filesystem::Path path(modelDir.GetView());\n                    path.Append(metallicRoughnessView.texture->image->uri);\n                    desc.MetallicRoughnessTexID = IDFromTexturePath(path);\n                }\n\n                desc.MetallicFactor = (float)mat.pbr_metallic_roughness.metallic_factor;\n                desc.SpecularRoughnessFactor = (float)mat.pbr_metallic_roughness.roughness_factor;\n            }\n\n            // Emissive map\n            {\n                const cgltf_texture_view& emissiveView = mat.emissive_texture;\n                if (emissiveView.texture)\n                {\n                    Check(emissiveView.texture->image, \"textureView doesn't point to any image.\");\n\n                    Filesystem::Path path(modelDir.GetView());\n                    path.Append(emissiveView.texture->image->uri);\n                    desc.EmissiveTexID = IDFromTexturePath(path);\n                }\n\n                auto& f = mat.emissive_factor;\n                desc.EmissiveFactor = float3((float)f[0], (float)f[1], (float)f[2]);\n\n                if (mat.has_emissive_strength)\n                    desc.EmissiveStrength = mat.emissive_strength.emissive_strength;\n            }\n\n            if (mat.has_ior)\n            {\n                if ((mat.ior.ior - 1.0f) < 1e-3f)\n                {\n                    LOG_UI_WARNING(\"IOR value of %.3f for material %s is invalid.\\n\",\n                        mat.ior.ior, mat.name ? mat.name : \"unnamed\");\n                }\n\n                desc.SpecularIOR = mat.ior.ior;\n            }\n            if (mat.has_transmission)\n                desc.TransmissionWeight = mat.transmission.transmission_factor;\n            if (mat.has_clearcoat)\n            {\n                desc.CoatWeight = mat.clearcoat.clearcoat_factor;\n                desc.CoatRoughness = mat.clearcoat.clearcoat_roughness_factor;\n            }\n\n            SceneCore& scene = App::GetScene();\n            scene.AddMaterial(desc, ddsImages, false);\n        }\n    }\n\n    void NumEmissiveInstancesAndTrianglesSubtree(const cgltf_node& node, ThreadContext& context)\n    {\n        if (node.mesh)\n        {\n            const int meshIdx = (int)(node.mesh - context.Model->meshes);\n\n            // A separate instance for each primitive\n            for (int primIdx = 0; primIdx < node.mesh->primitives_count; primIdx++)\n            {\n                const cgltf_primitive& meshPrim = node.mesh->primitives[primIdx];\n\n                if (meshPrim.material)\n                {\n                    const uint64_t meshID = Scene::MeshID(context.SceneID, (int)meshIdx, primIdx);\n                    const auto idx = BinarySearch(Span(context.EmissiveMeshPrims), meshID, \n                        [](const EmissiveMeshPrim& p) {return p.MeshID; });\n\n                    // Does this mesh prim have an emissive material assigned to it?\n                    if (idx != -1)\n                    {\n                        const auto& meshPrimInfo = context.EmissiveMeshPrims[idx];\n                        Assert(meshPrimInfo.MaterialIdx == (int)(meshPrim.material - context.Model->materials), \n                            \"Material index mismatch.\");\n\n                        context.NumEmissiveTris += meshPrimInfo.NumIndices / 3;\n                        context.NumEmissiveInstances++;\n                    }\n                }\n            }\n        }\n\n        for (int c = 0; c < node.children_count; c++)\n        {\n            const cgltf_node& childNode = *node.children[c];\n            NumEmissiveInstancesAndTrianglesSubtree(childNode, context);\n        }\n    }\n\n    void NumEmissiveInstancesAndTriangles(ThreadContext& context)\n    {\n        for (size_t i = 0; i < context.Model->scene->nodes_count; i++)\n        {\n            const cgltf_node& node = *context.Model->scene->nodes[i];\n            NumEmissiveInstancesAndTrianglesSubtree(node, context);\n        }\n    }\n\n    void ProcessEmissiveSubtree(const cgltf_node& node, ThreadContext& context, int& emissiveMeshIdx,\n        uint32_t& rtEmissiveTriIdx)\n    {\n        SceneCore& scene = App::GetScene();\n        uint32_t currGlobalTriIdx = rtEmissiveTriIdx;\n\n        if (node.mesh)\n        {\n            const int meshIdx = (int)(node.mesh - context.Model->meshes);\n\n            // A separate instance for each primitive\n            for (int primIdx = 0; primIdx < node.mesh->primitives_count; primIdx++)\n            {\n                const cgltf_primitive& meshPrim = node.mesh->primitives[primIdx];\n\n                if (meshPrim.material)\n                {\n                    const uint64_t meshID = Scene::MeshID(context.SceneID, (int)meshIdx, primIdx);\n                    const auto idx = BinarySearch(Span(context.EmissiveMeshPrims), meshID, \n                        [](const EmissiveMeshPrim& p) {return p.MeshID; });\n\n                    if (idx != -1)\n                    {\n                        uint32_t emissiveFactorRGB = Float3ToRGB8(float3(meshPrim.material->emissive_factor[0],\n                            meshPrim.material->emissive_factor[1],\n                            meshPrim.material->emissive_factor[2]));\n\n                        const auto& meshPrimInfo = context.EmissiveMeshPrims[idx];\n\n                        const uint32_t matID = Scene::MaterialID(context.SceneID, meshPrimInfo.MaterialIdx);\n                        const Material* mat = scene.GetMaterial(matID).value();\n\n                        const int nodeIdx = (int)(&node - context.Model->nodes);\n                        const uint64_t currInstanceID = Scene::InstanceID(context.SceneID, nodeIdx, meshIdx, primIdx);\n\n                        // Add emissive instance\n                        context.EmissiveInstances[emissiveMeshIdx++] = EmissiveInstance\n                            {\n                                .InstanceID = currInstanceID,\n                                .BaseTriOffset = currGlobalTriIdx,\n                                .NumTriangles = meshPrimInfo.NumIndices / 3,\n                                .MaterialIdx = meshPrimInfo.MaterialIdx + 1\n                            };\n\n                        uint32_t currMeshTriIdx = 0;\n\n                        // Add all triangles for this instance\n                        for (size_t i = meshPrimInfo.BaseIdxOffset; i < meshPrimInfo.BaseIdxOffset + meshPrimInfo.NumIndices; i += 3)\n                        {\n                            uint32_t i0 = context.Indices[i];\n                            uint32_t i1 = context.Indices[i + 1];\n                            uint32_t i2 = context.Indices[i + 2];\n\n                            const Vertex& v0 = context.Vertices[meshPrimInfo.BaseVtxOffset + i0];\n                            const Vertex& v1 = context.Vertices[meshPrimInfo.BaseVtxOffset + i1];\n                            const Vertex& v2 = context.Vertices[meshPrimInfo.BaseVtxOffset + i2];\n\n                            context.RTEmissives[currGlobalTriIdx++] = RT::EmissiveTriangle(\n                                v0.Position, v1.Position, v2.Position,\n                                v0.TexUV, v1.TexUV, v2.TexUV,\n                                emissiveFactorRGB, mat->GetEmissiveTex(), mat->GetEmissiveStrength(),\n                                currMeshTriIdx++, mat->DoubleSided());\n                        }\n                    }\n                }\n            }\n        }\n\n        rtEmissiveTriIdx = currGlobalTriIdx;\n\n        for (int c = 0; c < node.children_count; c++)\n        {\n            const cgltf_node& childNode = *node.children[c];\n            ProcessEmissiveSubtree(childNode, context, emissiveMeshIdx, rtEmissiveTriIdx);\n        }\n    }\n\n    void ProcessEmissives(ThreadContext& context)\n    {\n        int emissiveMeshIdx = 0;\n        uint32_t rtEmissiveTriIdx = 0;\n\n        for (size_t i = 0; i < context.Model->scene->nodes_count; i++)\n        {\n            const cgltf_node& node = *context.Model->scene->nodes[i];\n            ProcessEmissiveSubtree(node, context, emissiveMeshIdx, rtEmissiveTriIdx);\n        }\n\n        Assert(emissiveMeshIdx == context.NumEmissiveInstances, \"these must match.\");\n        Assert(rtEmissiveTriIdx == context.NumEmissiveTris, \"these must match.\");\n    }\n\n    void ProcessNodeSubtree(const cgltf_node& node, uint32_t sceneID, const cgltf_data& model,\n        uint64_t parentId)\n    {\n        uint64_t currInstanceID = SceneCore::ROOT_ID;\n\n        AffineTransformation transform = AffineTransformation::GetIdentity();\n\n        if (node.has_matrix)\n        {\n            float4x4a M(node.matrix);\n            v_float4x4 vM = load4x4(M);\n            auto det = store(det3x3(vM));\n            //Check(fabsf(det.x) > 1e-6f, \"Transformation matrix with a zero determinant is invalid.\");\n            Check(det.x > 0.0f, \n                \"Transformation matrices that change the orientation (e.g. negative scaling) are not supported.\");\n\n            // Column-major storage to row-major storage\n            vM = transpose(vM);\n            M = store(vM);\n\n            // To apply the transformation matrix M = [u v w] from the RHS coordinate system (+Y up) \n            // to some vector x in the LHS system (+Y up), let C denote the change-of-basis transformation \n            // matrix from the latter to the former. The transformation of x (denote by x') is given by\n            //\n            //      x' = C^-1 M C x.\n            // \n            // Replacing C in above\n            //\n            //           | 1  0  0 |         | 1  0  0 |\n            //      x' = | 0  1  0 | [u v w] | 0  1  0 | x\n            //           | 0  0 -1 |         | 0  0 -1 |\n            //\n            //           | 1  0  0 |\n            //         = | 0  1  0 | [u v -w] x\n            //           | 0  0 -1 |\n            //\n            //           |  u_1  v_1  -w_1 |\n            //         = |  u_2  v_2  -w_2 | x\n            //           | -u_3 -v_3   w_3 |\n            //\n            M.m[0].z *= -1.0f;\n            M.m[1].z *= -1.0f;\n            M.m[2].x *= -1.0f;\n            M.m[2].y *= -1.0f;\n\n            // Convert translation to LHS\n            M.m[2].w *= -1.0f;\n\n            vM = load4x4(M);\n            decomposeTRS(vM, transform.Scale, transform.Rotation, transform.Translation);\n        }\n        else\n        {\n            if (node.has_scale)\n            {\n                Check(node.scale[0] > 0 && node.scale[1] > 0 && node.scale[2] > 0, \n                    \"Negative scale factors are not supported.\");\n                transform.Scale = float3((float)node.scale[0], (float)node.scale[1], (float)node.scale[2]);\n            }\n\n            if (node.has_translation)\n            {\n                transform.Translation = float3((float)node.translation[0], (float)node.translation[1], \n                    (float)-node.translation[2]);\n            }\n\n            if (node.has_rotation)\n            {\n                // Rotation quaternion q = (n_x * s, n_y * s, n_z * s, c)\n                // where s = sin(theta/2) and c = cos(theta/2).\n                //\n                // In the LHS system (+Y up), n_lhs = (n_x, n_y, -n_z)\n                // and theta_lhs = -theta. Since sin(-a) = -sin(a) and cos(-a) = cos(a)\n                //\n                //        q_lhs = (n_x * -s, n_y * -s, -n_z * -s, c)\n                //              = (-n_x * s, -n_y * s, n_z * s, c)\n                //\n                transform.Rotation = float4(-(float)node.rotation[0],\n                    -(float)node.rotation[1],\n                    (float)node.rotation[2],\n                    (float)node.rotation[3]);\n\n#if CHECK_QUATERNION_VALID == 1\n                // check ||quaternion|| = 1\n                __m128 vV = _mm_loadu_ps(&transform.Rotation.x);\n                __m128 vLength = _mm_dp_ps(vV, vV, 0xff);\n                vLength = _mm_sqrt_ps(vLength);\n                __m128 vOne = _mm_set1_ps(1.0f);\n                __m128 vDiff = _mm_sub_ps(vLength, vOne);\n                float d = _mm_cvtss_f32(abs(vDiff));\n                Check(d < 1e-6f, \"Invalid rotation quaternion.\");\n#endif\n            }\n        }\n\n        // Workaround for nodes without a name\n        const int nodeIdx = (int)(&node - model.nodes);\n        Assert(nodeIdx < model.nodes_count, \"Invalid node index.\");\n\n        if (node.mesh)\n        {\n            const int meshIdx = (int)(node.mesh - model.meshes);\n            Assert(meshIdx < model.meshes_count, \"Invalid mesh index.\");\n\n            // A separate instance for each primitive\n            for (int primIdx = 0; primIdx < node.mesh->primitives_count; primIdx++)\n            {\n                const cgltf_primitive& meshPrim = node.mesh->primitives[primIdx];\n                float emissiveFactDot1 = 0;\n\n                if (meshPrim.material)\n                {\n                    emissiveFactDot1 = meshPrim.material->emissive_factor[0] +\n                        meshPrim.material->emissive_factor[1] +\n                        meshPrim.material->emissive_factor[2];\n                }\n\n                const uint8_t rtInsMask = meshPrim.material &&\n                    (meshPrim.material->emissive_texture.texture || (emissiveFactDot1 > 0)) ?\n                    RT_AS_SUBGROUP::EMISSIVE :\n                    RT_AS_SUBGROUP::NON_EMISSIVE;\n\n                // Parent-child relationships will be w.r.t. the last mesh primitive\n                currInstanceID = Scene::InstanceID(sceneID, nodeIdx, meshIdx, primIdx);\n\n                const bool isOpaque = meshPrim.material && meshPrim.material->alpha_mode != cgltf_alpha_mode_opaque ?\n                    false :\n                    true;\n\n                glTF::Asset::InstanceDesc desc{\n                    .LocalTransform = transform,\n                    .SceneID = sceneID,\n                    .ID = currInstanceID,\n                    .ParentID = parentId,\n                    .MeshIdx = meshIdx,\n                    .MeshPrimIdx = primIdx,\n                    .RtMeshMode = RT_MESH_MODE::STATIC,\n                    .RtInstanceMask = rtInsMask,\n                    .IsOpaque = isOpaque };\n\n                SceneCore& scene = App::GetScene();\n                scene.AddInstance(desc, false);\n            }\n        }\n        else\n        {\n            currInstanceID = Scene::InstanceID(sceneID, nodeIdx, -1, -1);\n\n            glTF::Asset::InstanceDesc desc{\n                .LocalTransform = transform,\n                    .SceneID = sceneID,\n                    .ID = currInstanceID,\n                    .ParentID = parentId,\n                    .MeshIdx = -1,\n                    .MeshPrimIdx = -1,\n                    .RtMeshMode = RT_MESH_MODE::STATIC,\n                    .RtInstanceMask = RT_AS_SUBGROUP::NON_EMISSIVE,\n                    .IsOpaque = true };\n\n            SceneCore& scene = App::GetScene();\n            scene.AddInstance(desc, false);\n        }\n\n        for (int c = 0; c < node.children_count; c++)\n        {\n            const cgltf_node& childNode = *node.children[c];\n            ProcessNodeSubtree(childNode, sceneID, model, currInstanceID);\n        }\n    }\n\n    void ProcessNodes(const cgltf_data& model, uint32_t sceneID)\n    {\n        for (size_t i = 0; i < model.scene->nodes_count; i++)\n        {\n            const cgltf_node& node = *model.scene->nodes[i];\n            ProcessNodeSubtree(node, sceneID, model, SceneCore::ROOT_ID);\n        }\n    }\n\n    void DescendTree(const cgltf_node& node, int height, Vector<int>& treeLevels)\n    {\n        // Some meshes can have multiple mesh primitives, each one is treated as a separate\n        // instance here\n        treeLevels[height] += node.mesh ? (int)node.mesh->primitives_count : 1;\n\n        for (size_t i = 0; i < node.children_count; i++)\n        {\n            const cgltf_node& childNode = *node.children[i];\n            DescendTree(childNode, height + 1, treeLevels);\n        }\n    }\n\n    void PrecomputeNodeHierarchy(const cgltf_data& model, Vector<int>& treeLevels)\n    {\n        // NOTE model.scene->nodes refers to first-level nodes only\n        for (size_t i = 0; i < model.scene->nodes_count; i++)\n        {\n            const cgltf_node& firstLevelNode = *model.scene->nodes[i];\n            treeLevels[0] += firstLevelNode.mesh ? (int)firstLevelNode.mesh->primitives_count : 1;\n        }\n\n        for (size_t i = 0; i < model.scene->nodes_count; i++)\n        {\n            const cgltf_node& firstLevelNode = *model.scene->nodes[i];\n            if (firstLevelNode.children_count)\n            {\n                for (size_t j = 0; j < firstLevelNode.children_count; j++)\n                {\n                    const cgltf_node& childNode = *firstLevelNode.children[j];\n                    DescendTree(childNode, 1, treeLevels);\n                }\n            }\n        }\n    }\n\n    int TreeHeight(const cgltf_node& node)\n    {\n        int height = 0;\n\n        for (size_t i = 0; i < node.children_count; i++)\n        {\n            const cgltf_node& childNode = *node.children[i];\n            height = Max(height, TreeHeight(childNode) + 1);\n        }\n\n        return height;\n    }\n\n    int ComputeNodeHierarchyHeight(const cgltf_data& model)\n    {\n        int height = 0;\n\n        for (size_t i = 0; i < model.scene->nodes_count; i++)\n        {\n            const cgltf_node& childNode = *model.scene->nodes[i];\n            height = Max(height, TreeHeight(childNode) + 1);\n        }\n\n        return height;\n    }\n\n    void TotalNumVerticesAndIndices(cgltf_data* model, size_t& numVertices, size_t& numIndices, \n        size_t& numMeshes)\n    {\n        numVertices = 0;\n        numIndices = 0;\n        numMeshes = 0;\n\n        for (size_t meshIdx = 0; meshIdx != model->meshes_count; meshIdx++)\n        {\n            const auto& mesh = model->meshes[meshIdx];\n            numMeshes += mesh.primitives_count;\n\n            for (size_t primIdx = 0; primIdx < mesh.primitives_count; primIdx++)\n            {\n                const auto& prim = mesh.primitives[primIdx];\n\n                if (prim.type != cgltf_primitive_type_triangles)\n                    continue;\n\n                for (int attrib = 0; attrib < prim.attributes_count; attrib++)\n                {\n                    if (strcmp(\"POSITION\", prim.attributes[attrib].name) == 0)\n                    {\n                        auto& accessor = prim.attributes[attrib].data;\n                        numVertices += accessor->count;\n\n                        break;\n                    }\n                }\n\n                numIndices += prim.indices->count;\n            }\n        }\n    }\n}\n\nvoid glTF::Load(const App::Filesystem::Path& pathToglTF)\n{\n    // Parse json\n    cgltf_options options{};\n    cgltf_data* model = nullptr;\n    Checkgltf(cgltf_parse_file(&options, pathToglTF.GetView().data(), &model));\n\n    // Load buffers\n    Check(model->buffers_count == 1, \"Invalid number of buffers.\");\n    Filesystem::Path bufferPath(pathToglTF.GetView());\n    bufferPath.Directory();\n    bufferPath.Append(model->buffers[0].uri);\n    Checkgltf(cgltf_load_buffers(&options, model, bufferPath.Get()));\n\n    Check(model->scene, \"glTF model doesn't have a default scene: %s.\", pathToglTF.GetView());\n    const uint32_t sceneID = XXH3_64_To_32(XXH3_64bits(pathToglTF.GetView().data(), pathToglTF.Length()));\n    SceneCore& scene = App::GetScene();\n\n    // Figure out total number of vertices and indices\n    size_t totalNumVertices;\n    size_t totalNumIndices;\n    size_t totalNumMeshPrims;\n    TotalNumVerticesAndIndices(model, totalNumVertices, totalNumIndices, totalNumMeshPrims);\n\n    // Height of the node hierarchy\n    const int height = ComputeNodeHierarchyHeight(*model);\n    constexpr int DEFAULT_NUM_LEVELS = 10;\n    SmallVector<int, SystemAllocator, DEFAULT_NUM_LEVELS> levels;\n    levels.resize(height, 0);\n\n    // Precompute number of nodes per level\n    PrecomputeNodeHierarchy(*model, levels);\n\n    size_t total = 0;\n    for (size_t i = 0; i < levels.size(); i++)\n        total += levels[i];\n\n    // Preallocate\n    scene.ResizeAdditionalMaterials((uint32_t)model->materials_count);\n    scene.ReserveInstances(levels, total);\n\n    // How many meshes are processed by each worker\n    constexpr size_t MAX_NUM_MESH_WORKERS = 4;\n    constexpr size_t MIN_MESHES_PER_WORKER = 20;\n    size_t meshWorkerOffset[MAX_NUM_MESH_WORKERS];\n    size_t meshWorkerCount[MAX_NUM_MESH_WORKERS];\n    uint32_t workerEmissiveCount[MAX_NUM_MESH_WORKERS];\n\n    const int numMeshWorkers = (int)SubdivideRangeWithMin(model->meshes_count,\n        MAX_NUM_MESH_WORKERS,\n        meshWorkerOffset,\n        meshWorkerCount,\n        MIN_MESHES_PER_WORKER);\n\n    // How many images are processed by each worker\n    constexpr size_t MAX_NUM_IMAGE_WORKERS = 5;\n    constexpr size_t MIN_IMAGES_PER_WORKER = 15;\n    size_t imgWorkerOffset[MAX_NUM_IMAGE_WORKERS];\n    size_t imgWorkerCount[MAX_NUM_IMAGE_WORKERS];\n\n    const int numImgWorkers = (int)SubdivideRangeWithMin(model->images_count,\n        MAX_NUM_IMAGE_WORKERS,\n        imgWorkerOffset,\n        imgWorkerCount,\n        MIN_IMAGES_PER_WORKER);\n\n    ThreadContext tc;\n    tc.glTFPath = &pathToglTF;\n    tc.SceneID = sceneID;\n    tc.Model = model;\n    tc.NumMeshWorkers = numMeshWorkers;\n    tc.NumImgWorkers = numImgWorkers;\n    tc.MeshThreadOffsets = meshWorkerOffset;\n    tc.MeshThreadSizes = meshWorkerCount;\n    tc.ImgThreadOffsets = imgWorkerOffset;\n    tc.ImgThreadSizes = imgWorkerCount;\n    tc.EmissiveMeshPrimCountPerWorker = workerEmissiveCount;\n\n    // Preallocate\n    tc.Vertices.resize(totalNumVertices);\n    tc.Indices.resize(totalNumIndices);\n    tc.Meshes.resize(totalNumMeshPrims);\n    tc.DDSImages.resize(model->images_count);\n    tc.EmissiveMeshPrims.resize(totalNumMeshPrims);\n    ResetEmissiveSubsets(tc.EmissiveMeshPrims);\n\n    TaskSet ts;\n\n    auto procEmissiveMeshPrims = ts.EmplaceTask(\"gltf::EmissivePrims\", [&tc]()\n        {\n            // EmissiveMeshPrimCountPerWorker is filled in by mesh workers\n            for (int i = 0; i < tc.NumMeshWorkers; i++)\n                tc.NumEmissiveMeshPrims += tc.EmissiveMeshPrimCountPerWorker[i];\n\n            // For binary search. Also, since non-emissive meshes were assigned the INVALID\n            // ID (= UINT64_MAX), this also partitions the non-null entries before the null\n            // entries.\n            std::sort(tc.EmissiveMeshPrims.begin(), tc.EmissiveMeshPrims.end(),\n                [](const EmissiveMeshPrim& lhs, const EmissiveMeshPrim& rhs)\n                {\n                    return lhs.MeshID < rhs.MeshID;\n                });\n\n            // In order to do only one allocation, number of emissive mesh primitives was assumed\n            // to be the worst case -- total number of mesh primitives. As such, there may be a number \n            // of \"null\" entries in the EmissiveMeshPrims. Now that the actual size is known, adjust \n            // the size accordingly.\n            //tc.EmissiveMeshPrims = MutableSpan(tc.EmissiveMeshPrims.data(), tc.NumEmissiveMeshPrims);\n            tc.EmissiveMeshPrims.resize(tc.NumEmissiveMeshPrims);\n            NumEmissiveInstancesAndTriangles(tc);\n        });\n\n    for (int i = 0; i < tc.NumMeshWorkers; i++)\n    {\n        StackStr(tname, n, \"gltf::Mesh_%d\", i);\n\n        auto procMesh = ts.EmplaceTask(tname, [&tc, workerIdx = i]()\n            {\n                ProcessMeshes(*tc.Model, tc.SceneID, tc.MeshThreadOffsets[workerIdx],\n                    tc.MeshThreadSizes[workerIdx],\n                    tc.Vertices, tc.CurrVtxOffset,\n                    tc.Indices, tc.CurrIdxOffset,\n                    tc.Meshes, tc.CurrMeshPrimOffset,\n                    tc.EmissiveMeshPrims, \n                    tc.EmissiveMeshPrimCountPerWorker[workerIdx]);\n            });\n\n        ts.AddOutgoingEdge(procMesh, procEmissiveMeshPrims);\n    }\n\n    auto procMats = ts.EmplaceTask(\"gltf::Materials\", [&tc]()\n        {\n            // For binary search\n            std::sort(tc.DDSImages.begin(), tc.DDSImages.end(),\n                [](const Texture& lhs, const Texture& rhs)\n                {\n                    return lhs.ID() < rhs.ID();\n                });\n\n            Filesystem::Path parent(tc.glTFPath->GetView());\n            parent.ToParent();\n\n            ProcessMaterials(tc.SceneID, parent, *tc.Model, 0, (int)tc.Model->materials_count, \n                tc.DDSImages);\n        });\n\n    for (int i = 0; i < numImgWorkers; i++)\n    {\n        StackStr(tname, n, \"gltf::Img_%d\", i);\n\n        // Loads dds textures from disk and upload them to GPU\n        auto h = ts.EmplaceTask(tname, [&tc, workerIdx = i]()\n            {\n                Filesystem::Path parent(tc.glTFPath->GetView());\n                parent.ToParent();\n\n                LoadDDSImages(tc.SceneID, parent, *tc.Model, tc.ImgThreadOffsets[workerIdx], \n                    tc.ImgThreadSizes[workerIdx], tc.DDSImages);\n            });\n\n        // Material processing should start after textures are loaded\n        ts.AddOutgoingEdge(h, procMats);\n    }\n\n    // For each node with an emissive mesh primitive, add all of its triangles to \n    // the emissives buffer\n    auto procEmissives = ts.EmplaceTask(\"gltf::Emissives\", [&tc]()\n        {\n            tc.EmissiveInstances.resize(tc.NumEmissiveInstances);\n            tc.RTEmissives.resize(tc.NumEmissiveTris);\n\n            ProcessEmissives(tc);\n\n            // Transfer ownership of emissives\n            SceneCore& scene = App::GetScene();\n            scene.AddEmissives(ZetaMove(tc.EmissiveInstances), ZetaMove(tc.RTEmissives), false);\n        });\n\n    // Processing emissives starts after materials are loaded and emissive primitives \n    // have been processed\n    ts.AddOutgoingEdge(procEmissiveMeshPrims, procEmissives);\n    ts.AddOutgoingEdge(procMats, procEmissives);\n\n    ts.EmplaceTask(\"gltf::Nodes\", [&tc]()\n        {\n            ProcessNodes(*tc.Model, tc.SceneID);\n        });\n\n    auto last = ts.EmplaceTask(\"gltf::Final\", [&tc]()\n        {\n            // Transfer ownership of mesh buffers\n            SceneCore& scene = App::GetScene();\n            scene.AddMeshes(ZetaMove(tc.Meshes), ZetaMove(tc.Vertices), ZetaMove(tc.Indices), false);\n\n            cgltf_free(tc.Model);\n        });\n\n    // Final task has to run after all the other tasks\n    ts.AddIncomingEdgeFromAll(last);\n\n    WaitObject waitObj;\n    ts.Sort();\n    ts.Finalize(&waitObj);\n    App::Submit(ZetaMove(ts));\n\n    // Help out with unfinished tasks. Note: This thread might help\n    // with tasks that are not related to loading glTF.\n    App::FlushWorkerThreadPool();\n    waitObj.Wait();\n}\n"
  },
  {
    "path": "Source/ZetaCore/Model/glTF.h",
    "content": "#pragma once\n\n#include \"../App/Path.h\"\n\nnamespace ZetaRay::Model::glTF\n{\n    void Load(const App::Filesystem::Path& p);\n}"
  },
  {
    "path": "Source/ZetaCore/Model/glTFAsset.h",
    "content": "#pragma once\n\n#include \"../Core/Vertex.h\"\n#include \"../Core/GpuMemory.h\"\n#include \"../Math/Matrix.h\"\n#include \"../App/Filesystem.h\"\n#include \"../Core/Material.h\"\n#include \"../Model/Mesh.h\"\n#include \"../Scene/SceneCommon.h\"\n\nnamespace ZetaRay::Model::glTF::Asset\n{\n    struct Mesh\n    {\n        uint32_t SceneID;\n        int glTFMaterialIdx;\n        int MeshIdx;\n        int MeshPrimIdx;\n        uint32_t BaseVtxOffset;\n        uint32_t BaseIdxOffset;\n        uint32_t NumVertices;\n        uint32_t NumIndices;\n    };\n\n    struct EmissiveInstance\n    {\n        uint64_t InstanceID;\n        uint32_t BaseTriOffset;\n        uint32_t NumTriangles;\n        int MaterialIdx;\n    };\n\n    struct InstanceDesc\n    {\n        Math::AffineTransformation LocalTransform;\n        uint32_t SceneID;\n        uint64_t ID;\n        uint64_t ParentID;\n        int MeshIdx;\n        int MeshPrimIdx;\n        RT_MESH_MODE RtMeshMode;\n        uint8_t RtInstanceMask;\n        bool IsOpaque;\n    };\n\n    struct MaterialDesc\n    {\n        Core::GpuMemory::Texture::ID_TYPE BaseColorTexID = Core::GpuMemory::Texture::INVALID_ID;\n        Core::GpuMemory::Texture::ID_TYPE MetallicRoughnessTexID = Core::GpuMemory::Texture::INVALID_ID;\n        Core::GpuMemory::Texture::ID_TYPE NormalTexID = Core::GpuMemory::Texture::INVALID_ID;\n        Core::GpuMemory::Texture::ID_TYPE EmissiveTexID = Core::GpuMemory::Texture::INVALID_ID;\n\n        // Base\n        Math::float4 BaseColorFactor = Math::float4(1.0f);\n        float MetallicFactor = 1.0f;\n        // Specular\n        float SpecularRoughnessFactor = 1.0f;\n        float SpecularIOR = DEFAULT_ETA_MAT;\n        // Transmission\n        float TransmissionWeight = 0.0f;\n        Math::float3 TransmissionColor = Math::float3(1.0f);\n        float TransmissionDepth = 0.0f;\n        // Subsurface\n        float SubsurfaceWeight = 0.0f;\n        // Coat\n        float CoatWeight = 0.0f;\n        Math::float3 CoatColor = Math::float3(0.8f);\n        float CoatRoughness = 0.0f;\n        float CoatIOR = DEFAULT_ETA_COAT;\n        // Emission\n        float EmissiveStrength = 1.0f;\n        Math::float3 EmissiveFactor = Math::float3(0.0f);\n        // Geometry\n        float NormalScale = 1.0f;\n        float AlphaCutoff = 0.5f;\n        Material::ALPHA_MODE AlphaMode = Material::ALPHA_MODE::OPAQUE_;\n        bool DoubleSided = false;\n        // Unique ID of each material\n        uint32_t ID = Scene::DEFAULT_MATERIAL_ID;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/RayTracing/CMakeLists.txt",
    "content": "set(RT_DIR \"${ZETA_CORE_DIR}/RayTracing\")\nset(RT_SRC\n    \"${RT_DIR}/RtAccelerationStructure.cpp\"\n    \"${RT_DIR}/RtAccelerationStructure.h\"\n    \"${RT_DIR}/RtCommon.h\")\nset(RT_SRC ${RT_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaCore/RayTracing/RtAccelerationStructure.cpp",
    "content": "#include \"RtAccelerationStructure.h\"\n#include \"../Core/RendererCore.h\"\n#include \"../Core/CommandList.h\"\n#include \"../Scene/SceneCore.h\"\n#include \"../Core/SharedShaderResources.h\"\n#include \"../Core/RenderGraph.h\"\n#include \"../App/Log.h\"\n#include \"../App/Timer.h\"\n#include <algorithm>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::RT;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Model;\nusing namespace ZetaRay::Model::glTF::Asset;\nusing namespace ZetaRay::Support;\n\nnamespace\n{\n    struct BLASTransform\n    {\n        float M[3][4];\n    };\n\n    struct DynamicBlasBuild\n    {\n        D3D12_RAYTRACING_GEOMETRY_DESC GeoDesc;\n        D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO BuildInfo;\n        uint32_t BlasBufferOffset;\n        uint32_t ScratchBufferOffset;\n        uint32_t TreeLevel;\n        uint32_t LevelIdx;\n    };\n\n    ZetaInline D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS BuildFlags(RT_MESH_MODE t)\n    {\n        D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS f = \n            D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_NONE;\n\n        if (t == RT_MESH_MODE::STATIC)\n        {\n            f |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE;\n            f |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_COMPACTION;\n        }\n        else if (t == RT_MESH_MODE::DYNAMIC_NO_REBUILD)\n            f |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE;\n        //else if (t == RT_MESH_MODE::DYNAMIC_REBUILD)\n        //    f |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD;\n\n        return f;\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// StaticBLAS\n//--------------------------------------------------------------------------------------\n\nvoid StaticBLAS::FillMeshTransformBufferForBuild(ID3D12Heap* heap, uint32_t heapOffsetInBytes)\n{\n    SceneCore& scene = App::GetScene();\n    Assert(scene.m_numStaticInstances, \"Invalid call.\");\n\n    SmallVector<BLASTransform, App::FrameAllocator> transforms;\n    transforms.resize(scene.m_numStaticInstances);\n\n    size_t currInstance = 0;\n\n    // Skip the first level\n    for (size_t treeLevelIdx = 1; treeLevelIdx < scene.m_sceneGraph.size(); treeLevelIdx++)\n    {\n        auto& currTreeLevel = scene.m_sceneGraph[treeLevelIdx];\n\n        for (size_t i = 0; i < currTreeLevel.m_rtFlags.size(); i++)\n        {\n            if (currTreeLevel.m_meshIDs[i] == Scene::INVALID_MESH)\n                continue;\n\n            const auto rtFlags = RT_Flags::Decode(currTreeLevel.m_rtFlags[i]);\n\n            if (rtFlags.MeshMode == RT_MESH_MODE::STATIC)\n            {\n                const float4x3& M = currTreeLevel.m_toWorlds[i];\n\n                for (int j = 0; j < 4; j++)\n                {\n                    transforms[currInstance].M[0][j] = M.m[j].x;\n                    transforms[currInstance].M[1][j] = M.m[j].y;\n                    transforms[currInstance].M[2][j] = M.m[j].z;\n                }\n\n                currInstance++;\n            }\n        }\n    }\n\n    Assert(!m_perMeshTransform.IsInitialized(), \"Unexpected condition.\");\n    const uint32_t sizeInBytes = scene.m_numStaticInstances * sizeof(BLASTransform);\n\n    if (heap)\n    {\n        m_perMeshTransform = GpuMemory::GetPlacedHeapBufferAndInit(\"StaticBLASTransform\",\n            sizeInBytes,\n            heap,\n            heapOffsetInBytes,\n            false,\n            MemoryRegion{ .Data = transforms.data(), .SizeInBytes = sizeInBytes });\n    }\n    // Not possible to batch memory allocations with other resources in first frame\n    else\n    {\n        m_perMeshTransform = GpuMemory::GetDefaultHeapBufferAndInit(\"StaticBLASTransform\",\n            sizeInBytes, false, \n            MemoryRegion{ .Data = transforms.data(), .SizeInBytes = sizeInBytes });\n    }\n}\n\nvoid StaticBLAS::Rebuild(ComputeCmdList& cmdList)\n{\n    SceneCore& scene = App::GetScene();\n    //Assert(scene.m_numOpaqueInstances + scene.m_numNonOpaqueInstances == \n    // scene.m_numStaticInstances, \"these should match.\");\n\n    SmallVector<D3D12_RAYTRACING_GEOMETRY_DESC, App::FrameAllocator> meshDescs;\n    meshDescs.resize(scene.m_numStaticInstances);\n\n    constexpr int transformMatSize = sizeof(BLASTransform);\n    const auto sceneVBGpuVa = scene.GetMeshVB().GpuVA();\n    const auto sceneIBGpuVa = scene.GetMeshIB().GpuVA();\n    const D3D12_GPU_VIRTUAL_ADDRESS transformGpuVa = m_perMeshTransform.GpuVA();\n    size_t currInstance = 0;\n\n    // Add a triangle mesh to list of BLAS geometries\n    // Following loop should exactly match the one in FillMeshTransformBufferForBuild()\n    for (size_t treeLevelIdx = 1; treeLevelIdx < scene.m_sceneGraph.size(); treeLevelIdx++)\n    {\n        auto& currTreeLevel = scene.m_sceneGraph[treeLevelIdx];\n\n        for (size_t i = 0; i < currTreeLevel.m_rtFlags.size(); i++)\n        {\n            const RT_Flags flags = RT_Flags::Decode(currTreeLevel.m_rtFlags[i]);\n\n            if (flags.MeshMode == RT_MESH_MODE::STATIC)\n            {\n                const uint64_t meshID = currTreeLevel.m_meshIDs[i];\n                if (meshID == Scene::INVALID_MESH)\n                    continue;\n\n                const TriangleMesh* mesh = scene.GetMesh(meshID).value();\n\n                meshDescs[currInstance].Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES;\n                // Force mesh to be opaque when possible to avoid invoking any-hit shaders\n                meshDescs[currInstance].Flags = flags.IsOpaque ? \n                    D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE : \n                    D3D12_RAYTRACING_GEOMETRY_FLAG_NONE;\n                // Elements are tightly packed as size of each element is a multiple \n                // of required alignment\n                meshDescs[currInstance].Triangles.Transform3x4 = transformGpuVa + \n                    currInstance * transformMatSize;\n                meshDescs[currInstance].Triangles.IndexFormat = DXGI_FORMAT_R32_UINT;\n                meshDescs[currInstance].Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT;\n                meshDescs[currInstance].Triangles.IndexCount = mesh->m_numIndices;\n                meshDescs[currInstance].Triangles.VertexCount = mesh->m_numVertices;\n                meshDescs[currInstance].Triangles.IndexBuffer = sceneIBGpuVa + \n                    mesh->m_idxBuffStartOffset * sizeof(uint32_t);\n                meshDescs[currInstance].Triangles.VertexBuffer.StartAddress = sceneVBGpuVa + \n                    mesh->m_vtxBuffStartOffset * sizeof(Vertex);\n                meshDescs[currInstance].Triangles.VertexBuffer.StrideInBytes = sizeof(Vertex);\n\n                currTreeLevel.m_rtASInfo[i] = RT_AS_Info{\n                    .GeometryIndex = (uint32_t)currInstance,\n                    .InstanceID = 0 };\n\n                currInstance++;\n            }\n        }\n    }\n\n    Assert(currInstance == scene.m_numStaticInstances, \"Invalid instance index.\");\n\n    D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc;\n    buildDesc.Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL;\n    buildDesc.Inputs.Flags = BuildFlags(RT_MESH_MODE::STATIC);\n    buildDesc.Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;\n    buildDesc.Inputs.NumDescs = (UINT)meshDescs.size();\n    buildDesc.Inputs.pGeometryDescs = meshDescs.data();\n\n    // Very expensive. Only needed for first frame - future frames use the cached result.\n    if (m_prebuildInfo.ResultDataMaxSizeInBytes == 0)\n    {\n        App::GetRenderer().GetDevice()->GetRaytracingAccelerationStructurePrebuildInfo(\n            &buildDesc.Inputs, &m_prebuildInfo);\n    }\n\n    Assert(m_prebuildInfo.ResultDataMaxSizeInBytes > 0,\n        \"GetRaytracingAccelerationStructurePrebuildInfo() failed.\");\n    Assert(m_prebuildInfo.ResultDataMaxSizeInBytes < UINT32_MAX,\n        \"Allocation size exceeded maximum allowed.\");\n\n    // Use the same buffer for scratch and compaction info\n    const uint32_t compactionInfoStartOffset = (uint32_t)AlignUp(m_prebuildInfo.ScratchDataSizeInBytes,\n        alignof(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE_DESC));\n    const uint32_t scratchBuffSizeInBytes = compactionInfoStartOffset +\n        sizeof(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE_DESC);\n\n    if (!m_resHeap.IsInitialized())\n    {\n        PlacedResourceList<2> list;\n        // BLAS (before compaction)\n        list.PushBuffer((uint32_t)m_prebuildInfo.ResultDataMaxSizeInBytes, true, true);\n        // Scratch buffer & compaction info\n        list.PushBuffer(scratchBuffSizeInBytes, true, false);\n        list.End();\n\n        m_resHeap = GpuMemory::GetResourceHeap(list.TotalSizeInBytes());\n\n        auto allocs = list.AllocInfos();\n        m_BLASHeapOffsetInBytes = (uint32)allocs[0].Offset;\n        m_scratchHeapOffsetInBytes = (uint32)allocs[1].Offset;\n    }\n\n    Assert(m_BLASHeapOffsetInBytes != UINT32_MAX, \"Invalid heap offset.\");\n    Assert(m_scratchHeapOffsetInBytes != UINT32_MAX, \"Invalid heap offset.\");\n\n    m_buffer = GpuMemory::GetPlacedHeapBuffer(\"StaticBLAS\",\n        (uint32_t)m_prebuildInfo.ResultDataMaxSizeInBytes,\n        m_resHeap.Heap(),\n        m_BLASHeapOffsetInBytes,\n        true,\n        true);\n    m_scratch = GpuMemory::GetPlacedHeapBuffer(\"StaticBLAS_scratch\",\n        scratchBuffSizeInBytes,\n        m_resHeap.Heap(),\n        m_scratchHeapOffsetInBytes,\n        true,\n        false);\n\n    // For reading back the compacted size\n    m_postBuildInfoReadback = GpuMemory::GetReadbackHeapBuffer(\n        sizeof(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE_DESC));\n\n    buildDesc.DestAccelerationStructureData = m_buffer.GpuVA();\n    buildDesc.ScratchAccelerationStructureData = m_scratch.GpuVA();\n    buildDesc.SourceAccelerationStructureData = 0;\n\n    D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC compactionDesc;\n    compactionDesc.InfoType = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE;\n    compactionDesc.DestBuffer = m_scratch.GpuVA() + compactionInfoStartOffset;\n\n    cmdList.PIXBeginEvent(\"StaticBLASBuild\");\n\n    cmdList.BuildRaytracingAccelerationStructure(&buildDesc, 1, &compactionDesc);\n\n    // Wait until build is completed before copying the compacted size\n    auto barrier = Direct3DUtil::BufferBarrier(m_scratch.Resource(),\n        D3D12_BARRIER_SYNC_COMPUTE_SHADING,\n        D3D12_BARRIER_SYNC_COPY,\n        D3D12_BARRIER_ACCESS_UNORDERED_ACCESS,\n        D3D12_BARRIER_ACCESS_COPY_SOURCE);\n\n    cmdList.ResourceBarrier(barrier);\n\n    cmdList.CopyBufferRegion(m_postBuildInfoReadback.Resource(),\n        0,\n        m_scratch.Resource(),\n        compactionInfoStartOffset,\n        sizeof(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE_DESC));\n\n    cmdList.PIXEndEvent();\n\n    m_BLASHeapOffsetInBytes = UINT32_MAX;\n    m_scratchHeapOffsetInBytes = UINT32_MAX;\n}\n\nvoid StaticBLAS::DoCompaction(ComputeCmdList& cmdList)\n{\n    D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE_DESC compactDesc;\n\n    m_postBuildInfoReadback.Map();\n    memcpy(&compactDesc, m_postBuildInfoReadback.MappedMemory(), sizeof(compactDesc));\n\n    Check(compactDesc.CompactedSizeInBytes > 0, \"Invalid RtAS compacted size.\");\n    LOG_UI_INFO(\"Allocated compacted static BLAS (%llu MB -> %llu MB).\", \n        m_prebuildInfo.ResultDataMaxSizeInBytes / (1024 * 1024),\n        compactDesc.CompactedSizeInBytes / (1024 * 1024));\n\n    // Allocate a new BLAS with compacted size\n    m_bufferCompacted = GpuMemory::GetDefaultHeapBuffer(\"CompactStaticBLAS\",\n        (uint32_t)compactDesc.CompactedSizeInBytes,\n        true,\n        true);\n\n    cmdList.PIXBeginEvent(\"StaticBLAS_Compaction\");\n    cmdList.CompactAccelerationStructure(m_bufferCompacted.GpuVA(), m_buffer.GpuVA());\n    cmdList.PIXEndEvent();\n}\n\nvoid StaticBLAS::CompactionCompletedCallback()\n{\n    m_compactionCompleted.store(true, std::memory_order_release);\n    m_heapAllocated.store(false, std::memory_order_relaxed);\n\n    // Release resources that are not needed anymore\n    m_postBuildInfoReadback.Unmap();\n    m_scratch.Reset();\n    m_postBuildInfoReadback.Reset();\n    m_perMeshTransform.Reset();\n    m_resHeap.Reset();\n}\n\n//--------------------------------------------------------------------------------------\n// TLAS\n//--------------------------------------------------------------------------------------\n\nvoid TLAS::FillMeshInstanceData(uint64_t instanceID, uint64_t meshID, const float4x3& M,\n    uint32_t emissiveTriOffset, bool staticMesh, uint32_t currInstance)\n{\n    Assert(meshID != Scene::INVALID_MESH, \"Invalid call.\");\n\n    SceneCore& scene = App::GetScene();\n    const TriangleMesh* mesh = scene.GetMesh(meshID).value();\n    uint32 matBufferIdx = UINT32_MAX;\n    const Material* mat = scene.GetMaterial(mesh->m_materialID, &matBufferIdx).value();\n\n    v_float4x4 vM = load4x3(M);\n\n    // Meshes in TLAS go through the following transformations:\n    // \n    // 1. Optional transform during BLAS build\n    // 2. Per-instance transform for each BLAS instance in TLAS\n    //\n    // When accessing triangle data in closest-hit shaders, transform 2 can be accessed\n    // using the ObjectToWorld3x4() intrinsic, but transform 1 is lost\n    float4a t;\n    float4a r;\n    float4a s;\n    decomposeSRT(vM, s, r, t);\n\n    m_frameInstanceData[currInstance].MatIdx = (uint16_t)matBufferIdx;\n    m_frameInstanceData[currInstance].BaseVtxOffset = mesh->m_vtxBuffStartOffset;\n    m_frameInstanceData[currInstance].BaseIdxOffset = mesh->m_idxBuffStartOffset;\n    m_frameInstanceData[currInstance].Rotation = unorm4::FromNormalized(r);\n    m_frameInstanceData[currInstance].Scale = half3(s);\n    m_frameInstanceData[currInstance].Translation = float3(t.x, t.y, t.z);\n    m_frameInstanceData[currInstance].BaseEmissiveTriOffset = emissiveTriOffset;\n\n    const uint32_t texIdx = mat->GetBaseColorTex();\n    m_frameInstanceData[currInstance].BaseColorTex = texIdx == Material::INVALID_ID ?\n        UINT16_MAX :\n        (uint16_t)texIdx;\n\n    float alpha = float((mat->BaseColorFactor >> 24) & 0xff) / 255.0f;\n    m_frameInstanceData[currInstance].AlphaFactor_Cutoff =\n        Float2ToRG8(float2(alpha, mat->GetAlphaCutoff()));\n\n    if (!staticMesh)\n    {\n        const float4x3& M_prev = *scene.GetPrevToWorld(instanceID).value();\n        v_float4x4 vM_prev = load4x3(M_prev);\n        float4a t_prev;\n        float4a r_prev;\n        float4a s_prev;\n        decomposeSRT(vM_prev, s_prev, r_prev, t_prev);\n\n        m_frameInstanceData[currInstance].PrevRotation = unorm4::FromNormalized(r_prev);\n        m_frameInstanceData[currInstance].PrevScale = half3(s_prev);\n        m_frameInstanceData[currInstance].dTranslation = half3(t - t_prev);\n    }\n    else\n    {\n        m_frameInstanceData[currInstance].PrevRotation =\n            m_frameInstanceData[currInstance].Rotation;\n        m_frameInstanceData[currInstance].PrevScale =\n            m_frameInstanceData[currInstance].Scale;\n        m_frameInstanceData[currInstance].dTranslation = half3(0, 0, 0);\n    }\n}\n\nvoid TLAS::RebuildFrameMeshInstanceData()\n{\n    SceneCore& scene = App::GetScene();\n    const uint32_t numInstances = scene.m_numStaticInstances + scene.m_numDynamicInstances;\n    m_frameInstanceData.resize(numInstances);\n\n    size_t currInstance = 0;\n    const bool sceneHasEmissives = scene.NumEmissiveInstances() > 0;\n\n    // Resize to avoid repeatedly growing it\n    scene.m_rtMeshInstanceIdxToID.resize(numInstances);\n\n    // Layout:\n    // \n    //  - N static meshes (SM)\n    //  - D dynamic meshes (DM)\n    //  -------------------------------------------------------------\n    // | SM 0 | SM 1 | ... | SM N - 1 | DM 0 | DM 1 | ... | DM D - 1 |\n    //  -------------------------------------------------------------\n    // \n    //  - TLAS instance for static BLAS has instanceID of 0. \n    //  - TLAS instance for dynamic BLAS d where 0 <= d < D has InstanceID of N + d\n    //  - With this setup, every instance can use GeometryIndex() + InstanceID() to index \n    //    into the mesh instance buffer\n\n    // Static meshes\n    if (scene.m_numStaticInstances)\n    {\n        for (size_t treeLevelIdx = 1; treeLevelIdx < scene.m_sceneGraph.size(); treeLevelIdx++)\n        {\n            auto& currTreeLevel = scene.m_sceneGraph[treeLevelIdx];\n            const auto& rtFlagVec = currTreeLevel.m_rtFlags;\n\n            for (size_t i = 0; i < rtFlagVec.size(); i++)\n            {\n                const auto rtFlags = RT_Flags::Decode(currTreeLevel.m_rtFlags[i]);\n                const uint64_t meshID = currTreeLevel.m_meshIDs[i];\n                if (meshID == Scene::INVALID_MESH)\n                    continue;\n\n                if (rtFlags.MeshMode == RT_MESH_MODE::STATIC)\n                {\n                    const uint64_t instanceID = currTreeLevel.m_IDs[i];\n                    const uint32_t emissiveTriOffset = sceneHasEmissives &&\n                        (rtFlags.InstanceMask & RT_AS_SUBGROUP::EMISSIVE) ?\n                        scene.m_emissives.FindInstance(instanceID).value()->BaseTriOffset :\n                        UINT32_MAX;\n\n                    FillMeshInstanceData(instanceID, meshID, currTreeLevel.m_toWorlds[i], \n                        emissiveTriOffset, true, (uint32)currInstance);\n\n                    // Update RT mesh to instance ID map\n                    scene.m_rtMeshInstanceIdxToID[currInstance++] = currTreeLevel.m_IDs[i];\n                }\n            }\n        }\n    }\n\n    Assert(currInstance == scene.m_numStaticInstances, \"Invalid instance count.\");\n\n    // Dynamic meshes\n    if (scene.m_numDynamicInstances)\n    {\n        for (size_t treeLevelIdx = 1; treeLevelIdx < scene.m_sceneGraph.size(); treeLevelIdx++)\n        {\n            auto& currTreeLevel = scene.m_sceneGraph[treeLevelIdx];\n            const auto& rtFlagVec = currTreeLevel.m_rtFlags;\n\n            for (size_t i = 0; i < rtFlagVec.size(); i++)\n            {\n                const auto rtFlags = RT_Flags::Decode(currTreeLevel.m_rtFlags[i]);\n                const uint64_t meshID = currTreeLevel.m_meshIDs[i];\n                if (meshID == Scene::INVALID_MESH)\n                    continue;\n\n                if (rtFlags.MeshMode == RT_MESH_MODE::DYNAMIC_NO_REBUILD)\n                {\n                    const uint64_t instanceID = currTreeLevel.m_IDs[i];\n                    const uint32_t emissiveTriOffset = sceneHasEmissives &&\n                        (rtFlags.InstanceMask & RT_AS_SUBGROUP::EMISSIVE) ?\n                        scene.m_emissives.FindInstance(instanceID).value()->BaseTriOffset :\n                        UINT32_MAX;\n\n                    FillMeshInstanceData(instanceID, meshID, currTreeLevel.m_toWorlds[i], \n                        emissiveTriOffset, false, (uint32)currInstance);\n\n                    // Update RT mesh to instance ID map\n                    scene.m_rtMeshInstanceIdxToID[currInstance++] = currTreeLevel.m_IDs[i];\n                }\n            }\n        }\n    }\n\n    Assert(currInstance == numInstances, \"Invalid instance count.\");\n\n    const uint32_t sizeInBytes = numInstances * sizeof(RT::MeshInstance);\n\n    PlacedResourceList<2> list;\n    list.PushBuffer(sizeInBytes, false, false);\n    list.PushBuffer(sizeInBytes, false, false);\n    list.End();\n    m_meshInstanceResHeap = GpuMemory::GetResourceHeap(list.TotalSizeInBytes());\n\n    m_framesMeshInstances[m_frameIdx] = GpuMemory::GetPlacedHeapBufferAndInit(\n        GlobalResource::RT_FRAME_MESH_INSTANCES_CURR,\n        sizeInBytes,\n        m_meshInstanceResHeap.Heap(),\n        list.AllocInfos()[0].Offset,\n        false,\n        MemoryRegion{ .Data = m_frameInstanceData.data(), .SizeInBytes = sizeInBytes });\n    m_framesMeshInstances[1 - m_frameIdx] = GpuMemory::GetPlacedHeapBufferAndInit(\n        GlobalResource::RT_FRAME_MESH_INSTANCES_PREV,\n        sizeInBytes,\n        m_meshInstanceResHeap.Heap(),\n        list.AllocInfos()[1].Offset,\n        false,\n        MemoryRegion{ .Data = m_frameInstanceData.data(), .SizeInBytes = sizeInBytes });\n\n    // Register the shared resources\n    auto& r = App::GetRenderer().GetSharedShaderResources();\n    r.InsertOrAssignDefaultHeapBuffer(GlobalResource::RT_FRAME_MESH_INSTANCES_CURR,\n        m_framesMeshInstances[m_frameIdx]);\n    r.InsertOrAssignDefaultHeapBuffer(GlobalResource::RT_FRAME_MESH_INSTANCES_PREV,\n        m_framesMeshInstances[1 - m_frameIdx]);\n}\n\nvoid TLAS::UpdateFrameMeshInstances_StaticToDynamic()\n{\n    SceneCore& scene = App::GetScene();\n    const uint32_t numInstances = scene.m_numStaticInstances + scene.m_numDynamicInstances;\n    const bool sceneHasEmissives = scene.NumEmissiveInstances() > 0;\n    uint32_t copyStartOffset = UINT32_MAX;\n\n    // Note: GetInstanceRtASInfo() calls must happen before m_rtASInfo is updated \n    // (by RebuildTLASInstances() & StaticBLAS::Rebuild())\n\n    // Sort in descending order (see visualization below)\n    std::sort(scene.m_pendingRtMeshModeSwitch.begin(), scene.m_pendingRtMeshModeSwitch.end(),\n        [&scene](const uint64_t& lhs, const uint64_t& rhs)\n        {\n            RT_AS_Info lhsAsInfo = scene.GetInstanceRtASInfo(lhs);\n            RT_AS_Info rhsAsInfo = scene.GetInstanceRtASInfo(rhs);\n            Assert(lhsAsInfo.InstanceID == 0 && rhsAsInfo.InstanceID == 0, \n                \"InstanceID for static meshes must be zero.\");\n\n            return lhsAsInfo.GeometryIndex > rhsAsInfo.GeometryIndex;\n        });\n\n    // Shift left\n    // \n    // MeshesToSwitch                *       *\n    // FrameInstanceArray: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8\n    //                               *\n    //                     | 0 | 1 | 2 | 3 | 5 | 6 | 7 | 8 | 8\n    //                     | 0 | 1 | 3 | 5 | 6 | 7 | 8 | 8 | 8\n    for (size_t i = 0; i < scene.m_pendingRtMeshModeSwitch.size(); i++)\n    {\n        const auto instance = scene.m_pendingRtMeshModeSwitch[i];\n        const RT_AS_Info asInfo = scene.GetInstanceRtASInfo(instance);\n        // One less instance to move per iteration\n        const int64 numToMove = numInstances - asInfo.GeometryIndex - 1 - i;\n\n        memmove(m_frameInstanceData.data() + asInfo.GeometryIndex,\n            m_frameInstanceData.data() + asInfo.GeometryIndex + 1,\n            numToMove * sizeof(RT::MeshInstance));\n        memmove(scene.m_rtMeshInstanceIdxToID.data() + asInfo.GeometryIndex,\n            scene.m_rtMeshInstanceIdxToID.data() + asInfo.GeometryIndex + 1,\n            numToMove * sizeof(uint64_t));\n\n        // Last element is the smallest\n        if (i == scene.m_pendingRtMeshModeSwitch.size() - 1)\n            copyStartOffset = asInfo.GeometryIndex;\n    }\n\n    uint32_t currInstance = numInstances - (uint32)scene.m_pendingRtMeshModeSwitch.size();\n\n    struct TreePosAndIdx\n    {\n        uint32_t TreeLevel;\n        uint32_t LevelIdx;\n        uint32_t PreSortIdx;\n    };\n\n    SmallVector<TreePosAndIdx, App::FrameAllocator> dynamicInstanceTreePositions;\n    dynamicInstanceTreePositions.reserve(scene.m_numDynamicInstances);\n\n    Assert(m_dynamicBLASes.size() + scene.m_pendingRtMeshModeSwitch.size() == \n        scene.m_numDynamicInstances, \"Unexpected value.\");\n\n    // Append existing dynamic meshes\n    for (size_t i = 0; i < m_dynamicBLASes.size(); i++)\n    {\n        dynamicInstanceTreePositions.push_back(TreePosAndIdx{ \n            .TreeLevel = m_dynamicBLASes[i].TreeLevel,\n            .LevelIdx = m_dynamicBLASes[i].LevelIdx, \n            .PreSortIdx = (uint32)i });\n    }\n\n    // Append the newly converted dynamic meshes\n    for (size_t i = 0; i < scene.m_pendingRtMeshModeSwitch.size(); i++)\n    {\n        const auto instance = scene.m_pendingRtMeshModeSwitch[i];\n        const auto treePos = scene.FindTreePosFromID(instance).value();\n        auto& currTreeLevel = scene.m_sceneGraph[treePos.Level];\n        const auto rtFlags = RT_Flags::Decode(currTreeLevel.m_rtFlags[treePos.Offset]);\n\n        const uint64_t meshID = currTreeLevel.m_meshIDs[treePos.Offset];\n        Assert(meshID != Scene::INVALID_MESH, \"Invalid mesh\");\n\n        const uint32_t emissiveTriOffset = sceneHasEmissives &&\n            (rtFlags.InstanceMask & RT_AS_SUBGROUP::EMISSIVE) ?\n            scene.m_emissives.FindInstance(instance).value()->BaseTriOffset :\n            UINT32_MAX;\n\n        // Unsorted, sort happens below\n        FillMeshInstanceData(instance, meshID, currTreeLevel.m_toWorlds[treePos.Offset],\n            emissiveTriOffset, false, currInstance);\n        scene.m_rtMeshInstanceIdxToID[currInstance++] = instance;\n\n        dynamicInstanceTreePositions.push_back(TreePosAndIdx{\n            .TreeLevel = treePos.Level,\n            .LevelIdx = treePos.Offset,\n            .PreSortIdx = (uint32)(i + m_dynamicBLASes.size()) });\n    }\n\n    // Sort the dynamic instances based on tree position\n    std::sort(dynamicInstanceTreePositions.begin(), dynamicInstanceTreePositions.end(),\n        [](const TreePosAndIdx& lhs, const TreePosAndIdx& rhs)\n        {\n            if (lhs.TreeLevel < rhs.TreeLevel)\n                return true;\n            else if (lhs.TreeLevel > rhs.TreeLevel)\n                return false;\n\n            return lhs.LevelIdx < rhs.LevelIdx;\n        });    \n    \n    // m_frameInstanceData & m_rtMeshInstanceIdxToID for new elements were filled above\n    SmallVector<RT::MeshInstance, App::FrameAllocator> tempMeshInstances;\n    tempMeshInstances.resize(scene.m_numDynamicInstances);\n    memcpy(tempMeshInstances.data(), m_frameInstanceData.data() + scene.m_numStaticInstances,\n        scene.m_numDynamicInstances * sizeof(RT::MeshInstance));\n\n    SmallVector<uint64_t, App::FrameAllocator> tempRtMeshInstanceIdxToID;\n    tempRtMeshInstanceIdxToID.resize(scene.m_numDynamicInstances);\n    memcpy(tempRtMeshInstanceIdxToID.data(), scene.m_rtMeshInstanceIdxToID.data() + scene.m_numStaticInstances,\n        scene.m_numDynamicInstances * sizeof(uint64_t));\n\n    for (size_t i = 0; i < scene.m_numDynamicInstances; i++)\n    {\n        const auto& sorted = dynamicInstanceTreePositions[i];\n\n        m_frameInstanceData[scene.m_numStaticInstances + i] = \n            tempMeshInstances[sorted.PreSortIdx];\n        scene.m_rtMeshInstanceIdxToID[scene.m_numStaticInstances + i] = \n            tempRtMeshInstanceIdxToID[sorted.PreSortIdx];\n    }\n\n    // Copy from the smallest modified entry\n    Assert(copyStartOffset != UINT32_MAX, \"copyStartOffset hasn't been set.\");\n    const uint32_t copySizeInBytes = (numInstances - copyStartOffset) * sizeof(RT::MeshInstance);\n\n    GpuMemory::UploadToDefaultHeapBuffer(m_framesMeshInstances[m_frameIdx], copySizeInBytes,\n        MemoryRegion{ .Data = m_frameInstanceData.data() + copyStartOffset,\n        .SizeInBytes = copySizeInBytes },\n        copyStartOffset * sizeof(RT::MeshInstance));\n}\n\nvoid TLAS::UpdateFrameMeshInstances_NewTransform()\n{\n    SceneCore& scene = App::GetScene();\n    const bool sceneHasEmissives = scene.NumEmissiveInstances() > 0;\n    int64 minIdx = m_dynamicBLASes.size() - 1;\n    int64 maxIdx = 0;\n\n    for (auto it = scene.m_instanceUpdates.begin_it(); it != scene.m_instanceUpdates.end_it();\n        it = scene.m_instanceUpdates.next_it(it))\n    {\n        const auto instance = it->Key;\n        const auto treePos = scene.FindTreePosFromID(instance).value();\n        const auto& treeLevel = scene.m_sceneGraph[treePos.Level];\n\n        const auto rtFlags = RT_Flags::Decode(treeLevel.m_rtFlags[treePos.Offset]);\n        const uint32_t emissiveTriOffset = sceneHasEmissives &&\n            (rtFlags.InstanceMask & RT_AS_SUBGROUP::EMISSIVE) ?\n            scene.m_emissives.FindInstance(instance).value()->BaseTriOffset :\n            UINT32_MAX;\n\n        auto vecIt = std::lower_bound(m_dynamicBLASes.begin(), m_dynamicBLASes.end(), treePos,\n            [](const DynamicBLAS& lhs, const SceneCore::TreePos& key)\n            {\n                if (lhs.TreeLevel < key.Level)\n                    return true;\n                else if (lhs.TreeLevel > key.Level)\n                    return false;\n\n                return lhs.LevelIdx < key.Offset;\n            });\n\n        Assert(vecIt != m_dynamicBLASes.end(), \"Dynamic BLAS for instance was not found.\");\n        const auto& blas = *vecIt;\n        Assert(blas.TreeLevel == treePos.Level && blas.LevelIdx == treePos.Offset,\n            \"Dynamic BLAS for instance was not found.\");\n        const auto idx = vecIt - m_dynamicBLASes.begin();\n\n        FillMeshInstanceData(instance, treeLevel.m_meshIDs[treePos.Offset],\n            treeLevel.m_toWorlds[treePos.Offset], \n            emissiveTriOffset, \n            false, \n            blas.InstanceID);\n\n        minIdx = Min(minIdx, idx);\n        maxIdx = Max(maxIdx, idx);\n    }\n\n    Assert(minIdx <= maxIdx, \"Invalid range.\");\n    const size_t numInstancesToCopy = maxIdx - minIdx + 1;\n    const size_t sizeInBytes = numInstancesToCopy * sizeof(RT::MeshInstance);\n    const size_t offset = scene.m_numStaticInstances + minIdx;\n\n    GpuMemory::UploadToDefaultHeapBuffer(m_framesMeshInstances[m_frameIdx], (uint32)sizeInBytes,\n        MemoryRegion{ .Data = m_frameInstanceData.data() + offset,\n        .SizeInBytes = sizeInBytes },\n        (uint32)(offset * sizeof(RT::MeshInstance)));\n}\n\nvoid TLAS::Update()\n{\n    SceneCore& scene = App::GetScene();\n    m_frameIdx = 1 - m_frameIdx;\n    ID3D12Heap* heap = nullptr;\n    uint32_t meshTransformHeapOffsetInBytes = 0;\n\n    // Avoid rebuild while compaction is in progress (it'll be queued up for later)\n    if (!scene.m_pendingRtMeshModeSwitch.empty() && m_staticBLASCompacted)\n    {\n        Assert(m_staticBLAS.m_prebuildInfo.ResultDataMaxSizeInBytes != UINT32_MAX,\n            \"Unexpected value.\");\n\n        // Use the same buffer for scratch and compaction info\n        const uint32_t compactionInfoStartOffset = (uint32_t)AlignUp(\n            m_staticBLAS.m_prebuildInfo.ScratchDataSizeInBytes,\n            alignof(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE_DESC));\n        const uint32_t scratchBufferSizeInBytes = compactionInfoStartOffset +\n            sizeof(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE_DESC);\n\n        PlacedResourceList<3> list;\n        // BLAS (before compaction)\n        list.PushBuffer((uint32_t)m_staticBLAS.m_prebuildInfo.ResultDataMaxSizeInBytes, true, true);\n        // Scratch buffer & compaction info\n        list.PushBuffer(scratchBufferSizeInBytes, true, false);\n        // Per mesh transform during BLAS build\n        list.PushBuffer(scene.m_numStaticInstances * sizeof(BLASTransform), true, false);\n        list.End();\n\n        // Do heap allocation on a background thread to avoid a hitch\n        if (m_staticBLAS.m_heapAllocated.load(std::memory_order_acquire))\n        {\n            Assert(m_staticBLAS.m_resHeap.IsInitialized(), \"Unexpected condition.\");\n            heap = m_staticBLAS.m_resHeap.Heap();\n\n            auto allocs = list.AllocInfos();\n            m_staticBLAS.m_BLASHeapOffsetInBytes = (uint32)allocs[0].Offset;\n            m_staticBLAS.m_scratchHeapOffsetInBytes = (uint32)allocs[1].Offset;\n            meshTransformHeapOffsetInBytes = (uint32)allocs[2].Offset;\n\n            m_updateType = UPDATE_TYPE::STATIC_TO_DYNAMIC;\n            m_staticBLASCompacted = false;\n            m_staticBLAS.m_heapAllocationInProgress = false;\n        }\n        else if(!m_staticBLAS.m_heapAllocationInProgress)\n        {\n            const uint64_t heapSizeInBytes = list.TotalSizeInBytes();\n            m_staticBLAS.m_heapAllocationInProgress = true;\n\n            Task t(\"AllocateHeap\", TASK_PRIORITY::BACKGROUND, [this, heapSizeInBytes]()\n                {\n                    m_staticBLAS.m_resHeap = GpuMemory::GetResourceHeap(heapSizeInBytes);\n                    m_staticBLAS.m_heapAllocated.store(true, std::memory_order_release);\n                });\n\n            App::SubmitBackground(ZetaMove(t));\n        }\n    }\n    // Make sure updates are performed even if compaction is in progress \n    // (when m_staticBLASCompacted = false)\n    else if (!scene.m_instanceUpdates.empty())\n    {\n        m_updateType = UPDATE_TYPE::INSTANCE_TRANSFORM;\n    }\n\n    const bool firstTime = m_frameInstanceData.empty();\n\n    if (firstTime || m_updateType == UPDATE_TYPE::STATIC_TO_DYNAMIC)\n    {\n        Assert(firstTime || heap, \"Invalid condition.\");\n        m_staticBLAS.FillMeshTransformBufferForBuild(heap, meshTransformHeapOffsetInBytes);\n    }\n\n    if(firstTime)\n        RebuildFrameMeshInstanceData();\n    else if (m_updateType == UPDATE_TYPE::STATIC_TO_DYNAMIC)\n        UpdateFrameMeshInstances_StaticToDynamic();\n    else if (m_updateType == UPDATE_TYPE::INSTANCE_TRANSFORM)\n        UpdateFrameMeshInstances_NewTransform();\n}\n\nvoid TLAS::Render(CommandList& cmdList)\n{\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT ||\n        cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE, \"Invalid downcast.\");\n    ComputeCmdList& computeCmdList = static_cast<ComputeCmdList&>(cmdList);\n\n    auto& gpuTimer = App::GetRenderer().GetGpuTimer();\n    computeCmdList.PIXBeginEvent(\"RtAS\");\n    const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"RtAS\");\n\n    RebuildOrUpdateBLASes(computeCmdList);\n    UpdateTLASInstances(computeCmdList);\n    RebuildTLAS(computeCmdList);\n\n    gpuTimer.EndQuery(computeCmdList, queryIdx);\n    computeCmdList.PIXEndEvent();\n}\n\nvoid TLAS::BuildDynamicBLASes(ComputeCmdList& cmdList)\n{\n    SceneCore& scene = App::GetScene();\n\n    SmallVector<DynamicBlasBuild, App::FrameAllocator> blasBuilds;\n    blasBuilds.reserve(scene.m_numDynamicInstances);\n    m_dynamicBLASes.reserve(scene.m_numDynamicInstances);\n\n    // Skip the first level\n    for (size_t treeLevelIdx = 1; treeLevelIdx < scene.m_sceneGraph.size(); treeLevelIdx++)\n    {\n        auto& currTreeLevel = scene.m_sceneGraph[treeLevelIdx];\n        auto& rtFlagVec = currTreeLevel.m_rtFlags;\n\n        for (size_t i = 0; i < rtFlagVec.size(); i++)\n        {\n            Scene::RT_Flags flags = RT_Flags::Decode(rtFlagVec[i]);\n            Assert((flags.RebuildFlag & flags.UpdateFlag) == 0,\n                \"Rebuild & update flags can't be set at the same time.\");\n\n            if (flags.MeshMode != RT_MESH_MODE::STATIC)\n            {\n                const TriangleMesh* mesh = scene.GetMesh(currTreeLevel.m_meshIDs[i]).value();\n                const auto sceneVBGpuVa = scene.GetMeshVB().GpuVA();\n                const auto sceneIBGpuVa = scene.GetMeshIB().GpuVA();\n\n                DynamicBlasBuild buildItem;\n                buildItem.TreeLevel = (uint32_t)treeLevelIdx;\n                buildItem.LevelIdx = (uint32_t)i;\n                buildItem.GeoDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES;\n                buildItem.GeoDesc.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NONE;\n                buildItem.GeoDesc.Triangles.IndexBuffer = sceneIBGpuVa + mesh->m_idxBuffStartOffset * sizeof(uint32_t);\n                buildItem.GeoDesc.Triangles.IndexCount = mesh->m_numIndices;\n                buildItem.GeoDesc.Triangles.IndexFormat = DXGI_FORMAT_R32_UINT;\n                buildItem.GeoDesc.Triangles.Transform3x4 = 0;\n                buildItem.GeoDesc.Triangles.VertexBuffer.StartAddress = sceneVBGpuVa +\n                    mesh->m_vtxBuffStartOffset * sizeof(Vertex);\n                buildItem.GeoDesc.Triangles.VertexBuffer.StrideInBytes = sizeof(Vertex);\n                buildItem.GeoDesc.Triangles.VertexCount = mesh->m_numVertices;\n                buildItem.GeoDesc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT;\n\n                blasBuilds.push_back(buildItem);\n\n                rtFlagVec[i] = RT_Flags::Encode(flags.MeshMode, flags.InstanceMask,\n                    0, 0, flags.IsOpaque);\n\n                currTreeLevel.m_rtASInfo[i] = RT_AS_Info{\n                    .GeometryIndex = 0,\n                    .InstanceID = scene.m_numStaticInstances + (uint32)blasBuilds.size() - 1 };\n            }\n        }\n    }\n\n    auto* device = App::GetRenderer().GetDevice();\n    uint32_t currBuildSizeInBytes = 0;\n    uint32_t currScratchSize = 0;\n\n    for (auto& b : blasBuilds)\n    {\n        D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc;\n        buildDesc.Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL;\n        buildDesc.Inputs.Flags = BuildFlags(RT_MESH_MODE::DYNAMIC_NO_REBUILD);\n        buildDesc.Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;\n        buildDesc.Inputs.NumDescs = 1;\n        buildDesc.Inputs.pGeometryDescs = &b.GeoDesc;\n\n        device->GetRaytracingAccelerationStructurePrebuildInfo(&buildDesc.Inputs, &b.BuildInfo);\n\n        Assert(b.BuildInfo.ResultDataMaxSizeInBytes > 0,\n            \"GetRaytracingAccelerationStructurePrebuildInfo() failed.\");\n\n        currBuildSizeInBytes = AlignUp(currBuildSizeInBytes,\n            uint32_t(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT));\n        b.BlasBufferOffset = currBuildSizeInBytes;\n        currBuildSizeInBytes += (uint32_t)b.BuildInfo.ResultDataMaxSizeInBytes;\n\n        currScratchSize = AlignUp(currScratchSize,\n            uint32_t(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT));\n        b.ScratchBufferOffset = currScratchSize;\n        currScratchSize += (uint32_t)b.BuildInfo.ScratchDataSizeInBytes;\n\n        // InstanceID is filled in by RebuildTLASInstances()\n        m_dynamicBLASes.push_back(DynamicBLAS{ .PageIdx = 0,\n            .PageOffset = b.BlasBufferOffset,\n            .TreeLevel = b.TreeLevel,\n            .LevelIdx = b.LevelIdx,\n            .InstanceID = UINT32_MAX });\n    }\n\n    Assert(m_dynamicBLASArenas.empty(), \"bug\");\n\n    const uint32_t sizeInBytes = Max(currBuildSizeInBytes, BLAS_ARENA_PAGE_SIZE);\n    auto page = GpuMemory::GetDefaultHeapBuffer(\"BLASArenaPage\",\n        sizeInBytes,\n        true,\n        true);\n\n    const uint32_t offsetInBytes = AlignUp(sizeInBytes,\n        uint32_t(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT));\n    m_dynamicBLASArenas.push_back(ArenaPage{ .Page = ZetaMove(page), .CurrOffset = offsetInBytes });\n\n    const uint32_t alignedScratchSize = AlignUp(currScratchSize,\n        (uint32_t)D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);\n\n    if (!m_scratchBuffer.IsInitialized() ||\n        m_scratchBuffer.Desc().Width < alignedScratchSize)\n    {\n        m_scratchBuffer = GpuMemory::GetDefaultHeapBuffer(\"DynamicBLAS_scratch\",\n            alignedScratchSize,\n            D3D12_RESOURCE_STATE_COMMON,\n            true);\n    }\n\n    for (auto& b : blasBuilds)\n    {\n        D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc;\n        buildDesc.Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL;\n        buildDesc.Inputs.Flags = BuildFlags(RT_MESH_MODE::DYNAMIC_NO_REBUILD);\n        buildDesc.Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;\n        buildDesc.Inputs.NumDescs = 1;\n        buildDesc.Inputs.pGeometryDescs = &b.GeoDesc;\n\n        buildDesc.DestAccelerationStructureData = m_dynamicBLASArenas[0].Page.GpuVA() +\n            b.BlasBufferOffset;\n        buildDesc.ScratchAccelerationStructureData = m_scratchBuffer.GpuVA() +\n            b.ScratchBufferOffset;\n        buildDesc.SourceAccelerationStructureData = 0;\n\n        cmdList.PIXBeginEvent(\"DynamicBLASBuild\");\n        cmdList.BuildRaytracingAccelerationStructure(&buildDesc, 0, nullptr);\n        cmdList.PIXEndEvent();\n    }\n}\n\nvoid TLAS::RebuildOrUpdateBLASes(ComputeCmdList& cmdList)\n{\n    SceneCore& scene = App::GetScene();\n\n    // From Ray Tracing Gems 1 Chapter 19:\n    // \"One important optimization is to ensure that any resource transition barriers that\n    // are needed after BLAS updates are deferred to be executed right before the\n    // TLAS build, instead of executing these right after each BLAS update. Deferral is\n    // important because each of these transition barriers is a synchronization step on\n    // the GPU. Having the transitions coalesced into a single point in the command buffer\n    // avoids redundant synchronization that would otherwise cause the GPU to frequently\n    // become idle.\"\n    SmallVector<D3D12_BUFFER_BARRIER, App::FrameAllocator> uavBarriers;\n    const bool staticBLASReady = !scene.m_numStaticInstances || m_staticBLASCompacted;\n\n    // Compacting static BLAS requires two CPU-GPU synchronizations that'll likely\n    // span multiple frames and has the following steps:\n    // \n    // 1. Build static BLAS for the first time and ask the GPU for compaction info\n    // 2. Wait for GPU to finish step 1\n    // 3. Read back compaction info on CPU and allocate a new buffer with the \n    //    compacted size. Then, record a command for compaction operation (on GPU).\n    // 4. Wait for GPU to finish step 3\n    // 5. Replace BLAS from step 1 with the new compacted BLAS \n    if (!staticBLASReady || m_updateType == UPDATE_TYPE::STATIC_TO_DYNAMIC)\n    {\n        // Step 1\n        if (!m_staticBLAS.m_buffer.IsInitialized() || m_updateType == UPDATE_TYPE::STATIC_TO_DYNAMIC)\n        {\n            m_staticBLAS.Rebuild(cmdList);\n\n            const D3D12_BUFFER_BARRIER barrier = Direct3DUtil::BufferBarrier(m_staticBLAS.m_buffer.Resource(),\n                D3D12_BARRIER_SYNC_BUILD_RAYTRACING_ACCELERATION_STRUCTURE,\n                D3D12_BARRIER_SYNC_BUILD_RAYTRACING_ACCELERATION_STRUCTURE | D3D12_BARRIER_SYNC_COMPUTE_SHADING,\n                D3D12_BARRIER_ACCESS_UNORDERED_ACCESS | D3D12_BARRIER_ACCESS_RAYTRACING_ACCELERATION_STRUCTURE_WRITE,\n                D3D12_BARRIER_ACCESS_RAYTRACING_ACCELERATION_STRUCTURE_READ);\n\n            uavBarriers.push_back(barrier);\n\n            // Step 2\n            Task t(\"WaitForRtAsBuild\", TASK_PRIORITY::BACKGROUND, [this]()\n                {\n                    m_waitObj.Reset();\n                    App::GetScene().GetRenderGraph()->SetFrameSubmissionWaitObj(m_waitObj);\n                    m_waitObj.Wait();\n\n                    const uint64_t fence = App::GetScene().GetRenderGraph()->GetFrameCompletionFence();\n                    Assert(fence != UINT64_MAX, \"Invalid fence value.\");\n\n                    App::GetRenderer().WaitForDirectQueueFenceCPU(fence);\n                    m_compactionInfoReady.store(true, std::memory_order_release);\n                });\n\n            App::SubmitBackground(ZetaMove(t));\n        }\n        // Step 3\n        else if (m_compactionInfoReady.load(std::memory_order_acquire))\n        {\n            // Read compaction info and submit a compaction command\n            m_staticBLAS.DoCompaction(cmdList);\n\n            m_waitObj.Reset();\n            App::GetScene().GetRenderGraph()->SetFrameSubmissionWaitObj(m_waitObj);\n\n            // Step 4\n            Task t(\"ReleaseRtAsBuffers\", TASK_PRIORITY::BACKGROUND, [this]()\n                {\n                    m_waitObj.Wait();\n\n                    const uint64_t fence = App::GetScene().GetRenderGraph()->GetFrameCompletionFence();\n                    Assert(fence != UINT64_MAX, \"Invalid fence value.\");\n\n                    App::GetRenderer().WaitForDirectQueueFenceCPU(fence);\n                    m_staticBLAS.CompactionCompletedCallback();\n                });\n\n            App::SubmitBackground(ZetaMove(t));\n            m_compactionInfoReady.store(false, std::memory_order_relaxed);\n        }\n        // Step 5\n        else if (m_staticBLAS.m_compactionCompleted.load(std::memory_order_acquire))\n        {\n            m_staticBLAS.m_buffer = ZetaMove(m_staticBLAS.m_bufferCompacted);\n            m_staticBLASCompacted = true;\n            m_updateType = UPDATE_TYPE::STATIC_BLAS_COMPACTED;\n\n            m_staticBLAS.m_compactionCompleted.store(false, std::memory_order_relaxed);\n        }\n    }\n\n    // Once in the first frame\n    if (m_rebuildDynamicBLASes && scene.m_numDynamicInstances)\n    {\n        BuildDynamicBLASes(cmdList);\n\n        // One barrier covers all of the builds\n        D3D12_BUFFER_BARRIER barrier = Direct3DUtil::BufferBarrier(m_dynamicBLASArenas[0].Page.Resource(),\n            D3D12_BARRIER_SYNC_BUILD_RAYTRACING_ACCELERATION_STRUCTURE,\n            D3D12_BARRIER_SYNC_BUILD_RAYTRACING_ACCELERATION_STRUCTURE | D3D12_BARRIER_SYNC_COMPUTE_SHADING,\n            D3D12_BARRIER_ACCESS_UNORDERED_ACCESS | D3D12_BARRIER_ACCESS_RAYTRACING_ACCELERATION_STRUCTURE_WRITE,\n            D3D12_BARRIER_ACCESS_RAYTRACING_ACCELERATION_STRUCTURE_READ);\n\n        uavBarriers.push_back(barrier);\n    }\n\n    if (m_updateType == UPDATE_TYPE::STATIC_TO_DYNAMIC && scene.m_numDynamicInstances)\n    {\n        Assert(!scene.m_pendingRtMeshModeSwitch.empty(), \"Unexpected condition.\");\n\n        SmallVector<DynamicBlasBuild, SystemAllocator, 3> builds;\n        builds.reserve(scene.m_pendingRtMeshModeSwitch.size());\n\n        for (auto instance : scene.m_pendingRtMeshModeSwitch)\n        {\n            const auto treePos = scene.FindTreePosFromID(instance).value();\n            const auto meshID = scene.m_sceneGraph[treePos.Level].m_meshIDs[treePos.Offset];\n\n            const TriangleMesh* mesh = scene.GetMesh(meshID).value();\n            const auto sceneVBGpuVa = scene.GetMeshVB().GpuVA();\n            const auto sceneIBGpuVa = scene.GetMeshIB().GpuVA();\n\n            DynamicBlasBuild build;\n            build.GeoDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES;\n            build.GeoDesc.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NONE;\n            build.GeoDesc.Triangles.IndexBuffer = sceneIBGpuVa + mesh->m_idxBuffStartOffset * sizeof(uint32_t);\n            build.GeoDesc.Triangles.IndexCount = mesh->m_numIndices;\n            build.GeoDesc.Triangles.IndexFormat = DXGI_FORMAT_R32_UINT;\n            build.GeoDesc.Triangles.Transform3x4 = 0;\n            build.GeoDesc.Triangles.VertexBuffer.StartAddress = sceneVBGpuVa +\n                mesh->m_vtxBuffStartOffset * sizeof(Vertex);\n            build.GeoDesc.Triangles.VertexBuffer.StrideInBytes = sizeof(Vertex);\n            build.GeoDesc.Triangles.VertexCount = mesh->m_numVertices;\n            build.GeoDesc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT;\n\n            build.TreeLevel = treePos.Level;\n            build.LevelIdx = treePos.Offset;\n\n            builds.push_back(build);\n        }\n\n        uint32_t totalScratchDataSizeInBytes = 0;\n\n        for (auto& b : builds)\n        {\n            D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc{};\n            buildDesc.Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL;\n            buildDesc.Inputs.Flags = BuildFlags(RT_MESH_MODE::DYNAMIC_NO_REBUILD);\n            buildDesc.Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;\n            buildDesc.Inputs.NumDescs = 1;\n            buildDesc.Inputs.pGeometryDescs = &b.GeoDesc;\n\n            App::GetRenderer().GetDevice()->GetRaytracingAccelerationStructurePrebuildInfo(\n                &buildDesc.Inputs, &b.BuildInfo);\n\n            Assert(b.BuildInfo.ResultDataMaxSizeInBytes > 0,\n                \"GetRaytracingAccelerationStructurePrebuildInfo() failed.\");\n\n            totalScratchDataSizeInBytes = AlignUp(totalScratchDataSizeInBytes,\n                (uint32)D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT);\n            b.ScratchBufferOffset = totalScratchDataSizeInBytes;\n\n            totalScratchDataSizeInBytes += (uint32)b.BuildInfo.ScratchDataSizeInBytes;\n        }\n\n        const uint32_t alignedScratchSize = AlignUp(totalScratchDataSizeInBytes,\n            (uint32_t)D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);\n\n        if (!m_scratchBuffer.IsInitialized() ||\n            m_scratchBuffer.Desc().Width < totalScratchDataSizeInBytes)\n        {\n            m_scratchBuffer = GpuMemory::GetDefaultHeapBuffer(\"DynamicBLAS_scratch\",\n                alignedScratchSize,\n                D3D12_RESOURCE_STATE_COMMON,\n                true);\n        }\n\n        SmallVector<int, App::FrameAllocator, 3> touchedPages;\n\n        for (auto& b : builds)\n        {\n            if (!m_dynamicBLASArenas.empty())\n            {\n                m_dynamicBLASArenas.back().CurrOffset = AlignUp(m_dynamicBLASArenas.back().CurrOffset,\n                    (uint32_t)D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT);\n            }\n\n            if (m_dynamicBLASArenas.empty() ||\n                (m_dynamicBLASArenas.back().CurrOffset + b.BuildInfo.ResultDataMaxSizeInBytes >=\n                    m_dynamicBLASArenas.back().Page.Desc().Width))\n            {\n                const uint32_t sizeInBytes = Max((uint32)b.BuildInfo.ResultDataMaxSizeInBytes,\n                    BLAS_ARENA_PAGE_SIZE);\n                auto page = GpuMemory::GetDefaultHeapBuffer(\"BLASArenaPage\",\n                    sizeInBytes,\n                    true,\n                    true);\n\n                m_dynamicBLASArenas.push_back(ArenaPage{ .Page = ZetaMove(page),\n                    .CurrOffset = 0 });\n\n                LOG_UI_INFO(\"Allocated dynamic BLAS page (%llu MB)...\", sizeInBytes / (1024 * 1024));\n            }\n\n            // InstanceID is filled in by RebuildTLASInstances()\n            m_dynamicBLASes.push_back(DynamicBLAS{ .PageIdx = (int)m_dynamicBLASArenas.size() - 1,\n                .PageOffset = m_dynamicBLASArenas.back().CurrOffset,\n                .TreeLevel = b.TreeLevel,\n                .LevelIdx = b.LevelIdx,\n                .InstanceID = UINT32_MAX });\n            m_dynamicBLASArenas.back().CurrOffset += (uint32)b.BuildInfo.ResultDataMaxSizeInBytes;\n\n            touchedPages.push_back((int)(m_dynamicBLASArenas.size() - 1));\n\n            D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc{};\n            buildDesc.Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL;\n            buildDesc.Inputs.Flags = BuildFlags(RT_MESH_MODE::DYNAMIC_NO_REBUILD);\n            buildDesc.Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;\n            buildDesc.Inputs.NumDescs = 1;\n            buildDesc.Inputs.pGeometryDescs = &b.GeoDesc;\n            buildDesc.DestAccelerationStructureData = m_dynamicBLASArenas.back().Page.GpuVA() +\n                m_dynamicBLASes.back().PageOffset;\n            buildDesc.ScratchAccelerationStructureData = m_scratchBuffer.GpuVA() +\n                b.ScratchBufferOffset;\n            buildDesc.SourceAccelerationStructureData = 0;\n\n            cmdList.PIXBeginEvent(\"DynamicBLASBuild\");\n            cmdList.BuildRaytracingAccelerationStructure(&buildDesc, 0, nullptr);\n            cmdList.PIXEndEvent();\n\n            std::sort(m_dynamicBLASes.begin(), m_dynamicBLASes.end(),\n                [](const DynamicBLAS& lhs, const DynamicBLAS& rhs)\n                {\n                    if (lhs.TreeLevel < rhs.TreeLevel)\n                        return true;\n                    else if (lhs.TreeLevel > rhs.TreeLevel)\n                        return false;\n\n                    return lhs.LevelIdx < rhs.LevelIdx;\n                });\n        }\n\n        // Insert a barrier for every used page\n        if(touchedPages.size() > 1)\n            std::sort(touchedPages.begin(), touchedPages.end());\n\n        for (int i = 0; i < (int)touchedPages.size(); i++)\n        {\n            if (i == 0 || touchedPages[i] != touchedPages[i - 1])\n            {\n                D3D12_BUFFER_BARRIER barrier = Direct3DUtil::BufferBarrier(\n                    m_dynamicBLASArenas[touchedPages[i]].Page.Resource(),\n                    D3D12_BARRIER_SYNC_BUILD_RAYTRACING_ACCELERATION_STRUCTURE,\n                    D3D12_BARRIER_SYNC_BUILD_RAYTRACING_ACCELERATION_STRUCTURE | D3D12_BARRIER_SYNC_COMPUTE_SHADING,\n                    D3D12_BARRIER_ACCESS_UNORDERED_ACCESS | D3D12_BARRIER_ACCESS_RAYTRACING_ACCELERATION_STRUCTURE_WRITE,\n                    D3D12_BARRIER_ACCESS_RAYTRACING_ACCELERATION_STRUCTURE_READ);\n\n                uavBarriers.push_back(barrier);\n            }\n        }\n    }\n\n    if (!uavBarriers.empty())\n        cmdList.ResourceBarrier(uavBarriers.data(), (uint32_t)uavBarriers.size());\n\n    m_rebuildDynamicBLASes = false;\n}\n\nvoid TLAS::UpdateTLASInstances(ComputeCmdList& cmdList)\n{\n    // When static BLAS is compacted, the GPU buffer changes and static BLAS instance\n    // below also changes, which requires TLAS instance buffer to be updated.\n    if (m_updateType == UPDATE_TYPE::NONE && m_tlasInstanceBuffer.IsInitialized())\n        return;\n\n    SceneCore& scene = App::GetScene();\n    const uint32_t numInstances = scene.m_numDynamicInstances + (scene.m_numStaticInstances > 0);\n    if (numInstances == 0)\n        return;\n\n    // Following order is important, STATIC_TO_DYNAMIC should supercede INSTANCE_TRANSFORM\n    if (m_updateType == UPDATE_TYPE::STATIC_TO_DYNAMIC || !m_tlasInstanceBuffer.IsInitialized())\n    {\n        RebuildTLASInstances(cmdList);\n        scene.m_pendingRtMeshModeSwitch.clear();\n    }\n    else if (m_updateType == UPDATE_TYPE::STATIC_BLAS_COMPACTED)\n        UpdateTLASInstances_StaticCompacted(cmdList);\n    else if (m_updateType == UPDATE_TYPE::INSTANCE_TRANSFORM)\n        UpdateTLASInstances_NewTransform(cmdList);\n    else\n        Assert(false, \"Unreachable case.\");\n\n    // Wait for copy to be finished before doing compute work\n    auto barrier = Direct3DUtil::BufferBarrier(m_tlasInstanceBuffer.Resource(),\n        D3D12_BARRIER_SYNC_COPY,\n        D3D12_BARRIER_SYNC_COMPUTE_SHADING,\n        D3D12_BARRIER_ACCESS_COPY_DEST,\n        D3D12_BARRIER_ACCESS_SHADER_RESOURCE);\n\n    cmdList.ResourceBarrier(barrier);\n}\n\nvoid TLAS::RebuildTLASInstances(ComputeCmdList& cmdList)\n{\n    SceneCore& scene = App::GetScene();\n    const uint32_t numStaticInstances = scene.m_numStaticInstances;\n    const uint32_t numInstances = scene.m_numDynamicInstances + (scene.m_numStaticInstances > 0);\n\n    m_tlasInstances.resize(numInstances);\n\n    if (numStaticInstances)\n    {\n        m_tlasInstances[0].InstanceID = 0;\n        m_tlasInstances[0].InstanceMask = RT_AS_SUBGROUP::ALL;\n        m_tlasInstances[0].InstanceContributionToHitGroupIndex = 0;\n        m_tlasInstances[0].Flags = D3D12_RAYTRACING_INSTANCE_FLAG_NONE;\n        m_tlasInstances[0].AccelerationStructure = m_staticBLAS.m_buffer.GpuVA();\n\n        // Identity transform for static BLAS instance\n        memset(&m_tlasInstances[0].Transform, 0, sizeof(BLASTransform));\n        m_tlasInstances[0].Transform[0][0] = 1.0f;\n        m_tlasInstances[0].Transform[1][1] = 1.0f;\n        m_tlasInstances[0].Transform[2][2] = 1.0f;\n    }\n\n    // Following traversal order must match the one in RebuildOrUpdateBLASes()\n    uint32_t currDynamicInstance = 0;\n\n    // Skip the first level\n    if (scene.m_numDynamicInstances)\n    {\n        for (size_t treeLevelIdx = 1; treeLevelIdx < scene.m_sceneGraph.size(); treeLevelIdx++)\n        {\n            auto& currTreeLevel = scene.m_sceneGraph[treeLevelIdx];\n            const auto& rtFlagVec = currTreeLevel.m_rtFlags;\n\n            // Add one TLAS instance for every dynamic mesh\n            for (size_t i = 0; i < rtFlagVec.size(); i++)\n            {\n                if (currTreeLevel.m_meshIDs[i] == Scene::INVALID_MESH)\n                    continue;\n\n                const auto flags = RT_Flags::Decode(rtFlagVec[i]);\n\n                if (flags.MeshMode != RT_MESH_MODE::STATIC)\n                {\n                    auto& blas = m_dynamicBLASes[currDynamicInstance];\n                    blas.InstanceID = numStaticInstances + currDynamicInstance;\n\n                    D3D12_RAYTRACING_INSTANCE_DESC instance;\n                    instance.InstanceID = blas.InstanceID;\n                    instance.InstanceMask = flags.InstanceMask;\n                    instance.InstanceContributionToHitGroupIndex = 0;\n                    instance.Flags = D3D12_RAYTRACING_INSTANCE_FLAG_NONE;\n                    instance.AccelerationStructure = \n                        m_dynamicBLASArenas[blas.PageIdx].Page.GpuVA() +\n                        blas.PageOffset;\n\n                    auto& M = currTreeLevel.m_toWorlds[i];\n\n                    for (int j = 0; j < 4; j++)\n                    {\n                        instance.Transform[0][j] = M.m[j].x;\n                        instance.Transform[1][j] = M.m[j].y;\n                        instance.Transform[2][j] = M.m[j].z;\n                    }\n\n                    m_tlasInstances[(numStaticInstances > 0) + currDynamicInstance++] = instance;\n\n                    // Update RT-AS info\n                    currTreeLevel.m_rtASInfo[i].GeometryIndex = 0;\n                    currTreeLevel.m_rtASInfo[i].InstanceID = instance.InstanceID;\n                }\n            }\n        }\n    }\n\n    // When static BLAS is compacted but otherwise no other changes, only the 1st instance\n    // needs to be updated\n    Assert((numStaticInstances > 0) + currDynamicInstance == numInstances, \"bug\");\n    const uint32_t sizeInBytes = sizeof(D3D12_RAYTRACING_INSTANCE_DESC) * numInstances;\n\n    const uint32_t alignedSizeInBytes = AlignUp(sizeInBytes,\n        (uint32)D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);\n\n    if (!m_tlasInstanceBuffer.IsInitialized() || AlignUp(m_tlasInstanceBuffer.Desc().Width,\n        (uint64)D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT) < alignedSizeInBytes)\n    {\n        m_tlasInstanceBuffer = GpuMemory::GetDefaultHeapBuffer(\"TLASInstances\",\n            alignedSizeInBytes, D3D12_RESOURCE_STATE_COMMON, false);\n    }\n\n    UploadHeapBuffer scratchBuff = GpuMemory::GetUploadHeapBuffer(sizeInBytes);\n    scratchBuff.Copy(0, sizeInBytes, m_tlasInstances.data());\n\n    cmdList.CopyBufferRegion(m_tlasInstanceBuffer.Resource(),\n        0,\n        scratchBuff.Resource(),\n        scratchBuff.Offset(),\n        sizeInBytes);\n}\n\nvoid TLAS::UpdateTLASInstances_StaticCompacted(ComputeCmdList& cmdList)\n{\n    SceneCore& scene = App::GetScene();\n    Assert(scene.m_numStaticInstances, \"Invalid call.\");\n\n    m_tlasInstances.resize(Max(m_tlasInstances.size(), 1llu));\n\n    m_tlasInstances[0].InstanceID = 0;\n    m_tlasInstances[0].InstanceMask = RT_AS_SUBGROUP::ALL;\n    m_tlasInstances[0].InstanceContributionToHitGroupIndex = 0;\n    m_tlasInstances[0].Flags = D3D12_RAYTRACING_INSTANCE_FLAG_NONE;\n    m_tlasInstances[0].AccelerationStructure = m_staticBLAS.m_buffer.GpuVA();\n\n    // Identity transform for static BLAS instance\n    memset(&m_tlasInstances[0].Transform, 0, sizeof(BLASTransform));\n    m_tlasInstances[0].Transform[0][0] = 1.0f;\n    m_tlasInstances[0].Transform[1][1] = 1.0f;\n    m_tlasInstances[0].Transform[2][2] = 1.0f;\n\n    // When static BLAS is compacted but otherwise no other changes, only the 1st instance\n    // needs to be updated\n    constexpr uint32_t sizeInBytes = sizeof(D3D12_RAYTRACING_INSTANCE_DESC);\n    constexpr uint32_t alignedSizeInBytes = AlignUp(sizeInBytes,\n        (uint32)D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);\n\n    if (!m_tlasInstanceBuffer.IsInitialized() || AlignUp(m_tlasInstanceBuffer.Desc().Width,\n        (uint64)D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT) < alignedSizeInBytes)\n    {\n        m_tlasInstanceBuffer = GpuMemory::GetDefaultHeapBuffer(\"TLASInstances\",\n            alignedSizeInBytes, D3D12_RESOURCE_STATE_COMMON, false);\n    }\n\n    UploadHeapBuffer scratchBuff = GpuMemory::GetUploadHeapBuffer(sizeInBytes);\n    scratchBuff.Copy(0, sizeInBytes, m_tlasInstances.data());\n\n    cmdList.CopyBufferRegion(m_tlasInstanceBuffer.Resource(),\n        0,\n        scratchBuff.Resource(),\n        scratchBuff.Offset(),\n        sizeInBytes);\n}\n\nvoid TLAS::UpdateTLASInstances_NewTransform(ComputeCmdList& cmdList)\n{\n    auto& scene = App::GetScene();\n    const auto currFrame = App::GetTimer().GetTotalFrameCount();\n    int64 minIdx = m_dynamicBLASes.size() - 1;\n    int64 maxIdx = 0;\n    bool hadUpdates = false;\n\n    for (auto it = scene.m_instanceUpdates.begin_it(); it != scene.m_instanceUpdates.end_it();\n        it = scene.m_instanceUpdates.next_it(it))\n    {\n        // Just need to update current frame's transformation for TLAS instances (same\n        // check as SceneCore::UpdateWorldTransformations())\n        if (it->Val < currFrame - 1)\n            continue;\n\n        const auto instance = it->Key;\n        const SceneCore::TreePos treePos = scene.FindTreePosFromID(instance).value();\n\n        auto vecIt = std::lower_bound(m_dynamicBLASes.begin(), m_dynamicBLASes.end(), treePos,\n            [](const DynamicBLAS& lhs, const SceneCore::TreePos &key)\n            {\n                if (lhs.TreeLevel < key.Level)\n                    return true;\n                else if (lhs.TreeLevel > key.Level)\n                    return false;\n\n                return lhs.LevelIdx < key.Offset;\n            });\n\n        Assert(vecIt != m_dynamicBLASes.end(), \"Dynamic BLAS for instance was not found.\");\n        const auto& blas = *vecIt;\n        Assert(blas.TreeLevel == treePos.Level && blas.LevelIdx == treePos.Offset,\n            \"Dynamic BLAS for instance was not found.\");\n        const auto idx = vecIt - m_dynamicBLASes.begin();\n        minIdx = Min(minIdx, idx);\n        maxIdx = Max(maxIdx, idx);\n\n        D3D12_RAYTRACING_INSTANCE_DESC tlasIns;\n        tlasIns.InstanceID = blas.InstanceID;\n        tlasIns.InstanceMask = 0xff;\n        tlasIns.InstanceContributionToHitGroupIndex = 0;\n        tlasIns.Flags = D3D12_RAYTRACING_INSTANCE_FLAG_NONE;\n        tlasIns.AccelerationStructure =\n            m_dynamicBLASArenas[blas.PageIdx].Page.GpuVA() +\n            blas.PageOffset;\n\n        auto& M = scene.GetToWorld(instance);\n\n        for (int j = 0; j < 4; j++)\n        {\n            tlasIns.Transform[0][j] = M.m[j].x;\n            tlasIns.Transform[1][j] = M.m[j].y;\n            tlasIns.Transform[2][j] = M.m[j].z;\n        }\n\n        // + 1 to skip static instance\n        m_tlasInstances[idx + 1] = tlasIns;\n\n        hadUpdates = true;\n    }\n\n    Assert(!hadUpdates || minIdx <= maxIdx, \"Invalid range.\");\n    if (hadUpdates)\n    {\n        const size_t numInstancesToCopy = maxIdx - minIdx + 1;\n        const size_t sizeInBytes = numInstancesToCopy * sizeof(D3D12_RAYTRACING_INSTANCE_DESC);\n\n        UploadHeapBuffer scratchBuff = GpuMemory::GetUploadHeapBuffer((uint32)sizeInBytes);\n        // + 1 to skip static instance\n        minIdx++;\n        scratchBuff.Copy(0, (uint32)sizeInBytes, m_tlasInstances.data() + minIdx);\n\n        cmdList.CopyBufferRegion(m_tlasInstanceBuffer.Resource(),\n            minIdx * sizeof(D3D12_RAYTRACING_INSTANCE_DESC),\n            scratchBuff.Resource(),\n            scratchBuff.Offset(),\n            sizeInBytes);\n    }\n\n    for (auto it = scene.m_instanceUpdates.begin_it(); it != scene.m_instanceUpdates.end_it();\n        it = scene.m_instanceUpdates.next_it(it))\n    {\n        // TODO For some reason the following check has to be against currFrame - 2 instead\n        // of currFrame - 1. Sequence of actions for world transfrom update from frame T to \n        // W_new:\n        // T: Update was added at the tail end of frame\n        // T + 1: Scene and RT transforms are updated to W_new, prev transform is changed to W_old\n        // T + 2: Prev transform in scene and then mesh instance buffer are updated to W_new. Motion\n        //        vectors become zero again.\n        // T + 3: ?\n        if (it->Val < currFrame - 2)\n        {\n            scene.m_instanceUpdates.erase(it->Key);\n            //LOG_UI_INFO(\"Erased frame %llu\", it->Val);\n        }\n    }\n}\n\nvoid TLAS::RebuildTLAS(ComputeCmdList& cmdList)\n{\n    SceneCore& scene = App::GetScene();\n\n    const uint32_t numInstances = scene.m_numDynamicInstances + (scene.m_numStaticInstances > 0);\n    if (numInstances == 0)\n        return;\n\n    D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc;\n    buildDesc.Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL;\n    buildDesc.Inputs.Flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE;\n    buildDesc.Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;\n    buildDesc.Inputs.NumDescs = numInstances;\n    buildDesc.Inputs.InstanceDescs = m_tlasInstanceBuffer.GpuVA();\n\n    D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuildInfo;\n    App::GetRenderer().GetDevice()->GetRaytracingAccelerationStructurePrebuildInfo(\n        &buildDesc.Inputs, &prebuildInfo);\n    Assert(prebuildInfo.ResultDataMaxSizeInBytes != 0, \n        \"GetRaytracingAccelerationStructurePrebuildInfo() failed.\");\n\n    const uint32_t alignedBufferSize = AlignUp((uint32_t)prebuildInfo.ResultDataMaxSizeInBytes,\n        (uint32_t)D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);\n\n    if (!m_tlasBuffer[m_frameIdx].IsInitialized() ||\n        m_tlasBuffer[m_frameIdx].Desc().Width < alignedBufferSize)\n    {\n        const size_t offset = AlignUp(alignedBufferSize, \n            (uint32_t)D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT);\n        const size_t totalSize = offset + alignedBufferSize;\n        m_tlasResHeap = GpuMemory::GetResourceHeap(totalSize);\n\n        m_tlasBuffer[m_frameIdx] = GpuMemory::GetPlacedHeapBuffer(\"TLAS_A\",\n            alignedBufferSize,\n            m_tlasResHeap.Heap(),\n            0,\n            true,\n            true);\n        m_tlasBuffer[1 - m_frameIdx] = GpuMemory::GetPlacedHeapBuffer(\"TLAS_B\",\n            alignedBufferSize,\n            m_tlasResHeap.Heap(),\n            offset,\n            true,\n            true);\n\n        cmdList.UAVBarrier(m_tlasBuffer[m_frameIdx].Resource());\n\n        cmdList.CopyAccelerationStructure(m_tlasBuffer[1 - m_frameIdx].GpuVA(), \n            m_tlasBuffer[m_frameIdx].GpuVA());\n    }\n\n    auto& r = App::GetRenderer().GetSharedShaderResources();\n    r.InsertOrAssignDefaultHeapBuffer(GlobalResource::RT_SCENE_BVH_CURR, m_tlasBuffer[m_frameIdx]);\n    r.InsertOrAssignDefaultHeapBuffer(GlobalResource::RT_SCENE_BVH_PREV, m_tlasBuffer[1 - m_frameIdx]);\n    r.InsertOrAssignDefaultHeapBuffer(GlobalResource::RT_FRAME_MESH_INSTANCES_CURR, \n        m_framesMeshInstances[m_frameIdx]);\n    r.InsertOrAssignDefaultHeapBuffer(GlobalResource::RT_FRAME_MESH_INSTANCES_PREV, \n        m_framesMeshInstances[1 - m_frameIdx]);\n\n    const uint32_t alignedScratchSize = AlignUp((uint32_t)prebuildInfo.ScratchDataSizeInBytes,\n        (uint32_t)D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);\n\n    if (!m_scratchBuffer.IsInitialized() || \n        m_scratchBuffer.Desc().Width < alignedScratchSize)\n    {\n        m_scratchBuffer = GpuMemory::GetDefaultHeapBuffer(\"TLAS_scratch\",\n            alignedScratchSize,\n            D3D12_RESOURCE_STATE_COMMON,\n            true);\n    }\n\n    buildDesc.DestAccelerationStructureData = m_tlasBuffer[m_frameIdx].GpuVA();\n    // Note that scratch buffer is reused for dynamic BLAS builds & TLAS with overlapping\n    // addresses, but due to inserted barrier, it's safe.\n    buildDesc.ScratchAccelerationStructureData = m_scratchBuffer.GpuVA();\n    buildDesc.SourceAccelerationStructureData = 0;\n\n    cmdList.BuildRaytracingAccelerationStructure(&buildDesc, 0, nullptr);\n\n     if (m_updateType == UPDATE_TYPE::STATIC_BLAS_COMPACTED ||\n         m_updateType == UPDATE_TYPE::STATIC_TO_DYNAMIC)\n     {\n         cmdList.UAVBarrier(m_tlasBuffer[m_frameIdx].Resource());\n\n         cmdList.CopyAccelerationStructure(m_tlasBuffer[1 - m_frameIdx].GpuVA(),\n             m_tlasBuffer[m_frameIdx].GpuVA());\n         cmdList.CopyResource(m_framesMeshInstances[1 - m_frameIdx].Resource(),\n             m_framesMeshInstances[m_frameIdx].Resource());\n     }\n\n    // Even though TLAS was created with an initial stete of \n    // D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, the debug layer \n    // warns that \"D3D12_BARRIER_ACCESS_RAYTRACING_ACCELERATION_STRUCTURE_READ and \n    // D3D12_BARRIER_ACCESS_RAYTRACING_ACCELERATION_STRUCTURE_WRITE can only be \n    // used with resources created using D3D12_RESOURCE_FLAG_RAYTRACING_ACCELERATION_STRUCTURE \n    // or with a legacy InitialState of D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE\".\n#if 0\n    // wait for build to be finished before doing any raytracing\n    D3D12_BUFFER_BARRIER barrier = Direct3DUtil::BufferBarrier(m_tlasBuffer.Resource(),\n        D3D12_BARRIER_SYNC_BUILD_RAYTRACING_ACCELERATION_STRUCTURE,\n        D3D12_BARRIER_SYNC_COMPUTE_SHADING,\n        D3D12_BARRIER_ACCESS_UNORDERED_ACCESS | D3D12_BARRIER_ACCESS_RAYTRACING_ACCELERATION_STRUCTURE_WRITE,\n        D3D12_BARRIER_ACCESS_RAYTRACING_ACCELERATION_STRUCTURE_READ);\n\n    cmdList.ResourceBarrier(barrier);\n#endif\n\n    m_updateType = UPDATE_TYPE::NONE;\n    m_ready = true;\n}\n"
  },
  {
    "path": "Source/ZetaCore/RayTracing/RtAccelerationStructure.h",
    "content": "#pragma once\n\n#include \"../Core/GpuMemory.h\"\n#include \"RtCommon.h\"\n#include \"../Scene/SceneCommon.h\"\n#include \"../Support/Task.h\"\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n    class ComputeCmdList;\n}\n\nnamespace ZetaRay::Util\n{\n    template<typename T>\n    struct Span;\n}\n\nnamespace ZetaRay::RT\n{\n    //--------------------------------------------------------------------------------------\n    // Static BLAS\n    //--------------------------------------------------------------------------------------\n\n    struct StaticBLAS\n    {\n        void Rebuild(Core::ComputeCmdList& cmdList);\n        void DoCompaction(Core::ComputeCmdList& cmdList);\n        void CompactionCompletedCallback();\n        void FillMeshTransformBufferForBuild(ID3D12Heap* heap = nullptr, \n            uint32_t heapOffsetInBytes = 0);\n\n        Core::GpuMemory::Buffer m_buffer;\n        Core::GpuMemory::Buffer m_bufferCompacted;\n        Core::GpuMemory::Buffer m_scratch;\n        Core::GpuMemory::ResourceHeap m_resHeap;\n\n        Core::GpuMemory::ReadbackHeapBuffer m_postBuildInfoReadback;\n\n        // 3x4 affine transformation matrix for each triangle mesh\n        Core::GpuMemory::Buffer m_perMeshTransform;\n\n        // Cache the results as it's expensive to compute\n        D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO m_prebuildInfo = {};\n\n        std::atomic_bool m_compactionCompleted = false;\n        std::atomic_bool m_heapAllocated = false;\n        bool m_heapAllocationInProgress = false;\n        uint32_t m_BLASHeapOffsetInBytes = UINT32_MAX;\n        uint32_t m_scratchHeapOffsetInBytes = UINT32_MAX;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // TLAS\n    //--------------------------------------------------------------------------------------\n\n    struct TLAS\n    {\n        void Update();\n        void Render(Core::CommandList& cmdList);\n        ZetaInline const Core::GpuMemory::Buffer& GetTLAS() const { return m_tlasBuffer[m_frameIdx];  };\n        ZetaInline bool IsReady() const { return m_ready; };\n\n    private:\n        static constexpr uint32_t BLAS_ARENA_PAGE_SIZE = 4 * 1024 * 1024;\n\n        struct ArenaPage\n        {\n            Core::GpuMemory::Buffer Page;\n            uint32_t CurrOffset;\n        };\n\n        struct DynamicBLAS\n        {\n            int PageIdx;\n            uint32_t PageOffset;\n            uint32_t TreeLevel;\n            uint32_t LevelIdx;\n            uint32_t InstanceID;\n        };\n\n        enum class UPDATE_TYPE\n        {\n            NONE,\n            STATIC_TO_DYNAMIC,\n            STATIC_BLAS_COMPACTED,\n            INSTANCE_TRANSFORM\n        };\n\n        // Frame mesh instances\n        void FillMeshInstanceData(uint64_t instanceID, uint64_t meshID, const Math::float4x3& M,\n            uint32_t emissiveTriOffset, bool staticMesh, uint32_t currInstance);\n        void RebuildFrameMeshInstanceData();\n        void UpdateFrameMeshInstances_StaticToDynamic();\n        void UpdateFrameMeshInstances_NewTransform();\n\n        // BLASes\n        void BuildDynamicBLASes(Core::ComputeCmdList& cmdList);\n        void RebuildOrUpdateBLASes(Core::ComputeCmdList& cmdList);\n\n        // TLAS instances\n        void UpdateTLASInstances(Core::ComputeCmdList& cmdList);\n        void RebuildTLASInstances(Core::ComputeCmdList& cmdList);\n        void UpdateTLASInstances_StaticCompacted(Core::ComputeCmdList& cmdList);\n        void UpdateTLASInstances_NewTransform(Core::ComputeCmdList& cmdList);\n\n        void RebuildTLAS(Core::ComputeCmdList& cmdList);\n\n        StaticBLAS m_staticBLAS;\n        Core::GpuMemory::Buffer m_framesMeshInstances[2];\n        Core::GpuMemory::Buffer m_tlasBuffer[2];\n        Core::GpuMemory::Buffer m_scratchBuffer;\n        Core::GpuMemory::Buffer m_tlasInstanceBuffer;\n        Core::GpuMemory::ResourceHeap m_tlasResHeap;\n        Core::GpuMemory::ResourceHeap m_meshInstanceResHeap;\n\n        // Dynamic BLAS\n        Util::SmallVector<ArenaPage> m_dynamicBLASArenas;\n        Util::SmallVector<DynamicBLAS> m_dynamicBLASes;\n\n        Util::SmallVector<RT::MeshInstance> m_frameInstanceData;\n        Util::SmallVector<D3D12_RAYTRACING_INSTANCE_DESC, Support::SystemAllocator, 1> m_tlasInstances;\n\n        Support::WaitObject m_waitObj;\n        std::atomic_bool m_compactionInfoReady = false;\n        bool m_staticBLASCompacted = false;\n        bool m_rebuildDynamicBLASes = true;\n        UPDATE_TYPE m_updateType = UPDATE_TYPE::NONE;\n        int m_frameIdx = 0;\n\n        bool m_ready = false;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/RayTracing/RtCommon.h",
    "content": "#ifndef RTCOMMON_H\n#define RTCOMMON_H\n\n#include \"../Core/Material.h\"\n\n#ifdef __cplusplus\n#include \"../Math/VectorFuncs.h\"\n#else\n#include \"../../ZetaRenderPass/Common/Math.hlsli\"\n#endif\n\n// When enabled, instead of storing vertex positions directly, store normalized \n// edge vector (e.g. v0v1) along with the corresponding edge length. Position can \n// then be reconstructed as e.g. v1 = v0 + v0v1 * ||v1 - v0||. Saves 12 bytes per \n// triangle.\n#define ENCODE_EMISSIVE_POS 1\n\n// Use 16-bit floats for storing triangle uv coordinates. Emissive textures tend \n// to have lower resolutions, so the loss of precision might be acceptable. Saves\n// 12 bytes per triangle.\n#define EMISSIVE_UV_HALF 1\n\n#if EMISSIVE_UV_HALF == 1\n#define EMISSIVE_UV_TYPE half2_\n#else\n#define EMISSIVE_UV_TYPE float2_\n#endif\n\n// From DXR docs:\n// \"Meshes present in an acceleration structure can be subdivided into groups\n// based on a specified 8-bit mask value. During ray traversal, instance mask from \n// the ray and corresponding mask from each mesh are ANDed together. Mesh is skipped\n// if the result is zero\".\nnamespace RT_AS_SUBGROUP\n{\n    static const uint32_t EMISSIVE = 0x1;\n    static const uint32_t NON_EMISSIVE = 0x2;\n    static const uint32_t ALL = EMISSIVE | NON_EMISSIVE;\n}\n\n#ifdef __cplusplus\nnamespace ZetaRay\n{\n#endif\n    namespace RT\n    {\n        struct MeshInstance\n        {\n            uint32_t BaseVtxOffset;\n            uint32_t BaseIdxOffset;\n            unorm4_ Rotation;\n            half3_ Scale;\n            uint16_t MatIdx;\n            uint32_t BaseEmissiveTriOffset;\n\n            float3_ Translation;\n            unorm4_ PrevRotation;\n            half3_ PrevScale;\n            half3_ dTranslation;\n\n            // inline alpha stuff to avoid loading material data in anyhit shaders\n            uint16_t BaseColorTex;\n            uint16_t AlphaFactor_Cutoff;\n        };\n\n        struct EmissiveTriangle\n        {\n            static const uint32_t TriIDPatchedBit = 24;\n            static const uint32_t DoubleSidedBit = 25;\n\n#ifdef __cplusplus\n            EmissiveTriangle() = default;\n            EmissiveTriangle(const Math::float3& vtx0, const Math::float3& vtx1, const Math::float3& vtx2,\n                const Math::float2& uv0, const Math::float2& uv1, const Math::float2& uv2,\n                uint32_t emissiveFactorRGB8, uint32_t emissiveTex, Math::half emissiveStr, \n                uint32_t triIdx, bool doubleSided = true)\n                : ID(triIdx),\n                UV0(uv0),\n                UV1(uv1),\n                UV2(uv2)\n            {\n                __m128 v0 = Math::loadFloat3(const_cast<Math::float3&>(vtx0));\n                __m128 v1 = Math::loadFloat3(const_cast<Math::float3&>(vtx1));\n                __m128 v2 = Math::loadFloat3(const_cast<Math::float3&>(vtx2));\n                StoreVertices(v0, v1, v2);\n\n                PackedA = emissiveFactorRGB8 & 0xffffff;\n                PackedA |= (doubleSided << DoubleSidedBit);\n                PackedA |= ((emissiveStr.x & 0xf) << 28);\n                PackedB = emissiveTex | (uint32_t(emissiveStr.x) << Material::NUM_TEXTURE_BITS);\n            }\n#endif\n\n            float3_ Vtx0;\n\n#if ENCODE_EMISSIVE_POS == 1\n            unorm2_ V0V1;\n            unorm2_ V0V2;\n            half2_ EdgeLengths;\n#else\n            float3_ Vtx1;\n            float3_ Vtx2;\n#endif\n\n            // Initially, triangle index within the mesh, then changed to tri ID\n            uint32_t ID;\n            // [0 - 24): Emissive factor, [24 - 32): flags\n            uint32_t PackedA;\n            // [0 - 16): Texture, [16 - 32): strength\n            uint32_t PackedB;\n\n            EMISSIVE_UV_TYPE UV0;\n            EMISSIVE_UV_TYPE UV1;\n            EMISSIVE_UV_TYPE UV2;\n\n            bool IsDoubleSided() CONST\n            {\n                return PackedA & (1u << DoubleSidedBit);\n            }\n\n            half_ GetStrength() CONST\n            {\n                uint16_t str = uint16_t(PackedB >> Material::NUM_TEXTURE_BITS);\n#ifdef __cplusplus\n                return Math::half::asfloat16(str);\n#else\n                return asfloat16(str);\n#endif\n            }\n\n            float3_ GetFactor() CONST\n            {\n                return Math::UnpackRGB8(PackedA);\n            }\n\n            uint32_t GetTex() CONST\n            {\n                return PackedB & Material::TEXTURE_MASK;\n            }\n\n#ifdef __cplusplus\n            ZetaInline void __vectorcall StoreVertices(__m128 v0, __m128 v1, __m128 v2)\n            {\n                Vtx0 = Math::storeFloat3(v0);\n\n#if ENCODE_EMISSIVE_POS == 1\n                __m256 vV0V0 = _mm256_insertf128_ps(_mm256_castps128_ps256(v0), v0, 1);\n                __m256 vV1V2 = _mm256_insertf128_ps(_mm256_castps128_ps256(v1), v2, 1);\n\n                // (v1 - v0, v2 - v0)\n                __m256 vE0E1 = _mm256_sub_ps(vV1V2, vV0V0);\n\n                // (||v1 - v0||, ||v2 - v0||, _, _)\n                __m256 vE0E1_2 = _mm256_mul_ps(vE0E1, vE0E1);\n                __m128 vLower = _mm256_extractf128_ps(vE0E1_2, 0);\n                __m128 vUpper = _mm256_extractf128_ps(vE0E1_2, 1);\n                __m128 vEdgeLengths = _mm_hadd_ps(vLower, vUpper);\n                vEdgeLengths = _mm_hadd_ps(vEdgeLengths, vEdgeLengths);\n                vEdgeLengths = _mm_sqrt_ps(vEdgeLengths);\n\n                // (||e0||, ||e0||, ||e0||, ||e0||, ||e1||, ||e1||, ||e1||, ||e1||)\n                __m256 vEdgeLengthsSplatted = _mm256_insertf128_ps(\n                    _mm256_castps128_ps256(_mm_shuffle_ps(vEdgeLengths, vEdgeLengths, V_SHUFFLE_XYZW(0, 0, 0, 0))),\n                    _mm_shuffle_ps(vEdgeLengths, vEdgeLengths, V_SHUFFLE_XYZW(1, 1, 1, 1)), 1);\n                //  = normalize(v1 - v0, v2 - v0)\n                __m256 vE0E1Normalized = _mm256_div_ps(vE0E1, vEdgeLengthsSplatted);\n\n                // Octahedral encoding\n                __m128 vE0 = _mm256_extractf128_ps(vE0E1Normalized, 0);\n                vE0 = Math::encode_octahedral(vE0);\n                __m128 vE1 = _mm256_extractf128_ps(vE0E1Normalized, 1);\n                vE1 = Math::encode_octahedral(vE1);\n                vE0E1Normalized = _mm256_insertf128_ps(_mm256_castps128_ps256(vE0), vE1, 1);\n\n                // Encode using 16-bit UNORMs\n                __m256 vHalf = _mm256_set1_ps(0.5f);\n                // [-1, 1] -> [0, 1]\n                vE0E1Normalized = _mm256_fmadd_ps(vE0E1Normalized, vHalf, vHalf);\n                __m256 vMax = _mm256_set1_ps((1 << 16) - 1);\n                __m256 vTemp = _mm256_mul_ps(vE0E1Normalized, vMax);\n                __m256i vE0E1Encoded = _mm256_cvtps_epi32(vTemp);\n\n                // Store normalized edges\n                __m128i vEdge0 = _mm_castps_si128(_mm256_extractf128_ps(_mm256_castsi256_ps(vE0E1Encoded), 0));\n                StoreEdge(vEdge0, V0V1);\n\n                __m128i vEdge1 = _mm_castps_si128(_mm256_extractf128_ps(_mm256_castsi256_ps(vE0E1Encoded), 1));\n                StoreEdge(vEdge1, V0V2);\n\n                // Store edge lengths as 16-bit floats\n                __m128i vEdgeLengthsHalf = _mm_cvtps_ph(vEdgeLengths, 0);\n                int lengths = _mm_cvtsi128_si32(vEdgeLengthsHalf);\n                memcpy(&EdgeLengths, &lengths, sizeof(int));\n#else\n                Vtx1 = Math::storeFloat3(v1);\n                Vtx2 = Math::storeFloat3(v2);\n#endif\n            }\n\n            ZetaInline static void DecodeVertices(float3_& vtx0, unorm2_& v0v1, unorm2_& v0v2,\n                half2_& edgeLengths, __m128& v0, __m128& v1, __m128& v2)\n            {\n                alignas(16) int32_t packed[4] = { int32_t(v0v1.x),\n                    int32_t(v0v1.y),\n                    int32_t(v0v2.x), \n                    int32_t(v0v2.y) };\n\n                // Decode UNORM-16\n                __m128 vE0E1 = _mm_cvtepi32_ps(_mm_load_si128(reinterpret_cast<__m128i*>(packed)));\n                vE0E1 = _mm_div_ps(vE0E1, _mm_set1_ps((1 << 16) - 1));\n                // [0, 1] -> [-1, 1]\n                vE0E1 = _mm_fmadd_ps(vE0E1, _mm_set1_ps(2.0f), _mm_set1_ps(-1.0f));\n\n                // Convert length to float\n                __m128i vLengthsHalf = _mm_cvtsi32_si128(edgeLengths.x | (edgeLengths.y << 16));\n                __m128 vLengths = _mm_cvtph_ps(vLengthsHalf);\n\n                // Interpolate\n                __m128 vV0 = Math::loadFloat3(vtx0);\n\n                __m128 vV1 = Math::decode_octahedral(vE0E1);\n                vV1 = _mm_fmadd_ps(vV1, _mm_broadcastss_ps(vLengths), vV0);\n                v1 = vV1;\n\n                __m128 vV2 = Math::decode_octahedral(_mm_movehl_ps(vE0E1, vE0E1));\n                vV2 = _mm_fmadd_ps(vV2, _mm_shuffle_ps(vLengths, vLengths, V_SHUFFLE_XYZW(1, 1, 1, 1)), vV0);\n                v2 = vV2;\n\n                // Set v[3] = 1\n                __m128 vOne = _mm_set1_ps(1.0f);\n                v0 = _mm_insert_ps(vV0, vOne, 0x30);\n                v1 = _mm_insert_ps(vV1, vOne, 0x30);\n                v2 = _mm_insert_ps(vV2, vOne, 0x30);\n            }\n\n            ZetaInline void __vectorcall LoadVertices(__m128& v0, __m128& v1, __m128& v2)\n            {\n#if ENCODE_EMISSIVE_POS == 1\n                EmissiveTriangle::DecodeVertices(Vtx0, V0V1, V0V2, EdgeLengths, v0, v1, v2);\n#else\n                __m128 vV0 = Math::loadFloat3(Vtx0);\n                __m128 vV1 = Math::loadFloat3(Vtx1);\n                __m128 vV2 = Math::loadFloat3(Vtx2);\n                // Set v[3] = 1\n                __m128 vOne = _mm_set1_ps(1.0f);\n                v0 = _mm_insert_ps(vV0, vOne, 0x30);\n                v1 = _mm_insert_ps(vV1, vOne, 0x30);\n                v2 = _mm_insert_ps(vV2, vOne, 0x30);\n#endif\n            }\n\n            ZetaInline bool IsIDPatched()\n            {\n                return PackedA & (1u << TriIDPatchedBit);\n            }\n\n            ZetaInline void ResetID(uint32_t id)\n            {\n                PackedA |= (1u << TriIDPatchedBit);\n                ID = id;\n            }\n\n            ZetaInline void __vectorcall StoreEdge(__m128i vEdge, unorm2_& e)\n            {\n                vEdge = _mm_and_si128(vEdge, _mm_set1_epi32(0xffff));\n\n                alignas(16) uint32_t a[4];\n                _mm_store_si128(reinterpret_cast<__m128i*>(a), vEdge);\n\n                e.x = static_cast<uint16_t>(a[0]);\n                e.y = static_cast<uint16_t>(a[1]);\n            }\n\n            ZetaInline void SetStrength(float newStrength)\n            {\n                Math::half h(newStrength);\n                SetStrength(h);\n            }\n\n            ZetaInline void SetStrength(Math::half newStrength)\n            {\n                PackedB = (PackedB & Material::TEXTURE_MASK) | \n                    (uint32_t(newStrength.x) << Material::NUM_TEXTURE_BITS);\n            }\n\n            ZetaInline void SetEmissiveFactor(uint32_t newFactorRGB8)\n            {\n                PackedA = newFactorRGB8 | (PackedA & Material::UPPER_8_BITS_MASK);\n            }\n#endif\n        };\n\n        // Given discrete probability distribution P with N outcomes, such that for outcome i and random variable x,\n        //      P[i] = P[x = i],\n        // \n        // alias table is a lookup table of length N for P. To draw samples from P, draw a discrete uniform sample x \n        // in [0, N), then\n        // \n        // 1. Draw another uniform sample u in [0, 1)\n        // 2. If u <= AliasTable[x].P_Curr, return x\n        // 3. Return AliasTable[x].Alias\n        struct EmissiveLumenAliasTableEntry\n        {\n            // Cache the probabilities for both outcomes to avoid another (random) memory access at the\n            // cost of extra storage\n            float CachedP_Orig;\n            float CachedP_Alias;\n            float P_Curr;\n            uint32_t Alias;\n        };\n\n        struct PresampledEmissiveTriangle\n        {\n            float3_ pos;\n            unorm2_ normal;\n            float pdf;\n            uint32_t ID;\n            uint32_t idx;\n            unorm2_ bary;\n            half3_ le;\n            uint16_t twoSided;\n        };\n\n        struct VoxelSample\n        {\n            float3_ pos;\n            unorm2_ normal;\n            float pdf;\n            uint32_t ID;\n            half3_ le;\n            uint16_t twoSided;\n        };\n    }\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "Source/ZetaCore/Scene/Asset.cpp",
    "content": "#include \"Asset.h\"\n#include \"../Core/RendererCore.h\"\n#include \"../Core/SharedShaderResources.h\"\n#include \"SceneCore.h\"\n#include \"../App/Log.h\"\n#include \"../App/Timer.h\"\n#include <algorithm>\n\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Scene::Internal;\nusing namespace ZetaRay::App;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Model;\nusing namespace ZetaRay::Model::glTF;\n\n//--------------------------------------------------------------------------------------\n// TexSRVDescriptorTable\n//--------------------------------------------------------------------------------------\n\nTexSRVDescriptorTable::TexSRVDescriptorTable(const uint32_t descTableSize)\n    : m_descTableSize(descTableSize),\n    m_numMasks(descTableSize >> 6)\n{\n    Assert(Math::IsPow2(descTableSize), \"descriptor table size must be a power of two.\");\n    Assert(descTableSize < MAX_NUM_DESCRIPTORS, \"desc. table size exceeded maximum allowed.\");\n}\n\nvoid TexSRVDescriptorTable::Init(uint64_t id)\n{\n    m_descTable = App::GetRenderer().GetGpuDescriptorHeap().Allocate(m_descTableSize);\n    Assert(!m_descTable.IsEmpty(), \"Allocating descriptors from the GPU descriptor heap failed.\");\n\n    auto& s = App::GetRenderer().GetSharedShaderResources();\n    s.InsertOrAssignDescriptorTable(id, m_descTable);\n}\n\nuint32_t TexSRVDescriptorTable::Add(Texture&& tex)\n{\n    // If texture already exists, just increase the ref count and return it\n    if (auto it = m_cache.find(tex.ID()); it)\n    {\n        const uint32_t offset = it.value()->DescTableOffset;\n        Assert(offset < m_descTableSize, \"invalid offset.\");\n        it.value()->RefCount++;\n\n        return offset;\n    }\n\n    Assert(tex.IsInitialized(), \"Texture hasn't been initialized.\");\n\n    // Find first free slot in table\n    uint32_t freeSlot = UINT32_MAX;\n    int i = 0;\n\n    for (; i < (int)m_numMasks; i++)\n    {\n        freeSlot = (uint32)_tzcnt_u64(~m_inUseBitset[i]);\n        if (freeSlot != 64)\n            break;\n    }\n\n    Assert(freeSlot != UINT32_MAX, \"No free slot was found.\");\n    m_inUseBitset[i] |= (1llu << freeSlot);    // Set the slot to occupied\n\n    freeSlot += i * 64;        // Each uint64_t covers 64 slots\n    Assert(freeSlot < m_descTableSize, \"Invalid table index.\");\n\n    auto descCpuHandle = m_descTable.CPUHandle(freeSlot);\n    Direct3DUtil::CreateTexture2DSRV(tex, descCpuHandle);\n\n    // Remember ID before moving the texture\n    const Texture::ID_TYPE id = tex.ID();\n\n    // Add this texture to cache\n    m_cache.insert_or_assign(id, CacheEntry{\n        .T = ZetaMove(tex), \n        .DescTableOffset = freeSlot,\n        .RefCount = 1 });\n\n    return freeSlot;\n}\n\nvoid TexSRVDescriptorTable::Recycle(uint64_t completedFenceVal)\n{\n    for(auto it = m_pending.begin(); it != m_pending.end();)\n    {\n        // GPU is finished with this descriptor\n        if (it->FenceVal <= completedFenceVal)\n        {\n            // Set the descriptor slot to free\n            const uint32_t idx = it->DescTableOffset >> 6;\n            Assert(idx < m_numMasks, \"invalid index.\");\n            m_inUseBitset[idx] |= (1llu << (it->DescTableOffset & 63));\n\n            it = m_pending.erase(*it);\n        }\n        else\n            it++;\n    }\n}\n\nvoid TexSRVDescriptorTable::Clear()\n{\n    for (auto it = m_cache.begin_it(); it < m_cache.end_it(); it = m_cache.next_it(it))\n        it->Val.T.Reset(false);\n\n    for (auto& t : m_pending)\n        t.T.Reset(false);\n}\n\n//--------------------------------------------------------------------------------------\n// MaterialBuffer\n//--------------------------------------------------------------------------------------\n\nvoid MaterialBuffer::Add(uint32_t ID, const Material& mat)\n{\n    // Find first free slot in buffer (i.e. first-fit)\n    uint32 freeIdx = UINT32_MAX;\n    int i = 0;\n\n    for (; i < NUM_MASKS; i++)\n    {\n        freeIdx = (uint32)_tzcnt_u64(~m_inUseBitset[i]);\n        if (freeIdx != 64)\n            break;\n    }\n\n    Assert(freeIdx != UINT32_MAX, \"No free slot was found.\");\n    m_inUseBitset[i] |= (1llu << freeIdx);        // Set the slot to occupied\n\n    freeIdx += i << 6;        // Each uint64_t covers 64 slots\n    Assert(freeIdx < MAX_NUM_MATERIALS, \"Invalid table index.\");\n\n    m_materials[ID] = Entry{ .Mat = mat, .GpuBufferIdx = freeIdx };\n}\n\nvoid MaterialBuffer::UploadToGPU()\n{\n    // First time\n    if (!m_buffer.IsInitialized())\n    {\n        SmallVector<Material, FrameAllocator> buffer;\n        buffer.resize(m_materials.size());\n\n        // Convert hash table to array\n        for (auto it = m_materials.begin_it(); it < m_materials.end_it(); it = m_materials.next_it(it))\n        {\n            const uint32_t bufferIndex = it->Val.GpuBufferIdx;\n            buffer[bufferIndex] = it->Val.Mat;\n        }\n\n        auto& renderer = App::GetRenderer();\n        const size_t sizeInBytes = buffer.size() * sizeof(Material);\n        m_buffer = GpuMemory::GetDefaultHeapBufferAndInit(\"MaterialBuffer\",\n            (uint32_t)sizeInBytes,\n            false,\n            MemoryRegion{.Data = buffer.data(), .SizeInBytes = sizeInBytes });\n\n        auto& r = renderer.GetSharedShaderResources();\n        r.InsertOrAssignDefaultHeapBuffer(GlobalResource::MATERIAL_BUFFER, m_buffer);\n    }\n    // Update a single material\n    else if (m_staleID != UINT32_MAX)\n    {\n        auto* entry = m_materials.find(m_staleID).value();\n\n        GpuMemory::UploadToDefaultHeapBuffer(m_buffer, sizeof(Material),\n            MemoryRegion{.Data = &entry->Mat, .SizeInBytes = sizeof(Material)}, \n            sizeof(Material) * entry->GpuBufferIdx);\n\n        m_staleID = UINT32_MAX;\n    }\n}\n\nvoid MaterialBuffer::ResizeAdditionalMaterials(uint32_t num)\n{\n    m_materials.resize(m_materials.size() + num, true);\n}\n\nvoid MaterialBuffer::Clear()\n{\n    // Assumes CPU-GPU synchronization has been performed, so that GPU is done with the material buffer.\n    m_buffer.Reset();\n}\n\n//--------------------------------------------------------------------------------------\n// MeshContainer\n//--------------------------------------------------------------------------------------\n\nuint32_t MeshContainer::Add(SmallVector<Core::Vertex>&& vertices, SmallVector<uint32_t>&& indices,\n    uint32_t matIdx)\n{\n    const uint32_t vtxOffset = (uint32_t)m_vertices.size();\n    const uint32_t idxOffset = (uint32_t)m_indices.size();\n\n    const uint32_t meshIdx = (uint32_t)m_meshes.size();\n    const uint64_t meshFromSceneID = Scene::MeshID(Scene::DEFAULT_SCENE_ID, meshIdx, 0);\n    bool success = m_meshes.try_emplace(meshFromSceneID, vertices, vtxOffset, idxOffset, \n        (uint32_t)indices.size(), matIdx);\n    Check(success, \"mesh with ID (from mesh index %u) already exists.\", meshIdx);\n\n    m_vertices.append_range(vertices.begin(), vertices.end());\n    m_indices.append_range(indices.begin(), indices.end());\n\n    return meshIdx;\n}\n\nvoid MeshContainer::AddBatch(SmallVector<Model::glTF::Asset::Mesh>&& meshes, \n    SmallVector<Core::Vertex>&& vertices, SmallVector<uint32_t>&& indices)\n{\n    const uint32_t vtxOffset = (uint32_t)m_vertices.size();\n    const uint32_t idxOffset = (uint32_t)m_indices.size();\n    m_meshes.resize(meshes.size(), true);\n\n    // Each mesh primitive + material index combo must be unique\n    for (auto& mesh : meshes)\n    {\n        const uint64_t meshFromSceneID = Scene::MeshID(mesh.SceneID, mesh.MeshIdx, mesh.MeshPrimIdx);\n        const uint32_t matFromSceneID = mesh.glTFMaterialIdx != -1 ?\n            Scene::MaterialID(mesh.SceneID, mesh.glTFMaterialIdx) :\n            Scene::DEFAULT_MATERIAL_ID;\n\n        bool success = m_meshes.try_emplace(meshFromSceneID, \n            Span(vertices.begin() + mesh.BaseVtxOffset, mesh.NumVertices),\n            vtxOffset + mesh.BaseVtxOffset,\n            idxOffset + mesh.BaseIdxOffset,\n            mesh.NumIndices, \n            matFromSceneID);\n\n        Assert(success, \"Mesh with ID %llu already exists.\", meshFromSceneID);\n    }\n\n    if (m_vertices.empty())\n        m_vertices = ZetaMove(vertices);\n    else\n        m_vertices.append_range(vertices.begin(), vertices.end());\n\n    if (m_indices.empty())\n        m_indices = ZetaMove(indices);\n    else\n        m_indices.append_range(indices.begin(), indices.end());\n}\n\nvoid MeshContainer::Reserve(size_t numVertices, size_t numIndices)\n{\n    m_vertices.reserve(numVertices);\n    m_indices.reserve(numIndices);\n}\n\nvoid MeshContainer::RebuildBuffers()\n{\n    Assert(m_vertices.size() > 0, \"vertex buffer is empty\");\n    Assert(m_indices.size() > 0, \"index buffer is empty\");\n\n    const uint32_t vbSizeInBytes = sizeof(Vertex) * (uint32_t)m_vertices.size();\n    const uint32_t ibSizeInBytes = sizeof(uint32_t) * (uint32_t)m_indices.size();\n\n    PlacedResourceList<2> list;\n    list.PushBuffer(vbSizeInBytes, false, false);\n    list.PushBuffer(ibSizeInBytes, false, false);\n    list.End();\n\n    m_heap = GpuMemory::GetResourceHeap(list.TotalSizeInBytes());\n    ID3D12Heap* heap = m_heap.Heap();\n    auto allocs = list.AllocInfos();\n\n    m_vertexBuffer = GpuMemory::GetPlacedHeapBufferAndInit(GlobalResource::SCENE_VERTEX_BUFFER, \n        vbSizeInBytes, heap, allocs[0].Offset, false, \n        MemoryRegion{ .Data = m_vertices.data(), .SizeInBytes = vbSizeInBytes }, true);\n\n    m_indexBuffer = GpuMemory::GetPlacedHeapBufferAndInit(GlobalResource::SCENE_INDEX_BUFFER,\n        ibSizeInBytes, heap, allocs[1].Offset, false, \n        MemoryRegion{ .Data = m_indices.data(), .SizeInBytes = ibSizeInBytes }, true);\n\n    auto& r = App::GetRenderer().GetSharedShaderResources();\n    r.InsertOrAssignDefaultHeapBuffer(GlobalResource::SCENE_VERTEX_BUFFER, m_vertexBuffer);\n    r.InsertOrAssignDefaultHeapBuffer(GlobalResource::SCENE_INDEX_BUFFER, m_indexBuffer);\n\n    m_vertices.free_memory();\n    m_indices.free_memory();\n}\n\nvoid MeshContainer::Clear()\n{\n    m_vertexBuffer.Reset(false);\n    m_indexBuffer.Reset(false);\n    m_heap.Reset();\n}\n\n//--------------------------------------------------------------------------------------\n// EmissiveBuffer\n//--------------------------------------------------------------------------------------\n\nvoid EmissiveBuffer::AddBatch(SmallVector<Asset::EmissiveInstance>&& instances, \n    SmallVector<RT::EmissiveTriangle>&& tris)\n{\n    App::DeltaTimer timer;\n    timer.Start();\n\n    // TODO implement\n    Check(m_trisCpu.empty(), \"Not implemented.\");\n    m_instances = instances;\n\n    // Map instance ID to index in instances\n    HashTable<uint32, uint64, App::FrameAllocator> idToIdxMap;\n    idToIdxMap.resize(instances.size(), true);\n\n    for (size_t i = 0; i < instances.size(); i++)\n        idToIdxMap[instances[i].InstanceID] = (uint32)i;\n\n    // Sort by material - this makes updates simpler and faster\n    std::sort(m_instances.begin(), m_instances.end(),\n        [](const Asset::EmissiveInstance& a1, const Asset::EmissiveInstance& a2)\n        {\n            return a1.MaterialIdx < a2.MaterialIdx;\n        });\n\n    m_trisCpu.resize(tris.size());\n    m_triInitialPos.resize(tris.size());\n    uint32_t currNumTris = 0;\n\n    // Shuffle triangles according to new sorted order\n    for (size_t i = 0; i < m_instances.size(); i++)\n    {\n        const uint64_t currID = m_instances[i].InstanceID;\n        const uint32_t idx = *idToIdxMap.find(currID).value();\n\n        memcpy(&m_trisCpu[currNumTris], \n            &tris[instances[idx].BaseTriOffset],\n            instances[idx].NumTriangles * sizeof(RT::EmissiveTriangle));\n\n        m_instances[i].BaseTriOffset = currNumTris;\n        currNumTris += instances[idx].NumTriangles;\n    }\n\n    for (size_t i = 0; i < m_instances.size(); i++)\n        m_idToIdxMap[m_instances[i].InstanceID] = (uint32)i;\n\n    timer.End();\n    LOG_UI_INFO(\"Emissive buffers processed in %u [us].\", (uint32_t)timer.DeltaMicro());\n}\n\nvoid EmissiveBuffer::UploadToGPU()\n{\n    if (m_trisCpu.empty())\n        return;\n\n    if (!m_trisGpu.IsInitialized())\n    {\n        const size_t sizeInBytes = sizeof(RT::EmissiveTriangle) * m_trisCpu.size();\n        m_trisGpu = GpuMemory::GetDefaultHeapBufferAndInit(GlobalResource::EMISSIVE_TRIANGLE_BUFFER,\n            (uint32)sizeInBytes,\n            false,\n            MemoryRegion{ .Data = m_trisCpu.data(), .SizeInBytes = sizeInBytes });\n\n        auto& r = App::GetRenderer().GetSharedShaderResources();\n        r.InsertOrAssignDefaultHeapBuffer(GlobalResource::EMISSIVE_TRIANGLE_BUFFER, m_trisGpu);\n    }\n    else if(m_staleNumTris > 0)\n    {\n        Assert(m_staleBaseOffset != UINT32_MAX, \"Invalid base offset.\");\n        const size_t numMbytes = sizeof(RT::EmissiveTriangle) * m_staleNumTris / (1024 * 1024);\n        LOG_UI_INFO(\"Uploading %d emissive triangles (%d MB)...\", m_staleNumTris, numMbytes);\n\n        const size_t sizeInBytes = sizeof(RT::EmissiveTriangle) * m_staleNumTris;\n        GpuMemory::UploadToDefaultHeapBuffer(m_trisGpu, (uint32)sizeInBytes,\n            MemoryRegion{ .Data = &m_trisCpu[m_staleBaseOffset], .SizeInBytes = (uint32)sizeInBytes },\n            m_staleBaseOffset * sizeof(RT::EmissiveTriangle));\n\n        m_staleNumTris = 0;\n        m_staleBaseOffset = UINT32_MAX;\n    }\n}\n\nvoid EmissiveBuffer::Clear()\n{\n    m_trisGpu.Reset(false);\n}\n\nvoid EmissiveBuffer::UpdateMaterial(uint64_t instanceID, const float3& emissiveFactor, float strength)\n{\n    auto& instance = *FindInstance(instanceID).value();\n    const int modifiedMatIdx = instance.MaterialIdx;\n\n    // BinarySearch() must return the leftmost index when keys aren't unique\n    auto idx = BinarySearch(Span(m_instances), modifiedMatIdx,\n        [](const Asset::EmissiveInstance& e) { return e.MaterialIdx; });\n    Assert(idx != -1, \"Material was not found.\");\n\n    const uint32 newEmissiveFactor = Float3ToRGB8(emissiveFactor);\n    const half newStrength(strength);\n\n    m_staleBaseOffset = m_instances[idx].BaseTriOffset;\n\n    // Find every instance that uses this material\n    while (idx < (int64)m_instances.size() && m_instances[idx].MaterialIdx == modifiedMatIdx)\n    {\n        // Update all triangles for this instance\n        for (int64 i = m_instances[idx].BaseTriOffset; \n            i < m_instances[idx].BaseTriOffset + m_instances[idx].NumTriangles; i++)\n        {\n            m_trisCpu[i].SetEmissiveFactor(newEmissiveFactor);\n            m_trisCpu[i].SetStrength(newStrength);\n        }\n\n        m_staleNumTris += m_instances[idx].NumTriangles;\n        idx++;\n    } \n}\n\nvoid EmissiveBuffer::UpdateTriPositions(size_t startIdx, size_t endIdx)\n{\n    Assert(endIdx <= m_trisCpu.size(), \"Invalid index.\");\n\n    m_staleBaseOffset = (uint32)startIdx;\n    m_staleNumTris = (uint32)(endIdx - startIdx);\n}\n"
  },
  {
    "path": "Source/ZetaCore/Scene/Asset.h",
    "content": "#pragma once\n\n#include \"../Utility/HashTable.h\"\n#include \"../Core/DescriptorHeap.h\"\n#include \"../Model/glTFAsset.h\"\n#include \"../RayTracing/RtCommon.h\"\n#include <Utility/Optional.h>\n\nnamespace ZetaRay::Scene::Internal\n{\n    //--------------------------------------------------------------------------------------\n    // TextureDescriptorTable: A descriptor table containing a contiguous set of textures, \n    // which are to be bound as unbounded descriptor tables in shaders. Each texture index in\n    // a given Material refers to an offset in one such descriptor table\n    //--------------------------------------------------------------------------------------\n\n    struct TexSRVDescriptorTable\n    {\n        explicit TexSRVDescriptorTable(const uint32_t descTableSize = 1024);\n        ~TexSRVDescriptorTable() = default;\n\n        TexSRVDescriptorTable(const TexSRVDescriptorTable&) = delete;\n        TexSRVDescriptorTable& operator=(const TexSRVDescriptorTable&) = delete;\n\n        void Init(uint64_t id);\n        // Assumes proper GPU synchronization has been performed\n        void Clear();\n        // Returns offset of the given texture in the descriptor table. The texture is then loaded from\n        // the disk. \"id\" is hash of the texture path.\n        uint32_t Add(Core::GpuMemory::Texture&& tex);\n        void Recycle(uint64_t completedFenceVal);\n        ZetaInline uint32_t GPUDescriptorHeapIndex() const { return m_descTable.GPUDescriptorHeapIndex(); }\n\n    private:\n        struct ToBeFreedTexture\n        {\n            Core::GpuMemory::Texture T;\n            uint64_t FenceVal;\n            uint32_t DescTableOffset;\n        };\n\n        struct CacheEntry\n        {\n            Core::GpuMemory::Texture T;\n            uint32_t DescTableOffset = UINT32_MAX;\n            uint32_t RefCount = 0;\n        };\n\n        static constexpr int MAX_NUM_DESCRIPTORS = 4096;\n        static constexpr int MAX_NUM_MASKS = MAX_NUM_DESCRIPTORS >> 6;\n        static_assert(MAX_NUM_MASKS * 64 == MAX_NUM_DESCRIPTORS, \"these must match.\");\n\n        Util::SmallVector<ToBeFreedTexture> m_pending;\n        const uint32_t m_descTableSize;\n        const uint32_t m_numMasks;\n        uint64_t m_inUseBitset[MAX_NUM_MASKS] = { 0 };\n        Core::DescriptorTable m_descTable;\n        // TODO Duplicate texture ID storage as key and texture object member\n        Util::HashTable<CacheEntry, Core::GpuMemory::Texture::ID_TYPE> m_cache;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // MaterialBuffer: Wrapper over a GPU buffer containing all the materials\n    //--------------------------------------------------------------------------------------\n\n    struct MaterialBuffer\n    {\n        MaterialBuffer() = default;\n        ~MaterialBuffer() = default;\n\n        MaterialBuffer(const MaterialBuffer&) = delete;\n        MaterialBuffer& operator=(const MaterialBuffer&) = delete;\n\n        void Clear();\n        void Add(uint32_t ID, const Material& mat);\n        void Update(uint32_t ID, const Material& mat)\n        {\n            auto it = m_materials.find(ID);\n            it.value()->Mat = mat;\n            m_staleID = ID;\n        }\n        void UploadToGPU();\n        void ResizeAdditionalMaterials(uint32_t num);\n        uint32_t NumMaterials() const { return (uint32_t)m_materials.size(); }\n\n        ZetaInline Util::Optional<const Material*> Get(uint32_t ID, uint32* bufferIdx = nullptr) const\n        {\n            auto it = m_materials.find(ID);\n            if (it)\n            {\n                auto* entry = it.value();\n\n                if (bufferIdx)\n                    *bufferIdx = entry->GpuBufferIdx;\n\n                return &entry->Mat;\n            }\n\n            return {};\n        }\n\n    private:\n        struct Entry\n        {\n            Material Mat;\n            uint32_t GpuBufferIdx;\n        };\n\n        static constexpr int MAX_NUM_MATERIALS = 4096;\n        static constexpr int NUM_MASKS = MAX_NUM_MATERIALS >> 6;\n        static_assert(NUM_MASKS * 64 == MAX_NUM_MATERIALS, \"these must match.\");\n        uint64_t m_inUseBitset[NUM_MASKS] = { 0 };\n\n        Core::GpuMemory::Buffer m_buffer;\n        Util::HashTable<Entry, uint32_t> m_materials;\n        uint32 m_staleID = UINT32_MAX;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // MeshContainer\n    //--------------------------------------------------------------------------------------\n\n    struct MeshContainer\n    {\n        uint32_t Add(Util::SmallVector<Core::Vertex>&& vertices, Util::SmallVector<uint32_t>&& indices,\n            uint32_t matIdx);\n        void AddBatch(Util::SmallVector<Model::glTF::Asset::Mesh>&& meshes, \n            Util::SmallVector<Core::Vertex>&& vertices,\n            Util::SmallVector<uint32_t>&& indices);\n        void Reserve(size_t numVertices, size_t numIndices);\n        void RebuildBuffers();\n        void Clear();\n\n        // Note: not thread safe for reading and writing at the same time\n        ZetaInline Util::Optional<const Model::TriangleMesh*> GetMesh(uint64_t id) const\n        {\n            auto it = m_meshes.find(id);\n            if (it)\n                return it.value();\n\n            return {};\n        }\n\n        const Core::GpuMemory::Buffer& GetVB() const { return m_vertexBuffer; }\n        const Core::GpuMemory::Buffer& GetIB() const { return m_indexBuffer; }\n        uint32_t NumMeshes() const { return (uint32_t)m_meshes.size(); }\n\n    private:\n        Util::HashTable<Model::TriangleMesh> m_meshes;\n        Util::SmallVector<Core::Vertex> m_vertices;\n        Util::SmallVector<uint32_t> m_indices;\n\n        Core::GpuMemory::Buffer m_vertexBuffer;\n        Core::GpuMemory::Buffer m_indexBuffer;\n        Core::GpuMemory::ResourceHeap m_heap;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // EmissiveBuffer\n    //--------------------------------------------------------------------------------------\n\n    struct EmissiveBuffer\n    {\n        struct Triangle\n        {\n            // = CommittedPrimitiveIndex(): \"...index of the primitive within the geometry \n            // inside the bottom-level acceleration structure instance...\"\n            uint32_t PrimIdx;\n            Math::float3 Vtx0;\n            unorm2_ V0V1;\n            unorm2_ V0V2;\n            half2_ EdgeLengths;\n        };\n\n        using Instance = Model::glTF::Asset::EmissiveInstance;\n\n        EmissiveBuffer() = default;\n        ~EmissiveBuffer() = default;\n\n        EmissiveBuffer(const EmissiveBuffer&) = delete;\n        EmissiveBuffer& operator=(const EmissiveBuffer&) = delete;\n\n        ZetaInline bool Initialized() const { return m_trisGpu.IsInitialized(); }\n        ZetaInline uint32_t NumInstances() const { return (uint32_t)m_instances.size(); }\n        ZetaInline uint32_t NumTriangles() const { return (uint32_t)m_trisCpu.size(); }\n        ZetaInline Util::Span<Instance> Instances() { return m_instances; }\n        ZetaInline Util::MutableSpan<RT::EmissiveTriangle> Triagnles() { return m_trisCpu; }\n        ZetaInline Util::MutableSpan<Triangle> InitialTriPositions() { return m_triInitialPos; }\n        ZetaInline bool HasStaleMaterials() const { return m_staleNumTris > 0; }\n        ZetaInline Util::Optional<const Instance*> FindInstance(uint64_t ID)\n        {\n            auto it = m_idToIdxMap.find(ID);\n            if (it)\n                return &m_instances[*it.value()];\n\n            return {};\n        }\n\n        // Assumes proper GPU synchronization has been performed\n        void Clear();\n        void UpdateMaterial(uint64_t instanceID, const Math::float3& emissiveFactor, float strength);\n        void UpdateTriPositions(size_t startIdx, size_t endIdx);\n        void AddBatch(Util::SmallVector<Instance>&& instances,\n            Util::SmallVector<RT::EmissiveTriangle>&& tris);\n        void UploadToGPU();\n\n    private:\n        Util::SmallVector<Instance> m_instances;\n        Util::SmallVector<RT::EmissiveTriangle> m_trisCpu;\n        Util::SmallVector<Triangle> m_triInitialPos;\n        // Maps instance ID to index in m_instances\n        Util::HashTable<uint32_t> m_idToIdxMap;\n        Core::GpuMemory::Buffer m_trisGpu;\n        uint32_t m_staleBaseOffset = UINT32_MAX;\n        uint32_t m_staleNumTris = 0;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Scene/CMakeLists.txt",
    "content": "set(SCENE_DIR \"${ZETA_CORE_DIR}/Scene\")\nset(SCENE_SRC\n    \"${SCENE_DIR}/Asset.cpp\"\n    \"${SCENE_DIR}/Asset.h\"\n    \"${SCENE_DIR}/Camera.cpp\"\n    \"${SCENE_DIR}/Camera.h\"\n    \"${SCENE_DIR}/SceneCommon.h\"\n    \"${SCENE_DIR}/SceneCore.cpp\"\n    \"${SCENE_DIR}/SceneCore.h\"\n    \"${SCENE_DIR}/SceneRenderer.h\")\n\nset(SCENE_SRC ${SCENE_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaCore/Scene/Camera.cpp",
    "content": "#include \"Camera.h\"\n#include \"../App/Timer.h\"\n#include \"../Core/RendererCore.h\"\n#include \"../Math/CollisionFuncs.h\"\n#include \"../Math/Sampling.h\"\n#include \"../Support/Param.h\"\n#include \"SceneCore.h\"\n#include \"../Assets/Font/IconsFontAwesome6.h\"\n\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Math;\n\nnamespace\n{\n    ZetaInline void __vectorcall setCamPos(const __m128 vNewCamPos, float4x4a& view, float4x4a& viewInv)\n    {\n        const __m128 vT = negate(vNewCamPos);\n        viewInv.m[3] = store(vNewCamPos);\n\n        __m128 vRow0 = _mm_load_ps(reinterpret_cast<float*>(&view.m[0]));\n        __m128 vRow1 = _mm_load_ps(reinterpret_cast<float*>(&view.m[1]));\n        __m128 vRow2 = _mm_load_ps(reinterpret_cast<float*>(&view.m[2]));\n\n        __m128 v4thRow = _mm_mul_ps(_mm_shuffle_ps(vT, vT, V_SHUFFLE_XYZW(0, 0, 0, 0)), vRow0);\n        v4thRow = _mm_fmadd_ps(_mm_shuffle_ps(vT, vT, V_SHUFFLE_XYZW(1, 1, 1, 0)), vRow1, v4thRow);\n        v4thRow = _mm_fmadd_ps(_mm_shuffle_ps(vT, vT, V_SHUFFLE_XYZW(2, 2, 2, 0)), vRow2, v4thRow);\n\n        // Set the 4th element to 1.0\n        view.m[3] = store(_mm_insert_ps(v4thRow, _mm_set1_ps(1.0f), 0x30));\n    }\n\n    ZetaInline v_float4x4 __vectorcall resetViewMatrix(const __m128 vBasisX, const __m128 vBasisY,\n        const __m128 vBasisZ, const __m128 vEye, float4x4a& viewInv)\n    {\n        v_float4x4 vViewInv;\n        vViewInv.vRow[0] = vBasisX;\n        vViewInv.vRow[1] = vBasisY;\n        vViewInv.vRow[2] = vBasisZ;\n        vViewInv.vRow[3] = _mm_setzero_ps();\n\n        v_float4x4 vNewView = transpose(vViewInv);\n        // Transforms from view space to world space\n        vViewInv.vRow[3] = vEye;\n        viewInv = store(vViewInv);\n\n        const __m128 vT = negate(vEye);\n        __m128 v4thRow = _mm_mul_ps(_mm_shuffle_ps(vT, vT, V_SHUFFLE_XYZW(0, 0, 0, 0)), vNewView.vRow[0]);\n        v4thRow = _mm_fmadd_ps(_mm_shuffle_ps(vT, vT, V_SHUFFLE_XYZW(1, 1, 1, 0)), vNewView.vRow[1], v4thRow);\n        v4thRow = _mm_fmadd_ps(_mm_shuffle_ps(vT, vT, V_SHUFFLE_XYZW(2, 2, 2, 0)), vNewView.vRow[2], v4thRow);\n\n        // Set the 4th element to 1.0\n        vNewView.vRow[3] = _mm_insert_ps(v4thRow, _mm_set1_ps(1.0f), 0x30);\n\n        return vNewView;\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// Camera\n//--------------------------------------------------------------------------------------\n\nvoid Camera::Init(float3 posw, float aspectRatio, float fov, float nearZ, bool jitter, \n    float3 focusOrViewDir, bool lookAt)\n{\n    m_posW = float4a(posw, 1.0f);\n    m_fov = fov;\n    m_aspectRatio = aspectRatio;\n    m_tanHalfFOV = tanf(0.5f * m_fov);\n    m_nearZ = nearZ;\n    m_farZ = FLT_MAX;\n    m_viewFrustum = ViewFrustum(fov, aspectRatio, nearZ, m_farZ);\n    m_jitteringEnabled = jitter;\n\n    // \"Ray Tracing Gems\", ch. 20, eq. (30)\n    m_pixelSpreadAngle = atanf(2 * m_tanHalfFOV / App::GetRenderer().GetRenderHeight());\n\n    v_float4x4 vView;\n\n    if (lookAt)\n        vView = lookAtLH(m_posW, focusOrViewDir, m_upW);\n    else\n    {\n        Assert(fabs(focusOrViewDir.dot(focusOrViewDir)) > 1e-7,\n            \"(0, 0, 0) is not a valid view vector.\");\n        vView = lookToLH(m_posW, focusOrViewDir, m_upW);\n    }\n\n    m_view = store(vView);\n\n    // Extract the basis vectors from the view matrix. Make sure the 4th element is zero.\n    v_float4x4 vT = transpose(vView);\n    __m128 vBasisX = _mm_insert_ps(vT.vRow[0], vT.vRow[0], 0x8);\n    __m128 vBasisY = _mm_insert_ps(vT.vRow[1], vT.vRow[1], 0x8);\n    __m128 vBasisZ = _mm_insert_ps(vT.vRow[2], vT.vRow[2], 0x8);\n    __m128 vEye = _mm_load_ps(reinterpret_cast<float*>(&m_posW));\n\n    v_float4x4 vViewToWorld(vBasisX, vBasisY, vBasisZ, vEye);\n    m_viewInv = store(vViewToWorld);\n\n    UpdateProj();\n    UpdateFocalLength();\n\n    m_basisX = store(vBasisX);\n    m_basisY = store(vBasisY);\n    m_basisZ = store(vBasisZ);\n\n    ParamVariant jitterCamera;\n    jitterCamera.InitBool(ICON_FA_FILM \" Renderer\", \"Anti-Aliasing\", \"Jitter Camera Ray\",\n        fastdelegate::MakeDelegate(this, &Camera::SetJitteringEnabled), m_jitteringEnabled);\n    App::AddParam(jitterCamera);\n\n    ParamVariant fovParam;\n    fovParam.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Camera\", \"FOV\", fastdelegate::MakeDelegate(this, &Camera::SetFOV),\n        Math::RadiansToDegrees(m_fov), 20, 90, 1, \"Lens\");\n    App::AddParam(fovParam);\n\n    ParamVariant coeff;\n    coeff.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Camera\", \"Friction\",\n        fastdelegate::MakeDelegate(this, &Camera::SetFrictionCoeff),\n        m_frictionCoeff, 1, 20, 1, \"Motion\");\n    App::AddParam(coeff);\n\n    ParamVariant accAng;\n    accAng.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Camera\", \"Acc. (Angular)\",\n        fastdelegate::MakeDelegate(this, &Camera::SetAngularAcceleration),\n        m_angularAcc.x, 1.0f, 50.0f, 1.0f, \"Motion\");\n    App::AddParam(accAng);\n\n    ParamVariant dampScale;\n    dampScale.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Camera\", \"Damping (Angular)\",\n        fastdelegate::MakeDelegate(this, &Camera::SetAngularFrictionCoeff),\n        m_angularDamping.x, 1, 50, 1e-2f, \"Motion\");\n    App::AddParam(dampScale);\n\n    ParamVariant focusDepth;\n    focusDepth.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Camera\", \"Focus Depth\",\n        fastdelegate::MakeDelegate(this, &Camera::FocusDepthCallback),\n        m_focusDepth, 0.1f, 25.0f, 1e-2f, \"Lens\");\n    App::AddParam(focusDepth);\n\n    ParamVariant fstop;\n    fstop.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Camera\", \"F-Stop\",\n        fastdelegate::MakeDelegate(this, &Camera::FStopCallback),\n        m_fStop, 0.1f, 5.0f, 1e-2f, \"Lens\");\n    App::AddParam(fstop);\n\n    m_jitterPhaseCount = int(BASE_PHASE_COUNT * powf(App::GetUpscalingFactor(), 2.0f));\n}\n\nvoid Camera::Update(const Motion& m)\n{\n    float2 acc = float2(m.dMouse_x, m.dMouse_y) * m_angularAcc - m_angularDamping * m_initialAngularVelocity;\n    float2 newVelocity = acc * m.dt + m_initialAngularVelocity;\n    float2 dtheta = 0.5f * acc * m.dt * m.dt + m_initialAngularVelocity * m.dt;\n    m_initialAngularVelocity = newVelocity;\n\n    if (dtheta.x != 0.0)\n        RotateY(dtheta.x);\n    if (dtheta.y != 0.0)\n        RotateX(dtheta.y);\n\n    const __m128 vBasisX = _mm_load_ps(reinterpret_cast<float*>(&m_basisX));\n    const __m128 vBasisZ = _mm_load_ps(reinterpret_cast<float*>(&m_basisZ));\n    const __m128 vEye = _mm_load_ps(reinterpret_cast<float*>(&m_posW));\n    __m128 vInitialVelocity = _mm_load_ps(reinterpret_cast<float*>(&m_initialVelocity));\n\n    const __m128 vForce = loadFloat3(const_cast<float3&>(m.Acceleration));\n    __m128 vAcc = _mm_mul_ps(vBasisX, _mm_broadcastss_ps(vForce));\n    vAcc = _mm_fmadd_ps(vBasisZ, _mm_shuffle_ps(vForce, vForce, V_SHUFFLE_XYZW(2, 2, 2, 2)), vAcc);\n    vAcc = _mm_fmadd_ps(_mm_set1_ps(-m_frictionCoeff), vInitialVelocity, vAcc);\n\n    const __m128 vDt = _mm_set1_ps(m.dt);\n    const __m128 vVelocity = _mm_fmadd_ps(vAcc, vDt, vInitialVelocity);\n    const __m128 vDt2Over2 = _mm_mul_ps(_mm_mul_ps(vDt, vDt), _mm_set1_ps(0.5));\n    __m128 vVdt = _mm_mul_ps(vInitialVelocity, vDt);\n    __m128 vNewEye = _mm_fmadd_ps(vAcc, vDt2Over2, vVdt);\n    vNewEye = _mm_add_ps(vNewEye, vEye);\n    vInitialVelocity = vVelocity;\n\n    setCamPos(vNewEye, m_view, m_viewInv);\n    m_posW = store(vNewEye);\n    m_initialVelocity = store(vInitialVelocity);\n\n    if (m_jitteringEnabled)\n    {\n        const uint32_t frame = App::GetTimer().GetTotalFrameCount() % m_jitterPhaseCount;\n        m_currJitter.x = Halton(frame + 1, 2) - 0.5f;\n        m_currJitter.y = Halton(frame + 1, 3) - 0.5f;\n#if 0\n        // Shift each pixel by a value in [-0.5 / PixelWidth, 0.5 / PixelWidth] * [-0.5 / PixelHeight, 0.5 / PixelHeight]\n        // Jitter is relative to unit pixel offset -- [-0.5, -0.5] x [+0.5, +0.5]\n        // NDC is relative to [-1, -1] x [+1, +1], therefore multiply by 2\n        float2 projOffset = m_currJitter * float2(m_pixelSampleAreaWidth, m_pixelSampleAreaHeight) * float2(2.0f, -2.0f);\n\n        m_proj.m[2].x = projOffset.x;\n        m_proj.m[2].y = projOffset.y;\n#endif\n    }\n}\n\nvoid Camera::UpdateProj()\n{\n    v_float4x4 vP;\n\n    vP = perspectiveReverseZ(m_aspectRatio, m_fov, m_nearZ);\n    m_proj = store(vP);\n    vP = perspectiveReverseZ(m_aspectRatio, m_fov, m_nearZ, m_farZNonInfinite);\n    m_projNonInfinite = store(vP);\n\n    m_viewFrustum = ViewFrustum(m_fov, m_aspectRatio, m_nearZ, m_farZ);\n}\n\nvoid Camera::UpdateFocalLength()\n{\n    float sensorHeight = m_sensorWidth / m_aspectRatio;\n    m_focalLength = (0.5f * sensorHeight) / m_tanHalfFOV;\n}\n\nvoid Camera::OnWindowSizeChanged()\n{\n    const int renderWidth = App::GetRenderer().GetRenderWidth();\n    const int renderfHeight = App::GetRenderer().GetRenderHeight();\n    m_aspectRatio = (float)renderWidth / renderfHeight;\n\n    UpdateProj();\n    UpdateFocalLength();\n\n    m_pixelSpreadAngle = atanf(2 * m_tanHalfFOV / renderfHeight);\n    m_jitterPhaseCount = int(BASE_PHASE_COUNT * powf(App::GetUpscalingFactor(), 2.0f));\n}\n\nvoid Camera::RotateX(float theta)\n{\n    __m128 vBasisX = _mm_load_ps(reinterpret_cast<float*>(&m_basisX));\n    __m128 vBasisY = _mm_load_ps(reinterpret_cast<float*>(&m_basisY));\n    __m128 vBasisZ = _mm_load_ps(reinterpret_cast<float*>(&m_basisZ));\n    const __m128 vEye = _mm_load_ps(reinterpret_cast<float*>(&m_posW));\n\n    v_float4x4 vR = rotate(vBasisX, theta);\n    vBasisY = mul(vR, vBasisY);\n    vBasisZ = mul(vR, vBasisZ);\n\n    // Orthonormalize\n    vBasisZ = normalize(vBasisZ);\n    vBasisX = normalize(cross(vBasisY, vBasisZ));\n    vBasisY = cross(vBasisZ, vBasisX);\n\n    v_float4x4 vNewView = resetViewMatrix(vBasisX, vBasisY, vBasisZ, vEye, m_viewInv);\n    m_view = store(vNewView);\n\n    m_basisX = store(vBasisX);\n    m_basisY = store(vBasisY);\n    m_basisZ = store(vBasisZ);\n}\n\nvoid Camera::RotateY(float theta)\n{\n    __m128 vBasisX = _mm_load_ps(reinterpret_cast<float*>(&m_basisX));\n    __m128 vBasisY = _mm_load_ps(reinterpret_cast<float*>(&m_basisY));\n    __m128 vBasisZ = _mm_load_ps(reinterpret_cast<float*>(&m_basisZ));\n    const __m128 vEye = _mm_load_ps(reinterpret_cast<float*>(&m_posW));\n\n    v_float4x4 vR = rotateY(theta);\n\n    vBasisX = mul(vR, vBasisX);\n    vBasisY = mul(vR, vBasisY);\n    vBasisZ = mul(vR, vBasisZ);\n\n    // Orthonormalize\n    vBasisZ = normalize(vBasisZ);\n    vBasisX = normalize(cross(vBasisY, vBasisZ));\n    vBasisY = cross(vBasisZ, vBasisX);\n\n    v_float4x4 vNewView = resetViewMatrix(vBasisX, vBasisY, vBasisZ, vEye, m_viewInv);\n    m_view = store(vNewView);\n\n    m_basisX = store(vBasisX);\n    m_basisY = store(vBasisY);\n    m_basisZ = store(vBasisZ);\n}\n\nvoid Camera::SetFOV(const ParamVariant& p)\n{\n    m_fov = Math::DegreesToRadians(p.GetFloat().m_value);\n    m_tanHalfFOV = tanf(0.5f * m_fov);\n\n    UpdateProj();\n    UpdateFocalLength();\n\n    App::GetScene().SceneModified();\n}\n\nvoid Camera::SetJitteringEnabled(const ParamVariant& p)\n{\n    m_jitteringEnabled = p.GetBool();\n\n    m_proj.m[2].x = 0.0f;\n    m_proj.m[2].y = 0.0f;\n\n    m_currJitter = float2(0.0f, 0.0f);\n}\n\nvoid Camera::SetFrictionCoeff(const Support::ParamVariant& p)\n{\n    m_frictionCoeff = p.GetFloat().m_value;\n}\n\nvoid Camera::SetAngularFrictionCoeff(const Support::ParamVariant& p)\n{\n    m_angularDamping = float2(p.GetFloat().m_value);\n}\n\nvoid Camera::SetAngularAcceleration(const Support::ParamVariant& p)\n{\n    m_angularAcc = float2(p.GetFloat().m_value);\n}\n\nvoid Camera::FocusDepthCallback(const Support::ParamVariant& p)\n{\n    m_focusDepth = p.GetFloat().m_value;\n    App::GetScene().SceneModified();\n}\n\nvoid Camera::FStopCallback(const Support::ParamVariant& p)\n{\n    m_fStop = p.GetFloat().m_value;\n    App::GetScene().SceneModified();\n}\n"
  },
  {
    "path": "Source/ZetaCore/Scene/Camera.h",
    "content": "#pragma once\n\n#include \"../Math/Matrix.h\"\n#include \"../Math/CollisionTypes.h\"\n\nnamespace ZetaRay::Support\n{\n    struct ParamVariant;\n}\n\nnamespace ZetaRay::Scene\n{\n    struct Motion\n    {\n        void Reset()\n        {\n            dt = 0.0f;\n            Acceleration = Math::float3(0.0f);\n            dMouse_x = 0;\n            dMouse_y = 0;\n        }\n\n        float dt;\n        Math::float3 Acceleration;\n        int16_t dMouse_x;\n        int16_t dMouse_y;\n    };\n\n    class Camera\n    {\n    public:\n        Camera() = default;\n        ~Camera() = default;\n\n        void Init(Math::float3 pos, float aspectRatio, float fov, float nearZ = 1.0f, bool jitter = false, \n            Math::float3 focusOrViewDir = Math::float3(0.0f), bool lookAt = true);\n        void Update(const Motion& m);\n        void OnWindowSizeChanged();\n\n        ZetaInline const Math::float4x4a& GetCurrView() const { return m_view; }\n        ZetaInline const Math::float4x4a& GetViewInv() const { return m_viewInv; }\n        ZetaInline const Math::float4x4a& GetProj() const { return m_proj; }\n        ZetaInline const Math::float4x4a& GetProjNonInfiniteFarZ() const { return m_projNonInfinite; }\n        ZetaInline const Math::float3 GetPos() const { return Math::float3(m_posW.x, m_posW.y, m_posW.z); }\n        ZetaInline float GetAspectRatio() const { return m_aspectRatio; }\n        ZetaInline float GetFOV() const { return m_fov; }\n        ZetaInline float GetNearZ() const { return m_nearZ; }\n        ZetaInline float GetFarZ() const { return m_farZ; }\n        ZetaInline float GetTanHalfFOV() const { return m_tanHalfFOV; }\n        ZetaInline float GetPixelSpreadAngle() const { return m_pixelSpreadAngle; }\n        // Unit is mm\n        ZetaInline float GetFocalLength() const { return m_focalLength; }\n        ZetaInline float GetFStop() const { return m_fStop; }\n        ZetaInline float GetFocusDepth() const { return m_focusDepth; }\n        // Unit is meters\n        ZetaInline float GetLensRadius() const\n        { \n            // mul by 0.5 to get radius from diameter\n            return 0.5f * (m_focalLength / 1000.0f) / m_fStop; \n        }\n        ZetaInline Math::float2 GetCurrJitter() const { return m_currJitter; }\n        ZetaInline Math::float3 GetBasisX() const { return Math::float3(m_basisX.x, m_basisX.y, m_basisX.z); }\n        ZetaInline Math::float3 GetBasisY() const { return Math::float3(m_basisY.x, m_basisY.y, m_basisY.z); }\n        ZetaInline Math::float3 GetBasisZ() const { return Math::float3(m_basisZ.x, m_basisZ.y, m_basisZ.z); }\n        ZetaInline const Math::ViewFrustum& GetCameraFrustumViewSpace() const { return m_viewFrustum; }\n\n    private:\n        static constexpr int BASE_PHASE_COUNT = 64;\n\n        void UpdateProj();\n        void UpdateFocalLength();\n        void RotateX(float theta);\n        void RotateY(float theta);\n\n        // param callbacks\n        void SetFOV(const Support::ParamVariant& p);\n        void SetJitteringEnabled(const Support::ParamVariant& p);\n        void SetFrictionCoeff(const Support::ParamVariant& p);\n        void SetAngularFrictionCoeff(const Support::ParamVariant& p);\n        void SetAngularAcceleration(const Support::ParamVariant& p);\n        void FocusDepthCallback(const Support::ParamVariant& p);\n        void FStopCallback(const Support::ParamVariant& p);\n\n        Math::float4x4a m_view;\n        Math::float4x4a m_viewInv;\n        Math::float4x4a m_proj;\n        Math::float4x4a m_projNonInfinite;\n        Math::float4a m_posW;\n        Math::float4a m_initialVelocity = Math::float4a(0.0f);\n        Math::float2 m_initialAngularVelocity = Math::float2(0.0f);\n        Math::ViewFrustum m_viewFrustum;\n        Math::float4a m_upW = Math::float4a(0.0f, 1.0f, 0.0f, 0.0f);\n\n        Math::float4a m_basisX;\n        Math::float4a m_basisY;\n        Math::float4a m_basisZ;\n\n        float m_fov;\n        float m_aspectRatio;\n        float m_nearZ;\n        float m_farZ;\n        float m_farZNonInfinite = 100.0f;\n        float m_tanHalfFOV;\n        float m_pixelSpreadAngle;\n        // Unit is mm\n        float m_sensorWidth = 36;\n        // - Focal point: point where incident rays that are parallel to the optical axis \n        //   and pass through the lens focus at \n        // - Focal length (f): distance from the focal point to the lens (in mm). Computed\n        //   from FOV as: 0.5 * sensor height / tan(0.5 FOV), where \n        //   sensor height = sensor width / aspect ratio (so a wider FOV is achieved by using \n        //   a shorter focal length, leading to less defocus blur and vice versa)\n        float m_focalLength;\n        // f-number n expresses lens diameter as a fraction of focal length, d = f / n\n        float m_fStop = 1.4f;\n        // The distance that camera is focusing at\n        float m_focusDepth = 5.0f;\n        Math::float2 m_currJitter = Math::float2(0);\n        int m_jitterPhaseCount;\n        bool m_jitteringEnabled = false;\n        float m_frictionCoeff = 10.0f;\n        Math::float2 m_angularAcc = Math::float2(19.0f);\n        Math::float2 m_angularDamping = Math::float2(19.0f);\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Scene/SceneCommon.h",
    "content": "#pragma once\n\n#include <App/ZetaRay.h>\n\nnamespace ZetaRay::Scene\n{\n    static constexpr uint64_t INVALID_INSTANCE = UINT64_MAX;\n    static constexpr uint64_t INVALID_MESH = UINT64_MAX;\n    static constexpr uint32_t DEFAULT_MATERIAL_ID = 0;\n    static constexpr uint32_t DEFAULT_SCENE_ID = 0;\n}\n"
  },
  {
    "path": "Source/ZetaCore/Scene/SceneCore.cpp",
    "content": "#include \"SceneCore.h\"\n#include \"../Math/CollisionFuncs.h\"\n#include \"../Math/Quaternion.h\"\n#include \"../Support/Task.h\"\n#include \"Camera.h\"\n#include <App/Timer.h>\n#include <Support/Param.h>\n#include <algorithm>\n#include \"../Assets/Font/IconsFontAwesome6.h\"\n\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Scene::Internal;\nusing namespace ZetaRay::Model;\nusing namespace ZetaRay::Model::glTF;\nusing namespace ZetaRay::Model::glTF::Asset;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::App;\n\nnamespace\n{\n    ZetaInline uint3 Pcg3d(uint3 v)\n    {\n        v = v * 1664525u + 1013904223u;\n        v.x += v.y * v.z;\n        v.y += v.z * v.x;\n        v.z += v.x * v.y;\n        v = v ^ (v >> 16u);\n        v.x += v.y * v.z;\n        v.y += v.z * v.x;\n        v.z += v.x * v.y;\n        return v;\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// Scene\n//--------------------------------------------------------------------------------------\n\nSceneCore::SceneCore()\n    : m_baseColorDescTable(BASE_COLOR_DESC_TABLE_SIZE),\n    m_normalDescTable(NORMAL_DESC_TABLE_SIZE),\n    m_metallicRoughnessDescTable(METALLIC_ROUGHNESS_DESC_TABLE_SIZE),\n    m_emissiveDescTable(EMISSIVE_DESC_TABLE_SIZE)\n{}\n\nvoid SceneCore::Init(Renderer::Interface& rendererInterface)\n{\n    m_rendererInterface = rendererInterface;\n    Assert(m_rendererInterface.Init, \"Init() was null.\");\n    Assert(m_rendererInterface.Update, \"Update() was null.\");\n    Assert(m_rendererInterface.Render, \"Render() was null.\");\n    Assert(m_rendererInterface.Shutdown, \"Shutdown() was null.\");\n    Assert(m_rendererInterface.OnWindowSizeChanged, \"OnWindowSizeChanged() was null.\");\n    Assert(m_rendererInterface.DebugDrawRenderGraph, \"DebugDrawRenderGraph() was null.\");\n\n    // Level 0 is just a (dummy) root\n    //m_sceneGraph.reserve(2);\n    //m_sceneGraph.emplace_back(TreeLevel());\n    //m_sceneGraph.emplace_back(TreeLevel());\n    m_sceneGraph.resize(2);\n\n    m_sceneGraph[0].m_toWorlds.resize(1);\n    m_sceneGraph[0].m_subtreeRanges.resize(1);\n    m_sceneGraph[0].m_subtreeRanges[0] = Range(0, 0);\n\n    v_float4x4 I = identity();\n    m_sceneGraph[0].m_toWorlds[0] = float4x3(store(I));\n\n    m_baseColorDescTable.Init(XXH3_64bits(GlobalResource::BASE_COLOR_DESCRIPTOR_TABLE,\n        strlen(GlobalResource::BASE_COLOR_DESCRIPTOR_TABLE)));\n    m_normalDescTable.Init(XXH3_64bits(GlobalResource::NORMAL_DESCRIPTOR_TABLE, \n        strlen(GlobalResource::NORMAL_DESCRIPTOR_TABLE)));\n    m_metallicRoughnessDescTable.Init(XXH3_64bits(GlobalResource::METALLIC_ROUGHNESS_DESCRIPTOR_TABLE,\n        strlen(GlobalResource::METALLIC_ROUGHNESS_DESCRIPTOR_TABLE)));\n    m_emissiveDescTable.Init(XXH3_64bits(GlobalResource::EMISSIVE_DESCRIPTOR_TABLE, \n        strlen(GlobalResource::EMISSIVE_DESCRIPTOR_TABLE)));\n\n    m_rendererInterface.Init();\n\n    // Allocate a slot for the default material\n    m_matBuffer.ResizeAdditionalMaterials(1);\n\n    Material defaultMat;\n    m_matBuffer.Add(DEFAULT_MATERIAL_ID, defaultMat);\n\n    ParamVariant animation;\n    animation.InitBool(ICON_FA_LANDMARK \" Scene\", \"Animation\", \"Pause\",\n        fastdelegate::MakeDelegate(this, &SceneCore::AnimateCallback),\n        !m_animate);\n    App::AddParam(animation);\n}\n\nvoid SceneCore::OnWindowSizeChanged()\n{\n    m_rendererInterface.OnWindowSizeChanged();\n}\n\nvoid SceneCore::Update(double dt, TaskSet& sceneTS, TaskSet& sceneRendererTS)\n{\n    if (m_isPaused)\n        return;\n\n    auto updateWorldTransforms = sceneTS.EmplaceTask(\"Scene::UpdateWorldTransform\", [this]()\n        {\n            if (m_rebuildBVHFlag)\n                InitWorldTransformations();\n\n            if (m_animate)\n            {\n                SmallVector<AnimationUpdate, App::FrameAllocator> animUpdates;\n                UpdateAnimations((float)App::GetTimer().GetTotalTime(), animUpdates);\n                UpdateLocalTransforms(animUpdates);\n            }\n\n            if (!m_instanceUpdates.empty())\n            {\n                SmallVector<BVH::BVHUpdateInput, App::FrameAllocator> toUpdateInstances;\n                UpdateWorldTransformations(toUpdateInstances);\n            }\n\n            m_rebuildBVHFlag = false;\n        });\n\n    const uint32_t numInstances = m_emissives.NumInstances();\n    m_staleEmissiveMats = m_emissives.HasStaleMaterials() || !m_emissives.Initialized();\n    // Size of m_instanceUpdates may change after async. task above runs, but since it never\n    // goes from > 0 to 0, it doesn't matter\n    m_staleEmissivePositions = m_staleEmissivePositions || !m_emissives.Initialized();\n\n    if (!m_emissives.Initialized() && numInstances)\n    {\n        ParamVariant emissives;\n        emissives.InitBool(ICON_FA_LANDMARK \" Scene\", \"Emissives\", \"Enabled\",\n            fastdelegate::MakeDelegate(this, &SceneCore::ToggleEmissivesCallback),\n            !m_ignoreEmissives);\n        App::AddParam(emissives);\n    }\n\n    // When emissives have stale position or material\n    if (numInstances && (m_staleEmissivePositions || m_staleEmissiveMats))\n    {\n        TaskSet::TaskHandle resetRtAsInfo = TaskSet::INVALID_TASK_HANDLE;\n\n        // NOTE RT-AS info is needed to compute a unique hash for emissives. It is managed\n        // by TLAS, but since that runs later, it's not available for initialization\n        // of emissives. For future frames, TLAS expects the old (stale) RT-AS info \n        // so it can't be changed here. \n        // \n        // TODO In the case of StaticToDynamic, the first UpdateEmissivePositions() call \n        // uses the wrong InstanceID. Later in the frame, it's updated by TLAS and from \n        // the second frame on, the correct value is used. Since movement usually lasts \n        // for more than one frame, it shouldn't be a problem.\n#if 0\n        if (m_staleEmissivePositions)\n#else\n        if (!m_emissives.Initialized())\n#endif\n        {\n            resetRtAsInfo = sceneTS.EmplaceTask(\"Scene::UpdateRtAsInfo\", [this]()\n                {\n                    ResetRtAsInfos();\n                });\n        }\n\n        auto upload = sceneTS.EmplaceTask(\"UploadEmissiveBuffer\", [this]()\n            {\n                m_emissives.UploadToGPU();\n            });\n\n        // Full rebuild of emissive buffer for first time\n        if (!m_emissives.Initialized())\n        {\n            constexpr size_t MAX_NUM_EMISSIVE_WORKERS = 5;\n            constexpr size_t MIN_EMISSIVE_INSTANCES_PER_WORKER = 35;\n            size_t threadOffsets[MAX_NUM_EMISSIVE_WORKERS];\n            size_t threadSizes[MAX_NUM_EMISSIVE_WORKERS];\n\n            const size_t numEmissiveWorkers = SubdivideRangeWithMin(numInstances,\n                MAX_NUM_EMISSIVE_WORKERS,\n                threadOffsets,\n                threadSizes,\n                MIN_EMISSIVE_INSTANCES_PER_WORKER);\n\n            for (size_t i = 0; i < numEmissiveWorkers; i++)\n            {\n                StackStr(tname, n, \"Scene::Emissive_%d\", i);\n\n                auto h = sceneTS.EmplaceTask(tname, [this, offset = threadOffsets[i], size = threadSizes[i]]()\n                    {\n                        auto emissvies = m_emissives.Instances();\n                        auto tris = m_emissives.Triagnles();\n                        auto triInitialPos = m_emissives.InitialTriPositions();\n                        v_float4x4 I = identity();\n\n                        // For every emissive instance, apply world transformation to all of its triangles\n                        for (size_t instance = offset; instance < offset + size; instance++)\n                        {\n                            const auto& e = emissvies[instance];\n                            const v_float4x4 vW = load4x3(GetToWorld(e.InstanceID));\n                            const bool skipTransform = equal(vW, I);\n\n                            const auto rtASInfo = GetInstanceRtASInfo(e.InstanceID);\n\n                            for (size_t t = e.BaseTriOffset; t < e.BaseTriOffset + e.NumTriangles; t++)\n                            {\n                                if (!skipTransform)\n                                {\n                                    __m128 vV0;\n                                    __m128 vV1;\n                                    __m128 vV2;\n                                    tris[t].LoadVertices(vV0, vV1, vV2);\n\n                                    triInitialPos[t].Vtx0 = tris[t].Vtx0;\n                                    triInitialPos[t].V0V1 = tris[t].V0V1;\n                                    triInitialPos[t].V0V2 = tris[t].V0V2;\n                                    triInitialPos[t].EdgeLengths = tris[t].EdgeLengths;\n                                    triInitialPos[t].PrimIdx = tris[t].ID;\n\n                                    vV0 = mul(vW, vV0);\n                                    vV1 = mul(vW, vV1);\n                                    vV2 = mul(vW, vV2);\n                                    tris[t].StoreVertices(vV0, vV1, vV2);\n                                }\n\n                                const uint32_t hash = Pcg3d(uint3(rtASInfo.GeometryIndex, \n                                    rtASInfo.InstanceID,\n                                    tris[t].ID)).x;\n\n                                Assert(!tris[t].IsIDPatched(), \n                                    \"Rewriting emissive triangle ID after the first assignment is invalid.\");\n                                tris[t].ResetID(hash);\n                            }\n                        }\n                    });\n\n                sceneTS.AddOutgoingEdge(updateWorldTransforms, h);\n\n                Assert(resetRtAsInfo != TaskSet::INVALID_TASK_HANDLE, \"Invalid task handle.\");\n                sceneTS.AddOutgoingEdge(resetRtAsInfo, h);\n\n                sceneTS.AddOutgoingEdge(h, upload);\n            }\n        }\n        else if (m_staleEmissivePositions)\n        {\n            auto h = sceneTS.EmplaceTask(\"Scene::UpdateEmissivePos\", [this]()\n                {\n                    UpdateEmissivePositions();\n                });\n\n            //sceneTS.AddOutgoingEdge(resetRtAsInfo, h);\n            sceneTS.AddOutgoingEdge(h, upload);\n        }\n\n        m_staleEmissivePositions = false;\n    }\n\n    if (m_meshBufferStale)\n    {\n        sceneTS.EmplaceTask(\"Scene::RebuildMeshBuffers\", [this]()\n            {\n                m_meshes.RebuildBuffers();\n            });\n\n        m_meshBufferStale = false;\n    }\n\n    m_matBuffer.UploadToGPU();\n    m_rendererInterface.Update(sceneRendererTS);\n}\n\nvoid SceneCore::Shutdown()\n{\n    // Make sure all GPU resources (texture, buffers, etc) are manually released,\n    // as they normally call the GPU memory subsystem upon destruction, which\n    // is deleted at that point.\n    m_matBuffer.Clear();\n    m_baseColorDescTable.Clear();\n    m_normalDescTable.Clear();\n    m_metallicRoughnessDescTable.Clear();\n    m_emissiveDescTable.Clear();\n    m_meshes.Clear();\n    m_emissives.Clear();\n\n    for (auto& heap : m_textureHeaps)\n        heap.Reset();\n\n    m_rendererInterface.Shutdown();\n}\n\nuint32_t SceneCore::AddMesh(SmallVector<Vertex>&& vertices, SmallVector<uint32_t>&& indices,\n    uint32_t matIdx, bool lock)\n{\n    if (lock)\n        AcquireSRWLockExclusive(&m_meshLock);\n\n    m_numTriangles += (uint32_t)indices.size();\n    uint32_t idx = m_meshes.Add(ZetaMove(vertices), ZetaMove(indices), matIdx);\n\n    if (lock)\n        ReleaseSRWLockExclusive(&m_meshLock);\n\n    return idx;\n}\n\nvoid SceneCore::AddMeshes(SmallVector<Asset::Mesh>&& meshes, SmallVector<Vertex>&& vertices,\n    SmallVector<uint32_t>&& indices, bool lock)\n{\n    if (lock)\n        AcquireSRWLockExclusive(&m_meshLock);\n\n    m_numTriangles += (uint32_t)indices.size();\n    m_meshes.AddBatch(ZetaMove(meshes), ZetaMove(vertices), ZetaMove(indices));\n\n    if (lock)\n        ReleaseSRWLockExclusive(&m_meshLock);\n}\n\nvoid SceneCore::AddMaterial(const Asset::MaterialDesc& matDesc, bool lock)\n{\n    Material mat;\n    mat.SetBaseColorFactor(matDesc.BaseColorFactor);\n    mat.SetMetallic(matDesc.MetallicFactor);\n    mat.SetSpecularRoughness(matDesc.SpecularRoughnessFactor);\n    mat.SetSpecularIOR(matDesc.SpecularIOR);\n    mat.SetTransmission(matDesc.TransmissionWeight);\n    mat.SetSubsurface(matDesc.SubsurfaceWeight);\n    mat.SetCoatWeight(matDesc.CoatWeight);\n    mat.SetCoatColor(matDesc.CoatColor);\n    mat.SetCoatRoughness(matDesc.CoatRoughness);\n    mat.SetCoatIOR(matDesc.CoatIOR);\n    mat.SetEmissiveFactor(matDesc.EmissiveFactor);\n    mat.SetEmissiveStrength(matDesc.EmissiveStrength);\n    mat.SetNormalScale(matDesc.NormalScale);\n    mat.SetAlphaCutoff(matDesc.AlphaCutoff);\n    mat.SetAlphaMode(matDesc.AlphaMode);\n    mat.SetDoubleSided(matDesc.DoubleSided);\n\n    if (lock)\n        AcquireSRWLockExclusive(&m_matLock);\n\n    m_matBuffer.Add(matDesc.ID, mat);\n\n    if (lock)\n        ReleaseSRWLockExclusive(&m_matLock);\n}\n\nvoid SceneCore::AddMaterial(const Asset::MaterialDesc& matDesc, MutableSpan<Texture> ddsImages,\n    bool lock)\n{\n    Material mat;\n    mat.SetBaseColorFactor(matDesc.BaseColorFactor);\n    mat.SetMetallic(matDesc.MetallicFactor);\n    mat.SetSpecularRoughness(matDesc.SpecularRoughnessFactor);\n    mat.SetSpecularIOR(matDesc.SpecularIOR);\n    mat.SetTransmission(matDesc.TransmissionWeight);\n    mat.SetSubsurface(matDesc.SubsurfaceWeight);\n    mat.SetCoatWeight(matDesc.CoatWeight);\n    mat.SetCoatColor(matDesc.CoatColor);\n    mat.SetCoatRoughness(matDesc.CoatRoughness);\n    mat.SetCoatIOR(matDesc.CoatIOR);\n    mat.SetEmissiveFactor(matDesc.EmissiveFactor);\n    mat.SetEmissiveStrength(matDesc.EmissiveStrength);\n    mat.SetNormalScale(matDesc.NormalScale);\n    mat.SetAlphaCutoff(matDesc.AlphaCutoff);\n    mat.SetAlphaMode(matDesc.AlphaMode);\n    mat.SetDoubleSided(matDesc.DoubleSided);\n\n    auto addTex = [](Texture::ID_TYPE ID, const char* type, TexSRVDescriptorTable& table, uint32_t& tableOffset, \n        MutableSpan<Texture> ddsImages)\n        {\n            auto idx = BinarySearch(Span(ddsImages), ID, [](const Texture& obj) {return obj.ID(); });\n            Check(idx != -1, \"%s image with ID %llu was not found.\", type, ID);\n\n            tableOffset = table.Add(ZetaMove(ddsImages[idx]));\n\n            // HACK Since the texture was moved, ID was changed to -1. Add a dummy texture with the same ID\n            // so that binary search continues to work.\n            ddsImages[idx] = Texture(ID, nullptr, RESOURCE_HEAP_TYPE::COMMITTED);\n        };\n\n    if (lock)\n        AcquireSRWLockExclusive(&m_matLock);\n\n    {\n        uint32_t tableOffset = Material::INVALID_ID;    // i.e. index in GPU descriptor table\n\n        if (matDesc.BaseColorTexID != Texture::INVALID_ID)\n        {\n            addTex(matDesc.BaseColorTexID, \"BaseColor\", m_baseColorDescTable, tableOffset, ddsImages);\n            mat.SetBaseColorTex(tableOffset);\n        }\n    }\n\n    {\n        uint32_t tableOffset = Material::INVALID_ID;\n        if (matDesc.NormalTexID != Texture::INVALID_ID)\n        {\n            addTex(matDesc.NormalTexID, \"NormalMap\", m_normalDescTable, tableOffset, ddsImages);\n            mat.SetNormalTex(tableOffset);\n        }\n    }\n\n    {\n        uint32_t tableOffset = Material::INVALID_ID;\n        if (matDesc.MetallicRoughnessTexID != Texture::INVALID_ID)\n        {\n            addTex(matDesc.MetallicRoughnessTexID, \"MetallicRoughnessMap\",\n                m_metallicRoughnessDescTable, tableOffset, ddsImages);\n\n            mat.SetMetallicRoughnessTex(tableOffset);\n        }\n    }\n\n    {\n        uint32_t tableOffset = Material::INVALID_ID;\n        if (matDesc.EmissiveTexID != Texture::INVALID_ID)\n        {\n            addTex(matDesc.EmissiveTexID, \"EmissiveMap\", m_emissiveDescTable, tableOffset, ddsImages);\n            mat.SetEmissiveTex(tableOffset);\n        }\n    }\n\n    // Add this material to GPU material buffer. Contained texture indices offset into \n    // descriptor tables above.\n    m_matBuffer.Add(matDesc.ID, mat);\n\n    if (lock)\n        ReleaseSRWLockExclusive(&m_matLock);\n}\n\nvoid SceneCore::UpdateMaterial(uint32 ID, const Material& newMat)\n{\n    m_matBuffer.Update(ID, newMat);\n    m_rendererInterface.SceneModified();\n}\n\nvoid SceneCore::ResizeAdditionalMaterials(uint32_t num)\n{\n    m_matBuffer.ResizeAdditionalMaterials(num);\n}\n\nvoid SceneCore::AddInstance(Asset::InstanceDesc& instance, bool lock)\n{\n    const uint64_t meshID = instance.MeshIdx == -1 ? INVALID_MESH :\n        MeshID(instance.SceneID, instance.MeshIdx, instance.MeshPrimIdx);\n\n    if (lock)\n        AcquireSRWLockExclusive(&m_instanceLock);\n\n    if (meshID != INVALID_MESH)\n    {\n        m_meshBufferStale = true;\n\n        if (instance.RtMeshMode == RT_MESH_MODE::STATIC)\n        {\n            m_numStaticInstances++;\n            m_numOpaqueInstances += instance.IsOpaque;\n            m_numNonOpaqueInstances += !instance.IsOpaque;\n        }\n        else\n            m_numDynamicInstances++;\n    }\n\n    uint32_t treeLevel = 1;\n    uint32_t parentIdx = 0;\n\n    // Get parent's index from the hashmap\n    if (instance.ParentID != ROOT_ID)\n    {\n        const TreePos& p = FindTreePosFromID(instance.ParentID).value();\n\n        treeLevel = p.Level + 1;\n        parentIdx = p.Offset;\n    }\n\n    const uint32_t insertIdx = InsertAtLevel(instance.ID, treeLevel, parentIdx, instance.LocalTransform, meshID,\n        instance.RtMeshMode, instance.RtInstanceMask, instance.IsOpaque);\n\n    // Update instance \"dictionary\"\n    {\n        Assert(!m_IDtoTreePos.find(instance.ID), \"instance with id %llu already exists.\", instance.ID);\n        m_IDtoTreePos.insert_or_assign(instance.ID, TreePos{ .Level = treeLevel, .Offset = insertIdx });\n\n        // Adjust tree positions of shifted instances\n        for (size_t i = insertIdx + 1; i < m_sceneGraph[treeLevel].m_IDs.size(); i++)\n        {\n            uint64_t insID = m_sceneGraph[treeLevel].m_IDs[i];\n            auto pos = m_IDtoTreePos.find(insID);\n\n            // Shift tree position to right\n            pos.value()->Offset++;\n        }\n    }\n\n    m_rebuildBVHFlag = true;\n\n    if (lock)\n        ReleaseSRWLockExclusive(&m_instanceLock);\n}\n\nuint32_t SceneCore::InsertAtLevel(uint64_t id, uint32_t treeLevel, uint32_t parentIdx, \n    AffineTransformation& localTransform, uint64_t meshID, RT_MESH_MODE rtMeshMode, \n    uint8_t rtInstanceMask, bool isOpaque)\n{\n    Assert(m_sceneGraph.size() > treeLevel, \"Scene graph hasn't been preallocated.\");\n    //m_sceneGraph.resize(Max(treeLevel + 1, (uint32_t)m_sceneGraph.size()));\n\n    //while (m_sceneGraph.size() <= treeLevel)\n    //    m_sceneGraph.emplace_back(TreeLevel());\n\n    auto& parentLevel = m_sceneGraph[treeLevel - 1];\n    auto& currLevel = m_sceneGraph[treeLevel];\n    auto& parentRange = parentLevel.m_subtreeRanges[parentIdx];\n\n    // Insert position is right next to parent's rightmost child\n    const uint32_t insertIdx = parentRange.Base + parentRange.Count;\n\n    // Increment parent's #children\n    parentRange.Count++;\n\n    auto rearrange = []<typename T, typename... Args> requires std::is_trivially_copyable_v<T>\n        (Vector<T>& vec, uint32_t insertIdx, Args&&... args)\n    {\n        const size_t numToMove = vec.size() - insertIdx;\n\n        // Resize for one additional entry\n        vec.resize(vec.size() + 1);\n        // Shift existing elements with index >= insertIdx to right by one\n        if (numToMove)\n            memmove(vec.data() + insertIdx + 1, vec.data() + insertIdx, numToMove * sizeof(T));\n\n        // Construct the new entry in-place\n        new (vec.data() + insertIdx) T(ZetaForward(args)...);\n    };\n\n    float4x3 I = float4x3(store(identity()));\n\n    Assert(insertIdx <= currLevel.m_IDs.size(), \"Out-of-bounds insertion index.\");\n    Assert(currLevel.m_IDs.capacity() >= currLevel.m_IDs.size() + 1, \"Scene graph hasn't been preallocated.\");\n    rearrange(currLevel.m_IDs, insertIdx, id);\n    rearrange(currLevel.m_localTransforms, insertIdx, localTransform);\n    rearrange(currLevel.m_toWorlds, insertIdx, I);\n    rearrange(currLevel.m_meshIDs, insertIdx, meshID);\n    const uint32_t newBase = currLevel.m_subtreeRanges.empty() ? 0 :\n        currLevel.m_subtreeRanges.back().Base + currLevel.m_subtreeRanges.back().Count;\n    rearrange(currLevel.m_subtreeRanges, insertIdx, newBase, 0);\n    // Set rebuild flag to true when there's new any instance\n    auto flags = RT_Flags::Encode(rtMeshMode, rtInstanceMask, 1, 0, isOpaque);\n    rearrange(currLevel.m_rtFlags, insertIdx, flags);\n    rearrange(currLevel.m_rtASInfo, insertIdx, RT_AS_Info());\n\n    // Shift base offset of parent's right siblings to right by one\n    for (size_t siblingIdx = parentIdx + 1; siblingIdx != parentLevel.m_subtreeRanges.size(); siblingIdx++)\n        parentLevel.m_subtreeRanges[siblingIdx].Base++;\n\n    return insertIdx;\n}\n\nvoid SceneCore::ResetRtAsInfos()\n{\n    // Following must exactly match the iteration order of StaticBLAS::Rebuild().\n    uint32_t currInstance = 0;\n\n    for (size_t treeLevelIdx = 1; treeLevelIdx < m_sceneGraph.size(); treeLevelIdx++)\n    {\n        auto& currTreeLevel = m_sceneGraph[treeLevelIdx];\n\n        for (size_t i = 0; i < currTreeLevel.m_rtFlags.size(); i++)\n        {\n            const Scene::RT_Flags flags = RT_Flags::Decode(currTreeLevel.m_rtFlags[i]);\n\n            if (flags.MeshMode == RT_MESH_MODE::STATIC)\n            {\n                const uint64_t meshID = currTreeLevel.m_meshIDs[i];\n                if (meshID == Scene::INVALID_MESH)\n                    continue;\n\n                currTreeLevel.m_rtASInfo[i] = RT_AS_Info{\n                    .GeometryIndex = currInstance,\n                    .InstanceID = 0 };\n\n                currInstance++;\n            }\n        }\n    }\n\n    if (m_numDynamicInstances == 0)\n        return;\n\n    currInstance = 0;\n\n    for (size_t treeLevelIdx = 1; treeLevelIdx < m_sceneGraph.size(); treeLevelIdx++)\n    {\n        auto& currTreeLevel = m_sceneGraph[treeLevelIdx];\n        auto& rtFlagVec = currTreeLevel.m_rtFlags;\n\n        for (size_t i = 0; i < rtFlagVec.size(); i++)\n        {\n            const Scene::RT_Flags flags = RT_Flags::Decode(currTreeLevel.m_rtFlags[i]);\n\n            if (flags.MeshMode != RT_MESH_MODE::STATIC)\n            {\n                const uint64_t meshID = currTreeLevel.m_meshIDs[i];\n                if (meshID == Scene::INVALID_MESH)\n                    continue;\n\n                currTreeLevel.m_rtASInfo[i] = RT_AS_Info{\n                    .GeometryIndex = 0,\n                    .InstanceID = m_numStaticInstances + currInstance };\n\n                currInstance++;\n            }\n        }\n    }\n}\n\nvoid SceneCore::AddAnimation(uint64_t id, MutableSpan<Keyframe> keyframes, float t_start, \n    bool loop, bool isSorted)\n{\n#ifndef NDEBUG\n    TreePos& p = FindTreePosFromID(id).value();\n    Assert(RT_Flags::Decode(m_sceneGraph[p.Level].m_rtFlags[p.Offset]).MeshMode != RT_MESH_MODE::STATIC,\n        \"Static instances can't be animated.\");\n#endif\n\n    Check(keyframes.size() > 1, \"Invalid animation.\");\n\n    if (!isSorted)\n    {\n        std::sort(m_keyframes.begin(), m_keyframes.end(),\n            [](const Keyframe& k1, const Keyframe& k2)\n            {\n                return k1.Time < k2.Time;\n            });\n    }\n\n    // Remember starting offset and number of keyframes\n    const uint32_t currOffset = (uint32_t)m_keyframes.size();\n    m_animationMetadata.push_back(AnimationMetadata{\n            .InstanceID = id,\n            .StartOffset = currOffset,\n            .Length = (uint32_t)keyframes.size(),\n            .T0 = t_start,\n            .Loop = loop\n        });\n\n    m_keyframes.append_range(keyframes.begin(), keyframes.end());\n}\n\nvoid SceneCore::TransformInstance(uint64_t id, const float3& tr, const float3x3& rotation,\n    const float3& scale)\n{\n    m_tempWorldTransformUpdates[id] = TransformUpdate{ .Tr = tr, .Rotation = rotation, .Scale = scale };\n\n    const auto treePos = FindTreePosFromID(id).value();\n    const auto rtFlags = RT_Flags::Decode(m_sceneGraph[treePos.Level].m_rtFlags[treePos.Offset]);\n\n    m_staleEmissivePositions = m_staleEmissivePositions || \n        (m_emissives.NumInstances() &&\n        (rtFlags.InstanceMask & RT_AS_SUBGROUP::EMISSIVE));\n\n    ConvertInstanceDynamic(id, treePos, rtFlags);\n    // Updates if instance already exists\n    m_instanceUpdates[id] = App::GetTimer().GetTotalFrameCount();\n\n    m_rendererInterface.SceneModified();\n}\n\nvoid SceneCore::ReserveInstances(Span<int> treeLevels, size_t total)\n{\n    Assert(treeLevels.size() > 0, \"Invalid tree.\");\n\n    // +1 for root\n    m_sceneGraph.resize(treeLevels.size() + 1);\n    for (size_t i = 0; i < treeLevels.size(); i++)\n    {\n        m_sceneGraph[i + 1].m_IDs.reserve(treeLevels[i]);\n        m_sceneGraph[i + 1].m_localTransforms.reserve(treeLevels[i]);\n        m_sceneGraph[i + 1].m_meshIDs.reserve(treeLevels[i]);\n        m_sceneGraph[i + 1].m_rtASInfo.reserve(treeLevels[i]);\n        m_sceneGraph[i + 1].m_rtFlags.reserve(treeLevels[i]);\n        m_sceneGraph[i + 1].m_subtreeRanges.reserve(treeLevels[i]);\n        m_sceneGraph[i + 1].m_toWorlds.reserve(treeLevels[i]);\n    }\n\n    m_prevToWorlds.resize(total, true);\n    m_IDtoTreePos.resize(total, true);\n    m_worldTransformUpdates.resize(Min(total, 32llu));\n}\n\nvoid SceneCore::AddEmissives(Util::SmallVector<Asset::EmissiveInstance>&& emissiveInstances,\n    SmallVector<RT::EmissiveTriangle>&& emissiveTris, bool lock)\n{\n    if (emissiveTris.empty())\n        return;\n\n    if(lock)\n        AcquireSRWLockExclusive(&m_emissiveLock);\n    \n    m_emissives.AddBatch(ZetaMove(emissiveInstances), ZetaMove(emissiveTris));\n\n    if(lock)\n        ReleaseSRWLockExclusive(&m_emissiveLock);\n}\n\nvoid SceneCore::UpdateEmissiveMaterial(uint64_t instanceID, const float3& emissiveFactor, float strength)\n{\n    m_emissives.UpdateMaterial(instanceID, emissiveFactor, strength);\n    m_rendererInterface.SceneModified();\n}\n\nvoid SceneCore::ToggleEmissivesCallback(const Support::ParamVariant& p)\n{\n    m_ignoreEmissives = !p.GetBool();\n    m_rendererInterface.SceneModified();\n    m_rendererInterface.ToggleEmissives();\n}\n\nvoid SceneCore::InitWorldTransformations()\n{\n    const float4x3 I = float4x3(store(identity()));\n\n    // No parent transformation for first level\n    for (size_t i = 0; i < m_sceneGraph[1].m_localTransforms.size(); i++)\n    {\n        AffineTransformation& tr = m_sceneGraph[1].m_localTransforms[i];\n        v_float4x4 vLocal = affineTransformation(tr.Scale, tr.Rotation, tr.Translation);\n        const uint64_t ID = m_sceneGraph[1].m_IDs[i];\n\n        // Set prev = new for 1st frame\n        m_sceneGraph[1].m_toWorlds[i] = float4x3(store(vLocal));\n        m_prevToWorlds[ID] = m_sceneGraph[1].m_toWorlds[i];\n    }\n\n    const size_t numLevels = m_sceneGraph.size();\n\n    for (size_t level = 1; level < numLevels - 1; ++level)\n    {\n        for (size_t i = 0; i < m_sceneGraph[level].m_subtreeRanges.size(); i++)\n        {\n            const v_float4x4 vParentTr = load4x3(m_sceneGraph[level].m_toWorlds[i]);\n            const float4x3 P = float4x3(store(vParentTr));\n            const auto& range = m_sceneGraph[level].m_subtreeRanges[i];\n\n            for (size_t j = range.Base; j < range.Base + range.Count; j++)\n            {\n                AffineTransformation& tr = m_sceneGraph[level + 1].m_localTransforms[j];\n                v_float4x4 vLocal = affineTransformation(tr.Scale, tr.Rotation, tr.Translation);\n                // Bottom up transformation hierarchy\n                v_float4x4 newW = mul(vLocal, vParentTr);\n                const uint64_t ID = m_sceneGraph[level + 1].m_IDs[j];\n\n                // Set prev = new for 1st frame\n                m_sceneGraph[level + 1].m_toWorlds[j] = float4x3(store(newW));\n                m_prevToWorlds[ID] = m_sceneGraph[level + 1].m_toWorlds[j];\n            }\n        }\n    }\n}\n\nvoid SceneCore::UpdateWorldTransformations(Vector<BVH::BVHUpdateInput, App::FrameAllocator>& toUpdateInstances)\n{\n    struct Entry\n    {\n        v_float4x4 W;\n        uint32_t TreeLevel;\n        uint32_t Base;\n        uint32_t Count;\n    };\n\n    SmallVector<Entry, App::FrameAllocator, 10> stack;\n    const auto currFrame = App::GetTimer().GetTotalFrameCount();\n\n    // Can't append while iterating\n    SmallVector<uint64, App::FrameAllocator, 3> toAppend;\n\n    for (auto it = m_instanceUpdates.begin_it(); it != m_instanceUpdates.end_it(); \n        it = m_instanceUpdates.next_it(it))\n    {\n        const auto instance = it->Key;\n        const auto frame = it->Val;\n        const TreePos& p = FindTreePosFromID(instance).value();\n\n        // -1 -> update was added at the tail end of last frame\n        if (frame < currFrame - 1)\n        {\n            // Mesh hasn't moved, just update previous transformation\n            m_prevToWorlds[instance] = m_sceneGraph[p.Level].m_toWorlds[p.Offset];\n            continue;\n        }\n\n        // Grab current to world transformation\n        const float4x3& prevW = m_sceneGraph[p.Level].m_toWorlds[p.Offset];\n        v_float4x4 vW = load4x3(prevW);\n\n        float4a t;\n        float4a r;\n        float4a s;\n        decomposeSRT(vW, s, r, t);\n\n        // Apply the update\n        auto& delta = m_tempWorldTransformUpdates[instance];\n        float3 newTr = delta.Tr + t.xyz();\n        float3 newScale = delta.Scale * s.xyz();\n\n        v_float4x4 vR = rotationMatFromQuat(load(r));\n        v_float4x4 vNewR = load3x3(delta.Rotation);\n        vR = mul(vR, vNewR);\n\n        v_float4x4 vNewWorld = affineTransformation(vR, newScale, newTr);\n\n        float3x3 R = float3x3(store(vNewR));\n        Assert(fabsf(R.m[0].length() - 1) < 1e-5, \"\");\n        Assert(fabsf(R.m[1].length() - 1) < 1e-5, \"\");\n        Assert(fabsf(R.m[2].length() - 1) < 1e-5, \"\");\n\n        // Update previous & current transformations\n        m_prevToWorlds[instance] = prevW;\n        m_sceneGraph[p.Level].m_toWorlds[p.Offset] = float4x3(store(vNewWorld));\n        \n        // Add subtree to stack\n        if (const auto range = m_sceneGraph[p.Level].m_subtreeRanges[p.Offset]; range.Count)\n        {\n            stack.push_back(Entry{ .W = vNewWorld,\n                .TreeLevel = p.Level, \n                .Base = range.Base, \n                .Count = range.Count });\n        }\n\n        // Remember transformation update for future\n        if (auto existingIt = m_worldTransformUpdates.find(instance); existingIt)\n        {\n            auto& curr = *existingIt.value();\n            curr.Translation += delta.Tr;\n            curr.Scale *= delta.Scale;\n\n            v_float4x4 vCurrR = rotationMatFromQuat(loadFloat4(curr.Rotation));\n            vCurrR = mul(vCurrR, vNewR);\n            curr.Rotation = quaternionFromRotationMat1(vCurrR);\n        }\n        else\n        {\n            AffineTransformation tr;\n            tr.Translation = delta.Tr;\n            tr.Scale = delta.Scale;\n            tr.Rotation = quaternionFromRotationMat1(vNewR);\n\n            m_worldTransformUpdates[instance] = tr;\n        }\n    }\n\n    while (!stack.empty())\n    {\n        Entry e = stack.back();\n        stack.pop_back();\n        auto& currLevel = m_sceneGraph[e.TreeLevel + 1];\n\n        for (size_t j = e.Base; j < e.Base + e.Count; j++)\n        {\n            Assert(RT_Flags::Decode(currLevel.m_rtFlags[j]).MeshMode ==\n                RT_MESH_MODE::DYNAMIC_NO_REBUILD, \"Invalid scene graph.\");\n\n            const uint64_t ID = m_sceneGraph[e.TreeLevel + 1].m_IDs[j];\n            toAppend.push_back(ID);\n\n            AffineTransformation& local = currLevel.m_localTransforms[j];\n            v_float4x4 vLocal = affineTransformation(local.Scale, local.Rotation, local.Translation);\n            v_float4x4 vNewWorld = mul(vLocal, e.W);\n\n            // If instance has had updates, apply them\n            if (auto updateIt = m_worldTransformUpdates.find(ID); updateIt)\n            {\n                float4a t;\n                float4a s;\n                v_float4x4 vR = decomposeSRT(vNewWorld, s, t);\n\n                AffineTransformation& existing = *updateIt.value();\n                float3 newTr = existing.Translation + t.xyz();\n                float3 newScale = existing.Scale * s.xyz();\n\n                v_float4x4 vRotUpdate = rotationMatFromQuat(loadFloat4(existing.Rotation));\n                vR = mul(vR, vRotUpdate);\n\n                vNewWorld = affineTransformation(vR, newScale, newTr);\n            }\n\n            // Update previous & current transformations\n            m_prevToWorlds[ID] = currLevel.m_toWorlds[j];\n            currLevel.m_toWorlds[j] = float4x3(store(vNewWorld));\n\n            // Add subtree to stack\n            if (const auto& subtree = currLevel.m_subtreeRanges[j]; subtree.Count)\n            {\n                stack.push_back(Entry{ .W = vNewWorld,\n                    .TreeLevel = e.TreeLevel + 2,\n                    .Base = subtree.Base,\n                    .Count = subtree.Count });\n            }\n        }\n    }\n\n    m_tempWorldTransformUpdates.clear();\n    \n    for(auto id : toAppend)\n        m_instanceUpdates[id] = App::GetTimer().GetTotalFrameCount() - 1;\n}\n\nvoid SceneCore::UpdateEmissivePositions()\n{\n    auto tris = m_emissives.Triagnles();\n    auto triInitialPos = m_emissives.InitialTriPositions();\n\n    uint32_t minIdx = (uint32_t)tris.size() - 1;\n    uint32_t maxIdx = 0;\n\n    for (auto it = m_instanceUpdates.begin_it(); it != m_instanceUpdates.end_it();\n        it = m_instanceUpdates.next_it(it))\n    {\n        auto instance = it->Key;\n        const auto& emissiveInstance = *m_emissives.FindInstance(instance).value();\n        const v_float4x4 vW = load4x3(GetToWorld(instance));\n        const auto rtASInfo = GetInstanceRtASInfo(instance);\n\n        for (size_t t = emissiveInstance.BaseTriOffset; \n            t < emissiveInstance.BaseTriOffset + emissiveInstance.NumTriangles; t++)\n        {\n            EmissiveBuffer::Triangle& initTri = triInitialPos[t];\n\n            __m128 vV0;\n            __m128 vV1;\n            __m128 vV2;\n            RT::EmissiveTriangle::DecodeVertices(initTri.Vtx0, initTri.V0V1, initTri.V0V2,\n                initTri.EdgeLengths,\n                vV0, vV1, vV2);\n\n            vV0 = mul(vW, vV0);\n            vV1 = mul(vW, vV1);\n            vV2 = mul(vW, vV2);\n            tris[t].StoreVertices(vV0, vV1, vV2);\n\n            // Dynamic instances have geometry index = 0\n            const uint32_t hash = Pcg3d(uint3(0,\n                rtASInfo.InstanceID,\n                initTri.PrimIdx)).x;\n            tris[t].ID = hash;\n        }\n\n        minIdx = Min(minIdx, emissiveInstance.BaseTriOffset);\n        maxIdx = Max(maxIdx, emissiveInstance.BaseTriOffset + emissiveInstance.NumTriangles);\n    }\n\n    Assert(minIdx <= maxIdx, \"Invalid indices.\");\n    m_emissives.UpdateTriPositions(minIdx, maxIdx);\n}\n\nvoid SceneCore::UpdateAnimations(float t, Vector<AnimationUpdate, App::FrameAllocator>& animVec)\n{\n    for (auto& anim : m_animationMetadata)\n    {\n        AffineTransformation vRes;\n\n        const Keyframe& kStart = m_keyframes[anim.StartOffset];\n        const Keyframe& kEnd = m_keyframes[anim.StartOffset + anim.Length - 1];\n        const float t_start = anim.T0;\n\n        // Fast paths\n        if (t <= kStart.Time + t_start)\n        {\n            vRes = kStart.Transform;\n        }\n        else if (!anim.Loop && t >= kEnd.Time + t_start)\n        {\n            vRes = kEnd.Transform;\n        }\n        else\n        {\n            if (t >= kEnd.Time + t_start)\n            {\n                float numLoops = floorf((t - kStart.Time) / (kEnd.Time - kStart.Time));\n                float excess = numLoops * (kEnd.Time - kStart.Time) + kStart.Time;\n                t -= excess;\n                t += kStart.Time;\n            }\n\n            auto idx = FindInterval(Span(m_keyframes), t, [](const Keyframe& k) { return k.Time; },\n                anim.StartOffset,\n                anim.StartOffset + anim.Length - 1);\n\n            Assert(idx != -1, \"FindInterval() unexpectedly failed.\");\n            Keyframe& k1 = m_keyframes[idx];\n            Keyframe& k2 = m_keyframes[idx + 1];\n\n            Assert(t >= k1.Time + t_start && t <= k2.Time + t_start, \"bug\");\n            Assert(k1.Time < k2.Time, \"divide-by-zero\");\n\n            float interpolatedT = (t - (k1.Time + t_start)) / (k2.Time - k1.Time);\n\n            // Scale\n            const __m128 vScale1 = loadFloat3(k1.Transform.Scale);\n            const __m128 vScale2 = loadFloat3(k2.Transform.Scale);\n            const __m128 vScaleInt = lerp(vScale1, vScale2, interpolatedT);\n\n            // Translation\n            const __m128 vTranslate1 = loadFloat3(k1.Transform.Translation);\n            const __m128 vTranslate2 = loadFloat3(k2.Transform.Translation);\n            const __m128 vTranslateInt = lerp(vTranslate1, vTranslate2, interpolatedT);\n\n            // Rotation\n            const __m128 vRot1 = loadFloat4(k1.Transform.Rotation);\n            const __m128 vRot2 = loadFloat4(k2.Transform.Rotation);\n            const __m128 vRotInt = slerp(vRot1, vRot2, interpolatedT);\n\n            vRes.Scale = storeFloat3(vScaleInt);\n            vRes.Rotation = storeFloat4(vRotInt);\n            vRes.Translation = storeFloat3(vTranslateInt);\n        }\n\n        animVec.push_back(AnimationUpdate{\n            .M = vRes,\n            .InstanceID = anim.InstanceID });\n    }\n}\n\nvoid SceneCore::UpdateLocalTransforms(Span<AnimationUpdate> animVec)\n{\n    for (auto& update : animVec)\n    {\n        TreePos t = FindTreePosFromID(update.InstanceID).value();\n        m_sceneGraph[t.Level].m_localTransforms[t.Offset] = update.M;\n    }\n}\n\nbool SceneCore::ConvertInstanceDynamic(uint64_t instanceID, const TreePos& treePos, \n    RT_Flags rtFlags)\n{\n    if (rtFlags.MeshMode == RT_MESH_MODE::STATIC)\n    {\n        m_sceneGraph[treePos.Level].m_rtFlags[treePos.Offset] = RT_Flags::Encode(\n            RT_MESH_MODE::DYNAMIC_NO_REBUILD,\n            rtFlags.InstanceMask, 1, 0, rtFlags.IsOpaque);\n\n        m_pendingRtMeshModeSwitch.push_back(instanceID);\n        m_numStaticInstances--;\n        m_numDynamicInstances++;\n\n        auto subtree = m_sceneGraph[treePos.Level].m_subtreeRanges[treePos.Offset];\n        if (subtree.Count)\n            ConvertSubtreeDynamic(treePos.Level + 1, subtree);\n\n        return true;\n    }\n\n    return false;\n}\n\nvoid SceneCore::ConvertSubtreeDynamic(uint32_t treeLevel, Range r)\n{\n    for (size_t i = r.Base; i < r.Base + r.Count; i++)\n    {\n        auto rtFlags = RT_Flags::Decode(m_sceneGraph[treeLevel].m_rtFlags[i]);\n        if (rtFlags.MeshMode != Model::RT_MESH_MODE::DYNAMIC_NO_REBUILD)\n        {\n            m_sceneGraph[treeLevel].m_rtFlags[i] = RT_Flags::Encode(\n                Model::RT_MESH_MODE::DYNAMIC_NO_REBUILD,\n                rtFlags.InstanceMask, 1, 0, rtFlags.IsOpaque);\n\n            m_pendingRtMeshModeSwitch.push_back(m_sceneGraph[treeLevel].m_IDs[i]);\n            m_numStaticInstances--;\n            m_numDynamicInstances++;\n        }\n\n        if (m_sceneGraph[treeLevel].m_subtreeRanges[i].Count > 0)\n            ConvertSubtreeDynamic(treeLevel + 1, m_sceneGraph[treeLevel].m_subtreeRanges[i]);\n    }\n}\n\nvoid SceneCore::AnimateCallback(const ParamVariant& p)\n{\n    m_animate = !p.GetBool();\n}\n\nvoid SceneCore::ClearPick()\n{\n    m_rendererInterface.ClearPick();\n\n    AcquireSRWLockExclusive(&m_pickLock);\n    m_pickedInstances.clear();\n    ReleaseSRWLockExclusive(&m_pickLock);\n}\n\nvoid SceneCore::SetPickedInstance(uint64 instanceID)\n{\n    AcquireSRWLockExclusive(&m_pickLock);\n\n    if (!m_multiPick)\n    {\n        m_pickedInstances.resize(1);\n        m_pickedInstances[0] = instanceID;\n    }\n    else\n    {\n        // NOTE usually there aren't more than a few objects picked\n        // at the same time, so linear search should be fine\n        bool found = false;\n        for (size_t i = 0; i < m_pickedInstances.size(); i++)\n        {\n            if (m_pickedInstances[i] == instanceID)\n            {\n                m_pickedInstances.erase_at_index(i);\n                found = true;\n                break;\n            }\n        }\n\n        if(!found)\n            m_pickedInstances.push_back(instanceID);\n    }\n\n    ReleaseSRWLockExclusive(&m_pickLock);\n}\n"
  },
  {
    "path": "Source/ZetaCore/Scene/SceneCore.h",
    "content": "#pragma once\n\n#include \"../Math/BVH.h\"\n#include \"Asset.h\"\n#include \"SceneRenderer.h\"\n#include \"SceneCommon.h\"\n#include \"../Utility/Utility.h\"\n#include \"../Utility/SynchronizedView.h\"\n#include <xxHash/xxhash.h>\n#include <atomic>\n\nnamespace ZetaRay::Model\n{\n    struct TriangleMesh;\n}\n\nnamespace ZetaRay::RT\n{\n    struct StaticBLAS;\n    struct TLAS;\n}\n\nnamespace ZetaRay::Support\n{\n    struct ParamVariant;\n}\n\nnamespace ZetaRay::Scene\n{\n    struct Keyframe\n    {\n        static Keyframe Identity()\n        {\n            Keyframe k;\n            k.Transform = Math::AffineTransformation::GetIdentity();\n\n            return k;\n        }\n\n        Math::AffineTransformation Transform;\n        float Time;\n    };\n\n    struct RT_Flags\n    {\n        static RT_Flags Decode(uint8_t f)\n        {\n            return RT_Flags{\n                .MeshMode = (Model::RT_MESH_MODE)(f >> 6),\n                .InstanceMask = (uint8_t)(f & 0x7),\n                .IsOpaque = bool((f >> 3) & 0x1),\n                .RebuildFlag = bool((f >> 4) & 0x1),\n                .UpdateFlag = bool((f >> 5) & 0x1) };\n        }\n\n        // 7        6     5         4       3     2     1     0\n        //  meshmode    update    build   opaque     instance\n        static uint8_t Encode(Model::RT_MESH_MODE m, uint8_t instanceMask, uint8_t rebuild,\n            uint8_t update, bool isOpaque)\n        {\n            return ((uint8_t)m << 6) | instanceMask | (isOpaque << 3) | (rebuild << 4) | (update << 5);\n        }\n\n        Model::RT_MESH_MODE MeshMode;\n        // Note: Instance masks are specified per instance here, but in DXR can \n        // only be applied per TLAS instance.\n        uint8_t InstanceMask;\n        bool IsOpaque;\n        bool RebuildFlag;\n        bool UpdateFlag;\n    };\n\n    struct RT_AS_Info\n    {\n        uint32_t GeometryIndex;\n        uint32_t InstanceID;\n    };\n\n    ZetaInline uint64_t InstanceID(uint32_t sceneID, int nodeIdx, int mesh, int meshPrim)\n    {\n        StackStr(str, n, \"instance_%u_%d_%d_%d\", sceneID, nodeIdx, mesh, meshPrim);\n        uint64_t instanceFromSceneID = XXH3_64bits(str, n);\n\n        return instanceFromSceneID;\n    }\n\n    ZetaInline uint32_t MaterialID(uint32_t sceneID, int matIdx)\n    {\n        StackStr(str, n, \"mesh_%u_%d\", sceneID, matIdx);\n        uint64_t meshFromSceneID = XXH3_64bits(str, n);\n\n        return Util::XXH3_64_To_32(meshFromSceneID);\n    }\n\n    ZetaInline uint64_t MeshID(uint32_t sceneID, int meshIdx, int meshPrimIdx)\n    {\n        StackStr(str, n, \"mesh_%u_%d_%d\", sceneID, meshIdx, meshPrimIdx);\n        uint64_t meshFromSceneID = XXH3_64bits(str, n);\n\n        return meshFromSceneID;\n    }\n}\n\nnamespace ZetaRay::Scene\n{\n    class SceneCore\n    {\n        friend struct RT::StaticBLAS;\n        friend struct RT::TLAS;\n\n    public:\n        static constexpr uint64_t ROOT_ID = UINT64_MAX;\n\n        SceneCore();\n        ~SceneCore() = default;\n\n        SceneCore(const SceneCore&) = delete;\n        SceneCore& operator=(const SceneCore&) = delete;\n\n        void Init(Renderer::Interface& rendererInterface);\n        void Pause() { m_isPaused = true; }\n        void Resume() { m_isPaused = false; }\n        void OnWindowSizeChanged();\n        void Shutdown();\n\n        void Update(double dt, Support::TaskSet& sceneTS, Support::TaskSet& sceneRendererTS);\n        void Render(Support::TaskSet& ts) { m_rendererInterface.Render(ts); };\n\n        //\n        // Mesh\n        //\n        uint32_t AddMesh(Util::SmallVector<Core::Vertex>&& vertices, Util::SmallVector<uint32_t>&& indices,\n            uint32_t matIdx, bool lock = true);\n        void AddMeshes(Util::SmallVector<Model::glTF::Asset::Mesh>&& meshes,\n            Util::SmallVector<Core::Vertex>&& vertices,\n            Util::SmallVector<uint32_t>&& indices,\n            bool lock = true);\n        ZetaInline Util::Optional<const Model::TriangleMesh*> GetMesh(uint64_t id) const\n        {\n            return m_meshes.GetMesh(id);\n        }\n        ZetaInline Util::Optional<const Model::TriangleMesh*> GetInstanceMesh(uint64_t id) const\n        {\n            const TreePos& p = FindTreePosFromID(id).value();\n            const uint64_t meshID = m_sceneGraph[p.Level].m_meshIDs[p.Offset];\n\n            return m_meshes.GetMesh(meshID);\n        }\n        ZetaInline const Core::GpuMemory::Buffer& GetMeshVB() { return m_meshes.GetVB(); }\n        ZetaInline const Core::GpuMemory::Buffer& GetMeshIB() { return m_meshes.GetIB(); }\n\n        //\n        // Material\n        //\n        void AddMaterial(const Model::glTF::Asset::MaterialDesc& mat, bool lock = true);\n        void AddMaterial(const Model::glTF::Asset::MaterialDesc& mat,\n            Util::MutableSpan<Core::GpuMemory::Texture> ddsImages, bool lock = true);\n        ZetaInline Util::Optional<const Material*> GetMaterial(uint32_t ID, uint32_t* bufferIdx = nullptr) const\n        {\n            return m_matBuffer.Get(ID, bufferIdx);\n        }\n        void UpdateMaterial(uint32 ID, const Material& newMat);\n        void ResizeAdditionalMaterials(uint32_t num);\n        ZetaInline void AddTextureHeap(Core::GpuMemory::ResourceHeap&& heap) { m_textureHeaps.push_back(ZetaForward(heap)); }\n\n        ZetaInline uint32_t GetBaseColMapsDescHeapOffset() const { return m_baseColorDescTable.GPUDescriptorHeapIndex(); }\n        ZetaInline uint32_t GetNormalMapsDescHeapOffset() const { return m_normalDescTable.GPUDescriptorHeapIndex(); }\n        ZetaInline uint32_t GetMetallicRougnessMapsDescHeapOffset() const { return m_metallicRoughnessDescTable.GPUDescriptorHeapIndex(); }\n        ZetaInline uint32_t GetEmissiveMapsDescHeapOffset() const { return m_emissiveDescTable.GPUDescriptorHeapIndex(); }\n\n        //\n        // Instance\n        //\n        void AddInstance(Model::glTF::Asset::InstanceDesc& instance, bool lock = true);\n        ZetaInline Util::Optional<const Math::float4x3*> GetPrevToWorld(uint64_t id) const\n        {\n            auto it = m_prevToWorlds.find(id);\n            if (it)\n                return it.value();\n\n            return {};\n        }\n        ZetaInline const Math::float4x3& GetToWorld(uint64_t id) const\n        {\n            const TreePos& p = FindTreePosFromID(id).value();\n            return m_sceneGraph[p.Level].m_toWorlds[p.Offset];\n        }\n        ZetaInline Math::AffineTransformation GetLocalTransform(uint64_t id) const\n        {\n            auto it = m_worldTransformUpdates.find(id);\n            if (it)\n                return *it.value();\n\n            return Math::AffineTransformation::GetIdentity();\n        }\n        ZetaInline const Math::AABB& GetAABB(uint64_t id) const\n        {\n            const TreePos& p = FindTreePosFromID(id).value();\n            const uint64_t meshID = m_sceneGraph[p.Level].m_meshIDs[p.Offset];\n            return m_meshes.GetMesh(meshID).value()->m_AABB;\n        }\n        ZetaInline uint64_t GetInstanceMeshID(uint64_t id) const\n        {\n            const TreePos& p = FindTreePosFromID(id).value();\n            return m_sceneGraph[p.Level].m_meshIDs[p.Offset];\n        }\n        ZetaInline RT_AS_Info GetInstanceRtASInfo(uint64_t id) const\n        {\n            const TreePos& p = FindTreePosFromID(id).value();\n            return m_sceneGraph[p.Level].m_rtASInfo[p.Offset];\n        }\n        ZetaInline RT_Flags GetInstanceRtFlags(uint64_t id) const\n        {\n            const TreePos& p = FindTreePosFromID(id).value();\n            return RT_Flags::Decode(m_sceneGraph[p.Level].m_rtFlags[p.Offset]);\n        }\n        ZetaInline uint64_t GetIDFromRtMeshIdx(uint32 idx) const\n        {\n            return m_rtMeshInstanceIdxToID[idx];\n        }\n        void TransformInstance(uint64_t id, const Math::float3& tr, const Math::float3x3& rotation,\n            const Math::float3& scale);\n        void ReserveInstances(Util::Span<int> treeLevels, size_t total);\n\n        //\n        // Emissive\n        //\n        void AddEmissives(Util::SmallVector<Model::glTF::Asset::EmissiveInstance>&& emissiveInstances,\n            Util::SmallVector<RT::EmissiveTriangle>&& emissiveTris, bool lock);\n        ZetaInline bool EmissiveLighting() const { return !m_ignoreEmissives && (m_emissives.NumInstances() > 0); }\n        ZetaInline size_t NumEmissiveInstances() const { return m_emissives.NumInstances(); }\n        ZetaInline size_t NumEmissiveTriangles() const { return m_emissives.NumTriangles(); }\n        ZetaInline bool AreEmissivePositionsStale() const { return m_staleEmissivePositions; }\n        ZetaInline bool AreEmissiveMaterialsStale() const { return m_staleEmissiveMats; }\n        void UpdateEmissiveMaterial(uint64_t instanceID, const Math::float3& emissiveFactor, float strength);\n        void ToggleEmissivesCallback(const Support::ParamVariant& p);\n\n        //\n        // Animation\n        //\n        void AddAnimation(uint64_t id, Util::MutableSpan<Keyframe> keyframes, float t_start,\n            bool loop = true, bool isSorted = true);\n        void AnimateCallback(const Support::ParamVariant& p);\n\n        //\n        // Misc\n        //\n        //ZetaInline Math::AABB GetWorldAABB() { return m_bvh.GetWorldAABB(); }\n        ZetaInline uint32_t TotalNumTriangles() const { return m_numTriangles; }\n        ZetaInline uint32_t TotalNumInstances() const { return (uint32_t)m_IDtoTreePos.size(); }\n        ZetaInline uint32_t TotalNumMeshes() const { return m_meshes.NumMeshes(); }\n        ZetaInline uint32_t TotalNumMaterials() const { return m_matBuffer.NumMaterials(); }\n        ZetaInline uint32_t NumOpaqueInstances() const { return m_numOpaqueInstances; }\n        ZetaInline uint32_t NumNonOpaqueInstances() const { return m_numNonOpaqueInstances; }\n        ZetaInline Core::RenderGraph* GetRenderGraph() { return m_rendererInterface.GetRenderGraph(); }\n        ZetaInline void SceneModified() { m_rendererInterface.SceneModified(); }\n        ZetaInline void DebugDrawRenderGraph() { m_rendererInterface.DebugDrawRenderGraph(); }\n\n        //\n        // Picking\n        //\n        ZetaInline void Pick(uint16 screenPosX, uint16 screenPosY) \n        { \n            m_multiPick = false;\n            m_rendererInterface.Pick(screenPosX, screenPosY); \n        }\n        ZetaInline void MultiPick(uint16 screenPosX, uint16 screenPosY) \n        { \n            m_multiPick = true;\n            m_rendererInterface.Pick(screenPosX, screenPosY); \n        }\n        void ClearPick();\n        void SetPickedInstance(uint64 instanceID);\n        ZetaInline Util::SynchronizedSpan<uint64_t> GetPickedInstances()\n        { \n            return Util::SynchronizedSpan<uint64_t>(m_pickedInstances, m_pickLock);\n        }\n        ZetaInline void CaptureScreen() { m_rendererInterface.CaptureScreen(); }\n\n    private:\n        static constexpr uint32_t BASE_COLOR_DESC_TABLE_SIZE = 256;\n        static constexpr uint32_t NORMAL_DESC_TABLE_SIZE = 256;\n        static constexpr uint32_t METALLIC_ROUGHNESS_DESC_TABLE_SIZE = 256;\n        static constexpr uint32_t EMISSIVE_DESC_TABLE_SIZE = 64;\n\n        struct TreePos\n        {\n            uint32_t Level;\n            uint32_t Offset;\n        };\n\n        struct AnimationUpdate\n        {\n            Math::AffineTransformation M;\n            uint64_t InstanceID;\n        };\n\n        struct Range\n        {\n            Range() = default;\n            Range(uint32_t b, uint32_t c)\n                : Base(b),\n                Count(c)\n            {}\n\n            uint32_t Base;\n            uint32_t Count;\n        };\n\n        struct TreeLevel\n        {\n            Util::SmallVector<uint64_t> m_IDs;\n            Util::SmallVector<Math::AffineTransformation> m_localTransforms;\n            Util::SmallVector<Math::float4x3> m_toWorlds;\n            Util::SmallVector<uint64_t> m_meshIDs;\n            Util::SmallVector<Range> m_subtreeRanges;\n            Util::SmallVector<uint8_t> m_rtFlags;\n            // (Also) filled in by TLAS::RebuildTLASInstances()\n            Util::SmallVector<RT_AS_Info> m_rtASInfo;\n        };\n\n        // Offset into \"m_keyframes\" array\n        struct AnimationMetadata\n        {\n            uint64_t InstanceID;\n            uint32_t StartOffset;\n            uint32_t Length;\n            float T0;\n            bool Loop;\n        };\n\n        ZetaInline Util::Optional<TreePos> FindTreePosFromID(uint64_t id) const\n        {\n            auto pos = m_IDtoTreePos.find(id);\n            if (pos)\n                return *pos.value();\n\n            return {};\n        }\n\n        uint32_t InsertAtLevel(uint64_t id, uint32_t treeLevel, uint32_t parentIdx, \n            Math::AffineTransformation& localTransform, uint64_t meshID, \n            Model::RT_MESH_MODE rtMeshMode, uint8_t rtInstanceMask, bool isOpaque);\n        void ResetRtAsInfos();\n        void InitWorldTransformations();\n        void UpdateWorldTransformations(Util::Vector<Math::BVH::BVHUpdateInput, \n            App::FrameAllocator>& toUpdateInstances);\n        void UpdateEmissivePositions();\n        void RebuildBVH();\n        void UpdateAnimations(float t, Util::Vector<AnimationUpdate, App::FrameAllocator>& animVec);\n        void UpdateLocalTransforms(Util::Span<AnimationUpdate> animVec);\n        bool ConvertInstanceDynamic(uint64_t instanceID, const TreePos& treePos, RT_Flags rtFlags);\n        void ConvertSubtreeDynamic(uint32_t treeLevel, Range r);\n\n        // Maps instance ID to tree position\n        Util::HashTable<TreePos> m_IDtoTreePos;\n        // Maps RT mesh index to instance ID -- filled in by TLAS::BuildFrameMeshInstanceData()\n        Util::SmallVector<uint64> m_rtMeshInstanceIdxToID;\n        Util::SmallVector<TreeLevel, Support::SystemAllocator, 3> m_sceneGraph;\n        // Previous frame's world transformation\n        Util::HashTable<Math::float4x3> m_prevToWorlds;\n        Util::SmallVector<uint64, Support::SystemAllocator, 4> m_pickedInstances;\n        bool m_multiPick = false;\n        bool m_isPaused = false;\n\n        //\n        // Scene metadata\n        //\n        uint32_t m_numStaticInstances = 0;\n        uint32_t m_numDynamicInstances = 0;\n        uint32_t m_numOpaqueInstances = 0;\n        uint32_t m_numNonOpaqueInstances = 0;\n        uint32_t m_numTriangles = 0;\n        bool m_meshBufferStale = false;\n        Util::SmallVector<uint64_t, Support::SystemAllocator, 3> m_pendingRtMeshModeSwitch;\n        Util::HashTable<uint64_t> m_instanceUpdates;\n        \n        struct TransformUpdate\n        {\n            Math::float3 Tr;\n            Math::float3x3 Rotation;\n            Math::float3 Scale;\n        };\n        \n        Util::HashTable<TransformUpdate> m_tempWorldTransformUpdates;\n        Util::HashTable<Math::AffineTransformation> m_worldTransformUpdates;\n\n        //\n        // BVH\n        //\n        //Math::BVH m_bvh;\n        bool m_rebuildBVHFlag = false;\n\n        //\n        // Assets\n        //\n        Internal::MeshContainer m_meshes;\n        Internal::MaterialBuffer m_matBuffer;\n        Internal::TexSRVDescriptorTable m_baseColorDescTable;\n        Internal::TexSRVDescriptorTable m_normalDescTable;\n        Internal::TexSRVDescriptorTable m_metallicRoughnessDescTable;\n        Internal::TexSRVDescriptorTable m_emissiveDescTable;\n        Util::SmallVector<Core::GpuMemory::ResourceHeap, Support::SystemAllocator, 8> m_textureHeaps;\n\n        //\n        // Emissives\n        //\n        Internal::EmissiveBuffer m_emissives;\n        Util::SmallVector<uint64_t, App::FrameAllocator> m_toUpdateEmissives;\n        bool m_staleEmissiveMats = false;\n        bool m_staleEmissivePositions = false;\n        bool m_ignoreEmissives = false;\n\n        SRWLOCK m_matLock = SRWLOCK_INIT;\n        SRWLOCK m_meshLock = SRWLOCK_INIT;\n        SRWLOCK m_instanceLock = SRWLOCK_INIT;\n        SRWLOCK m_emissiveLock = SRWLOCK_INIT;\n        SRWLOCK m_pickLock = SRWLOCK_INIT;\n\n        //\n        // Animation\n        //\n        Util::SmallVector<AnimationMetadata> m_animationMetadata;\n        Util::SmallVector<Keyframe> m_keyframes;\n        bool m_animate = true;\n\n        //\n        // Scene Renderer\n        //\n        Renderer::Interface m_rendererInterface;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Scene/SceneRenderer.h",
    "content": "#pragma once\n\n#include \"../App/ZetaRay.h\"\n\nnamespace ZetaRay::Support\n{\n    struct TaskSet;\n}\n\nnamespace ZetaRay::Core\n{\n    class RenderGraph;\n}\n\nnamespace ZetaRay::Scene::GlobalResource\n{\n    inline static constexpr const char* MATERIAL_BUFFER = \"MaterialBuffer\";\n    inline static constexpr const char* BASE_COLOR_DESCRIPTOR_TABLE = \"BaseColorDescTable\";\n    inline static constexpr const char* NORMAL_DESCRIPTOR_TABLE = \"NormalDescTable\";\n    inline static constexpr const char* METALLIC_ROUGHNESS_DESCRIPTOR_TABLE = \"MRDescTable\";\n    inline static constexpr const char* EMISSIVE_DESCRIPTOR_TABLE = \"EmissiveDescTable\";\n    inline static constexpr const char* FRAME_CONSTANTS_BUFFER = \"FrameConstants\";\n    inline static constexpr const char* EMISSIVE_TRIANGLE_BUFFER = \"EmissiveTriangles\";\n    inline static constexpr const char* EMISSIVE_TRIANGLE_ALIAS_TABLE = \"EmissiveAliasTable\";\n    inline static constexpr const char* PRESAMPLED_EMISSIVE_SETS = \"PresampledEmissiveTris\";\n    inline static constexpr const char* LIGHT_VOXEL_GRID = \"LVG\";\n    inline static constexpr const char* RT_SCENE_BVH_PREV = \"PrevSceneBVH\";\n    inline static constexpr const char* RT_SCENE_BVH_CURR = \"CurrSceneBVH\";\n    inline static constexpr const char* SCENE_VERTEX_BUFFER = \"SceneVB\";\n    inline static constexpr const char* SCENE_INDEX_BUFFER = \"SceneIB\";\n    inline static constexpr const char* RT_FRAME_MESH_INSTANCES_PREV = \"PrevRtFrameMeshInstances\";\n    inline static constexpr const char* RT_FRAME_MESH_INSTANCES_CURR = \"CurrRtFrameMeshInstances\";\n}\n\nnamespace ZetaRay::Scene::Renderer\n{\n    using fp_Init = void(*)();\n    using fp_Update = void(*)(Support::TaskSet& ts);\n    using fp_Render = void(*)(Support::TaskSet& ts);\n    using fp_Shutdown = void(*)();\n    using fp_OnWindowSizeChanged = void(*)();\n    using fp_GetRenderGraph = Core::RenderGraph*(*)();\n    using fp_DebugDrawRenderGraph = void(*)();\n    using fp_IsRTASBuilt = bool(*)();\n    using fp_SceneModified = void(*)();\n    using fp_Pick = void(*)(uint16 screenPosX, uint16 screenPosY);\n    using fp_ClearPick = void(*)();\n    using fp_CaptureScreen = void(*)();\n    using fp_ToggleEmissives = void(*)();\n\n    struct Interface\n    {\n        fp_Init Init;\n        fp_Update Update;\n        fp_Render Render;\n        fp_Shutdown Shutdown;\n        fp_OnWindowSizeChanged OnWindowSizeChanged;\n        fp_GetRenderGraph GetRenderGraph;\n        fp_DebugDrawRenderGraph DebugDrawRenderGraph;\n        fp_IsRTASBuilt IsRTASBuilt;\n        fp_SceneModified SceneModified;\n        fp_Pick Pick;\n        fp_ClearPick ClearPick;\n        fp_CaptureScreen CaptureScreen;\n        fp_ToggleEmissives ToggleEmissives;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Support/CMakeLists.txt",
    "content": "set(SUPPORT_DIR \"${ZETA_CORE_DIR}/Support\")\nset(SUPPORT_SRC\n    \"${SUPPORT_DIR}/FrameMemory.h\"\n    \"${SUPPORT_DIR}/Memory.h\"\n    \"${SUPPORT_DIR}/MemoryPool.cpp\"\n    \"${SUPPORT_DIR}/MemoryPool.h\"\n    \"${SUPPORT_DIR}/MemoryArena.cpp\"\n    \"${SUPPORT_DIR}/MemoryArena.h\"\n    \"${SUPPORT_DIR}/OffsetAllocator.cpp\"\n    \"${SUPPORT_DIR}/OffsetAllocator.h\"\n    \"${SUPPORT_DIR}/Param.cpp\"\n    \"${SUPPORT_DIR}/Param.h\"\n    \"${SUPPORT_DIR}/Stat.h\"\n    \"${SUPPORT_DIR}/Task.cpp\"\n    \"${SUPPORT_DIR}/Task.h\"\n    \"${SUPPORT_DIR}/ThreadPool.cpp\"\n    \"${SUPPORT_DIR}/ThreadPool.h\")\nset(SUPPORT_SRC ${SUPPORT_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaCore/Support/FrameMemory.h",
    "content": "#pragma once\n\n#include \"../App/App.h\"\n#include <string.h>\n\nnamespace ZetaRay::Support\n{\n    template<size_t BlockSize>\n    struct FrameMemory\n    {\n        FrameMemory()\n        {\n            memset(m_blocks, 0, sizeof(MemoryBlock) * NUM_BLOCKS);\n        }\n        ~FrameMemory()\n        {\n            for (int i = 0; i < NUM_BLOCKS; i++)\n            {\n                if (m_blocks[i].Start)\n                    free(m_blocks[i].Start);\n            }\n        }\n\n        FrameMemory(FrameMemory&&) = delete;\n        FrameMemory& operator=(FrameMemory&&) = delete;\n\n        struct MemoryBlock\n        {\n            void* Start;\n            uintptr_t Offset;\n            int UsageCounter;\n        };\n\n        ZetaInline MemoryBlock& GetAndInitIfEmpty(int i)\n        {\n            Assert(i >= 0 && i < NUM_BLOCKS, \"Invalid block index.\");\n\n            if (!m_blocks[i].Start)\n            {\n                m_blocks[i].Start = malloc(BLOCK_SIZE);\n                m_blocks[i].Offset = 0;\n            }\n\n            m_blocks[i].UsageCounter = NUM_FRAMES_TO_FREE_DELAY;\n\n            return m_blocks[i];\n        }\n\n        void Reset()\n        {\n            for (int i = 0; i < NUM_BLOCKS; i++)\n            {\n                m_blocks[i].Offset = 0;\n\n                m_blocks[i].UsageCounter = (m_blocks[i].UsageCounter == NUM_FRAMES_TO_FREE_DELAY) ?\n                    NUM_FRAMES_TO_FREE_DELAY :\n                    m_blocks[i].UsageCounter - 1;\n\n                if (m_blocks[i].UsageCounter == 0)\n                {\n                    free(m_blocks[i].Start);\n                    m_blocks[i].Start = nullptr;\n                }\n            }\n        }\n\n        size_t TotalSize()\n        {\n            size_t sum = 0;\n\n            for (int i = 0; i < NUM_BLOCKS; i++)\n            {\n                if (m_blocks[i].Start)\n                    sum += BLOCK_SIZE;\n            }\n\n            return sum;\n        }\n\n        static constexpr int NUM_BLOCKS = MAX_NUM_THREADS * 2;\n        static constexpr int NUM_FRAMES_TO_FREE_DELAY = 10;\n        static constexpr size_t BLOCK_SIZE = BlockSize;\n\n        MemoryBlock m_blocks[NUM_BLOCKS];\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Support/Memory.h",
    "content": "#pragma once\n\n#include \"../App/ZetaRay.h\"\n#include <malloc.h>\n#include <concepts>\n\nnamespace ZetaRay::Support\n{\n    template<typename T>\n    concept AllocatorType = \n        std::is_copy_constructible_v<T> && \n        std::is_copy_assignable_v<T> &&\n        requires(T t, size_t s, size_t a, void* mem)\n        {\n            { t.AllocateAligned(s, a) } -> std::same_as<void*>;\n            { t.FreeAligned(mem, s, a) } -> std::same_as<void>;\n        };\n\n    struct SystemAllocator\n    {\n        ZetaInline void* AllocateAligned(size_t size, size_t alignment)\n        {\n            return _aligned_malloc(size, alignment);\n        }\n\n        ZetaInline void FreeAligned(void* mem, size_t size, size_t alignment)\n        {\n            _aligned_free(mem);\n        }\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Support/MemoryArena.cpp",
    "content": "#include \"MemoryArena.h\"\n\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Math;\n\n//--------------------------------------------------------------------------------------\n// MemoryArena\n//--------------------------------------------------------------------------------------\n\nMemoryArena::MemoryArena(size_t blockSize)\n    : m_blockSize(blockSize)\n{}\n\nMemoryArena::MemoryArena(MemoryArena&& other)\n    : m_blockSize(other.m_blockSize)\n{\n    m_blocks.swap(other.m_blocks);\n\n#ifndef NDEBUG\n    m_numAllocs = other.m_numAllocs;\n#endif\n}\n\nMemoryArena& MemoryArena::operator=(MemoryArena&& other)\n{\n    Check(m_blockSize == other.m_blockSize, \"These MemoryArenas are incompatible.\");\n\n    m_blocks.swap(other.m_blocks);\n    other.m_blocks.free_memory();\n\n#ifndef NDEBUG\n    m_numAllocs = other.m_numAllocs;\n    other.m_numAllocs = 0;\n#endif\n\n    return *this;\n}\n\nvoid* MemoryArena::AllocateAligned(size_t size, size_t alignment)\n{\n    for (auto& block : m_blocks)\n    {\n        const uintptr_t start = reinterpret_cast<uintptr_t>(block.Start);\n        const uintptr_t ret = AlignUp(start + block.Offset, alignment);\n        const uintptr_t startOffset = ret - start;\n\n        if (startOffset + size < block.Size)\n        {\n            block.Offset = startOffset + size;\n\n#ifndef NDEBUG\n            m_numAllocs++;\n#endif\n\n            return reinterpret_cast<void*>(ret);\n        }\n    }\n\n    size_t blockSize = Max(m_blockSize, size);\n\n    // Memory allocationss are 16-byte aligned by default -- for larger alignments, at\n    // most alignment - 1 extra bytes are required\n    if (alignment > 16)\n        blockSize = AlignUp(blockSize + alignment - 1, alignment);\n\n    MemoryBlock memBlock(blockSize);\n\n    const uintptr_t ret = AlignUp(reinterpret_cast<uintptr_t>(memBlock.Start), \n        alignment);\n    memBlock.Offset = ret - reinterpret_cast<uintptr_t>(memBlock.Start);\n    memBlock.Offset += size;\n    Assert(memBlock.Offset <= memBlock.Size, \"Offset must be <= size.\");\n\n    // Push the newly added block to the front, so it's searched before others \n    // for future allocations\n    m_blocks.push_front(ZetaMove(memBlock));\n\n    return reinterpret_cast<void*>(ret);\n}\n\nsize_t MemoryArena::TotalSize() const\n{\n    size_t sum = 0;\n\n    for (auto& block : m_blocks)\n        sum += block.Size;\n\n    return sum;\n}\n\nvoid MemoryArena::Reset()\n{\n    while (m_blocks.size() > 1)\n        m_blocks.pop_back();\n\n    if (!m_blocks.empty())\n        m_blocks[0].Offset = 0;\n}\n\n"
  },
  {
    "path": "Source/ZetaCore/Support/MemoryArena.h",
    "content": "#pragma once\n\n#include \"../Utility/SmallVector.h\"\n\nnamespace ZetaRay::Support\n{\n    class MemoryArena\n    {\n    public:\n        explicit MemoryArena(size_t blockSize = 64 * 1024);\n        ~MemoryArena() = default;\n        MemoryArena(MemoryArena&&);\n        MemoryArena& operator=(MemoryArena&&);\n\n        void* AllocateAligned(size_t size, size_t alignment = alignof(std::max_align_t));\n        void FreeAligned(void* pMem, size_t size, size_t alignment = alignof(std::max_align_t)) {};\n        size_t TotalSize() const;\n        void Reset();\n\n    private:\n        struct MemoryBlock\n        {\n            MemoryBlock() = default;\n            explicit MemoryBlock(size_t size)\n                : Size(size),\n                Offset(0)\n            {\n                Start = malloc(size);\n            }\n            ~MemoryBlock()\n            {\n                if (Start)\n                    free(Start);\n\n                Start = nullptr;\n                Offset = 0;\n                Size = 0;\n            }\n            MemoryBlock(MemoryBlock&& rhs)\n                : Start(rhs.Start),\n                Size(rhs.Size),\n                Offset(rhs.Offset)\n            {\n                rhs.Start = nullptr;\n                rhs.Offset = 0;\n                rhs.Size = 0;\n            }\n            MemoryBlock& operator=(MemoryBlock&& rhs)\n            {\n                Start = rhs.Start;\n                Size = rhs.Size;\n                Offset = rhs.Offset;\n\n                rhs.Start = nullptr;\n                rhs.Size = 0;\n                rhs.Offset = 0;\n\n                return *this;\n            }\n\n            void* Start;\n            size_t Size;\n            uintptr_t Offset;\n        };\n\n        const size_t m_blockSize;\n        Util::SmallVector<MemoryBlock, SystemAllocator, 8> m_blocks;\n#ifndef NDEBUG\n        uint32_t m_numAllocs = 0;\n#endif\n    };\n\n    struct ArenaAllocator\n    {\n        ArenaAllocator(MemoryArena& ma)\n            : m_allocator(&ma)\n        {}\n        ArenaAllocator(const ArenaAllocator& other)\n            : m_allocator(other.m_allocator)\n        {}\n        ArenaAllocator& operator=(const ArenaAllocator& other)\n        {\n            m_allocator = other.m_allocator;\n            return *this;\n        }\n\n        ZetaInline void* AllocateAligned(size_t size, size_t alignment = alignof(std::max_align_t))\n        {\n            return m_allocator->AllocateAligned(size, alignment);\n        }\n\n        ZetaInline void FreeAligned(void* mem, size_t size, size_t alignment = alignof(std::max_align_t))\n        {\n            m_allocator->FreeAligned(mem, size, alignment);\n        }\n\n    private:\n        MemoryArena* m_allocator;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Support/MemoryPool.cpp",
    "content": "#include \"MemoryPool.h\"\n#include \"../Utility/Error.h\"\n#include \"../Math/Common.h\"\n#include <intrin.h>\n#include <cstdio>\n#include <string.h>\n\nusing namespace ZetaRay::Support;\n\n#define VALIDATE_MOVE 0\n\n#ifdef NDEBUG\n#define VALIDATE_MOVE 0\n#endif\n\nnamespace\n{\n    int Length(void* head)\n    {\n        int ret = 0;\n\n        void* currHead = head;\n        while (currHead)\n        {\n            memcpy(&currHead, currHead, sizeof(void*));\n            ret++;\n        }\n\n        return ret;\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// MemoryPool\n//--------------------------------------------------------------------------------------\n\nMemoryPool::~MemoryPool()\n{\n    Clear();\n}\n\nvoid MemoryPool::Init()\n{\n    for (int i = 0; i < POOL_COUNT; i++)\n    {\n        m_currHead[i] = nullptr;\n        m_numMemoryBlocks[i] = 0;\n        m_pools[i] = nullptr;\n\n        //Grow(i);\n    }\n}\n\nvoid MemoryPool::Clear()\n{\n    for (int i = 0; i < POOL_COUNT; i++)\n    {\n        if (m_pools[i])\n        {\n            for (int j = 0; j < m_numMemoryBlocks[i]; j++)\n            {\n                // Free the pointer to heads of linked list for each memory block\n                free(m_pools[i][j]);\n            }\n\n            // Free the block itself\n            free(m_pools[i]);\n\n            m_pools[i] = nullptr;\n            m_currHead[i] = nullptr;\n        }\n    }\n\n    memset(m_numMemoryBlocks, 0, sizeof(size_t) * POOL_COUNT);\n}\n\nsize_t MemoryPool::GetPoolIndexFromSize(size_t x)\n{\n    size_t s = Math::Max(MIN_ALLOC_SIZE, Math::NextPow2(x));\n    unsigned long idx;\n    _BitScanForward64(&idx, s);\n\n    return idx - INDEX_SHIFT;\n}\n\nvoid MemoryPool::MoveTo(MemoryPool& dest)\n{\n    for (int poolIndex = 0; poolIndex < POOL_COUNT; poolIndex++)\n    {\n        void* curr = m_currHead[poolIndex];\n        void* tail = nullptr;\n        int sourceLen = 0;\n\n        // Walk the linked list and find the tail\n        while (curr)\n        {\n            tail = curr;\n            memcpy(&curr, curr, sizeof(void*));\n            sourceLen++;\n        }\n\n        // Append destination's existing linked list to the tail\n        if (tail)\n        {\n#if VALIDATE_MOVE\n            int destLen = 0;\n\n            {\n                void* currHead = dest.m_currHead[poolIndex];\n                while (currHead)\n                {\n                    memcpy(&currHead, currHead, sizeof(void*));\n                    destLen++;\n                }\n            }\n#endif\n\n            memcpy(tail, &dest.m_currHead[poolIndex], sizeof(void*));\n            dest.m_currHead[poolIndex] = m_currHead[poolIndex];\n            m_currHead[poolIndex] = nullptr;\n\n#if VALIDATE_MOVE\n            int newLen = 0;\n            void* currHead = dest.m_currHead[poolIndex];\n\n            while (currHead)\n            {\n                memcpy(&currHead, currHead, sizeof(void*));\n                newLen++;\n            }\n\n            Assert(sourceLen + destLen == newLen, \"bug\");\n#endif\n        }\n    }\n}\n\nvoid* MemoryPool::Allocate(size_t size)\n{\n    // Use malloc for requests larger than block size\n    if (size > MAX_ALLOC_SIZE)\n        return malloc(size);\n\n    // Which memory pool does it live in?\n    size_t poolIndex = GetPoolIndexFromSize(size);\n    size_t chunkSize = GetChunkSizeFromPoolIndex(poolIndex);\n\n    // No more chunks, add a new memory block\n    if (!m_currHead[poolIndex])\n        Grow(poolIndex);\n\n    Assert(m_currHead[poolIndex], \"bug\");\n\n    // Get the pointer to first entry in the linked list\n    void* oldHead = m_currHead[poolIndex];\n    // Update head of the linked list\n    memcpy(&m_currHead[poolIndex], m_currHead[poolIndex], sizeof(void*));\n\n    return oldHead;\n}\n\nvoid* MemoryPool::AllocateAligned(size_t size, size_t alignment)\n{\n    if (alignment <= alignof(std::max_align_t))\n        return Allocate(size);\n\n    // Alignment > 256 is not supported\n    if(alignment > 256)\n        return _aligned_malloc(size, alignment);\n\n    // Given alignment a, at most a - 1 additional bytes are needed, e.g. size = 1, a = 64, \n    // then 63 extra bytes has to be allocated assuming original memory was allocated at an \n    // address that ended with 0x1.\n    // \n    // Difference between the aligned address and the original address needs to be saved \n    // so it can be undone when freeing the memory. The extra alignment - 1 bytes provide \n    // the space to store that. A few points:\n    // \n    //  - One corner case happens when the address is already aligned, which means there won't \n    // be any extra space between the aligned and original addresses. To handle this, allocate \n    // alignment more bytes and always shift the original pointer to the next aligned address.\n    // \n    // - In the worst case, only 1 byte can be used to store the difference, so alignments up to \n    // 256 are supported (0 is interpreted as 256).\n    // \n    // Ref: Jason Gregory, Game Engine Architecture, CRC Press, 2019.\n    const size_t maxNumBytes = size + alignment - 1;\n\n    // Which memory pool does it live in?\n    size_t poolIndex = GetPoolIndexFromSize(maxNumBytes);\n    size_t chunkSize = GetChunkSizeFromPoolIndex(poolIndex);\n\n    // use malloc for requests larger than 512 bytes\n    if (poolIndex >= POOL_COUNT)\n    {\n        Assert(size >= MAX_ALLOC_SIZE, \"bug\");\n        return _aligned_malloc(size, alignment);\n    }\n\n    // If the pool for the requested size is empty or has become full, add a new memory block\n    if (!m_currHead[poolIndex])\n        Grow(poolIndex);\n\n    // Get the pointer to the first entry in the linked list\n    void* head = m_currHead[poolIndex];\n    void* oldHead = head;\n    void* newHead = *reinterpret_cast<void**>(head);\n\n    // Update head of the linked list\n    m_currHead[poolIndex] = newHead;\n\n    // Align the return pointer\n    uintptr_t aligned = reinterpret_cast<uintptr_t>(oldHead);\n    aligned = (aligned + alignment - 1) & ~(alignment - 1);\n\n    // Corner case described above\n    if (aligned == reinterpret_cast<uintptr_t>(oldHead))\n        aligned += alignment;\n\n    ptrdiff_t diff = (aligned - reinterpret_cast<uintptr_t>(oldHead)) & 0xff;\n    Assert(diff > 0 && diff <= 256, \"Invalid difference between aligned and original pointer.\");\n\n    // Store the difference\n    memcpy(reinterpret_cast<void*>(aligned - 1), &diff, 1);\n\n    return reinterpret_cast<void*>(aligned);\n}\n\nvoid MemoryPool::Free(void* mem, size_t size)\n{\n    if (mem)\n    {\n        // This request was allocated with malloc\n        if (size > MAX_ALLOC_SIZE)\n        {\n            free(mem);\n            return;\n        }\n\n        size_t poolIndex = GetPoolIndexFromSize(size);\n\n        // Set \"mem\"s next pointer to be current head of the linked list\n        memcpy(mem, &m_currHead[poolIndex], sizeof(void*));\n\n        // Update the head of linked list to point to \"mem\"\n        m_currHead[poolIndex] = mem;\n    }\n}\n\nvoid MemoryPool::FreeAligned(void* mem, size_t size, size_t alignment)\n{\n    if (alignment <= alignof(std::max_align_t))\n        return Free(mem, size);\n\n    if (mem)\n    {\n        const size_t maxNumBytes = size + alignment - 1;\n\n        // This request was allocated with malloc\n        if (maxNumBytes > MAX_ALLOC_SIZE || alignment > 256)\n        {\n            _aligned_free(mem);\n            return;\n        }\n\n        size_t poolIndex = GetPoolIndexFromSize(maxNumBytes);\n\n        // Undo alignment\n        uintptr_t origMem = reinterpret_cast<uintptr_t>(mem);\n        uint8_t diff = *(reinterpret_cast<uint8_t*>(origMem - 1));\n        origMem = diff > 0 ? origMem - diff : origMem - 256;\n\n        // Set \"mem\"s next pointer to be current head of the linked list\n        memcpy(reinterpret_cast<void*>(origMem), &m_currHead[poolIndex], sizeof(void*));\n\n        // Update the head of linked list to point to \"pMem\"\n        m_currHead[poolIndex] = reinterpret_cast<void*>(origMem);\n    }\n}\n\nvoid* MemoryPool::AllocateNewBlock(size_t chunkSize)\n{\n    // Allocate a new block of memory\n    void* block = malloc(BLOCK_SIZE);\n    Assert(block, \"malloc() failed.\");\n\n    // Make this block a linked list, i.e. store a pointer to the next chunk in each chunk \n    uintptr_t currHead = reinterpret_cast<uintptr_t>(block);\n    uintptr_t nextHead = currHead + chunkSize;\n    const uintptr_t end = currHead + BLOCK_SIZE;\n\n    while (nextHead < end)\n    {\n        memcpy(reinterpret_cast<void*>(currHead), &nextHead, sizeof(void*));\n        currHead = nextHead;\n        nextHead += chunkSize;\n    }\n\n    Assert(currHead == end - chunkSize, \"bug\");\n\n    // Make sure the last one points to null, so we'd know when to add a new block when this one becomes full\n    memset(reinterpret_cast<void*>(currHead), 0, sizeof(void*));\n\n    return block;\n}\n\nvoid MemoryPool::Grow(size_t poolIndex)\n{\n    size_t chunkSize = GetChunkSizeFromPoolIndex(poolIndex);\n\n    // Array of pointers to heads of memory blocks for this pool size. size has changed so we need the destroy the old one\n    // and allocate a new one. moreover all the head pointers have to be copied over to this new array\n    void** newMemoryBlockArray = reinterpret_cast<void**>(malloc((m_numMemoryBlocks[poolIndex] + 1) * sizeof(void*)));\n    Assert(newMemoryBlockArray, \"malloc() failed.\");\n\n    void* newBlock = AllocateNewBlock(chunkSize);\n\n    // Copy over the pointers to the previous memory blocks to this new array\n    if (m_numMemoryBlocks[poolIndex])\n    {\n        memcpy(newMemoryBlockArray, m_pools[poolIndex], sizeof(void*) * m_numMemoryBlocks[poolIndex]);\n\n        // Free the old array\n        Assert(m_pools[poolIndex], \"this shouldn't be NULL\");\n        free(m_pools[poolIndex]);\n    }\n\n    Assert(m_currHead[poolIndex] == nullptr, \"bug\");\n\n    // Save the head pointer to this newly added memory block\n    newMemoryBlockArray[m_numMemoryBlocks[poolIndex]] = newBlock;\n\n    m_currHead[poolIndex] = newBlock;\n    m_pools[poolIndex] = newMemoryBlockArray;\n    m_numMemoryBlocks[poolIndex]++;\n}\n\nsize_t MemoryPool::TotalSize() const\n{\n    size_t size = 0;\n\n    for (int i = 0; i < POOL_COUNT; i++)\n    {\n        //size += GetChunkSizeFromPoolIndex(i) * NUM_CHUNKS * (m_numMemoryBlocks[i] + 1);\n        size += BLOCK_SIZE * (m_numMemoryBlocks[i] + 1);\n    }\n\n    return size;\n}\n"
  },
  {
    "path": "Source/ZetaCore/Support/MemoryPool.h",
    "content": "#pragma once\n\n#include \"Memory.h\"\n\nnamespace ZetaRay::Support\n{\n    //    Pool-based memory allocator\n    //     - A collection of pools where each pool is made up of chunks of the same size\n    //     - Starting from a chunk size of 8 bytes, pool i has chuck size 2^(i + 3).\n    //     - Total number of chunks in each pool can be configured in the constructor and is\n    //       held in member \"m_numChunks\".\n    //     - There are a total of \"m_poolCount\" pools.\n    //\n    //     - Visualization:\n    //\n    //        pool 0:\n    //            8 bytes - 8 bytes - 8 bytes - .. - 8 bytes\n    //            ------------- m_numChunks ----------------\n    //        pool 1:\n    //            16 bytes - 16 bytes - 16 bytes - .. - 16 bytes\n    //            ------------- m_numChunks ----------------\n    //        pool 2:\n    //            32 bytes - 32 bytes - 32 bytes - .. - 32 bytes\n    //            ------------- m_numChunks ----------------\n    //\n    //                            ....\n    class MemoryPool\n    {\n    public:\n        MemoryPool() = default;\n        ~MemoryPool();\n\n        MemoryPool(MemoryPool&&) = delete;\n        MemoryPool& operator=(MemoryPool&&) = delete;\n\n        // Initialize the memory pool. Has to be called before any allocation/deallocation can take place\n        void Init();\n        void Clear();\n\n        void* AllocateAligned(size_t size, size_t alignment = alignof(std::max_align_t));\n        void FreeAligned(void* pMem, size_t size, size_t alignment = alignof(std::max_align_t));\n\n        size_t TotalSize() const;\n\n        void MoveTo(MemoryPool& mp);\n\n    private:\n        void* Allocate(size_t size);\n        void Free(void* pMem, size_t size);\n\n        // Given x, returns:\n        //        0    -> 8 bytes allocator    when 0 < x <= 8\n        //        1    -> 16 bytes allocator    when 8 < x <= 16\n        //        2    -> 32 bytes allocator    when 16 < x <= 32\n        //        3    -> 64 bytes allocator    when 32 < x <= 64\n        //            ...\n        size_t GetPoolIndexFromSize(size_t x);\n\n        // Chunk size for given pool index\n        ZetaInline size_t GetChunkSizeFromPoolIndex(size_t x) const\n        {\n            return 1llu << (x + INDEX_SHIFT);\n        }\n\n        // Allocates a new memory block and turns it into a linked list\n        void* AllocateNewBlock(size_t chunkSize);\n\n        // Adds a new memory block\n        void Grow(size_t poolIndex);\n\n        static constexpr size_t BLOCK_SIZE = 4096;                    \n        static constexpr size_t MAX_ALLOC_SIZE = BLOCK_SIZE;        // Allocation up to 4 kb supported    \n        static constexpr size_t POOL_COUNT = 10;                    // Number of pools == log_2 (4096) - log_2 (8) + 1\n        static constexpr size_t INDEX_SHIFT = 3;                    // First block starts at 8 bytes (log_2(sizeof(void *))\n        static constexpr size_t MIN_ALLOC_SIZE = 1 << INDEX_SHIFT;        \n\n        // Holds the pointer to head of memory blocks allocated for each pool size\n        void** m_pools[POOL_COUNT] = { nullptr };\n\n        // Keep track of how many memory blocks are there per block size\n        size_t m_numMemoryBlocks[POOL_COUNT] = { 0 };\n\n        // Pointer to head of the linked list for each memory block\n        void* m_currHead[POOL_COUNT] = { nullptr };\n    };\n\n    struct PoolAllocator\n    {\n        PoolAllocator(MemoryPool& mp)\n            : m_allocator(&mp)\n        {}\n\n        PoolAllocator(const PoolAllocator& other)\n            : m_allocator(other.m_allocator)\n        {\n        }\n\n        PoolAllocator& operator=(const PoolAllocator& other)\n        {\n            m_allocator = other.m_allocator;\n            return *this;\n        }\n\n        ZetaInline void* AllocateAligned(size_t size, size_t alignment = alignof(std::max_align_t))\n        {\n            return m_allocator->AllocateAligned(size, alignment);\n        }\n\n        ZetaInline void FreeAligned(void* mem, size_t size, size_t alignment = alignof(std::max_align_t))\n        {\n            m_allocator->FreeAligned(mem, size, alignment);\n        }\n\n    private:\n        MemoryPool* m_allocator;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Support/OffsetAllocator.cpp",
    "content": "#include \"OffsetAllocator.h\"\n#include \"../Utility/Error.h\"\n#include \"../Math/Common.h\"\n#include <intrin.h>\n#include <concepts>\n\nusing namespace ZetaRay::Support;\n\n// Ref: https://github.com/sebbbi/OffsetAllocator/blob/main/offsetAllocator.cpp\nnamespace SmallFloat\n{\n    static constexpr uint32_t MANTISSA_BITS = 3;\n    static constexpr uint32_t MANTISSA_VALUE = 1 << MANTISSA_BITS;\n    static constexpr uint32_t MANTISSA_MASK = MANTISSA_VALUE - 1;\n\n    // Bin sizes follow floating point (exponent + mantissa) distribution (piecewise linear log approx)\n    // This ensures that for each size class, the average overhead percentage stays the same\n    uint32_t uintToFloatRoundUp(uint32_t size)\n    {\n        Assert(size > 0, \"Invalid arg.\");\n\n        uint32_t exp = 0;\n        uint32_t mantissa = 0;\n\n        if (size < MANTISSA_VALUE)\n        {\n            // Denorm: 0..(MANTISSA_VALUE-1)\n            mantissa = size;\n        }\n        else\n        {\n            // Normalized: Hidden high bit always 1. Not stored. Just like float.\n            const uint32_t leadingZeros = _lzcnt_u32(size);\n            const uint32_t highestSetBit = 31 - leadingZeros;\n\n            const uint32_t mantissaStartBit = highestSetBit - MANTISSA_BITS;\n            exp = mantissaStartBit + 1;\n            mantissa = (size >> mantissaStartBit) & MANTISSA_MASK;\n\n            const uint32_t lowBitsMask = (1 << mantissaStartBit) - 1;\n\n            // Round up!\n            if ((size & lowBitsMask) != 0)\n                mantissa++;\n        }\n\n        return (exp << MANTISSA_BITS) + mantissa; // + allows mantissa->exp overflow for round up\n    }\n\n    uint32_t uintToFloatRoundDown(uint32_t size)\n    {\n        Assert(size > 0, \"Invalid arg.\");\n\n        uint32_t exp = 0;\n        uint32_t mantissa = 0;\n\n        if (size < MANTISSA_VALUE)\n        {\n            // Denorm: 0..(MANTISSA_VALUE-1)\n            mantissa = size;\n        }\n        else\n        {\n            // Normalized: Hidden high bit always 1. Not stored. Just like float.\n            const uint32_t leadingZeros = _lzcnt_u32(size);\n            const uint32_t highestSetBit = 31 - leadingZeros;\n\n            const uint32_t mantissaStartBit = highestSetBit - MANTISSA_BITS;\n            exp = mantissaStartBit + 1;\n            mantissa = (size >> mantissaStartBit) & MANTISSA_MASK;\n        }\n\n        return (exp << MANTISSA_BITS) | mantissa;\n    }\n\n    uint32_t floatToUint(uint32_t floatValue)\n    {\n        const uint32_t exponent = floatValue >> MANTISSA_BITS;\n        const uint32_t mantissa = floatValue & MANTISSA_MASK;\n        \n        if (exponent == 0)\n        {\n            // Denorms\n            return mantissa;\n        }\n        else\n            return (mantissa | MANTISSA_VALUE) << (exponent - 1);\n    }\n}\n\nnamespace\n{\n    ZetaInline uint32_t LowestSetBitGeIndex(uint32_t mask, uint32_t idx)\n    {\n        const uint32_t geIdxMask = ~((1 << idx) - 1);\n        mask &= geIdxMask;\n        return mask > 0 ? _tzcnt_u32(mask & geIdxMask) : OffsetAllocator::INVALID_INDEX;\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// OffsetAllocator\n//--------------------------------------------------------------------------------------\n\nOffsetAllocator::OffsetAllocator(uint32_t size, uint32_t maxNumAllocs)\n{\n    Init(size, maxNumAllocs);\n}\n\nOffsetAllocator::~OffsetAllocator()\n{\n    if(m_nodes)\n        delete[] m_nodes;\n\n    if(m_nodeStack)\n        delete[] m_nodeStack;\n}\n\nOffsetAllocator::OffsetAllocator(OffsetAllocator&& rhs)\n    : m_size(rhs.m_size),\n    m_maxNumAllocs(rhs.m_maxNumAllocs),\n    m_freeStorage(rhs.m_freeStorage),\n    m_firstLevelMask(rhs.m_firstLevelMask),\n    m_nodes(rhs.m_nodes),\n    m_nodeStack(rhs.m_nodeStack),\n    m_stackTop(rhs.m_stackTop)\n{\n    rhs.m_nodes = nullptr;\n    rhs.m_nodeStack = nullptr;\n    rhs.m_freeStorage = 0;\n    rhs.m_firstLevelMask = 0;\n\n    memcpy(m_freeListsHeads, rhs.m_freeListsHeads, ZetaArrayLen(m_freeListsHeads) * sizeof(uint32_t));\n    memcpy(m_secondLevelMask, rhs.m_secondLevelMask, ZetaArrayLen(m_secondLevelMask) * sizeof(uint8_t));\n}\n\nOffsetAllocator& OffsetAllocator::operator=(OffsetAllocator&& rhs)\n{\n    Assert(m_size == rhs.m_size, \"invalid assignment - size can't change after construction.\");\n    Assert(m_maxNumAllocs == rhs.m_maxNumAllocs, \"invalid assignment - max num allocs can't change after construction.\");\n\n    m_freeStorage = rhs.m_freeStorage;\n    m_firstLevelMask = rhs.m_firstLevelMask;\n    m_nodes = rhs.m_nodes;\n    m_nodeStack = rhs.m_nodeStack;\n    m_stackTop = rhs.m_stackTop;\n\n    rhs.m_nodes = nullptr;\n    rhs.m_nodeStack = nullptr;\n    rhs.m_freeStorage = 0;\n    rhs.m_firstLevelMask = 0;\n\n    memcpy(m_freeListsHeads, rhs.m_freeListsHeads, ZetaArrayLen(m_freeListsHeads) * sizeof(uint32_t));\n    memcpy(m_secondLevelMask, rhs.m_secondLevelMask, ZetaArrayLen(m_secondLevelMask) * sizeof(uint8_t));\n\n    return *this;\n}\n\nvoid OffsetAllocator::Init(uint32_t size, uint32_t maxNumAllocs)\n{\n    Assert(size >= 1 && maxNumAllocs >= 1 && maxNumAllocs <= size, \"Invalid args.\");\n    m_size = size;\n    // + 1 so the first stack entry (whole memory region) doesn't count towards maximum\n    m_maxNumAllocs = maxNumAllocs + 1;\n\n    Reset();\n}\n\nvoid OffsetAllocator::Reset()\n{\n    Assert((m_nodes && m_nodeStack) || (!m_nodes && !m_nodeStack), \"either both are allocated or both are null.\");\n\n    if (m_nodes)\n    {\n        delete[] m_nodes;\n        delete[] m_nodeStack;\n    }\n\n    m_nodes = new Node[m_maxNumAllocs];\n    m_nodeStack = new uint32_t[m_maxNumAllocs];\n\n    // Push 0...m_maxNumAllocs - 1 in reverse\n    for (int64 i = 0; i < m_maxNumAllocs; i++)\n        m_nodeStack[i] = m_maxNumAllocs - 1 - (uint32)i;\n\n    m_firstLevelMask = 0;\n\n    for (int i = 0; i < ZetaArrayLen(m_secondLevelMask); i++)\n        m_secondLevelMask[i] = 0;\n\n    for (int i = 0; i < ZetaArrayLen(m_freeListsHeads); i++)\n        m_freeListsHeads[i] = INVALID_NODE;\n\n    m_stackTop = m_maxNumAllocs - 1;\n    m_freeStorage = 0;\n\n    InsertNode(0, m_size);\n}\n\nuint32_t OffsetAllocator::InsertNode(uint32_t offset, uint32_t size)\n{\n    Assert(offset + size <= m_size, \"Requested node exceeded memory region bounds.\");\n    Assert(m_stackTop >= 0, \"Out of stack storage, InsertNode() shouldn't have been called.\");\n\n    const uint32_t listIdx = SmallFloat::uintToFloatRoundDown(size);\n    const uint32_t currHead = m_freeListsHeads[listIdx];\n    const uint32_t nodeIdx = m_nodeStack[m_stackTop--];\n    Assert(nodeIdx >= 0 && nodeIdx < m_maxNumAllocs, \"Out-of-bound stack access.\");\n\n    Node& node = m_nodes[nodeIdx];\n    node = Node{ .Offset = offset, \n        .Size = size, \n        .Next = currHead,\n        .LeftNeighbor = node.LeftNeighbor,\n        .RightNeighbor = node.RightNeighbor };\n\n    if (currHead != INVALID_NODE)\n        m_nodes[currHead].Prev = nodeIdx;\n\n    m_freeListsHeads[listIdx] = nodeIdx;\n\n    const uint32_t firstLevelIdx = listIdx >> FIRST_LEVEL_INDEX_SHIFT;\n    const uint32_t secondLevelIdx = listIdx & SECOND_LEVEL_INDEX_MASK;\n\n    m_firstLevelMask |= 1 << firstLevelIdx;\n    m_secondLevelMask[firstLevelIdx] |= 1 << secondLevelIdx;\n\n    m_freeStorage += size;\n    Assert(m_freeStorage <= m_size, \"Size of free storage exceeded maximum.\");\n\n    return nodeIdx;\n}\n\nvoid OffsetAllocator::RemoveNode(uint32_t nodeIdx)\n{\n    Node& node = m_nodes[nodeIdx];\n\n    if (node.Prev != INVALID_NODE)\n    {\n        m_nodes[node.Prev].Next = node.Next;\n\n        if (node.Next != INVALID_NODE)\n            m_nodes[node.Next].Prev = node.Prev;\n    }\n    else\n    {\n        const uint32_t listIdx = SmallFloat::uintToFloatRoundDown(node.Size);\n        m_freeListsHeads[listIdx] = node.Next;\n\n        if (node.Next != INVALID_NODE)\n            m_nodes[node.Next].Prev = INVALID_NODE;\n        else\n        {\n            const uint32_t firstLevelIdx = listIdx >> FIRST_LEVEL_INDEX_SHIFT;\n            const uint32_t secondLevelIdx = listIdx & SECOND_LEVEL_INDEX_MASK;\n\n            m_secondLevelMask[firstLevelIdx] ^= (1 << secondLevelIdx);\n\n            if (m_secondLevelMask[firstLevelIdx] == 0)\n                m_firstLevelMask ^= (1 << firstLevelIdx);\n        }\n    }\n\n    m_nodeStack[++m_stackTop] = nodeIdx;\n    m_freeStorage -= node.Size;\n}\n\nOffsetAllocator::Allocation OffsetAllocator::Allocate(uint32_t size, uint32_t alignment)\n{\n    Assert(alignment >= 1, \"Invalid alignment.\");\n    Assert(size != 0, \"Redundant call.\");\n\n    //if (size == 0)\n    //    return Allocation::Empty();\n\n    // Out of node storage. \n    // Note: Entries are pushed in the order 0, ..., m_maxNumAllocs - 1, so\n    // after popping the last entry, top index becomes 0 - 1 = uint32_max.\n    static_assert(std::same_as<decltype(m_stackTop), uint32>, \"Stack index must be uint32.\");\n    if (m_stackTop == UINT32_MAX)\n        return Allocation::Empty();\n\n    // Assuming start offset is aligned, at most alignment - 1 extra bytes are required\n    const uint32_t alignedSize = size + alignment - 1;\n\n    uint32_t listIdx = SmallFloat::uintToFloatRoundUp(alignedSize);\n    uint32_t firstLevelIdx = listIdx >> FIRST_LEVEL_INDEX_SHIFT;\n    uint32_t secondLevelIdx = listIdx & SECOND_LEVEL_INDEX_MASK;\n\n    secondLevelIdx = LowestSetBitGeIndex(m_secondLevelMask[firstLevelIdx], secondLevelIdx);\n    firstLevelIdx = secondLevelIdx != INVALID_INDEX ? \n        firstLevelIdx : \n        LowestSetBitGeIndex(m_firstLevelMask, firstLevelIdx + 1);\n\n    // Out of space\n    if (firstLevelIdx == INVALID_INDEX)\n        return Allocation::Empty();\n\n    Assert(m_firstLevelMask & (1 << firstLevelIdx), \"1st/2nd level mask mismatch.\");\n\n    secondLevelIdx = secondLevelIdx != INVALID_INDEX ?\n        secondLevelIdx :\n        _tzcnt_u32(m_secondLevelMask[firstLevelIdx]);\n\n    listIdx = (firstLevelIdx << FIRST_LEVEL_INDEX_SHIFT) + secondLevelIdx;\n    Assert(m_freeListsHeads[listIdx] != INVALID_NODE, \"List/mask mismatch.\");\n    const uint32_t nodeIdx = m_freeListsHeads[listIdx];\n    Node& head = m_nodes[nodeIdx];\n    Assert(!head.InUse, \"A freelist node shouldn't be in use.\");\n\n    const uint32_t oldSize = head.Size;\n    const uint32_t oldRightNeighbor = head.RightNeighbor;\n    // Due to rounding up, oldSize > alignedSize\n    const uint32_t leftoverSize = oldSize - alignedSize;\n\n    // Pop head node from list\n    m_freeListsHeads[listIdx] = head.Next;\n\n    if (head.Next != INVALID_NODE)\n        m_nodes[head.Next].Prev = INVALID_NODE;\n\n    head = Node{ .Offset = head.Offset,\n        .Size = alignedSize, \n        .LeftNeighbor = head.LeftNeighbor,\n        .RightNeighbor = head.RightNeighbor,\n        .InUse = true};\n\n    // No more nodes in this freelist\n    if (m_freeListsHeads[listIdx] == INVALID_NODE)\n    {\n        m_secondLevelMask[firstLevelIdx] ^= (1 << secondLevelIdx);\n\n        if (m_secondLevelMask[firstLevelIdx] == 0)\n            m_firstLevelMask ^= (1 << firstLevelIdx);\n    }\n\n    m_freeStorage -= oldSize;\n\n    if (leftoverSize)\n    {\n        const uint32_t newRightNeighbor = InsertNode(head.Offset + head.Size, leftoverSize);\n\n        if (newRightNeighbor == INVALID_NODE)\n            return Allocation::Empty();\n\n        if (oldRightNeighbor != INVALID_NODE)\n            m_nodes[oldRightNeighbor].LeftNeighbor = newRightNeighbor;\n\n        m_nodes[newRightNeighbor].LeftNeighbor = nodeIdx;\n        m_nodes[newRightNeighbor].RightNeighbor = oldRightNeighbor;\n        head.RightNeighbor = newRightNeighbor;\n    }\n\n    const uint32_t alignedOffset = (uint32_t)Math::AlignUp(head.Offset, alignment);\n    Assert(alignedOffset + size <= head.Offset + alignedSize, \"invalid bin idx.\");\n\n    return Allocation{ .Size = size,\n        .Offset = alignedOffset,\n        .Internal = nodeIdx };\n}\n\nvoid OffsetAllocator::Free(const Allocation& alloc)\n{\n    const uint32_t listIdx = SmallFloat::uintToFloatRoundUp(alloc.Size);\n    const uint32_t firstLevelIdx = listIdx >> FIRST_LEVEL_INDEX_SHIFT;\n    const uint32_t secondLevelIdx = listIdx & SECOND_LEVEL_INDEX_MASK;\n\n    const uint32_t nodeIdx = alloc.Internal;\n    Assert(nodeIdx != INVALID_NODE, \"invalid node index.\");\n    Node& node = m_nodes[nodeIdx];\n    Assert(node.InUse == true, \"can't free node that isn't in use.\");\n\n    uint32_t newOffset = node.Offset;\n    uint32_t newSize = node.Size;\n    uint32_t newLeftNeighbor = node.LeftNeighbor;\n    uint32_t newRightNeighbor = node.RightNeighbor;\n\n    if (node.LeftNeighbor != INVALID_NODE)\n    {\n        Node& leftNeighbor = m_nodes[node.LeftNeighbor];\n        Assert(leftNeighbor.RightNeighbor == nodeIdx, \"these must match.\");\n\n        if (!leftNeighbor.InUse)\n        {\n            newOffset = leftNeighbor.Offset;\n            newSize += leftNeighbor.Size;\n            newLeftNeighbor = leftNeighbor.LeftNeighbor;\n\n            RemoveNode(node.LeftNeighbor);\n        }\n    }\n\n    if (node.RightNeighbor != INVALID_NODE)\n    {\n        Node& rightNeighbor = m_nodes[node.RightNeighbor];\n        Assert(rightNeighbor.LeftNeighbor == nodeIdx, \"these must match.\");\n\n        if (!rightNeighbor.InUse)\n        {\n            newSize += rightNeighbor.Size;\n            newRightNeighbor = rightNeighbor.RightNeighbor;\n\n            RemoveNode(node.RightNeighbor);\n        }\n    }\n\n    m_nodeStack[++m_stackTop] = nodeIdx;\n\n    const uint32_t newNodeIdx = InsertNode(newOffset, newSize);\n\n    m_nodes[newNodeIdx].RightNeighbor = newRightNeighbor;\n    m_nodes[newNodeIdx].LeftNeighbor = newLeftNeighbor;\n\n    if (newLeftNeighbor != INVALID_NODE)\n        m_nodes[newLeftNeighbor].RightNeighbor = newNodeIdx;\n\n    if (newRightNeighbor != INVALID_NODE)\n        m_nodes[newRightNeighbor].LeftNeighbor = newNodeIdx;\n}\n\nOffsetAllocator::StorageReport OffsetAllocator::GetStorageReport() const\n{\n    uint32_t largestFreeRegion = 0;\n    uint32_t freeStorage = 0;\n\n    if (m_stackTop != INVALID_NODE)\n    {\n        freeStorage = m_freeStorage;\n\n        if (m_firstLevelMask)\n        {\n            const uint32_t firstLevel = 31 - _lzcnt_u32(m_firstLevelMask);\n            const uint32_t secondLevel = 31 - _lzcnt_u32(m_secondLevelMask[firstLevel]);\n\n            largestFreeRegion = SmallFloat::floatToUint((firstLevel << FIRST_LEVEL_INDEX_SHIFT) + secondLevel);\n            Assert(freeStorage >= largestFreeRegion, \"\");\n        }\n    }\n\n    return { .TotalFreeSpace = freeStorage, .LargestFreeRegion = largestFreeRegion };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Support/OffsetAllocator.h",
    "content": "#pragma once\n\n#include \"../App/ZetaRay.h\"\n\nnamespace ZetaRay::Support\n{\n    // Ref: https://github.com/sebbbi/OffsetAllocator\n    class OffsetAllocator\n    {\n    public:\n        static constexpr uint32_t INVALID_INDEX = UINT32_MAX;\n        static constexpr uint32_t INVALID_NODE = UINT32_MAX;\n\n        struct Allocation\n        {\n            static Allocation Empty()\n            {\n                return Allocation{ .Size = 0,\n                    .Offset = 0,\n                    .Internal = INVALID_NODE };\n            }\n\n            bool IsEmpty() const { return Internal == INVALID_NODE; }\n\n            uint32_t Size;\n            uint32_t Offset;\n            uint32_t Internal;\n        };\n\n        struct StorageReport\n        {\n            uint32_t TotalFreeSpace;\n            uint32_t LargestFreeRegion;\n        };\n\n        OffsetAllocator() = default;\n        OffsetAllocator(uint32_t size, uint32_t maxNumAllocs);\n        ~OffsetAllocator();\n\n        OffsetAllocator(OffsetAllocator&& rhs);\n        OffsetAllocator& operator=(OffsetAllocator&& rhs);\n\n        void Init(uint32_t size, uint32_t maxNumAllocs);\n        Allocation Allocate(uint32_t size, uint32_t alignment = 1);\n        void Free(const Allocation& alloc);\n        void Reset();\n        uint32_t FreeStorage() const { return m_freeStorage; }\n        StorageReport GetStorageReport() const;\n\n    private:\n        static constexpr uint32_t NUM_FIRST_LEVEL_BINS = 32;\n        static constexpr uint32_t NUM_SPLITS_PER_FIRST_LEVEL_BIN = 8;\n        static constexpr uint32_t FIRST_LEVEL_INDEX_SHIFT = 3;\n        static constexpr uint32_t SECOND_LEVEL_INDEX_MASK = NUM_SPLITS_PER_FIRST_LEVEL_BIN - 1;\n\n        struct Node\n        {\n            uint32_t Offset = 0;\n            uint32_t Size = 0;\n            uint32_t Next = INVALID_NODE;\n            uint32_t Prev = INVALID_NODE;\n            uint32_t LeftNeighbor = INVALID_NODE;\n            uint32_t RightNeighbor = INVALID_NODE;\n            bool InUse = false;\n        };\n\n        uint32_t InsertNode(uint32_t offset, uint32_t size);\n        void RemoveNode(uint32_t nodeIdx);\n\n        uint32_t m_size;\n        uint32_t m_maxNumAllocs;\n        uint32_t m_freeStorage;\n\n        uint32_t m_firstLevelMask = 0;\n        uint8_t m_secondLevelMask[NUM_FIRST_LEVEL_BINS];\n\n        // List i contains nodes N such that,\n        //        i = SmallFloat(N.size)\n        // e.g. when i = 35, SmallFloat(x) = 35 for x in [88, 96) \n        uint32_t m_freeListsHeads[NUM_FIRST_LEVEL_BINS * NUM_SPLITS_PER_FIRST_LEVEL_BIN];\n        Node* m_nodes = nullptr;\n        // A stack of at most m_maxNumAllocs entries where every node points to some\n        // contiguous region (i.e. [offset, offset + size)) of underlying resource. Also,\n        // each node maintains pointers to its siblings in the same bin.\n        uint32_t* m_nodeStack = nullptr;\n        // Index to top stack entry in [0, m_maxNumAllocs - 1]\n        uint32_t m_stackTop;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Support/Param.cpp",
    "content": "#include \"Param.h\"\n#include <xxHash/xxhash.h>\n#include <string.h>\n\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Math;\n\n//--------------------------------------------------------------------------------------\n// ParamVariant\n//--------------------------------------------------------------------------------------\n\nvoid ParamVariant::InitCommon(const char* group, const char* subgroup, \n    const char* subsubgroup, const char* name, \n    fastdelegate::FastDelegate1<const ParamVariant&> dlg)\n{\n    Assert(group, \"Group can't be null.\");\n    Assert(subgroup, \"Subgroup can't be null.\");\n    Assert(name, \"Name can't be null.\");\n\n    m_dlg = dlg;\n\n    size_t lenGroup = Min((int)strlen(group), (MAX_GROUP_LEN - 1));\n    Assert(lenGroup >= 1, \"Empty group name.\");\n    memcpy(m_group, group, lenGroup);\n    m_group[lenGroup] = '\\0';\n\n    size_t lenSubgroup = Min((int)strlen(subgroup), (MAX_SUBGROUP_LEN - 1));\n    Assert(lenSubgroup >= 1, \"Empty subgroup name.\");\n    memcpy(m_subgroup, subgroup, lenSubgroup);\n    m_subgroup[lenSubgroup] = '\\0';\n\n    size_t lenSubSubgroup = subsubgroup ? Min((int)strlen(subsubgroup), (MAX_SUBSUBGROUP_LEN - 1)) : 0;\n    if (subsubgroup)\n        memcpy(m_subsubgroup, subsubgroup, lenSubSubgroup);\n    \n    m_subsubgroup[lenSubSubgroup] = '\\0';\n\n    size_t lenName = Min((int)strlen(name), (MAX_NAME_LEN - 1));\n    Assert(lenName >= 1, \"Empty name.\");\n    memcpy(m_name, name, lenName);\n    m_name[lenName] = '\\0';\n\n    constexpr int BUFF_SIZE = ParamVariant::MAX_GROUP_LEN + ParamVariant::MAX_SUBGROUP_LEN + \n        ParamVariant::MAX_NAME_LEN;\n    char buff[BUFF_SIZE];\n    size_t ptr = 0;\n\n    memcpy(buff, group, lenGroup);\n    ptr += lenGroup;\n    memcpy(buff + ptr, subgroup, lenSubgroup);\n    ptr += lenSubgroup;\n    memcpy(buff + ptr, name, lenName);\n\n    m_id = XXH3_64bits(buff, ptr + lenName);\n}\n\nvoid ParamVariant::InitFloat(const char* group, const char* subgroup, const char* name, \n    fastdelegate::FastDelegate1<const ParamVariant&> dlg, float val, float min, float max, \n    float step, const char* subsubgroup)\n{\n    InitCommon(group, subgroup, subsubgroup, name, dlg);\n\n    m_type = PARAM_TYPE::PT_float;\n    m_float.Init(val, min, max, step);\n}\n\nvoid ParamVariant::InitInt(const char* group, const char* subgroup, const char* name, \n    fastdelegate::FastDelegate1<const ParamVariant&> dlg, int val, int min, int max, \n    int step, const char* subsubgroup)\n{\n    InitCommon(group, subgroup, subsubgroup, name, dlg);\n\n    m_type = PARAM_TYPE::PT_int;\n    m_int.Init(val, min, max, step);\n}\n\nvoid ParamVariant::InitFloat2(const char* group, const char* subgroup, const char* name, \n    fastdelegate::FastDelegate1<const ParamVariant&> dlg, float2 val, float min, \n    float max, float step, const char* subsubgroup)\n{\n    InitCommon(group, subgroup, subsubgroup, name, dlg);\n\n    m_type = PARAM_TYPE::PT_float2;\n    m_float2.Init(val, min, max, step, false);\n}\n\nvoid ParamVariant::InitFloat3(const char* group, const char* subgroup, const char* name, \n    fastdelegate::FastDelegate1<const ParamVariant&> dlg, float3 val, float min, float max, \n    float step, const char* subsubgroup)\n{\n    InitCommon(group, subgroup, subsubgroup, name, dlg);\n\n    m_type = PARAM_TYPE::PT_float3;\n    m_float3.Init(val, min, max, step, false);\n}\n\nvoid ParamVariant::InitUnitDir(const char* group, const char* subgroup, const char* name, \n    fastdelegate::FastDelegate1<const ParamVariant&> dlg, float pitch, float yaw, \n    const char* subsubgroup)\n{\n    InitCommon(group, subgroup, subsubgroup, name, dlg);\n\n    Assert(pitch >= 0 && pitch <= Math::PI, \"Pitch must be in [0, +PI].\");\n    Assert(yaw >= 0 && yaw <= Math::TWO_PI, \"Yaw must be in [0, 2 * PI].\");\n    m_type = PARAM_TYPE::PT_unit_dir;\n    m_unitDir.Init(pitch, yaw);\n}\n\nvoid ParamVariant::InitUnitDir(const char* group, const char* subgroup, const char* name, \n    fastdelegate::FastDelegate1<const ParamVariant&> dlg, float3 dir, \n    const char* subsubgroup)\n{\n    InitCommon(group, subgroup, subsubgroup, name, dlg);\n\n    float theta;\n    float phi;\n    SphericalFromCartesian(dir, theta, phi);\n\n    m_type = PARAM_TYPE::PT_unit_dir;\n    m_unitDir.Init(theta, phi);\n}\n\nvoid ParamVariant::InitNormalizedFloat3(const char* group, const char* subgroup, \n    const char* name, fastdelegate::FastDelegate1<const ParamVariant&> dlg, \n    float3 val, const char* subsubgroup)\n{\n    InitCommon(group, subgroup, subsubgroup, name, dlg);\n\n    m_type = PARAM_TYPE::PT_float3;\n    m_float3.Init(val, -1.0f, 1.0f, 1e-2f, true);\n}\n\nvoid ParamVariant::InitColor(const char* group, const char* subgroup, const char* name, \n    fastdelegate::FastDelegate1<const ParamVariant&> dlg, float3 val, \n    const char* subsubgroup)\n{\n    InitCommon(group, subgroup, subsubgroup, name, dlg);\n\n    m_type = PARAM_TYPE::PT_color;\n    m_float3.Init(val, 0.0f, 1.0f, 0.01f, false);\n}\n\nvoid ParamVariant::InitBool(const char* group, const char* subgroup, const char* name, \n    fastdelegate::FastDelegate1<const ParamVariant&> dlg, bool val, \n    const char* subsubgroup)\n{\n    InitCommon(group, subgroup, subsubgroup, name, dlg);\n\n    m_type = PARAM_TYPE::PT_bool;\n    m_bool = val;\n}\n\nvoid ParamVariant::InitEnum(const char* group, const char* subgroup, const char* name, \n    fastdelegate::FastDelegate1<const ParamVariant&> dlg, const char** vals, int num, \n    int index, const char* subsubgroup)\n{\n    InitCommon(group, subgroup, subsubgroup, name, dlg);\n\n    m_type = PARAM_TYPE::PT_enum;\n    Assert(index < num, \"Out-of-bound index.\");\n    m_enum.Init(vals, num, index);\n}\n\nconst FloatParam& ParamVariant::GetFloat() const\n{\n    Assert(m_type == PARAM_TYPE::PT_float, \"Invalid union type.\");\n    return m_float;\n}\n\nvoid ParamVariant::SetFloat(float v)\n{\n    Assert(m_type == PARAM_TYPE::PT_float, \"Invalid union type.\");\n    m_float.m_value = v;\n    m_dlg(*this);\n}\n\nconst Float2Param& ParamVariant::GetFloat2() const\n{\n    Assert(m_type == PARAM_TYPE::PT_float2, \"Invalid union type.\");\n    return m_float2;\n}\n\nvoid ParamVariant::SetFloat2(const float2& v)\n{\n    Assert(m_type == PARAM_TYPE::PT_float2, \"Invalid union type.\");\n    m_float2.m_value = v;\n\n    if (m_float2.m_keepNormalized)\n        m_float2.m_value.normalize();\n\n    m_dlg(*this);\n}\n\nconst Float3Param& ParamVariant::GetFloat3() const\n{\n    Assert(m_type == PARAM_TYPE::PT_float3 || m_type == PARAM_TYPE::PT_color, \"Invalid union type.\");\n    return m_float3;\n}\n\nvoid ParamVariant::SetFloat3(const float3& v)\n{\n    Assert(m_type == PARAM_TYPE::PT_float3, \"Invalid union type.\");\n    m_float3.m_value = v;\n\n    if (m_float3.m_keepNormalized)\n        m_float3.m_value.normalize();\n\n    m_dlg(*this);\n}\n\nconst UnitDirParam& ParamVariant::GetUnitDir() const\n{\n    Assert(m_type == PARAM_TYPE::PT_unit_dir, \"Invalid union type.\");\n    return m_unitDir;\n}\n\nvoid ParamVariant::SetUnitDir(float pitch, float yaw)\n{\n    Assert(m_type == PARAM_TYPE::PT_unit_dir, \"Invalid union type.\");\n    m_unitDir.m_pitch = pitch;\n    m_unitDir.m_yaw = yaw;\n    m_dlg(*this);\n}\n\nconst Float3Param& ParamVariant::GetColor() const\n{\n    Assert(m_type == PARAM_TYPE::PT_color, \"Invalid union type.\");\n    return m_float3;\n}\n\nvoid ParamVariant::SetColor(const float3& v)\n{\n    Assert(m_type == PARAM_TYPE::PT_color, \"Invalid union type.\");\n    m_float3.m_value = v;\n    m_dlg(*this);\n}\n\nconst IntParam& ParamVariant::GetInt() const\n{\n    Assert(m_type == PARAM_TYPE::PT_int, \"Invalid union type.\");\n    return m_int;\n}\n\nvoid ParamVariant::SetInt(int v)\n{\n    Assert(m_type == PARAM_TYPE::PT_int, \"Invalid union type.\");\n    m_int.m_value = v;\n    m_dlg(*this);\n}\n\nbool ParamVariant::GetBool() const\n{\n    Assert(m_type == PARAM_TYPE::PT_bool, \"Invalid union type.\");\n    return m_bool;\n}\n\nvoid ParamVariant::SetBool(bool v)\n{\n    Assert(m_type == PARAM_TYPE::PT_bool, \"Invalid union type.\");\n    m_bool = v;\n    m_dlg(*this);\n}\n\nconst EnumParam& ParamVariant::GetEnum() const\n{\n    Assert(m_type == PARAM_TYPE::PT_enum, \"Invalid union type.\");\n    return m_enum;\n}\n\nvoid ParamVariant::SetEnum(int v)\n{\n    Assert(m_type == PARAM_TYPE::PT_enum, \"Invalid union type.\");\n    Assert(v < m_enum.m_num, \"Out-of-bound index.\");\n    m_enum.m_curr = v;\n    m_dlg(*this);\n}\n\nfloat3 UnitDirParam::GetDir() const\n{\n    return SphericalToCartesian(m_pitch, m_yaw);\n}\n"
  },
  {
    "path": "Source/ZetaCore/Support/Param.h",
    "content": "#pragma once\n\n#include \"../Math/Vector.h\"\n#include <type_traits>\n#include <FastDelegate/FastDelegate.h>\n\nnamespace ZetaRay::Support\n{\n    //--------------------------------------------------------------------------------------\n    // FloatParam\n    //--------------------------------------------------------------------------------------\n\n    struct FloatParam\n    {\n        void Init(float value, float min, float max, float step)\n        {\n            Assert(value >= min && value <= max, \"Default value is outside the given bounds.\");\n            m_value = value;\n            m_min = min;\n            m_max = max;\n            m_stepSize = step;\n        }\n\n        float m_value;\n        float m_min;\n        float m_max;\n        float m_stepSize;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // Float2Param\n    //--------------------------------------------------------------------------------------\n\n    struct Float2Param\n    {\n        void Init(Math::float2 val, float min, float max, float step, bool keepNormalized)\n        {\n            m_value = val;\n            m_min = min;\n            m_max = max;\n            m_stepSize = step;\n            m_keepNormalized = keepNormalized;\n        }\n\n        Math::float2 m_value;\n        float m_min;\n        float m_max;\n        float m_stepSize;\n        bool m_keepNormalized;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // Float3Param\n    //--------------------------------------------------------------------------------------\n\n    struct Float3Param\n    {\n        void Init(Math::float3 val, float min, float max, float step, bool keepNormalized)\n        {\n            m_value = val;\n            m_min = min;\n            m_max = max;\n            m_stepSize = step;\n            m_keepNormalized = keepNormalized;\n        }\n\n        Math::float3 m_value;\n        float m_min;\n        float m_max;\n        float m_stepSize;\n        bool m_keepNormalized;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // UnitDirParam\n    //--------------------------------------------------------------------------------------\n\n    struct UnitDirParam\n    {\n        void Init(float pitch, float yaw)\n        {\n            m_pitch = pitch;\n            m_yaw = yaw;\n        }\n\n        Math::float3 GetDir() const;\n\n        float m_pitch;      // Angle of rotation around the x-axis (radians)\n        float m_yaw;        // Angle of rotation around the y-axis (radians)\n    };\n\n    //--------------------------------------------------------------------------------------\n    // ColorParam\n    //--------------------------------------------------------------------------------------\n\n    struct ColorParam\n    {\n        void Init(Math::float3 val, float min, float max, float step)\n        {\n            m_value = val;\n            m_min = min;\n            m_max = max;\n            m_stepSize = step;\n        }\n\n        Math::float3 m_value;\n        float m_min;\n        float m_max;\n        float m_stepSize;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // IntParam\n    //--------------------------------------------------------------------------------------\n\n    struct IntParam\n    {\n        void Init(int val, int min, int max, int step)\n        {\n            Assert(val >= min && val <= max, \"Default value is outside the given bounds.\");\n            m_value = val;\n            m_min = min;\n            m_max = max;\n            m_stepSize = step;\n        }\n\n        int m_value;\n        int m_min;\n        int m_max;\n        int m_stepSize;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // EnumParam\n    //--------------------------------------------------------------------------------------\n\n    struct EnumParam\n    {\n        void Init(const char** vals, int n, int curr)\n        {\n            m_values = vals;\n            m_num = n;\n            m_curr = curr;\n        }\n\n        const char** m_values;\n        int m_num;\n        int m_curr;\n    };\n\n    static_assert(std::is_trivial_v<FloatParam>);\n    static_assert(std::is_trivial_v<Float3Param>);\n    static_assert(std::is_trivial_v<UnitDirParam>);\n    static_assert(std::is_trivial_v<ColorParam>);\n    static_assert(std::is_trivial_v<IntParam>);\n    static_assert(std::is_trivial_v<EnumParam>);\n\n\n    //--------------------------------------------------------------------------------------\n    // ParamVariant\n    //--------------------------------------------------------------------------------------\n\n    enum class PARAM_TYPE\n    {\n        PT_float,\n        PT_float2,\n        PT_float3,\n        PT_unit_dir,\n        PT_color,\n        PT_int,\n        PT_bool,\n        PT_enum\n    };\n\n    struct ParamVariant\n    {\n        static const int MAX_NAME_LEN = 32;\n        static const int MAX_GROUP_LEN = 16;\n        static const int MAX_SUBGROUP_LEN = 28;\n        static const int MAX_SUBSUBGROUP_LEN = 16;\n\n        void InitFloat(const char* group, const char* subgroup, const char* name, \n            fastdelegate::FastDelegate1<const ParamVariant&> dlg,\n            float val, float min, float max, float step, const char* subsubgroup = nullptr);\n        void InitInt(const char* group, const char* subgroup, const char* name, \n            fastdelegate::FastDelegate1<const ParamVariant&> dlg,\n            int val, int min, int max, int step, const char* subsubgroup = nullptr);\n        void InitFloat2(const char* group, const char* subgroup, const char* name, \n            fastdelegate::FastDelegate1<const ParamVariant&> dlg,\n            Math::float2 val, float min, float max, float step, const char* subsubgroup = nullptr);\n        void InitFloat3(const char* group, const char* subgroup, const char* name, \n            fastdelegate::FastDelegate1<const ParamVariant&> dlg,\n            Math::float3 val, float min, float max, float step, const char* subsubgroup = nullptr);\n        void InitUnitDir(const char* group, const char* subgroup, const char* name, \n            fastdelegate::FastDelegate1<const ParamVariant&> dlg,\n            float pitch, float yaw, const char* subsubgroup = nullptr);\n        void InitUnitDir(const char* group, const char* subgroup, const char* name, \n            fastdelegate::FastDelegate1<const ParamVariant&> dlg,\n            Math::float3 dir, const char* subsubgroup = nullptr);\n        void InitNormalizedFloat3(const char* group, const char* subgroup, const char* name, \n            fastdelegate::FastDelegate1<const ParamVariant&> dlg,\n            Math::float3 val, const char* subsubgroup = nullptr);\n        void InitColor(const char* group, const char* subgroup, const char* name, \n            fastdelegate::FastDelegate1<const ParamVariant&> dlg,\n            Math::float3 val, const char* subsubgroup = nullptr);\n        void InitBool(const char* group, const char* subgroup, const char* name, \n            fastdelegate::FastDelegate1<const ParamVariant&> dlg, bool val, \n            const char* subsubgroup = nullptr);\n        void InitEnum(const char* group, const char* subgroup, const char* name,\n            fastdelegate::FastDelegate1<const ParamVariant&> dlg, const char** enumVals, \n            int num, int curr, const char* subsubgroup = nullptr);\n\n        const char* GetGroup() const { return m_group; }\n        const char* GetSubGroup() const { return m_subgroup; }\n        const char* GetSubSubGroup() const { return m_subsubgroup; }\n        const char* GetName() const { return m_name; }\n        PARAM_TYPE GetType() const { return m_type; }\n        uint64_t ID() const { return m_id; }\n\n        const FloatParam& GetFloat() const;\n        void SetFloat(float v);\n\n        const Float2Param& GetFloat2() const;\n        void SetFloat2(const Math::float2& v);\n\n        const Float3Param& GetFloat3() const;\n        void SetFloat3(const Math::float3& v);\n\n        const UnitDirParam& GetUnitDir() const;\n        void SetUnitDir(float pitch, float yaw);\n\n        const Float3Param& GetColor() const;\n        void SetColor(const Math::float3& v);\n\n        const IntParam& GetInt() const;\n        void SetInt(int v);\n\n        bool GetBool() const;\n        void SetBool(bool v);\n\n        const EnumParam& GetEnum() const;\n        void SetEnum(int v);\n\n    private:\n        void InitCommon(const char* group, const char* subgroup, const char* subsubgroup, \n            const char* name, fastdelegate::FastDelegate1<const ParamVariant&> dlg);\n\n        fastdelegate::FastDelegate1<const ParamVariant&> m_dlg;\n        uint64_t m_id;\n        PARAM_TYPE m_type;\n        char m_group[MAX_GROUP_LEN];\n        char m_subgroup[MAX_SUBGROUP_LEN];\n        char m_subsubgroup[MAX_SUBSUBGROUP_LEN];\n        char m_name[MAX_NAME_LEN];\n\n        union\n        {\n            FloatParam m_float;\n            Float2Param m_float2;\n            Float3Param m_float3;\n            UnitDirParam m_unitDir;\n            IntParam m_int;\n            EnumParam m_enum;\n            bool m_bool;\n        };\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Support/Stat.h",
    "content": "#pragma once\n\n#include \"../Utility/Error.h\"\n#include \"../Math/Common.h\"\n\nnamespace ZetaRay::Support\n{\n    struct Stat\n    {\n        enum class ST_TYPE\n        {\n            ST_INT,\n            ST_UINT,\n            ST_FLOAT,\n            ST_UINT64,\n            ST_RATIO\n        };\n\n        Stat() = default;\n        Stat(const char* group, const char* name, int i)\n        {\n            InitCommon(group, name);\n            m_type = ST_TYPE::ST_INT;\n            m_int = i;\n        }\n        Stat(const char* group, const char* name, uint32_t u)\n        {\n            InitCommon(group, name);\n            m_type = ST_TYPE::ST_UINT;\n            m_uint = u;\n        }\n        Stat(const char* group, const char* name, float f)\n        {\n            InitCommon(group, name);\n            m_type = ST_TYPE::ST_FLOAT;\n            m_float = f;\n        }\n        Stat(const char* group, const char* name, uint64_t u)\n        {\n            InitCommon(group, name);\n            m_type = ST_TYPE::ST_UINT64;\n            m_uint64 = u;\n        }\n        Stat(const char* group, const char* name, uint32_t u, uint32_t total)\n        {\n            InitCommon(group, name);\n            m_type = ST_TYPE::ST_RATIO;\n            m_uint64 = ((uint64_t)u << 32) | total;\n        }\n\n        const char* GetGroup() { return m_group; }\n        const char* GetName() { return m_name; }\n        ST_TYPE GetType() { return m_type; }\n\n        int GetInt()\n        {\n            Assert(m_type == ST_TYPE::ST_INT, \"Invalid union type.\");\n            return m_int;\n        }\n\n        uint32_t GetUInt()\n        {\n            Assert(m_type == ST_TYPE::ST_UINT, \"Invalid union type.\");\n            return m_uint;\n        }\n\n        float GetFloat()\n        {\n            Assert(m_type == ST_TYPE::ST_FLOAT, \"Invalid union type.\");\n            return m_float;\n        }\n\n        uint64_t GetUInt64()\n        {\n            Assert(m_type == ST_TYPE::ST_UINT64, \"Invalid union type.\");\n            return m_uint64;\n        }\n\n        void GetRatio(uint32_t& num, uint32_t& total)\n        {\n            Assert(m_type == ST_TYPE::ST_RATIO, \"Invalid union type.\");\n            num = m_uint64 >> 32;\n            total = m_uint64 & 0xffffffff;\n        }\n\n    private:\n        void InitCommon(const char* group, const char* name)\n        {\n            Assert(group, \"Group can't be NULL\");\n            Assert(name, \"Name can't be NULL\");\n\n            auto ng = Math::Min(GROUP_LEN - 1, strlen(group));\n            auto nn = Math::Min(NAME_LEN - 1, strlen(name));\n\n            memcpy(m_group, group, ng);\n            m_group[ng] = '\\0';\n\n            memcpy(m_name, name, nn);\n            m_name[nn] = '\\0';\n\n            //char temp[GROUP_LEN + NAME_LEN];\n            //memcpy(temp, m_group, ng);\n            //memcpy(temp + ng, m_name, nn);\n\n            //m_id = XXH3_64bits(temp, ng + nn);\n        }\n\n        static constexpr size_t GROUP_LEN = 16;\n        static constexpr size_t NAME_LEN = 32;\n\n        char m_group[GROUP_LEN];\n        char m_name[NAME_LEN];\n        ST_TYPE m_type;\n\n        union\n        {\n            int m_int;\n            uint32_t m_uint;\n            float m_float;\n            uint64_t m_uint64;\n        };\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Support/Task.cpp",
    "content": "#include \"Task.h\"\n#include \"../App/Timer.h\"\n#include <intrin.h>\n\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Math;\n\n//--------------------------------------------------------------------------------------\n// Task\n//--------------------------------------------------------------------------------------\n\nTask::Task(const char* name, TASK_PRIORITY priority, Function&& f)\n    : m_dlg(ZetaMove(f)),\n    m_priority(priority)\n{\n    if(m_priority == TASK_PRIORITY::NORMAL)\n        m_signalHandle = App::RegisterTask();\n}\n\nTask::Task(Task&& other)\n    : m_dlg(ZetaMove(other.m_dlg)),\n    m_signalHandle(other.m_signalHandle),\n    m_indegree(other.m_indegree),\n    m_priority(other.m_priority)\n{\n    //m_adjacentTailNodes.swap(other.m_adjacentTailNodes);\n    m_adjacentTailNodes = ZetaMove(other.m_adjacentTailNodes);\n    other.m_adjacentTailNodes.clear();\n\n    other.m_indegree = 0;\n    other.m_signalHandle = -1;\n}\n\nTask& Task::operator=(Task&& other)\n{\n    if (this == &other)\n        return *this;\n\n    //m_adjacentTailNodes.swap(other.m_adjacentTailNodes);\n    m_adjacentTailNodes = ZetaMove(other.m_adjacentTailNodes);\n    other.m_adjacentTailNodes.clear();\n\n    m_dlg = ZetaMove(other.m_dlg);\n    m_indegree = other.m_indegree;\n    m_signalHandle = other.m_signalHandle;\n    m_priority = other.m_priority;\n    other.m_indegree = 0;\n    other.m_signalHandle = -1;\n\n    return *this;\n}\n\nvoid Task::Reset(const char* name, TASK_PRIORITY priority, Function&& f)\n{\n    Assert(m_signalHandle == -1, \"Reinitialization is not allowed.\");\n\n    m_priority = priority;\n    m_indegree = 0;\n    m_dlg = ZetaMove(f);\n\n    if(m_priority == TASK_PRIORITY::NORMAL)\n        m_signalHandle = App::RegisterTask();\n}\n\n//--------------------------------------------------------------------------------------\n// TaskSet\n//--------------------------------------------------------------------------------------\n\nvoid TaskSet::AddOutgoingEdge(TaskHandle a, TaskHandle b)\n{\n    Assert(a < m_currSize && b < m_currSize, \"Invalid task handles.\");\n    TaskMetadata& ta = m_taskMetadata[a];\n    TaskMetadata& tb = m_taskMetadata[b];\n\n    bool prev1 = _bittestandset((long*)&ta.SuccessorMask, b);\n    Assert(!prev1, \"Redundant call, edge already exists.\");\n\n    bool prev2 = _bittestandset((long*)&tb.PredecessorMask, a);\n    Assert(!prev2, \"Redundant call, edge already exists.\");\n\n    m_tasks[a].m_adjacentTailNodes.push_back(m_tasks[b].m_signalHandle);\n}\n\nvoid TaskSet::AddOutgoingEdgeToAll(TaskHandle a)\n{\n    Assert(a < m_currSize, \"Invalid task handle.\");\n    TaskMetadata& ta = m_taskMetadata[a];\n\n    for (int b = 0; b < m_currSize; b++)\n    {\n        if (b == a)\n            continue;\n\n        TaskMetadata& tb = m_taskMetadata[b];\n        ta.SuccessorMask |= (1 << b);\n        tb.PredecessorMask |= (1 << a);\n\n        m_tasks[a].m_adjacentTailNodes.push_back(m_tasks[b].m_signalHandle);\n    }\n}\n\nvoid TaskSet::AddIncomingEdgeFromAll(TaskHandle a)\n{\n    Assert(a < m_currSize, \"Invalid task handle.\");\n    TaskMetadata& ta = m_taskMetadata[a];\n\n    for (int b = 0; b < m_currSize; b++)\n    {\n        if (b == a)\n            continue;\n\n        TaskMetadata& tb = m_taskMetadata[b];\n        ta.PredecessorMask |= (1 << b);\n        tb.SuccessorMask |= (1 << a);\n\n        m_tasks[b].m_adjacentTailNodes.push_back(m_tasks[a].m_signalHandle);\n    }\n}\n\nvoid TaskSet::Sort()\n{\n    Assert(!m_isSorted, \"TaskSet is already sorted.\");\n    TopologicalSort();\n    ComputeInOutMask();\n\n    m_isSorted = true;\n}\n\nvoid TaskSet::Finalize(WaitObject* waitObj)\n{\n    Assert(!m_isFinalized && m_isSorted, \"Finalize() shouldn't be called when TaskSet hasn't been sorted.\");\n\n    for (int i = 0; i < m_currSize; i++)\n    {\n        const int indegree = m_taskMetadata[i].Indegree();\n\n        // Dependencies between TaskSets can't be detected by indegree as those only\n        // for dependencies inside the TaskSet\n        if (indegree > 0 || m_tasks[i].m_indegree > 0)\n        {\n            // Dependencies between TaskSets only increase the indegree\n            // for root nodes (which have indegree of 0 inside the taskset)\n            Assert(indegree * m_tasks[i].m_indegree == 0, \"bug\");\n            m_tasks[i].m_indegree = Max(indegree, m_tasks[i].m_indegree);\n\n            // Only need to register tasks that have indegree > 0\n            App::TaskFinalizedCallback(m_tasks[i].m_signalHandle, m_tasks[i].m_indegree);\n        }\n    }\n\n    m_isFinalized = true;\n\n    if (waitObj)\n    {\n        Assert(m_currSize < MAX_NUM_TASKS, \"Out of space for new tasks in this TaskSet.\");\n        m_tasks[m_currSize++].Reset(\"NotifyCompletion\", m_tasks[0].m_priority, [waitObj]()\n            {\n                waitObj->Notify();\n            });\n\n        // ConnectTo(m_tasks[m_currSize]);\n        Task& notifyTask = m_tasks[m_currSize - 1];\n        uint64_t mask = m_leafMask;\n        notifyTask.m_indegree += __popcnt((uint32_t)mask);\n\n        unsigned long idx;\n        while (_BitScanForward64(&idx, mask))\n        {\n            Assert(idx < m_currSize, \"Bug\");\n            m_tasks[idx].m_adjacentTailNodes.push_back(notifyTask.m_signalHandle);\n\n            mask &= ~(1llu << idx);\n        }\n\n        App::TaskFinalizedCallback(notifyTask.m_signalHandle, notifyTask.m_indegree);\n    }\n}\n\nvoid TaskSet::ComputeInOutMask()\n{\n    for (int i = 0; i < m_currSize; ++i)\n    {\n        if (m_taskMetadata[i].Indegree() == 0)\n            m_rootMask |= (1llu << i);\n\n        if (m_taskMetadata[i].Outdegree() == 0)\n            m_leafMask |= (1llu << i);\n    }\n}\n\nvoid TaskSet::TopologicalSort()\n{\n    // Find the root nodes\n    uint32_t rootMask = 0;\n\n    for (int i = 0; i < m_currSize; ++i)\n    {\n        if (m_taskMetadata[i].Indegree() == 0)\n            rootMask |= (1llu << i);\n    }\n\n    // In each iteration, points to remaining elements that have an indegree of zero\n    uint32_t currMask = rootMask;\n    size_t currIdx = 0;\n    int sorted[MAX_NUM_TASKS];\n\n    // Make a temporary copy for the duration of topological sorting\n    int tempIndegree[MAX_NUM_TASKS];\n    for (int i = 0; i < m_currSize; i++)\n        tempIndegree[i] = m_taskMetadata[i].Indegree();\n\n    // Find all nodes with zero indegree\n    unsigned long zeroIndegreeIdx;\n    while (_BitScanForward64(&zeroIndegreeIdx, currMask))\n    {\n        Assert(zeroIndegreeIdx < m_currSize, \"Invalid index.\");\n        TaskMetadata& t = m_taskMetadata[zeroIndegreeIdx];\n        uint32_t tails = t.SuccessorMask;\n        unsigned long tailIdx;\n\n        // For every tail-adjacent node\n        while (_BitScanForward64(&tailIdx, tails))\n        {\n            Assert(tailIdx < m_currSize, \"Invalid index.\");\n\n            // Remove one edge\n            tempIndegree[tailIdx] -= 1;\n\n            // If tail node's indegree has become 0, add it to mask\n            if (tempIndegree[tailIdx] == 0)\n                currMask |= (1 << tailIdx);\n\n            tails &= ~(1 << tailIdx);\n        }\n\n        // Save new position for current node\n        sorted[currIdx++] = zeroIndegreeIdx;\n\n        // Remove current node\n        currMask &= ~(1 << zeroIndegreeIdx);\n    }\n\n    Assert(currIdx == m_currSize, \"Graph has a cycle.\");\n\n    for (int i = 0; i < m_currSize; i++)\n        Assert(tempIndegree[i] == 0, \"Graph has a cycle.\");\n\n    Task oldTaskArr[MAX_NUM_TASKS];\n    for (int i = 0; i < m_currSize; i++)\n        oldTaskArr[i] = ZetaMove(m_tasks[i]);\n\n    TaskMetadata oldTaskMetadata[MAX_NUM_TASKS];\n    memcpy(oldTaskMetadata, m_taskMetadata, m_currSize * sizeof(TaskMetadata));\n\n    for (int i = 0; i < m_currSize; i++)\n    {\n        m_tasks[i] = ZetaMove(oldTaskArr[sorted[i]]);\n        m_taskMetadata[i] = oldTaskMetadata[sorted[i]];\n    }\n}\n\nvoid TaskSet::ConnectTo(TaskSet& other)\n{\n    Assert(!m_isFinalized, \"Calling this method on a finalized TaskSet is invalid.\");\n    Assert(!other.m_isFinalized, \"Calling this method on a finalized TaskSet is invalid.\");\n\n    uint64_t headMask = m_leafMask;\n    const uint64_t tailMask = other.m_rootMask;\n\n    // Connect every leaf of this TaskSet to every root of \"other\"\n    unsigned long headIdx;\n    while (_BitScanForward64(&headIdx, headMask))\n    {\n        Assert(headIdx < m_currSize, \"Bug\");\n        Assert(m_tasks[headIdx].m_adjacentTailNodes.empty(), \"Leaf task should not have tail nodes.\");\n        m_tasks[headIdx].m_adjacentTailNodes.reserve(__popcnt16(other.m_rootMask));\n\n        unsigned long tailIdx;\n        uint64_t tailMaskCopy = tailMask;\n        while (_BitScanForward64(&tailIdx, tailMaskCopy))\n        {\n            Assert(tailIdx < other.m_currSize, \"Index out of bound.\");\n\n            // Add one edge\n            other.m_tasks[tailIdx].m_indegree += 1;\n            m_tasks[headIdx].m_adjacentTailNodes.push_back(other.m_tasks[tailIdx].m_signalHandle);\n\n            tailMaskCopy &= ~(1llu << tailIdx);\n        }\n\n        headMask &= ~(1llu << headIdx);\n    }\n}\n\nvoid TaskSet::ConnectTo(Task& other)\n{\n    Assert(!m_isFinalized, \"Calling this method on a finalized TaskSet is invalid.\");\n\n    uint64_t mask = m_leafMask;\n\n    unsigned long idx;\n    while (_BitScanForward64(&idx, mask))\n    {\n        Assert(idx < m_currSize, \"Bug\");\n        m_tasks[idx].m_adjacentTailNodes.push_back(other.m_signalHandle);\n\n        mask &= ~(1llu << idx);\n    }\n\n    other.m_indegree += __popcnt((uint32_t)mask);\n}\n\nvoid TaskSet::ConnectFrom(Task& other)\n{\n    Assert(!m_isFinalized, \"Calling this method on a finalized TaskSet is invalid.\");\n\n    uint64_t mask = m_rootMask;\n\n    unsigned long idx;\n    while (_BitScanForward64(&idx, mask))\n    {\n        Assert(idx < m_currSize, \"Invalid index.\");\n        m_tasks[idx].m_indegree += 1;\n        other.m_adjacentTailNodes.push_back(m_tasks[idx].m_signalHandle);\n\n        mask &= ~(1llu << idx);\n    }\n}"
  },
  {
    "path": "Source/ZetaCore/Support/Task.h",
    "content": "#pragma once\n\n#include \"../Utility/Span.h\"\n#include \"../Utility/Function.h\"\n#include \"../App/App.h\"\n#include <atomic>\n\nnamespace ZetaRay::Support\n{\n    enum class TASK_PRIORITY\n    {\n        NORMAL,\n        BACKGROUND\n    };\n\n    //--------------------------------------------------------------------------------------\n    // Task\n    //--------------------------------------------------------------------------------------\n\n    struct TaskSet;\n\n    struct alignas(64) Task\n    {\n        friend struct TaskSet;\n        static constexpr int MAX_NAME_LENGTH = 64;\n\n        Task() = default;\n        Task(const char* name, TASK_PRIORITY priority, Util::Function&& f);\n        ~Task() = default;\n        Task(Task&&);\n        Task& operator=(Task&&);\n\n        void Reset(const char* name, TASK_PRIORITY priority, Util::Function&& f);\n        ZetaInline int GetSignalHandle() const { return m_signalHandle; }\n        ZetaInline Util::Span<int> GetAdjacencies() { return Util::Span(m_adjacentTailNodes); }\n        ZetaInline TASK_PRIORITY GetPriority() const { return m_priority; }\n\n        ZetaInline void DoTask()\n        {\n            Assert(m_dlg.IsSet(), \"Attempting to run an empty Function.\");\n            m_dlg.Run();\n        }\n\n    private:\n        Util::Function m_dlg;\n        Util::SmallVector<int, App::FrameAllocator, 3> m_adjacentTailNodes;\n        int m_signalHandle = -1;\n        int m_indegree = 0;\n        TASK_PRIORITY m_priority;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // WaitObject\n    //--------------------------------------------------------------------------------------\n\n    struct WaitObject\n    {\n        void Notify()\n        {\n            m_completionFlag.store(true, std::memory_order_release);\n            m_completionFlag.notify_one();\n        }\n        void Wait()\n        {\n            m_completionFlag.wait(false, std::memory_order_acquire);\n        }\n        void Reset()\n        {\n            m_completionFlag.store(false, std::memory_order_release);\n        }\n\n    private:\n        std::atomic_bool m_completionFlag = false;\n    };\n\n    //--------------------------------------------------------------------------------------\n    // TaskSet\n    //--------------------------------------------------------------------------------------\n\n    // Intended for usage by a single thread.\n    // \n    // Usage:\n    // \n    // 1. Add Tasks (EmplaceTask())\n    // 2. Add intra-TaskSet edges (AddOutgoingEdge())\n    // 3. Sort\n    // 4. (Optional) Connect different TaskSets\n    // 5. Finalize\n    struct TaskSet\n    {\n        static constexpr int MAX_NUM_TASKS = 16;\n        using TaskHandle = int;\n        static constexpr TaskHandle INVALID_TASK_HANDLE = -1;\n\n        TaskSet() = default;\n        ~TaskSet() = default;\n\n        TaskSet(const TaskSet&) = delete;\n        TaskSet& operator=(const TaskSet&) = delete;\n\n        TaskHandle EmplaceTask(const char* name, Util::Function&& f)\n        {\n            Assert(!m_isFinalized, \"Calling AddTask() on an unfinalized TaskSet is not allowed.\");\n            Assert(m_currSize < MAX_NUM_TASKS, \n                \"Current implementation doesn't support more than %d tasks.\", MAX_NUM_TASKS);\n\n            // TaskSet is not needed for background tasks\n            m_tasks[m_currSize++].Reset(name, TASK_PRIORITY::NORMAL, ZetaMove(f));\n\n            return (TaskHandle)(m_currSize - 1);\n        }\n\n        // Adds a dependent task to the list of tasks that are notified by this task upon completion\n        void AddOutgoingEdge(TaskHandle a, TaskHandle b);\n        // Adds an edge from the given task to every other task that is currently is the TaskSet\n        void AddOutgoingEdgeToAll(TaskHandle a);\n        void AddIncomingEdgeFromAll(TaskHandle a);\n        void ConnectTo(TaskSet& other);\n        void ConnectTo(Task& other);\n        void ConnectFrom(Task& other);\n\n        ZetaInline bool IsFinalized() { return m_isFinalized; }\n        void Sort();\n        void Finalize(WaitObject* waitObj = nullptr);\n        ZetaInline int GetSize() { return m_currSize; }\n        ZetaInline Util::MutableSpan<Task> GetTasks() { return Util::MutableSpan(m_tasks, m_currSize); }\n\n    private:\n        struct TaskMetadata\n        {\n            ZetaInline int Indegree() const { return __popcnt16(PredecessorMask); }\n            ZetaInline int Outdegree() const { return __popcnt16(SuccessorMask); }\n\n            // Index of adjacent tasks (i.e. this task has an edge to them)\n            uint16_t SuccessorMask = 0;\n\n            // Index of predecessor tasks (i.e. have an edge to this task)\n            uint16_t PredecessorMask = 0;\n        };\n\n        void ComputeInOutMask();\n        void TopologicalSort();\n\n        Task m_tasks[MAX_NUM_TASKS];\n        TaskMetadata m_taskMetadata[MAX_NUM_TASKS];\n\n        uint16_t m_rootMask = 0;\n        uint16_t m_leafMask = 0;\n        uint8_t m_currSize = 0;\n        bool m_isSorted = false;\n        bool m_isFinalized = false;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Support/ThreadPool.cpp",
    "content": "#include \"ThreadPool.h\"\n#include \"../App/Log.h\"\n\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::App;\nusing namespace ZetaRay::Util;\n\n//--------------------------------------------------------------------------------------\n// ThreadPool\n//--------------------------------------------------------------------------------------\n\nvoid ThreadPool::Init(int poolSize, int totalNumThreads, const wchar_t* threadNamePrefix, \n    THREAD_PRIORITY priority, int threadIdxOffset)\n{\n    m_threadPoolSize = poolSize;\n    m_totalNumThreads = totalNumThreads;\n\n    // Tokens below have to conisder that threads outside this thread pool\n    // (e.g. the main thread) may also insert tasks and occasionally execute \n    // tasks (for example when trying to pump the queue to empty it)\n\n    // Consumers\n    {\n        // +1 for main therad\n        uintptr_t curr = reinterpret_cast<uintptr_t>(m_consumerTokensMem);\n        for (int i = 0; i < m_totalNumThreads; i++)\n        {\n            new (reinterpret_cast<void*>(curr)) moodycamel::ConsumerToken(m_taskQueue);\n            curr += sizeof(moodycamel::ConsumerToken);\n        }\n\n        m_consumerTokens = reinterpret_cast<moodycamel::ConsumerToken*>(m_consumerTokensMem);\n    }\n\n    // Producers\n    {\n        // +1 for main therad\n        uintptr_t curr = reinterpret_cast<uintptr_t>(m_producerTokensMem);\n        for (int i = 0; i < m_totalNumThreads; i++)\n        {\n            new (reinterpret_cast<void*>(curr)) moodycamel::ProducerToken(m_taskQueue);\n            curr += sizeof(moodycamel::ProducerToken);\n        }\n\n        m_producerTokens = reinterpret_cast<moodycamel::ProducerToken*>(m_producerTokensMem);\n    }\n\n    for (int i = 0; i < m_threadPoolSize; i++)\n    {\n        // g_threadIdx needs to be unique for all threads - threadIdxOffset is used\n        // to account for other threads\n        m_threadPool[i] = std::thread(&ThreadPool::WorkerThread, this, threadIdxOffset + i);\n\n        wchar_t buffer[32];\n        //swprintf(buff, L\"ZetaWorker_%d\", i);\n        swprintf(buffer, L\"%ls_%d\", threadNamePrefix, i);\n        App::SetThreadDesc(m_threadPool[i].native_handle(), buffer);\n\n        App::SetThreadPriority(m_threadPool[i].native_handle(), priority);\n    }\n}\n\nvoid ThreadPool::Start()\n{\n    m_start.store(true, std::memory_order_release);\n}\n\nvoid ThreadPool::Shutdown()\n{\n    // Relaxed since Enqueue has a release op\n    m_shutdown.store(true, std::memory_order_relaxed);\n\n    // Upon observing shutdown flag to be true, all the threads are going to exit\n\n    for (int i = 0; i < m_threadPoolSize; i++)\n    {\n        Task t(\"NoOp\", TASK_PRIORITY::NORMAL, []() {});\n        Enqueue(ZetaMove(t));\n    }\n\n    for (int i = 0; i < m_threadPoolSize; i++)\n        m_threadPool[i].join();\n}\n\nvoid ThreadPool::Enqueue(Task&& task)\n{\n    bool memAllocFailed = m_taskQueue.enqueue(m_producerTokens[g_threadIdx], ZetaMove(task));\n    Assert(memAllocFailed, \"moodycamel::ConcurrentQueue couldn't allocate memory.\");\n\n    m_numTasksToFinishTarget.fetch_add(1, std::memory_order_relaxed);\n    m_numTasksInQueue.fetch_add(1, std::memory_order_release);\n}\n\nvoid ThreadPool::Enqueue(TaskSet&& ts)\n{\n    Assert(ts.IsFinalized(), \"Given TaskSet is not finalized.\");\n\n    m_numTasksToFinishTarget.fetch_add(ts.GetSize(), std::memory_order_relaxed);\n    m_numTasksInQueue.fetch_add(ts.GetSize(), std::memory_order_release);\n    auto tasks = ts.GetTasks();\n\n    bool memAllocFailed = m_taskQueue.enqueue_bulk(m_producerTokens[g_threadIdx],\n        std::make_move_iterator(tasks.data()), tasks.size());\n    Assert(memAllocFailed, \"moodycamel::ConcurrentQueue couldn't allocate memory.\");\n}\n\nvoid ThreadPool::PumpUntilEmpty()\n{\n    Task task;\n\n    // \"try_dequeue()\" returning false doesn't guarantee that queue is empty\n    while (m_numTasksInQueue.load(std::memory_order_acquire) != 0)\n    {\n        if (m_taskQueue.try_dequeue(m_consumerTokens[g_threadIdx], task))\n        {\n            m_numTasksInQueue.fetch_sub(1, std::memory_order_relaxed);\n\n            const int taskHandle = task.GetSignalHandle();\n\n            // Block if this task depends on other unfinished tasks\n            App::WaitForAdjacentHeadNodes(taskHandle);\n\n            task.DoTask();\n\n            // Signal dependent tasks that this task has finished\n            auto adjacencies = task.GetAdjacencies();\n            if (adjacencies.size() > 0)\n                App::SignalAdjacentTailNodes(adjacencies);\n\n            m_numTasksFinished.fetch_add(1, std::memory_order_release);\n        }\n    }\n}\n\nbool ThreadPool::TryFlush()\n{\n    const bool success = m_numTasksFinished.load(std::memory_order_acquire) == \n        m_numTasksToFinishTarget.load(std::memory_order_acquire);\n    if (!success)\n    {\n        PumpUntilEmpty();\n    }\n    else\n    {\n        // Reset the counters\n        m_numTasksFinished.store(0, std::memory_order_relaxed);\n        m_numTasksToFinishTarget.store(0, std::memory_order_relaxed);\n    }\n\n    return success;\n}\n\nvoid ThreadPool::WorkerThread(int idx)\n{\n    Assert(g_threadIdx == -1, \"Two or more threads have the same global index.\");\n    g_threadIdx = idx;\n\n    while (!m_start.load(std::memory_order_acquire)) {}\n\n    LOG_UI(INFO, \"Thread %d waiting for tasks...\\n\", g_threadIdx);\n\n    while (true)\n    {\n        Task task;\n\n        // Exit\n        if (m_shutdown.load(std::memory_order_acquire))\n            break;\n\n        // block if there aren't any tasks\n        m_taskQueue.wait_dequeue(m_consumerTokens[g_threadIdx], task);\n        m_numTasksInQueue.fetch_sub(1, std::memory_order_acquire);\n\n        const int taskHandle = task.GetSignalHandle();\n\n        // Block if this task has unfinished dependencies\n        if(task.GetPriority() != TASK_PRIORITY::BACKGROUND)\n            App::WaitForAdjacentHeadNodes(taskHandle);\n\n        task.DoTask();\n\n        // Signal dependent tasks that this task has finished\n        if (task.GetPriority() != TASK_PRIORITY::BACKGROUND)\n        {\n            auto adjacencies = task.GetAdjacencies();\n            if (adjacencies.size() > 0)\n                App::SignalAdjacentTailNodes(adjacencies);\n        }\n\n        m_numTasksFinished.fetch_add(1, std::memory_order_release);\n    }\n\n    LOG_UI(INFO, \"Thread %d exiting...\\n\", g_threadIdx);\n}\n"
  },
  {
    "path": "Source/ZetaCore/Support/ThreadPool.h",
    "content": "#pragma once\n\n#include \"Task.h\"\n#include \"concurrentqueue/blockingconcurrentqueue.h\"\n\nnamespace ZetaRay::Support\n{\n    class ThreadPool\n    {\n    public:\n        ThreadPool() = default;\n        ~ThreadPool() = default;\n        ThreadPool(const ThreadPool&) = delete;\n        ThreadPool& operator=(const ThreadPool&) = delete;\n\n        void Init(int poolSize, int totalNumThreads, const wchar_t* threadNamePrefix, \n            App::THREAD_PRIORITY priority, int threadIdxOffset);\n        void Start();\n        void Shutdown();\n\n        void Enqueue(TaskSet&& ts);\n        void Enqueue(Task&& t);\n\n        // The calling thread dequeues task until task queue becomes empty\n        void PumpUntilEmpty();\n        // Waits until all tasks are finished (!= empty queue)\n        bool TryFlush();\n\n        ZetaInline bool AreAllTasksFinished() const\n        {\n            const bool isEmpty = m_numTasksFinished.load(std::memory_order_acquire) == \n                m_numTasksToFinishTarget.load(std::memory_order_acquire);\n            return isEmpty;\n        }\n\n        ZetaInline int ThreadPoolSize() const { return m_threadPoolSize; }\n\n    private:\n        void WorkerThread(int idx);\n\n        int m_threadPoolSize;\n        int m_totalNumThreads;\n        std::atomic_int32_t m_numTasksInQueue = 0;\n        std::atomic_int32_t m_numTasksFinished = 0;\n        std::atomic_int32_t m_numTasksToFinishTarget = 0;\n\n        std::thread m_threadPool[MAX_NUM_THREADS];\n\n        // Concurrent task queue\n        // Source: https://github.com/cameron314/concurrentqueue\n        struct MyTraits : public moodycamel::ConcurrentQueueDefaultTraits\n        {\n            static const size_t BLOCK_SIZE = 256;\n        };\n\n        moodycamel::BlockingConcurrentQueue<Task, MyTraits> m_taskQueue;\n\n        alignas(alignof(moodycamel::ProducerToken)) uint8_t m_producerTokensMem[\n            sizeof(moodycamel::ProducerToken) * MAX_NUM_THREADS];\n        moodycamel::ProducerToken* m_producerTokens;\n\n        alignas(alignof(moodycamel::ConsumerToken)) uint8_t m_consumerTokensMem[\n            sizeof(moodycamel::ConsumerToken) * MAX_NUM_THREADS];\n        moodycamel::ConsumerToken* m_consumerTokens;\n\n        std::atomic_bool m_start = false;\n        std::atomic_bool m_shutdown = false;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Utility/CMakeLists.txt",
    "content": "set(UTIL_DIR \"${ZETA_CORE_DIR}/Utility\")\nset(UTIL_SRC\n    \"${UTIL_DIR}/Error.cpp\"\n    \"${UTIL_DIR}/Error.h\"\n    \"${UTIL_DIR}/Function.h\"\n    \"${UTIL_DIR}/HashTable.h\"\n    \"${UTIL_DIR}/Optional.h\"\n    \"${UTIL_DIR}/RNG.h\"\n    \"${UTIL_DIR}/SmallVector.h\"\n    \"${UTIL_DIR}/Span.h\"\n    \"${UTIL_DIR}/SynchronizedView.h\"\n    \"${UTIL_DIR}/Utility.h\")\nset(UTIL_SRC ${UTIL_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaCore/Utility/Error.cpp",
    "content": "#define STB_SPRINTF_IMPLEMENTATION\n\n#include \"Error.h\"\n#include \"Span.h\"\n#include \"../Win32/Win32.h\"\n#include \"../Support/MemoryArena.h\"\n\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Support;\n\n// Ref: https://gist.github.com/rioki/85ca8295d51a5e0b7c56e5005b0ba8b4\n//\n// Debug Helpers\n// \n// Copyright (c) 2015 - 2017 Sean Farrell <sean.farrell@rioki.org>\n// \n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n// \n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n// \n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n// \n\n#ifndef NDEBUG\n\n#include <dbghelp.h>\n#include <string>\n#include \"../App/Log.h\"\n\n#define DBG_TRACE(MSG, ...)  dbg::trace(MSG, __VA_ARGS__)\n\n#define BUFF_SIZE 2048\n#define MAX_NUM_STACK_FRAMES 16llu\n\nnamespace dbg\n{\n    //void trace(const char* msg, ...)\n    //{\n    //    char buff[1024];\n\n    //    va_list args;\n    //    va_start(args, msg);\n    //    vsnprintf(buff, 1024, msg, args);\n\n    //    OutputDebugStringA(buff);\n\n    //    va_end(args);\n    //}\n\n    std::string basename(const std::string& file)\n    {\n        size_t i = file.find_last_of(\"\\\\/\");\n        if (i == std::string::npos)\n            return file;\n        else\n            return file.substr(i + 1);\n    }\n\n    struct StackFrame\n    {\n        DWORD64 address;\n        std::string name;\n        std::string module;\n        unsigned int line;\n        std::string file;\n    };\n\n    void stack_trace(Vector<StackFrame, ArenaAllocator>& frames)\n    {\n        DWORD machine = IMAGE_FILE_MACHINE_AMD64;\n        HANDLE process = GetCurrentProcess();\n        HANDLE thread = GetCurrentThread();\n\n        if (SymInitialize(process, NULL, TRUE) == FALSE)\n        {\n            LOG_CONSOLE(\"%s: Failed to call SymInitialize.\", __func__);\n            return;\n        }\n\n        SymSetOptions(SYMOPT_LOAD_LINES);\n\n        CONTEXT context = {};\n        context.ContextFlags = CONTEXT_FULL;\n        RtlCaptureContext(&context);\n\n        STACKFRAME frame = {};\n        frame.AddrPC.Offset = context.Rip;\n        frame.AddrPC.Mode = AddrModeFlat;\n        frame.AddrFrame.Offset = context.Rbp;\n        frame.AddrFrame.Mode = AddrModeFlat;\n        frame.AddrStack.Offset = context.Rsp;\n        frame.AddrStack.Mode = AddrModeFlat;\n\n        bool first = true;\n\n        while (StackWalk(machine, process, thread, &frame, &context, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL))\n        {\n            StackFrame f = {};\n            f.address = frame.AddrPC.Offset;\n\n            DWORD64 moduleBase = 0;\n\n            moduleBase = SymGetModuleBase(process, frame.AddrPC.Offset);\n\n            char moduleBuff[MAX_PATH];\n            if (moduleBase && GetModuleFileNameA((HINSTANCE)moduleBase, moduleBuff, MAX_PATH))\n                f.module = basename(moduleBuff);\n            else\n                f.module = \"Unknown Module\";\n\n            DWORD64 offset = 0;\n\n            char symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 255];\n            PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL)symbolBuffer;\n            symbol->SizeOfStruct = (sizeof(IMAGEHLP_SYMBOL)) + 255;\n            symbol->MaxNameLength = 254;\n\n            if (SymGetSymFromAddr(process, frame.AddrPC.Offset, &offset, symbol))\n                f.name = symbol->Name;\n            else\n            {\n                DWORD error = GetLastError();\n                LOG_CONSOLE(\"%s: Failed to resolve address 0x%llX: %lu\\n\", __func__, frame.AddrPC.Offset, error);\n                f.name = \"Unknown Function\";\n            }\n\n            IMAGEHLP_LINE line;\n            line.SizeOfStruct = sizeof(IMAGEHLP_LINE);\n\n            DWORD offset_ln = 0;\n            if (SymGetLineFromAddr(process, frame.AddrPC.Offset, &offset_ln, &line))\n            {\n                f.file = line.FileName;\n                f.line = line.LineNumber;\n            }\n            else\n            {\n                DWORD error = GetLastError();\n                LOG_CONSOLE(\"%s: Failed to resolve line for 0x%llX: %lu\\n\", __func__, frame.AddrPC.Offset, error);\n                f.line = 0;\n            }\n\n            if (!first)\n                frames.push_back(f);\n\n            first = false;\n\n            if (frames.size() >= MAX_NUM_STACK_FRAMES)\n                break;\n        }\n\n        SymCleanup(process);\n    }\n\n    void fail(MutableSpan<char> buff, const char* msg)\n    {\n        int curr = stbsp_snprintf(buff.data(), (int)buff.size(), \"%s\\n\\n\", msg);\n        size_t bytesLeft = buff.size() - curr;\n        if (bytesLeft <= 0)\n            return;\n\n        MemoryArena ma(1024 * 8);\n        ArenaAllocator aa(ma);\n\n        SmallVector<StackFrame, ArenaAllocator> stack(aa);\n        stack_trace(stack);\n\n        curr += stbsp_snprintf(buff.data() + curr, (int)bytesLeft, \"Callstack: \\n\");\n        bytesLeft = BUFF_SIZE - curr;\n        if (bytesLeft <= 0)\n            return;\n\n        for (auto i = 0; i < std::min(stack.size(), MAX_NUM_STACK_FRAMES); i++)\n        {\n            if (stack[i].name.starts_with(\"dbg::fail\"))\n                continue;\n\n            else if (stack[i].name.starts_with(\"ZetaRay::Util::ReportError\"))\n                continue;\n\n            curr += stbsp_snprintf(buff.data() + curr, (int)bytesLeft, \" - 0x%x: %s(%d) in %s\\n\",\n                stack[i].address, stack[i].name.c_str(), stack[i].line, stack[i].module.c_str());\n\n            bytesLeft = BUFF_SIZE - curr;\n\n            if (bytesLeft <= 0)\n                return;\n        }\n    }\n}\n#endif\n\n\nvoid ZetaRay::Util::ReportError(const char* title, const char* msg)\n{\n#ifndef NDEBUG\n    char buff[BUFF_SIZE];\n\n    dbg::fail(buff, msg);\n    MessageBoxA(nullptr, buff, title, MB_ICONERROR | MB_OK);\n#else\n    MessageBoxA(nullptr, msg, title, MB_ICONERROR | MB_OK);\n#endif\n}\n\nvoid ZetaRay::Util::ReportErrorWin32(const char* file, int line, const char* call)\n{\n    char msg[256];\n    stbsp_snprintf(msg, 256, \"%s: %d\\nPredicate: %s\\nError code: %d\", file, line, call, GetLastError());\n\n#ifndef NDEBUG\n    char buff[BUFF_SIZE];\n    dbg::fail(buff, msg);\n    MessageBoxA(nullptr, buff, \"Win32 call failed\", MB_ICONERROR | MB_OK);\n#else\n    MessageBoxA(nullptr, msg, \"Win32 call failed\", MB_ICONERROR | MB_OK);\n#endif\n}\n\nvoid ZetaRay::Util::DebugBreak()\n{\n    __debugbreak();\n}\n\nvoid ZetaRay::Util::Exit()\n{\n    exit(EXIT_FAILURE);\n}\n"
  },
  {
    "path": "Source/ZetaCore/Utility/Error.h",
    "content": "#pragma once\n\n#include \"../App/ZetaRay.h\"\n#include <stb/stb_sprintf.h>\n\n//--------------------------------------------------------------------------------------\n// Stack-allocated string with a maximum size\n//--------------------------------------------------------------------------------------\n\n// Note: stbsp_snprintf always returns a zero-terminated string.\n\n#ifndef NDEBUG\n#define StackStr(buffName, lenName, formatStr, ...)                         \\\n    char buffName[512];                                                     \\\n    int lenName = stbsp_snprintf(buffName, 512, formatStr, __VA_ARGS__);    \n#else\n#define StackStr(buffName, lenName, formatStr, ...)                         \\\n    char buffName[512];                                                     \\\n    int lenName = stbsp_snprintf(buffName, 512, formatStr, __VA_ARGS__);    \n#endif\n\n//--------------------------------------------------------------------------------------\n// Error checking\n//--------------------------------------------------------------------------------------\n\nnamespace ZetaRay::Util\n{\n    void ReportError(const char* title, const char* msg);\n    void ReportErrorWin32(const char* file, int line, const char* call);\n    void DebugBreak();\n    void Exit();\n}\n\n#ifndef NDEBUG \n#define Assert(expr, formatStr, ...)                                                          \\\n    if(!(expr))                                                                               \\\n    {                                                                                         \\\n        char buff_[256];                                                                      \\\n        int n_ = stbsp_snprintf(buff_, 256, \"%s: %d\\n\", __FILE__, __LINE__);                  \\\n        stbsp_snprintf(buff_ + n_, 256 - n_, formatStr, __VA_ARGS__);                         \\\n        ZetaRay::Util::ReportError(\"Assertion failed\", buff_);                                \\\n        ZetaRay::Util::DebugBreak();                                                          \\\n    }\n#else\n#define Assert(expr, formatStr, ...) ((void)0)\n#endif\n\n#ifndef NDEBUG \n#define CheckWin32(expr)                                            \\\n    [[unlikely]]                                                    \\\n    if(!(expr))                                                     \\\n    {                                                               \\\n        ZetaRay::Util::ReportErrorWin32(__FILE__, __LINE__, #expr); \\\n        ZetaRay::Util::DebugBreak();                                \\\n    }\n#else\n#define CheckWin32(expr)                                            \\\n    [[unlikely]]                                                    \\\n    if(!(expr))                                                     \\\n    {                                                               \\\n        ZetaRay::Util::ReportErrorWin32(__FILE__, __LINE__, #expr); \\\n        ZetaRay::Util::Exit();                                      \\\n    }\n#endif\n\n#ifndef NDEBUG\n#ifndef Check\n#define Check(expr, formatStr, ...)                                                          \\\n    [[unlikely]]                                                                             \\\n    if(!(expr))                                                                              \\\n    {                                                                                        \\\n        char buff_[256];                                                                     \\\n        int n_ = stbsp_snprintf(buff_, 256, \"%s: %d\\n\", __FILE__, __LINE__);                 \\\n        stbsp_snprintf(buff_ + n_, 256 - n_, formatStr, __VA_ARGS__);                        \\\n        ZetaRay::Util::ReportError(\"Fatal Error\", buff_);                                    \\\n        ZetaRay::Util::DebugBreak();                                                         \\\n    }\n#endif\n#else\n#ifndef Check\n#define Check(expr, formatStr, ...)                                                          \\\n    [[unlikely]]                                                                             \\\n    if(!(expr))                                                                              \\\n    {                                                                                        \\\n        char buff_[256];                                                                     \\\n        int n_ = stbsp_snprintf(buff_, 256, \"%s: %d\\n\", __FILE__, __LINE__);                 \\\n        stbsp_snprintf(buff_ + n_, 256 - n_, formatStr, __VA_ARGS__);                        \\\n        ZetaRay::Util::ReportError(\"Fatal Error\", buff_);                                    \\\n        ZetaRay::Util::Exit();                                                               \\\n    }\n#endif\n#endif\n"
  },
  {
    "path": "Source/ZetaCore/Utility/Function.h",
    "content": "#pragma once\n\n#include \"../App/ZetaRay.h\"\n\nnamespace ZetaRay::Util\n{\n    // Ref: https://stackoverflow.com/questions/18633697/fastdelegate-and-lambdas-cant-get-them-to-work-don-clugstons-fastest-possib\n    struct Function\n    {\n        Function() = default;\n\n        template <typename F>\n        Function(F&& f)\n        {\n            static_assert(sizeof(F) <= BUFFER_SIZE, \"Memory needed exceeded capture buffer size.\");\n            static_assert(std::is_move_constructible_v<F>);\n\n            m_lambda = &Get<F>();\n            new (&m_buffer) F(ZetaMove(f));\n        }\n\n        ~Function()\n        {\n            if (m_lambda)\n            {\n                m_lambda->destruct(&m_buffer);\n            }\n        }\n\n        Function(Function&& other)\n            : m_lambda(other.m_lambda)\n        {\n            other.m_lambda = nullptr;\n            memcpy(m_buffer, other.m_buffer, BUFFER_SIZE);\n            memset(other.m_buffer, 0, BUFFER_SIZE);\n        }\n\n        Function& operator=(Function&& other)\n        {\n            m_lambda = other.m_lambda;\n            other.m_lambda = nullptr;\n            memcpy(m_buffer, other.m_buffer, BUFFER_SIZE);\n            memset(other.m_buffer, 0, BUFFER_SIZE);\n\n            return *this;\n        }\n\n        bool IsSet() const\n        {\n            return m_lambda != nullptr;\n        }\n\n        //template <typename F>\n        //void Reset(F&& f)\n        //{\n        //    static_assert(sizeof(F) <= BUFFER_SIZE, \"Memory needed exceede capture buffer size.\");\n        //    static_assert(std::is_move_constructible_v<F>);\n\n        //    if (m_lambda)\n        //        m_lambda->destruct(&m_buffer);\n\n        //    m_lambda = &Get<F>();\n        //    new (&m_buffer) F(ZetaMove(f));\n        //}\n\n        ZetaInline void Run()\n        {\n            return m_lambda->call(&m_buffer);\n        }\n\n    private:\n        // Due to [[no_unique_address]] not working in clang-cl < 18, following needs to be larger\n#if !defined(ZETA_HAS_NO_UNIQUE_ADDRESS)\n        static constexpr int BUFFER_SIZE = 40;\n#else\n        static constexpr int BUFFER_SIZE = 32;\n#endif\n\n        struct LambdaFuncPtrs\n        {\n            void (*call)(void*);\n            void (*destruct)(void*);\n        };\n\n        template <typename F>\n        static void Call(void* f)\n        {\n            (*reinterpret_cast<F*>(f))();\n        }\n\n        template <typename F>\n        static void Destruct(void* f)\n        {\n            reinterpret_cast<F*>(f)->~F();\n        }\n\n        template <typename F>\n        const LambdaFuncPtrs& Get()\n        {\n            static const LambdaFuncPtrs lambda = { &Call<F>, &Destruct<F> };\n            return lambda;\n        }\n\n        const LambdaFuncPtrs* m_lambda = nullptr;\n        alignas(alignof(std::max_align_t)) uint8_t m_buffer[BUFFER_SIZE];\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Utility/HashTable.h",
    "content": "#pragma once\n\n#include \"../Math/Common.h\"\n#include \"../Support/Memory.h\"\n#include \"../Utility/Optional.h\"\n\nnamespace ZetaRay::Util\n{\n    // Open-set addressing with linear probing\n    // \n    //  - Assumes keys are already hashed; key itself is not stored, only its hash (uint64_t). Consequently,\n    //    collisions on keys could lead to wrong results. By using a decent hash function, chances of \n    //    such collisions should be low.\n    //  - Iterators (pointers) are NOT stable; pointer to an entry found earlier might not be valid\n    //    anymore due to subsequent insertions and possible resize.\n    //  - Not thread-safe\n    template<typename ValueType, typename KeyType = uint64_t, Support::AllocatorType Allocator = Support::SystemAllocator>\n    requires std::is_integral_v<KeyType>\n    class HashTable\n    {\n        static_assert(std::is_copy_constructible_v<ValueType> || std::is_move_constructible_v<ValueType>, \n            \"ValueType is not move or copy-constructible.\");\n\n    public:\n        struct Entry\n        {\n            KeyType Key;\n            ValueType Val;\n        };\n\n        explicit HashTable(const Allocator& a = Allocator())\n            : m_allocator(a)\n        {}\n        explicit HashTable(size_t initialSize, const Allocator& a = Allocator())\n            : m_allocator(a)\n        {\n            static_assert(std::is_default_constructible_v<ValueType>);\n            relocate(Math::NextPow2(initialSize));\n        }\n        ~HashTable()\n        {\n            free_memory();\n\n            if constexpr (!std::is_trivially_destructible_v<Allocator>)\n                this->m_allocator.~Allocator();\n        }\n\n        // TODO implement move & copy constructors/assignments\n        HashTable(const HashTable&) = delete;\n        HashTable& operator=(const HashTable&) = delete;\n\n        // \"accountForMaxLoad\": A common use case is when the maximum number of \n        // elements is known, so resize is used to allocate all the necessary storage \n        // once. But this doesn't account for load factor, as when size approaches \n        // \"n\", another allocation takes place so that load factor stays below maximum.\n        // When accounting for this, table should be resized to ceil(n / max_load_factor).\n        void resize(size_t n, bool accountForMaxLoad = false)\n        {\n            if (n <= bucket_count()) // also covers when n == 0\n                return;\n\n            n = Math::Max(n, MIN_NUM_BUCKETS);\n            n = accountForMaxLoad ? Math::Ceil(n / MAX_LOAD) : n;\n            n = Math::NextPow2(n);  // n > #buckets, so the next power of two will also respect the max load factor\n            relocate(n);\n        }\n\n        // Returns NULL if an element with the given key is not found.\n        // Note: in contrast to find(), find_entry() returns NULL only when the table is empty.\n        Util::Optional<ValueType*> find(KeyType key) const\n        {\n            Entry* e = find_entry(key);\n            if (e && e->Key == key)\n                return &e->Val;\n\n            return {};\n        }\n\n        // Inserts a new entry only if it doesn't already exist\n        template<typename... Args>\n        bool try_emplace(KeyType key, Args&&... args)\n        {\n            Assert(key != NULL_KEY && key != TOMBSTONE_KEY, \"Invalid key.\");\n\n            Entry* elem = find_entry(key);\n            if (!elem || elem->Key != key)\n            {\n                if (elem && (elem->Key == TOMBSTONE_KEY))\n                {\n                    elem->Key = key;\n                    new (&elem->Val) ValueType(ZetaForward(args)...);\n                    m_numNonTombstoneEntries++;\n\n                    return true;\n                }\n\n                if (!m_beg || load_factor() >= MAX_LOAD || m_numEntries + 1 == bucket_count())\n                {\n                    relocate(Math::Max(bucket_count() << 1, MIN_NUM_BUCKETS));\n                    // Find the new position to construct this Entry\n                    elem = find_entry(key);\n                }\n\n                elem->Key = key;\n                new (&elem->Val) ValueType(ZetaForward(args)...);\n                m_numEntries++;\n                m_numNonTombstoneEntries++;\n                Assert(m_numEntries < bucket_count(), \"Load factor should never be 1.0.\");\n\n                return true;\n            }\n\n            return false;\n        }\n\n        // Assign to the entry if already exists, otherwise inserts a new entry\n        Entry& insert_or_assign(KeyType key, const ValueType& val)\n        {\n            static_assert(std::is_copy_constructible_v<ValueType> || std::is_move_constructible_v<ValueType>,\n                \"ValueType must be move-or-copy constructible.\");\n            Assert(key != NULL_KEY && key != TOMBSTONE_KEY, \"Invalid key.\");\n\n            Entry* elem = find_entry(key);\n            if (!elem || elem->Key != key)\n            {\n                if (elem && elem->Key == TOMBSTONE_KEY)\n                {\n                    elem->Key = key;\n                    new (&elem->Val) ValueType(val);\n                    m_numNonTombstoneEntries++;\n\n                    return *elem;\n                }\n\n                if (!m_beg || load_factor() >= MAX_LOAD || m_numEntries + 1 == bucket_count())\n                {\n                    relocate(Math::Max(bucket_count() << 1, MIN_NUM_BUCKETS));\n                    elem = find_entry(key);\n                }\n\n                elem->Key = key;\n                m_numEntries++;\n                m_numNonTombstoneEntries++;\n                Assert(m_numEntries < bucket_count(), \"Load factor should never be 1.0.\");\n            }\n\n            new (&elem->Val) ValueType(val);\n\n            return *elem;\n        }\n\n        Entry& insert_or_assign(KeyType key, ValueType&& val)\n        {\n            static_assert(std::is_copy_constructible_v<ValueType> || std::is_move_constructible_v<ValueType>,\n                \"ValueType must be move-or-copy constructible.\");\n            Assert(key != NULL_KEY && key != TOMBSTONE_KEY, \"Invalid key.\");\n\n            Entry* elem = find_entry(key);\n            if (!elem || elem->Key != key)\n            {\n                if (elem && elem->Key == TOMBSTONE_KEY)\n                {\n                    elem->Key = key;\n                    new (&elem->Val) ValueType(ZetaForward(val));\n                    m_numNonTombstoneEntries++;\n\n                    return *elem;\n                }\n\n                if (!m_beg || load_factor() >= MAX_LOAD || m_numEntries + 1 == bucket_count())\n                {\n                    relocate(Math::Max(bucket_count() << 1, MIN_NUM_BUCKETS));\n                    elem = find_entry(key);\n                }\n\n                elem->Key = key;\n                m_numEntries++;\n                m_numNonTombstoneEntries++;\n                Assert(m_numEntries < bucket_count(), \"Load factor should never be 1.0.\");\n            }\n\n            new (&elem->Val) ValueType(ZetaForward(val));\n\n            return *elem;\n        }\n\n        ZetaInline size_t erase(KeyType key)\n        {\n            Entry* elem = find_entry(key);\n            if (!elem || elem->Key != key || elem->Key == TOMBSTONE_KEY)\n                return 0;\n\n            elem->Key = TOMBSTONE_KEY;\n            Assert(m_numNonTombstoneEntries >= 1, \"Invalid hash table state.\");\n            m_numNonTombstoneEntries--;\n            if constexpr (!std::is_trivially_destructible_v<ValueType>)\n                elem->~Entry();\n\n            return 1;\n        }\n\n        ZetaInline size_t bucket_count() const\n        {\n            return m_end - m_beg;\n        }\n\n        // Note that tombstone entries count towards #entries\n        ZetaInline size_t size() const\n        {\n            return m_numNonTombstoneEntries;\n        }\n\n        ZetaInline float load_factor() const\n        {\n            // Avoid divide-by-zero\n            return m_numEntries == 0 ? 0.0f : (float)m_numEntries / bucket_count();\n        }\n\n        ZetaInline bool empty() const\n        {\n            return m_numNonTombstoneEntries == 0;\n        }\n\n        void clear()\n        {\n            if constexpr (!std::is_trivially_destructible_v<ValueType>)\n            {\n                size_t i = 0;\n                \n                for (auto it = begin_it(); it < end_it(); it = next_it(it))\n                {\n                    it->~Entry();\n                    i++;\n                }\n                \n                Assert(i == m_numNonTombstoneEntries, \"Number of cleared entries must match the number of entries.\");\n            }\n\n            for (Entry* curr = m_beg; curr != m_end; curr++)\n                curr->Key = NULL_KEY;\n\n            m_numEntries = 0;\n            m_numNonTombstoneEntries = 0;\n            // Don't free the memory\n        }\n\n        void free_memory()\n        {\n            if constexpr (!std::is_trivially_destructible_v<ValueType>)\n            {\n                size_t i = 0;\n\n                for (auto it = begin_it(); it < end_it(); it = next_it(it))\n                {\n                    it->~Entry();\n                    i++;\n                }\n\n                Assert(i == m_numNonTombstoneEntries, \"Number of cleared entries must match the number of entries.\");\n            }\n\n            // Free the previously allocated memory\n            if(bucket_count())\n                m_allocator.FreeAligned(m_beg, bucket_count() * sizeof(Entry), alignof(Entry));\n\n            m_numEntries = 0;\n            m_numNonTombstoneEntries = 0;\n            m_beg = nullptr;\n            m_end = nullptr;\n        }\n\n        void swap(HashTable& other)\n        {\n            std::swap(m_beg, other.m_beg);\n            std::swap(m_end, other.m_end);\n            std::swap(m_numEntries, other.m_numEntries);\n            std::swap(m_numNonTombstoneEntries, other.m_numNonTombstoneEntries);\n            std::swap(m_allocator, other.m_allocator);\n        }\n\n        ValueType& operator[](KeyType key)\n        {\n            static_assert(std::is_default_constructible_v<ValueType>, \"ValueType must be default-constructible\");\n            Assert(key != NULL_KEY && key != TOMBSTONE_KEY, \"Invalid key.\");\n\n            Entry* elem = find_entry(key);\n            if (!elem || elem->Key != key)\n            {\n                if (elem && elem->Key == TOMBSTONE_KEY)\n                {\n                    elem->Key = key;\n                    new (&elem->Val) ValueType();\n                    m_numNonTombstoneEntries++;\n\n                    return elem->Val;\n                }\n\n                if (!m_beg || load_factor() >= MAX_LOAD || m_numEntries + 1 == bucket_count())\n                {\n                    relocate(Math::Max(bucket_count() << 1, MIN_NUM_BUCKETS));\n                    elem = find_entry(key);\n                }\n\n                elem->Key = key;\n                new (&elem->Val) ValueType();\n                m_numEntries++;\n                m_numNonTombstoneEntries++;\n                Assert(m_numEntries < bucket_count(), \"Load factor should never be 1.0.\");\n            }\n\n            return elem->Val;\n        }\n\n        ZetaInline Entry* begin_it()\n        {\n            // When memory is allocated, but there hasn't been any insertions,\n            // m_beg != m_end, which would erroneously indicate table is non-mepty.\n            if (m_numEntries == 0)\n                return m_end;\n\n            auto it = m_beg;\n            while (it != m_end && (it->Key == NULL_KEY || it->Key == TOMBSTONE_KEY))\n                it++;\n\n            return it;\n        }\n\n        ZetaInline Entry* next_it(Entry* curr)\n        {\n            Entry* next = curr + 1;\n            while (next != m_end && (next->Key == NULL_KEY || next->Key == TOMBSTONE_KEY))\n                next++;\n\n            return next;\n        }\n\n        ZetaInline Entry* end_it()\n        {\n            return m_end;\n        }\n\n    private:\n        Entry* find_entry(KeyType key) const\n        {\n            const size_t n = bucket_count();\n            if (n == 0)\n                return nullptr;\n\n            const size_t origPos = key & (n - 1);    // == key % n (n is a power of two)\n            size_t nextPos = origPos;\n            Entry* curr = m_beg + origPos;\n            Entry* tombstone = nullptr;\n\n            // Which bucket the entry belongs to\n            while (curr->Key != key && curr->Key != NULL_KEY)\n            {\n                // Remember tombstone entries but keep probing\n                if (curr->Key == TOMBSTONE_KEY)\n                    tombstone = curr;\n \n                nextPos++;                                  // Linear probing\n                nextPos = nextPos < n ? nextPos : 0;        // Wrap around to zero\n                curr = m_beg + nextPos;\n                Assert(nextPos != origPos, \"infinite loop\");    // Should never happen due to load_factor < 1\n            }\n\n            if (curr->Key == key)\n                return curr;\n\n            return tombstone ? tombstone : curr;\n        }\n\n        void relocate(size_t n)\n        {\n            Assert(Math::IsPow2(n), \"n must be a power of two.\");\n            Assert(n > bucket_count(), \"n must be greater than the current bucket count.\");\n            Entry* oldTable = m_beg;\n            const size_t oldBucketCount = bucket_count();\n\n            m_beg = reinterpret_cast<Entry*>(m_allocator.AllocateAligned(n * sizeof(Entry), alignof(Entry)));\n            m_end = m_beg + n;  // Adjust end pointer\n            m_numEntries = 0;\n            m_numNonTombstoneEntries = 0;\n\n            // Initialize new table\n            for (Entry* curr = m_beg; curr != m_beg + n; curr++)\n            {\n                if constexpr (!std::is_trivially_default_constructible_v<Entry>)\n                    new (curr) Entry;\n\n                curr->Key = NULL_KEY;\n            }\n\n            // Reinsert all elements\n            for (Entry* curr = oldTable; curr < oldTable + oldBucketCount; curr++)\n            {\n                if (curr->Key == NULL_KEY || curr->Key == TOMBSTONE_KEY)\n                    continue;\n\n                Entry* elem = find_entry(curr->Key);\n                Assert(elem->Key == NULL_KEY, \"duplicate keys.\");\n                elem->Key = curr->Key;\n                elem->Val = ZetaMove(curr->Val);\n                m_numEntries++;\n            }\n\n            m_numNonTombstoneEntries = m_numEntries;\n\n            // Destruct previous elements (if necessary)\n            if constexpr (!std::is_trivially_destructible_v<Entry>)\n            {\n                for (Entry* curr = oldTable; curr < oldTable + oldBucketCount; curr++)\n                    curr->~Entry();\n            }\n\n            // Free the previously allocated memory\n            if(oldTable)\n                m_allocator.FreeAligned(oldTable, oldBucketCount * sizeof(Entry), alignof(Entry));\n        }\n\n        static constexpr size_t MIN_NUM_BUCKETS = 4;\n        static constexpr float MAX_LOAD = 0.8f;\n        static constexpr KeyType NULL_KEY = KeyType(-1);\n        static constexpr KeyType TOMBSTONE_KEY = KeyType(-2);\n\n        Entry* m_beg = nullptr;        // Pointer to the beginning of memory block\n        Entry* m_end = nullptr;        // Pointer to the end of memory block\n        size_t m_numEntries = 0;\n        size_t m_numNonTombstoneEntries = 0;\n#if defined(ZETA_HAS_NO_UNIQUE_ADDRESS)\n        [[msvc::no_unique_address]] Allocator m_allocator;\n#else\n        Allocator m_allocator;\n#endif\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Utility/Optional.h",
    "content": "#pragma once\n\n#include <Utility/Error.h>\n#include <type_traits>\n\nnamespace ZetaRay::Util\n{\n    template<typename T>\n    struct Optional\n    {\n        Optional() = default;\n        ~Optional()\n        {\n            reset();\n        }\n\n        Optional(const T& v)\n            requires std::is_copy_constructible_v<T>\n            : m_hasValue(true)\n        {\n            new (reinterpret_cast<T*>(m_value)) T(v);\n\n            // treat null as not containing a value\n            if constexpr (std::is_pointer_v<T>)\n                m_hasValue = v != nullptr;\n        }\n        Optional& operator=(const T& other)\n            requires std::is_copy_constructible_v<T>\n        {\n            reset();\n            new (reinterpret_cast<T*>(m_value)) T(other);\n            m_hasValue = true;\n\n            if constexpr (std::is_pointer_v<T>)\n                m_hasValue = other != nullptr;\n\n            return *this;\n        }\n        Optional(T&& v)\n            requires std::is_move_constructible_v<T>\n            : m_hasValue(true)\n        {\n            new (reinterpret_cast<T*>(m_value)) T(ZetaMove(v));\n\n            if constexpr (std::is_pointer_v<T>)\n                m_hasValue = v != nullptr;\n        }\n        Optional& operator=(T&& other)\n            requires std::is_move_constructible_v<T>\n        {\n            reset();\n            new (reinterpret_cast<T*>(m_value)) T(ZetaMove(other));\n            m_hasValue = true;\n\n            if constexpr (std::is_pointer_v<T>)\n                m_hasValue = other != nullptr;\n\n            return *this;\n        }\n        Optional(const Optional<T>& other)\n            : m_hasValue(other.m_hasValue)\n        {\n            if (other.m_hasValue)\n                new (reinterpret_cast<T*>(m_value)) T(other.value());\n        }\n        Optional& operator=(const Optional<T>& other)\n        {\n            if (this == &other)\n                return *this;\n\n            reset();\n\n            if (other.m_hasValue)\n            {\n                new (reinterpret_cast<T*>(m_value)) T(other.value());\n                m_hasValue = true;\n            }\n\n            return *this;\n        }\n        Optional(Optional<T>&& other)\n            : m_hasValue(other.m_hasValue)\n        {\n            if (other.m_hasValue)\n            {\n                new (reinterpret_cast<T*>(m_value)) T(ZetaMove(other.value()));\n                other.reset();\n            }\n        }\n        Optional& operator=(Optional<T>&& other)\n        {\n            if (this == &other)\n                return *this;\n\n            reset();\n\n            if (other.m_hasValue)\n            {\n                new (reinterpret_cast<T*>(m_value)) T(ZetaMove(other.value()));\n                m_hasValue = true;\n                other.reset();\n            }\n\n            return *this;\n        }\n\n        ZetaInline explicit operator bool() const { return m_hasValue; }\n\n        void reset()\n        {\n            if constexpr (!std::is_trivially_destructible_v<T>)\n            {\n                if (m_hasValue)\n                    value().~T();\n            }\n\n            m_hasValue = false;\n        }\n\n        // only checks in debug build\n        ZetaInline T& value()\n        {\n            Assert(m_hasValue, \"Optional is empty.\");\n            return *reinterpret_cast<T*>(m_value);\n        }\n        ZetaInline const T& value() const\n        {\n            Assert(m_hasValue, \"Optional is empty.\");\n            return *reinterpret_cast<const T*>(m_value);\n        }\n\n        // safe version, always checks\n        ZetaInline T& value_s()\n        {\n            Check(m_hasValue, \"Optional is empty.\");\n            return *reinterpret_cast<T*>(m_value);\n        }\n        ZetaInline const T& value_s() const\n        {\n            Check(m_hasValue, \"Optional is empty.\");\n            return *reinterpret_cast<const T*>(m_value);\n        }\n\n    private:\n        alignas(T) uint8_t m_value[sizeof(T)];\n        bool m_hasValue = false;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Utility/RNG.h",
    "content": "#pragma once\n\n#include \"../Math/Vector.h\"\n#include <float.h>\n\nnamespace ZetaRay::Util\n{\n    // Following is based on: https://github.com/mmp/pbrt-v3/blob/master/src/core/rng.h\n    // \n    // pbrt source code is Copyright(c) 1998-2016\n    //                    Matt Pharr, Greg Humphreys, and Wenzel Jakob.\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    //  - 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 copyright\n    //    notice, this list of conditions and the following disclaimer in the\n    //    documentation and/or other materials provided with the distribution.\n    // \n    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n    // IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n    // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n    // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n    // HOLDER 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    struct RNG\n    {\n        // Seeds the rng. stream ID specifies which sequence to use.\n        explicit RNG(uint64_t streamID = 0xda3e39cb94b95bdbULL)\n        {\n            State = 0U;\n            Inc = (streamID << 1u) | 1u;\n            UniformUint();\n\n            // state initializer is fixed\n            State += 0x853c49e6748fea9bULL;\n            UniformUint();\n        }\n\n        // Generates a uniformly distributed 32-bit random number\n        uint32_t UniformUint()\n        {\n            uint64_t oldstate = State;\n            State = oldstate * 6364136223846793005ULL + Inc;\n\n            // Note: (uint32_t)((oldstate >> 18u) ^ oldstate) >> 27u leads to disaster!\n            uint32_t xorshifted = (uint32_t)(((oldstate >> 18u) ^ oldstate) >> 27u);\n            uint32_t rot = oldstate >> 59u;\n\n            return (xorshifted >> rot) | (xorshifted << ((~rot + 1u) & 31));\n        }\n\n        // Generates a uniformly distributed float in [0, 1)\n        float Uniform()\n        {\n            return float(UniformUint() >> 8) * 0x1p-24f;\n        }\n\n        Math::float2 Uniform2D()\n        {\n            return Math::float2(Uniform(), Uniform());\n        }\n\n        // Generates a uniformly distributed number r, where 0 <= r < bound.\n        // See https://www.pcg-random.org for more info.\n        uint32_t UniformUintBounded(uint32_t bound)\n        {\n            uint32_t threshold = (~bound + 1u) % bound;\n\n            for (;;) \n            {\n                uint32_t r = UniformUint();\n\n                if (r >= threshold)\n                    return r % bound;\n            }\n        }\n\n    private:\n        // RNG state\n        uint64_t State;      // All values are possible.\n        uint64_t Inc;        // Controls which RNG sequence (stream) is selected. Must *always* be odd.\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Utility/SmallVector.h",
    "content": "#pragma once\n\n#include \"../Math/Common.h\"\n#include \"../Support/Memory.h\"\n#include <utility>    // std::swap\n\nnamespace ZetaRay::Util\n{\n    //--------------------------------------------------------------------------------------\n    // Vector\n    // \n    // Cannot be directly constructed -- base class for SmallVector.\n    //--------------------------------------------------------------------------------------\n\n    template<typename T, Support::AllocatorType Allocator = Support::SystemAllocator>\n    class Vector\n    {\n        static constexpr size_t MIN_CAPACITY = Math::Max(64 / sizeof(T), 4llu);\n\n    public:\n        bool has_inline_storage() const\n        {\n            constexpr size_t inlineStorageOffset = Math::AlignUp(sizeof(Vector<T, Allocator>), alignof(T));\n            return reinterpret_cast<uintptr_t>(m_beg) == reinterpret_cast<uintptr_t>(this) + inlineStorageOffset;\n        }\n\n        void swap(Vector& other)\n        {\n            if (this == &other)\n                return;\n\n            if (empty() && other.empty())\n                return;\n\n            if (!has_inline_storage() && !other.has_inline_storage())\n            {\n                std::swap(m_beg, other.m_beg);\n                std::swap(m_end, other.m_end);\n                std::swap(m_last, other.m_last);\n\n                return;\n            }\n\n            const size_t oldSize = size();\n            const size_t oldOtherSize = other.size();\n            const bool otherIsLarger = oldOtherSize > oldSize;\n            const size_t minSize = Math::Min(oldSize, oldOtherSize);\n            const size_t maxSize = Math::Max(oldSize, oldOtherSize);\n\n            if (!other.empty())\n                reserve(oldOtherSize);         // Doesn't allocate if inline storage happens to be large enough\n\n            if (!empty())\n                other.reserve(oldSize);        // Doesn't allocate if inline storage happens to be large enough\n\n            T* largerBeg = otherIsLarger ? other.m_beg : m_beg;\n            T* smallerBeg = otherIsLarger ? m_beg : other.m_beg;\n\n            for (size_t i = 0; i < minSize; i++)\n                std::swap(*(m_beg + i), *(other.m_beg + i));\n\n            // Copy over the remaining elements to the smaller Vector\n            if constexpr (std::is_trivially_copyable_v<T>)\n            {\n                memcpy(smallerBeg + minSize, largerBeg + minSize, sizeof(T) * (maxSize - minSize));\n            }\n            else if constexpr (std::is_move_constructible_v<T>)\n            {\n                for (size_t i = minSize; i < maxSize; i++)\n                    new (smallerBeg + i) T(ZetaMove(*(largerBeg + i)));\n            }\n            else if constexpr (std::is_copy_constructible_v<T>)\n            {\n                for (size_t i = minSize; i < maxSize; i++)\n                    new (smallerBeg + i) T(*(largerBeg + i));\n            }\n\n            m_end = m_beg + oldOtherSize;\n            other.m_end = other.m_beg + oldSize;\n        }\n\n        ZetaInline T* begin()\n        {\n            return m_beg;\n        }\n\n        ZetaInline T* end()\n        {\n            return m_end;\n        }\n\n        ZetaInline const T* begin() const\n        {\n            return m_beg;\n        }\n\n        ZetaInline const T* end() const\n        {\n            return m_end;\n        }\n\n        ZetaInline T* data()\n        {\n            return m_beg;\n        }\n\n        ZetaInline const T* data() const\n        {\n            return m_beg;\n        }\n\n        ZetaInline T& back()\n        {\n            Assert(size() > 0, \"Vector is empty.\");\n            return *(m_beg + size() - 1);\n        }\n\n        ZetaInline const T& back() const\n        {\n            Assert(size() > 0, \"Vector is empty.\");\n            return *(m_beg + size() - 1);\n        }\n\n        ZetaInline T& operator[](size_t pos)\n        {\n            Assert(pos < (uintptr_t)(m_end - m_beg), \"Out-of-bound access.\");\n            return *(m_beg + pos);\n        }\n\n        ZetaInline const T& operator[](size_t pos) const\n        {\n            Assert(pos < (uintptr_t)(m_end - m_beg), \"Out-of-bound access.\");\n            return *(m_beg + pos);\n        }\n\n        ZetaInline size_t capacity() const\n        {\n            return m_last - m_beg;\n        }\n\n        ZetaInline size_t size() const\n        {\n            return m_end - m_beg;\n        }\n\n        ZetaInline bool empty() const\n        {\n            return m_end - m_beg == 0;\n        }\n\n        void reserve(size_t n)\n        {\n            const size_t currCapacity = capacity();\n            const size_t oldSize = size();\n\n            if (n <= currCapacity)\n                return;\n\n            void* mem = relocate(n);\n\n            // Adjust pointers\n            m_beg = reinterpret_cast<T*>(mem);\n            m_end = m_beg + oldSize;\n            m_last = m_beg + n;\n        }\n\n        void resize(size_t n)\n        {\n            static_assert(std::is_default_constructible_v<T>, \"T is not default-constructible.\");\n\n            const size_t currCapacity = capacity();\n            const size_t oldSize = size();\n\n            // Check if current capacity is enough, otherwise just adjust the \"end\" pointer\n            if (currCapacity < n)\n            {\n                void* mem = relocate(n);\n                m_beg = reinterpret_cast<T*>(mem);\n                m_last = m_beg + n;\n            }\n\n            // Adjust the end pointer\n            m_end = m_beg + n;\n\n            // Default construct the newly added elements\n            if constexpr (!std::is_trivially_default_constructible_v<T>)\n            {\n                if (oldSize < n)\n                {\n                    T* curr = m_beg + oldSize;\n                    while (curr != m_end)\n                    {\n                        new (curr) T;\n                        curr++;\n                    }\n                }\n            }\n\n            // Default destruct leftovers if size decreased\n            if constexpr (!std::is_trivially_destructible_v<T>)\n            {\n                if (n < oldSize)\n                {\n                    T* curr = m_beg + n;\n                    const T* oldEnd = m_beg + oldSize;\n                    while (curr != oldEnd)\n                        curr++->~T();\n                }\n            }\n        }\n\n        // Note: \"Val\" is used to initialize the newly added elements (if any) and the \n        // existing elements aren't replaced by it. May have to change in the future.\n        void resize(size_t n, const T& val)\n        {\n            static_assert(std::is_copy_constructible_v<T> || std::is_move_constructible_v<T>, \n                \"T is not copy-or-move-constructible.\");\n\n            const size_t oldSize = size();\n            const size_t currCapacity = capacity();\n\n            if (currCapacity < n)\n            {\n                void* mem = relocate(n);\n                m_beg = reinterpret_cast<T*>(mem);\n                m_last = m_beg + n;\n            }\n\n            // Adjust the pointers\n            m_end = m_beg + n;\n\n            // Copy/move construct the new elements\n            if (oldSize < n)\n            {\n                T* curr = m_beg + oldSize;\n                while (curr != m_end)\n                {\n                    new (curr) T(ZetaForward(val));\n                    curr++;\n                }\n            }\n\n            // Default-destruct leftovers if size decreased\n            if constexpr (!std::is_trivially_destructible_v<T>)\n            {\n                if (n < oldSize)\n                {\n                    T* curr = m_beg + n;\n                    const T* oldEnd = m_beg + oldSize;\n                    while (curr != oldEnd)\n                        curr++->~T();\n                }\n            }\n        }\n\n        void pop_back(size_t num = 1)\n        {\n            Assert(size() >= num, \"Number of elements to pop exceeds Vector's size.\");\n\n            if constexpr (!std::is_trivially_destructible_v<T>)\n            {\n                for (size_t i = 0; i < num; i++)\n                    (m_end - 1 - i)->~T();\n            }\n\n            m_end -= num;\n        }\n\n        void push_back(const T& val)\n        {\n            static_assert(std::is_copy_constructible_v<T> || std::is_move_constructible_v<T>, \n                \"T is not move-or-copy-constructible.\");\n            emplace_back(val);\n        }\n\n        void push_back(T&& val)\n        {\n            static_assert(std::is_copy_constructible_v<T> || std::is_move_constructible_v<T>, \n                \"T is not move-or-copy-constructible.\");\n            emplace_back(ZetaMove(val));\n        }\n\n        template<typename... Args>\n        void emplace_back(Args&&... args)\n        {\n            if (m_last == m_end)\n            {\n                const size_t prevCapacity = capacity();\n                const size_t newCapacity = Math::Max(MIN_CAPACITY, prevCapacity + (prevCapacity >> 1));\n                Assert(newCapacity > prevCapacity, \"Capacity must strictly increase.\");\n\n                reserve(newCapacity);\n            }\n\n            new (reinterpret_cast<void*>(m_end)) T(ZetaForward(args)...);\n            m_end++;\n        }\n\n        void append_range(const T* beg, const T* end, bool exact = false)\n        {\n            if (!beg || !end || beg == end || beg > end)\n                return;\n\n            const size_t num = end - beg;\n            const size_t oldSize = size();\n            const size_t currCapacity = capacity();\n\n            if (currCapacity < oldSize + num)\n            {\n                size_t newCapacity = oldSize + num;\n                newCapacity = !exact ? Math::Max(MIN_CAPACITY, newCapacity + (newCapacity >> 1)) :\n                    Math::Max(MIN_CAPACITY, newCapacity);\n\n                reserve(newCapacity);\n            }\n\n            if constexpr (std::is_trivially_constructible_v<T>)\n            {\n                memcpy(m_beg + oldSize, const_cast<T*>(beg), sizeof(T) * num);\n            }\n            else if constexpr (std::is_move_constructible_v<T>)\n            {\n                T* source = const_cast<T*>(beg);\n                T* target = m_beg + oldSize;\n\n                while (source != end)\n                {\n                    new (target) T(ZetaMove(*source));\n\n                    source++;\n                    target++;\n                }\n            }\n            else if constexpr (std::is_copy_constructible_v<T>)\n            {\n                T* source = const_cast<T*>(beg);\n                T* target = m_beg + oldSize;\n\n                while (source != end)\n                {\n                    new (target) T(*source);\n\n                    source++;\n                    target++;\n                }\n            }\n            else\n                Assert(false, \"Calling reserve() for a non-copyable and non-movable T when Vector is non-empty is invalid.\");\n\n            m_end += num;\n        }\n\n        // Erases an element by swapping it with the last element. Returns a pointer to the next element.\n        T* erase_at_index(size_t pos)\n        {\n            static_assert(std::is_swappable_v<T>, \"T is not swappable.\");\n            const size_t n = size();\n            Assert(pos < n, \"Out-of-bound access.\");\n            Assert(!empty(), \"Attempting to erase from an empty Vector.\");\n\n            if (pos == n - 1)\n            {\n                pop_back();\n                return m_beg + pos;\n            }\n\n            std::swap(*(m_beg + pos), *(m_beg + n - 1));\n            pop_back();\n\n            return m_beg + pos;\n        }\n\n        // Erases an element by swapping it with the last element. Returns a pointer to the next element.\n        T* erase(const T& item)\n        {\n            const size_t pos = &item - m_beg;\n            return erase_at_index(pos);\n        }\n\n        void push_front(const T& val)\n        {\n            static_assert(std::is_copy_constructible_v<T> || std::is_move_constructible_v<T>, \n                \"T is not move-or-copy-constructible.\");\n            static_assert(std::is_swappable_v<T>, \"T is not swappable.\");\n\n            emplace_back(val);\n\n            if (const size_t n = size(); n > 1)\n                std::swap(*m_beg, *(m_beg + n - 1));\n        }\n\n        void push_front(T&& val)\n        {\n            static_assert(std::is_copy_constructible_v<T> || std::is_move_constructible_v<T>, \n                \"T is not move-or-copy-constructible.\");\n            static_assert(std::is_swappable_v<T>, \"T is not swappable.\");\n\n            emplace_back(ZetaMove(val));\n\n            if (const size_t n = size(); n > 1)\n                std::swap(*m_beg, *(m_beg + n - 1));\n        }\n\n        void clear()\n        {\n            if constexpr (!std::is_trivially_destructible_v<T>)\n            {\n                for (T* curr = m_beg; curr != m_end; curr++)\n                    curr->~T();\n            }\n\n            m_end = m_beg;\n        }\n\n    protected:\n        // Constructor\n        Vector(const Allocator& a)\n            : m_allocator(a)\n        {}\n        Vector(Allocator&& a)\n            : m_allocator(ZetaMove(a))\n        {}\n        // Copy constructor\n        Vector(const Vector& other)\n            : m_allocator(other.m_allocator)\n        {}\n        // Move constructor\n        Vector(Vector&& other)\n            : m_allocator(ZetaMove(other.m_allocator))\n        {}\n        // Move assignment\n        Vector& operator=(Vector<T, Allocator>&& other)\n        {\n            m_allocator = ZetaMove(other.m_allocator);\n            return *this;\n        }\n\n        void* relocate(size_t n)\n        {\n            // Allocate memory to accommodate the new size\n            void* mem = m_allocator.AllocateAligned(n * sizeof(T), alignof(T));\n            const size_t oldSize = size();\n\n            // Copy over the old elements\n            if (oldSize > 0)\n            {\n                if constexpr (std::is_trivially_copyable_v<T>)\n                {\n                    // TODO overlap leads to undefined behavior\n                    memcpy(mem, m_beg, sizeof(T) * oldSize);\n                }\n                else if constexpr (std::is_move_constructible_v<T>)\n                {\n                    T* source = m_beg;\n                    T* target = reinterpret_cast<T*>(mem);\n                    const T* end = target + oldSize;\n\n                    while (target != end)\n                    {\n                        new (target) T(ZetaMove(*source));\n\n                        source++;\n                        target++;\n                    }\n                }\n                else if constexpr (std::is_copy_constructible_v<T>)\n                {\n                    T* source = m_beg;\n                    T* target = reinterpret_cast<T*>(mem);\n                    const T* end = target + oldSize;\n\n                    while (target != end)\n                    {\n                        new (target) T(*source);\n\n                        source++;\n                        target++;\n                    }\n                }\n                else\n                    Assert(false, \"Calling reserve() for a non-copyable and non-movable type T when Vector is non-empty is invalid.\");\n\n                // Destruct old elements\n                if constexpr (!std::is_trivially_destructible_v<T>)\n                {\n                    for (T* curr = m_beg; curr < m_end; curr++)\n                        curr->~T();\n                }\n            }\n\n            // Free the previously allocated memory\n            const size_t currCapacity = capacity();\n\n            if (currCapacity && !has_inline_storage())\n                m_allocator.FreeAligned(m_beg, currCapacity * sizeof(T), alignof(T));\n\n            return mem;\n        }\n\n        void move_from(size_t N, Vector<T, Allocator>&& other)\n        {\n            static_assert(std::is_move_assignable_v<T> || std::is_copy_assignable_v<T>,\n                \"T is not copy-or-move-assignable.\");\n            static_assert(std::is_move_assignable_v<Allocator> || std::is_copy_assignable_v<Allocator>,\n                \"Allocator is not copy-or-move-assignable.\");\n\n            // Just switch pointers when MovedFrom is using the heap and MovedTo's \n            // inline storage isn't large enough\n            if ((N < other.size()) && !other.has_inline_storage())\n            {\n                m_beg = other.m_beg;\n                m_end = other.m_end;\n                m_last = other.m_last;\n\n                other.m_beg = nullptr;\n                other.m_end = nullptr;\n                other.m_last = nullptr;\n            }\n            // Existing inline storage isn't large enough or MoveFrom isn't using the heap\n            else if (!other.empty())\n            {\n                // Doesn't allocate if inline storage happens to be large enough\n                reserve(other.size());\n\n                if constexpr (std::is_trivially_copyable_v<T>)\n                {\n                    memcpy(m_beg, other.m_beg, sizeof(T) * other.size());\n                }\n                else if constexpr (std::is_move_constructible_v<T>)\n                {\n                    T* source = other.m_beg;\n                    T* target = m_beg;\n                    const T* end = target + other.size();\n\n                    while (target != end)\n                    {\n                        new (target) T(ZetaMove(*source));\n\n                        source++;\n                        target++;\n                    }\n                }\n                else if constexpr (std::is_copy_constructible_v<T>)\n                {\n                    T* source = other.m_beg;\n                    T* target = m_beg;\n                    const T* end = target + other.size();\n\n                    while (target != end)\n                    {\n                        new (target) T(*source);\n\n                        source++;\n                        target++;\n                    }\n                }\n\n                // Adjust the pointers (m_last was set by reserve())\n                m_end = m_beg + other.size();\n                Assert(size() == other.size(), \"These must be equal.\");\n\n                other.clear();\n            }\n        }\n\n        void copy_from(const Vector<T, Allocator>& other)\n        {\n            static_assert(std::is_move_assignable_v<T> || std::is_copy_assignable_v<T>,\n                \"T is not copy-or-move-assignable.\");\n            static_assert(std::is_move_assignable_v<Allocator> || std::is_copy_assignable_v<Allocator>,\n                \"Allocator is not copy-or-move-assignable.\");\n\n            const size_t currCapacity = capacity();\n            const size_t newSize = other.size();\n\n            if (newSize == 0)\n                return;\n\n            if (currCapacity < newSize)\n            {\n                // Free the previously allocated memory\n                if (currCapacity > 0 && !has_inline_storage())\n                    m_allocator.FreeAligned(m_beg, currCapacity * sizeof(T), alignof(T));\n\n                // Allocate memory to accommodate new size\n                void* mem = m_allocator.AllocateAligned(newSize * sizeof(T), alignof(T));\n\n                // Adjust the pointers\n                m_beg = reinterpret_cast<T*>(mem);\n                m_last = m_beg + newSize;\n            }\n\n            // Regardless of whether new memory was allocated\n            m_end = m_beg + newSize;\n\n            // Just copy the memory\n            if constexpr (std::is_trivially_copyable_v<T>)\n            {\n                memcpy(m_beg, other.m_beg, sizeof(T) * newSize);\n            }\n            // Call the copy constructor\n            else\n            {\n                T* source = m_beg;\n                T* target = other.m_beg;\n\n                for (int64_t i = 0; i < newSize; i++)\n                {\n                    new (source) T(*target);\n\n                    source++;\n                    target++;\n                }\n            }\n        }\n\n        T* m_beg = nullptr;        // Pointer to the beginning of memory block\n        T* m_end = nullptr;        // Pointer to element to insert at next (one past the last inserted element)\n        T* m_last = nullptr;       // Pointer to the end of memory block\n\n#if defined(ZETA_HAS_NO_UNIQUE_ADDRESS)\n        [[msvc::no_unique_address]] Allocator m_allocator;\n#else\n        Allocator m_allocator;\n#endif\n    };\n\n    //--------------------------------------------------------------------------------------\n    // InlineStorage\n    //--------------------------------------------------------------------------------------\n\n    template<typename T, uint32_t N>\n    struct InlineStorage\n    {\n        alignas(T) uint8_t Buffer[sizeof(T) * N];\n    };\n\n    // Reminder: empty struct occupies one byte (unless c++20 [[no_unique_address]] is used)\n    template<typename T>\n    struct InlineStorage<T, 0>\n    {};\n\n    //--------------------------------------------------------------------------------------\n    // SmallVector \n    // \n    // Dynamic array with inline storage that holds a static number of elements within the \n    // object. Inspired by the following talk:\n    // Chandler Carruth, \"High Performance Code 201: Hybrid Data Structures\", CppCon 2016.\n    //--------------------------------------------------------------------------------------\n\n    template<typename T, Support::AllocatorType Allocator>\n    constexpr uint32_t GetExcessSize()\n    {\n        auto vecSize = Math::AlignUp(sizeof(Vector<T, Allocator>), alignof(T));\n        auto alignment = Math::Max(alignof(T), alignof(std::max_align_t));\n        int total = (int)Math::AlignUp(vecSize + 1, alignment);\n        int leftover = (total - (int)vecSize) / sizeof(T);\n        return Math::Max<int>(0, leftover);\n    }\n\n    template<typename T, Support::AllocatorType Allocator = Support::SystemAllocator, \n        uint32_t N = GetExcessSize<T, Allocator>()>\n    class SmallVector : public Vector<T, Allocator>\n    {\n    public:\n        // Constructor\n        SmallVector()\n            : Vector<T, Allocator>(Allocator())\n        {\n            static_assert(std::is_default_constructible_v<T>, \n                \"T is not default-constructible.\");\n            static_assert(std::is_default_constructible_v<Allocator>, \n                \"Allocator is not default-constructible.\");\n            init_storage();\n        }\n        ~SmallVector()\n        {\n            free_memory();\n\n            if constexpr (!std::is_trivially_destructible_v<Allocator>)\n                this->m_allocator.~Allocator();\n        }\n        explicit SmallVector(const Allocator& allocator)\n            : Vector<T, Allocator>(allocator)\n        {\n            static_assert(std::is_default_constructible_v<T>, \"T is not default-constructible.\");\n            init_storage();\n        }\n        explicit SmallVector(const T& t)\n            : Vector<T, Allocator>(Allocator())\n        {\n            static_assert(std::is_copy_constructible_v<T>, \"T is not copy-constructible.\");\n            static_assert(std::is_default_constructible_v<Allocator>, \"Allocator is not default-constructible.\");\n            init_storage(t);\n        }\n        SmallVector(const T& t, const Allocator& allocator)\n            : Vector<T, Allocator>(allocator)\n        {\n            static_assert(std::is_copy_constructible_v<T>, \"T is not copy-constructible.\");\n            init_storage(t);\n        }\n        SmallVector(size_t count, const Allocator& allocator = Allocator())\n            : Vector<T, Allocator>(allocator)\n        {\n            static_assert(std::is_default_constructible_v<T>, \"T is not default-constructible.\");\n            init_storage();\n            this->resize(count);\n        }\n        // Copy constructor/assignment\n        SmallVector(const SmallVector& other)\n            : Vector<T, Allocator>(other)\n        {\n            init_storage();\n            this->copy_from(other);\n        }\n        SmallVector(const Vector<T, Allocator>& other)\n            : Vector<T, Allocator>(other)\n        {\n            init_storage();\n            this->copy_from(other);\n        }\n        // Note: Currently, copy assignment doesn't change the allocator. Furthermore, \n        // the existing memory is retained if it can accommodate the new size. May need\n        // to change in the future.\n        SmallVector& operator=(const SmallVector& other)\n        {\n            if (this == &other)\n                return *this;\n\n            // Destruct existing elements\n            this->clear();\n            reset_storage();\n            this->copy_from(other);\n\n            return *this;\n        }\n        SmallVector& operator=(const Vector<T, Allocator>& other)\n        {\n            if (this == &other)\n                return *this;\n\n            // Destruct existing elements\n            this->clear();\n            reset_storage();\n            this->copy_from(other);\n\n            return *this;\n        }\n        // Move constructor/assignment\n        SmallVector(SmallVector&& other)\n            : Vector<T, Allocator>(ZetaMove(other))\n        {\n            init_storage();\n            this->move_from(N, ZetaMove(other));\n        }\n        SmallVector(Vector<T, Allocator>&& other)\n            : Vector<T, Allocator>(ZetaMove(other))\n        {\n            init_storage();\n            this->move_from(N, ZetaMove(other));\n        }\n        SmallVector& operator=(SmallVector&& other)\n        {\n            if (this == &other)\n                return *this;\n\n            // Previously allocated memory is not needed anymore and can be released. Also\n            // storage is reverted to inline storage.\n            free_memory();\n\n            if constexpr (!std::is_trivially_destructible_v<Allocator>)\n                this->m_allocator.~Allocator();\n\n            this->m_allocator = ZetaMove(other.m_allocator);\n            this->move_from(N, ZetaMove(other));\n\n            return *this;\n        }\n        SmallVector& operator=(Vector<T, Allocator>&& other)\n        {\n            if (this == &other)\n                return *this;\n\n            // Previously allocated memory is not needed anymore and can be released. Also\n            // storage is reverted to inline storage.\n            free_memory();\n\n            if constexpr (!std::is_trivially_destructible_v<Allocator>)\n                this->m_allocator.~Allocator();\n\n            Vector<T, Allocator>::operator=(ZetaMove(other));\n            this->move_from(N, ZetaMove(other));\n\n            return *this;\n        }\n\n        void free_memory()\n        {\n            // Destruct existing items (if any)\n            this->clear();\n\n            const size_t currCapacity = this->capacity();\n\n            // Free the previously allocated memory\n            if (currCapacity && !this->has_inline_storage())\n                this->m_allocator.FreeAligned(this->m_beg, currCapacity * sizeof(T), alignof(T));\n\n            // Revert back to inline storage\n            reset_storage();\n        }\n\n    private:\n        void init_storage()\n        {\n            constexpr size_t inlineStorageOffset = Math::AlignUp(sizeof(Vector<T, Allocator>), alignof(T));\n            this->m_beg = reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(this) + inlineStorageOffset);\n            this->m_end = this->m_beg;\n            this->m_last = this->m_beg + N;\n\n            if constexpr (!std::is_trivially_default_constructible_v<T>)\n            {\n                for (T* curr = this->m_beg; curr != this->m_last; curr++)\n                    new (curr) T;\n            }\n\n            Assert(this->has_inline_storage(), \"Must've reverted to inline storage.\");\n            Assert(this->capacity() == N, \"Capacity must be N.\");\n        }\n        void init_storage(const T& t)\n        {\n            constexpr size_t inlineStorageOffset = Math::AlignUp(sizeof(Vector<T, Allocator>), alignof(T));\n            this->m_beg = reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(this) + inlineStorageOffset);\n            this->m_end = this->m_beg + N;\n            this->m_last = this->m_beg + N;\n\n            for (T* curr = this->m_beg; curr != this->m_last; curr++)\n                new (curr) T(t);\n\n            Assert(this->has_inline_storage(), \"Must've reverted to inline storage.\");\n            Assert(this->capacity() == N, \"Capacity must be N.\");\n        }\n        void reset_storage()\n        {\n            constexpr size_t inlineStorageOffset = Math::AlignUp(sizeof(Vector<T, Allocator>), alignof(T));\n            this->m_beg = reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(this) + inlineStorageOffset);\n            this->m_end = this->m_beg;\n            this->m_last = this->m_beg + N;\n            Assert(this->has_inline_storage(), \"Must've reverted to inline storage.\");\n            Assert(this->capacity() == N, \"Capacity must be N.\");\n        }\n\n#if defined(ZETA_HAS_NO_UNIQUE_ADDRESS)\n        [[msvc::no_unique_address]] InlineStorage<T, N> m_inlineStorage;\n#else\n        InlineStorage<T, N> m_inlineStorage;\n#endif\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Utility/Span.h",
    "content": "#pragma once\n\n#include \"SmallVector.h\"\n\nnamespace ZetaRay::Util\n{\n    // Doesn't own the data -- just a pointer and a size.\n    template<typename T>\n    struct MutableSpan\n    {\n        MutableSpan(T* ptr, size_t n)\n            : m_ptr(ptr),\n            m_size(n)\n        {}\n        template<typename Allocator = Support::SystemAllocator, uint32_t N>\n        MutableSpan(SmallVector<T, Allocator, N>& vec)\n            : m_ptr(vec.data()),\n            m_size(vec.size())\n        {}\n        template<typename Allocator = Support::SystemAllocator>\n        MutableSpan(Vector<T, Allocator>& vec)\n            : m_ptr(vec.data()),\n            m_size(vec.size())\n        {}\n        template<size_t N>\n        MutableSpan(T(&arr)[N])\n            : m_ptr(arr),\n            m_size(N)\n        {}\n\n        ZetaInline bool empty() const\n        {\n            return m_ptr == nullptr || m_size == 0;\n        }\n        ZetaInline T* begin() const\n        {\n            return m_ptr;\n        }\n        ZetaInline T* end() const\n        {\n            return m_ptr + m_size;\n        }\n        ZetaInline T& operator[](size_t pos) const\n        {\n            Assert(pos < m_size, \"Out-of-bound access.\");\n            return *(m_ptr + pos);\n        }\n        ZetaInline size_t size() const\n        {\n            return m_size;\n        }\n        ZetaInline T* data() const\n        {\n            return m_ptr;\n        }\n\n    private:\n        T* m_ptr;\n        size_t m_size;\n    };\n\n    // Doesn't own the data -- just a pointer and a size. Read-only access.\n    template<typename T>\n    struct Span\n    {\n        Span(const T* ptr, size_t n)\n            : m_ptr(ptr),\n            m_size(n)\n        {}\n        template<typename Allocator = Support::SystemAllocator, uint32_t N>\n        Span(const SmallVector<T, Allocator, N>& vec)\n            : m_ptr(vec.data()),\n            m_size(vec.size())\n        {}\n        template<typename Allocator = Support::SystemAllocator>\n        Span(const Vector<T, Allocator>& vec)\n            : m_ptr(vec.data()),\n            m_size(vec.size())\n        {}\n        template<size_t N>\n        Span(T(&arr)[N])\n            : m_ptr(static_cast<const T*>(arr)),\n            m_size(N)\n        {}\n        Span(MutableSpan<T> span)\n            : m_ptr(static_cast<const T*>(span.data())),\n            m_size(span.size())\n        {}\n\n        ZetaInline bool empty() const\n        {\n            return m_ptr == nullptr || m_size == 0;;\n        }\n        ZetaInline const T* begin() const\n        {\n            return m_ptr;\n        }\n        ZetaInline const T* end() const\n        {\n            return m_ptr + m_size;\n        }\n        ZetaInline const T& operator[](size_t pos) const\n        {\n            Assert(pos < m_size, \"Out-of-bound access.\");\n            return *(m_ptr + pos);\n        }\n        ZetaInline size_t size() const\n        {\n            return m_size;\n        }\n        ZetaInline const T* data() const\n        {\n            return m_ptr;\n        }\n\n    private:\n        const T* m_ptr;\n        size_t m_size;\n    };\n\n    // Span for strings\n    // Note that the underlying string is not necessarily null-terminated.\n    struct StrView\n    {\n        StrView(const char* str, size_t n)\n            : m_ptr(str),\n            m_size(n)\n        {}\n        // Assumes string is null-terminated.\n        StrView(const char* str)\n            : m_ptr(str),\n            m_size(strlen(str))\n        {}\n\n        ZetaInline bool empty() const\n        {\n            return m_ptr == nullptr;\n        }\n        ZetaInline const char* begin() const\n        {\n            return m_ptr;\n        }\n        ZetaInline const char* end() const\n        {\n            return m_ptr + m_size;\n        }\n        ZetaInline const char& operator[](size_t pos) const\n        {\n            Assert(pos < m_size, \"Out-of-bound access.\");\n            return *(m_ptr + pos);\n        }\n        // Note that the terminating null character (if any) is not counted\n        ZetaInline size_t size() const\n        {\n            return m_size;\n        }\n        ZetaInline const char* data() const\n        {\n            return m_ptr;\n        }\n\n    private:\n        const char* m_ptr;\n        size_t m_size;\n    };\n\n    struct MemoryRegion\n    {\n        void* Data;\n        size_t SizeInBytes;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaCore/Utility/SynchronizedView.h",
    "content": "#pragma once\n\n#include \"../Win32/Win32.h\"\n#include \"Span.h\"\n\nnamespace ZetaRay::Util\n{\n    template<typename T>\n    struct RSynchronizedView\n    {\n        RSynchronizedView(const T& t, SRWLOCK& lock)\n            : m_view(t),\n            m_lock(lock)\n        {\n            AcquireSRWLockShared(&m_lock);\n        }\n        ~RSynchronizedView()\n        {\n            ReleaseSRWLockShared(&m_lock);\n        }\n        RSynchronizedView(RSynchronizedView&&) = delete;\n        RSynchronizedView& operator=(RSynchronizedView&&) = delete;\n\n        const T& View() const { return m_view; }\n\n    private:\n        const T& m_view;\n        SRWLOCK& m_lock;\n    };\n\n    template<typename T>\n    struct RWSynchronizedView\n    {\n        RWSynchronizedView(T& t, SRWLOCK& lock)\n            : m_view(t),\n            m_lock(lock)\n        {\n            AcquireSRWLockExclusive(&m_lock);\n        }\n        ~RWSynchronizedView()\n        {\n            ReleaseSRWLockExclusive(&m_lock);\n        }\n        RWSynchronizedView(RWSynchronizedView&&) = delete;\n        RWSynchronizedView& operator=(RWSynchronizedView&&) = delete;\n\n        T& View() const { return m_view; }\n\n    private:\n        T& m_view;\n        SRWLOCK& m_lock;\n    };\n\n    template<typename T>\n    struct SynchronizedSpan\n    {\n        SynchronizedSpan(Util::Span<T> t, SRWLOCK& lock)\n            : m_span(t),\n            m_lock(lock)\n        {\n            AcquireSRWLockShared(&m_lock);\n        }\n        ~SynchronizedSpan()\n        {\n            ReleaseSRWLockShared(&m_lock);\n        }\n        SynchronizedSpan(SynchronizedSpan&&) = delete;\n        SynchronizedSpan& operator=(SynchronizedSpan&&) = delete;\n\n        const Util::Span<T> m_span;\n    private:\n        SRWLOCK& m_lock;\n    };    \n    \n    template<typename T>\n    struct SynchronizedMutableSpan\n    {\n        SynchronizedMutableSpan(Util::MutableSpan<T> t, SRWLOCK& lock)\n            : m_span(t),\n            m_lock(lock)\n        {\n            AcquireSRWLockExclusive(&m_lock);\n        }\n        ~SynchronizedMutableSpan()\n        {\n            ReleaseSRWLockExclusive(&m_lock);\n        }\n        SynchronizedMutableSpan(SynchronizedMutableSpan&&) = delete;\n        SynchronizedMutableSpan& operator=(SynchronizedMutableSpan&&) = delete;\n\n        const Util::MutableSpan<T> m_span;\n    private:\n        SRWLOCK& m_lock;\n    };\n}"
  },
  {
    "path": "Source/ZetaCore/Utility/Utility.h",
    "content": "#pragma once\n\n#include \"Span.h\"\n\nnamespace ZetaRay::Util\n{\n    // Callable type Accessor that accepts type T and returns type Key\n    template<typename T, typename Key, typename Accessor>\n    concept GetKey = requires(Accessor a, T t) {\n        { a(t) } -> std::same_as<Key>;\n    };\n\n    // Alternatively:\n    // template<typename T, typename Key, typename Accessor> \n    // requires GetKey<T, Key, Accessor>\n    // int64_t BinarySearch(Span<T> data, Key key, Accessor getMember, int64_t beg = 0, int64_t end = -1)\n    // requires requires(Accessor a, T t) { { a(t) } -> std::same_as<Key>; }\n\n    // Performs binary search in the range [beg, end)\n    template<typename T, typename Key, typename Accessor>\n    requires GetKey<T, Key, Accessor>\n    int64_t BinarySearch(Span<T> data, Key key, Accessor getMember, int64_t beg = 0, int64_t end = -1)\n    {\n        if (data.empty())\n            return -1;\n\n        end = end == -1 ? (int64_t)data.size() : end;\n\n        while (beg < end)\n        {\n            int64_t mid = (beg + end) >> 1;\n\n            if (getMember(data[mid]) < key)\n                beg = mid + 1;\n            else\n                end = mid;\n        }\n\n        if (beg >= (int64_t)data.size() || getMember(data[beg]) != key)\n            return -1;\n\n        return beg;\n    }\n\n    template<typename T>\n    requires std::integral<T>\n    int64_t BinarySearch(Span<T> data, T key, int64_t beg = 0, int64_t end = -1)\n    {\n        if (data.empty())\n            return -1;\n\n        end = end == -1 ? (int64_t)data.size() : end;\n\n        while (beg < end)\n        {\n            int64_t mid = (beg + end) >> 1;\n\n            if (data[mid] < key)\n                beg = mid + 1;\n            else\n                end = mid;\n        }\n\n        if (beg >= (int64_t)data.size() || data[beg] != key)\n            return -1;\n\n        return beg;\n    }\n\n    // Callable type Accessor that accepts type T and returns type Key\n    template<typename T, typename Key, typename Accessor>\n    concept GetFloatKey = std::floating_point<Key> && \n        requires(Accessor a, T t) \n        {\n            { a(t) } -> std::same_as<Key>;\n        };\n\n    // Performs binary search in the range [beg, end]\n    template<typename T, typename Key, typename Accessor>\n    requires GetFloatKey<T, Key, Accessor>\n    int64_t FindInterval(Span<T> data, Key key, Accessor getMember, int64_t beg = 0, int64_t end = -1)\n    {\n        if (data.size() < 2)\n            return -1;\n\n        end = end == -1 ? (int64_t)data.size() - 1 : end;\n\n        while (beg != end)\n        {\n            int64_t mid = 1 + ((beg + end - 1) >> 1);\n\n            if (getMember(data[mid]) > key)\n                end = mid - 1;\n            else\n                beg = mid;\n        }\n\n        if (getMember(data[beg]) <= key && getMember(data[beg + 1]) > key)\n            return beg;\n\n        return -1;\n    }\n\n    ZetaInline uint32_t XXH3_64_To_32(uint64_t hash)\n    {\n        // Ref: https://github.com/Cyan4973/xxHash/issues/453\n        return hash & 0xffffffff;\n    }\n}"
  },
  {
    "path": "Source/ZetaCore/Win32/CMakeLists.txt",
    "content": "set(WIN32_DIR \"${ZETA_CORE_DIR}/Win32\")\nset(WIN32_SRC\n    \"${WIN32_DIR}/Win32App.cpp\"\n    \"${WIN32_DIR}/Win32Filesystem.cpp\"\n    \"${WIN32_DIR}/Win32Timer.cpp\"\n    \"${WIN32_DIR}/Win32.h\"\n    \"${WIN32_DIR}/Win32Common.cpp\")\nset(WIN32_SRC ${WIN32_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaCore/Win32/Win32.h",
    "content": "#pragma once\n\n#define NOMINMAX\n#define NODRAWTEXT\n//#define NOGDI\n#define NOBITMAP\n#define NOMCX\n#define NOSERVICE\n#define NOHELP\n#define NOIME\n#define WIN32_LEAN_AND_MEAN\n#include <Windows.h>\n\n// from <Windowsx.h>\n#define GET_X_LPARAM(lp)           ((int)(short)LOWORD(lp))\n#define GET_Y_LPARAM(lp)           ((int)(short)HIWORD(lp))"
  },
  {
    "path": "Source/ZetaCore/Win32/Win32App.cpp",
    "content": "#include \"../App/Log.h\"\n#include \"../Support/FrameMemory.h\"\n#include \"../App/Timer.h\"\n#include \"../App/Common.h\"\n#include \"../Support/Param.h\"\n#include \"../Support/Stat.h\"\n#include \"../Core/RendererCore.h\"\n#include \"../Scene/SceneCore.h\"\n#include \"../Scene/Camera.h\"\n#include \"../Support/ThreadPool.h\"\n#include \"../Assets/Font/Font.h\"\n#include \"../Assets/Font/IconsFontAwesome6.h\"\n\n#define XXH_STATIC_LINKING_ONLY\n#define XXH_IMPLEMENTATION \n#include <xxHash/xxhash.h>\n\n#include <ImGui/imgui.h>\n#include <ImGui/implot.h>\n#include <ImGui/imnodes.h>\n\n#include <Uxtheme.h>    // for HTHEME\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::App;\nusing namespace ZetaRay::App::Common;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Math;\n\nnamespace\n{\n    struct FrameTime\n    {\n        static constexpr int HIST_LEN = 60;\n        float FrameTimeHist[HIST_LEN] = { 0.0 };\n        int NextFramHistIdx = 0;\n    };\n\n    struct ParamUpdate\n    {\n        enum OP_TYPE\n        {\n            ADD,\n            REMOVE\n        };\n\n        ZetaRay::Support::ParamVariant P;\n        OP_TYPE Op;\n    };\n\n    // Ref: https://github.com/ysc3839/win32-darkmode\n    enum PreferredAppMode\n    {\n        Default,\n        AllowDark,\n        ForceDark,\n        ForceLight,\n        Max\n    };\n\n    enum WINDOWCOMPOSITIONATTRIB\n    {\n        WCA_UNDEFINED = 0,\n        WCA_NCRENDERING_ENABLED = 1,\n        WCA_NCRENDERING_POLICY = 2,\n        WCA_TRANSITIONS_FORCEDISABLED = 3,\n        WCA_ALLOW_NCPAINT = 4,\n        WCA_CAPTION_BUTTON_BOUNDS = 5,\n        WCA_NONCLIENT_RTL_LAYOUT = 6,\n        WCA_FORCE_ICONIC_REPRESENTATION = 7,\n        WCA_EXTENDED_FRAME_BOUNDS = 8,\n        WCA_HAS_ICONIC_BITMAP = 9,\n        WCA_THEME_ATTRIBUTES = 10,\n        WCA_NCRENDERING_EXILED = 11,\n        WCA_NCADORNMENTINFO = 12,\n        WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,\n        WCA_VIDEO_OVERLAY_ACTIVE = 14,\n        WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,\n        WCA_DISALLOW_PEEK = 16,\n        WCA_CLOAK = 17,\n        WCA_CLOAKED = 18,\n        WCA_ACCENT_POLICY = 19,\n        WCA_FREEZE_REPRESENTATION = 20,\n        WCA_EVER_UNCLOAKED = 21,\n        WCA_VISUAL_OWNER = 22,\n        WCA_HOLOGRAPHIC = 23,\n        WCA_EXCLUDED_FROM_DDA = 24,\n        WCA_PASSIVEUPDATEMODE = 25,\n        WCA_USEDARKMODECOLORS = 26,\n        WCA_LAST = 27\n    };\n\n    struct WINDOWCOMPOSITIONATTRIBDATA\n    {\n        WINDOWCOMPOSITIONATTRIB Attrib;\n        PVOID pvData;\n        SIZE_T cbData;\n    };\n\n    using fnSetWindowCompositionAttribute = BOOL(WINAPI*)(HWND hWnd, WINDOWCOMPOSITIONATTRIBDATA*);\n    // 1809 17763\n    using fnShouldAppsUseDarkMode = bool (WINAPI*)(); // ordinal 132\n    using fnAllowDarkModeForWindow = bool (WINAPI*)(HWND hWnd, bool allow); // ordinal 133\n    using fnRefreshImmersiveColorPolicyState = void (WINAPI*)(); // ordinal 104\n    using fnIsDarkModeAllowedForWindow = bool (WINAPI*)(HWND hWnd); // ordinal 137\n    using fnOpenNcThemeData = HTHEME(WINAPI*)(HWND hWnd, LPCWSTR pszClassList); // ordinal 49\n    // 1903 18362\n    using fnShouldSystemUseDarkMode = bool (WINAPI*)(); // ordinal 138\n    using fnSetPreferredAppMode = PreferredAppMode(WINAPI*)(PreferredAppMode appMode); // ordinal 135, in 1903\n    using fnIsDarkModeAllowedForApp = bool (WINAPI*)(); // ordinal 139\n}\n\nnamespace\n{\n    struct FrameMemoryContext\n    {\n        alignas(64) int m_threadFrameAllocIndices[MAX_NUM_THREADS] = { -1 };\n        std::atomic_int32_t m_currFrameAllocIndex;\n    };\n\n    struct AppData\n    {\n        inline static constexpr const char* COMPILED_SHADER_DIR = \"..\\\\Assets\\\\CSO\";\n        inline static constexpr const char* PSO_CACHE_DIR = \"..\\\\Assets\\\\PsoCache\";\n        inline static constexpr const char* ASSET_DIR = \"..\\\\Assets\";\n        inline static constexpr const char* TOOLS_DIR = \"..\\\\Tools\";\n        inline static constexpr const char* DXC_PATH = \"..\\\\Tools\\\\dxc\\\\bin\\\\x64\\\\dxc.exe\";\n        inline static constexpr const char* RENDER_PASS_DIR = \"..\\\\Source\\\\ZetaRenderPass\";\n        static constexpr int NUM_BACKGROUND_THREADS = 2;\n        static constexpr int MAX_NUM_TASKS_PER_FRAME = 256;\n        static constexpr int CLIPBOARD_LEN = 128;\n        static constexpr int FRAME_ALLOCATOR_BLOCK_SIZE = FRAME_ALLOCATOR_MAX_ALLOCATION_SIZE;\n\n        struct alignas(64) TaskSignal\n        {\n            std::atomic_int32_t Indegree;\n            std::atomic_bool BlockFlag;\n        };\n\n        TaskSignal m_registeredTasks[MAX_NUM_TASKS_PER_FRAME];\n\n        FrameMemoryContext m_frameMemoryContext;\n        Camera m_camera;\n        FrameMemory<FRAME_ALLOCATOR_BLOCK_SIZE> m_frameMemory;\n        ThreadPool m_workerThreadPool;\n        ThreadPool m_backgroundThreadPool;\n        RendererCore m_renderer;\n        Timer m_timer;\n        SceneCore m_scene;\n        Core::GpuMemory::Texture m_imguiFontTex;\n        Core::DescriptorTable m_fontTexSRV;\n        SmallVector<ParamVariant> m_params;\n        SmallVector<ParamUpdate, SystemAllocator, 32> m_paramsUpdates;\n        SmallVector<ShaderReloadHandler> m_shaderReloadHandlers;\n        SmallVector<Stat, FrameAllocator> m_frameStats;\n        MemoryArena m_logStrArena;\n        SmallVector<LogMessage> m_frameLogs;\n\n        SRWLOCK m_stdOutLock = SRWLOCK_INIT;\n        SRWLOCK m_paramLock = SRWLOCK_INIT;\n        SRWLOCK m_paramUpdateLock = SRWLOCK_INIT;\n        SRWLOCK m_shaderReloadLock = SRWLOCK_INIT;\n        SRWLOCK m_statsLock = SRWLOCK_INIT;\n        SRWLOCK m_logLock = SRWLOCK_INIT;\n\n        HWND m_hwnd;\n        HWND m_imguiMouseHwnd;\n        FrameTime m_frameTime;\n        Motion m_frameMotion;\n        std::atomic_int32_t m_currTaskSignalIdx = 0;\n        int m_inMouseWheelMove = 0;\n        RECT m_wndRectCache;\n        ImGuiMouseCursor m_imguiCursor = ImGuiMouseCursor_COUNT;\n        int m_imguiMouseTrackedArea = 0;   // 0: not tracked, 1: client are, 2: non-client area\n        int m_imguiMouseButtonsDown = 0;\n        float m_upscaleFactor = 1.0f;\n        float m_queuedUpscaleFactor = 1.0f;\n        float m_cameraAcceleration = 40.0f;\n        RECT m_dpiChangeNewRect;\n        uint16_t m_processorCoreCount = 0;\n        uint16_t m_displayWidth;\n        uint16_t m_displayHeight;\n        int16 m_lastMousePosX = 0;\n        int16 m_lastMousePosY = 0;\n        int16 m_lastLMBClickPosX = 0;\n        int16 m_lastLMBClickPosY = 0;\n        uint16_t m_dpi;\n        bool m_isActive = true;\n        bool m_manuallyPaused = false;\n        bool m_picked = false;\n        bool m_multiPick = false;\n        bool m_inSizeMove = false;\n        bool m_minimized = false;\n        bool m_isFullScreen = false;\n        bool m_imguiMouseTracked = false;\n        char m_clipboard[CLIPBOARD_LEN];\n        bool m_isInitialized = false;\n        bool m_issueResize = false;\n        bool m_dpiChanged = false;\n    };\n\n    AppData* g_app = nullptr;\n}\n\n// Copied from imgui_impl_win32\nnamespace\n{\n    // See https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages\n    // Prefer to call this at the top of the message handler to avoid the possibility of \n    // other Win32 calls interfering with this.\n    ImGuiMouseSource ImGui_GetMouseSourceFromMessageExtraInfo()\n    {\n        LPARAM extra_info = GetMessageExtraInfo();\n        if ((extra_info & 0xFFFFFF80) == 0xFF515700)\n            return ImGuiMouseSource_Pen;\n        if ((extra_info & 0xFFFFFF80) == 0xFF515780)\n            return ImGuiMouseSource_TouchScreen;\n        return ImGuiMouseSource_Mouse;\n    }\n\n    bool ImGui_UpdateMouseCursor()\n    {\n        ImGuiIO& io = ImGui::GetIO();\n        if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)\n            return false;\n\n        ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();\n        if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)\n        {\n            // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor\n            SetCursor(nullptr);\n        }\n        else\n        {\n            // Show OS mouse cursor\n            LPTSTR win32_cursor = IDC_ARROW;\n            switch (imgui_cursor)\n            {\n            case ImGuiMouseCursor_Arrow:        win32_cursor = IDC_ARROW; break;\n            case ImGuiMouseCursor_TextInput:    win32_cursor = IDC_IBEAM; break;\n            case ImGuiMouseCursor_ResizeAll:    win32_cursor = IDC_SIZEALL; break;\n            case ImGuiMouseCursor_ResizeEW:     win32_cursor = IDC_SIZEWE; break;\n            case ImGuiMouseCursor_ResizeNS:     win32_cursor = IDC_SIZENS; break;\n            case ImGuiMouseCursor_ResizeNESW:   win32_cursor = IDC_SIZENESW; break;\n            case ImGuiMouseCursor_ResizeNWSE:   win32_cursor = IDC_SIZENWSE; break;\n            case ImGuiMouseCursor_Hand:         win32_cursor = IDC_HAND; break;\n            case ImGuiMouseCursor_NotAllowed:   win32_cursor = IDC_NO; break;\n            }\n\n            SetCursor(LoadCursor(nullptr, win32_cursor));\n        }\n\n        return true;\n    }\n\n    void ImGui_UpdateMouse()\n    {\n        ImGuiIO& io = ImGui::GetIO();\n\n        HWND focused_window = ::GetForegroundWindow();\n        const bool is_app_focused = (focused_window == g_app->m_hwnd);\n        if (is_app_focused)\n        {\n            // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when \n            // ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)\n            if (io.WantSetMousePos)\n            {\n                POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };\n                if (ClientToScreen(g_app->m_hwnd, &pos))\n                    SetCursorPos(pos.x, pos.y);\n            }\n\n            // (Optional) Fallback to provide mouse position when focused (WM_MOUSEMOVE already provides this when hovered or captured)\n            // This also fills a short gap when clicking non-client area: WM_NCMOUSELEAVE -> modal OS move -> gap -> WM_NCMOUSEMOVE\n            if (!io.WantSetMousePos && g_app->m_imguiMouseTrackedArea == 0)\n            {\n                POINT pos;\n                if (GetCursorPos(&pos) && ScreenToClient(g_app->m_hwnd, &pos))\n                    io.AddMousePosEvent((float)pos.x, (float)pos.y);\n            }\n        }\n    }\n\n    ImGuiKey ImGui_VirtualKeyToImGuiKey(WPARAM wParam, LPARAM lParam)\n    {\n        // There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED.\n        if ((wParam == VK_RETURN) && (HIWORD(lParam) & KF_EXTENDED))\n            return ImGuiKey_KeypadEnter;\n\n        switch (wParam)\n        {\n        case VK_TAB: return ImGuiKey_Tab;\n        case VK_LEFT: return ImGuiKey_LeftArrow;\n        case VK_RIGHT: return ImGuiKey_RightArrow;\n        case VK_UP: return ImGuiKey_UpArrow;\n        case VK_DOWN: return ImGuiKey_DownArrow;\n        case VK_PRIOR: return ImGuiKey_PageUp;\n        case VK_NEXT: return ImGuiKey_PageDown;\n        case VK_HOME: return ImGuiKey_Home;\n        case VK_END: return ImGuiKey_End;\n        case VK_INSERT: return ImGuiKey_Insert;\n        case VK_DELETE: return ImGuiKey_Delete;\n        case VK_BACK: return ImGuiKey_Backspace;\n        case VK_SPACE: return ImGuiKey_Space;\n        case VK_RETURN: return ImGuiKey_Enter;\n        case VK_ESCAPE: return ImGuiKey_Escape;\n        case VK_OEM_7: return ImGuiKey_Apostrophe;\n        case VK_OEM_COMMA: return ImGuiKey_Comma;\n        case VK_OEM_MINUS: return ImGuiKey_Minus;\n        case VK_OEM_PERIOD: return ImGuiKey_Period;\n        case VK_OEM_2: return ImGuiKey_Slash;\n        case VK_OEM_1: return ImGuiKey_Semicolon;\n        case VK_OEM_PLUS: return ImGuiKey_Equal;\n        case VK_OEM_4: return ImGuiKey_LeftBracket;\n        case VK_OEM_5: return ImGuiKey_Backslash;\n        case VK_OEM_6: return ImGuiKey_RightBracket;\n        case VK_OEM_3: return ImGuiKey_GraveAccent;\n        case VK_CAPITAL: return ImGuiKey_CapsLock;\n        case VK_SCROLL: return ImGuiKey_ScrollLock;\n        case VK_NUMLOCK: return ImGuiKey_NumLock;\n        case VK_SNAPSHOT: return ImGuiKey_PrintScreen;\n        case VK_PAUSE: return ImGuiKey_Pause;\n        case VK_NUMPAD0: return ImGuiKey_Keypad0;\n        case VK_NUMPAD1: return ImGuiKey_Keypad1;\n        case VK_NUMPAD2: return ImGuiKey_Keypad2;\n        case VK_NUMPAD3: return ImGuiKey_Keypad3;\n        case VK_NUMPAD4: return ImGuiKey_Keypad4;\n        case VK_NUMPAD5: return ImGuiKey_Keypad5;\n        case VK_NUMPAD6: return ImGuiKey_Keypad6;\n        case VK_NUMPAD7: return ImGuiKey_Keypad7;\n        case VK_NUMPAD8: return ImGuiKey_Keypad8;\n        case VK_NUMPAD9: return ImGuiKey_Keypad9;\n        case VK_DECIMAL: return ImGuiKey_KeypadDecimal;\n        case VK_DIVIDE: return ImGuiKey_KeypadDivide;\n        case VK_MULTIPLY: return ImGuiKey_KeypadMultiply;\n        case VK_SUBTRACT: return ImGuiKey_KeypadSubtract;\n        case VK_ADD: return ImGuiKey_KeypadAdd;\n        case VK_LSHIFT: return ImGuiKey_LeftShift;\n        case VK_LCONTROL: return ImGuiKey_LeftCtrl;\n        case VK_LMENU: return ImGuiKey_LeftAlt;\n        case VK_LWIN: return ImGuiKey_LeftSuper;\n        case VK_RSHIFT: return ImGuiKey_RightShift;\n        case VK_RCONTROL: return ImGuiKey_RightCtrl;\n        case VK_RMENU: return ImGuiKey_RightAlt;\n        case VK_RWIN: return ImGuiKey_RightSuper;\n        case VK_APPS: return ImGuiKey_Menu;\n        case '0': return ImGuiKey_0;\n        case '1': return ImGuiKey_1;\n        case '2': return ImGuiKey_2;\n        case '3': return ImGuiKey_3;\n        case '4': return ImGuiKey_4;\n        case '5': return ImGuiKey_5;\n        case '6': return ImGuiKey_6;\n        case '7': return ImGuiKey_7;\n        case '8': return ImGuiKey_8;\n        case '9': return ImGuiKey_9;\n        case 'A': return ImGuiKey_A;\n        case 'B': return ImGuiKey_B;\n        case 'C': return ImGuiKey_C;\n        case 'D': return ImGuiKey_D;\n        case 'E': return ImGuiKey_E;\n        case 'F': return ImGuiKey_F;\n        case 'G': return ImGuiKey_G;\n        case 'H': return ImGuiKey_H;\n        case 'I': return ImGuiKey_I;\n        case 'J': return ImGuiKey_J;\n        case 'K': return ImGuiKey_K;\n        case 'L': return ImGuiKey_L;\n        case 'M': return ImGuiKey_M;\n        case 'N': return ImGuiKey_N;\n        case 'O': return ImGuiKey_O;\n        case 'P': return ImGuiKey_P;\n        case 'Q': return ImGuiKey_Q;\n        case 'R': return ImGuiKey_R;\n        case 'S': return ImGuiKey_S;\n        case 'T': return ImGuiKey_T;\n        case 'U': return ImGuiKey_U;\n        case 'V': return ImGuiKey_V;\n        case 'W': return ImGuiKey_W;\n        case 'X': return ImGuiKey_X;\n        case 'Y': return ImGuiKey_Y;\n        case 'Z': return ImGuiKey_Z;\n        case VK_F1: return ImGuiKey_F1;\n        case VK_F2: return ImGuiKey_F2;\n        case VK_F3: return ImGuiKey_F3;\n        case VK_F4: return ImGuiKey_F4;\n        case VK_F5: return ImGuiKey_F5;\n        case VK_F6: return ImGuiKey_F6;\n        case VK_F7: return ImGuiKey_F7;\n        case VK_F8: return ImGuiKey_F8;\n        case VK_F9: return ImGuiKey_F9;\n        case VK_F10: return ImGuiKey_F10;\n        case VK_F11: return ImGuiKey_F11;\n        case VK_F12: return ImGuiKey_F12;\n        case VK_F13: return ImGuiKey_F13;\n        case VK_F14: return ImGuiKey_F14;\n        case VK_F15: return ImGuiKey_F15;\n        case VK_F16: return ImGuiKey_F16;\n        case VK_F17: return ImGuiKey_F17;\n        case VK_F18: return ImGuiKey_F18;\n        case VK_F19: return ImGuiKey_F19;\n        case VK_F20: return ImGuiKey_F20;\n        case VK_F21: return ImGuiKey_F21;\n        case VK_F22: return ImGuiKey_F22;\n        case VK_F23: return ImGuiKey_F23;\n        case VK_F24: return ImGuiKey_F24;\n        case VK_BROWSER_BACK: return ImGuiKey_AppBack;\n        case VK_BROWSER_FORWARD: return ImGuiKey_AppForward;\n        default: return ImGuiKey_None;\n        }\n    }\n\n    bool ImGui_IsVkDown(int vk)\n    {\n        return (GetKeyState(vk) & 0x8000) != 0;\n    }\n\n    void ImGui_AddKeyEvent(ImGuiKey key, bool down, int native_keycode, int native_scancode = -1)\n    {\n        ImGuiIO& io = ImGui::GetIO();\n        io.AddKeyEvent(key, down);\n        // To support legacy indexing (<1.87 user code)\n        io.SetKeyEventNativeData(key, native_keycode, native_scancode);\n        IM_UNUSED(native_scancode);\n    }\n\n    void ImGui_UpdateKeyModifiers()\n    {\n        ImGuiIO& io = ImGui::GetIO();\n        io.AddKeyEvent(ImGuiMod_Ctrl, ImGui_IsVkDown(VK_CONTROL));\n        io.AddKeyEvent(ImGuiMod_Shift, ImGui_IsVkDown(VK_SHIFT));\n        io.AddKeyEvent(ImGuiMod_Alt, ImGui_IsVkDown(VK_MENU));\n        io.AddKeyEvent(ImGuiMod_Super, ImGui_IsVkDown(VK_LWIN) || ImGui_IsVkDown(VK_RWIN));\n    }\n\n    void ImGui_ProcessKeyEventsWorkarounds()\n    {\n        // Left & right Shift keys: when both are pressed together, Windows tend to not \n        // generate the WM_KEYUP event for the first released one.\n        if (ImGui::IsKeyDown(ImGuiKey_LeftShift) && !ImGui_IsVkDown(VK_LSHIFT))\n            ImGui_AddKeyEvent(ImGuiKey_LeftShift, false, VK_LSHIFT);\n        if (ImGui::IsKeyDown(ImGuiKey_RightShift) && !ImGui_IsVkDown(VK_RSHIFT))\n            ImGui_AddKeyEvent(ImGuiKey_RightShift, false, VK_RSHIFT);\n\n        // Sometimes WM_KEYUP for Win key is not passed down to the app (e.g. for Win+V \n        // on some setups, according to GLFW).\n        if (ImGui::IsKeyDown(ImGuiKey_LeftSuper) && !ImGui_IsVkDown(VK_LWIN))\n            ImGui_AddKeyEvent(ImGuiKey_LeftSuper, false, VK_LWIN);\n        if (ImGui::IsKeyDown(ImGuiKey_RightSuper) && !ImGui_IsVkDown(VK_RWIN))\n            ImGui_AddKeyEvent(ImGuiKey_RightSuper, false, VK_RWIN);\n    }\n}\n\nnamespace ZetaRay::AppImpl\n{\n    void LoadFont()\n    {\n        ImGuiIO& io = ImGui::GetIO();\n        io.Fonts->Clear();\n\n#if defined(__clang__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wcast-function-type-mismatch\"\n#endif\n        using getFontFP = FontSpan(*)(FONT_TYPE f);\n        HINSTANCE fontLib = LoadLibraryExA(\"Font\", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);\n        CheckWin32(fontLib);\n\n        auto fpGetFont = reinterpret_cast<getFontFP>(GetProcAddress(fontLib, \"GetFont\"));\n        CheckWin32(fpGetFont);\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n\n        constexpr auto fontType = FONT_TYPE::BFONT;\n        FontSpan f = fpGetFont(fontType);\n        Check(f.Data, \"font was not found.\");\n\n        constexpr float fontSizePixels96 = 12.0f;\n        float fontSizePixelsDPI = ((float)g_app->m_dpi / USER_DEFAULT_SCREEN_DPI) * fontSizePixels96;\n        fontSizePixelsDPI = roundf(fontSizePixelsDPI);\n\n        ImFontConfig font_cfg;\n        // Retain ownership of font data so ImGui wouldn't free it\n        font_cfg.FontDataOwnedByAtlas = false;\n        io.Fonts->AddFontFromMemoryCompressedBase85TTF(reinterpret_cast<const char*>(f.Data),\n            fontSizePixelsDPI, &font_cfg);\n\n        float baseFontSize = 16.0f;\n        baseFontSize *= ((float)g_app->m_dpi / USER_DEFAULT_SCREEN_DPI);\n        // FontAwesome fonts need to have their sizes reduced by 2.0f/3.0f in order to align correctly\n        float iconFontSize = baseFontSize * 2.0f / 3.0f;\n\n        constexpr ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };\n        ImFontConfig icons_config;\n        icons_config.MergeMode = true;\n        icons_config.PixelSnapH = true;\n        icons_config.GlyphMinAdvanceX = iconFontSize;\n        // Retain ownership of font data so ImGui wouldn't free it\n        icons_config.FontDataOwnedByAtlas = false;\n\n        auto iconFont = fpGetFont(FONT_TYPE::FONT_AWESOME_6);\n        io.Fonts->AddFontFromMemoryTTF(const_cast<void*>(iconFont.Data), (int)iconFont.N,\n            iconFontSize, &icons_config, icons_ranges);\n\n        unsigned char* pixels;\n        int width;\n        int height;\n        io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);\n\n        g_app->m_imguiFontTex = GpuMemory::GetTexture2DAndInit(\"ImGuiFont\", width, height,\n            DXGI_FORMAT_R8G8B8A8_UNORM, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, pixels);\n        // Data copied to upload heap, safe to release\n        io.Fonts->ClearTexData();\n\n        g_app->m_fontTexSRV = App::GetRenderer().GetGpuDescriptorHeap().Allocate(1);\n        Direct3DUtil::CreateTexture2DSRV(g_app->m_imguiFontTex, g_app->m_fontTexSRV.CPUHandle(0));\n\n        const uint32_t gpuDescHeapIdx = g_app->m_fontTexSRV.GPUDescriptorHeapIndex(0);\n        static_assert(sizeof(gpuDescHeapIdx) <= sizeof(io.UserData), \"overflow\");\n        memcpy(&io.UserData, &gpuDescHeapIdx, sizeof(gpuDescHeapIdx));\n\n        FreeLibrary(fontLib);\n    }\n\n    void OnActivated()\n    {\n        g_app->m_timer.Resume();\n        g_app->m_isActive = true;\n        SetWindowTextA(g_app->m_hwnd, \"ZetaRay\");\n    }\n\n    void OnDeactivated()\n    {\n        g_app->m_timer.Pause();\n        g_app->m_isActive = false;\n        SetWindowTextA(g_app->m_hwnd, \"ZetaRay (Paused - press 'P' to resume)\");\n    }\n\n    void OnDPIChanged(uint16_t newDPI, const RECT* newRect)\n    {\n        g_app->m_dpi = newDPI;\n        g_app->m_dpiChangeNewRect = *newRect;\n        g_app->m_dpiChanged = true;\n    }\n\n    void InitImGui()\n    {\n        ImGui::CreateContext();\n        ImPlot::CreateContext();\n        ImNodes::CreateContext();\n\n        ImGui::StyleColorsDark();\n\n        ImGuiStyle& style = ImGui::GetStyle();\n        ImVec4* colors = style.Colors;\n\n        colors[ImGuiCol_WindowBg] = ImVec4(0.012286487f, 0.012286487f, 0.012286487f, 1.0f);\n        colors[ImGuiCol_Border] = ImVec4(1.0f / 255, 1.0f / 255, 1.1f / 255, 0.0f);\n        colors[ImGuiCol_TitleBg] = ImVec4(26 / 255.0f, 26 / 255.0f, 26 / 255.0f, 1.0f);\n        colors[ImGuiCol_Tab] = ImVec4(0.046665083f, 0.046665083f, 0.046665083f, 1.0f);\n        colors[ImGuiCol_TabHovered] = ImVec4(40 / 255.0f, 42 / 255.0f, 47 / 255.0f, 1.0f);\n        colors[ImGuiCol_TabSelected] = ImVec4(7 / 255.0f, 26 / 255.0f, 56 / 255.0f, 1.0f);\n        colors[ImGuiCol_TitleBg] = colors[ImGuiCol_Tab];\n        colors[ImGuiCol_TitleBgActive] = ImVec4(0.08865560f, 0.08865560f, 0.08865560f, 1.0f);\n        colors[ImGuiCol_FrameBg] = ImVec4(10 / 255.0f, 10 / 255.0f, 10 / 255.0f, 1.0f);\n        colors[ImGuiCol_Header] = ImVec4(0.046665083f, 0.046665083f, 0.046665083f, 1.0f);\n        colors[ImGuiCol_HeaderActive] = colors[ImGuiCol_WindowBg];\n        colors[ImGuiCol_HeaderHovered] = ImVec4(33 / 255.0f, 33 / 255.0f, 33 / 255.0f, 1.0f);\n        colors[ImGuiCol_CheckMark] = ImVec4(112 / 255.0f, 118 / 255.0f, 128 / 255.0f, 1.0f);\n        colors[ImGuiCol_TableHeaderBg] = ImVec4(15 / 255.0f, 15 / 255.0f, 15 / 255.0f, 1.0f);\n        colors[ImGuiCol_TableRowBg] = ImVec4(1 / 255.0f, 1 / 255.0f, 1 / 255.0f, 1.0f);\n        colors[ImGuiCol_TableRowBgAlt] = ImVec4(7 / 255.0f, 7 / 255.0f, 8 / 255.0f, 1.0f);\n        colors[ImGuiCol_TableBorderLight] = ImVec4(15 / 255.0f, 15 / 255.0f, 15 / 255.0f, 1.0f);\n        colors[ImGuiCol_TableBorderStrong] = ImVec4(27 / 255.0f, 27 / 255.0f, 27 / 255.0f, 1.0f);\n        colors[ImGuiCol_Button] = ImVec4(31 / 255.0f, 31 / 255.0f, 31 / 255.0f, 1.0f);\n        colors[ImGuiCol_ButtonHovered] = ImVec4(95 / 255.0f, 95 / 255.0f, 95 / 255.0f, 1.0f);\n        colors[ImGuiCol_ButtonActive] = ImVec4(46 / 255.0f, 103 / 255.0f, 130 / 255.0f, 1.0f);\n        colors[ImGuiCol_FrameBgHovered] = ImVec4(23 / 255.0f, 23 / 255.0f, 23 / 255.0f, 1.0f);\n        colors[ImGuiCol_FrameBgActive] = ImVec4(73 / 255.0f, 73 / 255.0f, 73 / 255.0f, 1.0f);\n        colors[ImGuiCol_SliderGrab] = ImVec4(41 / 255.0f, 41 / 255.0f, 41 / 255.0f, 1.0f);\n        colors[ImGuiCol_SliderGrabActive] = ImVec4(150 / 255.0f, 150 / 255.0f, 150 / 255.0f, 1.0f);\n\n        style.FramePadding = ImVec2(7.0f, 3.0f);\n        style.GrabMinSize = 13.0f;\n        style.FrameRounding = 2.5f;\n        style.GrabRounding = 2.5f;\n        style.ItemSpacing = ImVec2(8.0f, 7.0f);\n        style.CellPadding.x = 10.0;\n\n        style.ScaleAllSizes((float)g_app->m_dpi / USER_DEFAULT_SCREEN_DPI);\n\n        ImGuiIO& io = ImGui::GetIO();\n        io.DisplaySize = ImVec2((float)g_app->m_displayWidth, (float)g_app->m_displayHeight);\n        io.IniFilename = nullptr;\n        // We can honor GetMouseCursor() values (optional)\n        io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;\n        // We can honor io.WantSetMousePos requests (optional, rarely used)\n        io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;\n\n        LoadFont();\n\n        ImNodes::GetIO().AltMouseButton = ImGuiMouseButton_Right;\n    }\n\n    void UpdateStats(size_t tempMemoryUsage)\n    {\n        g_app->m_frameStats.free_memory();\n\n        const float frameTimeMs = g_app->m_timer.GetTotalFrameCount() > 1 ?\n            (float)(g_app->m_timer.GetElapsedTime() * 1000.0f) :\n            0.0f;\n\n        auto& frameStats = g_app->m_frameTime;\n\n        if (frameStats.NextFramHistIdx < frameStats.HIST_LEN)\n            frameStats.FrameTimeHist[frameStats.NextFramHistIdx++] = frameTimeMs;\n        else\n        {\n            // shift left\n            for (int i = 0; i < frameStats.HIST_LEN - 1; i++)\n                frameStats.FrameTimeHist[i] = frameStats.FrameTimeHist[i + 1];\n\n            frameStats.FrameTimeHist[frameStats.HIST_LEN - 1] = frameTimeMs;\n        }\n\n        DXGI_QUERY_VIDEO_MEMORY_INFO memoryInfo = {};\n        CheckHR(g_app->m_renderer.GetAdapter()->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &memoryInfo));\n\n        if (memoryInfo.CurrentUsage > memoryInfo.Budget)\n            LOG_UI_WARNING(\"VRAM usage exceeded available budget; performance can be severely impacted.\");\n\n        float movingAvg = 0;\n        constexpr int N = 8;\n        for (int i = 0; i < N; i++)\n            movingAvg += frameStats.FrameTimeHist[frameStats.HIST_LEN - 1 - i];\n\n        g_app->m_frameStats.emplace_back(\"Frame\", \"FPS\", g_app->m_timer.GetFramesPerSecond());\n        g_app->m_frameStats.emplace_back(\"Frame\", \"Frame time\", movingAvg / N);\n        g_app->m_frameStats.emplace_back(\"GPU\", \"VRAM Usage (MB)\", memoryInfo.CurrentUsage >> 20);\n        g_app->m_frameStats.emplace_back(\"GPU\", \"VRAM Budget (MB)\", memoryInfo.Budget >> 20);\n        g_app->m_frameStats.emplace_back(\"Frame\", \"Frame temp memory usage (kb)\", tempMemoryUsage >> 10);\n    }\n\n    void Update(TaskSet& sceneTS, TaskSet& sceneRendererTS, size_t tempMemoryUsage)\n    {\n        UpdateStats(tempMemoryUsage);\n\n        ImGui_UpdateMouse();\n        ImGui_ProcessKeyEventsWorkarounds();\n\n        // Update OS mouse cursor with the cursor requested by imgui\n        ImGuiMouseCursor mouse_cursor = ImGui::GetIO().MouseDrawCursor ? ImGuiMouseCursor_None :\n            ImGui::GetMouseCursor();\n        if (g_app->m_imguiCursor != mouse_cursor)\n        {\n            g_app->m_imguiCursor = mouse_cursor;\n            ImGui_UpdateMouseCursor();\n        }\n\n        ImGui::NewFrame();\n\n        if (!(GetAsyncKeyState(VK_LSHIFT) & (1 << 15)))\n        {\n            float scale = g_app->m_inMouseWheelMove ? g_app->m_inMouseWheelMove * 20 : 1.0f;\n            scale = g_app->m_frameMotion.Acceleration.z != 0 || g_app->m_frameMotion.Acceleration.x != 0 ?\n                fabsf(scale) : scale;\n\n            if (g_app->m_inMouseWheelMove || (GetAsyncKeyState('W') & (1 << 16)))\n                g_app->m_frameMotion.Acceleration.z = 1;\n            if (GetAsyncKeyState('A') & (1 << 16))\n                g_app->m_frameMotion.Acceleration.x = -1;\n            if (!g_app->m_inMouseWheelMove && (GetAsyncKeyState('S') & (1 << 16)))\n                g_app->m_frameMotion.Acceleration.z = -1;\n            if (GetAsyncKeyState('D') & (1 << 16))\n                g_app->m_frameMotion.Acceleration.x = 1;\n\n            g_app->m_frameMotion.Acceleration.normalize();\n            g_app->m_frameMotion.Acceleration *= g_app->m_cameraAcceleration * scale;\n        }\n        else\n        {\n            if (g_app->m_inMouseWheelMove)\n                g_app->m_cameraAcceleration *= (1 + g_app->m_inMouseWheelMove * 0.1f);\n        }\n\n        g_app->m_inMouseWheelMove = 0;\n        g_app->m_frameMotion.dt = (float)g_app->m_timer.GetElapsedTime();\n\n        g_app->m_camera.Update(g_app->m_frameMotion);\n\n        if (g_app->m_picked)\n        {\n            if (g_app->m_multiPick)\n                g_app->m_scene.MultiPick(g_app->m_lastLMBClickPosX, g_app->m_lastLMBClickPosY);\n            else\n                g_app->m_scene.Pick(g_app->m_lastLMBClickPosX, g_app->m_lastLMBClickPosY);\n\n            g_app->m_picked = false;\n            g_app->m_multiPick = false;\n        }\n\n        g_app->m_scene.Update(g_app->m_timer.GetElapsedTime(), sceneTS, sceneRendererTS);\n    }\n\n    void OnWindowSizeChanged()\n    {\n        if (g_app->m_timer.GetTotalFrameCount() > 0)\n        {\n            RECT rect;\n            GetClientRect(g_app->m_hwnd, &rect);\n\n            const uint16_t newWidth = (uint16_t)(rect.right - rect.left);\n            const uint16_t newHeight = (uint16_t)(rect.bottom - rect.top);\n\n            if (newWidth == g_app->m_displayWidth && newHeight == g_app->m_displayHeight)\n                return;\n\n            g_app->m_displayWidth = newWidth;\n            g_app->m_displayHeight = newHeight;\n\n            const float renderWidth = g_app->m_displayWidth / g_app->m_upscaleFactor;\n            const float renderHeight = g_app->m_displayHeight / g_app->m_upscaleFactor;\n\n            // following order is important\n            g_app->m_renderer.OnWindowSizeChanged(g_app->m_hwnd, (uint16_t)renderWidth, (uint16_t)renderHeight,\n                g_app->m_displayWidth, g_app->m_displayHeight);\n            g_app->m_scene.OnWindowSizeChanged();\n            g_app->m_camera.OnWindowSizeChanged();\n\n            ImGuiIO& io = ImGui::GetIO();\n            io.DisplaySize = ImVec2((float)g_app->m_displayWidth, (float)g_app->m_displayHeight);\n        }\n    }\n\n    void OnKeyboard(UINT message, WPARAM wParam, LPARAM lParam)\n    {\n        if (ImGui::GetCurrentContext() == nullptr)\n            return;\n\n        const bool is_key_down = (message == WM_KEYDOWN || message == WM_SYSKEYDOWN);\n        if (wParam < 256)\n        {\n            // Submit modifiers\n            ImGui_UpdateKeyModifiers();\n\n            // Obtain virtual key code and convert to ImGuiKey\n            const ImGuiKey key = ImGui_VirtualKeyToImGuiKey(wParam, lParam);\n            const int vk = (int)wParam;\n            const int scancode = (int)LOBYTE(HIWORD(lParam));\n\n            // Special behavior for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't \n            // emit the key down event.\n            if (key == ImGuiKey_PrintScreen && !is_key_down)\n                ImGui_AddKeyEvent(key, true, vk, scancode);\n\n            // Submit key event\n            if (key != ImGuiKey_None)\n                ImGui_AddKeyEvent(key, is_key_down, vk, scancode);\n\n            // Submit individual left/right modifier events\n            if (vk == VK_SHIFT)\n            {\n                // Important: Shift keys tend to get stuck when pressed together, missing key-up \n                // events are corrected in ImGui_ImplWin32_ProcessKeyEventsWorkarounds()\n                if (ImGui_IsVkDown(VK_LSHIFT) == is_key_down)\n                    ImGui_AddKeyEvent(ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode);\n                if (ImGui_IsVkDown(VK_RSHIFT) == is_key_down)\n                    ImGui_AddKeyEvent(ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode);\n            }\n            else if (vk == VK_CONTROL)\n            {\n                if (ImGui_IsVkDown(VK_LCONTROL) == is_key_down)\n                    ImGui_AddKeyEvent(ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode);\n                if (ImGui_IsVkDown(VK_RCONTROL) == is_key_down)\n                    ImGui_AddKeyEvent(ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode);\n            }\n            else if (vk == VK_MENU)\n            {\n                if (ImGui_IsVkDown(VK_LMENU) == is_key_down)\n                    ImGui_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode);\n                if (ImGui_IsVkDown(VK_RMENU) == is_key_down)\n                    ImGui_AddKeyEvent(ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode);\n            }\n        }\n\n        if (!ImGui::GetIO().WantCaptureKeyboard)\n        {\n            if (GetAsyncKeyState('P') & (1 << 16))\n            {\n                if (g_app->m_isActive)\n                {\n                    g_app->m_manuallyPaused = true;\n                    AppImpl::OnDeactivated();\n                }\n                else\n                {\n                    g_app->m_manuallyPaused = false;\n                    AppImpl::OnActivated();\n                }\n            }\n            else if (GetAsyncKeyState(VK_ESCAPE) & (1 << 16))\n                g_app->m_scene.ClearPick();\n        }\n    }\n\n    void OnMouseDown(UINT message, WPARAM btnState, LPARAM lParam)\n    {\n        if (ImGui::GetCurrentContext() == nullptr)\n            return;\n\n        ImGuiMouseSource mouse_source = ImGui_GetMouseSourceFromMessageExtraInfo();\n        int button = 0;\n        if (message == WM_LBUTTONDOWN || message == WM_LBUTTONDBLCLK)\n            button = 0;\n        if (message == WM_RBUTTONDOWN || message == WM_RBUTTONDBLCLK)\n            button = 1;\n        if (message == WM_MBUTTONDOWN || message == WM_MBUTTONDBLCLK)\n            button = 2;\n        if (g_app->m_imguiMouseButtonsDown == 0 && GetCapture() == nullptr)\n            SetCapture(g_app->m_hwnd);\n\n        g_app->m_imguiMouseButtonsDown |= 1 << button;\n        ImGuiIO& io = ImGui::GetIO();\n        io.AddMouseSourceEvent(mouse_source);\n        io.AddMouseButtonEvent(button, true);\n\n        if (!io.WantCaptureMouse)\n        {\n            int16 x = GET_X_LPARAM(lParam);\n            int16 y = GET_Y_LPARAM(lParam);\n            constexpr uint32_t buttons = MK_LBUTTON | MK_CONTROL;\n            constexpr uint32_t ignoreButtons = ~buttons;\n\n            if ((btnState & buttons) && !(btnState & ignoreButtons))\n            {\n                SetCapture(g_app->m_hwnd);\n                g_app->m_lastMousePosX = x;\n                g_app->m_lastMousePosY = y;\n                g_app->m_lastLMBClickPosX = x;\n                g_app->m_lastLMBClickPosY = y;\n                g_app->m_multiPick = btnState & MK_CONTROL;\n            }\n        }\n    }\n\n    void OnMouseUp(UINT message, WPARAM btnState, LPARAM lParam)\n    {\n        if (ImGui::GetCurrentContext() == nullptr)\n            return;\n\n        ImGuiIO& io = ImGui::GetIO();\n\n        ImGuiMouseSource mouse_source = ImGui_GetMouseSourceFromMessageExtraInfo();\n        int button = 0;\n        if (message == WM_LBUTTONUP)\n            button = 0;\n        if (message == WM_RBUTTONUP)\n            button = 1;\n        if (message == WM_MBUTTONUP)\n            button = 2;\n\n        g_app->m_imguiMouseButtonsDown &= ~(1 << button);\n        if (g_app->m_imguiMouseButtonsDown == 0 && GetCapture() == g_app->m_hwnd)\n            ReleaseCapture();\n\n        io.AddMouseSourceEvent(mouse_source);\n        io.AddMouseButtonEvent(button, false);\n\n        if (!io.WantCaptureMouse)\n        {\n            if (message == WM_LBUTTONUP)\n                ReleaseCapture();\n\n            if (g_app->m_lastLMBClickPosX == GET_X_LPARAM(lParam) &&\n                g_app->m_lastLMBClickPosY == GET_Y_LPARAM(lParam))\n            {\n                g_app->m_picked = true;\n            }\n        }\n    }\n\n    void OnMouseMove(UINT message, WPARAM btnState, LPARAM lParam, HWND hwnd)\n    {\n        if (ImGui::GetCurrentContext() == nullptr)\n            return;\n\n        // We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events\n        ImGuiMouseSource mouse_source = ImGui_GetMouseSourceFromMessageExtraInfo();\n        const int area = (message == WM_MOUSEMOVE) ? 1 : 2;\n        g_app->m_imguiMouseHwnd = hwnd;\n\n        if (g_app->m_imguiMouseTrackedArea != area)\n        {\n            TRACKMOUSEEVENT tme_cancel = { sizeof(tme_cancel), TME_CANCEL, hwnd, 0 };\n            TRACKMOUSEEVENT tme_track = { sizeof(tme_track), (DWORD)((area == 2) ?\n                (TME_LEAVE | TME_NONCLIENT) : TME_LEAVE), hwnd, 0 };\n            if (g_app->m_imguiMouseTrackedArea != 0)\n                TrackMouseEvent(&tme_cancel);\n\n            TrackMouseEvent(&tme_track);\n            g_app->m_imguiMouseTrackedArea = area;\n        }\n\n        POINT mouse_pos = { (LONG)GET_X_LPARAM(lParam), (LONG)GET_Y_LPARAM(lParam) };\n        // WM_NCMOUSEMOVE are provided in absolute coordinates.\n        if (message == WM_NCMOUSEMOVE && ScreenToClient(hwnd, &mouse_pos) == FALSE)\n            return;\n\n        ImGuiIO& io = ImGui::GetIO();\n        io.AddMouseSourceEvent(mouse_source);\n        io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y);\n\n        if (message != WM_MOUSEMOVE)\n            return;\n\n        if (!io.WantCaptureMouse)\n        {\n            if (btnState == MK_LBUTTON)\n            {\n                int16 x = GET_X_LPARAM(lParam);\n                int16 y = GET_Y_LPARAM(lParam);\n\n                g_app->m_frameMotion.dMouse_x = int16_t(x - g_app->m_lastMousePosX);\n                g_app->m_frameMotion.dMouse_y = int16_t(y - g_app->m_lastMousePosY);\n\n                g_app->m_lastMousePosX = x;\n                g_app->m_lastMousePosY = y;\n            }\n        }\n    }\n\n    void OnMouseWheel(UINT message, WPARAM btnState, LPARAM lParam)\n    {\n        if (ImGui::GetCurrentContext() == nullptr)\n            return;\n\n        ImGuiIO& io = ImGui::GetIO();\n        io.AddMouseWheelEvent(0.0f, (float)GET_WHEEL_DELTA_WPARAM(btnState) / (float)WHEEL_DELTA);\n\n        if (!io.WantCaptureMouse)\n        {\n            short zDelta = GET_WHEEL_DELTA_WPARAM(btnState);\n\n            if (zDelta > 0)\n                g_app->m_inMouseWheelMove = 1;\n            else\n                g_app->m_inMouseWheelMove = -1;\n        }\n    }\n\n    void OnDestroy()\n    {\n        App::FlushAllThreadPools();\n        g_app->m_renderer.FlushAllCommandQueues();\n\n        g_app->m_imguiFontTex.Reset(false);\n\n        // Shuts down render passes and releases scene GPU resources\n        g_app->m_scene.Shutdown();\n\n        ImGui::DestroyContext();\n        ImPlot::DestroyContext();\n        ImNodes::DestroyContext();\n\n        // Shuts down GPU memory\n        g_app->m_renderer.Shutdown();\n\n        g_app->m_workerThreadPool.Shutdown();\n        g_app->m_backgroundThreadPool.Shutdown();\n\n        delete g_app;\n        g_app = nullptr;\n    }\n\n    void ApplyParamUpdates()\n    {\n        AcquireSRWLockExclusive(&g_app->m_paramUpdateLock);\n        AcquireSRWLockExclusive(&g_app->m_paramLock);\n\n        for (auto& p : g_app->m_paramsUpdates)\n        {\n            if (p.Op == ParamUpdate::OP_TYPE::ADD)\n                g_app->m_params.push_back(p.P);\n            else if (p.Op == ParamUpdate::OP_TYPE::REMOVE)\n            {\n                size_t i = 0;\n                bool found = false;\n                while (i < g_app->m_params.size())\n                {\n                    if (g_app->m_params[i].ID() == p.P.ID())\n                    {\n                        found = true;\n                        break;\n                    }\n\n                    i++;\n                }\n\n                if (found)\n                    g_app->m_params.erase_at_index(i);\n            }\n        }\n\n        g_app->m_paramsUpdates.clear();\n\n        ReleaseSRWLockExclusive(&g_app->m_paramLock);\n        ReleaseSRWLockExclusive(&g_app->m_paramUpdateLock);\n    }\n\n    // Ref: https://github.com/ysc3839/win32-darkmode\n    bool TryInitDarkMode(HMODULE* uxthemeLib, HWND hWnd)\n    {\n        bool darkModeEnabled = false;\n\n        *uxthemeLib = LoadLibraryExA(\"uxtheme.dll\", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);\n        if (*uxthemeLib)\n        {\n#if defined(__clang__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wcast-function-type-mismatch\"\n#endif\n            fnRefreshImmersiveColorPolicyState refreshImmersiveColorPolicyState =\n                reinterpret_cast<fnRefreshImmersiveColorPolicyState>(\n                    GetProcAddress(*uxthemeLib, MAKEINTRESOURCEA(104)));\n            fnShouldAppsUseDarkMode shouldAppsUseDarkMode = reinterpret_cast<fnShouldAppsUseDarkMode>(\n                GetProcAddress(*uxthemeLib, MAKEINTRESOURCEA(132)));\n            fnSetPreferredAppMode setPreferredAppMode = reinterpret_cast<fnSetPreferredAppMode>(\n                GetProcAddress(*uxthemeLib, MAKEINTRESOURCEA(135)));\n            fnAllowDarkModeForWindow allowDarkModeForWindow = reinterpret_cast<fnAllowDarkModeForWindow>(\n                GetProcAddress(*uxthemeLib, MAKEINTRESOURCEA(133)));\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n\n            if (refreshImmersiveColorPolicyState &&\n                shouldAppsUseDarkMode &&\n                setPreferredAppMode)\n            {\n                setPreferredAppMode(PreferredAppMode::AllowDark);\n\n                refreshImmersiveColorPolicyState();\n\n                bool isHighContrast = false;\n                HIGHCONTRASTW highContrast;\n                highContrast.cbSize = sizeof(highContrast);\n                highContrast.dwFlags = 0;\n                highContrast.lpszDefaultScheme = nullptr;\n                if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(highContrast), &highContrast, FALSE))\n                    isHighContrast = highContrast.dwFlags & HCF_HIGHCONTRASTON;\n\n                darkModeEnabled = shouldAppsUseDarkMode() && !isHighContrast;\n                if (darkModeEnabled)\n                    allowDarkModeForWindow(hWnd, true);\n            }\n        }\n\n        return darkModeEnabled;\n    }\n\n    LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\n    {\n        switch (message)\n        {\n        case WM_CREATE:\n        {\n            HMODULE uxthemeLib = nullptr;\n            BOOL dark = TryInitDarkMode(&uxthemeLib, hWnd);\n\n#if defined(__clang__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wcast-function-type-mismatch\"\n#endif\n            fnSetWindowCompositionAttribute setWindowCompositionAttribute =\n                reinterpret_cast<fnSetWindowCompositionAttribute>(\n                    GetProcAddress(GetModuleHandleA(\"user32.dll\"), \"SetWindowCompositionAttribute\"));\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n            if (setWindowCompositionAttribute)\n            {\n                WINDOWCOMPOSITIONATTRIBDATA data = { WCA_USEDARKMODECOLORS, &dark, sizeof(dark) };\n                setWindowCompositionAttribute(hWnd, &data);\n            }\n\n            FreeLibrary(uxthemeLib);\n        }\n        return 0;\n\n        case WM_ACTIVATEAPP:\n            if (wParam && !g_app->m_manuallyPaused)\n                AppImpl::OnActivated();\n            else\n                AppImpl::OnDeactivated();\n\n            return 0;\n\n        case WM_ENTERSIZEMOVE:\n            g_app->m_inSizeMove = true;\n            AppImpl::OnDeactivated();\n            return 0;\n\n        case WM_EXITSIZEMOVE:\n            g_app->m_inSizeMove = false;\n            AppImpl::OnWindowSizeChanged();\n\n            if (!g_app->m_manuallyPaused)\n                AppImpl::OnActivated();\n\n            return 0;\n\n        case WM_SIZE:\n            if (!g_app->m_inSizeMove)\n            {\n                if (wParam == SIZE_MINIMIZED)\n                {\n                    g_app->m_minimized = true;\n                    AppImpl::OnDeactivated();\n                }\n                else if (wParam == SIZE_RESTORED)\n                {\n                    if (g_app->m_minimized && !g_app->m_manuallyPaused)\n                        AppImpl::OnActivated();\n\n                    AppImpl::OnWindowSizeChanged();\n                }\n                else if (wParam == SIZE_MAXIMIZED)\n                    AppImpl::OnWindowSizeChanged();\n            }\n            return 0;\n\n        case WM_KEYDOWN:\n        case WM_KEYUP:\n        case WM_SYSKEYDOWN:\n        case WM_SYSKEYUP:\n            AppImpl::OnKeyboard(message, wParam, lParam);\n            return 0;\n\n        case WM_CHAR:\n        {\n            wchar_t wch = 0;\n            MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (char*)&wParam, 1, &wch, 1);\n            ImGui::GetIO().AddInputCharacter(wch);\n        }\n        return 0;\n\n        case WM_MOUSEMOVE:\n        case WM_NCMOUSEMOVE:\n            AppImpl::OnMouseMove(message, wParam, lParam, hWnd);\n            return 0;\n\n        case WM_MOUSELEAVE:\n        case WM_NCMOUSELEAVE:\n        {\n            const int area = (message == WM_MOUSELEAVE) ? 1 : 2;\n            if (g_app->m_imguiMouseTrackedArea == area)\n            {\n                if (g_app->m_imguiMouseHwnd == hWnd)\n                    g_app->m_imguiMouseHwnd = nullptr;\n\n                g_app->m_imguiMouseTrackedArea = 0;\n                ImGui::GetIO().AddMousePosEvent(-FLT_MAX, -FLT_MAX);\n            }\n            return 0;\n        }\n\n        case WM_LBUTTONDOWN:\n        case WM_MBUTTONDOWN:\n        case WM_RBUTTONDOWN:\n            AppImpl::OnMouseDown(message, wParam, lParam);\n            return 0;\n\n        case WM_LBUTTONUP:\n        case WM_MBUTTONUP:\n        case WM_RBUTTONUP:\n            AppImpl::OnMouseUp(message, wParam, lParam);\n            return 0;\n\n        case WM_MOUSEWHEEL:\n            AppImpl::OnMouseWheel(message, wParam, lParam);\n            return 0;\n\n        case WM_DPICHANGED:\n            OnDPIChanged(HIWORD(wParam), reinterpret_cast<RECT*>(lParam));\n            return 0;\n\n        case WM_SETCURSOR:\n            // This is required to restore cursor when transitioning from e.g resize borders to client area.\n            if (LOWORD(lParam) == HTCLIENT && ImGui_UpdateMouseCursor())\n                return 1;\n            return DefWindowProc(hWnd, message, wParam, lParam);\n\n        case WM_SETFOCUS:\n        case WM_KILLFOCUS:\n            if (ImGui::GetCurrentContext() == nullptr)\n                return DefWindowProc(hWnd, message, wParam, lParam);;\n\n            ImGui::GetIO().AddFocusEvent(message == WM_SETFOCUS);\n            return 0;\n\n        case WM_DESTROY:\n            AppImpl::OnDestroy();\n            PostQuitMessage(0);\n            return 0;\n        }\n\n        return DefWindowProc(hWnd, message, wParam, lParam);\n    }\n\n    void CreateAppWindow(HINSTANCE instance)\n    {\n        const char* wndClassName = \"MyWindowClass\";\n        WNDCLASSA wc{};\n\n        wc.style = CS_HREDRAW | CS_VREDRAW;\n        wc.lpfnWndProc = WndProc;\n        wc.cbClsExtra = 0;\n        wc.cbWndExtra = 0;\n        wc.hInstance = instance;\n        wc.hCursor = LoadCursor(nullptr, IDC_ARROW);\n        wc.lpszClassName = wndClassName;\n\n        RegisterClassA(&wc);\n\n        g_app->m_hwnd = CreateWindowA(wndClassName,\n            \"ZetaRay\",\n            WS_OVERLAPPEDWINDOW,\n            CW_USEDEFAULT, CW_USEDEFAULT,\n            CW_USEDEFAULT, CW_USEDEFAULT,\n            nullptr, nullptr,\n            instance,\n            nullptr);\n\n        CheckWin32(g_app->m_hwnd);\n\n        RECT workingArea;\n        CheckWin32(SystemParametersInfoA(SPI_GETWORKAREA, 0, &workingArea, 0));\n\n        CheckWin32(SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2));\n        g_app->m_dpi = (uint16_t)GetDpiForWindow(g_app->m_hwnd);\n\n        const int monitorWidth = workingArea.right - workingArea.left;\n        const int monitorHeight = workingArea.bottom - workingArea.top;\n\n        const int wndWidth = (int)((monitorWidth * g_app->m_dpi) / USER_DEFAULT_SCREEN_DPI);\n        const int wndHeight = (int)((monitorHeight * g_app->m_dpi) / USER_DEFAULT_SCREEN_DPI);\n\n        SetWindowPos(g_app->m_hwnd, nullptr, 0, 0, wndWidth, wndHeight, 0);\n        ShowWindow(g_app->m_hwnd, SW_SHOWNORMAL);\n    }\n\n    void SetCameraAcceleration(const ParamVariant& p)\n    {\n        g_app->m_cameraAcceleration = p.GetFloat().m_value;\n    }\n\n    void ResizeIfQueued()\n    {\n        if (g_app->m_issueResize)\n        {\n            g_app->m_upscaleFactor = g_app->m_queuedUpscaleFactor;\n\n            const float renderWidth = g_app->m_displayWidth / g_app->m_upscaleFactor;\n            const float renderHeight = g_app->m_displayHeight / g_app->m_upscaleFactor;\n\n            g_app->m_renderer.OnWindowSizeChanged(g_app->m_hwnd, (uint16_t)renderWidth, (uint16_t)renderHeight,\n                g_app->m_displayWidth, g_app->m_displayHeight);\n            g_app->m_scene.OnWindowSizeChanged();\n            g_app->m_camera.OnWindowSizeChanged();\n\n            g_app->m_issueResize = false;\n        }\n    }\n\n    void ChangeDPIIfQueued()\n    {\n        if (g_app->m_dpiChanged)\n        {\n            SetWindowPos(g_app->m_hwnd, nullptr,\n                g_app->m_dpiChangeNewRect.left,\n                g_app->m_dpiChangeNewRect.top,\n                g_app->m_dpiChangeNewRect.right - g_app->m_dpiChangeNewRect.left,\n                g_app->m_dpiChangeNewRect.bottom - g_app->m_dpiChangeNewRect.top,\n                SWP_NOZORDER | SWP_NOACTIVATE);\n\n            // Fonts need to be rebuilt\n            LoadFont();\n\n            ImGuiStyle& style = ImGui::GetStyle();\n            style.ScaleAllSizes((float)g_app->m_dpi / USER_DEFAULT_SCREEN_DPI);\n\n            g_app->m_dpiChanged = false;\n        }\n    }\n\n    template<size_t blockSize>\n    ZetaInline void* AllocateFrameAllocator(FrameMemory<blockSize>& frameMemory, FrameMemoryContext& context,\n        size_t size, size_t alignment)\n    {\n        alignment = Math::Max(alignof(std::max_align_t), alignment);\n\n        // at most alignment - 1 extra bytes are required\n        Assert(size + alignment - 1 <= frameMemory.BLOCK_SIZE,\n            \"allocations larger than FrameMemory::BLOCK_SIZE are not possible with FrameAllocator.\");\n\n        // current memory block has enough space\n        int allocIdx = context.m_threadFrameAllocIndices[g_threadIdx];\n\n        // first time in this frame\n        if (allocIdx != -1)\n        {\n            auto& block = frameMemory.GetAndInitIfEmpty(allocIdx);\n\n            const uintptr_t start = reinterpret_cast<uintptr_t>(block.Start);\n            const uintptr_t ret = Math::AlignUp(start + block.Offset, alignment);\n            const uintptr_t startOffset = ret - start;\n\n            if (startOffset + size < frameMemory.BLOCK_SIZE)\n            {\n                block.Offset = startOffset + size;\n                return reinterpret_cast<void*>(ret);\n            }\n        }\n\n        // allocate/reuse a new block\n        allocIdx = context.m_currFrameAllocIndex.fetch_add(1, std::memory_order_relaxed);\n        context.m_threadFrameAllocIndices[g_threadIdx] = allocIdx;\n        auto& block = frameMemory.GetAndInitIfEmpty(allocIdx);\n        Assert(block.Offset == 0, \"block offset should be initially 0\");\n\n        const uintptr_t start = reinterpret_cast<uintptr_t>(block.Start);\n        const uintptr_t ret = Math::AlignUp(start, alignment);\n        const uintptr_t startOffset = ret - start;\n\n        Assert(startOffset + size < frameMemory.BLOCK_SIZE, \"should never happen.\");\n        block.Offset = startOffset + size;\n\n        return reinterpret_cast<void*>(ret);\n    }\n}\n\nnamespace ZetaRay\n{\n    CpuInfo App::GetProcessorInfo()\n    {\n        DWORD buffSize = 0;\n        GetLogicalProcessorInformation(nullptr, &buffSize);\n        Assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER, \"GetLogicalProcessorInformation() failed.\");\n\n        SmallVector<unsigned char, SystemAllocator, 1024> buffer;\n        buffer.resize(buffSize);\n        SYSTEM_LOGICAL_PROCESSOR_INFORMATION* dataPtr =\n            reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION*>(buffer.data());\n\n        bool rc = GetLogicalProcessorInformation(dataPtr, &buffSize);\n        Assert(rc, \"GetLogicalProcessorInformation() failed.\");\n\n        const int n = buffSize / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);\n        SYSTEM_LOGICAL_PROCESSOR_INFORMATION* curr = dataPtr;\n        //int logicalProcessorCount = 0;\n\n        CpuInfo ret{};\n\n        for (int i = 0; i < n; i++)\n        {\n            switch (curr->Relationship)\n            {\n            case RelationProcessorCore:\n                ret.NumPhysicalCores++;\n\n                // A hyperthreaded core supplies more than one logical processor.\n                ret.NumLogicalCores += (int)__popcnt64(curr->ProcessorMask);\n                break;\n\n            default:\n                break;\n            }\n\n            curr++;\n        }\n\n        return ret;\n    }\n\n    void App::SetThreadPriority(void* handle, THREAD_PRIORITY priority)\n    {\n        switch (priority)\n        {\n        case THREAD_PRIORITY::NORMAL:\n            CheckWin32(::SetThreadPriority(handle, THREAD_PRIORITY_NORMAL));\n            break;\n        case THREAD_PRIORITY::BACKGROUND:\n            CheckWin32(::SetThreadPriority(handle, THREAD_PRIORITY_BELOW_NORMAL));\n            break;\n        default:\n            break;\n        }\n    }\n\n    void App::SetThreadDesc(void* handle, wchar_t* buffer)\n    {\n        Assert(handle && buffer, \"Invalid args.\");\n\n        auto hr = SetThreadDescription(handle, buffer);\n        CheckWin32(SUCCEEDED(hr));\n    }\n\n    ShaderReloadHandler::ShaderReloadHandler(const char* name, fastdelegate::FastDelegate0<> dlg)\n        : Dlg(dlg)\n    {\n        int n = std::min(MAX_LEN - 1, (int)strlen(name));\n        Assert(n >= 1, \"Invalid arg\");\n        memcpy(Name, name, n);\n        Name[n] = '\\0';\n\n        ID = XXH3_64bits(Name, n);\n    }\n\n    LogMessage::LogMessage(const char* msg, LogMessage::MsgType t)\n    {\n        const char* logType = t == MsgType::INFO ? \"INFO\" : \"WARNING\";\n        Type = t;\n\n        // Compute total size first (without the null terminator)\n        const int n = stbsp_snprintf(nullptr, 0, \"[Frame %04d] [tid %05d] [%s] | %s\",\n            g_app->m_timer.GetTotalFrameCount(), GetCurrentThreadId(), logType, msg);\n\n        Msg = reinterpret_cast<char*>(g_app->m_logStrArena.AllocateAligned(n + 1, alignof(char)));\n        stbsp_snprintf(Msg, n + 1, \"[Frame %04d] [tid %05d] [%s] | %s\",\n            g_app->m_timer.GetTotalFrameCount(), GetCurrentThreadId(), logType, msg);\n    }\n\n    void App::Init(Scene::Renderer::Interface& rendererInterface, const char* name)\n    {\n        // check intrinsics support\n        const auto supported = Common::CheckIntrinsicSupport();\n        Check(supported & CPU_Intrinsic::AVX2, \"AVX2 is not supported.\");\n        Check(supported & CPU_Intrinsic::F16C, \"F16C is not supported.\");\n        Check(supported & CPU_Intrinsic::BMI1, \"BMI1 is not supported.\");\n\n        // set locale to C\n        setlocale(LC_ALL, \"C\");\n\n        // create PSO cache directories\n        Filesystem::CreateDirectoryIfNotExists(AppData::PSO_CACHE_DIR);\n\n        HINSTANCE instance = GetModuleHandleA(nullptr);\n        CheckWin32(instance);\n\n        g_app = new (std::nothrow) AppData;\n\n        CpuInfo cpuInfo = App::GetProcessorInfo();\n        g_app->m_processorCoreCount = (uint16)Min(cpuInfo.NumPhysicalCores,\n            (MAX_NUM_THREADS - AppData::NUM_BACKGROUND_THREADS));\n\n        // create the window\n        AppImpl::CreateAppWindow(instance);\n        SetWindowTextA(g_app->m_hwnd, name ? name : \"ZetaRay\");\n\n        // Initialize thread pools - totalNumThreads is passed to account for all the \n        // other threads that may insert tasks such as the main thread\n        const int totalNumThreads = g_app->m_processorCoreCount + AppData::NUM_BACKGROUND_THREADS;\n\n        // main thread\n        g_threadIdx = 0;\n\n        // Offset by 1 to account for main thread\n        g_app->m_workerThreadPool.Init(g_app->m_processorCoreCount - 1,\n            totalNumThreads,\n            L\"ZetaWorker\",\n            THREAD_PRIORITY::NORMAL,\n            1);\n\n        // Offset by m_processorCoreCount to account for main thread and worker threads\n        g_app->m_backgroundThreadPool.Init(AppData::NUM_BACKGROUND_THREADS,\n            totalNumThreads,\n            L\"ZetaBackgroundWorker\",\n            THREAD_PRIORITY::BACKGROUND,\n            g_app->m_processorCoreCount);\n\n        // Initialize frame allocators\n        memset(g_app->m_frameMemoryContext.m_threadFrameAllocIndices, -1,\n            sizeof(int) * MAX_NUM_THREADS);\n        g_app->m_frameMemoryContext.m_currFrameAllocIndex.store(0, std::memory_order_release);\n\n        g_app->m_workerThreadPool.Start();\n        g_app->m_backgroundThreadPool.Start();\n\n        RECT rect;\n        GetClientRect(g_app->m_hwnd, &rect);\n\n        g_app->m_displayWidth = (uint16_t)(rect.right - rect.left);\n        g_app->m_displayHeight = (uint16_t)(rect.bottom - rect.top);\n\n        // initialize renderer\n        const float renderWidth = g_app->m_displayWidth / g_app->m_upscaleFactor;\n        const float renderHeight = g_app->m_displayHeight / g_app->m_upscaleFactor;\n        g_app->m_renderer.Init(g_app->m_hwnd, (uint16_t)renderWidth, (uint16_t)renderHeight,\n            g_app->m_displayWidth, g_app->m_displayHeight);\n\n        // ImGui\n        AppImpl::InitImGui();\n\n        // initialize camera\n        g_app->m_frameMotion.Reset();\n\n        g_app->m_camera.Init(float3(0, 1.2f, -4.043f), App::GetRenderer().GetAspectRatio(),\n            Math::DegreesToRadians(60.0f), 0.2f, true, float3(0, 0, 1), false);\n\n        // scene can now be initialized\n        g_app->m_scene.Init(rendererInterface);\n\n        ParamVariant acc;\n        acc.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Camera\", \"Acc.\",\n            fastdelegate::FastDelegate1<const ParamVariant&>(&AppImpl::SetCameraAcceleration),\n            g_app->m_cameraAcceleration, 1.0f, 100.0f, 1.0f, \"Motion\");\n        App::AddParam(acc);\n\n        g_app->m_isInitialized = true;\n\n        LOG_UI(INFO, \"Detected %d physical CPU cores\", g_app->m_processorCoreCount);\n        LOG_UI(INFO, \"Work area on the primary display monitor is %dx%d\",\n            g_app->m_displayWidth, g_app->m_displayHeight);\n    }\n\n    void App::InitBasic()\n    {\n        setlocale(LC_ALL, \"C\");\n\n        g_app = new (std::nothrow) AppData;\n\n        CpuInfo cpuInfo = App::GetProcessorInfo();\n        g_app->m_processorCoreCount = (uint16)Min(cpuInfo.NumPhysicalCores, MAX_NUM_THREADS);\n\n        // Initialize thread pool\n        const int totalNumThreads = g_app->m_processorCoreCount;\n        g_app->m_workerThreadPool.Init(g_app->m_processorCoreCount - 1,\n            totalNumThreads,\n            L\"ZetaWorker\",\n            THREAD_PRIORITY::NORMAL,\n            1);\n\n        // main thread\n        g_threadIdx = 0;\n\n        g_app->m_workerThreadPool.Start();\n\n        // renderer (for d3dDevice)\n        g_app->m_renderer.InitBasic();\n    }\n\n    void App::ShutdownBasic()\n    {\n        g_app->m_renderer.ShutdownBasic();\n        g_app->m_workerThreadPool.Shutdown();\n\n        delete g_app;\n        g_app = nullptr;\n    }\n\n    int App::Run()\n    {\n        MSG msg = {};\n        bool success = false;\n        g_app->m_timer.Start();\n\n        while (true)\n        {\n            if (g_app->m_isActive && success)\n                g_app->m_renderer.WaitForSwapChainWaitableObject();\n\n            // process messages\n            while (PeekMessageA(&msg, nullptr, 0, 0, PM_REMOVE))\n            {\n                if (msg.message == WM_QUIT)\n                    return (int)msg.wParam;\n\n                TranslateMessage(&msg);\n                DispatchMessageA(&msg);\n            }\n\n            if (!g_app->m_isActive)\n            {\n                Sleep(16);\n                continue;\n            }\n\n            // help out while there are (non-background) unfinished tasks from previous frame\n            success = g_app->m_workerThreadPool.TryFlush();\n\n            // don't block the message-handling thread\n            if (!success)\n                continue;\n\n            // at this point, all worker tasks from previous frame are done (GPU may still \n            // be executing those though)\n            g_app->m_currTaskSignalIdx.store(0, std::memory_order_relaxed);\n            const size_t tempMemoryUsed = g_app->m_frameMemory.TotalSize();\n\n            // Skip first frame\n            if (g_app->m_timer.GetTotalFrameCount() > 0)\n            {\n                g_app->m_frameMemoryContext.m_currFrameAllocIndex.store(0, std::memory_order_release);\n                for (int i = 0; i < MAX_NUM_THREADS; i++)\n                    g_app->m_frameMemoryContext.m_threadFrameAllocIndices[i] = -1;\n                g_app->m_frameMemory.Reset();        // set the offset to 0, essentially releasing the memory\n            }\n\n            g_app->m_renderer.BeginFrame();\n            // Startup is counted as \"frame\" 0, so program loop starts from frame 1\n            g_app->m_timer.Tick();\n            AppImpl::ResizeIfQueued();\n            AppImpl::ChangeDPIIfQueued();\n\n            // update\n            {\n                TaskSet sceneTS;\n                TaskSet sceneRendererTS;\n                AppImpl::Update(sceneTS, sceneRendererTS, tempMemoryUsed);\n\n                if (!g_app->m_paramsUpdates.empty())\n                {\n                    sceneTS.EmplaceTask(\"ParamUpdates\", []()\n                        {\n                            AppImpl::ApplyParamUpdates();\n                        });\n                }\n\n                auto h0 = sceneRendererTS.EmplaceTask(\"ResourceUploadSubmission\", []()\n                    {\n                        g_app->m_renderer.SubmitResourceCopies();\n                    });\n\n                // make sure resource submission runs after everything else\n                sceneRendererTS.AddIncomingEdgeFromAll(h0);\n\n                sceneTS.Sort();\n                sceneRendererTS.Sort();\n\n                // sceneRendererTS has to run after sceneTS. This may seem sequential but\n                // each taskset is spawning more tasks (which can potentially run in parallel).\n                sceneTS.ConnectTo(sceneRendererTS);\n\n                sceneTS.Finalize();\n                sceneRendererTS.Finalize();\n\n                Submit(ZetaMove(sceneTS));\n                Submit(ZetaMove(sceneRendererTS));\n            }\n\n            // help out as long as updates are not finished before moving to rendering\n            success = false;\n            while (!success)\n                success = g_app->m_workerThreadPool.TryFlush();\n\n            g_app->m_frameMotion.Reset();\n\n            // render\n            {\n                TaskSet renderTS;\n                TaskSet endFrameTS;\n\n                g_app->m_scene.Render(renderTS);\n                renderTS.Sort();\n\n                g_app->m_renderer.EndFrame(endFrameTS);\n                endFrameTS.Sort();\n\n                renderTS.ConnectTo(endFrameTS);\n\n                renderTS.Finalize();\n                endFrameTS.Finalize();\n\n                Submit(ZetaMove(renderTS));\n                Submit(ZetaMove(endFrameTS));\n            }\n\n            g_app->m_workerThreadPool.PumpUntilEmpty();\n        }\n\n        return (int)msg.wParam;\n    }\n\n    void App::Abort()\n    {\n        AppImpl::OnDestroy();\n        PostQuitMessage(0);\n    }\n\n    void* App::AllocateFrameAllocator(size_t size, size_t alignment)\n    {\n        return AppImpl::AllocateFrameAllocator<>(g_app->m_frameMemory,\n            g_app->m_frameMemoryContext, size, alignment);\n    }\n\n    int App::RegisterTask()\n    {\n        int idx = g_app->m_currTaskSignalIdx.fetch_add(1, std::memory_order_relaxed);\n        Assert(idx < AppData::MAX_NUM_TASKS_PER_FRAME,\n            \"Number of task signals exceeded MAX_NUM_TASKS_PER_FRAME.\");\n\n        return idx;\n    }\n\n    void App::TaskFinalizedCallback(int handle, int indegree)\n    {\n        Assert(indegree > 0, \"Redundant call.\");\n        const int c = g_app->m_currTaskSignalIdx.load(std::memory_order_relaxed);\n        Assert(handle < c, \"Received handle %d while #handles for current frame is %d.\", c);\n\n        g_app->m_registeredTasks[handle].Indegree.store(indegree, std::memory_order_release);\n        g_app->m_registeredTasks[handle].BlockFlag.store(true, std::memory_order_release);\n    }\n\n    void App::WaitForAdjacentHeadNodes(int handle)\n    {\n        const int c = g_app->m_currTaskSignalIdx.load(std::memory_order_relaxed);\n        Assert(handle >= 0 && handle < c, \"Received handle %d while #handles for current frame is %d.\", c);\n\n        auto& taskSignal = g_app->m_registeredTasks[handle];\n        const int indegree = taskSignal.Indegree.load(std::memory_order_acquire);\n        Assert(indegree >= 0, \"Invalid task indegree.\");\n\n        if (indegree != 0)\n        {\n            taskSignal.BlockFlag.wait(true, std::memory_order_acquire);\n            return;\n        }\n    }\n\n    void App::SignalAdjacentTailNodes(Span<int> taskIDs)\n    {\n        for (auto handle : taskIDs)\n        {\n            auto& taskSignal = g_app->m_registeredTasks[handle];\n            const int remaining = taskSignal.Indegree.fetch_sub(1, std::memory_order_acquire);\n\n            // this was the last dependency, unblock the task\n            if (remaining == 1)\n            {\n                taskSignal.BlockFlag.store(false, std::memory_order_release);\n                taskSignal.BlockFlag.notify_one();\n            }\n        }\n    }\n\n    void App::Submit(Task&& t)\n    {\n        Assert(t.GetPriority() == TASK_PRIORITY::NORMAL,\n            \"Background task is not allowed to be executed on the main thread pool.\");\n        g_app->m_workerThreadPool.Enqueue(ZetaMove(t));\n    }\n\n    void App::Submit(TaskSet&& ts)\n    {\n        g_app->m_workerThreadPool.Enqueue(ZetaMove(ts));\n    }\n\n    void App::SubmitBackground(Task&& t)\n    {\n        Assert(t.GetPriority() == TASK_PRIORITY::BACKGROUND,\n            \"Normal-priority task is not allowed to be executed on the background thread pool.\");\n        g_app->m_backgroundThreadPool.Enqueue(ZetaMove(t));\n    }\n\n    void App::FlushWorkerThreadPool()\n    {\n        bool success = false;\n        while (!success)\n            success = g_app->m_workerThreadPool.TryFlush();\n    }\n\n    void App::FlushAllThreadPools()\n    {\n        bool success = false;\n        while (!success)\n            success = g_app->m_workerThreadPool.TryFlush();\n\n        success = false;\n        while (!success)\n            success = g_app->m_backgroundThreadPool.TryFlush();\n    }\n\n    RendererCore& App::GetRenderer() { return g_app->m_renderer; }\n    SceneCore& App::GetScene() { return g_app->m_scene; }\n    const Camera& App::GetCamera() { return g_app->m_camera; }\n    int App::GetNumWorkerThreads() { return g_app->m_processorCoreCount; }\n    int App::GetNumBackgroundThreads() { return AppData::NUM_BACKGROUND_THREADS; }\n    uint32_t App::GetDPI() { return g_app->m_dpi; }\n    float App::GetDPIScaling() { return (float)g_app->m_dpi / USER_DEFAULT_SCREEN_DPI; }\n    float App::GetUpscalingFactor() { return g_app->m_upscaleFactor; }\n    bool App::IsFullScreen() { return g_app->m_isFullScreen; }\n    const App::Timer& App::GetTimer() { return g_app->m_timer; }\n    const char* App::GetPSOCacheDir() { return AppData::PSO_CACHE_DIR; }\n    const char* App::GetCompileShadersDir() { return AppData::COMPILED_SHADER_DIR; }\n    const char* App::GetAssetDir() { return AppData::ASSET_DIR; }\n    const char* App::GetDXCPath() { return AppData::DXC_PATH; }\n    const char* App::GetToolsDir() { return AppData::TOOLS_DIR; }\n    const char* App::GetRenderPassDir() { return AppData::RENDER_PASS_DIR; }\n\n    void App::SetUpscaleFactor(float f)\n    {\n        Assert(f >= 1.0f, \"Invalid upscale factor.\");\n        const float oldScaleFactor = g_app->m_upscaleFactor;\n\n        if (f != oldScaleFactor)\n        {\n            g_app->m_issueResize = true;\n            g_app->m_queuedUpscaleFactor = f;\n        }\n    }\n\n    void App::LockStdOut()\n    {\n        if (g_app)\n            AcquireSRWLockExclusive(&g_app->m_stdOutLock);\n    }\n\n    void App::UnlockStdOut()\n    {\n        if (g_app)\n            ReleaseSRWLockExclusive(&g_app->m_stdOutLock);\n    }\n\n    SynchronizedMutableSpan<ParamVariant> App::GetParams()\n    {\n        return SynchronizedMutableSpan<ParamVariant>(g_app->m_params, g_app->m_paramLock);\n    }\n\n    SynchronizedMutableSpan<ShaderReloadHandler> App::GetShaderReloadHandlers()\n    {\n        return SynchronizedMutableSpan<ShaderReloadHandler>(g_app->m_shaderReloadHandlers, g_app->m_shaderReloadLock);\n    }\n\n    SynchronizedSpan<Stat> App::GetStats()\n    {\n        return SynchronizedSpan<Stat>(g_app->m_frameStats, g_app->m_statsLock);\n    }\n\n    void App::AddParam(ParamVariant& p)\n    {\n        AcquireSRWLockExclusive(&g_app->m_paramUpdateLock);\n\n        g_app->m_paramsUpdates.push_back(ParamUpdate{\n            .P = p,\n            .Op = ParamUpdate::ADD });\n\n        ReleaseSRWLockExclusive(&g_app->m_paramUpdateLock);\n    }\n\n    void App::TryAddParam(ParamVariant& p)\n    {\n        AcquireSRWLockExclusive(&g_app->m_paramUpdateLock);\n\n        // TODO Linear search can be slow if there are a lot of parameters\n        bool found = false;\n        for (auto& param : g_app->m_params)\n        {\n            if (param.ID() == p.ID())\n            {\n                found = true;\n                break;\n            }\n        }\n\n        if (!found)\n        {\n            g_app->m_paramsUpdates.push_back(ParamUpdate{\n                .P = p,\n                .Op = ParamUpdate::ADD });\n        }\n\n        ReleaseSRWLockExclusive(&g_app->m_paramUpdateLock);\n    }\n\n    void App::RemoveParam(const char* group, const char* subgroup, const char* name)\n    {\n        AcquireSRWLockExclusive(&g_app->m_paramUpdateLock);\n\n        // create a dummy ParamVariant (never exposed to outside)\n        ParamVariant dummy;\n        dummy.InitBool(group, subgroup, name, fastdelegate::FastDelegate1<const ParamVariant&>(), false);\n\n        g_app->m_paramsUpdates.push_back(ParamUpdate{\n            .P = dummy,\n            .Op = ParamUpdate::REMOVE });\n\n        ReleaseSRWLockExclusive(&g_app->m_paramUpdateLock);\n    }\n\n    void App::AddShaderReloadHandler(const char* name, fastdelegate::FastDelegate0<> dlg)\n    {\n        AcquireSRWLockExclusive(&g_app->m_shaderReloadLock);\n        g_app->m_shaderReloadHandlers.emplace_back(name, dlg);\n        ReleaseSRWLockExclusive(&g_app->m_shaderReloadLock);\n    }\n\n    void App::RemoveShaderReloadHandler(const char* name)\n    {\n        uint64_t id = XXH3_64bits(name, Math::Min(ShaderReloadHandler::MAX_LEN - 1, (int)strlen(name)));\n\n        AcquireSRWLockExclusive(&g_app->m_shaderReloadLock);\n        int i = 0;\n        bool found = false;\n\n        for (i = 0; i < (int)g_app->m_shaderReloadHandlers.size(); i++)\n        {\n            if (g_app->m_shaderReloadHandlers[i].ID == id)\n            {\n                found = true;\n                break;\n            }\n        }\n\n        if (found)\n            g_app->m_shaderReloadHandlers.erase_at_index(i);\n\n        ReleaseSRWLockExclusive(&g_app->m_shaderReloadLock);\n    }\n\n    void App::AddFrameStat(const char* group, const char* name, int i)\n    {\n        AcquireSRWLockExclusive(&g_app->m_statsLock);\n        g_app->m_frameStats.emplace_back(group, name, i);\n        ReleaseSRWLockExclusive(&g_app->m_statsLock);\n    }\n\n    void App::AddFrameStat(const char* group, const char* name, uint32_t u)\n    {\n        AcquireSRWLockExclusive(&g_app->m_statsLock);\n        g_app->m_frameStats.emplace_back(group, name, u);\n        ReleaseSRWLockExclusive(&g_app->m_statsLock);\n    }\n\n    void App::AddFrameStat(const char* group, const char* name, float f)\n    {\n        AcquireSRWLockExclusive(&g_app->m_statsLock);\n        g_app->m_frameStats.emplace_back(group, name, f);\n        ReleaseSRWLockExclusive(&g_app->m_statsLock);\n    }\n\n    void App::AddFrameStat(const char* group, const char* name, uint64_t u)\n    {\n        AcquireSRWLockExclusive(&g_app->m_statsLock);\n        g_app->m_frameStats.emplace_back(group, name, u);\n        ReleaseSRWLockExclusive(&g_app->m_statsLock);\n    }\n\n    void App::AddFrameStat(const char* group, const char* name, uint32_t num, uint32_t total)\n    {\n        AcquireSRWLockExclusive(&g_app->m_statsLock);\n        g_app->m_frameStats.emplace_back(group, name, num, total);\n        ReleaseSRWLockExclusive(&g_app->m_statsLock);\n    }\n\n    Span<float> App::GetFrameTimeHistory()\n    {\n        auto& frameStats = g_app->m_frameTime;\n        return frameStats.FrameTimeHist;\n    }\n\n    void App::Log(const char* msg, LogMessage::MsgType t)\n    {\n        AcquireSRWLockExclusive(&g_app->m_logLock);\n        g_app->m_frameLogs.emplace_back(msg, t);\n        ReleaseSRWLockExclusive(&g_app->m_logLock);\n    }\n\n    Util::RWSynchronizedView<Vector<App::LogMessage, SystemAllocator>> App::GetLogs()\n    {\n        return RWSynchronizedView<Vector<LogMessage>>(g_app->m_frameLogs, g_app->m_logLock);;\n    }\n    \n    void App::CopyToClipboard(StrView data)\n    {\n        if (data.empty())\n            return;\n\n        const size_t n = Math::Min(data.size() - 1, (size_t)AppData::CLIPBOARD_LEN - 1);\n        memcpy(g_app->m_clipboard, data.data(), data.size());\n\n        Task t(\"Clipboard\", TASK_PRIORITY::BACKGROUND, [str = g_app->m_clipboard, n, hwnd = g_app->m_hwnd]()\n            {\n                auto h = GlobalAlloc(GMEM_MOVEABLE, n + 1);\n                void* dst = GlobalLock(h);\n                CheckWin32(dst);\n\n                memcpy(dst, str, n);\n                reinterpret_cast<char*>(dst)[n] = '\\0';\n\n                if (GlobalUnlock(h) == 0)\n                    Check(GetLastError() == NO_ERROR, \"GlobalUnlock() failed.\");\n\n                CheckWin32(OpenClipboard(hwnd));\n                CheckWin32(EmptyClipboard());\n                // \"If SetClipboardData succeeds, the system owns the object identified by \n                // the hMem parameter. The application may not write to or free the data once \n                // ownership has been transferred to the system\".\n                CheckWin32(SetClipboardData(CF_TEXT, h));\n\n                CheckWin32(CloseClipboard());\n            });\n\n        App::SubmitBackground(ZetaMove(t));\n    }\n}\n"
  },
  {
    "path": "Source/ZetaCore/Win32/Win32Common.cpp",
    "content": "#include \"../App/Common.h\"\n#include \"Win32.h\"\n#include <intrin.h>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::App;\n\nint Common::WideToCharStr(const wchar_t* wideStr, MutableSpan<char> str)\n{\n    int size = WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, nullptr, 0, nullptr, nullptr);\n    Assert(str.size() > size, \"buffer overflow\");\n\n    WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, str.data(), Math::Min(size, \n        (int)str.size()), nullptr, nullptr);\n\n    return size;\n}\n\nint Common::CharToWideStrLen(const char* str)\n{\n    const int size = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0);\n    return size;\n}\n\nint Common::CharToWideStr(const char* str, Util::MutableSpan<wchar_t> wideStr)\n{\n    // #size includes terminating null character\n    const int size = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0);\n    Assert(wideStr.size() >= size, \"Provided buffer is too small.\");\n\n    MultiByteToWideChar(CP_UTF8, 0, str, -1, wideStr.data(), (int)wideStr.size());\n\n    return size;\n}\n\nuint32_t Common::CheckIntrinsicSupport()\n{\n    uint32_t ret = 0;\n\n    // All x64 processors support SSE2,\n    // following code checks for SSE3, SSE4, AVX, F16C, AVX2 and BMI1 support\n\n    // EAX, EBX, ECX, EDX\n    int cpuInfo[4] = { 0 };\n    __cpuid(cpuInfo, 1);\n\n    if ((cpuInfo[2] & (0x1 | (1 << 9))) == (0x1 | (1 << 9)))\n        ret |= CPU_Intrinsic::SSE3;\n    if ((cpuInfo[2] & ((1 << 20) | (1 << 19))) == ((1 << 20) | (1 << 19)))\n        ret |= CPU_Intrinsic::SSE4;\n    if (cpuInfo[2] & (1 << 28))\n        ret |= CPU_Intrinsic::AVX;\n    if (cpuInfo[2] & (1 << 29))\n        ret |= CPU_Intrinsic::F16C;\n\n    memset(cpuInfo, 0, ZetaArrayLen(cpuInfo) * sizeof(int));\n    __cpuid(cpuInfo, 0x7);\n\n    if (cpuInfo[1] & (1 << 5))\n        ret |= CPU_Intrinsic::AVX2;\n    if (cpuInfo[1] & (1 << 3))\n        ret |= CPU_Intrinsic::BMI1;\n\n    return ret;\n}"
  },
  {
    "path": "Source/ZetaCore/Win32/Win32Filesystem.cpp",
    "content": "#include \"../App/Filesystem.h\"\n#include \"../Support/MemoryArena.h\"\n#include \"Win32.h\"\n\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::App;\n\n//--------------------------------------------------------------------------------------\n// Functions\n//--------------------------------------------------------------------------------------\n\nvoid Filesystem::LoadFromFile(const char* path, Vector<uint8_t>& fileData)\n{\n    Assert(path, \"path argument was NULL.\");\n\n    HANDLE h = CreateFileA(path,\n        GENERIC_READ,\n        FILE_SHARE_READ,\n        nullptr,\n        OPEN_EXISTING,\n        FILE_ATTRIBUTE_NORMAL, nullptr);\n\n    Check(h, \"CreateFile() for path %s failed with the following error code: %d.\", path, \n        GetLastError());\n\n    LARGE_INTEGER s;\n    bool success = GetFileSizeEx(h, &s);\n    Check(success, \"GetFileSizeEx() for path %s failed with the following error code: %d.\", \n        path, GetLastError());\n\n    fileData.resize(s.QuadPart);\n    DWORD numRead;\n    success = ReadFile(h, fileData.data(), (DWORD)s.QuadPart, &numRead, nullptr);\n\n    Check(success, \"ReadFile() for path %s failed with the following error code: %d.\", \n        path, GetLastError());\n    Check(numRead == (DWORD)s.QuadPart,\n        \"ReadFile(): read %u bytes, requested size: %u\", numRead, (DWORD)s.QuadPart);\n\n    CloseHandle(h);\n}\n\nvoid Filesystem::LoadFromFile(const char* path, Vector<uint8_t, Support::ArenaAllocator>& fileData)\n{\n    Assert(path, \"path argument was NULL.\");\n\n    HANDLE h = CreateFileA(path,\n        GENERIC_READ,\n        FILE_SHARE_READ,\n        nullptr,\n        OPEN_EXISTING,\n        FILE_ATTRIBUTE_NORMAL, nullptr);\n\n    Check(h, \"CreateFile() for path %s failed with the following error code: %d.\", \n        path, GetLastError());\n\n    LARGE_INTEGER s;\n    bool success = GetFileSizeEx(h, &s);\n    Check(success, \"GetFileSizeEx() for path %s failed with the following error code: %d.\", \n        path, GetLastError());\n\n    fileData.resize(s.QuadPart);\n    DWORD numRead;\n    success = ReadFile(h, fileData.data(), (DWORD)s.QuadPart, &numRead, nullptr);\n\n    Check(success, \"ReadFile() for path %s failed with the following error code: %d.\", \n        path, GetLastError());\n    Check(numRead == (DWORD)s.QuadPart,\n        \"ReadFile(): read %u bytes, requested size: %u.\", numRead, (DWORD)s.QuadPart);\n\n    CloseHandle(h);\n}\n\nvoid Filesystem::WriteToFile(const char* path, uint8_t* data, uint32_t sizeInBytes)\n{\n    Assert(path, \"path argument was NULL.\");\n\n    HANDLE h = CreateFileA(path,\n        GENERIC_WRITE,\n        FILE_SHARE_WRITE,\n        nullptr,\n        CREATE_ALWAYS,\n        FILE_ATTRIBUTE_NORMAL,\n        nullptr);\n\n    if (h == INVALID_HANDLE_VALUE)\n    {\n        auto e = GetLastError();\n\n        // overwrite is fine\n        Check(e == ERROR_ALREADY_EXISTS, \n            \"CreateFile() for path %s failed with the following error code: %d\", path, e);\n    }\n\n    DWORD numWritten;\n    bool success = WriteFile(h, data, sizeInBytes, &numWritten, nullptr);\n\n    Check(success, \"WriteFile() for path %s failed with the following error code: %d.\", \n        path, GetLastError());\n    Check(numWritten == (DWORD)sizeInBytes,\n        \"WriteFile(): wrote %u bytes, requested size: %llu.\", numWritten, sizeInBytes);\n\n    CloseHandle(h);\n}\n\nvoid Filesystem::RemoveFile(const char* path)\n{\n    Assert(path, \"path argument was NULL.\");\n\n    bool success = DeleteFileA(path);\n    Check(success, \"DeleteFile() for path %s failed with the following error code: %d.\", \n        path, GetLastError());\n}\n\nbool Filesystem::Exists(const char* path)\n{\n    Assert(path, \"path argument was NULL.\");\n    auto attrib = GetFileAttributesA(path);\n\n    return (attrib != INVALID_FILE_ATTRIBUTES) && !(attrib & FILE_ATTRIBUTE_DIRECTORY);\n}\n\nsize_t Filesystem::GetFileSize(const char* path)\n{\n    Assert(path, \"path argument was NULL.\");\n\n    HANDLE h = CreateFileA(path,\n        GENERIC_READ,\n        FILE_SHARE_READ,\n        nullptr,\n        OPEN_EXISTING,\n        FILE_ATTRIBUTE_NORMAL, nullptr);\n\n    if (h == INVALID_HANDLE_VALUE)\n    {\n        auto e = GetLastError();\n        if (e == ERROR_FILE_NOT_FOUND)\n        {\n            CloseHandle(h);\n            return size_t(-1);\n        }\n\n        Check(false, \"CreateFile() for path %s failed with the following error code: %d.\", \n            path, e);\n    }\n\n    LARGE_INTEGER s;\n    CheckWin32(GetFileSizeEx(h, &s));\n\n    CloseHandle(h);\n\n    return s.QuadPart;\n}\n\nvoid Filesystem::CreateDirectoryIfNotExists(const char* path)\n{\n    Assert(path, \"path argument was NULL.\");\n    auto attrib = GetFileAttributesA(path);\n    if ((attrib != INVALID_FILE_ATTRIBUTES) && (attrib & FILE_ATTRIBUTE_DIRECTORY))\n        return;\n\n    CheckWin32(CreateDirectoryA(path, nullptr));\n}\n\nbool Filesystem::Copy(const char* path, const char* newPath, bool overwrite)\n{\n    bool ret = CopyFileA(path, newPath, !overwrite);\n    if (!ret)\n    {\n        auto err = GetLastError();\n        Check(err == ERROR_FILE_EXISTS, \"CopyFile() failed with the error code: %d\\n.\", err);\n\n        return false;\n    }\n\n    return true;\n}\n\nbool Filesystem::IsDirectory(const char* path)\n{\n    Assert(path, \"path argument was NULL.\");\n    auto ret = GetFileAttributesA(path);\n\n    if (ret == INVALID_FILE_ATTRIBUTES)\n    {\n        auto err = GetLastError();\n        auto validCodes = ERROR_FILE_NOT_FOUND;\n        Check(err & validCodes, \"GetFileAttributesA() failed with the error code: %d\\n.\", err);\n\n        return false;\n    }\n\n    return ret & FILE_ATTRIBUTE_DIRECTORY;\n}\n"
  },
  {
    "path": "Source/ZetaCore/Win32/Win32Timer.cpp",
    "content": "#include \"../App/Timer.h\"\n#include \"Win32.h\"\n\nusing namespace ZetaRay::App;\n\n//--------------------------------------------------------------------------------------\n// Timer\n//--------------------------------------------------------------------------------------\n\nTimer::Timer()\n{\n    LARGE_INTEGER freq;\n    bool success = QueryPerformanceFrequency(&freq);\n    Assert(success, \"QueryPerformanceFrequency() failed.\");\n    m_counterFreqSec = freq.QuadPart;\n}\n\nvoid Timer::Start()\n{\n    LARGE_INTEGER currCount;\n    CheckWin32(QueryPerformanceCounter(&currCount));\n    m_start = currCount.QuadPart;\n}\n\nvoid Timer::Resume()\n{\n    LARGE_INTEGER currCount;\n    CheckWin32(QueryPerformanceCounter(&currCount));\n    m_last = currCount.QuadPart;\n\n    if (m_paused)\n    {\n        m_totalPausedCounts += m_last - m_pauseCount;\n        m_pauseCount = 0;\n\n        m_paused = false;\n    }\n}\n\nvoid Timer::Pause()\n{\n    if (m_paused)\n        return;\n\n    LARGE_INTEGER currCount;\n    CheckWin32(QueryPerformanceCounter(&currCount));\n    m_pauseCount = currCount.QuadPart;\n\n    m_framesInLastSecond = 0;\n    m_numCountsInLastSecond = 0;\n    m_paused = true;\n}\n\nvoid Timer::Tick()\n{\n    if (m_paused)\n        return;\n\n    LARGE_INTEGER currCount;\n    CheckWin32(QueryPerformanceCounter(&currCount));\n\n    m_elapsedCounts = currCount.QuadPart - m_last;\n    m_numCountsInLastSecond += m_elapsedCounts;\n    m_framesInLastSecond++;\n    m_last = currCount.QuadPart;\n\n    m_delta = (double)m_elapsedCounts / m_counterFreqSec;\n    m_counterFreqSec += (int64_t)m_delta;\n\n    // there are \"m_counterFreqSec\" counts per second. by keeping track\n    // of number of counts we can know when one second has passed. number\n    // of times Tick() was called during that one second is equal to FPS\n    if (m_numCountsInLastSecond >= m_counterFreqSec)\n    {\n        m_fps = (int)m_framesInLastSecond;\n        m_framesInLastSecond = 0;\n        m_numCountsInLastSecond = 0;\n    }\n\n    m_frameCount++;\n}\n\n//--------------------------------------------------------------------------------------\n// DeltaTimer\n//--------------------------------------------------------------------------------------\n\nDeltaTimer::DeltaTimer()\n{\n    LARGE_INTEGER freq;\n    bool success = QueryPerformanceFrequency(&freq);\n    Assert(success, \"QueryPerformanceFrequency() failed.\");\n    m_counterFreqSec = freq.QuadPart;\n}\n\nvoid DeltaTimer::Start()\n{\n    LARGE_INTEGER currCount;\n    CheckWin32(QueryPerformanceCounter(&currCount));\n    m_start = currCount.QuadPart;\n}\n\nvoid DeltaTimer::End()\n{\n    LARGE_INTEGER currCount;\n    CheckWin32(QueryPerformanceCounter(&currCount));\n    m_end = currCount.QuadPart;\n}\n\ndouble DeltaTimer::DeltaNano()\n{\n    // convert to microseconds before dividing to avoid precision loss\n    // https://docs.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps\n    int64_t elapsedMicro = 1'000'000'000 * (m_end - m_start);\n    return (double)elapsedMicro / m_counterFreqSec;\n}\n\ndouble DeltaTimer::DeltaMicro()\n{\n    // convert to microseconds before dividing to avoid precision loss\n    // https://docs.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps\n    int64_t elapsedMicro = 1'000'000 * (m_end - m_start);\n    return (double)elapsedMicro / m_counterFreqSec;\n}\n\ndouble DeltaTimer::DeltaMilli()\n{\n    // convert to milliseconds before dividing to avoid precision loss\n    // https://docs.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps\n    int64_t elapsedMicro = 1'000 * (m_end - m_start);\n    return (double)elapsedMicro / m_counterFreqSec;\n}\n"
  },
  {
    "path": "Source/ZetaLab/CMakeLists.txt",
    "content": "add_executable(ZetaLab WIN32 \"${CMAKE_SOURCE_DIR}/Source/ZetaLab/ZetaLab.cpp\")\ntarget_link_libraries(ZetaLab ZetaCore ZetaRenderer ZetaRenderPass)\ntarget_include_directories(ZetaLab BEFORE PRIVATE ${ZETA_CORE_DIR} ${ZETA_RENDERER_DIR} ${ZETA_RENDER_PASS_DIR})\nset_target_properties(ZetaLab PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})\nset_target_properties(ZetaLab PROPERTIES FOLDER \"Samples\")\nset_target_properties(ZetaLab PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")"
  },
  {
    "path": "Source/ZetaLab/ZetaLab.cpp",
    "content": "//\n// Main.cpp\n//\n\n#define OPEN_CONSOLE 0\n\n#include <App/Log.h>\n#include <App/Timer.h>\n#include <Scene/SceneCore.h>\n#include <Model/glTF.h>\n#include <Default/DefaultRenderer.h>\n#include <App/Filesystem.h>\n\n#if OPEN_CONSOLE == 1\n#include <fcntl.h>\n#include <io.h>\n#endif\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Model;\n\n// Indicates to hybrid graphics systems to prefer the discrete part by default\nextern \"C\"\n{\n    __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;\n    __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;\n\n    _declspec(dllexport) extern const UINT D3D12SDKVersion = 615;\n    _declspec(dllexport) extern const char8_t* D3D12SDKPath = u8\".\\\\D3D12\\\\\";\n}\n\nint WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ PSTR lpCmdLine, _In_ int nCmdShow)\n{\n#if OPEN_CONSOLE == 1\n    AllocConsole();\n    HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);\n    int hConsole = _open_osfhandle(reinterpret_cast<intptr_t>(stdHandle), _O_TEXT);\n    FILE* fp = _fdopen(hConsole, \"w\");\n    freopen_s(&fp, \"CONOUT$\", \"w\", stdout);\n#endif\n\n    Check(strlen(lpCmdLine), \"Usage: ZetaLab <path-to-gltf>\\n\");\n\n    {\n        App::Filesystem::Path path(lpCmdLine);\n        Check(App::Filesystem::Exists(path.Get()), \"Provided path was not found: %s\\nExiting...\\n\", lpCmdLine);\n\n        App::DeltaTimer timer;\n        timer.Start();\n\n        auto rndIntrf = DefaultRenderer::InitAndGetInterface();\n        App::Init(rndIntrf);\n\n        timer.End();\n\n        LOG_UI(INFO, \"App initialization completed in %u[ms]\\n\", (uint32_t)timer.DeltaMilli());\n\n        // load the gltf model(s)\n        timer.Start();\n\n        glTF::Load(path);\n\n        App::FlushWorkerThreadPool();\n\n        timer.End();\n\n        LOG_UI(INFO, \"glTF scene loaded in %u[ms]\\n\", (uint32_t)timer.DeltaMilli());\n    }\n\n    App::Run();\n\n    return 0;\n}"
  },
  {
    "path": "Source/ZetaRenderPass/AutoExposure/AutoExposure.cpp",
    "content": "#include \"AutoExposure.h\"\n#include <Core/CommandList.h>\n#include <Scene/SceneRenderer.h>\n#include <Support/Param.h>\n#include \"../Assets/Font/IconsFontAwesome6.h\"\n\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::Direct3DUtil;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Support;\n\n//--------------------------------------------------------------------------------------\n// AutoExposure\n//--------------------------------------------------------------------------------------\n\nAutoExposure::AutoExposure()\n    : RenderPassBase(NUM_CBV, NUM_SRV, NUM_UAV, NUM_GLOBS, NUM_CONSTS)\n{\n    // frame constants\n    m_rootSig.InitAsCBV(0, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::FRAME_CONSTANTS_BUFFER);\n\n    // root constants\n    m_rootSig.InitAsConstants(1, NUM_CONSTS, 1);\n    m_rootSig.InitAsBufferUAV(2, 0, 0, D3D12_ROOT_DESCRIPTOR_FLAG_DATA_VOLATILE);\n}\n\nvoid AutoExposure::InitPSOs()\n{\n    constexpr D3D12_ROOT_SIGNATURE_FLAGS flags =\n        D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;\n\n    RenderPassBase::InitRenderPass(\"AutoExposure\", flags);\n\n    m_psoLib.CompileComputePSO((int)SHADER::HISTOGRAM, m_rootSigObj.Get(),\n        COMPILED_CS[(int)SHADER::HISTOGRAM]);\n    m_psoLib.CompileComputePSO((int)SHADER::WEIGHTED_AVG, m_rootSigObj.Get(),\n        COMPILED_CS[(int)SHADER::WEIGHTED_AVG]);\n}\n\nvoid AutoExposure::Init()\n{\n    InitPSOs();\n\n    m_minLum = DefaultParamVals::MinLum;\n    m_maxLum = DefaultParamVals::MaxLum;\n    m_cbHist.LumMapExp = DefaultParamVals::LumMapExp;\n    m_cbHist.AdaptationRate = DefaultParamVals::AdaptationRate;\n    m_cbHist.LowerPercentile = DefaultParamVals::LowerPercentile;\n    m_cbHist.UpperPercentile = DefaultParamVals::UpperPercentile;\n\n    ParamVariant p1;\n    p1.InitFloat(ICON_FA_FILM \" Renderer\", \"Auto Exposure\", \"Min Lum\", fastdelegate::MakeDelegate(this, &AutoExposure::MinLumCallback),\n        DefaultParamVals::MinLum, 1e-4f, 0.5f, 1e-3f);\n    App::AddParam(p1);\n\n    ParamVariant p2;\n    p2.InitFloat(ICON_FA_FILM \" Renderer\", \"Auto Exposure\", \"Max Lum\", fastdelegate::MakeDelegate(this, &AutoExposure::MaxLumCallback),\n        DefaultParamVals::MaxLum, 0.5f, 8.0f, 1e-2f);\n    App::AddParam(p2);\n\n    //ParamVariant p5;\n    //p5.InitFloat(ICON_FA_FILM \" Renderer\", \"Auto Exposure\", \"Lower Percentile\", fastdelegate::MakeDelegate(this, &AutoExposure::LowerPercentileCallback),\n    //    DefaultParamVals::LowerPercentile, 0.0f, 0.3f, 0.01f);\n    //App::AddParam(p5);\n\n    //ParamVariant p6;\n    //p6.InitFloat(ICON_FA_FILM \" Renderer\", \"Auto Exposure\", \"Upper Percentile\", fastdelegate::MakeDelegate(this, &AutoExposure::UpperPercentileCallback),\n    //    DefaultParamVals::UpperPercentile, 0.6f, 1.0f, 0.01f);\n    //App::AddParam(p6);\n\n    ParamVariant p3;\n    p3.InitFloat(ICON_FA_FILM \" Renderer\", \"Auto Exposure\", \"Lum Map Exp\", fastdelegate::MakeDelegate(this, &AutoExposure::LumMapExpCallback),\n        DefaultParamVals::LumMapExp, 1e-1f, 1.0f, 1e-2f);\n    App::AddParam(p3);\n\n    m_descTable = App::GetRenderer().GetGpuDescriptorHeap().Allocate((int)DESC_TABLE::COUNT);\n    CreateResources();\n\n    App::AddShaderReloadHandler(\"AutoExposure\", fastdelegate::MakeDelegate(this, &AutoExposure::Reload));\n}\n\nvoid AutoExposure::Render(CommandList& cmdList)\n{\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT ||\n        cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE, \"Invalid downcast\");\n    ComputeCmdList& computeCmdList = static_cast<ComputeCmdList&>(cmdList);\n\n    Assert(m_inputDesc[(int)SHADER_IN_DESC::COMPOSITED] != -1, \"Input descriptor hasn't been set.\");\n\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n    const uint32_t w = renderer.GetRenderWidth();\n    const uint32_t h = renderer.GetRenderHeight();\n\n    computeCmdList.PIXBeginEvent(\"AutoExposure\");\n    const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"AutoExposure\");\n\n    computeCmdList.SetRootSignature(m_rootSig, m_rootSigObj.Get());\n\n    m_cbHist.MinLum = m_minLum;\n    m_cbHist.LumRange = m_maxLum - m_minLum;\n    m_cbHist.InputDescHeapIdx = m_inputDesc[(int)SHADER_IN_DESC::COMPOSITED];\n    m_cbHist.ExposureDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((uint32_t)DESC_TABLE::EXPOSURE_UAV);\n\n    m_rootSig.SetRootUAV(2, m_hist.GpuVA());\n    m_rootSig.SetRootConstants(0, sizeof(cbAutoExposureHist) / sizeof(DWORD), &m_cbHist);\n    m_rootSig.End(computeCmdList);\n\n    const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, THREAD_GROUP_SIZE_HIST_X);\n    const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, THREAD_GROUP_SIZE_HIST_Y);\n\n    computeCmdList.ResourceBarrier(m_hist.Resource(), D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST);\n    computeCmdList.CopyBufferRegion(m_hist.Resource(), 0, m_zeroBuffer.Resource(), 0, HIST_BIN_COUNT * sizeof(uint32_t));\n    computeCmdList.ResourceBarrier(m_hist.Resource(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n\n    computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::HISTOGRAM));\n    computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n\n    auto uavBarrier = Direct3DUtil::UAVBarrier(m_hist.Resource());\n    computeCmdList.UAVBarrier(1, &uavBarrier);\n\n    computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::WEIGHTED_AVG));\n    computeCmdList.Dispatch(1, 1, 1);\n\n    gpuTimer.EndQuery(computeCmdList, queryIdx);\n    computeCmdList.PIXEndEvent();    \n}\n\nvoid AutoExposure::CreateResources()\n{\n    auto& renderer = App::GetRenderer();\n\n    m_hist = GpuMemory::GetDefaultHeapBuffer(\"LogLumHistogram\",\n        HIST_BIN_COUNT * sizeof(uint32_t),\n        D3D12_RESOURCE_STATE_COMMON,\n        true);\n\n    m_exposure = GpuMemory::GetTexture2D(\"Exposure\",\n        1,\n        1,\n        DXGI_FORMAT_R32G32_FLOAT,\n        D3D12_RESOURCE_STATE_COMMON,\n        TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS | TEXTURE_FLAGS::INIT_TO_ZERO);\n\n    // create a zero-initialized buffer for resetting the counter\n    m_zeroBuffer = GpuMemory::GetDefaultHeapBuffer(\"Zero\",\n        HIST_BIN_COUNT * sizeof(uint32_t),\n        D3D12_RESOURCE_STATE_COMMON,\n        false,\n        true);\n\n    Direct3DUtil::CreateTexture2DUAV(m_exposure, m_descTable.CPUHandle((int)DESC_TABLE::EXPOSURE_UAV));\n}\n\nvoid AutoExposure::MinLumCallback(const Support::ParamVariant& p)\n{\n    m_minLum = Math::Min(p.GetFloat().m_value, m_maxLum);\n}\n\nvoid AutoExposure::MaxLumCallback(const Support::ParamVariant& p)\n{\n    m_maxLum = Math::Max(p.GetFloat().m_value, m_minLum);\n}\n\nvoid AutoExposure::LumMapExpCallback(const Support::ParamVariant& p)\n{\n    m_cbHist.LumMapExp = p.GetFloat().m_value;\n}\n\nvoid AutoExposure::LowerPercentileCallback(const Support::ParamVariant& p)\n{\n    m_cbHist.LowerPercentile = p.GetFloat().m_value;\n}\n\nvoid AutoExposure::UpperPercentileCallback(const Support::ParamVariant& p)\n{\n    m_cbHist.UpperPercentile = p.GetFloat().m_value;\n}\n\nvoid AutoExposure::Reload()\n{\n    const int i = (int)SHADER::WEIGHTED_AVG;\n    m_psoLib.Reload(i, m_rootSigObj.Get(), \"AutoExposure\\\\AutoExposure_WeightedAvg.hlsl\");\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/AutoExposure/AutoExposure.h",
    "content": "#pragma once\n\n#include \"../RenderPass.h\"\n#include <Core/GpuMemory.h>\n#include \"AutoExposure_Common.h\"\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n}\n\nnamespace ZetaRay::RenderPass\n{\n    enum class AUTO_EXPOSURE_SHADER\n    {\n        HISTOGRAM,\n        WEIGHTED_AVG,\n        COUNT\n    };\n\n    struct AutoExposure final : public RenderPassBase<(int)AUTO_EXPOSURE_SHADER::COUNT>\n    {\n        enum class SHADER_IN_DESC\n        {\n            COMPOSITED,\n            COUNT\n        };\n\n        enum class SHADER_OUT_RES\n        {\n            EXPOSURE,\n            COUNT\n        };\n\n        AutoExposure();\n        ~AutoExposure() = default;\n\n        void InitPSOs();\n        void Init();\n        void SetDescriptor(SHADER_IN_DESC i, uint32_t heapIdx)\n        {\n            Assert((uint32_t)i < (uint32_t)SHADER_IN_DESC::COUNT, \"out-of-bound access.\");\n            m_inputDesc[(uint32_t)i] = heapIdx;\n        }\n        Core::GpuMemory::Texture& GetOutput(SHADER_OUT_RES i)\n        {\n            Assert((uint32_t)i < (uint32_t)SHADER_OUT_RES::COUNT, \"out-of-bound access.\");\n            return m_exposure;\n        }\n        void Render(Core::CommandList& cmdList);\n\n    private:\n        static constexpr int NUM_CBV = 1;\n        static constexpr int NUM_SRV = 0;\n        static constexpr int NUM_UAV = 1;\n        static constexpr int NUM_GLOBS = 1;\n        static constexpr int NUM_CONSTS = (int)sizeof(cbAutoExposureHist) / sizeof(DWORD);\n        using SHADER = RenderPass::AUTO_EXPOSURE_SHADER;\n\n        enum class DESC_TABLE\n        {\n            EXPOSURE_UAV,\n            HISTOGRAM_UAV,\n            COUNT\n        };\n\n        inline static constexpr const char* COMPILED_CS[(int)SHADER::COUNT] =\n        {\n            \"AutoExposure_Histogram_cs.cso\",\n            \"AutoExposure_WeightedAvg_cs.cso\"\n        };\n\n        struct DefaultParamVals\n        {\n            static constexpr float MinLum = 5e-3f;\n            static constexpr float MaxLum = 4.0f;\n            static constexpr float LumMapExp = 0.5f;\n            static constexpr float AdaptationRate = 1.0f;\n            static constexpr float LowerPercentile = 0.01f;\n            static constexpr float UpperPercentile = 0.9f;\n        };\n\n        void CreateResources();\n        void MinLumCallback(const Support::ParamVariant& p);\n        void MaxLumCallback(const Support::ParamVariant& p);\n        void LumMapExpCallback(const Support::ParamVariant& p);\n        void LowerPercentileCallback(const Support::ParamVariant& p);\n        void UpperPercentileCallback(const Support::ParamVariant& p);\n        void Reload();\n\n        Core::GpuMemory::Texture m_exposure;\n        Core::GpuMemory::Buffer m_counter;\n        Core::GpuMemory::Buffer m_hist;\n        Core::GpuMemory::Buffer m_zeroBuffer;        // for resetting the histogram to zero each frame\n        uint32_t m_inputDesc[(int)SHADER_IN_DESC::COUNT] = { 0 };\n        Core::DescriptorTable m_descTable;\n        float m_minLum;\n        float m_maxLum;\n        cbAutoExposureHist m_cbHist;\n    };\n}"
  },
  {
    "path": "Source/ZetaRenderPass/AutoExposure/AutoExposure_Common.h",
    "content": "#ifndef AUTO_EXPOSURE_H\n#define AUTO_EXPOSURE_H\n\n#include \"../../ZetaCore/Core/HLSLCompat.h\"\n\n#define THREAD_GROUP_SIZE_HIST_X 16u\n#define THREAD_GROUP_SIZE_HIST_Y 16u\n\n#define HIST_BIN_COUNT 256\n\nstruct cbAutoExposureHist\n{\n    uint32_t InputDescHeapIdx;\n    uint32_t ExposureDescHeapIdx;\n    float MinLum;\n    float LumRange;\n    float LumMapExp;\n    float AdaptationRate;\n    float LowerPercentile;\n    float UpperPercentile;\n};\n\n#endif // AUTO_EXPOSURE_H"
  },
  {
    "path": "Source/ZetaRenderPass/AutoExposure/AutoExposure_Histogram.hlsl",
    "content": "// Ref: https://alextardif.com/HistogramLuminance.html\n\n#include \"AutoExposure_Common.h\"\n#include \"../Common/Math.hlsli\"\n#include \"../Common/FrameConstants.h\"\n#include \"../Common/StaticTextureSamplers.hlsli\"\n\n#define EPS 1e-4f\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cbAutoExposureHist> g_local : register(b1);\nRWByteAddressBuffer g_hist : register(u0);\n\n//--------------------------------------------------------------------------------------\n// Helper functions\n//--------------------------------------------------------------------------------------\n\nuint CalculateeBin(uint2 DTid)\n{\n    // Can't early exit for out-of-screen threads\n    if (DTid.x >= g_frame.RenderWidth || DTid.y >= g_frame.RenderHeight)\n        return UINT32_MAX;\n\n    Texture2D<half4> g_input = ResourceDescriptorHeap[g_local.InputDescHeapIdx];\n    const float3 color = g_input[DTid].rgb;\n    const float lum = Math::Luminance(color);\n\n    if (lum <= EPS)\n        return 0;\n\n    float t = saturate((lum - g_local.MinLum) / g_local.LumRange);\n    t = pow(t, g_local.LumMapExp);\n    uint bin = (uint) (t * (HIST_BIN_COUNT - 2)) + 1;\n\n    return bin;\n}\n\n//--------------------------------------------------------------------------------------\n// main\n//--------------------------------------------------------------------------------------\n\ngroupshared uint g_binSize[HIST_BIN_COUNT];\n\n[numthreads(THREAD_GROUP_SIZE_HIST_X, THREAD_GROUP_SIZE_HIST_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint Gidx : SV_GroupIndex)\n{\n    g_binSize[Gidx] = 0;\n\n    GroupMemoryBarrierWithGroupSync();\n\n    const uint bin = CalculateeBin(DTid.xy);\n    const uint4 waveBinMask = WaveMatch(bin);\n    //const uint binSizeInWave = WaveMultiPrefixCountBits(true, waveBinMask);\n    const uint binSizeInWave = dot(1, countbits(waveBinMask));\n\n    // Add number of preceding bits (multiples of 32 bits). When mask is zero, firstbitlow \n    // returns -1 and the following logical or doesn't change it (x | -1 = -1).\n    const uint4 firstSetLanes = firstbitlow(waveBinMask) | uint4(0x0, 0x20, 0x40, 0x60);\n    // min between uint(-1) and anything else returns the latter\n    const uint writerLane = min(min(min(firstSetLanes.x, firstSetLanes.y), firstSetLanes.z), firstSetLanes.w);\n\n    // Make sure threads outside the screen are skipped\n    if (writerLane == WaveGetLaneIndex() && bin != UINT32_MAX)\n        InterlockedAdd(g_binSize[bin], binSizeInWave);\n\n    GroupMemoryBarrierWithGroupSync();\n\n    const uint byteOffsetForBin = Gidx * sizeof(uint);\n    g_hist.InterlockedAdd(byteOffsetForBin, g_binSize[Gidx]);\n}"
  },
  {
    "path": "Source/ZetaRenderPass/AutoExposure/AutoExposure_WeightedAvg.hlsl",
    "content": "#include \"AutoExposure_Common.h\"\n#include \"../Common/Math.hlsli\"\n#include \"../Common/FrameConstants.h\"\n#include \"../Common/StaticTextureSamplers.hlsli\"\n\n#define SKIP_OUTSIDE_PERCENTILE_RANGE 0\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cbAutoExposureHist> g_local : register(b1);\nRWByteAddressBuffer g_hist : register(u0);\n\n//--------------------------------------------------------------------------------------\n// Helper functions\n//--------------------------------------------------------------------------------------\n\nfloat ComputeAutoExposure(float avgLum)\n{\n    const float S = 100.0f;\n    const float K = 12.5f;\n    const float EV100 = log2((avgLum * S) / K);\n    const float q = 0.65f;\n    const float luminanceMax = (78.0f / (q * S)) * pow(2.0f, EV100);\n    return 1 / luminanceMax;\n}\n\n//--------------------------------------------------------------------------------------\n// main\n//--------------------------------------------------------------------------------------\n\nstatic const int MinWaveSize = 16;\nstatic const int MaxNumWaves = HIST_BIN_COUNT / MinWaveSize;\ngroupshared float g_waveSum[MaxNumWaves];\n\n#if SKIP_OUTSIDE_PERCENTILE_RANGE == 1\ngroupshared uint g_waveSampleCount[MaxNumWaves];\n#endif\n\n[numthreads(HIST_BIN_COUNT, 1, 1)]\nvoid main(uint Gidx : SV_GroupIndex)\n{\n    // Exclude the first (invalid) bin\n    const bool isFirstBin = (Gidx == 0);\n    const uint binSize = isFirstBin ? 0 : g_hist.Load(Gidx * sizeof(uint));\n    const uint numLanesInWave = WaveGetLaneCount();\n    const uint wave = Gidx / numLanesInWave;\n    const uint numWavesInGroup = HIST_BIN_COUNT / numLanesInWave;\t// HIST_BIN_COUNT is always divisible by wave size\n    const uint numExcludedSamples = g_hist.Load(0);\n    const uint numSamples = g_frame.RenderWidth * g_frame.RenderHeight - numExcludedSamples;\n\n    // Prefix sum for the whole group to calculate the percentiles up to each bin\n#if SKIP_OUTSIDE_PERCENTILE_RANGE == 1\n    uint binPercentile = WavePrefixSum(binSize) + binSize;\n\n    if (WaveGetLaneIndex() == WaveGetLaneCount() - 1)\n        g_waveSampleCount[wave] = binPercentile;\n#endif\n\n    GroupMemoryBarrierWithGroupSync();\n\n    // Add in the samples from previous waves\n#if SKIP_OUTSIDE_PERCENTILE_RANGE == 1\n    for (int w = 0; w < wave; w++)\n        binPercentile += g_waveSampleCount[w];\n\n    const uint lowerPercentileNumSamples = (uint)(numSamples * g_local.LowerPercentile);\n    const uint upperPercentileNumSamples = (uint)(numSamples * g_local.UpperPercentile);\n\n    // Exclude bins that don't fall in the intended range\n    bool skip = (binPercentile < lowerPercentileNumSamples) || (binPercentile > upperPercentileNumSamples);\n    skip = skip || isFirstBin;\n#else\n    bool skip = isFirstBin;\n#endif\n\n    // Skipped bins don't contribute to average\n    float val = skip ? 0 : binSize * (Gidx - 1 + 0.5f) / HIST_BIN_COUNT;\n    val = WaveActiveSum(val);\n\n    if (WaveIsFirstLane())\n        g_waveSum[wave] = val;\n\n    GroupMemoryBarrierWithGroupSync();\n\n    // Sum across the waves\n    float mean = Gidx < numWavesInGroup ? g_waveSum[Gidx] : 0.0;\n    // Assuming min wave size of at least 16, there are at most 16 values to sum together, \n    // so one WaveActiveSum is enough\n    mean = WaveActiveSum(mean);\n    mean /= max(numSamples, 1);\n\n    if (Gidx == 0)\n    {\n        // Do the inverse mapping\n        float result = pow(mean, 1.0 / g_local.LumMapExp);\n        result = result * g_local.LumRange + g_local.MinLum;\n\n        RWTexture2D<float2> g_out = ResourceDescriptorHeap[g_local.ExposureDescHeapIdx];\n        float prev = g_out[int2(0, 0)].y;\n\n        if (prev < 1e8f)\n            result = prev + (result - prev) * (1 - exp(-g_frame.dt * 1000.0f * g_local.AdaptationRate));\n\n        float exposure = ComputeAutoExposure(result);\n        g_out[int2(0, 0)] = float2(exposure, result);\n    }\n}"
  },
  {
    "path": "Source/ZetaRenderPass/AutoExposure/CMakeLists.txt",
    "content": "set(RP_AUTO_EXPOSURE_DIR ${ZETA_RENDER_PASS_DIR}/AutoExposure)\nset(RP_AUTO_EXPOSURE_SRC\n    ${RP_AUTO_EXPOSURE_DIR}/AutoExposure.cpp\n    ${RP_AUTO_EXPOSURE_DIR}/AutoExposure.h\n    ${RP_AUTO_EXPOSURE_DIR}/AutoExposure_Histogram.hlsl\n    ${RP_AUTO_EXPOSURE_DIR}/AutoExposure_WeightedAvg.hlsl\n    ${RP_AUTO_EXPOSURE_DIR}/AutoExposure_Common.h)\nset(RP_AUTO_EXPOSURE_SRC ${RP_AUTO_EXPOSURE_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaRenderPass/CMakeLists.txt",
    "content": "include(\"${CMAKE_INCLUDE_DIR}/CompileHLSL.cmake\")\n\nadd_subdirectory(AutoExposure)\nadd_subdirectory(Common)\nadd_subdirectory(Compositing)\nadd_subdirectory(Display)\nadd_subdirectory(DirectLighting)\nadd_subdirectory(FSR2)\nadd_subdirectory(GBuffer)\nadd_subdirectory(GUI)\nadd_subdirectory(IndirectLighting)\nadd_subdirectory(PreLighting)\nadd_subdirectory(Sky)\nadd_subdirectory(TAA)\n\nset(RENDERPASS_SRC \n    \"${ZETA_RENDER_PASS_DIR}/RenderPass.h\"\n    ${RP_AUTO_EXPOSURE_SRC} \n    ${RP_COMMON_SRC} \n    ${RP_COMPOSITING_SRC} \n    ${RP_DI_SRC} \n    ${RP_DISPLAY_SRC} \n    ${RP_FSR2_SRC} \n    ${RP_GBUFFER_RT_SRC} \n    ${RP_GUI_SRC} \n    ${RP_IND_LIGHTING_SRC} \n    ${RP_PRE_LIGHTING_SRC} \n    ${RP_SKY_SRC} \n    ${RP_TAA_SRC})\n        \nfile(GLOB_RECURSE ALL_SHADERS \"${ZETA_RENDER_PASS_DIR}/*.hlsl\")\n\nforeach(HLSL ${ALL_SHADERS})\n    CompileHLSL(${HLSL} CSOS)\n    set(ALL_CSOS ${ALL_CSOS} ${CSOS})\nendforeach()\n\nadd_custom_target(CompileShaders ALL DEPENDS ${ALL_CSOS})\n\n# override MSBuild, which tries to call fxc\nif(MSVC)\n    set_source_files_properties(${ALL_SHADERS} PROPERTIES VS_TOOL_OVERRIDE \"None\")\nendif()\n\n# build ZetaRenderPass as a static library\nadd_library(ZetaRenderPass STATIC ${RENDERPASS_SRC})\nadd_dependencies(ZetaRenderPass CompileShaders)\ntarget_include_directories(ZetaRenderPass PUBLIC \"${ZETA_CORE_DIR}\" \n    PRIVATE \"${EXTERNAL_DIR}\" \"${ZETA_RENDER_PASS_DIR}\" \"${EXTERNAL_DIR}/ImGui\" AFTER)\nset_target_properties(ZetaRenderPass PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\n\nsource_group(TREE \"${ZETA_RENDER_PASS_DIR}\" FILES ${RENDERPASS_SRC})\n\n# \n# FSR2\n# \nadd_library(FSR2 INTERFACE)\nset(FSR2_SDK_BIN\n    \"${EXTERNAL_DIR}/FSR2/Lib/ffx_fsr2_api_x64.dll\"\n    \"${EXTERNAL_DIR}/FSR2/Lib/ffx_fsr2_api_dx12_x64.dll\")\n\n# custom command that copies dlls into runtime directory\nCopy(\"${FSR2_SDK_BIN}\" \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/\" CopyFsr2SDKBins)\nadd_dependencies(FSR2 CopyFsr2SDKBins)\n\n# \n# link against all the external libraries\n# \nset(PUBLIC_LIBS ZetaCore)\nset(PRIVATE_LIBS FSR2)\ntarget_link_libraries(ZetaRenderPass PUBLIC ${PUBLIC_LIBS} PRIVATE ${PRIVATE_LIBS})\n"
  },
  {
    "path": "Source/ZetaRenderPass/Common/BSDF.hlsli",
    "content": "// Refs:\n//\n// 1. M. Pharr, W. Jakob, and G. Humphreys, Physically Based Rendering: From theory to implementation, Morgan Kaufmann, 2016.\n// 2. E. Heitz, \"Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs,\" Journal of Computer Graphics Techniques, 2014.\n// 3. B. Walter, S.R. Marschner1, H. Li, K.E. Torrance, \"Microfacet Models for Refraction through Rough Surfaces,\" in EGSR'07, 2007.\n// 4. J. Boksansky, \"Crash Course in BRDF Implementation,\" 2021. [Online]. Available: https://boksajak.github.io/blog/BRDF.\n// 5. S. Lagarde and C. de Rousiers, \"Moving Frostbite to Physically Based Rendering,\" 2014.\n// 6. Autodesk Standard Surface: https://autodesk.github.io/standard-surface/.\n// 7. OpenPBR Surface: https://academysoftwarefoundation.github.io/OpenPBR\n\n#ifndef BSDF_H\n#define BSDF_H\n\n#include \"Sampling.hlsli\"\n#include \"StaticTextureSamplers.hlsli\"\n#include \"../../ZetaCore/Core/Material.h\"\n\n// Conventions:\n//\n//  - All directions point out of the surface\n//  - Suffix o refers to outgoing direction (e.g. wo) - for the first path vertex, the same as eye vector\n//  - Suffix i refers to incident direction (e.g. wi)\n//  - Suffix t refers to transmitted direction\n//  - Normal is assumed to be on the same side as wo. Therefore, it should be reversed for double-sided\n//    surfaces if ray hit the backside.\n//  - \"metallic\" property is binary - a blend of metallic BRDF and dielectric BRDF is not performed.\n//  - alpha = roughness^2\n//  - eta = eta_i / eta_t\n\n// To check against (almost) perfect specular reflection or transmission.\n#define MIN_N_DOT_H_SPECULAR 0.99998\n\n// Maximum (linear) roughness to treat surface as specular. Helps avoid numerical-precision issues.\n#define MAX_ROUGHNESS_SPECULAR 0.04\n#define MAX_ALPHA_SPECULAR 0.0016\n\n// TODO buggy\n// If camera is placed in the air, this can be ignored as the correction factor cancels out between \n// refraction into the medium and refraction out of the medium.\n#define NON_SYMMTERIC_REFRACTION_CORRECTION 0\n\n// Sample from the isotropic VNDF distribution. Should be faster as building a local \n// coordinate system is not needed, but here it's slightly slower.\n#define USE_ISOTROPIC_VNDF 0\n\n#define USE_OREN_NAYAR 1\n#define ENERGY_PRESERVING_OREN_NAYAR 1\n#define APPROXIMATE_EON_MULTISCATTER 1\n\nnamespace BSDF\n{\n    enum class LOBE : uint16_t\n    {\n        DIFFUSE_R = 0,     // Diffuse reflection\n        DIFFUSE_T = 1,     // Diffuse transmission\n        GLOSSY_R = 2,      // Specular or glossy reflection\n        GLOSSY_T = 3,      // Specular or glossy transmission\n        COAT = 4,          // Coating\n        ALL = 5\n    };\n\n    uint16_t LobeToValue(LOBE t)\n    {\n        switch(t)\n        {\n            case LOBE::DIFFUSE_R:\n                return 0;\n            case LOBE::DIFFUSE_T:\n                return 1;\n            case LOBE::GLOSSY_R:\n                return 2;\n            case LOBE::GLOSSY_T:\n                return 3;\n            case LOBE::COAT:\n                return 4;\n            case LOBE::ALL:\n            default:\n                return 5;\n        }\n    }\n\n    LOBE LobeFromValue(uint x)\n    {\n        if(x == 0)\n            return LOBE::DIFFUSE_R;\n        if(x == 1)\n            return LOBE::DIFFUSE_T;\n        if(x == 2)\n            return LOBE::GLOSSY_R;\n        if(x == 3)\n            return LOBE::GLOSSY_T;\n        if(x == 4)\n            return LOBE::COAT;\n\n        return LOBE::ALL;\n    }\n\n    //--------------------------------------------------------------------------------------\n    // Fresnel\n    //--------------------------------------------------------------------------------------\n\n    // Note that F0(eta_i, eta_t) = F0(eta_t, eta_i).\n    // Inputs:\n    //   - eta_i: Refractive index of material travelled through by incident ray\n    //   - eta_t: Refractive index of material travelled through by transmitted ray\n    float DielectricF0(float eta_i, float eta_t)\n    {\n        float f0 = (eta_i - eta_t) / (eta_i + eta_t);\n        return f0 * f0;\n    }\n\n    // eta = eta_i / eta_t\n    float DielectricF0(float eta)\n    {\n        float f0 = (eta - 1) / (eta + 1);\n        return f0 * f0;\n    }\n\n    // whdotwx: \n    //   - When eta_i < eta_t, cosine of angle between half vector and incident ray\n    //   - When eta_t < eta_i, cosine of angle between half vector and transmitted ray\n    float3 FresnelSchlick(float3 F0, float whdotwx)\n    {\n        float tmp = 1.0f - whdotwx;\n        float tmpSq = tmp * tmp;\n        return mad(tmpSq * tmpSq * tmp, 1 - F0, F0);\n    }\n\n    // Specialization for dielectrics where Fresnel is assumed to be wavelength-independent\n    float FresnelSchlick_Dielectric(float F0, float whdotwx)\n    {\n        float tmp = 1.0f - whdotwx;\n        float tmpSq = tmp * tmp;\n        return mad(tmpSq * tmpSq * tmp, 1 - F0, F0);\n    }\n\n    // ndotwi: Cosine of angle between incident vector and normal\n    // eta = eta_i / eta_t (eta_i is IOR of incident medium and eta_t IOR of transmitted medium)\n    float Fresnel_Dielectric(float ndotwi, float eta)\n    {\n        float sinTheta_iSq = saturate(mad(-ndotwi, ndotwi, 1.0f));\n        float cosTheta_tSq = mad(-eta * eta, sinTheta_iSq, 1.0f);\n\n        // TIR\n        if(cosTheta_tSq <= 0)\n            return 1;\n\n        float cosTheta_t = sqrt(cosTheta_tSq);\n        float r_parallel = mad(-eta, cosTheta_t, ndotwi) / mad(eta, cosTheta_t, ndotwi);\n        float r_perp = mad(eta, ndotwi, -cosTheta_t) / mad(eta, ndotwi, cosTheta_t);\n        float2 r = float2(r_parallel, r_perp);\n\n        return 0.5 * dot(r, r);\n    }\n\n    float Fresnel_Dielectric(float ndotwi, float eta, float cosTheta_t)\n    {\n        float r_parallel = mad(-eta, cosTheta_t, ndotwi) / mad(eta, cosTheta_t, ndotwi);\n        float r_perp = mad(eta, ndotwi, -cosTheta_t) / mad(eta, ndotwi, cosTheta_t);\n        float2 r = float2(r_parallel, r_perp);\n\n        return 0.5 * dot(r, r);\n    }\n\n    //--------------------------------------------------------------------------------------\n    // Normal Distribution Function\n    //--------------------------------------------------------------------------------------\n\n    float GGX(float ndotwh, float alphaSq)\n    {\n        float denom = mad(ndotwh * ndotwh, alphaSq - 1.0f, 1.0f);\n        return alphaSq / (PI * denom * denom);\n    }\n\n    //--------------------------------------------------------------------------------------\n    // Smith Shadowing-Masking Functions\n    //--------------------------------------------------------------------------------------\n\n    // G1 is the Smith masking function. Output is in [0, 1].\n    //\n    // theta            = angle between wi or wo with normal\n    // ndotx            = n.wi or n.wo\n    // GGXLambda        = (sqrt(1 + alpha^2 tan^2(theta)) - 1) / 2\n    // G1(GGXLambda)    = 1 / (1 + GGXLambda)\n    float SmithG1(float alphaSq, float ndotx)\n    {\n        float ndotxSq = ndotx * ndotx;\n        float tanThetaSq = (1.0f - ndotxSq) / ndotxSq;\n        return 2.0f / (sqrt(mad(alphaSq, tanThetaSq, 1.0f)) + 1.0f);\n    }\n\n    // G2 is the height-correlated Smith shadowing-masking function defined as:\n    //      1 / (1 + SmithG1_GGX(alpha^2, ndotwo) + SmithG1_GGX(alpha^2, ndotwi))\n    float SmithHeightCorrelatedG2(float alphaSq, float ndotwi, float ndotwo)\n    {\n        float denomWo = ndotwi * sqrt((-ndotwo * alphaSq + ndotwo) * ndotwo + alphaSq);\n        float denomWi = ndotwo * sqrt((-ndotwi * alphaSq + ndotwi) * ndotwi + alphaSq);\n\n        return (2.0f * ndotwo * ndotwi) / (denomWo + denomWi);\n    }\n\n    // G2 can be further optimized for microfacet evaluation since some terms cancel out \n    // as follows:\n    //\n    //  - BRDF: Move 1 / (4.0 * ndotwi * ndotwo) from BRDF to G2 to return\n    //    G2 / (4.0 * ndotwi * ndotwo).\n    //  - BTDF: Move 1 / (ndotwi * ndotwo) from BTDF to G2 to return\n    //    G2 / (ndotwi * ndotwo).\n    template<int n>\n    float SmithHeightCorrelatedG2_Opt(float alphaSq, float ndotwi, float ndotwo)\n    {\n        float denomWo = ndotwi * sqrt(mad(mad(-ndotwo, alphaSq, ndotwo), ndotwo, alphaSq));\n        float denomWi = ndotwo * sqrt(mad(mad(-ndotwi, alphaSq, ndotwi), ndotwi, alphaSq));\n\n        return (0.5f * n) / (denomWo + denomWi);\n    }\n\n    // Ref: E. Heitz and J. Dupuy, \"Implementing a Simple Anisotropic Rough Diffuse \n    // Material with Stochastic Evaluation,\" 2015.\n    float SmithHeightCorrelatedG2OverG1(float alphaSq, float ndotwi, float ndotwo)\n    {\n        float G1wi = SmithG1(alphaSq, ndotwi);\n        float G1wo = SmithG1(alphaSq, ndotwo);\n\n        return G1wi / (G1wi + G1wo - G1wi * G1wo);\n    }\n\n    // Approximates how closely the specular lobe dominant direction is aligned with \n    // the reflected direction. Dominant direction tends to shift away from reflected \n    // direction as roughness or view angle increases (off-specular peak).\n    float MicrofacetBRDFGGXSmithDominantFactor(float ndotwo, float roughness)\n    {\n        float a = 0.298475f * log(39.4115f - 39.0029f * roughness);\n        float f = pow(1 - ndotwo, 10.8649f) * (1 - a) + a;\n\n        return saturate(f);\n    }\n\n    // Approximates the directional-hemispherical reflectance of the microfacet BRDF \n    // with GGX distribution.\n    // Ref: https://github.com/boksajak/brdf/\n    float3 GGXReflectance_Metal(float3 f0, float alpha, float ndotwo)\n    {\n        const float2x2 A = float2x2(0.995367f, -1.38839f,\n            -0.24751f, 1.97442f);\n\n        const float3x3 B = float3x3(1.0f, 2.68132f, 52.366f,\n            16.0932f, -3.98452f, 59.3013f,\n            -5.18731f, 255.259f, 2544.07f);\n\n        const float2x2 C = float2x2(-0.0564526f, 3.82901f,\n            16.91f, -11.0303f);\n\n        const float3x3 D = float3x3(1.0f, 4.11118f, -1.37886f,\n            19.3254f, -28.9947f, 16.9514f,\n            0.545386f, 96.0994f, -79.4492f);\n\n        const float alpha2 = alpha * alpha;\n        const float alpha3 = alpha * alpha2;\n        const float ndotwo2 = ndotwo * ndotwo;\n        const float ndotwo3 = ndotwo * ndotwo2;\n\n        const float E = dot(mul(A, float2(1.0f, ndotwo)), float2(1.0f, alpha));\n        const float F = dot(mul(B, float3(1.0f, ndotwo, ndotwo3)), float3(1.0f, alpha, alpha3));\n        const float G = dot(mul(C, float2(1.0f, ndotwo)), float2(1.0f, alpha));\n        const float H = dot(mul(D, float3(1.0f, ndotwo2, ndotwo3)), float3(1.0f, alpha, alpha3));\n\n        // Turn the bias off for near-zero specular \n        const float biasModifier = saturate(dot(f0, float3(0.333333f, 0.333333f, 0.333333f)) * 50.0f);\n\n        const float bias = max(0.0f, (E / F)) * biasModifier;\n        const float scale = max(0.0f, (G / H));\n\n        return bias + scale * f0;\n    }\n\n    // Approximates the directional-hemispherical reflectance of the microfacet BRDF \n    // with GGX distribution using a precomputed 3D LUT\n    float GGXReflectance_Dielectric(float alpha, float ndotwo, float eta)\n    {\n        Texture3D<float> g_rho = ResourceDescriptorHeap[0];\n        float3 uvw;\n        uvw.x = ndotwo;\n        uvw.y = ((alpha - 0.002025f) / (1.0f - 0.002025f));\n        // Don't interpolate between eta < 1 and eta > 1\n        // TODO For some reason, following causes frame spikes with dxc versions 1.8.2405 and newer\n#if 0\n        if(eta > 1.0f)\n            eta = max(1.1f, eta);\n        else\n            eta = min(0.99f, eta);\n#endif\n        uvw.z = ((eta - 0.5f) / (1.99f - 0.5f));\n        float rho = g_rho.SampleLevel(g_samLinearClamp, uvw, 0);\n        return saturate(rho);\n    }\n\n    //--------------------------------------------------------------------------------------\n    // Lambertian\n    //--------------------------------------------------------------------------------------\n\n    // Note that multiplication by n.wi is not part of the Lambertian BRDF and is included \n    // for convenience.\n    float3 Lambertian(float3 baseColor, float ndotwi)\n    {\n        return ONE_OVER_PI * ndotwi * baseColor;\n    }\n\n    // Lambertain BRDF times n.wi divided by pdf of cosine-weighted hemisphere sampling\n    float3 LambertianOverPdf(float3 baseColor)\n    {\n        return baseColor;\n    }\n\n    //--------------------------------------------------------------------------------------\n    // Microfacet Models\n    //--------------------------------------------------------------------------------------\n\n    // G(theta) = sin(theta) (theta - sin(theta) cos(theta) - 2 / 3)\n    //          + (2 / 3) tan(theta) (1 - sin^3(theta))\n    float OrenNayar_G(float cosTheta)\n    {\n        float sinThetaSq = saturate(1 - cosTheta * cosTheta);\n        float sinTheta = sqrt(sinThetaSq);\n        float theta = Math::ArcCos(cosTheta);\n        float tanTheta = sinTheta / cosTheta;\n        float multiplier_sin = mad(-sinTheta, cosTheta, theta - (2.0f / 3.0f));\n        float multiplier_tan = (2.0f / 3.0f) * mad(-sinTheta, sinThetaSq, 1.0f);\n\n        return sinTheta * multiplier_sin + tanTheta * multiplier_tan;\n    }\n\n    // Ref: J. Portsmouth, P. Kutz, S. Hill, \"EON: A practical energy-preserving rough diffuse BRDF,\" \n    //      Journal of Computer Graphics Techniques, 2024.\n    float E_FON_approx(float cosTheta, float roughness)\n    {\n        float mucomp = 1.0 - cosTheta;\n        float mucomp2 = mucomp * mucomp;\n        float2x2 Gcoeffs = float2x2(0.0571085289, 0.491881867, \n                                    -0.332181442, 0.0714429953);\n        float2 q = mul(Gcoeffs, float2(mucomp, mucomp2));\n        float GoverPi = dot(q, float2(1.0, mucomp2));\n\n        return mad(roughness, GoverPi, 1.0f) / mad(0.287793398f, roughness, 1.0f);\n    }\n\n    // Refs: Improved Oren-Nayar model from https://mimosa-pudica.net/improved-oren-nayar.html, \n    // energy-preserving multi-scattering term from the OpenPBR specs.\n    // \n    // Params:\n    //  - sigma: diffuse roughness\n    //  - rho: base color\n    //  - g_wo: OrenNayar_G(cos \\theta_o)\n    template<bool AccountForMultiScattering>\n    float3 OrenNayar(float3 rho, float sigma, float ndotwo, float ndotwi, float wodotwi,\n        float g_wo)\n    {\n        // Reduces to Lambertian\n        if(sigma == 0)\n            return ONE_OVER_PI * ndotwi * rho;\n\n        float A = 1.0f / mad(0.287793398f, sigma, 1.0f);\n        float B = sigma * A;\n        float s_over_t = mad(-ndotwi, ndotwo, wodotwi);\n        s_over_t = s_over_t > 0 ? s_over_t / max(ndotwi, ndotwo) : s_over_t;\n        float3 f = ONE_OVER_PI * mad(B, s_over_t, A);\n        float3 f_comp = 0;\n\n        if(AccountForMultiScattering)\n        {\n            float avgReflectance = mad(0.0724882111f, B, A);\n            float one_min_avgReflectance = 1 - avgReflectance;\n            float tmp = ONE_OVER_PI * (avgReflectance / one_min_avgReflectance);\n            float3 rho_ms_over_piSq = tmp / mad(-rho, one_min_avgReflectance, 1);\n            rho_ms_over_piSq *= rho;\n\n#if APPROXIMATE_EON_MULTISCATTER == 0\n            float B_over_pi = ONE_OVER_PI * B; \n            float E_wo = mad(B_over_pi, g_wo, A);\n            float E_wi = mad(B_over_pi, OrenNayar_G(ndotwi), A);\n#else\n            float E_wo = g_wo;\n            float E_wi = E_FON_approx(ndotwi, sigma);\n#endif\n            f_comp = (1 - E_wo) * (1 - E_wi) * rho_ms_over_piSq;\n        }\n\n        return ndotwi * (f + f_comp) * rho;\n    }\n\n    // Includes multiplication by n.wi from the rendering equation\n    float3 GGXMicrofacetBRDF(float alpha, float ndotwh, float ndotwo, float ndotwi,\n        float3 fr, bool specular)\n    {\n        if(specular)\n        {\n            // For specular surfaces, total radiance reflected back towards w_o (L_o(w_o)) \n            // should be F * L_i(w_r), where w_r = reflect(-w_o, n). Plugging into the rendering \n            // equation:\n            //      L_o(w_o) = /int f(w_o, w_i) * L_i(w_i) * ndotwi dw_i = F * L_i(w_r).\n            // Now in order for the above to hold, we must have\n            //      f(w_o, w_i) = F * delta(n - wh) / ndotwi\n            // Note that ndotwi cancels out.\n            return (ndotwh >= MIN_N_DOT_H_SPECULAR) * fr;\n        }\n\n        float alphaSq = alpha * alpha;\n        float NDF = GGX(ndotwh, alphaSq);\n        float G2DivDenom = SmithHeightCorrelatedG2_Opt<1>(alphaSq, ndotwi, ndotwo);\n        float f = NDF * G2DivDenom * ndotwi;\n\n        return f * fr;\n    }\n\n    // Given the bijective mapping w_i = f(w_h) where w_h denotes half vector,\n    // the pdfs are related as follows:\n    //      p(w_i) = p(w_h) / |J_f(w_h)|,\n    // where J_f() is the Jacobian of f, from which dw_i = |J_f(w_h)| dw_h.\n    // Putting everything together, p(w_i) = p(w_h) * dw_h / dw_i.\n    float JacobianHalfVecToIncident_Tr(float eta, float whdotwo, float whdotwi)\n    {\n        float denom = mad(whdotwo, 1 / eta, whdotwi);\n        denom *= denom;\n        float dwh_dwi = denom > 0 ? whdotwi / denom : 0;\n\n        return dwh_dwi;\n    }\n\n    // Includes multiplication by n.wi from the rendering equation\n    float GGXMicrofacetBTDF(float alpha, float ndotwh, float ndotwo, float ndotwi,\n        float whdotwo, float whdotwi, float eta, float fr, bool specular)\n    {\n        if(specular)\n        {\n            // For specular surfaces, total radiance reflected back towards w_o (L_o(w_o)) \n            // should be (1 - F) * L_i(w_t), where w_t = refract(-w_o, n). Plugging into the \n            // rendering equation:\n            //      L_o(w_o) = /int f(w_o, w_i) * L_i(w_i) * ndotwi dw_i = (1 - F) * L_i(w_t).\n            // Now in order for the above to hold, we must have\n            //      f(w_o, w_i) = (1 - F) * delta(n - wh) / ndotwi\n            // Note that ndotwi cancels out.\n            float f = ndotwh >= MIN_N_DOT_H_SPECULAR;\n            // f *= 1 / (surface.eta * surface.eta);\n            return f * (1 - fr);\n        }\n\n        float alphaSq = alpha * alpha;\n        float NDF = GGX(ndotwh, alphaSq);\n        float G2opt = SmithHeightCorrelatedG2_Opt<4>(alphaSq, ndotwi, ndotwo);\n\n        float f = NDF * G2opt * whdotwo;\n        float dwh_dwi = JacobianHalfVecToIncident_Tr(eta, whdotwo, whdotwi);\n        f *= dwh_dwi;\n        f *= ndotwi;\n        // f *= 1 / (surface.eta * surface.eta);\n\n        return f * (1 - fr);\n    }\n\n    // Samples half vector wh in a coordinate system where z is aligned with the shading \n    // normal. PDF is GGX(wh) * max(0, whdotwo) * G1(ndotwo) / ndotwo.\n    // Ref: J. Dupuy and A. Benyoub, \"Sampling Visible GGX Normals with Spherical Caps,\" \n    // High Performance Graphics, 2023.\n    float3 SampleGGXVNDF(float3 wo, float alpha_x, float alpha_y, float2 u)\n    {\n        // Section 3.2: transforming the view direction to the hemisphere configuration\n        float3 Vh = normalize(float3(alpha_x * wo.x, alpha_y * wo.y, wo.z));\n\n        // Sample a spherical cap in (-Vh.z, 1]\n        float phi = TWO_PI * u.x;\n        float z = mad((1.0f - u.y), (1.0f + Vh.z), -Vh.z);\n        float sinTheta = sqrt(saturate(1.0f - z * z));\n        float x = sinTheta * cos(phi);\n        float y = sinTheta * sin(phi);\n        float3 c = float3(x, y, z);\n\n        // Compute halfway direction\n        float3 Nh = c + Vh;\n\n        // Section 3.4: transforming the normal back to the ellipsoid configuration\n        float3 Ne = normalize(float3(alpha_x * Nh.x, alpha_y * Nh.y, max(0.0f, Nh.z)));\n\n        return Ne;\n    }\n\n    // Ref: https://auzaiffe.wordpress.com/2024/04/15/vndf-importance-sampling-an-isotropic-distribution/\n    float3 SampleGGXVNDF_Isotropic(float3 wi, float alpha, float3 n, float2 u)\n    {\n        // decompose the floattor in parallel and perpendicular components\n        float3 wi_z = -n * dot(wi, n);\n        float3 wi_xy = wi + wi_z;\n\n        // warp to the hemisphere configuration\n        float3 wiStd = -normalize(alpha * wi_xy + wi_z);\n\n        // sample a spherical cap in (-wiStd.z, 1]\n        float wiStd_z = dot(wiStd, n);\n        float z = 1.0 - u.y * (1.0 + wiStd_z);\n        float sinTheta = sqrt(saturate(1.0f - z * z));\n        float phi = TWO_PI * u.x - PI;\n        float x = sinTheta * cos(phi);\n        float y = sinTheta * sin(phi);\n        float3 cStd = float3(x, y, z);\n\n        // reflect sample to align with normal\n        float3 up = float3(0, 0, 1.000001); // Used for the singularity\n        float3 wr = n + up;\n        float3 c = dot(wr, cStd) * wr / wr.z - cStd;\n\n        // compute halfway direction as standard normal\n        float3 wmStd = c + wiStd;\n        float3 wmStd_z = n * dot(n, wmStd);\n        float3 wmStd_xy = wmStd_z - wmStd;\n\n        // return final normal\n        return normalize(alpha * wmStd_xy + wmStd_z);\n    }\n\n    float3 SampleGGXMicrofacet(float3 wo, float alpha, float3 shadingNormal, float2 u)\n    {\n#if USE_ISOTROPIC_VNDF == 0\n        // Build an orthonormal basis C around the normal such that it points towards +Z.\n        Math::CoordinateSystem onb = Math::CoordinateSystem::Build(shadingNormal);\n\n        // Transform wo from world space to C. M = [b1 b2 n] goes from C to world space, so \n        // we need its inverse. Since M is an orthogonal matrix, its inverse is just its transpose.\n        float3x3 worldToLocal = float3x3(onb.b1, onb.b2, shadingNormal);\n        float3 woLocal = mul(worldToLocal, wo);\n        float3 whLocal = SampleGGXVNDF(woLocal, alpha, alpha, u);\n\n        // Go from local space back to world space.\n        float3 wh = mad(whLocal.x, onb.b1, mad(whLocal.y, onb.b2, whLocal.z * shadingNormal));\n#else\n        float3 wh = SampleGGXVNDF_Isotropic(wo, alpha, shadingNormal, u);\n#endif\n\n        return wh;\n    }\n\n    // D(w_h) (distribution of visible normals) is defined as:\n    //      D(w_h) = GGX(w_h) * max(w_h.w_o, 0) * G1(n.w_o) / n.w_o.\n    // \n    // Note: The following returns D(w_h) / w_o.w_h as w_o.w_h is canceled out\n    // after change of variable from w_h to w_i for reflection. For transmission, \n    // it has to be mutiplied back.\n    float GGXMicrofacetPdf(float alpha, float ndotwh, float ndotwo)\n    {\n        float alphaSq = alpha * alpha;\n        float NDF = GGX(ndotwh, alphaSq);\n        float G1 = SmithG1(alphaSq, ndotwo);\n        float wh_pdf = (NDF * G1) / ndotwo;\n\n        return wh_pdf;\n    }\n\n    //--------------------------------------------------------------------------------------\n    // Utility structure with data needed for BSDF evaluation\n    //--------------------------------------------------------------------------------------\n\n    struct ShadingData\n    {\n        static ShadingData Init()\n        {\n            ShadingData ret;\n            ret.wo = 0;\n            ret.backfacing_wo = false;\n            ret.ndotwo = 0;\n            ret.metallic = false;\n            ret.alpha = 0;\n            ret.baseColor_Fr0_TrCol = 0;\n            ret.eta = DEFAULT_ETA_MAT / ETA_AIR;\n            ret.specTr = false;\n            ret.trDepth = 0;\n            ret.subsurface = 0;\n            ret.g_wo = 0;\n            ret.coat_weight = 0;\n            ret.coat_color = 0;\n            ret.coat_alpha = 0;\n            ret.coat_eta = DEFAULT_ETA_COAT;\n\n            return ret;\n        }\n\n        static ShadingData Init(float3 shadingNormal, float3 wo, bool metallic, float roughness, \n            float3 baseColor, float eta_curr = ETA_AIR, float eta_next = DEFAULT_ETA_MAT, \n            bool specTr = false, half transmissionDepth = 0, half subsurface = 0,\n            float coat_weight = 0, float3 coat_color = 0.0f, float coat_roughness = 0,\n            float eta_coat = DEFAULT_ETA_COAT)\n        {\n            // Coat roughening\n            float2 roughness4 = float2(roughness, coat_roughness);\n            if(coat_weight > 0 && coat_roughness > 0)\n            {\n                roughness4 *= roughness4;\n                roughness4 *= roughness4;\n                float roughness_coated = min(roughness4.x + 2 * roughness4.y, 1);\n                // = roughness_coated^(1 / 4)\n                roughness_coated = rsqrt(rsqrt(roughness_coated));\n                roughness = Math::Lerp(roughness, roughness_coated, coat_weight);\n            }\n\n            ShadingData si;\n\n            si.wo = wo;\n            float ndotwo = dot(shadingNormal, wo);\n            si.backfacing_wo = ndotwo <= 0;\n            // Clamp to a small value to avoid division by zero\n            si.ndotwo = max(ndotwo, 1e-5f);\n\n            si.metallic = metallic;\n            si.alpha = roughness * roughness;\n            si.baseColor_Fr0_TrCol = baseColor;\n            si.specTr = specTr;\n            si.trDepth = transmissionDepth;\n            si.subsurface = subsurface;\n            // TODO surrounding medium is assumed to be air\n            float eta_base = eta_curr == ETA_AIR ? eta_next : eta_curr;\n            float eta_no_coat = eta_next / eta_curr;\n            // To avoid spurious TIR\n            float eta_coated = eta_base >= eta_coat ? eta_base / eta_coat : eta_coat / eta_base;\n            // Adjust eta when surface is coated\n            si.eta = Math::Lerp(eta_no_coat, eta_coated, coat_weight);\n\n            // Precompute as it only depends on wo\n#if APPROXIMATE_EON_MULTISCATTER == 0\n            si.g_wo = !metallic && !specTr ? OrenNayar_G(max(ndotwo, 1e-4f)) : 0;\n#else\n            si.g_wo = !metallic && !specTr ? E_FON_approx(max(ndotwo, 1e-4f), roughness) : 0;\n#endif\n\n            si.coat_weight = coat_weight;\n            si.coat_color = coat_color;\n            si.coat_alpha = coat_roughness * coat_roughness;\n            // TODO surrounding medium is assumed to be air\n            si.coat_eta = eta_curr == ETA_AIR ? eta_coat / ETA_AIR : ETA_AIR / eta_coat;\n\n            return si;\n        }\n\n        void SetWi_Refl(float3 wi, float3 shadingNormal, float3 wh)\n        {\n            this.reflection = true;\n\n            float ndotwi_n = dot(shadingNormal, wi);\n            this.ndotwh = saturate(dot(shadingNormal, wh));\n            this.whdotwo = saturate(dot(wh, wo));\n            this.whdotwi = this.whdotwo;\n\n            bool isInvalid = this.backfacing_wo || this.ndotwh == 0 || this.whdotwo == 0;\n            this.invalid = isInvalid || ndotwi_n <= 0;\n\n            this.ndotwi = max(ndotwi_n, 1e-5f);\n            this.wodotwi = dot(wo, wi);\n        }\n\n        void SetWi_Refl(float3 wi, float3 shadingNormal)\n        {\n            float3 wh = normalize(wi + this.wo);\n            this.SetWi_Refl(wi, shadingNormal, wh);\n        }\n\n        void SetWi_Tr(float3 wi, float3 shadingNormal)\n        {\n            float3 wh = normalize(mad(wi, eta, this.wo));\n            wh = this.eta > 1 ? -wh : wh;\n            this.SetWi_Tr(wi, shadingNormal, wh);\n        }\n\n        void SetWi_Tr(float3 wi, float3 shadingNormal, float3 wh)\n        {\n            this.reflection = false;\n\n            float ndotwi_n = dot(shadingNormal, wi);\n            this.ndotwh = saturate(dot(shadingNormal, wh));\n            this.whdotwo = saturate(dot(wh, wo));\n            this.whdotwi = abs(dot(wh, wi));\n\n            bool isInvalid = this.backfacing_wo || (this.specTr && (this.ndotwh == 0 || this.whdotwo == 0));\n            this.invalid = isInvalid || ndotwi_n >= 0 || !Transmissive() || this.metallic;\n\n            this.ndotwi = max(abs(ndotwi_n), 1e-5f);\n            this.wodotwi = dot(wo, wi);\n        }\n\n        void SetWi(float3 wi, float3 shadingNormal, float3 wh)\n        {\n            float ndotwi_n = dot(shadingNormal, wi);\n            this.reflection = ndotwi_n >= 0;\n\n            // Backfacing half vectors are invalid\n            this.ndotwh = saturate(dot(shadingNormal, wh));\n            this.whdotwo = saturate(dot(wh, wo));\n\n            // reflection - wi and wo have to be on the same side as normal\n            bool backfacing_r = ndotwi_n <= 0;\n            // transmission - wi and wo have to be on the opposite sides w.r.t. normal. Furthermore,\n            // in case of TIR, wi = 0, from which n.wi = 0 and therefore also covered by condition below.\n            bool backfacing_t = ndotwi_n >= 0 || !Transmissive() || this.metallic;\n\n            bool isInvalid = this.backfacing_wo || (this.specTr && (this.ndotwh == 0 || this.whdotwo == 0));\n            this.invalid = isInvalid || (this.reflection && backfacing_r) || (!this.reflection && backfacing_t);\n\n            // Clamp to a small value to avoid division by zero\n            this.ndotwi = max(abs(ndotwi_n), 1e-5f);\n            this.whdotwi = abs(dot(wh, wi));\n            this.wodotwi = dot(wo, wi);\n        }\n\n        float3 SetWi(float3 wi, float3 shadingNormal)\n        {\n            // Transmission happens when wi and wo are on opposite sides of the surface\n            float ndotwi_n = dot(shadingNormal, wi);\n            this.reflection = ndotwi_n >= 0;\n\n            // For reflection:\n            //    wh = normalize(wi + wo)\n            // For transmission: \n            //  - wh = normalize(eta * wi + wo),    eta > 1\n            //  - wh = normalize(-eta * wi - wo),   eta < 1\n            float s = this.reflection ? 1 : this.eta;\n            float3 wh = normalize(mad(wi, s, this.wo));\n#if 0\n            wh = this.reflection || this.eta > 1 ? wh : -wh;\n            // For transmission, the half vector computed above always point towards the \n            // incident material, whereas the convention here is to assume normal is on \n            // the same side as wo.\n            wh = !this.reflection ? -wh : wh;\n#else\n            // Combines two expressions above\n            wh = !this.reflection && this.eta > 1 ? -wh : wh;\n#endif\n            SetWi(wi, shadingNormal, wh);\n\n            return wh;\n        }\n\n        float3 Fresnel(float3 fr0, out bool tir)\n        {\n            float cosTheta_i = this.whdotwo;\n            tir = false;\n\n            // Use Schlick's approximation for metals\n            if(this.metallic)\n                return FresnelSchlick(fr0, cosTheta_i);\n\n            float eta_relative = 1.0f / this.eta;\n            float sinTheta_iSq = saturate(mad(-cosTheta_i, cosTheta_i, 1.0f));\n            float cosTheta_tSq = mad(-eta_relative * eta_relative, sinTheta_iSq, 1.0f);\n\n            // Check for TIR\n            tir = cosTheta_tSq <= 0;\n            if(tir)\n                return 1;\n\n            float cosTheta_t = sqrt(cosTheta_tSq);\n\n            return Fresnel_Dielectric(cosTheta_i, eta_relative, cosTheta_t);\n        }\n\n        float3 Fresnel(out bool tir)\n        {\n            float3 fr0 = this.metallic ? this.baseColor_Fr0_TrCol : \n                DielectricF0(this.eta);\n\n            return Fresnel(fr0, tir);\n        }\n\n        float3 Fresnel()\n        {\n            float3 fr0 = this.metallic ? this.baseColor_Fr0_TrCol : \n                DielectricF0(this.eta);\n            bool unused;\n\n            return Fresnel(fr0, unused);\n        }\n\n        float Fresnel_Coat(out float cosTheta_t)\n        {\n            cosTheta_t = 0;\n            float cosTheta_i = this.whdotwo;\n            float eta_relative = 1.0f / this.coat_eta;\n            float sinTheta_iSq = saturate(mad(-cosTheta_i, cosTheta_i, 1.0f));\n            float cosTheta_tSq = mad(-eta_relative * eta_relative, sinTheta_iSq, 1.0f);\n\n            // Check for TIR\n            if(cosTheta_tSq <= 0)\n                return 1;\n\n            cosTheta_t = sqrt(cosTheta_tSq);\n            float Fr0 = DielectricF0(this.coat_eta);\n            float cosTheta = this.coat_eta > 1 ? cosTheta_i : cosTheta_t;\n\n            return FresnelSchlick_Dielectric(Fr0, cosTheta);\n        }\n\n        void Regularize()\n        {\n            // i.e. to linear roughness in [~0.3, 0.5]\n            this.alpha = this.alpha < 0.25f ? clamp(2.0f * this.alpha, 0.1f, 0.25f) : this.alpha;\n        }\n\n        float3 TransmissionTint()\n        {\n            return trDepth > 0 ? 1 : baseColor_Fr0_TrCol;\n        }\n\n        bool ThinWalled()\n        {\n            return subsurface > 0;\n        }\n\n        bool Transmissive()\n        {\n            return specTr || ThinWalled();\n        }\n\n        bool Coated()\n        {\n            return coat_weight != 0;\n        }\n\n        bool GlossSpecular()\n        {\n            return this.alpha <= MAX_ALPHA_SPECULAR;\n        }\n\n        bool CoatSpecular()\n        {\n            return this.coat_alpha <= MAX_ALPHA_SPECULAR;\n        }\n\n        // Roughness textures actually contain an \"interface\" value of roughness that \n        // is perceptively linear. That value needs to be remapped to the alpha value \n        // that's used in BSDF equations. Literature suggests alpha = roughness^2.\n        float alpha;\n\n        float3 wo;\n        float ndotwi;\n        float ndotwo;\n        float ndotwh;\n        float whdotwi;\n        float whdotwo;\n        float wodotwi;\n        float g_wo;\n        // Union of:\n        //  - Base color for dielectrics\n        //  - Fresnel at normal incidence for metals\n        //  - Transmission color for dielectrics with specular transmission\n        float3 baseColor_Fr0_TrCol;\n        float eta;      // eta_i / eta_t\n        bool specTr;\n        bool metallic;\n        bool backfacing_wo;\n        bool invalid;\n        bool reflection;\n        half trDepth;\n        half subsurface;\n        float coat_weight;\n        float3 coat_color;\n        float coat_alpha;\n        float coat_eta;\n    };\n\n    bool IsLobeValid(ShadingData surface, LOBE lt)\n    {\n        if(lt == LOBE::ALL)\n            return true;\n\n        if(surface.metallic && (lt != LOBE::GLOSSY_R) && (lt != LOBE::COAT))\n            return false;\n\n        if(!surface.specTr && (lt == LOBE::GLOSSY_T))\n            return false;\n\n        if(surface.specTr && (lt == LOBE::DIFFUSE_R))\n            return false;\n\n        if(!surface.ThinWalled() && (lt == LOBE::DIFFUSE_T))\n            return false;\n\n        if(!surface.Coated() && (lt == LOBE::COAT))\n            return false;\n\n        return true;\n    }\n\n    float LobeAlpha(ShadingData surface, LOBE lt)\n    {\n        if(lt == LOBE::GLOSSY_R || lt == LOBE::GLOSSY_T)\n            return surface.alpha;\n        if(lt == LOBE::COAT)\n            return surface.coat_alpha;\n\n        return 1.0f;\n    }\n\n    //--------------------------------------------------------------------------------------\n    // Slabs\n    //--------------------------------------------------------------------------------------\n\n    // Use the same routine for diffuse reflection and diffuse transmission to avoid\n    // a branching code path.\n    // Includes multiplication by n.wi from the rendering equation\n    template<bool EON>\n    float3 EvalDiffuse(ShadingData surface)\n    {\n        float s = surface.subsurface == 0 ? 1 : (float)surface.subsurface * 0.5f;\n\n#if USE_OREN_NAYAR == 1\n        // Diffuse roughness should be a separate parameter, but for now use specular \n        // roughness as existing test scenes don't make use of it and the default value \n        // of 0 would just reduce everything to Lambertian\n        float diffuseRoughness = sqrt(surface.alpha);\n        float3 diffuse = OrenNayar<EON>(surface.baseColor_Fr0_TrCol,\n            diffuseRoughness, surface.ndotwo, surface.ndotwi, surface.wodotwi,\n            surface.g_wo);\n#else\n        float3 diffuse = Lambertian(surface.baseColor_Fr0_TrCol, surface.ndotwi);\n#endif\n\n        return s * diffuse;\n    }\n\n    float3 SampleDiffuse(float3 normal, float2 u, out float pdf)\n    {\n        float3 wiLocal = Sampling::SampleCosineWeightedHemisphere(u, pdf);\n\n        Math::CoordinateSystem onb = Math::CoordinateSystem::Build(normal);\n        float3 wiWorld = mad(wiLocal.x, onb.b1, mad(wiLocal.y, onb.b2, wiLocal.z * normal));\n\n        return wiWorld;\n    }\n\n    float3 SampleDiffuse(float3 normal, float2 u)\n    {\n        float unused;\n        return SampleDiffuse(normal, u, unused);\n    }\n\n    // = Pdf of cosine-weighted hemisphere sampling\n    float DiffusePdf(ShadingData surface)\n    {\n        return surface.ndotwi * ONE_OVER_PI;\n    }\n\n    // Includes multiplication by n.wi from the rendering equation\n    float3 EvalGloss(ShadingData surface, float3 fr)\n    {\n        return GGXMicrofacetBRDF(surface.alpha, surface.ndotwh, surface.ndotwo, \n            surface.ndotwi, fr, surface.GlossSpecular());\n    }\n\n    float3 SampleGloss(ShadingData surface, float3 shadingNormal, float2 u)\n    {\n        // Reminder: reflect(w, n) = reflect(w, -n)\n\n        // Fast path for specular surfaces\n        if(surface.GlossSpecular())\n            return reflect(-surface.wo, shadingNormal);\n\n        // As a convention, microfacet normals point into the upper hemisphere (in the coordinate\n        // system aligned with normal). Since here it's assumed n.wo > 0, this is always true.\n        float3 wh = SampleGGXMicrofacet(surface.wo, surface.alpha, shadingNormal, u);\n\n        // Reflect wo about the plane with normal wh (each microsurface is a perfect mirror)\n        float3 wi = reflect(-surface.wo, wh);\n\n        return wi;\n    }\n\n    // Evaluates distribution of visible normals for reflection\n    //      D(w_h) = GGX(w_h) * max(w_h.w_o, 0) * G1(n.w_o) / n.w_o.\n    //\n    // After correction for change of variable from w_h to w_i, it becomes\n    //      p(wi) = D(w_h) * 1 / (4 * w_h.w_i)\n    //            = GGX(w_h) * G1(n.w_o) / (4 * n.w_o)\n    // (Note that w_h.w_o = w_h.w_i).\n    float GlossPdf(ShadingData surface)\n    {\n        if(surface.GlossSpecular())\n            return (surface.ndotwh >= MIN_N_DOT_H_SPECULAR);\n\n        float pdf = GGXMicrofacetPdf(surface.alpha, surface.ndotwh, surface.ndotwo);\n        return pdf / 4.0f;\n    }\n\n    float EvalTranslucentTr(ShadingData surface, float fr)\n    {\n        return GGXMicrofacetBTDF(surface.alpha, surface.ndotwh, surface.ndotwo, \n            surface.ndotwi, surface.whdotwo, surface.whdotwi, surface.eta, fr, \n            surface.GlossSpecular());\n    }\n\n    float3 SampleTranslucentTr(ShadingData surface, float3 shadingNormal, float2 u)\n    {\n        // Note that: \n        //  - refract(w, n, eta) requires w.n > 0 and ||n|| = 1. Here it's assumed \n        //    n.wo > 0, so this is always true.\n        //  - For sampling, transmitted direction is known (wo) and the goal is to sample \n        //    incident direction (wi). Therefore, refract() should be called with inputs\n        //    for the reverse direction -- eta = 1 / eta.\n\n        // Fast path for specular surfaces\n        if(surface.GlossSpecular())\n            return refract(-surface.wo, shadingNormal, 1 / surface.eta);\n\n        float3 wh = SampleGGXMicrofacet(surface.wo, surface.alpha, shadingNormal, u);\n\n        // Refract wo about the plane with normal wh using Snell's law.\n        float3 wi = refract(-surface.wo, wh, 1 / surface.eta);\n\n        return wi;\n    }\n\n    // Evaluates distribution of visible normals for transmission\n    //      D(w_h) = GGX(w_h) * max(w_h.wo, 0) * G1(n.w_o) / n.w_o.\n    //\n    // After correction for change of variable from wh to wi, it becomes\n    //      p(wi) = D(w_h) * w_h.w_i / (w_h.w_i + w_h.w_o / eta)^2\n    //            = GGX(wh) * w_h.w_o * w_h.w_i * G1(n.w_o) / (n.w_o * w_h.w_i + w_h.w_o / eta)^2)\n    float TranslucentTrPdf(ShadingData surface)\n    {\n        if(surface.GlossSpecular())\n            return (surface.ndotwh >= MIN_N_DOT_H_SPECULAR);\n\n        float pdf = GGXMicrofacetPdf(surface.alpha, surface.ndotwh, surface.ndotwo);\n        pdf *= surface.whdotwo;\n\n        float dwh_dwi = JacobianHalfVecToIncident_Tr(surface.eta, surface.whdotwo,\n            surface.whdotwi);\n        pdf *= dwh_dwi;\n\n        return pdf;\n    }\n\n    float EvalCoat(ShadingData surface, float Fr)\n    {\n        return surface.coat_weight * GGXMicrofacetBRDF(surface.coat_alpha, surface.ndotwh, \n            surface.ndotwo, surface.ndotwi, Fr, surface.CoatSpecular()).x;\n    }\n\n    float3 SampleCoat(ShadingData surface, float3 shadingNormal, float2 u)\n    {\n        float3 wh = surface.CoatSpecular() ? shadingNormal :\n            SampleGGXMicrofacet(surface.wo, surface.coat_alpha, shadingNormal, u);\n        float3 wi = reflect(-surface.wo, wh);\n\n        return wi;\n    }\n\n    float CoatPdf(ShadingData surface)\n    {\n        if(surface.CoatSpecular())\n            return (surface.ndotwh >= MIN_N_DOT_H_SPECULAR);\n\n        float pdf = GGXMicrofacetPdf(surface.coat_alpha, surface.ndotwh, surface.ndotwo);\n        return pdf / 4.0f;\n    }\n\n    // Includes multiplication by n.wi from the rendering equation\n    float3 GlossOverPdf(ShadingData surface, float3 fr)\n    {\n        if(surface.GlossSpecular())\n        {\n            // Note that ndotwi cancels out.\n            return fr;\n        }\n\n        // When VNDF is used for sampling the incident direction (wi), the expression \n        //        f * cos(theta) / Pdf(wi)\n        // is simplified to Fr * G2 / G1.\n        float alphaSq = surface.alpha * surface.alpha;\n        return SmithHeightCorrelatedG2OverG1(alphaSq, surface.ndotwi, surface.ndotwo) * \n            fr;\n    }\n\n    // Includes multiplication by n.wi from the rendering equation\n    float3 TranslucentTrOverPdf(ShadingData surface, float fr)\n    {\n        if(surface.GlossSpecular())\n        {\n            // Note that ndotwi cancels out.\n            return (1 - fr) * surface.TransmissionTint();\n        }\n\n        // When VNDF is used for sampling the incident direction (wi), the expression \n        //        f * cos(theta) / Pdf(wi)\n        // is simplified to (1 - Fr) * G2 / G1.\n        float alphaSq = surface.alpha * surface.alpha;\n        return SmithHeightCorrelatedG2OverG1(alphaSq, surface.ndotwi, surface.ndotwo) * \n            (1 - fr) * surface.TransmissionTint();\n    }\n\n    float3 BaseWeight(ShadingData surface)\n    {\n        float3 base_weight = 1;\n        if(surface.Coated())\n        {\n            float cosTheta_t;\n            float Fr_coat = surface.Fresnel_Coat(cosTheta_t);\n            bool tir_c = cosTheta_t <= 0;\n\n            if(tir_c)\n                return 0;\n\n            float reflectance_c = surface.CoatSpecular() ? Fr_coat : \n                GGXReflectance_Dielectric(surface.coat_alpha, surface.ndotwo, surface.coat_eta);\n\n            // View-dependent absorption\n            float c = 0.5f / cosTheta_t + 0.5f / surface.whdotwo;\n            // = coat_color^c\n            float3 coat_tr = exp(c * log(surface.coat_color));\n\n            // f = mix(base, layer(base, coat), coat_weight)\n            base_weight = Math::Lerp(1.0f.xxx, (1 - reflectance_c) * coat_tr, surface.coat_weight);\n        }\n\n        return base_weight;\n    }\n\n    float3 TransmittanceToDielectricBaseTr(ShadingData surface)\n    {\n        float3 base_weight = BaseWeight(surface);\n        // For specular, 1 - reflectance becomes 1 - Fr, which is accounted for separately\n        float reflectance_g = surface.GlossSpecular() ? 0 : \n            GGXReflectance_Dielectric(surface.alpha, surface.ndotwo, surface.eta);\n\n        return (1 - reflectance_g) * base_weight;\n    }\n\n    float3 DielectricBaseSpecularTr(ShadingData surface, float Fr_g)\n    {\n        if(surface.invalid || !surface.specTr)\n            return 0;\n\n        float3 transmittance = TransmittanceToDielectricBaseTr(surface);\n        float glossyTr = EvalTranslucentTr(surface, Fr_g);\n\n        return glossyTr * surface.TransmissionTint() * transmittance;\n    }\n\n    float3 DielectricBaseDiffuseTr(ShadingData surface, float Fr_g)\n    {\n        if(surface.invalid)\n            return 0;\n\n        float3 base_weight = BaseWeight(surface);\n        float reflectance_g = surface.GlossSpecular() ? Fr_g : \n            GGXReflectance_Dielectric(surface.alpha, surface.ndotwo, surface.eta);\n\n        return (1 - reflectance_g) * BSDF::EvalDiffuse<false>(surface) * base_weight;\n    }\n\n    //--------------------------------------------------------------------------------------\n    // Surface Shader\n    //--------------------------------------------------------------------------------------\n\n    struct BSDFEval\n    {\n        static BSDFEval Init()\n        {\n            BSDFEval ret;\n            ret.f = 0;\n            ret.Fr_g = 0;\n            ret.tir = false;\n\n            return ret;\n        }\n\n        float3 f;\n        float3 Fr_g;\n        bool tir;\n    };\n\n    // Includes multiplication by n.wi from the rendering equation\n    BSDFEval Unified(ShadingData surface)\n    {\n        BSDFEval ret = BSDFEval::Init();\n        if(surface.invalid)\n            return ret;\n\n        // Coat\n        float3 base_weight = 1;\n        if(surface.Coated())\n        {\n            float cosThetaT_o;\n            float Fr_coat = surface.Fresnel_Coat(cosThetaT_o);\n            bool tir_c = cosThetaT_o <= 0;\n\n            if(!surface.reflection && tir_c)\n                return ret;\n\n            if(surface.reflection)\n            {\n                ret.f = EvalCoat(surface, Fr_coat);\n                if(tir_c)\n                    return ret;\n            }\n\n            float reflectance_c = surface.CoatSpecular() ? Fr_coat : \n                GGXReflectance_Dielectric(surface.coat_alpha, surface.ndotwo, surface.coat_eta);\n\n            // View-dependent absorption\n            float c = 1.0f / cosThetaT_o;\n            // Note: Incorrect for transmission as wh.wo != wh.wi. Additionally needs \n            // the transmitted angle of incident ray using the relative IOR of coat \n            // layer. \n#if 0\n            if(!surface.reflection)\n            {\n                float sinThetaISq = saturate(mad(-this.whdotwi, this.whdotwi, 1.0f));\n                float cosThetaTSq = saturate(mad(-this.coat_eta * this.coat_eta, sinThetaISq, 1.0f));\n                float cosThetaT_i = sqrt(cosThetaTSq);\n                c = 0.5f * c + (0.5f / cosThetaT_i);\n            }\n#endif\n            // = coat_color^c\n            float3 coat_tr = exp(c * log(surface.coat_color));\n\n            // f = mix(base, layer(base, coat), coat_weight)\n            base_weight = Math::Lerp(1.0f.xxx, (1 - reflectance_c) * coat_tr, surface.coat_weight);\n        }\n\n        float3 fr0 = surface.metallic ? surface.baseColor_Fr0_TrCol : \n            DielectricF0(surface.eta);\n        ret.Fr_g = surface.Fresnel(fr0, ret.tir);\n\n        // = Metal = reflection from Translucent Base\n        float3 glossyRefl = EvalGloss(surface, ret.Fr_g);\n\n        // Metal or TIR\n        if(surface.metallic || ret.tir)\n        {\n            ret.f += base_weight * glossyRefl;\n            return ret;\n        }\n\n        float reflectance_g = surface.GlossSpecular() ? ret.Fr_g.x : \n            GGXReflectance_Dielectric(surface.alpha, surface.ndotwo, surface.eta);\n\n        // Opaque Base, possibly in thin walled mode\n        if(!surface.specTr)\n        {\n            float3 diffuse = EvalDiffuse<ENERGY_PRESERVING_OREN_NAYAR>(surface);\n\n            // For diffuse transmission, all other lobes are excluded\n            ret.f += base_weight * ((1 - reflectance_g) * diffuse + \n                glossyRefl * surface.reflection);\n\n            return ret;\n        }\n\n        // Translucent Base\n        if(surface.reflection)\n        {\n            ret.f += glossyRefl * base_weight;\n            return ret;\n        }\n\n        // For specular, (1 - Fresnel) factor is already accounted for\n        reflectance_g = surface.GlossSpecular() ? 0 : reflectance_g;\n        float glossyTr = EvalTranslucentTr(surface, ret.Fr_g.x);\n        ret.f = ((1 - reflectance_g) * glossyTr * surface.TransmissionTint()) * base_weight;\n\n        return ret;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/Common/BSDFSampling.hlsli",
    "content": "#ifndef BSDF_SAMPLING_H\n#define BSDF_SAMPLING_H\n\n#include \"BSDF.hlsli\"\n#include \"RT.hlsli\"\n\nnamespace BSDF\n{\n    //--------------------------------------------------------------------------------------\n    // BSDF sampling\n    //--------------------------------------------------------------------------------------\n\n    struct BSDFSample\n    {\n        static BSDFSample Init()\n        {\n            BSDFSample ret;\n            ret.bsdfOverPdf = 0;\n            ret.f = 0;\n            ret.pdf = 0;\n\n            return ret;\n        }\n\n        float3 wi;\n        BSDF::LOBE lobe;\n        // Joint pdf of sampling the lobe and direction \n        float pdf;\n        float3 bsdfOverPdf;\n        float3 f;\n    };\n\n    struct BSDFSamplerEval\n    {\n        static BSDFSamplerEval Init()\n        {\n            BSDFSamplerEval ret;\n            ret.bsdfOverPdf = 0;\n            ret.pdf = 0;\n            ret.f = 0;\n\n            return ret;\n        }\n\n        // Joint pdf of sampling the lobe and direction \n        float pdf;\n        float3 bsdfOverPdf;\n        float3 f;\n    };\n\n    struct NoOp \n    {\n        float3 operator()(float3 w)\n        {\n            return 1.0f;\n        }\n    };\n\n    template<typename Func>\n    BSDFSample SampleBSDF_NoDiffuse(float3 normal, ShadingData surface, float2 u_c, \n        float2 u_g, float u_wrs_0, float u_wrs_1, Func func)\n    {\n        BSDFSample ret;\n        float pdf_base = 1;\n\n        if(surface.Coated())\n        {\n            float reflectance_c = GGXReflectance_Dielectric(surface.coat_alpha, \n                surface.ndotwo, surface.coat_eta);\n            float pdf_coat = reflectance_c * surface.coat_weight;\n            pdf_base = 1 - pdf_coat;\n\n            if(u_wrs_0 < pdf_coat)\n            {\n                float3 wi_c = BSDF::SampleCoat(surface, normal, u_c);\n                surface.SetWi_Refl(wi_c, normal);\n\n                BSDFEval eval = BSDF::Unified(surface);\n                float3 target = eval.f * func(wi_c);\n\n                ret.wi = wi_c;\n                ret.lobe = BSDF::LOBE::COAT;\n                ret.f = target;\n                ret.pdf = BSDF::CoatPdf(surface) * pdf_coat;\n                ret.bsdfOverPdf = ret.f / ret.pdf;\n\n                return ret;\n            }\n        }\n\n        float3 wh = surface.GlossSpecular() ? normal : BSDF::SampleGGXMicrofacet(surface.wo, \n            surface.alpha, normal, u_g);\n        float3 wi_r = reflect(-surface.wo, wh);\n        surface.SetWi_Refl(wi_r, normal, wh);\n        float wh_pdf = BSDF::GGXMicrofacetPdf(surface.alpha, surface.ndotwh, surface.ndotwo);\n\n        ret.wi = wi_r;\n        ret.lobe = BSDF::LOBE::GLOSSY_R;\n        // Account for change of density from half vector to incident vector\n        ret.pdf = surface.GlossSpecular() ? 1 : wh_pdf / 4.0f;\n        ret.pdf *= pdf_base;\n\n        BSDFEval eval = BSDF::Unified(surface);\n        float3 func_r = func(wi_r);\n        ret.f = eval.f * func_r;\n        ret.bsdfOverPdf = ret.f / ret.pdf;\n\n        // TIR is for both coat and gloss layers\n        if(surface.metallic || !surface.specTr || eval.tir)\n            return ret;\n\n        // Transmissive dielectric\n        float3 wi_t = refract(-surface.wo, wh, 1 / surface.eta);\n        float3 func_t = func(wi_t);\n        float p_r = eval.Fr_g.x * Math::Luminance(func_r);\n        p_r = p_r / (p_r + (1 - eval.Fr_g.x) * Math::Luminance(func_t));\n\n        // Use Fresnel to decide between reflection and transmission\n        if (u_wrs_1 < p_r)\n        {\n            ret.bsdfOverPdf /= p_r;\n            ret.pdf *= p_r;\n        }\n        else\n        {\n            surface.SetWi_Tr(wi_t, normal, wh);\n            ret.pdf = (1 - p_r) * pdf_base;\n\n            if(!surface.GlossSpecular())\n            {\n                ret.pdf *= wh_pdf * surface.whdotwo;\n\n                // Account for change of density from half vector to incident vector\n                float dwh_dwi = BSDF::JacobianHalfVecToIncident_Tr(surface.eta, \n                    surface.whdotwo, surface.whdotwi);\n                ret.pdf *= dwh_dwi;\n            }\n\n            // Corner case: Fresnel returned no TIR, so sampling transmission is possible,\n            // yet refract() detected TIR and returned 0 (possibly due to floating-point \n            // errors). In that case, surface.invalid becomes true, causing bsdf to evaluate \n            // to 0 and the path-tracing loop is terminated.\n\n            ret.f = BSDF::DielectricBaseSpecularTr(surface, eval.Fr_g.x) * func_t;\n            // if code reached here, pdf should > 0 unless dwh_dwi = 0\n            ret.bsdfOverPdf = ret.pdf > 0 ? ret.f / ret.pdf : 0;\n            ret.wi = wi_t;\n            ret.lobe = BSDF::LOBE::GLOSSY_T;\n        }\n\n        return ret;\n    }\n\n    // Either surface is translucent or diffuse lobe is intentionally ignored\n    BSDFSample SampleBSDF_NoDiffuse(float3 normal, ShadingData surface, inout RNG rng)\n    {\n        float2 u_c = rng.Uniform2D();\n        float2 u_g = rng.Uniform2D();\n        float u_wrs_0 = rng.Uniform();\n        float u_wrs_1 = rng.Uniform();\n        NoOp noop;\n\n        return SampleBSDF_NoDiffuse<NoOp>(normal, surface, u_c, u_g, u_wrs_0, u_wrs_1, \n            noop);\n    }\n\n    template<typename Func>\n    BSDFSample SampleBSDF_NoDiffuse(float3 normal, ShadingData surface, Func func, \n        inout RNG rng)\n    {\n        float2 u_c = rng.Uniform2D();\n        float2 u_g = rng.Uniform2D();\n        float u_wrs_0 = rng.Uniform();\n        float u_wrs_1 = rng.Uniform();\n\n        return SampleBSDF_NoDiffuse(normal, surface, u_c, u_g, u_wrs_0, u_wrs_1, \n            func);\n    }\n\n    // For surfaces without specular transmission\n    template<typename Func>\n    BSDFSample SampleBSDF_NoSpecTr(float3 normal, ShadingData surface, float2 u_coat, float2 u_g, \n        float2 u_d, float u_wrs_g, float u_wrs_dr, float u_wrs_dt, Func func)\n    {\n        BSDFSample ret = BSDFSample::Init();\n\n        // Streaming RIS using weighted reservoir sampling to sample aggregate BSDF\n        float w_sum = 0;\n        float3 target = 0;\n\n        // Sample coat layer\n        if(surface.Coated())\n        {\n            float3 wi_c = BSDF::SampleCoat(surface, normal, u_coat);\n            surface.SetWi_Refl(wi_c, normal);\n\n            BSDFEval eval = BSDF::Unified(surface);\n            target = eval.f * func(wi_c);\n\n            ret.wi = wi_c;\n            ret.lobe = BSDF::LOBE::COAT;\n            ret.f = target;\n\n            float pdf_c = BSDF::CoatPdf(surface);\n            float pdf_g = BSDF::GlossPdf(surface);\n            float pdf_d = !surface.metallic ? BSDF::DiffusePdf(surface) : 0;\n            float targetLum_c = Math::Luminance(target);\n            w_sum = RT::BalanceHeuristic3(pdf_c, pdf_g, pdf_d, targetLum_c);\n        }\n\n        // Specular/glossy reflection\n        {\n            float3 wi_g = BSDF::SampleGloss(surface, normal, u_g);\n            surface.SetWi_Refl(wi_g, normal);\n\n            BSDFEval eval = Unified(surface);\n            float3 target_g = eval.f * func(wi_g);\n            \n            float pdf_g = BSDF::GlossPdf(surface);\n            float pdf_d = !surface.metallic && !eval.tir ? BSDF::DiffusePdf(surface) : 0;\n            float pdf_c = surface.Coated() ? BSDF::CoatPdf(surface) : 0;\n            float w_g = RT::BalanceHeuristic3(pdf_g, pdf_d, pdf_c, Math::Luminance(target_g));\n            w_sum += w_g;\n\n            if ((w_sum > 0) && (u_wrs_g < (w_g / w_sum)))\n            {\n                target = target_g;\n\n                ret.wi = wi_g;\n                ret.lobe = BSDF::LOBE::GLOSSY_R;\n                ret.f = target_g;\n            }\n        }\n\n        // Metals don't have transmission or diffuse lobes\n        if(!surface.metallic)\n        {\n            float pdf_d;\n            float3 wi_d = BSDF::SampleDiffuse(normal, u_d, pdf_d);\n            float Fr_g;\n\n            // Diffuse reflection\n            {\n                surface.SetWi_Refl(wi_d, normal);\n\n                BSDFEval eval = Unified(surface);\n                float3 target_dr = eval.f * func(wi_d);\n                Fr_g = eval.Fr_g.x;\n\n                float pdf_g = BSDF::GlossPdf(surface);\n                float pdf_c = surface.Coated() ? BSDF::CoatPdf(surface) : 0;\n                float w_dr = RT::BalanceHeuristic3(pdf_d, pdf_g, pdf_c, Math::Luminance(target_dr));\n                w_sum += w_dr;\n\n                if ((w_sum > 0) && (u_wrs_dr < (w_dr / w_sum)))\n                {\n                    target = target_dr;\n\n                    ret.wi = wi_d;\n                    ret.lobe = BSDF::LOBE::DIFFUSE_R;\n                    ret.f = target_dr;\n                }\n            }\n\n            // Diffuse transmission\n            if(surface.ThinWalled())\n            {\n                float3 wi_dt = -wi_d;\n\n                // Notes: \n                // 1. |n.wi_dt| = |n.wi_dr| and following computation happens right after \n                //    diffuse reflection above, another SetWi*() call isn't needed. \n                // 2. SetWi*() calls don't change reflectance.\n                float3 target_dt = BSDF::DielectricBaseDiffuseTr(surface, Fr_g);\n                target_dt *= func(wi_dt);\n\n                float w_dt = Math::Luminance(target_dt) / pdf_d;\n                w_sum += w_dt;\n\n                if ((w_sum > 0) && (u_wrs_dt < (w_dt / w_sum)))\n                {\n                    target = target_dt;\n\n                    ret.wi = wi_dt;\n                    ret.lobe = BSDF::LOBE::DIFFUSE_T;\n                    ret.f = target_dt;\n                }\n            }\n        }\n\n        float targetLum = Math::Luminance(target);\n        ret.bsdfOverPdf = targetLum > 0 ? target * w_sum / targetLum : 0;\n        ret.pdf = w_sum > 0 ? targetLum / w_sum : 0;\n\n        return ret;\n    }\n\n    template<typename Func>\n    BSDFSample SampleBSDF(float3 normal, ShadingData surface, Func func, inout RNG rng)\n    {\n        float2 u_c = rng.Uniform2D();\n        float2 u_g = rng.Uniform2D();\n        float2 u_d = rng.Uniform2D();\n        float u_wrs_0 = rng.Uniform();\n        float u_wrs_1 = rng.Uniform();\n        float u_wrs_2 = rng.Uniform();\n\n        if(!surface.specTr)\n        {\n            return SampleBSDF_NoSpecTr(normal, surface, u_c, u_g, u_d, u_wrs_0, \n                u_wrs_1, u_wrs_2, func);\n        }\n\n        return BSDF::SampleBSDF_NoDiffuse(normal, surface, u_c, u_g, u_wrs_0, \n            u_wrs_1, func);\n    }\n\n    BSDFSample SampleBSDF(float3 normal, ShadingData surface, inout RNG rng)\n    {\n        // Make sure the number of random numbers used in all code paths is the same. Since\n        // .UniformX() calls change the internal state of rng, they're not compiled out.\n        float2 u_c = rng.Uniform2D();\n        float2 u_g = rng.Uniform2D();\n        float2 u_d = rng.Uniform2D();\n        float u_wrs_0 = rng.Uniform();\n        float u_wrs_1 = rng.Uniform();\n        float u_wrs_2 = rng.Uniform();\n        NoOp noop;\n\n        if(!surface.specTr)\n        {\n            return SampleBSDF_NoSpecTr(normal, surface, u_c, u_g, u_d, u_wrs_0, \n                u_wrs_1, u_wrs_2, noop);\n        }\n\n        return BSDF::SampleBSDF_NoDiffuse(normal, surface, u_c, u_g, u_wrs_0, \n            u_wrs_1, noop);\n    }\n\n    template<typename Func>\n    BSDFSamplerEval EvalBSDFSampler_NoSpecTr(float3 normal, BSDF::ShadingData surface, float3 wi, \n        BSDF::LOBE lobe, float2 u_c, float2 u_g, float2 u_d, Func func)\n    {\n        BSDFSamplerEval ret;\n        const float3 targetScale_z = func(wi);\n        float w_sum = 0;\n        float3 target = 0;\n\n        // Coat\n        if(surface.Coated())\n        {\n            const bool isZ_c = lobe == BSDF::LOBE::COAT;\n            const float3 wi_c = isZ_c ? wi : BSDF::SampleCoat(surface, normal, u_c);\n            surface.SetWi_Refl(wi_c, normal);\n\n            const float3 targetScale_c = isZ_c ? targetScale_z : func(wi_c);\n            target = BSDF::Unified(surface).f * targetScale_c;\n            const float targetLum_c = Math::Luminance(target);\n\n            const float pdf_c = BSDF::CoatPdf(surface);\n            const float pdf_g = BSDF::GlossPdf(surface);\n            const float pdf_d = !surface.metallic ? BSDF::DiffusePdf(surface) : 0;\n            w_sum = RT::BalanceHeuristic3(pdf_c, pdf_g, pdf_d, targetLum_c);\n        }\n\n        // Specular/glossy reflection\n        {\n            const bool isZ_g = lobe == BSDF::LOBE::GLOSSY_R;\n            const float3 wi_g = isZ_g ? wi : BSDF::SampleGloss(surface, normal, u_g);\n            surface.SetWi_Refl(wi_g, normal);\n\n            const float3 targetScale_g = isZ_g ? targetScale_z : func(wi_g);\n            const float3 target_g = BSDF::Unified(surface).f * targetScale_g;\n            const float targetLum_g = Math::Luminance(target_g);\n\n            const float pdf_g = BSDF::GlossPdf(surface);\n            const float pdf_d = !surface.metallic ? BSDF::DiffusePdf(surface) : 0;\n            const float pdf_c = surface.Coated() ? BSDF::CoatPdf(surface) : 0;\n            w_sum += RT::BalanceHeuristic3(pdf_g, pdf_d, pdf_c, targetLum_g);\n            target = isZ_g ? target_g : target;\n        }\n\n        if(!surface.metallic)\n        {\n            float3 w_d = BSDF::SampleDiffuse(normal, u_d);\n            float Fr_g;\n\n            // Diffuse reflection\n            {\n                const bool isZ_dr = lobe == BSDF::LOBE::DIFFUSE_R;\n                const float3 wi_d = isZ_dr ? wi : w_d;\n                surface.SetWi_Refl(wi_d, normal);\n\n                const float3 targetScale_dr = isZ_dr ? targetScale_z : func(wi_d);\n                BSDFEval eval = BSDF::Unified(surface);\n                const float3 target_dr = eval.f * targetScale_dr;\n                Fr_g = eval.Fr_g.x;\n                const float targetLum_dr = Math::Luminance(target_dr);\n\n                const float pdf_d = BSDF::DiffusePdf(surface);\n                const float pdf_g = BSDF::GlossPdf(surface);\n                const float pdf_c = surface.Coated() ? BSDF::CoatPdf(surface) : 0;\n                w_sum += RT::BalanceHeuristic3(pdf_d, pdf_g, pdf_c, targetLum_dr);\n                target = isZ_dr ? target_dr : target;\n            }\n\n            if(surface.ThinWalled())\n            {\n                const bool isZ_dt = lobe == BSDF::LOBE::DIFFUSE_T;\n                const float3 wi_dt = isZ_dt ? wi : -w_d;\n\n                const float3 targetScale_dt = isZ_dt ? targetScale_z : func(wi_dt);\n                const float3 target_dt = BSDF::DielectricBaseDiffuseTr(surface, Fr_g) * targetScale_dt;\n                const float targetLum_dt = Math::Luminance(target_dt);\n\n                const float pdf_d = BSDF::DiffusePdf(surface);\n                w_sum += targetLum_dt / pdf_d;\n                target = isZ_dt ? target_dt : target;\n            }\n        }\n\n        float targetLum = Math::Luminance(target);\n        ret.bsdfOverPdf = targetLum > 0 ? target * w_sum / targetLum : 0;\n        ret.pdf = w_sum > 0 ? targetLum / w_sum : 0;\n        ret.f = target;\n\n        return ret;\n    }\n\n    template<typename Func>\n    BSDFSamplerEval EvalBSDFSampler_NoDiffuse(float3 normal, BSDF::ShadingData surface, float3 wi, \n        BSDF::LOBE lobe, float unused, Func func)\n    {\n        float3 wh = surface.SetWi(wi, normal);\n        BSDFEval eval = BSDF::Unified(surface);\n        const float3 targetScale = func(wi);\n        float pdf_base = 1;\n\n        BSDFSamplerEval ret;\n        ret.f = eval.f * targetScale;\n\n        if(surface.Coated())\n        {\n            float reflectance_c = GGXReflectance_Dielectric(surface.coat_alpha, \n                surface.ndotwo, surface.coat_eta);\n            float pdf_coat = reflectance_c * surface.coat_weight;\n            pdf_base = 1 - pdf_coat;\n\n            if(lobe == BSDF::LOBE::COAT)\n            {\n                ret.pdf = BSDF::CoatPdf(surface) * pdf_coat;\n                ret.bsdfOverPdf = ret.f / ret.pdf;\n\n                return ret;\n            }\n        }\n\n        const float wh_pdf = BSDF::GGXMicrofacetPdf(surface.alpha, surface.ndotwh, surface.ndotwo);\n        ret.pdf = !surface.GlossSpecular() ? wh_pdf / 4.0f : surface.ndotwh >= MIN_N_DOT_H_SPECULAR;\n        ret.pdf *= pdf_base;\n        ret.bsdfOverPdf = ret.f / ret.pdf;\n\n        if(surface.metallic || !surface.specTr || eval.tir)\n            return ret;\n\n        const float3 wi_other = lobe == BSDF::LOBE::GLOSSY_T ? \n            reflect(-surface.wo, wh) :\n            refract(-surface.wo, wh, 1 / surface.eta);\n        float3 targetScaleOther = func(wi_other);\n        float targetScaleLum = Math::Luminance(targetScale);\n        float targetScaleOtherLum = Math::Luminance(targetScaleOther);\n\n        float p_r = eval.Fr_g.x * (lobe == BSDF::LOBE::GLOSSY_R ? targetScaleLum : targetScaleOtherLum);\n        p_r = p_r / (p_r + (1 - eval.Fr_g.x) * (lobe == BSDF::LOBE::GLOSSY_R ? targetScaleOtherLum : targetScaleLum));\n\n        if(lobe == BSDF::LOBE::GLOSSY_R)\n        {\n            ret.bsdfOverPdf /= p_r;\n            ret.pdf *= p_r;\n\n            return ret;\n        }\n\n        ret.bsdfOverPdf = !surface.invalid * !surface.reflection * \n            BSDF::TranslucentTrOverPdf(surface, eval.Fr_g.x);\n        ret.bsdfOverPdf *= BSDF::TransmittanceToDielectricBaseTr(surface);\n        ret.bsdfOverPdf *= targetScale;\n        ret.bsdfOverPdf /= pdf_base;\n        ret.bsdfOverPdf /= (1 - p_r);\n        ret.pdf = 1 - p_r;\n        ret.pdf *= surface.GlossSpecular() ? surface.ndotwh >= MIN_N_DOT_H_SPECULAR : wh_pdf * surface.whdotwo;\n        ret.pdf *= pdf_base;\n\n        if(!surface.GlossSpecular())\n        {\n            float dwh_dwi = BSDF::JacobianHalfVecToIncident_Tr(surface.eta, \n                surface.whdotwo, surface.whdotwi);\n            ret.pdf *= dwh_dwi;\n        }\n\n        return ret;\n    }\n\n    template<typename Func>\n    BSDFSamplerEval EvalBSDFSampler_NoDiffuse(float3 normal, BSDF::ShadingData surface, float3 wi, \n        BSDF::LOBE lobe, Func func, inout RNG rng)\n    {\n        float2 u_c = rng.Uniform2D();\n        float2 u_g = rng.Uniform2D();\n        float u_wrs_0 = rng.Uniform();\n        float u_wrs_1 = rng.Uniform();\n\n        return EvalBSDFSampler_NoDiffuse(normal, surface, wi, lobe, u_wrs_0, func);\n    }\n\n    BSDFSamplerEval EvalBSDFSampler_NoDiffuse(float3 normal, BSDF::ShadingData surface, float3 wi, \n        BSDF::LOBE lobe, inout RNG rng)\n    {\n        float2 u_c = rng.Uniform2D();\n        float2 u_g = rng.Uniform2D();\n        float u_wrs_0 = rng.Uniform();\n        float u_wrs_1 = rng.Uniform();\n        NoOp noop;\n\n        // toto\n        return EvalBSDFSampler_NoDiffuse(normal, surface, wi, lobe, u_wrs_0, noop);\n    }\n\n    // Mirrors the computation in SampleBSDF() to return joint probability of sampling lobe l_z \n    // and direction wi given the specific random numbers u_0, ..., u_n.\n    template<typename Func>\n    BSDFSamplerEval EvalBSDFSampler(float3 normal, BSDF::ShadingData surface, float3 wi, \n        BSDF::LOBE lobe, Func func, inout RNG rng)\n    {\n        float2 u_c = rng.Uniform2D();\n        float2 u_g = rng.Uniform2D();\n        float2 u_d = rng.Uniform2D();\n        float u_wrs_0 = rng.Uniform();\n        float u_wrs_1 = rng.Uniform();\n        float u_wrs_2 = rng.Uniform();\n\n        if(!surface.specTr)\n            return EvalBSDFSampler_NoSpecTr(normal, surface, wi, lobe, u_c, u_g, u_d, func);\n\n        return EvalBSDFSampler_NoDiffuse(normal, surface, wi, lobe, u_wrs_1, func);\n    }    \n    \n    BSDFSamplerEval EvalBSDFSampler(float3 normal, BSDF::ShadingData surface, float3 wi, \n        BSDF::LOBE lobe, inout RNG rng)\n    {\n        float2 u_c = rng.Uniform2D();\n        float2 u_g = rng.Uniform2D();\n        float2 u_d = rng.Uniform2D();\n        float u_wrs_0 = rng.Uniform();\n        float u_wrs_1 = rng.Uniform();\n        float u_wrs_2 = rng.Uniform();\n        NoOp noop;\n\n        if(!surface.specTr)\n            return EvalBSDFSampler_NoSpecTr(normal, surface, wi, lobe, u_c, u_g, u_d, noop);\n\n        return EvalBSDFSampler_NoDiffuse(normal, surface, wi, lobe, u_wrs_1, noop);\n    }\n\n    template<typename Func>\n    float BSDFSamplerPdf_NoDiffuse(float3 normal, BSDF::ShadingData surface, float3 wi,\n        Func func)\n    {\n        float3 wh = surface.SetWi(wi, normal);\n        float pdf_base = 1;\n        float pdf_c = 0;\n\n        if(surface.Coated())\n        {\n            float reflectance_c = GGXReflectance_Dielectric(surface.coat_alpha, \n                surface.ndotwo, surface.coat_eta);\n            float pdf_coat = reflectance_c * surface.coat_weight;\n            pdf_base = 1 - pdf_coat;\n\n            if(surface.reflection)\n                pdf_c = BSDF::CoatPdf(surface) * pdf_coat;\n        }\n\n        const float wh_pdf = BSDF::GGXMicrofacetPdf(surface.alpha, surface.ndotwh, surface.ndotwo);\n\n        // P(wi) = P(wi | lobe = gloss) + P(wi | lobe = coat)\n        if(surface.metallic || !surface.specTr)\n        {\n            float pdf_gr = surface.GlossSpecular() ? \n                surface.ndotwh >= MIN_N_DOT_H_SPECULAR : \n                wh_pdf / 4.0f;\n            pdf_gr *= pdf_base;\n\n            return surface.reflection ? pdf_c + pdf_gr: 0;\n        }\n\n        // Transmissive dielectric\n        float pdf_g = surface.GlossSpecular() ? surface.ndotwh >= MIN_N_DOT_H_SPECULAR : 1;\n        pdf_g *= pdf_base;\n\n        const float3 wi_other = !surface.reflection? \n            reflect(-surface.wo, wh) :\n            refract(-surface.wo, wh, 1 / surface.eta);\n        float targetScaleLum = Math::Luminance(func(wi));\n        float targetScaleOtherLum = Math::Luminance(func(wi_other));\n        float Fr_g = surface.Fresnel().x;\n        // Prob. of reflection vs transmission\n        float pdf_r = Fr_g * (surface.reflection ? targetScaleLum : targetScaleOtherLum);\n        pdf_r = pdf_r / (pdf_r + (1 - Fr_g) * (surface.reflection ? targetScaleOtherLum : targetScaleLum));\n\n        if(surface.reflection)\n        {\n            // Account for change of density from half vector to incident vector\n            pdf_g *= surface.GlossSpecular() ? 1 : (wh_pdf / 4.0f);\n            pdf_g *= pdf_r;\n\n            return pdf_g + pdf_c;\n        }\n\n        pdf_g *= 1 - pdf_r;\n\n        if(!surface.GlossSpecular())\n        {\n            pdf_g *= wh_pdf * surface.whdotwo;\n            float dwh_dwi = BSDF::JacobianHalfVecToIncident_Tr(surface.eta, \n                surface.whdotwo, surface.whdotwi);\n            pdf_g *= dwh_dwi;\n        }\n\n        return pdf_g;\n    }\n\n    float BSDFSamplerPdf_NoDiffuse(float3 normal, BSDF::ShadingData surface, float3 wi)\n    {\n        NoOp noop;\n        return BSDFSamplerPdf_NoDiffuse(normal, surface, wi, noop);\n    }\n\n    template<typename Func>\n    float BSDFSamplerPdf(float3 normal, BSDF::ShadingData surface, float3 wi_z, \n        Func func, inout RNG rng)\n    {\n        if(surface.specTr)\n            return BSDFSamplerPdf_NoDiffuse(normal, surface, wi_z, func);\n\n        surface.SetWi(wi_z, normal);\n        if(!surface.reflection && !surface.ThinWalled())\n            return 0;\n\n        BSDFEval eval_z = BSDF::Unified(surface);\n        float targetLum = Math::Luminance(eval_z.f * func(wi_z));\n\n        if(targetLum == 0)\n            return 0;\n\n        // Surface is opaque dielectric or thin walled\n\n        // Using the law of total probability:\n        //      p(wi_z) = p(wi_z, lobe = lobe_0) + ... + p(wi_z, lobe = lobe_k)\n        float w_sum_c;\n        float w_sum_g;\n        float w_sum_dr;\n        float w_sum_dt;\n\n        // wi_z\n        {\n            float pdf_g = BSDF::GlossPdf(surface);\n            float pdf_d = !surface.metallic ? BSDF::DiffusePdf(surface) : 0;\n            float pdf_c = surface.Coated() ? BSDF::CoatPdf(surface) : 0;\n            float w = surface.reflection ? RT::BalanceHeuristic3(pdf_g, pdf_d, pdf_c, targetLum) : \n                (targetLum / pdf_d) * !surface.metallic;\n            w_sum_g = w;\n            w_sum_dr = w;\n            w_sum_dt = w;\n            w_sum_c = w;\n        }\n\n        if(w_sum_g == 0)\n            return 0;\n\n        float pdf_d;\n        float3 wi_d = BSDF::SampleDiffuse(normal, rng.Uniform2D(), pdf_d);\n        float Fr_g;\n\n        // wi_dr\n        if(!surface.metallic)\n        {\n            surface.SetWi_Refl(wi_d, normal);\n            BSDFEval eval = BSDF::Unified(surface);\n            Fr_g = eval.Fr_g.x;\n            float3 target_dr = eval.f;\n            float targetLum_dr = Math::Luminance(target_dr * func(wi_d));\n\n            float pdf_g = BSDF::GlossPdf(surface);\n            float pdf_c = surface.Coated() ? BSDF::CoatPdf(surface) : 0;\n            float w = RT::BalanceHeuristic3(pdf_d, pdf_g, pdf_c, targetLum_dr);\n            w_sum_g += w;\n            w_sum_dt += w;\n            w_sum_c += w;\n        }\n\n        // wi_dt\n        if(!surface.metallic && surface.ThinWalled())\n        {\n            float3 target_dt = BSDF::DielectricBaseDiffuseTr(surface, Fr_g);\n            float targetLum_dt = Math::Luminance(target_dt * func(-wi_d));\n\n            float w = targetLum_dt / pdf_d;\n            w_sum_g += w;\n            w_sum_dr += w;\n            w_sum_c += w;\n        }\n\n        // wi_g\n        {\n            float3 wi_g = BSDF::SampleGloss(surface, normal, rng.Uniform2D());\n            surface.SetWi_Refl(wi_g, normal);\n            float3 target_g = BSDF::Unified(surface).f;\n            float targetLum_g = Math::Luminance(target_g * func(wi_g));\n\n            // Account for change of density from half vector to incident vector\n            float pdf_g = BSDF::GlossPdf(surface);\n            float pdf_d = !surface.metallic ? BSDF::DiffusePdf(surface) : 0;\n            float pdf_c = surface.Coated() ? BSDF::CoatPdf(surface) : 0;\n            float w = RT::BalanceHeuristic3(pdf_g, pdf_d, pdf_c, targetLum_g);\n            w_sum_dr += w;\n            w_sum_dt += w;\n            w_sum_c += w;\n        }\n\n        // wi_c\n        if(surface.Coated())\n        {\n            float3 wi_c = BSDF::SampleCoat(surface, normal, rng.Uniform2D());\n            surface.SetWi_Refl(wi_c, normal);\n            float3 target_c = BSDF::Unified(surface).f;\n            float targetLum_c = Math::Luminance(target_c * func(wi_c));\n\n            // Account for change of density from half vector to incident vector\n            float pdf_g = BSDF::GlossPdf(surface);\n            float pdf_d = !surface.metallic ? BSDF::DiffusePdf(surface) : 0;\n            float pdf_c = BSDF::CoatPdf(surface);\n            float w = RT::BalanceHeuristic3(pdf_g, pdf_d, pdf_c, targetLum_c);\n            w_sum_g += w;\n            w_sum_dr += w;\n            w_sum_dt += w;\n        }\n\n        // p(wi_z, lobe = gloss)\n        float pdf = w_sum_g > 0 ? targetLum / w_sum_g : 0;\n        // p(wi_z, lobe = diffuse reflection)\n        pdf += w_sum_dr > 0 ? targetLum / w_sum_dr : 0;\n        // p(wi_z, lobe = coat)\n        pdf += w_sum_c > 0 ? targetLum / w_sum_c : 0;\n        // p(wi_z, lobe = diffuse transmission)\n        pdf += surface.ThinWalled() && (w_sum_dt > 0) ? targetLum / w_sum_dt : 0;\n\n        return pdf;\n    }\n\n    float BSDFSamplerPdf(float3 normal, BSDF::ShadingData surface, float3 wi_z, inout RNG rng)\n    {\n        NoOp noop;\n        return BSDFSamplerPdf(normal, surface, wi_z, noop, rng);\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/Common/CMakeLists.txt",
    "content": "set(RP_COMMON_DIR ${ZETA_RENDER_PASS_DIR}/Common)\nset(RP_COMMON_SRC\n    ${RP_COMMON_DIR}/BSDF.hlsli\n    ${RP_COMMON_DIR}/BSDFSampling.hlsli\n    ${RP_COMMON_DIR}/Math.hlsli\n    ${RP_COMMON_DIR}/Common.hlsli\n    ${RP_COMMON_DIR}/FrameConstants.h\n    ${RP_COMMON_DIR}/GBuffers.hlsli\n    ${RP_COMMON_DIR}/LightSource.hlsli\n    ${RP_COMMON_DIR}/LightVoxelGrid.hlsli\n    ${RP_COMMON_DIR}/RayQuery.hlsli\n    ${RP_COMMON_DIR}/RT.hlsli\n    ${RP_COMMON_DIR}/Sampling.hlsli\n    ${RP_COMMON_DIR}/SH.hlsli\n    ${RP_COMMON_DIR}/StaticTextureSamplers.hlsli\n    ${RP_COMMON_DIR}/Volumetric.hlsli)\nset(RP_COMMON_SRC ${RP_COMMON_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaRenderPass/Common/Common.hlsli",
    "content": "#ifndef COMMON_H\n#define COMMON_H\n\n// 28 bytes\nstruct Vertex\n{\n    float3 PosL;\n    float2 TexUV;\n    uint16_t2 NormalL;\n    uint16_t2 TangentU;\n};\n\nnamespace Common\n{\n    // Samples texture with Catmull-Rom filtering, using 5 texture fetches instead of 16.\n    // Ref: https://gist.github.com/TheRealMJP/c83b8c0f46b63f3a88a5986f4fa982b1\n    float3 SampleTextureCatmullRom_5Tap(Texture2D<float4> tex, SamplerState linearSampler, float2 uv, float2 texSize)\n    {\n        // We're going to sample a a 4x4 grid of texels surrounding the target UV coordinate. We'll do this by rounding\n        // down the sample location to get the exact center of our \"starting\" texel. The starting texel will be at\n        // location [1, 1] in the grid, where [0, 0] is the top left corner.\n        float2 samplePos = uv * texSize;\n        float2 texPos1 = floor(samplePos - 0.5f) + 0.5f;\n\n        // Compute the fractional offset from our starting texel to our original sample location, which we'll\n        // feed into the Catmull-Rom spline function to get our filter weights.\n        float2 f = samplePos - texPos1;\n\n        // Compute the Catmull-Rom weights using the fractional offset that we calculated earlier.\n        // These equations are pre-expanded based on our knowledge of where the texels will be located,\n        // which lets us avoid having to evaluate a piece-wise function.\n        float2 w0 = f * (-0.5f + f * (1.0f - 0.5f * f));\n        float2 w1 = 1.0f + f * f * (-2.5f + 1.5f * f);\n        float2 w2 = f * (0.5f + f * (2.0f - 1.5f * f));\n        float2 w3 = f * f * (-0.5f + 0.5f * f);\n\n        // Work out weighting factors and sampling offsets that will let us use bilinear filtering to\n        // simultaneously evaluate the middle 2 samples from the 4x4 grid.\n        float2 w12 = w1 + w2;\n        float2 offset12 = w2 / (w1 + w2);\n\n        // Compute the final UV coordinates we'll use for sampling the texture\n        float2 texPos0 = texPos1 - 1;\n        float2 texPos3 = texPos1 + 2;\n        float2 texPos12 = texPos1 + offset12;\n\n        texPos0 /= texSize;\n        texPos3 /= texSize;\n        texPos12 /= texSize;\n\n        float3 result = 0.0f;\n        result += tex.SampleLevel(linearSampler, float2(texPos12.x, texPos0.y), 0.0f).xyz * w12.x * w0.y;\n\n        result += tex.SampleLevel(linearSampler, float2(texPos0.x, texPos12.y), 0.0f).xyz * w0.x * w12.y;\n        result += tex.SampleLevel(linearSampler, float2(texPos12.x, texPos12.y), 0.0f).xyz * w12.x * w12.y;\n        result += tex.SampleLevel(linearSampler, float2(texPos3.x, texPos12.y), 0.0f).xyz * w3.x * w12.y;\n\n        result += tex.SampleLevel(linearSampler, float2(texPos12.x, texPos3.y), 0.0f).xyz * w12.x * w3.y;\n\n        return result;\n    }\n\n    // Samples texture with Catmull-Rom filtering, using 9 texture fetches instead of 16.\n    // Ref: https://gist.github.com/TheRealMJP/c83b8c0f46b63f3a88a5986f4fa982b1\n    float3 SampleTextureCatmullRom(Texture2D<float4> tex, SamplerState linearSampler, float2 uv, float2 texSize)\n    {\n        float2 samplePos = uv * texSize;\n        float2 texPos1 = floor(samplePos - 0.5f) + 0.5f;\n\n        float2 f = samplePos - texPos1;\n\n        float2 w0 = f * (-0.5f + f * (1.0f - 0.5f * f));\n        float2 w1 = 1.0f + f * f * (-2.5f + 1.5f * f);\n        float2 w2 = f * (0.5f + f * (2.0f - 1.5f * f));\n        float2 w3 = f * f * (-0.5f + 0.5f * f);\n\n        float2 w12 = w1 + w2;\n        float2 offset12 = w2 / (w1 + w2);\n\n        float2 texPos0 = texPos1 - 1;\n        float2 texPos3 = texPos1 + 2;\n        float2 texPos12 = texPos1 + offset12;\n\n        texPos0 /= texSize;\n        texPos3 /= texSize;\n        texPos12 /= texSize;\n\n        float3 result = 0.0f;\n        result += tex.SampleLevel(linearSampler, float2(texPos0.x, texPos0.y), 0.0f).xyz * w0.x * w0.y;\n        result += tex.SampleLevel(linearSampler, float2(texPos12.x, texPos0.y), 0.0f).xyz * w12.x * w0.y;\n        result += tex.SampleLevel(linearSampler, float2(texPos3.x, texPos0.y), 0.0f).xyz * w3.x * w0.y;\n        \n        result += tex.SampleLevel(linearSampler, float2(texPos0.x, texPos12.y), 0.0f).xyz * w0.x * w12.y;\n        result += tex.SampleLevel(linearSampler, float2(texPos12.x, texPos12.y), 0.0f).xyz * w12.x * w12.y;\n        result += tex.SampleLevel(linearSampler, float2(texPos3.x, texPos12.y), 0.0f).xyz * w3.x * w12.y;\n\n        result += tex.SampleLevel(linearSampler, float2(texPos0.x, texPos3.y), 0.0f).xyz * w0.x * w3.y;\n        result += tex.SampleLevel(linearSampler, float2(texPos12.x, texPos3.y), 0.0f).xyz * w12.x * w3.y;\n        result += tex.SampleLevel(linearSampler, float2(texPos3.x, texPos3.y), 0.0f).xyz * w3.x * w3.y;\n        \n        return result;\n    }\n\n    // Swizzle thread groups for better L2-cache behavior. Works by breaking the \n    // image into tiles of dimension (N, dispatchDim.y).\n    // dispatchDim: Same as DispatchThreads() arguments. Must be a power of two.\n    // Gid: SV_GroupID\n    // GTid: SV_GroupThreadID\n    // groupDim: e.g. [numthreads(8, 8, 1)] -> (8, 8)\n    // N: Number of horizontal blocks in each tile, common values are 8, 16, 32. Must \n    // be a power of two.\n    // Ref: https://developer.nvidia.com/blog/optimizing-compute-shaders-for-l2-locality-using-thread-group-id-swizzling/\n    void SwizzleGroupID(in uint2 Gid, in uint2 GTid, uint2 groupDim, in uint2 dispatchDim, in uint N,\n        out uint2 swizzledDTid, out uint2 swizzledGid)\n    {\n        const uint groupIDFlattened = Gid.y * dispatchDim.x + Gid.x;\n        const uint numGroupsInTile = N * dispatchDim.y;\n        const uint tileID = groupIDFlattened / numGroupsInTile;\n        const uint groupIDinTileFlattened = groupIDFlattened % numGroupsInTile;\n        const uint2 groupIDinTile = uint2(groupIDinTileFlattened % N, groupIDinTileFlattened / N);\n        const uint swizzledGidx = groupIDinTile.y * dispatchDim.x + tileID * N + groupIDinTile.x;\n    \n        swizzledGid = uint2(swizzledGidx % dispatchDim.x, swizzledGidx / dispatchDim.x);\n        swizzledDTid = swizzledGid * groupDim + GTid;\n    }\n\n    uint2 SwizzleThreadGroup(uint3 DTid, uint3 Gid, uint3 GTid, uint2 groupDim, uint dispatchDimX, uint tileWidth,\n        uint log2TileWidth, uint numGroupsInTile, out uint2 swizzledGid)\n    {\n        const uint groupIDFlattened = Gid.y * dispatchDimX + Gid.x;\n        const uint tileID = groupIDFlattened / numGroupsInTile;\n        const uint groupIDinTileFlattened = groupIDFlattened % numGroupsInTile;\n\n        // TileWidth is a power of 2 for all tiles except possibly the last one\n        const uint numFullTiles = dispatchDimX / tileWidth; // floor(DispatchDimX / TileWidth\n        const uint numGroupsInFullTiles = numFullTiles * numGroupsInTile;\n\n        uint2 groupIDinTile;\n        if (groupIDFlattened >= numGroupsInFullTiles)\n        {\n            // DispatchDimX & NumGroupsInTile\n            const uint lastTileDimX = dispatchDimX - tileWidth * numFullTiles;\n            groupIDinTile = uint2(groupIDinTileFlattened % lastTileDimX, groupIDinTileFlattened / lastTileDimX);\n        }\n        else\n        {\n            groupIDinTile = uint2(\n                groupIDinTileFlattened & (tileWidth - 1),\n                groupIDinTileFlattened >> log2TileWidth);\n        }\n\n        const uint swizzledGidFlattened = groupIDinTile.y * dispatchDimX + tileID * tileWidth + groupIDinTile.x;\n        swizzledGid = uint2(swizzledGidFlattened % dispatchDimX, swizzledGidFlattened / dispatchDimX);\n        const uint2 swizzledDTid = swizzledGid * groupDim + GTid.xy;\n    \n        return swizzledDTid;\n    }\n\n    bool IsFlagSet(uint32_t bitmask, uint32_t flag)\n    {\n        return (bitmask & flag) == flag;\n    }\n}\n\n#endif // COMMON_H"
  },
  {
    "path": "Source/ZetaRenderPass/Common/FrameConstants.h",
    "content": "#ifndef FRAME_CONSTANTS\n#define FRAME_CONSTANTS\n\n#include \"../../ZetaCore/Core/HLSLCompat.h\"\n\n#ifdef __cplusplus\nnamespace ZetaRay\n{\n#endif\n    struct cbFrameConstants\n    {\n        row_major float3x4_ CurrView;\n        row_major float3x4_ PrevView;\n        row_major float3x4_ CurrViewInv;\n        row_major float3x4_ PrevViewInv;\n        float4x4_ CurrViewProj;\n        float4x4_ PrevViewProj;\n\n        float3_ CameraPos;\n        float CameraNear;\n\n        float AspectRatio;\n        float PixelSpreadAngle;\n        float TanHalfFOV;\n        float dt;\n\n        uint32_t FrameNum;\n        uint32_t CurrGBufferDescHeapOffset;\n        uint32_t PrevGBufferDescHeapOffset;\n        uint32_t BaseColorMapsDescHeapOffset;\n\n        uint32_t NormalMapsDescHeapOffset;\n        uint32_t MetallicRoughnessMapsDescHeapOffset;\n        uint32_t EmissiveMapsDescHeapOffset;\n        uint32_t EnvMapDescHeapOffset;\n\n        uint32_t RenderWidth;\n        uint32_t RenderHeight;\n        uint32_t DisplayWidth;\n        uint32_t DisplayHeight;\n\n        float2_ CurrCameraJitter;\n        float2_ PrevCameraJitter;\n\n        float PlanetRadius;\n        float SunCosAngularRadius;\n        float SunSinAngularRadius;\n        float pad;\n\n        float3_ SunDir;\n        float SunIlluminance;\n\n        float3_ RayleighSigmaSColor;\n        float RayleighSigmaSScale;\n\n        float3_ OzoneSigmaAColor;\n        float OzoneSigmaAScale;\n\n        float MieSigmaS;\n        float MieSigmaA;\n        float AtmosphereAltitude;\n        float g;\n\n        uint32_t NumFramesCameraStatic;\n        uint32_t CameraStatic;\n        uint32_t Accumulate;\n        uint32_t SunMoved;\n\n        float CameraRayUVGradsScale;\n        float MipBias;\n        float OneDivNumEmissiveTriangles;\n        uint32_t NumEmissiveTriangles;\n\n        float FocusDepth;\n        float LensRadius;\n        uint32_t DoF;\n        uint32_t pad2;\n    };\n#ifdef __cplusplus\n}\n#endif\n\n#ifdef __cplusplus\nstatic_assert((offsetof(ZetaRay::cbFrameConstants, CameraPos) & 15) == 0);\nstatic_assert((offsetof(ZetaRay::cbFrameConstants, AspectRatio) & 15) == 0);\nstatic_assert((offsetof(ZetaRay::cbFrameConstants, FrameNum) & 15) == 0);\nstatic_assert((offsetof(ZetaRay::cbFrameConstants, NormalMapsDescHeapOffset) & 15) == 0);\nstatic_assert((offsetof(ZetaRay::cbFrameConstants, RenderWidth) & 15) == 0);\nstatic_assert((offsetof(ZetaRay::cbFrameConstants, CurrCameraJitter) & 15) == 0);\nstatic_assert((offsetof(ZetaRay::cbFrameConstants, PlanetRadius) & 15) == 0);\nstatic_assert((offsetof(ZetaRay::cbFrameConstants, SunDir) & 15) == 0);\nstatic_assert((offsetof(ZetaRay::cbFrameConstants, RayleighSigmaSColor) & 15) == 0);\nstatic_assert((offsetof(ZetaRay::cbFrameConstants, OzoneSigmaAColor) & 15) == 0);\nstatic_assert((offsetof(ZetaRay::cbFrameConstants, MieSigmaS) & 15) == 0);\nstatic_assert((offsetof(ZetaRay::cbFrameConstants, NumFramesCameraStatic) & 15) == 0);\nstatic_assert((offsetof(ZetaRay::cbFrameConstants, CameraRayUVGradsScale) & 15) == 0);\n#endif\n\n#endif\n"
  },
  {
    "path": "Source/ZetaRenderPass/Common/GBuffers.hlsli",
    "content": "#ifndef GBUFFERS_H\n#define GBUFFERS_H\n\n#include \"../../ZetaCore/Core/Material.h\"\n\nenum GBUFFER_OFFSET\n{\n    BASE_COLOR = 0,\n    NORMAL,\n    METALLIC_ROUGHNESS,\n    MOTION_VECTOR,\n    EMISSIVE_COLOR,\n    IOR,\n    COAT,\n    DEPTH,\n    TRI_DIFF_GEO_A,\n    TRI_DIFF_GEO_B\n};\n\n#define GBUFFER_BASE_COLOR Texture2D<float4>\n#define GBUFFER_NORMAL Texture2D<float2>\n#define GBUFFER_METALLIC_ROUGHNESS Texture2D<float2>\n#define GBUFFER_MOTION_VECTOR Texture2D<float2> \n#define GBUFFER_EMISSIVE_COLOR Texture2D<float3>\n#define GBUFFER_IOR Texture2D<float>\n#define GBUFFER_COAT Texture2D<uint4>\n#define GBUFFER_DEPTH Texture2D<float> \n#define GBUFFER_TRI_DIFF_GEO_A Texture2D<uint4> \n#define GBUFFER_TRI_DIFF_GEO_B Texture2D<uint2> \n\nnamespace GBuffer\n{\n    struct Flags\n    {\n        bool metallic;\n        bool transmissive;\n        bool emissive;\n        bool invalid;\n        bool trDepthGt0;\n        bool subsurface;\n        bool coated;\n    };\n\n    struct Coat\n    {\n        float weight;\n        float3 color;\n        float roughness;\n        float ior;\n    };\n\n    float EncodeMetallic(float metalness, bool isTransmissive, float3 emissive, float trDepth,\n        float subsurface, float coat_weight)\n    {\n        bool isMetal = metalness >= MIN_METALNESS_METAL;\n        bool isEmissive = dot(emissive, emissive) > 0;\n\n        uint ret = isTransmissive;\n        ret |= (uint(isEmissive) << 1);\n        ret |= (uint(trDepth > 0) << 3);\n        ret |= (uint(subsurface > 0) << 4);\n        ret |= (uint(coat_weight > 0) << 5);\n        ret |= (uint(isMetal) << 7);\n\n        return float(ret) / 255.0f;\n    }\n\n    GBuffer::Flags DecodeMetallic(float encoded)\n    {\n        uint v = (uint)mad(encoded, 255.0f, 0.5f);\n\n        Flags ret;\n        ret.transmissive = (v & 0x1) != 0;\n        ret.emissive = (v & (1 << 1)) != 0;\n        ret.invalid = (v & (1 << 2)) != 0;\n        ret.trDepthGt0 = (v & (1 << 3)) != 0;\n        ret.subsurface = (v & (1 << 4)) != 0;\n        ret.coated = (v & (1 << 5)) != 0;\n        ret.metallic = (v & (1 << 7)) != 0;\n\n        return ret;\n    }\n\n    bool4 DecodeMetallic(float4 encoded)\n    {\n        uint4 v = (uint4) round(encoded * 255.0f);\n        return (v & (1 << 7)) != 0;\n    }\n\n    void DecodeMetallicEmissive(float4 encoded, out bool4 isMetallic, out bool4 isEmissive)\n    {\n        uint4 v = (uint4) round(encoded * 255.0f);\n        isEmissive = (v & (1 << 1)) != 0;\n        isMetallic = (v & (1 << 7)) != 0;\n    }\n\n    float EncodeIOR(float ior)\n    {\n        return (ior - MIN_IOR) / (MAX_IOR - MIN_IOR);\n    }\n\n    float DecodeIOR(float encoded)\n    {\n        return mad(encoded, MAX_IOR - MIN_IOR, MIN_IOR);\n    }\n\n    GBuffer::Coat UnpackCoat(uint3 packed)\n    {\n        GBuffer::Coat ret;\n        ret.weight = Math::UNorm8ToFloat((packed.y >> 8) & 0xff);\n        ret.roughness = Math::UNorm8ToFloat(packed.z & 0xff);\n\n        uint c = packed.x | ((packed.y & 0xff) << 16);\n        ret.color = Math::UnpackRGB8(c);\n\n        float normalized = Math::UNorm8ToFloat(packed.z >> 8);\n        ret.ior = DecodeIOR(normalized);\n\n        return ret;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/Common/LightSource.hlsli",
    "content": "#ifndef LIGHT_SOURCE_H\n#define LIGHT_SOURCE_H\n\n#include \"FrameConstants.h\"\n#include \"StaticTextureSamplers.hlsli\"\n#include \"Volumetric.hlsli\"\n#include \"RT.hlsli\"\n#include \"BSDF.hlsli\"\n\nnamespace Light\n{\n    enum class TYPE : uint16_t\n    {\n        NONE = 0,\n        SUN = 1,\n        SKY = 2,\n        EMISSIVE = 3\n    };\n\n    uint16_t TypeToValue(TYPE t)\n    {\n        switch(t)\n        {\n            case TYPE::NONE:\n                return 0;\n            case TYPE::SUN:\n                return 1;\n            case TYPE::SKY:\n                return 2;\n            case TYPE::EMISSIVE:\n            default:\n                return 3;\n        }\n    }\n\n    TYPE TypeFromValue(uint x)\n    {\n        if(x == 0)\n            return TYPE::NONE;\n        if(x == 1)\n            return TYPE::SUN;\n        if(x == 2)\n            return TYPE::SKY;\n\n        return TYPE::EMISSIVE;\n    }\n\n    float3 DecodeEmissiveTriV1(RT::EmissiveTriangle tri)\n    {\n#if ENCODE_EMISSIVE_POS == 1\n        float2 v0v1 = (float2)tri.V0V1 / float((1 << 16) - 1);\n        float3 decoded = Math::DecodeUnitVector(v0v1.xy);\n\n        return mad(decoded, tri.EdgeLengths.x, tri.Vtx0);\n#else\n        return Vtx1;\n#endif\n    }\n\n    float3 DecodeEmissiveTriV2(RT::EmissiveTriangle tri)\n    {\n#if ENCODE_EMISSIVE_POS == 1\n        float2 v0v2 = (float2)tri.V0V2 / float((1 << 16) - 1);\n        float3 decoded = Math::DecodeUnitVector(v0v2.xy);\n        \n        return mad(decoded, tri.EdgeLengths.y, tri.Vtx0);\n#else\n        return Vtx2;\n#endif\n    }\n\n    struct AliasTableSample\n    {\n        static AliasTableSample get(StructuredBuffer<RT::EmissiveLumenAliasTableEntry> g_aliasTable, \n            uint numEmissiveTriangles, inout RNG rng)\n        {\n            AliasTableSample ret;\n            uint u0 = rng.UniformUintBounded(numEmissiveTriangles);\n            RT::EmissiveLumenAliasTableEntry s = g_aliasTable[u0];\n\n            if (rng.Uniform() < s.P_Curr)\n            {\n                ret.pdf = s.CachedP_Orig;\n                ret.idx = u0;\n\n                return ret;\n            }\n\n            ret.pdf = s.CachedP_Alias;\n            ret.idx = s.Alias;\n\n            return ret;\n        }\n\n        uint idx;\n        float pdf;\n    };\n\n    RT::PresampledEmissiveTriangle SamplePresampledSet(uint sampleSetIdx, \n        StructuredBuffer<RT::PresampledEmissiveTriangle> g_sampleSets, \n        uint sampleSetSize, inout RNG rng)\n    {\n        uint u = rng.UniformUintBounded_Faster(sampleSetSize);\n        uint idx = sampleSetIdx * sampleSetSize + u;\n        return g_sampleSets[idx];\n    }\n\n    struct EmissiveTriSample\n    {\n        static EmissiveTriSample get(float3 pos, RT::EmissiveTriangle tri, inout RNG rng, \n            bool reverseNormalIfTwoSided = true)\n        {\n            EmissiveTriSample ret;\n            float2 u = rng.Uniform2D();\n            ret.bary = Sampling::UniformSampleTriangle(u);\n\n            const float3 vtx1 = Light::DecodeEmissiveTriV1(tri);\n            const float3 vtx2 = Light::DecodeEmissiveTriV2(tri);\n            ret.pos = (1.0f - ret.bary.x - ret.bary.y) * tri.Vtx0 + ret.bary.x * vtx1 + ret.bary.y * vtx2;\n            ret.normal = cross(vtx1 - tri.Vtx0, vtx2 - tri.Vtx0);\n            bool normalIs0 = dot(ret.normal, ret.normal) == 0;\n            float twoArea = length(ret.normal);\n            ret.pdf = normalIs0 ? 0.0f : 2.0f / twoArea;\n\n            ret.normal = normalIs0 ? ret.normal : ret.normal / twoArea;\n            ret.normal = reverseNormalIfTwoSided && tri.IsDoubleSided() && dot(pos - ret.pos, ret.normal) < 0 ? \n                -ret.normal : \n                ret.normal;\n\n            return ret;\n        }\n\n        float3 pos;\n        float3 normal;\n        float2 bary;\n        float pdf;\n    };\n\n    float3 Le_Sun(float3 pos, ConstantBuffer<cbFrameConstants> g_frame)\n    {\n        const float3 sigma_t_rayleigh = g_frame.RayleighSigmaSColor * \n            g_frame.RayleighSigmaSScale;\n        const float sigma_t_mie = g_frame.MieSigmaA + g_frame.MieSigmaS;\n        const float3 sigma_t_ozone = g_frame.OzoneSigmaAColor * \n            g_frame.OzoneSigmaAScale;\n\n        float3 temp = pos;\n        temp.y += g_frame.PlanetRadius;\n    \n        const float t = Volume::IntersectRayAtmosphere(\n            g_frame.PlanetRadius + g_frame.AtmosphereAltitude, temp, -g_frame.SunDir);\n        const float3 tr = Volume::EstimateTransmittance(g_frame.PlanetRadius, temp, \n            -g_frame.SunDir, t, sigma_t_rayleigh, sigma_t_mie, sigma_t_ozone, 6);\n\n        return tr * g_frame.SunIlluminance;\n    }\n\n    float3 Le_Sky(float3 wi, uint skyViewDescHeapOffset)\n    {\n        const float2 thetaPhi = Math::SphericalFromCartesian(wi);\n        float2 uv = float2(thetaPhi.y * ONE_OVER_2_PI, thetaPhi.x * ONE_OVER_PI);\n\n        // Inverse non-linear map\n        const float sn = thetaPhi.x >= PI_OVER_2 ? 1.0f : -1.0f;\n        uv.y = mad(0.5f, thetaPhi.x, -PI_OVER_4);\n        uv.y = 0.5f + sn * sqrt(abs(uv.y) * ONE_OVER_PI);\n\n        Texture2D<float4> g_envMap = ResourceDescriptorHeap[skyViewDescHeapOffset];\n        // Linear sampler prevents banding artifacts\n        const float3 le = g_envMap.SampleLevel(g_samLinearWrap, uv, 0.0f).rgb;\n\n        return le;\n    }\n\n    float3 Le_SkyWithSunDisk(uint2 DTid, ConstantBuffer<cbFrameConstants> g_frame)\n    {\n        float3 wc = RT::GeneratePinholeCameraRay(DTid, float2(g_frame.RenderWidth, g_frame.RenderHeight), \n            g_frame.AspectRatio, g_frame.TanHalfFOV, g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, \n            g_frame.CurrView[2].xyz, g_frame.CurrCameraJitter);\n\n        float3 rayOrigin = float3(0, 1e-1, 0);\n        rayOrigin.y += g_frame.PlanetRadius;\n\n        float3 wTemp = wc;\n        // cos(a - b) = cos a cos b + sin a sin b\n        wTemp.y = wTemp.y * g_frame.SunCosAngularRadius + sqrt(1 - wc.y * wc.y) * \n            g_frame.SunSinAngularRadius;\n\n        float t;\n        bool intersectedPlanet = Volume::IntersectRayPlanet(g_frame.PlanetRadius, rayOrigin, \n            wTemp, t);\n\n        // a disk that's supposed to be the sun\n        if (dot(-wc, g_frame.SunDir) >= g_frame.SunCosAngularRadius && !intersectedPlanet)\n            return g_frame.SunIlluminance;\n        // sample the sky texture\n        else\n            return Light::Le_Sky(wc, g_frame.EnvMapDescHeapOffset);\n    }\n\n    // Assumes area light is diffuse\n    float3 Le_EmissiveTriangle(RT::EmissiveTriangle tri, float2 bary, uint emissiveMapsDescHeapOffset, \n        SamplerState s = g_samPointWrap)\n    {\n        const float3 emissiveFactor = tri.GetFactor();\n        const float emissiveStrength = (float)tri.GetStrength();\n        float3 le = emissiveFactor * emissiveStrength;\n\n        if (Math::Luminance(le) == 0)\n            return 0.0;\n\n        uint32_t emissiveTex = tri.GetTex();\n        if (emissiveTex != Material::INVALID_ID)\n        {\n            const uint offset = NonUniformResourceIndex(emissiveMapsDescHeapOffset + emissiveTex);\n            EMISSIVE_MAP g_emissiveMap = ResourceDescriptorHeap[offset];\n\n            float2 texUV = (1.0f - bary.x - bary.y) * tri.UV0 + bary.x * tri.UV1 + bary.y * tri.UV2;\n            le *= g_emissiveMap.SampleLevel(s, texUV, 0).rgb;\n        }\n\n        return le;\n    }\n\n    struct SunSample\n    {\n        static SunSample Init()\n        {\n            SunSample ret;\n            ret.f = 0;\n            ret.wi = 0;\n            ret.pdf = 0;\n\n            return ret;\n        }\n\n        static SunSample get(float3 sunDir, float sunCosAngularRadius, float3 normal, \n            BSDF::ShadingData surface, inout RNG rng)\n        {\n            SunSample ret = SunSample::Init();\n\n            // Light hits the backside and surfaces isn't transmissive\n            const float ndotSunDir = dot(sunDir, normal);\n            if(ndotSunDir < 0 && !surface.Transmissive())\n                return ret;\n\n            // Light sampling - since sun is a very small area light, area sampling \n            // should be fine\n            float pdf_light;\n            float3 sampleLocal = Sampling::UniformSampleCone(rng.Uniform2D(), \n                sunCosAngularRadius, pdf_light);\n            \n            Math::CoordinateSystem onb = Math::CoordinateSystem::Build(sunDir);\n            float3 wi_light = mad(sampleLocal.x, onb.b1, mad(sampleLocal.y, onb.b2, sampleLocal.z * sunDir));\n\n            surface.SetWi(wi_light, normal);\n            ret.f = BSDF::Unified(surface).f;\n            ret.wi = wi_light;\n            ret.pdf = pdf_light;\n\n            return ret;\n        }\n\n        float3 wi;\n        float3 f;\n        float pdf;\n    };\n\n    SunSample SampleSunDirection(uint2 DTid, uint frameNum, float3 sunDir, float sunCosAngularRadius, \n        float3 normal, BSDF::ShadingData surface)\n    {\n        RNG rng = RNG::Init(DTid, frameNum);\n        return SunSample::get(sunDir, sunCosAngularRadius, normal, surface, rng);\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/Common/LightVoxelGrid.hlsli",
    "content": "#ifndef LVG_H\n#define LVG_H\n\n#include \"LightSource.hlsli\"\n\nnamespace LVG\n{\n    uint FlattenVoxelIndex(uint3 voxelIdx, uint3 gridDim)\n    {\n        return voxelIdx.z * gridDim.x * gridDim.y + voxelIdx.y * gridDim.x + voxelIdx.x;\n    }\n\n    float3 VoxelCenter(int3 voxelIdx, int3 gridDim, float3 voxelExtents, float3x4 viewInv, float offset_y = 0)\n    {\n        // e.g. when dim = 8, map\n        //  0  1  2  3  4  5  6  7\n        // to\n        // -3 -2 -1  0  0  1  2  3\n        int3 dimDiv2 = gridDim >> 1;\n        int3 voxelIdxCamSpace = voxelIdx - dimDiv2;\n        voxelIdxCamSpace += voxelIdx < dimDiv2;\n        // voxel space Y points in the opposite direction of camera space Y\n        voxelIdxCamSpace.y *= -1;\n\n        float3 corner = voxelIdxCamSpace * 2 * voxelExtents;\n        float3 s = Math::SignNotZero(voxelIdxCamSpace);\n        float3 centerV = corner + voxelExtents * s;\n        centerV.y += offset_y;\n        float3 centerW = mul(viewInv, float4(centerV, 1));\n        \n        return centerW;\n    }\n\n    bool MapPosToVoxel(float3 pos, int3 gridDim, float3 voxelExtents, float3x4 view, out int3 idx, float offset_y = 0)\n    {\n        float3 posV = mul(view, float4(pos, 1));\n        posV.y -= offset_y;\n\n        int3 dimDiv2 = gridDim >> 1;\n        float3 voxel = floor(abs(posV) / (2 * voxelExtents));\n\n        if(any(voxel >= dimDiv2))\n            return false;\n        \n        voxel *= Math::SignNotZero(posV);\n        voxel.y *= -1;\n\n        int3 voxelIdx = int3(voxel) + dimDiv2;\n        voxelIdx -= int3(posV.x < 0, posV.y >= 0, posV.z < 0);\n        idx = voxelIdx;\n\n        return true;\n    }\n\n    bool Sample(float3 pos, uint3 gridDim, float3 voxelExtents, uint numLightsPerVoxel, float3x4 view, \n        StructuredBuffer<RT::VoxelSample> g_voxel, out RT::VoxelSample s, inout RNG rng, float offset_y = 0, \n        bool jitter = true)\n    {\n        float3 posJittered = jitter ? pos + (rng.Uniform3D() * 2 - 1) * voxelExtents : pos;\n        \n        int3 voxelIdx;\n        if(!MapPosToVoxel(posJittered, gridDim, voxelExtents, view, voxelIdx, offset_y))\n            return false;\n        \n        uint start = FlattenVoxelIndex(voxelIdx, gridDim) * numLightsPerVoxel;\n        uint u = rng.UniformUintBounded_Faster(numLightsPerVoxel);\n        s = g_voxel[start + u];\n        \n        return true;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/Common/Math.hlsli",
    "content": "#ifndef MATH_H\n#define MATH_H\n\n#define PI                   3.141592654f\n#define TWO_PI               6.283185307f\n#define PI_OVER_2            1.570796327f\n#define PI_OVER_4            0.7853981635f\n#define THREE_PI_OVER_2      4.7123889804f\n#define ONE_OVER_PI          0.318309886f\n#define ONE_OVER_2_PI        0.159154943f\n#define ONE_OVER_4_PI        0.079577472f\n#define TWO_OVER_PI          0.636619772f\n#define FLT_MIN              1.175494351e-38 \n#define FLT_MAX              3.402823466e+38 \n#define FLT16_MAX            65504 \n#define UINT8_MAX            0xffu\n#define UINT16_MAX           0xffffu\n#define UINT32_MAX           0xffffffffu\n\nnamespace Math\n{\n    // Returns whether pos is in [0, dim).\n    template<typename T>\n    bool IsWithinBounds(T pos, T dim)\n    {\n        return all(pos >= 0) && all(pos < dim);\n    }\n\n    // Returns smallest float value f' such that f' > f.\n    float NextFloat32(float f)\n    {\n        if(f == -0.0f)\n            f = 0.0f;\n\n        uint u = asuint(f);\n        u = f >= 0 ? u + 1 : u - 1;\n    \n        return asfloat(u);\n    }\n\n    // Returns largest float value f' such that f' < f.\n    float PrevFloat32(float f)\n    {\n        if(f == 0.0f)\n            f = -0.0f;\n\n        uint u = asuint(f);\n        u = f > 0 ? u - 1 : u + 1;\n    \n        return asfloat(u);\n    }\n\n    uint RoundUpToPowerOf2(uint x)\n    {\n        x--;\n        x |= x >> 1;\n        x |= x >> 2;\n        x |= x >> 4;\n        x |= x >> 8;\n        x |= x >> 16;\n        x++;\n\n        return x;\n    }\n\n    template<typename T>\n    T Lerp(T v0, T v1, float t) \n    {\n        return mad(t, v1, mad(-t, v0, v0));\n    }\n\n    template<typename T>\n    T Sanitize(T x)\n    {\n        return any(isnan(x)) || any(isinf(x)) ? 0 : x;\n    }\n\n    float3x3 Inverse(float3x3 M)\n    {\n        // Given 3x3 matrix M = [u, v, w] where u,v,w are column vectors, M^(-1) is given by\n        //        M^(-1) = [a b c]^T\n        //\n        // where \n        //        a = (v * w) / u.(v * w)\n        //        b = (w * u) / u.(v * w)\n        //        c = (u * v) / u.(v * w)        \n        const float3 u = float3(M._11, M._21, M._31);\n        const float3 v = float3(M._12, M._22, M._32);\n        const float3 w = float3(M._13, M._23, M._33);\n\n        const float3 vCrossW = cross(v, w);\n        const float det = dot(u, vCrossW);\n\n        const float3 a = vCrossW / det;\n        const float3 b = cross(w, u) / det;\n        const float3 c = cross(u, v) / det;\n\n        return float3x3(a, b, c);\n    }\n\n    // Input in [-1, 1] and output in [0, PI]\n    // Ref: https://seblagarde.wordpress.com/2014/12/01/inverse-trigonometric-functions-gpu-optimization-for-amd-gcn-architecture/\n    template<typename T>\n    T ArcCos(T x)\n    {\n        T xAbs = abs(x);\n        T res = mad(-0.0206453f, xAbs, 0.0764532f);\n        res = mad(res, xAbs, -0.21271f);\n        res = mad(res, xAbs, 1.57075f);\n        res *= sqrt(1.0f - xAbs);\n\n        return select((x >= 0), res, PI - res);\n    }\n\n    float3 SphericalToCartesian(float r, float theta, float phi)\n    {\n        float sinTheta = sin(theta);\n        return float3(r * sinTheta * cos(phi), r * cos(theta), -r * sinTheta * sin(phi));\n    }\n\n    float2 SphericalFromCartesian(float3 w)\n    {\n        float2 thetaPhi;\n\n        // x = sin(theta) * cos(phi)\n        // y = cos(theta)\n        // z = -sin(theta) * sin(phi)\n        thetaPhi.x = ArcCos(w.y);\n        // phi is measured clockwise from the x-axis and atan2 uses the sign to figure out the quadrant\n        thetaPhi.y = atan2(-w.z, w.x);                                    // [-PI, +PI]\n        thetaPhi.y = thetaPhi.y < 0 ? thetaPhi.y + TWO_PI : thetaPhi.y;   // [0, 2 * PI]\n\n        return thetaPhi;\n    }\n\n    float TriangleArea(float3 v0, float3 v1, float3 v2)\n    {\n        return 0.5f * length(cross(v1 - v0, v2 - v0));\n    }\n\n    // Returns -1.0 when v < 0 and +1.0 otherwise\n    template<typename T>\n    T SignNotZero(T v) \n    {\n        return select(v >= 0, +1.0f, -1.0f);\n    }\n\n    template<>\n    float SignNotZero(float x)\n    {\n        // asfloat(0x3f800000) = +1.0 \n        // asfloat(0x80000000) = -0.0 \n        uint s = 0x3f800000 | (0x80000000 & asuint(x));\n        return asfloat(s);\n    }\n\n    template<typename T>\n    T LinearDepthFromNDC(T z_NDC, float near)\n    {\n        return select(z_NDC == 0.0f, FLT_MAX, near / z_NDC);\n    }\n\n    float2 NDCFromUV(float2 uv)\n    {\n        float2 ndc = uv * 2.0f - 1.0f;\n        ndc.y = -ndc.y;\n\n        return ndc;\n    }\n\n    float2 UVFromNDC(float2 ndc)\n    {\n        return ndc * float2(0.5, -0.5) + 0.5f;\n    }\n\n    float2 ScreenSpaceFromNDC(float2 ndc, float2 renderDim)\n    {\n        // [-1, 1] * [-1, 1] -> [0, 1] * [0, 1]\n        float2 posSS = ndc * float2(0.5f, -0.5f) + 0.5f;\n        posSS *= renderDim;\n\n        return posSS;\n    }\n\n    float2 UVFromScreenSpace(uint2 posSS, float2 renderDim)\n    {\n        float2 uv = float2(posSS) + 0.5f;\n        uv /= renderDim;\n\n        return uv;\n    }\n\n    float3 WorldPosFromUV(float2 uv, float2 renderDim, float z_view, float tanHalfFOV, \n        float aspectRatio, float3x4 viewInv, float2 jitter)\n    {\n        float2 ndc = NDCFromUV(uv) + jitter / renderDim;\n        float3 dir_v = float3(ndc.x * aspectRatio * tanHalfFOV * z_view, \n            ndc.y * tanHalfFOV * z_view, \n            z_view);\n        float3 pos_w = mul(viewInv, float4(dir_v, 1.0f));\n\n        return pos_w;\n    }\n\n    float3 WorldPosFromScreenSpace(float2 pos_ss, float2 renderDim, float z_view, float tanHalfFOV,\n        float aspectRatio, float3x4 viewInv, float2 jitter)\n    {\n        float2 uv = (pos_ss + 0.5f + jitter) / renderDim;\n        float2 ndc = NDCFromUV(uv);\n        float3 dir_v = float3(ndc.x * aspectRatio * tanHalfFOV * z_view, \n            ndc.y * tanHalfFOV * z_view, \n            z_view);\n        float3 pos_w = mul(viewInv, float4(dir_v, 1.0f));\n\n        return pos_w;\n    }\n\n    float3 WorldPosFromScreenSpace2(float2 pos_ss, float2 renderDim, float z_view, float tanHalfFOV,\n        float aspectRatio, float2 jitter, float3 viewBasisX, float3 viewBasisY, float3 viewBasisZ, \n        bool thinLens, float2 lensSample, float focusDepth, inout float3 origin)\n    {\n        float2 uv = (pos_ss + 0.5f + jitter) / renderDim;\n        float2 ndc = NDCFromUV(uv);\n        float3 dir_w;\n\n        if(!thinLens)\n        {\n            float3 dir_v = float3(ndc.x * aspectRatio * tanHalfFOV * z_view, \n                ndc.y * tanHalfFOV * z_view, \n                z_view);\n            dir_w = mad(dir_v.x, viewBasisX, mad(dir_v.y, viewBasisY, dir_v.z * viewBasisZ));\n        }\n        else\n        {\n            float3 dir_v = float3(ndc.x * aspectRatio * tanHalfFOV, ndc.y * tanHalfFOV, 1);\n            float3 focalPoint = focusDepth * dir_v;\n            dir_v = focalPoint - float3(lensSample, 0);\n\n            dir_w = mad(dir_v.x, viewBasisX, mad(dir_v.y, viewBasisY, dir_v.z * viewBasisZ));\n            dir_w = normalize(dir_w);\n            // For thin lens, z_view = t_hit\n            dir_w *= z_view;\n\n            origin += mad(lensSample.x, viewBasisX, lensSample.y * viewBasisY);\n        }\n\n        return origin + dir_w;\n    }\n\n    float2 UVFromWorldPos(float3 posW, float2 renderDim, float tanHalfFOV, float aspectRatio, \n        float3x4 view, float2 jitter = 0.0)\n    {\n        float3 posV = mul(view, float4(posW, 1.0f));\n        float2 ndc = posV.xy / (tanHalfFOV * posV.z);\n        ndc.x /= aspectRatio;\n\n        float2 uv = Math::UVFromNDC(ndc);\n        uv += jitter / renderDim;\n\n        return uv;\n    }\n\n    float3 TangentSpaceToWorldSpace(float2 bumpNormal2, float3 tangent, float3 normal, float scale)\n    {\n        float3 bumpNormal = float3(mad(2.0f, bumpNormal2, -1.0f), 0.0f);\n        bumpNormal.z = sqrt(saturate(1.0f - dot(bumpNormal, bumpNormal)));\n        float3 scaledBumpNormal = bumpNormal * float3(scale, scale, 1.0f);\n\n        // Invalid scale or bump, normalize() leads to NaN\n        if (dot(scaledBumpNormal, scaledBumpNormal) < 1e-6f)\n            return normal;\n\n        scaledBumpNormal = normalize(scaledBumpNormal);\n\n        // Graham-Schmidt orthogonalization\n        normal = normalize(normal);\n        tangent = normalize(tangent - dot(tangent, normal) * normal);\n\n        // Change-of-coordinate transformation from TBN to world space\n        float3 bitangent = cross(normal, tangent);\n        float3x3 TangentSpaceToWorld = float3x3(tangent, bitangent, normal);\n\n        return mul(scaledBumpNormal, TangentSpaceToWorld);\n    }\n\n    // Builds an orthonormal coordinate system.\n    // Ref: T. Duff, J. Burgess, P. Christensen, C. Hery, A. Kensler, M. Liani, \n    // R. Villemin, \"Building an Orthonormal Basis, Revisited,\" Journal of Computer Graphics Techniques, 2017.\n    struct CoordinateSystem\n    {\n        static CoordinateSystem Build(float3 n)\n        {\n            const float s = SignNotZero(n.z);\n            const float a = -1.0 / (s + n.z);\n            const float b = n.x * n.y * a;\n\n            CoordinateSystem ret;\n            ret.b1 = float3(mad(n.x * a, n.x * s, 1.0f), s * b, -s * n.x);\n            ret.b2 = float3(b, mad(n.y * a, n.y, s), -n.y);\n\n            return ret;\n        }\n\n        float3 b1;\n        float3 b2;\n    };\n\n    float3 WorldToTangentFrame(float3 normal, float3 w)\n    {\n        CoordinateSystem onb = CoordinateSystem::Build(normal);\n        float3x3 worldToLocal = float3x3(onb.b1, onb.b2, normal);\n\n        return mul(worldToLocal, w);\n    }\n\n    float3 FromTangentFrameToWorld(float3 normal, float3 w_local)\n    {\n        CoordinateSystem onb = CoordinateSystem::Build(normal);\n        float3x3 localToWorld_T = float3x3(onb.b1, onb.b2, normal);\n\n        return mul(w_local, localToWorld_T);\n    }\n\n    // Ref: M. Pharr, W. Jakob, and G. Humphreys, Physically Based Rendering, Morgan Kaufmann, 2016.\n    struct TriDifferentials\n    {\n        static TriDifferentials Unpack(uint4 packed_a, uint2 packed_b)\n        {\n            TriDifferentials ret;\n\n            ret.dpdu = asfloat16(uint16_t3(packed_a.x & 0xffff, packed_a.x >> 16, packed_a.y & 0xffff));\n            ret.dpdv = asfloat16(uint16_t3(packed_a.y >> 16, packed_a.z & 0xffff, packed_a.z >> 16));\n            ret.dndu = asfloat16(uint16_t3(packed_a.w & 0xffff, packed_a.w >> 16, packed_b.x & 0xffff));\n            ret.dndv = asfloat16(uint16_t3(packed_b.x >> 16, packed_b.y & 0xffff, packed_b.y >> 16));\n\n            return ret;\n        }\n\n        static TriDifferentials Compute(float3 p0, float3 p1, float3 p2, \n            float3 n0, float3 n1, float3 n2,\n            float2 uv0, float2 uv1, float2 uv2)\n        {\n            TriDifferentials ret;\n\n            // For triangle with vertices (p0, p1, p2) and UV coords\n            // (uv0, uv1, uv2) (CW), we have the following first-order\n            // representation:\n            //          A             =       X                     B\n            // |                 |      |           |    |                     |\n            // | p1 - p0 p2 - p0 |    = | dpdu dpdv |    | uv1 - uv0 uv2 - uv0 |\n            // |                 |3x3   |           |3x2 |                     |2x3\n            // \n            // We know A and B and can solve for X.\n            float2 duv10 = uv1 - uv0;\n            float2 duv20 = uv2 - uv0;\n            float det = duv10.x * duv20.y - duv10.y * duv20.x;\n            float invdet = 1.0 / det;\n\n            if (abs(det) < 1e-7f)\n            {\n                float3 normal = normalize(cross(p1 - p0, p2 - p0));\n                CoordinateSystem onb = CoordinateSystem::Build(normal);\n                ret.dpdu = onb.b1;\n                ret.dpdv = onb.b2;\n                ret.dndu = 0;\n                ret.dndv = 0;\n\n                return ret;\n            }\n\n            // dpdu\n            float3 dp10 = p1 - p0;\n            float3 dp20 = p2 - p0;\n            ret.dpdu = (duv20.y * dp10 - duv10.y * dp20) * invdet;\n            ret.dpdv = (-duv20.x * dp10 + duv10.x * dp20) * invdet;\n            // dndu\n            float3 dn10 = n1 - n0;\n            float3 dn20 = n2 - n0;\n            ret.dndu = (duv20.y * dn10 - duv10.y * dn20) * invdet;\n            ret.dndv = (-duv20.x * dn10 + duv10.x * dn20) * invdet;\n\n            return ret;\n        }\n\n        float3 dpdu;\n        float3 dpdv;\n        float3 dndu;\n        float3 dndv;\n    };\n\n    float4 RotationQuaternion(float3 axis, float theta)\n    {\n        float s = sin(0.5f * theta);\n        float c = cos(0.5f * theta);\n        return float4(s * axis, c);\n    }\n\n    float4 RotationQuaternion_Acute(float3 axis, float theta)\n    {\n        float s = sin(0.5f * theta);\n        float c = sqrt(1 - s * s);\n        return float4(s * axis, c);\n    }\n\n    float4 InverseRotationQuaternion(float4 quat)\n    {\n        return float4(-quat.xyz, quat.w);\n    }\n\n    // Returns rotation quaternion that aligns u to v. u and v are assumed to be normalized.\n    float4 QuaternionFromUtoV(float3 u, float3 v, float thresh = 1e-6)\n    {\n        float4 q;\n        float udotv = dot(u, v);\n\n        // u = -v is a singularity\n        if (udotv < thresh - 1.0f)\n        {\n            float3 imaginary = cross(v, u);\n            float real = udotv + 1.0f;\n            q = normalize(float4(imaginary, real));\n        }\n        else\n        {\n            float3 p = cross(u, v);\n\n            // rotate 180/2 = 90 degrees\n            q = float4(p, 0.0f);\n\n            // p is already normalized, so no need to normalize q\n        }\n\n        return q;\n    }\n\n    // Quaternion that rotates +Y to u. Assumes ||u|| = 1.\n    float4 QuaternionFromY(float3 u)\n    {\n        float4 q;\n        float real = 1.0f + u.y;\n\n        // u = (0, -1, 0) is a singularity\n        if (real > 1e-6)\n        {\n            float3 yCrossU = float3(u.z, 0.0f, -u.x);\n            q = float4(yCrossU, real);\n            q = normalize(q);\n        }\n        else\n        {\n            // Rotate 180 degrees around the X-axis (Z-axis works too since both are orthogonal to Y)\n            //\n            // Rotation quaternion = (n_x * s, n_y * s, n_z * s, c)\n            // where\n            //        n = (1, 0, 0)\n            //        s = sin(theta/2) = sin(90) = 1 and c = cos(theta/2) = cos(90) = 0\n            q = float4(1.0f, 0.0f, 0.0f, 0.0f);\n\n            // No need to normalize q\n        }\n\n        return q;\n    }\n    \n    // Quaternion that rotates u to +Y. Assumes ||u|| = 1.\n    float4 QuaternionToY(float3 u)\n    {\n        float4 q;\n        float real = 1.0f + u.y;\n\n        // u = (0, 0, -1) is a singularity\n        if (real > 1e-6)\n        {\n            float3 uCrossY = float3(-u.z, 0.0f, u.x);\n            q = float4(uCrossY, real);\n            q = normalize(q);\n        }\n        else\n        {\n            // Rotate 180 degrees around the X-axis (Y-axis works too since both are orthogonal to Z)\n            //\n            // Rotation quaternion = (n_x * s, n_y * s, n_z * s, c)\n            // where\n            //        n = (1, 0, 0)\n            //        s = sin(theta/2) = sin(90) = 1 and c = cos(theta/2) = cos(90) = 0\n            q = float4(1.0f, 0.0f, 0.0f, 0.0f);\n\n            // No need to normalize q\n        }\n\n        return q;\n    }\n\n    // Quaternion that rotates +Z to u. Assumes ||u|| = 1.\n    float4 QuaternionFromZ(float3 u)\n    {\n        float4 q;\n        float real = 1.0f + u.z;\n\n        // u = (0, 0, -1) is a singularity\n        if (real > 1e-6)\n        {\n            float3 zCrossU = float3(-u.y, u.x, 0);\n            q = float4(zCrossU, real);\n            q = normalize(q);\n        }\n        else\n        {\n            // Rotate 180 degrees around the X-axis (Y-axis works too since both are orthogonal to Z)\n            //\n            // Rotation quaternion = (n_x * s, n_y * s, n_z * s, c)\n            // where\n            //        n = (1, 0, 0)\n            //        s = sin(theta/2) = sin(90) = 1 and c = cos(theta/2) = cos(90) = 0\n            q = float4(1.0f, 0.0f, 0.0f, 0.0f);\n\n            // No need to normalize q\n        }\n\n        return q;\n    }\n\n    // Quaternion that rotates u to +Z. Assumes ||u|| = 1.\n    float4 QuaternionToZ(float3 u)\n    {\n        float4 q;\n        float real = 1.0f + u.z;\n\n        // u = (0, 0, -1) is a singularity\n        if (real > 1e-6)\n        {\n            float3 uCrossZ = float3(u.y, -u.x, 0);\n            q = float4(uCrossZ, real);\n            q = normalize(q);\n        }\n        else\n        {\n            // Rotate 180 degrees around the X-axis (Y-axis works too since both are orthogonal to Z)\n            //\n            // Rotation quaternion = (n_x * s, n_y * s, n_z * s, c)\n            // where\n            //        n = (1, 0, 0)\n            //        s = sin(theta/2) = sin(90) = 1 and c = cos(theta/2) = cos(90) = 0\n            q = float4(1.0f, 0.0f, 0.0f, 0.0f);\n\n            // No need to normalize q\n        }\n\n        return q;\n    }\n\n    // Rotates v using unit quaternion q by computing q * u * q* where\n    //        * denotes quaternion multiplication\n    //        q* is the conjugate of q.\n    // Ref: https://fgiesen.wordpress.com/2019/02/09/rotating-a-single-vector-using-a-quaternion/\n    float3 RotateVector(float3 v, float4 q)\n    {\n        float3 imaginary = q.xyz;\n        float real = q.w;\n\n        float3 t = cross(2 * imaginary, v);\n        float3 rotated = v + real * t + cross(imaginary, t);\n        \n        return rotated;\n    }\n\n    float3 TransformTRS(float3 pos, float3 translation, float4 rotation, float3 scale)\n    {\n        float3 transformed = pos * scale;\n        transformed = Math::RotateVector(transformed, rotation);\n        transformed += translation;\n\n        return transformed;\n    }\n\n    float3 InverseTransformTRS(float3 pos, float3 translation, float4 rotation, float3 scale)\n    {\n        float3 transformed = pos - translation;\n        float4 q_conjugate = float4(-rotation.xyz, rotation.w);\n        transformed = Math::RotateVector(transformed, q_conjugate);\n        transformed *= 1.0f / scale;\n\n        return transformed;\n    }\n\n    uint FloatToUNorm8(float f)\n    {\n        f = saturate(f);\n        return (uint)mad(f, 255.0f, 0.5f);\n    }\n\n    float UNorm8ToFloat(uint u)\n    {\n        return u / 255.0f;\n    }\n\n    uint16_t FloatToUNorm16(float f)\n    {\n        f = saturate(f);\n        return (uint16_t)mad(f, float((1 << 16) - 1), 0.5f);\n    }\n\n    float UNorm16ToFloat(uint16_t u)\n    {\n        return u / (float)((1 << 16) - 1);\n    }\n\n    uint16_t2 UnpackUintToUint16(uint x)\n    {\n        return uint16_t2(x & 0xffff, x >> 16);\n    }\n\n    uint PackUint16_2ToUint(uint16_t2 e)\n    {\n        return e.x | (uint(e.y) << 16);\n    }\n\n    uint16_t2 EncodeAsUNorm2(float2 u)\n    {\n        u = saturate(u);\n        return (uint16_t2)mad(u, float((1 << 16) - 1), 0.5f);\n    }\n\n    float2 DecodeUNorm2(uint16_t2 u)\n    {\n        return u / float((1 << 16) - 1);\n    }\n\n    float4 DecodeNormalized4(uint16_t4 u)\n    {\n        float4 decoded = u / float((1 << 16) - 1);\n        // [0, 1] -> [-1, 1]\n        return mad(decoded, 2.0f, -1.0f);\n    }\n\n    // Encodes 3D unit vector using octahedral mapping.\n    // Ref: https://knarkowicz.wordpress.com/2014/04/16/octahedron-normal-vector-encoding/\n    float2 EncodeUnitVector(float3 n)\n    {\n        float2 p = n.xy / (abs(n.x) + abs(n.y) + abs(n.z));\n        float2 encoded = (n.z <= 0.0) ? ((1.0 - abs(p.yx)) * SignNotZero(p)) : p;\n        // [-1, 1] -> [0, 1]\n        return mad(encoded, 0.5f, 0.5f);\n    }\n\n    float3 DecodeUnitVector(float2 u)\n    {\n        // [0, 1] -> [-1, 1]\n        u = mad(u, 2.0f, -1.0f);\n\n        // https://twitter.com/Stubbesaurus/status/937994790553227264\n        float3 n = float3(u.x, u.y, 1.0f - abs(u.x) - abs(u.y));\n        float t = saturate(-n.z);\n        //n.xy += n.xy >= 0.0f ? -t : t;\n        n.xy += select(n.xy >= 0.0f, -t, t);\n\n        return normalize(n);\n    }\n\n    uint16_t2 EncodeOct32(float3 n)\n    {\n        float2 u = EncodeUnitVector(n);\n        return EncodeAsUNorm2(u);\n    }\n\n    uint32_t EncodeOct32u(float3 n)\n    {\n        float2 u = EncodeUnitVector(n);\n        uint16_t2 un = EncodeAsUNorm2(u);\n\n        return un.x | (uint(un.y) << 16);\n    }\n\n    float3 DecodeOct32(uint16_t2 e)\n    {\n        float2 u = DecodeUNorm2(e);\n        return DecodeUnitVector(u);\n    }\n\n    // Octahedral encoding for unit vector in upper hemisphere (n.y >= 0)\n    float2 EncodeUnitHemisphereVector(float3 n)\n    {\n        float2 p = n.xz / (abs(n.x) + abs(n.y) + abs(n.z));\n        return p;\n    }\n\n    float3 DecodeUnitHemisphereVector(float2 u)\n    {\n        float3 n = float3(u.x, 1.0f - abs(u.x) - abs(u.y), u.y);\n        return normalize(n);\n    }\n\n    float Luminance(float3 linearRGB)\n    {\n        return dot(float3(0.2126f, 0.7152f, 0.0722f), linearRGB);\n    }\n\n    float3 LinearTosRGB(float3 color)\n    {\n        float3 sRGBLo = color * 12.92;\n        float3 sRGBHi = pow(saturate(color), 1.0f / 2.4f) * 1.055f - 0.055f;\n        float3 sRGB = select((color <= 0.0031308f), sRGBLo, sRGBHi);\n\n        return sRGB;\n    }\n\n    float3 sRGBToLinear(float3 color)\n    {\n        float3 linearRGBLo = color / 12.92f;\n        float3 linearRGBHi = pow(max((color + 0.055f) / 1.055f, 0.0f), 2.4f);\n        float3 linearRGB = select(color <= 0.0404499993f, linearRGBLo, linearRGBHi);\n\n        return linearRGB;\n    }\n\n    float3 LinearToYCbCr(float3 x)\n    {\n        float3x3 M = float3x3(0.2126, 0.7152, 0.0722,\n                             -0.1146, -0.3854, 0.5,\n                              0.5, -0.4542, -0.0458);\n        return mul(M, x);\n    }\n\n    float2 UnpackRG(uint rg)\n    {\n        float2 ret;\n        ret.x = float(rg & 0xff) / 255.0f;\n        ret.y = float((rg >> 8) & 0xff) / 255.0f;\n\n        return ret;\n    }\n\n    float3 UnpackRGB8(uint rgb)\n    {\n        float3 ret;\n        ret.x = float(rgb & 0xff) / 255.0f;\n        ret.y = float((rgb >> 8) & 0xff) / 255.0f;\n        ret.z = float((rgb >> 16) & 0xff) / 255.0f;\n\n        return ret;\n    }\n\n    float4 UnpackRGBA8(uint rgba)\n    {\n        float4 ret;\n        ret.x = float(rgba & 0xff) / 255.0f;\n        ret.y = float((rgba >> 8) & 0xff) / 255.0f;\n        ret.z = float((rgba >> 16) & 0xff) / 255.0f;\n        ret.w = float((rgba >> 24) & 0xff) / 255.0f;\n\n        return ret;\n    }\n\n    uint Float3ToRGB8(float3 v)\n    {\n        v = saturate(v);\n        uint3 u = (uint3)mad(v, 255.0f, 0.5f);\n        uint packed = u.x | (u.y << 8) | (u.z << 16);\n\n        return packed;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/Common/RT.hlsli",
    "content": "#ifndef RT_H\n#define RT_H\n\n#include \"../../ZetaCore/RayTracing/RtCommon.h\"\n#include \"Math.hlsli\"\n#include \"Sampling.hlsli\"\n\nnamespace RT\n{\n    // Ref: T. Akenine-Moller, J. Nilsson, M. Andersson, C. Barre-Brisebois, R. Toth \n    // and T. Karras, \"Texture Level of Detail Strategies for Real-Time Ray Tracing,\" in \n    // Ray Tracing Gems 1, 2019.\n    struct RayCone\n    {\n        static RayCone InitFromPrimaryHit(float pixelSpreadAngle, float t)\n        {\n            RayCone r;\n            r.Width = (half)(pixelSpreadAngle * t);\n            r.SpreadAngle = (half)(pixelSpreadAngle);\n\n            return r;\n        }\n\n        void NewHit(float t)\n        {\n            this.Width = (half)((float)this.Width + t * (float)this.SpreadAngle);\n        }\n\n        void UpdateConeGeometry_Refl(float curvature)\n        {\n            this.SpreadAngle = (half)((float)this.SpreadAngle + 2.0f * curvature);\n        }\n\n        void UpdateConeGeometry_Tr(float3 wo, float3 wi, float3 normal, float curvature, float eta, \n            float3 p, float3 origin, float3 origin_l, float3 origin_u)\n        {\n            // Form coordinate system around normal\n            float3 m = wo - dot(normal, wo) * normal;\n            m = normalize(m);\n            float3 u = cross(m, normal);\n\n            // Find off-axis cone directions\n            float4 quat = Math::RotationQuaternion_Acute(u, 0.5f * (float)this.SpreadAngle);\n            float4 quat_inv = Math::InverseRotationQuaternion(quat);\n\n            float3 d_u = Math::RotateVector(-wo, quat);\n            float3 d_l = Math::RotateVector(-wo, quat_inv);\n\n            // Find refraction of off-axis cone directions with perturbed normals\n            quat = Math::RotationQuaternion_Acute(u, curvature);\n            quat_inv = Math::InverseRotationQuaternion(quat);\n\n            float3 n_l = Math::RotateVector(normal, quat);\n            float3 n_u = Math::RotateVector(normal, quat_inv);\n\n            float3 t_u = refract(-wo, n_u, 1 / eta);\n            float3 t_l = refract(-wo, n_l, 1 / eta);\n\n            // Intersect off-axis cone directions with tangent plane around hit point\n            float pdotNormal = dot(normal, p);\n\n            float numerator_l = pdotNormal - dot(normal, origin_l);\n            float denom_l = dot(normal, d_l);\n            float dist_l = numerator_l / denom_l;\n            float3 p_l = origin_l + dist_l * d_l;\n\n            float numerator_u = pdotNormal - dot(normal, origin_u);\n            float denom_u = dot(normal, d_u);\n            float dist_u = numerator_u / denom_u;\n            float3 p_u = origin_u + dist_u * d_u;\n\n            float3 q = m - dot(m, wi) * wi;\n            q = normalize(q);\n            float newWidth = 0;\n\n            // Find intersection of rays p + wq and p_u + w_u t_u. Skip in case of TIR.\n            if(dot(t_u, t_u) != 0)\n            {\n                // Solve for x = (A^T A)^-1 A^T b where A = [t_u -q]\n                float3 b = p - p_u;\n                float tdotq = dot(t_u, q);\n                float det = 1 - tdotq * tdotq;\n                float3 A1 = float3(tdotq * t_u.x - q.x,\n                    tdotq * t_u.y - q.y,\n                    tdotq * t_u.z - q.z);\n                newWidth += det == 0 ? 0 : abs(dot(A1, b) / det);\n            }\n\n            // Find intersection of rays p + wq and p_l + w_l t_l. Skip in case of TIR.\n            if(dot(t_l, t_l) != 0)\n            {\n                // Solve for x = (A^T A)^-1 A^T b where A = [t_l -q]\n                float3 b = p - p_l;\n                float tdotq = dot(t_l, q);\n                float det = 1 - tdotq * tdotq;\n                float3 A1 = float3(tdotq * t_l.x - q.x,\n                    tdotq * t_l.y - q.y,\n                    tdotq * t_l.z - q.z);\n                newWidth += det == 0 ? 0 : abs(dot(A1, b) / det);\n            }\n\n            this.Width = (half)newWidth;\n            this.SpreadAngle = (half)(Math::ArcCos(dot(t_u, t_l)) * sign(t_u.x * t_l.y - t_u.y * t_l.x));\n        }\n\n        void UpdateConeGeometry_Tr_CurvatureIs0(float3 wo, float3 wi, float3 normal, float eta, \n            float3 p, float3 origin)\n        {\n            if(this.SpreadAngle == 0)\n                return;\n\n            float3 m = wo - dot(normal, wo) * normal;\n            m = normalize(m);\n            float3 u = cross(m, normal);\n\n            float4 quat = Math::RotationQuaternion_Acute(u, 0.5f * (float)this.SpreadAngle);\n            float4 quat_inv = Math::InverseRotationQuaternion(quat);\n\n            float3 d_u = Math::RotateVector(-wo, quat);\n            float3 d_l = Math::RotateVector(-wo, quat_inv);\n\n            float3 t_u = refract(d_u, normal, 1 / eta);\n            float3 t_l = refract(d_l, normal, 1 / eta);\n\n            float3 v = normal - dot(normal, wo) * wo;\n            v = normalize(v);\n            float3 origin_u = origin + v * this.Width;\n            float3 origin_l = origin - v * this.Width;\n            float pdotNormal = dot(normal, p);\n\n            float numerator_l = pdotNormal - dot(normal, origin_l);\n            float denom_l = dot(normal, d_l);\n            float dist_l = numerator_l / denom_l;\n            float3 p_l = origin_l + dist_l * d_l;\n\n            float numerator_u = pdotNormal - dot(normal, origin_u);\n            float denom_u = dot(normal, d_u);\n            float dist_u = numerator_u / denom_u;\n            float3 p_u = origin_u + dist_u * d_u;\n\n            float3 q = m - dot(m, wi) * wi;\n            q = normalize(q);\n\n            // Approximate solution but faster\n#if 1\n            float2 newWidth = float2(dot(p_u - p, q), dot(p_l - p, q));\n            newWidth *= newWidth;\n            newWidth = sqrt(newWidth);\n            this.Width = (half)(newWidth.x * (dot(t_u, t_u) != 0) + newWidth.y * (dot(t_l, t_l) != 0));\n\n            // Exact solution\n#else\n            float newWidth = 0;\n\n            if(dot(t_u, t_u) != 0)\n            {\n                float3 b = p - p_u;\n                float tdotq = dot(t_u, q);\n                float det = 1 - tdotq * tdotq;\n                float3 A1 = float3(tdotq * t_u.x - q.x,\n                    tdotq * t_u.y - q.y,\n                    tdotq * t_u.z - q.z);\n                newWidth += det == 0 ? 0 : abs(dot(A1, b) / det);\n            }\n\n            if(dot(t_l, t_l) != 0)\n            {\n                float3 b = p - p_l;\n                float tdotq = dot(t_l, q);\n                float det = 1 - tdotq * tdotq;\n                float3 A1 = float3(tdotq * t_l.x - q.x,\n                    tdotq * t_l.y - q.y,\n                    tdotq * t_l.z - q.z);\n                newWidth += det == 0 ? 0 : abs(dot(A1, b) / det);\n            }\n\n            this.Width = (half)newWidth;\n#endif\n\n            this.SpreadAngle = (half)(Math::ArcCos(dot(t_u, t_l)) * sign(t_u.x * t_l.y - t_u.y * t_l.x));\n        }\n\n        void UpdateConeGeometry_Tr_PrimaryHit(float3 wo, float3 wi, float3 normal, float curvature, float eta, \n            float3 hitPoint, float3 origin)\n        {\n            this.UpdateConeGeometry_Tr(wo, wi, normal, curvature, eta, hitPoint, origin, origin, origin);\n        }\n\n        void UpdateConeGeometry_Tr(float3 wo, float3 wi, float3 normal, float curvature, float eta, \n            float3 hitPoint, float3 origin)\n        {\n            float3 v = normal - dot(normal, wo) * normal;\n            v = normalize(v);\n            float3 origin_l = origin + v * this.Width;\n            float3 origin_u = origin - v * this.Width;\n\n            this.UpdateConeGeometry_Tr(wo, wi, normal, curvature, eta, hitPoint, origin, origin_l, origin_u);\n        }\n\n        static float Lambda(float3 v0, float3 v1, float3 v2, float2 t0, float2 t1, float2 t2, float ndotwo)\n        {\n            float P_a = length(cross((v1 - v0), (v2 - v0)));\n            float T_a = abs((t1.x - t0.x) * (t2.y - t0.y) - (t2.x - t0.x) * (t1.y - t0.y));\n\n            float lambda = T_a;\n            lambda /= (P_a * ndotwo * ndotwo);\n\n            return lambda;\n        }\n\n        float MipmapLevel(float lambda, float w, float h)\n        {\n            float mip = lambda * w * h * (float)this.Width * (float)this.Width;\n            return 0.5f * log2(mip);\n        }\n\n        half Width;\n        half SpreadAngle;\n    };\n\n    // basis*: Camera basis vectors in world-space coordinates\n    float3 GeneratePinholeCameraRay(uint2 pixel, float2 renderDim, float aspectRatio, float tanHalfFOV,\n        float3 viewBasisX, float3 viewBasisY, float3 viewBasisZ, float2 jitter)\n    {\n        float2 uv = (pixel + 0.5f + jitter) / renderDim;\n        float2 ndc = Math::NDCFromUV(uv);\n        float3 dirV = float3(ndc.x * aspectRatio * tanHalfFOV, ndc.y * tanHalfFOV, 1);\n        float3 dirW = mad(dirV.x, viewBasisX, mad(dirV.y, viewBasisY, dirV.z * viewBasisZ));\n\n        return normalize(dirW);\n    }\n\n    float3 GeneratePinholeCameraRay_CS(uint2 pixel, float2 renderDim, float aspectRatio, float tanHalfFOV, \n        float2 jitter)\n    {\n        float2 uv = (pixel + 0.5f + jitter) / renderDim;\n        float2 ndc = Math::NDCFromUV(uv);\n        float3 dirV = float3(ndc.x * aspectRatio * tanHalfFOV, ndc.y * tanHalfFOV, 1);\n\n        return dirV;\n    }\n\n    // Geometric Normal points outward for rays exiting the surface, else should be flipped.\n    // Ref: C. Wachter and N. Binder, \"A Fast and Robust Method for Avoiding Self-Intersection\", in Ray Tracing Gems 1, 2019.\n    float3 OffsetRayRTG(float3 pos, float3 geometricNormal)\n    {\n        static const float origin = 1.0f / 32.0f;\n        static const float float_scale = 1.0f / 65536.0f;\n        static const float int_scale = 256.0f;\n\n        int3 of_i = int_scale * geometricNormal;\n\n        float3 p_i = float3(asfloat(asint(pos.x) + ((pos.x < 0) ? -of_i.x : of_i.x)),\n            asfloat(asint(pos.y) + ((pos.y < 0) ? -of_i.y : of_i.y)),\n            asfloat(asint(pos.z) + ((pos.z < 0) ? -of_i.z : of_i.z)));\n\n        float3 adjusted = float3(abs(pos.x) < origin ? pos.x + float_scale * geometricNormal.x : p_i.x,\n            abs(pos.y) < origin ? pos.y + float_scale * geometricNormal.y : p_i.y,\n            abs(pos.z) < origin ? pos.z + float_scale * geometricNormal.z : p_i.z);\n        \n        return adjusted;\n    }\n\n    float3 OffsetRay2(float3 origin, float3 dir, float3 normal, float minNormalBias = 5e-6f, \n        float maxNormalBias = 1e-4)\n    {\n        const float maxBias = max(minNormalBias, maxNormalBias);\n        const float normalBias = lerp(maxBias, minNormalBias, saturate(dot(normal, dir)));\n\n        return origin + dir * normalBias;\n    }\n\n    // Returns (n_1 p_1) / (n_1 p_1 + n_2 p_2) * f / p_1\n    template<typename T>\n    T BalanceHeuristic(float p_1, float p_2, T f, float n_1 = 1, float n_2 = 1)\n    {\n        float denom = n_1 * p_1 + n_2 * p_2;\n        if(denom == 0)\n            return 0;\n\n        return (n_1 * f) / denom;\n    }\n\n    // Returns (n_1 p_1) / (n_1 p_1 + n_2 p_2 + n_3 p_3) * f / p_1\n    template<typename T>\n    T BalanceHeuristic3(float p_1, float p_2, float p_3, T f, float n_1 = 1, float n_2 = 1, \n        float n_3 = 1)\n    {\n        float denom = n_1 * p_1 + n_2 * p_2 + n_3 * p_3;\n        if(denom == 0)\n            return 0;\n\n        return (n_1 * f) / denom;\n    }\n\n    // Returns (n_1 p_1)^2 / ((n_1 p_1)^2 + (n_2 p_2)^2) * f / p_1\n    template<typename T>\n    T PowerHeuristic(float p_1, float p_2, T f, float n_1 = 1, float n_2 = 1)\n    {\n        float a = n_1 * p_1;\n        float b = n_2 * p_2;\n        float denom = a * a + b * b;\n        if(denom == 0)\n            return 0;\n\n        return ((n_1 * n_1 * p_1 * f) / denom);\n    }\n\n    struct RayDifferentials\n    {\n        static RayDifferentials Init()\n        {\n            RayDifferentials ret;\n            ret.origin_x = 0;\n            ret.dir_x = 0;\n            ret.origin_y = 0;\n            ret.dir_y = 0;\n            ret.uv_grads = 0;\n\n            return ret;\n        }\n\n        static RayDifferentials Init(int2 DTid, float2 renderDim, float tanHalfFOV, \n            float aspectRatio, float2 jitter, float3 viewBasis_x, float3 viewBasis_y, \n            float3 viewBasis_z, bool thinLens, float focusDepth, float2 lensSample, \n            float3 origin)\n        {\n            RayDifferentials ret;\n\n            float3 dir_cs_x = RT::GeneratePinholeCameraRay_CS(int2(DTid.x + 1, DTid.y), \n                renderDim, aspectRatio, tanHalfFOV, jitter);\n            float3 dir_cs_y = RT::GeneratePinholeCameraRay_CS(int2(DTid.x, DTid.y - 1), \n                renderDim, aspectRatio, tanHalfFOV, jitter);\n\n            if(thinLens)\n            {\n                float3 focalPoint_x = focusDepth * dir_cs_x;\n                dir_cs_x = focalPoint_x - float3(lensSample, 0);\n\n                float3 focalPoint_y = focusDepth * dir_cs_y;\n                dir_cs_y = focalPoint_y - float3(lensSample, 0);\n            }\n\n            ret.dir_x = normalize(mad(dir_cs_x.x, viewBasis_x, \n                mad(dir_cs_x.y, viewBasis_y, dir_cs_x.z * viewBasis_z)));\n            ret.dir_y = normalize(mad(dir_cs_y.x, viewBasis_x, \n                mad(dir_cs_y.y, viewBasis_y, dir_cs_y.z * viewBasis_z)));\n\n            ret.origin_x = origin;\n            ret.origin_y = origin;\n\n            return ret;\n        }\n\n        // At each hit point, provides an estimate of how hit position changes w.r.t. one pixel\n        // screen movement, e.g. for one pixel horizontal movement:\n        //      (p_x - p) ~= (dpdx, dpdy).(dx, dy)\n        //                = (dpdx, dpdy).(1, 0)\n        //                = dpdx\n        // where p_x is offset ray's hit point. To estimate p_x, compute the \"virtual\" intersection\n        // with the tangent plane at the actual hit point of the main ray.\n        void dpdx_dpdy(float3 hitPoint, float3 normal, out float3 dpdx, out float3 dpdy)\n        {\n            float d = dot(normal, hitPoint);\n\n            // Intersection with tangent plan\n            float numerator_x = d - dot(normal, this.origin_x);\n            float denom_x = dot(normal, this.dir_x);\n            float t_x = numerator_x / denom_x;\n            float3 hitPoint_x = mad(t_x, dir_x, this.origin_x);\n\n            float numerator_y = d - dot(normal, this.origin_y);\n            float denom_y = dot(normal, this.dir_y);\n            float t_y = numerator_y / denom_y;\n            float3 hitPoint_y = mad(t_y, dir_y, this.origin_y);\n\n            // If ray is parallel to tangent plane, set differential to a large value,\n            // so that the highest mip would be used. From this point on, this\n            // differential is undefined.\n            dpdx = denom_x != 0 ? hitPoint_x - hitPoint : FLT16_MAX;\n            dpdy = denom_y != 0 ? hitPoint_y - hitPoint : FLT16_MAX;\n            // dpdx = denom_x != 0 ? hitPoint_x - hitPoint : 0;\n            // dpdy = denom_y != 0 ? hitPoint_y - hitPoint : 0;\n        }\n\n        // Notes: \n        //  - Assumes normal and wo are in the hemisphere\n        //  - eta: Relative IOR of wi's medium to wo's medium\n        void UpdateRays(float3 p, float3 normal, float3 wi, float3 wo, \n            Math::TriDifferentials triDiffs, float3 dpdx, float3 dpdy, \n            bool transmitted, float eta)\n        {\n            // First-order approximation of position\n            this.origin_x = p + dpdx;\n            this.origin_y = p + dpdy;\n\n            float3 dwodx = -this.dir_x - wo;\n            float3 dwody = -this.dir_y - wo;\n            // Chain rule: \n            //      dndx = dndu * dudx + dndv * dvdx\n            //      dndy = dndu * dudy + dndv * dvdy\n            float3 dndx = triDiffs.dndu * uv_grads.x + triDiffs.dndv * uv_grads.y;\n            float3 dndy = triDiffs.dndu * uv_grads.z + triDiffs.dndv * uv_grads.w;\n            // For vector-valued expressions a and b: (a.b)' = a'.b + a.b'.\n            // Then, d(n.wo)dx = (dndx).wo + n.(dwodx)\n            float dndotWodx = dot(dndx, wo) + dot(normal, dwodx);\n            float dndotWody = dot(dndy, wo) + dot(normal, dwody);\n            float ndotwo = dot(normal, wo);\n\n            if(!transmitted)\n            {\n                // Law of specular reflection: wi = -wo + 2(n.wo)n\n                // dwidx = -dwodx + 2[d(n.wo)dx n + (n.wo) dndx]\n                this.dir_x = wi + mad(2.0f, mad(dndotWodx, normal, ndotwo * dndx), -dwodx);\n                this.dir_y = wi + mad(2.0f, mad(dndotWody, normal, ndotwo * dndy), -dwody);\n            }\n            else\n            {\n                // Let eta be relative IOR of wo's medium to wi's medium, then\n                //      wi = -eta wo + qn \n                // where q = eta (n.wo) - cos(theta_i).\n                //\n                // Taking the partial derivative w.r.t. x,\n                //      dwidx = -eta dwodx + dqdx n + q dndx\n                // and\n                //      dqdx = eta d(n.wo)dx - d(cos theta_i)dx\n                //      d(cos theta_i)dx = (n.wo) d(n.wo)dx / eta^2 cos(theta_i)\n                // After simplifying \n                //      dqdx = eta d(n.wo)dx - (n.wo) d(n.wo)dx / eta^2 cos(theta_i)\n                //           = d(n.wo)dx (eta - (n.wo) / eta^2 cos(theta_i))\n                float eta_relative = 1.0f / eta;\n                float ndotwi = abs(dot(normal, wi));\n\n                float q = mad(eta_relative, ndotwo, -ndotwi);\n                float common = mad(eta_relative, -ndotwo / ndotwi, 1.0f);\n                float dqdx = eta_relative * dndotWodx * common;\n                float dqdy = eta_relative * dndotWody * common;\n\n                this.dir_x = mad(-eta_relative, dwodx, wi) + mad(q, dndx, dqdx * normal);\n                this.dir_y = mad(-eta_relative, dwody, wi) + mad(q, dndy, dqdy * normal);\n            }\n        }\n\n        void ComputeUVDifferentials(float3 dpdx, float3 dpdy, float3 dpdu, float3 dpdv)\n        {\n            // determinant of square matrix A^T A\n            float dpduDotdpdu = dot(dpdu, dpdu);\n            float dpdvDotdpdv = dot(dpdv, dpdv);\n            float dpduDotdpdv = dot(dpdu, dpdv);\n            float det = dpduDotdpdu * dpdvDotdpdv - dpduDotdpdv * dpduDotdpdv;\n            // A^T A is not invertible\n            if (abs(det) < 1e-7f)\n            {\n                this.uv_grads = 0;\n                return;\n            }\n\n            // division by determinant happens below\n            float2x2 A_T_A_Inv = float2x2(dpdvDotdpdv, -dpduDotdpdv,\n                                         -dpduDotdpdv, dpduDotdpdu);\n            float2 b_x = float2(dot(dpdu, dpdx), dot(dpdv, dpdx));\n            float2 grads_x = mul(A_T_A_Inv, b_x) / det;\n\n            float2 b_y = float2(dot(dpdu, dpdy), dot(dpdv, dpdy));\n            float2 grads_y = mul(A_T_A_Inv, b_y) / det;\n\n            bool invalid_x = (this.uv_grads.x == FLT16_MAX) || (dpdx.x == FLT16_MAX);\n            bool invalid_y = (this.uv_grads.z == FLT16_MAX) || (dpdy.x == FLT16_MAX);\n            this.uv_grads.xy = invalid_x ? FLT16_MAX : grads_x;\n            this.uv_grads.zw = invalid_y ? FLT16_MAX : grads_y;\n        }\n\n        float3 origin_x;\n        float3 dir_x;\n        float3 origin_y;\n        float3 dir_y;\n        // (ddx(uv), ddy(uv))\n        float4 uv_grads;\n    };\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/Common/RayQuery.hlsli",
    "content": "#ifndef RAY_QUERY_H\n#define RAY_QUERY_H\n\n#include \"RT.hlsli\"\n#include \"Common.hlsli\"\n#include \"FrameConstants.h\"\n#include \"StaticTextureSamplers.hlsli\"\n#include \"BSDF.hlsli\"\n\n#define T_MIN_REFL_RAY 1e-6\n#define T_MIN_TR_RAY 5e-5\n\nnamespace RtRayQuery\n{\n    struct Hit\n    {\n        template<bool ID, bool Curr>\n        static Hit FindClosest(float3 pos, float3 normal, float3 wi, RaytracingAccelerationStructure g_bvh, \n            StructuredBuffer<RT::MeshInstance> g_frameMeshData, StructuredBuffer<Vertex> g_vertices, \n            StructuredBuffer<uint> g_indices, bool transmissive)\n        {\n            Hit ret;\n            ret.hit = false;\n            ret.ID = UINT32_MAX;\n\n            float ndotwi = dot(normal, wi);\n            if(ndotwi == 0)\n                return ret;\n\n            bool wiBackface = ndotwi < 0;\n            if(wiBackface)\n            {\n                if(!transmissive)\n                    return ret;\n\n                normal = -normal;\n            }\n\n            const float3 adjustedOrigin = RT::OffsetRayRTG(pos, normal);\n\n            // Skip alpha testing for now\n            RayQuery<RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES | RAY_FLAG_FORCE_OPAQUE> rayQuery;\n\n            RayDesc ray;\n            ray.Origin = adjustedOrigin;\n            ray.TMin = wiBackface ? T_MIN_TR_RAY : T_MIN_REFL_RAY;\n            ray.TMax = FLT_MAX;\n            ray.Direction = wi;\n\n            rayQuery.TraceRayInline(g_bvh, RAY_FLAG_NONE, RT_AS_SUBGROUP::ALL, ray);\n            rayQuery.Proceed();\n            \n            if (rayQuery.CommittedStatus() == COMMITTED_TRIANGLE_HIT)\n            {\n                const uint meshIdx = rayQuery.CommittedGeometryIndex() + rayQuery.CommittedInstanceID();\n                const float2 bary = rayQuery.CommittedTriangleBarycentrics();\n\n                const RT::MeshInstance meshData = g_frameMeshData[NonUniformResourceIndex(meshIdx)];\n\n                ret.t = rayQuery.CommittedRayT();\n                ret.matIdx = meshData.MatIdx;\n                ret.meshIdx = meshIdx;\n\n                uint tri = rayQuery.CommittedPrimitiveIndex() * 3;\n                tri += meshData.BaseIdxOffset;\n                uint i0 = g_indices[NonUniformResourceIndex(tri)] + meshData.BaseVtxOffset;\n                uint i1 = g_indices[NonUniformResourceIndex(tri + 1)] + meshData.BaseVtxOffset;\n                uint i2 = g_indices[NonUniformResourceIndex(tri + 2)] + meshData.BaseVtxOffset;\n\n                Vertex V0 = g_vertices[NonUniformResourceIndex(i0)];\n                Vertex V1 = g_vertices[NonUniformResourceIndex(i1)];\n                Vertex V2 = g_vertices[NonUniformResourceIndex(i2)];\n\n                float3 t = Curr ? meshData.Translation : meshData.Translation - meshData.dTranslation;\n                float4 q = Math::DecodeNormalized4(Curr ? meshData.Rotation : meshData.PrevRotation);\n                float3 s = Curr ? meshData.Scale : meshData.PrevScale;\n                // Due to quantization, it's necessary to renormalize\n                q = normalize(q);\n\n                // Texture UV coords\n                float tmp = 1 - bary.x - bary.y;\n                float2 uv = mad(bary.y, V2.TexUV, tmp * V0.TexUV);\n                uv = mad(bary.x, V1.TexUV, uv);\n                ret.uv = uv;\n\n                // normal\n                float3 v0_n = Math::DecodeOct32(V0.NormalL);\n                float3 v1_n = Math::DecodeOct32(V1.NormalL);\n                float3 v2_n = Math::DecodeOct32(V2.NormalL);\n                float3 hitNormal = mad(bary.y, v2_n, tmp * v0_n);\n                hitNormal = mad(bary.x, v1_n, hitNormal);\n                // transform normal using the inverse transpose\n                // (M^-1)^T = ((SR)^-1)^T\n                //          = (R^-1 S^-1)^T\n                //          = (S^-1)^T (R^T)^T\n                //          = S^-1 R\n                const float3 scaleInv = 1.0f / s;\n                hitNormal *= scaleInv;\n                hitNormal = Math::RotateVector(hitNormal, q);\n                hitNormal = normalize(hitNormal);\n                ret.normal = hitNormal;\n\n                float3 v0W = Math::TransformTRS(V0.PosL, t, q, s);\n                float3 v1W = Math::TransformTRS(V1.PosL, t, q, s);\n                float3 v2W = Math::TransformTRS(V2.PosL, t, q, s);\n\n                float3 n0W = v0_n * scaleInv;\n                n0W = Math::RotateVector(n0W, q);\n                n0W = normalize(n0W);\n\n                float3 n1W = v1_n * scaleInv;\n                n1W = Math::RotateVector(n1W, q);\n                n1W = normalize(n1W);\n\n                float3 n2W = v2_n * scaleInv;\n                n2W = Math::RotateVector(n2W, q);\n                n2W = normalize(n2W);\n\n                ret.triDiffs = Math::TriDifferentials::Compute(v0W, v1W, v2W, \n                    n0W, n1W, n2W,\n                    V0.TexUV, V1.TexUV, V2.TexUV);\n\n                if(ID)\n                {\n                    uint3 key = uint3(rayQuery.CommittedGeometryIndex(), rayQuery.CommittedInstanceID(), \n                        rayQuery.CommittedPrimitiveIndex());\n                    ret.ID = RNG::PCG3d(key).x;\n                }\n\n                ret.hit = true;\n            }\n\n            return ret;\n        }\n\n        float t;\n        float2 uv;\n        float3 normal;\n        uint ID;\n        uint meshIdx;\n        bool hit;\n        Math::TriDifferentials triDiffs;\n        uint16_t matIdx;\n    };\n\n    struct Hit_Emissive\n    {\n        static Hit_Emissive FindClosest(float3 pos, float3 normal, float3 wi, \n            RaytracingAccelerationStructure g_bvh, StructuredBuffer<RT::MeshInstance> g_frameMeshData, \n            bool transmissive)\n        {\n            Hit_Emissive ret;\n            ret.hit = false;\n            ret.emissiveTriIdx = UINT32_MAX;\n\n            bool wiBackface = dot(normal, wi) <= 0;\n            if(wiBackface)\n            {\n                if(transmissive)\n                    normal *= -1;\n                else\n                    return ret;\n            }\n\n            const float3 adjustedOrigin = RT::OffsetRayRTG(pos, normal);\n\n            // Skip alpha testing for now\n            RayQuery<RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES | RAY_FLAG_FORCE_OPAQUE> rayQuery;\n\n            RayDesc ray;\n            ray.Origin = adjustedOrigin;\n            ray.TMin = wiBackface ? T_MIN_TR_RAY : T_MIN_REFL_RAY;\n            ray.TMax = FLT_MAX;\n            ray.Direction = wi;\n\n            rayQuery.TraceRayInline(g_bvh, RAY_FLAG_NONE, RT_AS_SUBGROUP::ALL, ray);\n            rayQuery.Proceed();\n\n            if (rayQuery.CommittedStatus() == COMMITTED_TRIANGLE_HIT)\n            {\n                ret.hit = true;\n                ret.bary = rayQuery.CommittedTriangleBarycentrics();\n                ret.t = rayQuery.CommittedRayT();\n                ret.geoIdx = rayQuery.CommittedGeometryIndex();\n                ret.insID = rayQuery.CommittedInstanceID();\n                ret.primIdx = rayQuery.CommittedPrimitiveIndex();\n                const uint meshIdx = rayQuery.CommittedGeometryIndex() + rayQuery.CommittedInstanceID();\n                const RT::MeshInstance meshData = g_frameMeshData[NonUniformResourceIndex(meshIdx)];\n\n                if (meshData.BaseEmissiveTriOffset == UINT32_MAX)\n                    return ret;\n\n                ret.emissiveTriIdx = meshData.BaseEmissiveTriOffset + rayQuery.CommittedPrimitiveIndex();\n                ret.lightPos = mad(rayQuery.CommittedRayT(), rayQuery.WorldRayDirection(),\n                    rayQuery.WorldRayOrigin());\n\n                return ret;\n            }\n\n            return ret;\n        }\n\n        bool HitWasEmissive()\n        {\n            return this.emissiveTriIdx != UINT32_MAX;\n        }\n\n        template<bool Curr>\n        Hit ToHitInfo(float3 wi, StructuredBuffer<RT::MeshInstance> g_frameMeshData, \n            StructuredBuffer<Vertex> g_vertices, \n            StructuredBuffer<uint> g_indices)\n        {\n            Hit hitInfo;\n            hitInfo.hit = this.hit;\n            hitInfo.t = this.t;\n\n            if(!this.hit)\n                return hitInfo;\n\n            const uint meshIdx = this.geoIdx + this.insID;\n            const RT::MeshInstance meshData = g_frameMeshData[NonUniformResourceIndex(meshIdx)];\n            hitInfo.meshIdx = meshIdx;\n            hitInfo.matIdx = meshData.MatIdx;\n\n            uint tri = primIdx * 3;\n            tri += meshData.BaseIdxOffset;\n            uint i0 = g_indices[NonUniformResourceIndex(tri)] + meshData.BaseVtxOffset;\n            uint i1 = g_indices[NonUniformResourceIndex(tri + 1)] + meshData.BaseVtxOffset;\n            uint i2 = g_indices[NonUniformResourceIndex(tri + 2)] + meshData.BaseVtxOffset;\n\n            Vertex V0 = g_vertices[NonUniformResourceIndex(i0)];\n            Vertex V1 = g_vertices[NonUniformResourceIndex(i1)];\n            Vertex V2 = g_vertices[NonUniformResourceIndex(i2)];\n\n            float3 t = Curr ? meshData.Translation : meshData.Translation - meshData.dTranslation;\n            float4 q = Math::DecodeNormalized4(Curr ? meshData.Rotation : meshData.PrevRotation);\n            float3 s = Curr ? meshData.Scale : meshData.PrevScale;\n\n            // Due to quantization, it's necessary to renormalize\n            q = normalize(q);\n\n            // Texture UV coords\n            float tmp = 1 - bary.x - bary.y;\n            float2 uv = mad(bary.y, V2.TexUV, tmp * V0.TexUV);\n            uv = mad(bary.x, V1.TexUV, uv);\n            hitInfo.uv = uv;\n\n            // normal\n            float3 v0_n = Math::DecodeOct32(V0.NormalL);\n            float3 v1_n = Math::DecodeOct32(V1.NormalL);\n            float3 v2_n = Math::DecodeOct32(V2.NormalL);\n            float3 hitNormal = mad(bary.y, v2_n, tmp * v0_n);\n            hitNormal = mad(bary.x, v1_n, hitNormal);\n            // transform normal using the inverse transpose\n            // (M^-1)^T = ((SR)^-1)^T\n            //          = (R^-1 S^-1)^T\n            //          = (S^-1)^T (R^T)^T\n            //          = S^-1 R\n            const float3 scaleInv = 1.0f / s;\n            hitNormal *= scaleInv;\n            hitNormal = Math::RotateVector(hitNormal, q);\n            hitNormal = normalize(hitNormal);\n            hitInfo.normal = hitNormal;\n\n            float3 v0W = Math::TransformTRS(V0.PosL, t, q, s);\n            float3 v1W = Math::TransformTRS(V1.PosL, t, q, s);\n            float3 v2W = Math::TransformTRS(V2.PosL, t, q, s);\n\n            float3 n0W = v0_n * scaleInv;\n            n0W = Math::RotateVector(n0W, q);\n            n0W = normalize(n0W);\n\n            float3 n1W = v1_n * scaleInv;\n            n1W = Math::RotateVector(n1W, q);\n            n1W = normalize(n1W);\n\n            float3 n2W = v2_n * scaleInv;\n            n2W = Math::RotateVector(n2W, q);\n            n2W = normalize(n2W);\n\n            hitInfo.triDiffs = Math::TriDifferentials::Compute(v0W, v1W, v2W, \n                n0W, n1W, n2W,\n                V0.TexUV, V1.TexUV, V2.TexUV);\n\n            uint3 key = uint3(this.geoIdx, this.insID, this.primIdx);\n            hitInfo.ID = RNG::PCG3d(key).x;\n\n            return hitInfo;\n        }\n\n        bool hit;\n        float t;\n        uint geoIdx;\n        uint insID;\n        uint primIdx;\n        uint emissiveTriIdx;\n        float2 bary;\n        float3 lightPos;\n    };\n\n    // For ray r = origin + t * wi, returns whether there's a hit with t in [0, +inf)\n    bool Visibility_Ray(float3 origin, float3 wi, float3 normal, RaytracingAccelerationStructure g_bvh, \n        bool transmissive)\n    {\n        bool wiBackface = dot(normal, wi) <= 0;\n        if(wiBackface)\n        {\n            if(transmissive)\n                normal *= -1;\n            else\n                return false;\n        }\n\n        float3 adjustedOrigin = RT::OffsetRayRTG(origin, normal);\n        // adjustedOrigin.y = max(adjustedOrigin.y, 5e-2);\n\n        RayQuery<RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH |\n                RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES |\n                RAY_FLAG_FORCE_OPAQUE> rayQuery;\n\n        RayDesc ray;\n        ray.Origin = adjustedOrigin;\n        ray.TMin = Math::Lerp(0.0f, 8e-5f, dot(normal, wi));\n        ray.TMax = FLT_MAX;\n        ray.Direction = wi;\n        \n        rayQuery.TraceRayInline(g_bvh, RAY_FLAG_NONE, RT_AS_SUBGROUP::ALL, ray);\n        rayQuery.Proceed();\n\n        if (rayQuery.CommittedStatus() == COMMITTED_TRIANGLE_HIT)\n            return false;\n\n        return true;\n    }\n\n    // For ray r = origin + t * wi, returns whether there's a hit with t in [0, rayT)\n    bool Visibility_Segment(float3 origin, float3 wi, float rayT, float3 normal, uint triID, \n        RaytracingAccelerationStructure g_bvh, bool transmissive)\n    {\n        if(triID == UINT32_MAX)\n            return false;\n\n        if(rayT < 1e-6)\n            return false;\n\n        float ndotwi = dot(normal, wi);\n        if(ndotwi == 0)\n            return false;\n\n        bool wiBackface = ndotwi < 0;\n        if(wiBackface)\n        {\n            if(transmissive)\n                normal *= -1;\n            else\n                return false;\n        }\n\n        const float3 adjustedOrigin = RT::OffsetRayRTG(origin, normal);\n\n#if APPROXIMATE_EMISSIVE_SHADOW_RAY == 1\n        // To test for occlusion against some light source at distance t_l, we need to \n        // see if there are any occluders with t_hit < t_l. According to dxr specs, for \n        // any committed triangle hit, t_hit < t_max. So we set t_max = t_l and trace a \n        // shadow ray. As any such hit indicates occlusion, the \n        // RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH flag can be specified for improved \n        // performance. Now due to floating-point precision issues, it's possible that the \n        // first hit could turn out to be the light source itself -- t_hit ~= t_l. In this \n        // scenario, occlusion is inconclusive as there may or may not be other occluders \n        // along the ray with t < t_hit. As an approximation, the following uses a smaller\n        // t_l to avoid the situation described above.\n        RayQuery<RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES |\n            RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH |\n            RAY_FLAG_FORCE_OPAQUE> rayQuery;\n\n        RayDesc ray;\n        ray.Origin = adjustedOrigin;\n        ray.TMin = 3e-6;\n        ray.TMax = Math::PrevFloat32(rayT * 0.999 - Math::NextFloat32(ray.TMin));\n        ray.Direction = wi;\n#else\n        RayQuery<RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES |\n            RAY_FLAG_FORCE_OPAQUE> rayQuery;\n\n        RayDesc ray;\n        ray.Origin = adjustedOrigin;\n        ray.TMin = 3e-6;\n        ray.TMax = rayT;\n        ray.Direction = wi;\n#endif\n\n        rayQuery.TraceRayInline(g_bvh, RAY_FLAG_NONE, RT_AS_SUBGROUP::NON_EMISSIVE, ray);\n        rayQuery.Proceed();\n\n        // triangle intersection only when hit_t < t_max\n        if (rayQuery.CommittedStatus() == COMMITTED_TRIANGLE_HIT)\n        {\n            uint3 key = uint3(rayQuery.CommittedGeometryIndex(), rayQuery.CommittedInstanceID(), \n                rayQuery.CommittedPrimitiveIndex());\n            uint hash = RNG::PCG3d(key).x;\n\n            return triID == hash;\n        }\n\n        return true;\n    }\n\n    struct AnisotropicSampler \n    {\n        float3 BaseColor(uint descHeapIdx, SamplerState samp, float2 uv, \n            float2 ddx_uv, float2 ddy_uv)\n        {\n            BASE_COLOR_MAP g_baseColor = ResourceDescriptorHeap[descHeapIdx];\n            return g_baseColor.SampleGrad(samp, uv, ddx_uv, ddy_uv).rgb;\n        }\n\n        float2 MR(uint descHeapIdx, SamplerState samp, float2 uv, \n            float2 ddx_uv, float2 ddy_uv)\n        {\n            METALLIC_ROUGHNESS_MAP g_mr = ResourceDescriptorHeap[descHeapIdx];\n            return g_mr.SampleGrad(samp, uv, ddx_uv, ddy_uv);\n        }\n    };\n\n    struct IsotropicSampler \n    {\n        float3 BaseColor(uint descHeapIdx, SamplerState samp, float2 uv, \n            float2 dd_uv, float2 unused)\n        {\n            BASE_COLOR_MAP g_baseColor = ResourceDescriptorHeap[descHeapIdx];\n            uint w;\n            uint h;\n            g_baseColor.GetDimensions(w, h);\n            float mip = log2(max(dd_uv.x * w, dd_uv.y * h));\n\n            return g_baseColor.SampleLevel(samp, uv, mip).rgb;\n        }\n\n        float2 MR(uint descHeapIdx, SamplerState samp, float2 uv, \n            float2 dd_uv, float2 unused)\n        {\n            METALLIC_ROUGHNESS_MAP g_mr = ResourceDescriptorHeap[descHeapIdx];\n            uint w;\n            uint h;\n            g_mr.GetDimensions(w, h);\n            float mip = log2(max(dd_uv.x * w, dd_uv.y * h));\n\n            return g_mr.SampleLevel(samp, uv, mip);\n        }\n    };\n\n    template<typename TexSampler>\n    bool GetMaterialData(float3 wo, StructuredBuffer<Material> g_materials, \n        ConstantBuffer<cbFrameConstants> g_frame, float eta_curr, float4 uv_grads, \n        inout Hit hitInfo, out BSDF::ShadingData surface, out float eta,\n        SamplerState samp, TexSampler ts)\n    {\n        const Material mat = g_materials[hitInfo.matIdx];\n        const bool hitBackface = dot(wo, hitInfo.normal) < 0;\n        // Set to an arbitrary value to fix compiler error\n        eta = DEFAULT_ETA_MAT;\n\n        // Ray hit the backside of an opaque surface, no radiance can be reflected back.\n        if(!mat.DoubleSided() && hitBackface)\n            return false;\n\n        // Reverse normal for double-sided surfaces\n        if(mat.DoubleSided() && hitBackface)\n        {\n            hitInfo.normal *= -1;\n            hitInfo.triDiffs.dndu *= -1;\n            hitInfo.triDiffs.dndv *= -1;\n        }\n\n        float3 baseColor = mat.GetBaseColorFactor();\n        float metallic = mat.Metallic() ? 1.0f : 0.0f;\n        float roughness = mat.GetSpecularRoughness();\n        bool tr = mat.Transmissive();\n        eta = mat.GetSpecularIOR();\n        half trDepth = tr ? mat.GetTransmissionDepth() : 0;\n\n        const uint32_t baseColorTex = mat.GetBaseColorTex();\n        const uint32_t metallicRoughnessTex = mat.GetMetallicRoughnessTex();\n\n        if ((trDepth == 0) && (baseColorTex != Material::INVALID_ID))\n        {\n            uint offset = NonUniformResourceIndex(g_frame.BaseColorMapsDescHeapOffset + \n                baseColorTex);\n            baseColor *= ts.BaseColor(offset, samp, hitInfo.uv, uv_grads.xy, uv_grads.zw);\n        }\n\n        if (metallicRoughnessTex != Material::INVALID_ID)\n        {\n            uint offset = NonUniformResourceIndex(g_frame.MetallicRoughnessMapsDescHeapOffset + \n                metallicRoughnessTex);\n            float2 mr = ts.MR(offset, samp, hitInfo.uv, uv_grads.xy, uv_grads.zw);\n            metallic *= mr.x;\n            roughness *= mr.y;\n        }\n\n        // TODO surrounding medium is assumed to be always air\n        float eta_next = eta_curr == ETA_AIR ? eta : ETA_AIR;\n        half subsurface = mat.ThinWalled() ? (half)mat.GetSubsurface() : 0;\n        float coat_weight = mat.GetCoatWeight();\n        float3 coat_color = mat.GetCoatColor();\n        float coat_roughness = mat.GetCoatRoughness();\n        float coat_ior = mat.GetCoatIOR();\n\n        surface = BSDF::ShadingData::Init(hitInfo.normal, wo, metallic >= MIN_METALNESS_METAL, \n            roughness, baseColor, eta_curr, eta_next, tr, trDepth, subsurface,\n            coat_weight, coat_color, coat_roughness, coat_ior);\n\n        return true;\n    }\n\n    bool GetMaterialData(float3 wo, StructuredBuffer<Material> g_materials, \n        ConstantBuffer<cbFrameConstants> g_frame, float eta_curr, float4 uv_grads, \n        inout Hit hitInfo, out BSDF::ShadingData surface, out float eta,\n        SamplerState samp)\n    {\n        AnisotropicSampler as;\n        return GetMaterialData(wo, g_materials, g_frame, eta_curr, uv_grads, hitInfo,\n            surface, eta, samp, as);\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/Common/SH.hlsli",
    "content": "//--------------------------------------------------------------------------------------\n// Constants\n//--------------------------------------------------------------------------------------\n\n// SH coeffs for projection of f(theta) = max(0, theta).\n// c_l^m == 0 when m != 0\nstatic const float COS_THETA_SH_COEFFS[11] = \n{ \n    0.8862268925f, 1.0233267546f, 0.4954159260f, 0.0000000000f, -0.1107783690f, 0.0000000000f, \n    0.0499271341f, 0.0000000000f, -0.0285469331f, 0.0000000000f, 0.0185080823f \n};\n\nstatic const float LAMBDA_L[11] = \n{ \n    3.544907701f, 2.046653415f, 1.585330919f, 1.339849171f, 1.1816359f, 1.0688298f, \n    0.983180498f, 0.915291232f, 0.859766405f, 0.813257601, 0.773562279f\n};\n\nstatic const float LAMBDA_LxCOS_THETA_SH[11] =\n{\n    3.141592536f, 2.094395197f, 0.785398185f, 0.0f, -0.130899697f, 0.0f, 0.049087384f, \n    0.0f, -0.024543694f, 0.0f, 0.014317154f\n};\n\n//--------------------------------------------------------------------------------------\n// Basis Functions in Cartesian Form\n// Ref: P. Sloan, \"Stupid Spherical Harmonics (SH) Tricks,\" 2008.\n//--------------------------------------------------------------------------------------\n\n//\n// band l = 0\n//\nstatic const float SHBasis00 = 0.2820947917738781f;\n\n//\n// band l = 1\n//\nfloat SHBasis1_1(float3 w)\n{\n    return 0.4886025119029199f * w.y;\n}\n\nfloat SHBasis10(float3 w)\n{\n    return 0.4886025119029199f * w.z;\n}\n\nfloat SHBasis11(float3 w)\n{\n    return 0.4886025119029199f * w.x;\n}\n\nfloat4 ProjectToSH1(float3 w, float f)\n{\n    float4 y = float4(SHBasis00, SHBasis1_1(w), SHBasis10(w), SHBasis11(w));\n    return y * f;\n}\n\n//\n// band l = 2\n//\nfloat SHBasis2_2(float3 w)\n{\n    return 1.0925484305920792f * w.x * w.y;\n}\n\nfloat SHBasis2_1(float3 w)\n{\n    return 1.0925484305920792f * w.y * w.z;\n}\n\nfloat SHBasis20(float3 w)\n{\n    return 0.31539156525252f * (3.0f * w.z * w.z - 1.0f);\n}\n\nfloat SHBasis21(float3 w)\n{\n    return 1.0925484305920792f * w.x * w.z;\n}\n\nfloat SHBasis22(float3 w)\n{\n    return 0.5462742152960396f * (w.x * w.x - w.y * w.y);\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/Common/Sampling.hlsli",
    "content": "#ifndef SAMPLING_H\n#define SAMPLING_H\n\n#include \"Math.hlsli\"\n\n// Refs: \n// 1. https://www.reedbeta.com/blog/hash-functions-for-gpu-rendering/\n// 2. M. Pharr, W. Jakob, and G. Humphreys, Physically Based Rendering: From theory to implementation, Morgan Kaufmann, 2016.\n// 3. P. Shirley, S. Laine, D. Hart, M. Pharr, P. Clarberg, E. Haines, M. Raab, and D. Cline, \"Sampling\n//    Transformations Zoo,\" in Ray Tracing Gems, 2019.\n\nstruct RNG\n{\n    static uint PCG(uint x)\n    {\n        uint state = x * 747796405u + 2891336453u;\n        uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;\n        return (word >> 22u) ^ word;\n    }\n\n    // Ref: M. Jarzynski and M. Olano, \"Hash Functions for GPU Rendering,\" Journal of Computer Graphics Techniques, 2020.\n    static uint3 PCG3d(uint3 v)\n    {\n        v = v * 1664525u + 1013904223u;\n        v.x += v.y * v.z;\n        v.y += v.z * v.x;\n        v.z += v.x * v.y;\n        v ^= v >> 16u;\n        v.x += v.y * v.z;\n        v.y += v.z * v.x;\n        v.z += v.x * v.y;\n        return v;\n    }\n\n    // Ref: M. Jarzynski and M. Olano, \"Hash Functions for GPU Rendering,\" Journal of Computer Graphics Techniques, 2020.\n    static uint4 PCG4d(uint4 v)\n    {\n        v = v * 1664525u + 1013904223u;\n        v.x += v.y * v.w; \n        v.y += v.z * v.x; \n        v.z += v.x * v.y; \n        v.w += v.y * v.z;\n        v ^= v >> 16u;\n        v.x += v.y * v.w; \n        v.y += v.z * v.x; \n        v.z += v.x * v.y; \n        v.w += v.y * v.z;\n        return v;\n    }\n\n    static RNG Init(uint2 pixel, uint frame)\n    {\n        RNG rng;\n#if 0\n        rng.State = RNG::PCG(pixel.x + RNG::PCG(pixel.y + RNG::PCG(frame)));\n#else\n        rng.State = RNG::PCG3d(uint3(pixel, frame)).x;\n#endif\n\n        return rng;\n    }\n\n    static RNG Init(uint2 pixel, uint frame, uint idx)\n    {\n        RNG rng;\n        rng.State = RNG::PCG4d(uint4(pixel, frame, idx)).x;\n\n        return rng;\n    }\n\n    static RNG Init(uint idx, uint frame)\n    {\n        RNG rng;\n        rng.State = rng.PCG(idx + PCG(frame));\n\n        return rng;\n    }\n\n    static RNG Init(uint seed)\n    {\n        RNG rng;\n        rng.State = seed;\n\n        return rng;\n    }\n\n    uint UniformUint()\n    {\n        this.State = this.State * 747796405u + 2891336453u;\n        uint word = ((this.State >> ((this.State >> 28u) + 4u)) ^ this.State) * 277803737u;\n\n        return (word >> 22u) ^ word;\n    }\n\n    float Uniform() \n    {\n#if 0\n    \treturn asfloat(0x3f800000 | (UniformUint() >> 9)) - 1.0f;\n#else\n        // For 32-bit floats, any integer in [0, 2^24] can be represented exactly and \n        // there may be rounding errors for anything larger, e.g. 2^24 + 1 is rounded \n        // down to 2^24. \n        // Given random integers, we can right shift by 8 bits to get integers in \n        // [0, 2^24 - 1]. After division by 2^-24, we have uniform numbers in [0, 1).\n        // Ref: https://prng.di.unimi.it/\n        return float(UniformUint() >> 8) * 0x1p-24f;\n#endif\n    }\n\n    // Returns samples in [0, bound)\n    uint UniformUintBounded(uint bound)\n    {\n        uint32_t threshold = (~bound + 1u) % bound;\n\n        for (;;) \n        {\n            uint32_t r = UniformUint();\n\n            if (r >= threshold)\n                return r % bound;\n        }        \n    }\n\n    // Returns samples in [0, bound). Biased but faster than #UniformUintBounded(): \n    // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle\n    uint UniformUintBounded_Faster(uint bound)\n    {\n        return (uint)(Uniform() * float(bound));\n    }\n\n    float2 Uniform2D()\n    {\n        float u0 = Uniform();\n        float u1 = Uniform();\n\n        return float2(u0, u1);\n    }\n\n    float3 Uniform3D()\n    {\n        float u0 = Uniform();\n        float u1 = Uniform();\n        float u2 = Uniform();\n\n        return float3(u0, u1, u2);\n    }\n\n    float4 Uniform4D()\n    {\n        float u0 = Uniform();\n        float u1 = Uniform();\n        float u2 = Uniform();\n        float u3 = Uniform();\n\n        return float4(u0, u1, u2, u3);\n    }\n\n    uint State;\n};\n\n//--------------------------------------------------------------------------------------\n// Sampling Transformations\n//--------------------------------------------------------------------------------------\n\nnamespace Sampling\n{\n    // Returns samples about the (0, 0, 1) axis\n    float3 UniformSampleHemisphere(float2 u, out float pdf)\n    {\n        const float phi = TWO_PI * u.y;\n        const float sinTheta = sqrt(1.0f - u.x * u.x);\n\n        const float x = cos(phi) * sinTheta;\n        const float y = sin(phi) * sinTheta;\n        const float z = u.x;\n\n        pdf = ONE_OVER_2_PI;\n\n        return float3(x, y, z);\n    }\n\n    // Returns samples about the (0, 0, 1) axis\n    float3 SampleCosineWeightedHemisphere(float2 u, out float pdf)\n    {\n        const float phi = TWO_PI * u.y;\n        const float sinTheta = sqrt(u.x);\n\n        const float x = cos(phi) * sinTheta;\n        const float y = sin(phi) * sinTheta;\n        const float z = sqrt(1.0f - u.x); // = cos(theta)\n\n        pdf = z * ONE_OVER_PI; // = cos(theta) / PI\n\n        return float3(x, y, z);\n    }\n\n    // Returns samples about the (0, 0, 1) axis\n    float3 UniformSampleCone(float2 u, float cosThetaMax, out float pdf)\n    {\n        const float phi = TWO_PI * u.y;\n\n        const float cosTheta = saturate((1.0f - u.x) + u.x * cosThetaMax);\n        const float sinTheta = sqrt(1.0f - cosTheta * cosTheta);\n\n        const float x = cos(phi) * sinTheta;\n        const float y = sin(phi) * sinTheta;\n        const float z = cosTheta;\n\n        pdf = ONE_OVER_2_PI / (1.0f - cosThetaMax);\n\n        return float3(x, y, z);\n    }\n\n    float2 UniformSampleDisk(float2 u)\n    {\n        const float r = sqrt(u.x);\n        const float phi = TWO_PI * u.y;\n\n        return float2(r * cos(phi), r * sin(phi));\n    }\n\n    float2 UniformSampleDiskConcentric(float2 u)\n    {\n        float a = 2.0f * u.x - 1.0f;\n        float b = 2.0f * u.y - 1.0f;\n        if(a == 0 && b == 0)\n            return 0;\n\n        float r;\n        float phi;\n\n        if (a * a > b * b)\n        {\n            r = a;\n            phi = PI_OVER_4 * (b / a);\n        }\n        else\n        {\n            r = b;\n            phi = PI_OVER_2 - PI_OVER_4 * (a / b);\n        }\n\n        return float2(r * cos(phi), r * sin(phi));\n    }\n\n    float3 UniformSampleSphere(float2 u)\n    {\n        // Compute radius r (branchless).\n        float u0 = 2.0f * u.x - 1.0f;\n        float u1 = 2.0f * u.y - 1.0f;\n\n        float d = 1.0f - (abs(u0) + abs(u1));\n        float r = 1.0f - abs(d);\n\n        // Compute phi in the first quadrant (branchless, except for the\n        // division-by-zero test), using sign(u) to map the result to the\n        // correct quadrant below.\n        float phi = (r == 0) ? 0 : PI_OVER_4 * ((abs(u1) - abs(u0)) / r + 1.0f);\n        float f = r * sqrt(2.0f - r * r);\n        float x = f * sign(u0) * cos(phi);\n        float y = f * sign(u1) * sin(phi);\n        float z = sign(d) * (1.0f - r * r);\n\n        return float3(x, y, z);\n    }\n\n    // Any point inside the triangle with vertices V0, V1, and V2 can be expressed as\n    //        P = b0 * V0 + b1 * V1 + b2 * V2\n    // where b0 + b1 + b2 = 1. Therefore, only b1 and b2 need to be sampled.\n    float2 UniformSampleTriangle(float2 u)\n    {\n        // Ref: Eric Heitz. A Low-Distortion Map Between Triangle and Square. 2019.\n        float b1, b2;\n        \n        if (u.y > u.x)\n        {\n            b1 = u.x * 0.5f;\n            b2 = u.y - b1;\n        }\n        else\n        {\n            b2 = u.y * 0.5f;\n            b1 = u.x - b2;\n        }\n\n        return float2(b1, b2);\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/Common/StaticTextureSamplers.hlsli",
    "content": "#ifndef SAMPLERS_H\n#define SAMPLERS_H\n\nSamplerState g_samMip0 : register(s0);\nSamplerState g_samPointWrap : register(s1);\nSamplerState g_samPointClamp : register(s2);\nSamplerState g_samLinearWrap : register(s3);\nSamplerState g_samLinearClamp : register(s4);\nSamplerState g_samAnisotropicWrap : register(s5);\nSamplerState g_samAnisotropicWrap_2x : register(s6);\nSamplerState g_samAnisotropicWrap_4x : register(s7);\nSamplerState g_samImgUi : register(s8);\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/Common/Volumetric.hlsli",
    "content": "#ifndef VOLUMETRIC_H\n#define VOLUMETRIC_H\n\n// Refs:\n// 1. M. Pharr and G. Humphreys, Physically Based Rendering: From theory to implementation, Morgan Kaufmann, 2010.\n// 2. S. Hillaire, \"A Scalable and Production Ready Sky and Atmosphere Rendering Technique,\" Computer Graphics Forum, 2020.\n// 3. https://github.com/Fewes/MinimalAtmosphere\n\n#include \"Math.hlsli\"\n\n//--------------------------------------------------------------------------------------\n// {Absorption, scattering, extinction} coefficients\n//--------------------------------------------------------------------------------------\n\n/*\nstatic const float3 SIGMA_S_RAYLEIGH = float3(5.802f, 13.558f, 33.1f) * 1e-6f;    // 1 / m\nstatic const float3 SIGMA_A_RAYLEIGH = float3(0.0f, 0.0f, 0.0f);                // 1 / m\nstatic const float3 SIGMA_T_RAYLEIGH = SIGMA_S_RAYLEIGH + SIGMA_A_RAYLEIGH;\nstatic const float SIGMA_S_MIE = 3.996f * 1e-6f;        // Mie scattering is not wavelength-dependent\nstatic const float SIGMA_A_MIE = 4.4f * 1e-6f;\nstatic const float SIGMA_T_MIE = SIGMA_S_MIE + SIGMA_A_MIE;\nstatic const float3 SIGMA_S_OZONE = float3(0.0f, 0.0f, 0.0f);\nstatic const float3 SIGMA_A_OZONE = float3(0.65f, 1.881f, 0.085f) * 1e-6f;\nstatic const float3 SIGMA_T_OZONE = SIGMA_S_OZONE + SIGMA_A_OZONE;\n*/\n\nnamespace Volume\n{\n    //--------------------------------------------------------------------------------------\n    // Phase functions\n    //--------------------------------------------------------------------------------------\n\n    // Used to describe light scattering from small molecules in \n    // earth's atmoshphere. \n    // theta is the angle between incoming and scattered light\n    float RayleighPhaseFunction(float cosTheta)\n    {\n        return 0.0596831f * (1.0f + cosTheta * cosTheta);\n    }\n\n    // Henyey-Greenstein phase function can be used to model Mie scattering, which describes \n    // scattering from dust, smoke, fog and pollution-like participating media\n    float PhaseHG(float cosTheta, float g)\n    {\n        float g2 = g * g;\n        float denom = (1 - g2) / (1 + g2 - 2 * g * cosTheta);\n\n        return ONE_OVER_4_PI * g2 / (denom * sqrt(denom));\n    }\n\n    // An approximation Henyey-Greenstein phase function that is faster to compute\n    float SchlickPhaseFunction(float cosTheta, float g)\n    {\n        float k = 1.55f * g - 0.55f * g * g * g;\n        float denom = 1.0f - k * cosTheta;\n\n        return ONE_OVER_4_PI * (1.0f - k * k) / (denom * denom);\n    }\n\n    //--------------------------------------------------------------------------------------\n    // Density functions for heterogeneous medium\n    //--------------------------------------------------------------------------------------\n\n    // Spatial density of participating media for Rayleigh scattering. Altitude should be \n    // in km.\n    float DensityRayleigh(float altitude)\n    {\n        return exp(-max(0.0f, altitude / 8.0f));\n    }\n\n    // Spatial density of participating media for Rayleigh scattering. Altitude should be \n    // in km.\n    float DensityMie(float altitude)\n    {\n        return exp(-max(0.0f, altitude / 1.2f));\n    }\n\n    // Spatial density of ozone. Altitude should be in km.\n    float DensityOzone(float altitude)\n    {\n        return max(0, 1 - abs(altitude - 25.0f) / 15.0f);\n    }\n\n    // Altitude should be in km\n    float3 AtmosphereDensity(float altitude)\n    {\n        return float3(DensityRayleigh(altitude), DensityMie(altitude), DensityOzone(altitude));\n    }\n\n    //--------------------------------------------------------------------------------------\n    // Estimating absorption, in-scattering and other helper functions\n    //--------------------------------------------------------------------------------------\n\n    // Both arguments are in units of km\n    float Altitude(float3 pos, float planetRadius)\n    {\n        // center is assumed to be (0, 0, 0)\n        return length(pos) - planetRadius;\n    }\n\n    // Ref: C. Ericson, Real-time Collision Detection, Morgan Kaufmann, 2005.\n    float IntersectRayAtmosphere(float radius, float3 rayOrigin, float3 rayDir)\n    {\n        // center is assumed to be (0, 0, 0)\n        float mDotdir = dot(rayDir, rayOrigin);\n        float delta = mDotdir * mDotdir - dot(rayOrigin, rayOrigin) + radius * radius;\n\n        // here, ray is always starting inside the sphere, so there's one negative answer and\n        // one positive answer, the latter is what's intended    \n        delta = sqrt(delta);\n        return -mDotdir + delta;\n    }\n\n    bool IntersectRayPlanet(float radius, float3 rayOrigin, float3 rayDir, out float t)\n    {\n        // center is assumed to be (0, 0, 0)\n        float mDotdir = dot(rayDir, rayOrigin);\n        float delta = mDotdir * mDotdir - dot(rayOrigin, rayOrigin) + radius * radius;\n\n        if (delta < 0.0f)\n        {\n            t = 0;\n            return false;\n        }\n\n        // here, ray is always starting outside the sphere and the first intersection \n        // is what's intended\n        delta = sqrt(delta);\n        t = min(-mDotdir - delta, -mDotdir + delta);\n\n        return t >= 0.0f;\n    }\n\n    // Estimates optical thickness by assuming extinction function sigma_t is \n    // piecewise constant. Riemann sum is then used to estimate the integral\n    // of sigma_t along the given ray\n    float3 EstimateTransmittance(float planetRadius, float3 rayOrigin, float3 rayDir, float t,\n        float3 sigma_t_rayleigh, float sigma_t_mie, float3 sigma_t_ozone, int numSteps)\n    {\n        if (t <= 1e-5f)\n            return 1.0;\n\n        const float stepSize = t / numSteps;\n        float3 pos = rayOrigin + 0.5f * stepSize * rayDir;\n        // float3 pos = rayOrigin;\n        float3 opticalThickness = 0.0f;\n\n        // Riemann sum\n        [loop]\n        for (int s = 0; s < numSteps; s++)\n        {\n            float altitude = Altitude(pos, planetRadius);\n            float3 density = AtmosphereDensity(altitude);\n            opticalThickness += density;\n            pos += stepSize * rayDir;\n        }\n\n        opticalThickness = sigma_t_rayleigh * opticalThickness.x +\n        sigma_t_mie * opticalThickness.y +\n        sigma_t_ozone * opticalThickness.z;\n\n        // midpoint rule\n        opticalThickness *= stepSize;\n\n        // trapezoid rule\n        // opticalThickness *= stepSize * 0.5f;\n\n        return exp(-opticalThickness);\n    }\n\n    // Estimates in-scattered light from sun\n    float3 EstimateLs(float planetRadius, float3 rayOrigin, float3 rayDir, \n        float3 lightDir, float atmosphereHeight, float g, float3 sigma_s_rayleigh, \n        float sigma_s_mie, float sigma_t_mie, float3 sigma_t_ozone, int numSteps)\n    {\n        float t = IntersectRayAtmosphere(planetRadius + atmosphereHeight, rayOrigin, \n            rayDir);\n\n        float tPlanet;\n        bool intersectedPlanet = IntersectRayPlanet(planetRadius, rayOrigin, rayDir, \n            tPlanet);\n        if (intersectedPlanet)\n            t = tPlanet;\n\n        const float3 atmosphereIntersection = mad(t, rayDir, rayOrigin);\n\n        const float stepSize = t / numSteps;\n        float3 pos = rayOrigin + 0.5f * stepSize * rayDir;\n\n        float3 opticalThickness = 0.0;\n        float3 LsRayleigh = 0.0;\n        float3 LsMie = 0.0;\n\n        // Riemann sum\n        [loop]\n        for (int s = 0; s < numSteps; s++)\n        {\n            float altitude = Altitude(pos, planetRadius);\n            float3 density = AtmosphereDensity(altitude);\n            opticalThickness += density * stepSize;\n\n            // Rayleigh scattering doesn't have absorption so sigma_t == sigma_s\n            float3 rayOriginToPosTr = exp(-(sigma_s_rayleigh * opticalThickness.x +\n            sigma_t_mie * opticalThickness.y +\n            sigma_t_ozone * opticalThickness.z));\n\n            const float posToAtmosphereDist = IntersectRayAtmosphere(\n                planetRadius + atmosphereHeight, pos, -lightDir);\n            float3 LoTranmittance = EstimateTransmittance(planetRadius, pos, -lightDir, \n                posToAtmosphereDist, sigma_s_rayleigh, sigma_t_mie, sigma_t_ozone, 8);\n\n            // for ray semgment p1, p2, p3 where p1 < p2 < p3\n            // Transmittance(p1, p3) = Transmittance(p1, p2) * Transmittance(p2, p3) \n            LsRayleigh += rayOriginToPosTr * density.x * LoTranmittance;\n            LsMie += rayOriginToPosTr * density.y * LoTranmittance;\n\n            pos += stepSize * rayDir;\n        }\n\n        // Following three are constant when sun is the light source\n        const float cosTheta = dot(lightDir, -rayDir);\n        const float phaseRayleigh = RayleighPhaseFunction(cosTheta);\n        const float phaseMie = SchlickPhaseFunction(cosTheta, g);\n\n        float3 Ls = LsRayleigh * sigma_s_rayleigh * phaseRayleigh;\n        Ls += LsMie * sigma_s_mie * phaseMie;\n        Ls *= stepSize;\n\n        return Ls;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/Compositing/CMakeLists.txt",
    "content": "set(RP_COMPOSITING_DIR ${ZETA_RENDER_PASS_DIR}/Compositing)\nset(RP_COMPOSITING_SRC\n    ${RP_COMPOSITING_DIR}/Compositing.cpp\n    ${RP_COMPOSITING_DIR}/Compositing.h\n    ${RP_COMPOSITING_DIR}/Compositing_Common.h\n    ${RP_COMPOSITING_DIR}/FireflyFilter.hlsl\n    ${RP_COMPOSITING_DIR}/Compositing.hlsl)\nset(RP_COMPOSITING_SRC ${RP_COMPOSITING_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaRenderPass/Compositing/Compositing.cpp",
    "content": "#include \"Compositing.h\"\n#include <Core/CommandList.h>\n#include <Scene/SceneRenderer.h>\n#include <Scene/SceneCore.h>\n#include <Support/Param.h>\n#include \"../Assets/Font/IconsFontAwesome6.h\"\n\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Support;\n\n//--------------------------------------------------------------------------------------\n// Compositing\n//--------------------------------------------------------------------------------------\n\nCompositing::Compositing()\n    : RenderPassBase(NUM_CBV, NUM_SRV, NUM_UAV, NUM_GLOBS, NUM_CONSTS)\n{\n    // root constants\n    m_rootSig.InitAsConstants(0, sizeof(cbCompositing) / sizeof(DWORD), 0);\n\n    // frame constants\n    m_rootSig.InitAsCBV(1, 1, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::FRAME_CONSTANTS_BUFFER);\n}\n\nvoid Compositing::InitPSOs()\n{\n    constexpr D3D12_ROOT_SIGNATURE_FLAGS flags =\n        D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;\n\n    auto& renderer = App::GetRenderer();\n    auto samplers = renderer.GetStaticSamplers();\n    RenderPassBase::InitRenderPass(\"Compositing\", flags, samplers);\n\n    for (int i = 0; i < (int)SHADER::COUNT; i++)\n        m_psoLib.CompileComputePSO(i, m_rootSigObj.Get(), COMPILED_CS[i]);\n}\n\nvoid Compositing::Init()\n{\n    InitPSOs();\n\n    memset(&m_cbComposit, 0, sizeof(m_cbComposit));\n    SET_CB_FLAG(m_cbComposit, CB_COMPOSIT_FLAGS::INDIRECT, true);\n\n    CreateCompositTexture();\n\n    ParamVariant p1;\n    p1.InitBool(ICON_FA_FILM \" Renderer\", \"Compositing\", \"Direct\",\n        fastdelegate::MakeDelegate(this, &Compositing::DirectCallback), m_directLighting);\n    App::AddParam(p1);\n\n    ParamVariant p6;\n    p6.InitBool(ICON_FA_FILM \" Renderer\", \"Compositing\", \"Indirect\",\n        fastdelegate::MakeDelegate(this, &Compositing::IndirectCallback),\n        IS_CB_FLAG_SET(m_cbComposit, CB_COMPOSIT_FLAGS::INDIRECT));\n    App::AddParam(p6);\n\n    ParamVariant p9;\n    p9.InitBool(ICON_FA_FILM \" Renderer\", \"Compositing\", \"Firefly Suppression\",\n        fastdelegate::MakeDelegate(this, &Compositing::FireflyFilterCallback),\n        m_filterFirefly);\n    App::AddParam(p9);\n\n    App::AddShaderReloadHandler(\"Compositing\", fastdelegate::MakeDelegate(this, &Compositing::ReloadCompositing));\n}\n\nvoid Compositing::OnWindowResized()\n{\n    CreateCompositTexture();\n}\n\nvoid Compositing::Render(CommandList& cmdList)\n{\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT ||\n        cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE, \"Invalid downcast\");\n    ComputeCmdList& computeCmdList = static_cast<ComputeCmdList&>(cmdList);\n\n    const uint32_t w = App::GetRenderer().GetRenderWidth();\n    const uint32_t h = App::GetRenderer().GetRenderHeight();\n    auto& gpuTimer = App::GetRenderer().GetGpuTimer();\n\n    computeCmdList.SetRootSignature(m_rootSig, m_rootSigObj.Get());\n\n    // compositing\n    {\n        computeCmdList.PIXBeginEvent(\"Compositing\");\n        const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"Compositing\");\n\n        const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, COMPOSITING_THREAD_GROUP_DIM_X);\n        const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, COMPOSITING_THREAD_GROUP_DIM_Y);\n\n        if (IS_CB_FLAG_SET(m_cbComposit, CB_COMPOSIT_FLAGS::INSCATTERING))\n        {\n            Assert(m_cbComposit.InscatteringDescHeapIdx > 0, \"Gpu descriptor for inscattering texture hasn't been set\");\n            Assert(m_cbComposit.VoxelGridNearZ >= 0.0f, \"Invalid voxel grid depth\");\n            Assert(m_cbComposit.VoxelGridFarZ > m_cbComposit.VoxelGridNearZ, \"Invalid voxel grid depth\");\n            Assert(m_cbComposit.DepthMappingExp > 0.0f, \"Invalid voxel grid depth mapping exponent\");\n        }\n\n        m_cbComposit.OutputUAVDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE::LIGHT_ACCUM_UAV);\n\n        m_rootSig.SetRootConstants(0, sizeof(cbCompositing) / sizeof(DWORD), &m_cbComposit);\n        m_rootSig.End(computeCmdList);\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::COMPOSIT));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n\n        gpuTimer.EndQuery(computeCmdList, queryIdx);\n        computeCmdList.PIXEndEvent();\n    }\n\n    if (m_filterFirefly)\n    {\n        computeCmdList.PIXBeginEvent(\"FireflyFilter\");\n        const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"FireflyFilter\");\n\n        const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, FIREFLY_FILTER_THREAD_GROUP_DIM_X);\n        const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, FIREFLY_FILTER_THREAD_GROUP_DIM_Y);\n\n        computeCmdList.UAVBarrier(m_compositTex.Resource());\n\n        cbFireflyFilter cb;\n        cb.CompositedUAVDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE::LIGHT_ACCUM_UAV);\n\n        m_rootSig.SetRootConstants(0, sizeof(cbFireflyFilter) / sizeof(DWORD), &cb);\n        m_rootSig.End(computeCmdList);\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::FIREFLY_FILTER));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n\n        gpuTimer.EndQuery(computeCmdList, queryIdx);\n        computeCmdList.PIXEndEvent();\n    }\n}\n\nvoid Compositing::CreateCompositTexture()\n{\n    auto& renderer = App::GetRenderer();\n    m_descTable = renderer.GetGpuDescriptorHeap().Allocate((int)DESC_TABLE::COUNT);\n\n    m_compositTex = GpuMemory::GetTexture2D(\"Composit\",\n        renderer.GetRenderWidth(), renderer.GetRenderHeight(),\n        ResourceFormats::LIGHT_ACCUM,\n        D3D12_RESOURCE_STATE_COMMON,\n        TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n    Direct3DUtil::CreateTexture2DUAV(m_compositTex, m_descTable.CPUHandle((int)DESC_TABLE::LIGHT_ACCUM_UAV));\n}\n\nvoid Compositing::FireflyFilterCallback(const Support::ParamVariant& p)\n{\n    m_filterFirefly = p.GetBool();\n}\n\nvoid Compositing::DirectCallback(const Support::ParamVariant& p)\n{\n    m_directLighting = p.GetBool();\n\n    if(App::GetScene().NumEmissiveInstances())\n        SET_CB_FLAG(m_cbComposit, CB_COMPOSIT_FLAGS::EMISSIVE_DI, m_directLighting);\n    else\n        SET_CB_FLAG(m_cbComposit, CB_COMPOSIT_FLAGS::SKY_DI, m_directLighting);\n}\n\nvoid Compositing::IndirectCallback(const Support::ParamVariant& p)\n{\n    SET_CB_FLAG(m_cbComposit, CB_COMPOSIT_FLAGS::INDIRECT, p.GetBool());\n}\n\nvoid Compositing::ReloadCompositing()\n{\n    const int i = (int)SHADER::COMPOSIT;\n    m_psoLib.Reload(0, m_rootSigObj.Get(), \"Compositing\\\\Compositing.hlsl\");\n}"
  },
  {
    "path": "Source/ZetaRenderPass/Compositing/Compositing.h",
    "content": "#pragma once\n\n#include \"../RenderPass.h\"\n#include <Core/GpuMemory.h>\n#include \"Compositing_Common.h\"\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n}\n\nnamespace ZetaRay::Support\n{\n    struct ParamVariant;\n}\n\nnamespace ZetaRay::RenderPass\n{\n    enum class COMPOSITING_SHADER\n    {\n        COMPOSIT,\n        FIREFLY_FILTER,\n        COUNT\n    };\n\n    struct Compositing final : public RenderPassBase<(int)COMPOSITING_SHADER::COUNT>\n    {\n        enum class SHADER_IN_GPU_DESC\n        {\n            SKY_DI,\n            INSCATTERING,\n            EMISSIVE_DI,\n            INDIRECT,\n            COUNT\n        };\n\n        enum class SHADER_OUT_RES\n        {\n            COMPOSITED,\n            COUNT\n        };\n\n        Compositing();\n        ~Compositing() = default;\n\n        void InitPSOs();\n        void Init();\n        void SetInscatteringEnablement(bool enable) { SET_CB_FLAG(m_cbComposit, CB_COMPOSIT_FLAGS::INSCATTERING, enable); }\n        void SetVoxelGridDepth(float zNear, float zFar) { m_cbComposit.VoxelGridNearZ = zNear, m_cbComposit.VoxelGridFarZ = zFar; }\n        void SetVoxelGridMappingExp(float exp) { m_cbComposit.DepthMappingExp = exp; }\n        void SetGpuDescriptor(SHADER_IN_GPU_DESC input, uint32_t descHeapIdx)\n        {\n            Assert((int)input < (int)SHADER_IN_GPU_DESC::COUNT, \"out-of-bound access.\");\n\n            switch (input)\n            {\n            case SHADER_IN_GPU_DESC::INSCATTERING:\n                m_cbComposit.InscatteringDescHeapIdx = descHeapIdx;\n                return;\n            case SHADER_IN_GPU_DESC::SKY_DI:\n                m_cbComposit.SkyDIDescHeapIdx = descHeapIdx;\n                SET_CB_FLAG(m_cbComposit, CB_COMPOSIT_FLAGS::SKY_DI, m_directLighting);\n                SET_CB_FLAG(m_cbComposit, CB_COMPOSIT_FLAGS::EMISSIVE_DI, false);\n                return;\n            case SHADER_IN_GPU_DESC::EMISSIVE_DI:\n                m_cbComposit.EmissiveDIDescHeapIdx = descHeapIdx;\n                SET_CB_FLAG(m_cbComposit, CB_COMPOSIT_FLAGS::SKY_DI, false);\n                SET_CB_FLAG(m_cbComposit, CB_COMPOSIT_FLAGS::EMISSIVE_DI, m_directLighting);\n                return;\n            case SHADER_IN_GPU_DESC::INDIRECT:\n                m_cbComposit.IndirectDescHeapIdx = descHeapIdx;\n                return;\n            default:\n                Assert(false, \"unreachable case.\");\n                return;\n            }\n        }\n        const Core::GpuMemory::Texture & GetOutput(SHADER_OUT_RES out) const\n        {\n            Assert((int)out < (int)SHADER_IN_GPU_DESC::COUNT, \"out-of-bound access.\");\n            return m_compositTex;\n        }\n        void OnWindowResized();\n        void Render(Core::CommandList& cmdList);\n\n    private:\n        static constexpr int NUM_CBV = 1;\n        static constexpr int NUM_SRV = 0;\n        static constexpr int NUM_UAV = 0;\n        static constexpr int NUM_GLOBS = 1;\n        static constexpr int NUM_CONSTS = sizeof(cbCompositing) / sizeof(DWORD);\n        using SHADER = RenderPass::COMPOSITING_SHADER;\n\n        struct ResourceFormats\n        {\n            static constexpr DXGI_FORMAT LIGHT_ACCUM = DXGI_FORMAT_R32G32B32A32_FLOAT;\n        };\n\n        enum class DESC_TABLE\n        {\n            LIGHT_ACCUM_UAV,\n            COUNT\n        };\n\n        inline static constexpr const char* COMPILED_CS[(int)SHADER::COUNT] = {\n            \"Compositing_cs.cso\",\n            \"FireflyFilter_cs.cso\"\n        };\n\n        void CreateCompositTexture();\n\n        // param callbacks\n        void FireflyFilterCallback(const Support::ParamVariant& p);\n        void DirectCallback(const Support::ParamVariant& p);\n        void IndirectCallback(const Support::ParamVariant& p);\n        // shader reload\n        void ReloadCompositing();\n\n        Core::GpuMemory::Texture m_compositTex;\n        Core::DescriptorTable m_descTable;\n        cbCompositing m_cbComposit;\n        bool m_filterFirefly = false;\n        bool m_directLighting = true;\n    };\n}"
  },
  {
    "path": "Source/ZetaRenderPass/Compositing/Compositing.hlsl",
    "content": "#include \"Compositing_Common.h\"\n#include \"../Common/Common.hlsli\"\n#include \"../Common/GBuffers.hlsli\"\n#include \"../Common/LightVoxelGrid.hlsli\"\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbCompositing> g_local : register(b0);\nConstantBuffer<cbFrameConstants> g_frame : register(b1);\n\n//--------------------------------------------------------------------------------------\n// Helper Functions\n//--------------------------------------------------------------------------------------\n\nfloat3 MapIdxToColor(uint i) \n{\n    float r = (i & 0xff) / 255.0f;\n    float g = ((i >> 8) & 0xff) / 255.0f;\n    float b = ((i >> 16) & 0xff) / 255.0f;\n\n    return float3(r, g, b);\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(COMPOSITING_THREAD_GROUP_DIM_X, COMPOSITING_THREAD_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint Gidx : SV_GroupIndex)\n{\n    if (DTid.x >= g_frame.RenderWidth || DTid.y >= g_frame.RenderHeight)\n        return;\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(g_metallicRoughness[DTid.xy].x);\n\n    RWTexture2D<float4> g_composited = ResourceDescriptorHeap[g_local.OutputUAVDescHeapIdx];\n    const bool accumulate = g_frame.Accumulate && g_frame.CameraStatic;\n    \n    if (flags.invalid && !accumulate)\n    {\n        const bool dirLighting = IS_CB_FLAG_SET(CB_COMPOSIT_FLAGS::SKY_DI) || IS_CB_FLAG_SET(CB_COMPOSIT_FLAGS::EMISSIVE_DI);\n        g_composited[DTid.xy].xyz = dirLighting ? Light::Le_SkyWithSunDisk(DTid.xy, g_frame) : 0;\n        return;\n    }\n\n    const uint numFramesAccumulated = accumulate ? g_frame.NumFramesCameraStatic : 1;\n    float3 color = 0; \n\n    if (IS_CB_FLAG_SET(CB_COMPOSIT_FLAGS::SKY_DI) && g_local.SkyDIDescHeapIdx != 0)\n    {\n        Texture2D<float4> g_sky = ResourceDescriptorHeap[g_local.SkyDIDescHeapIdx];\n        color = g_sky[DTid.xy].rgb;\n    }\n    else if (IS_CB_FLAG_SET(CB_COMPOSIT_FLAGS::EMISSIVE_DI) && g_local.EmissiveDIDescHeapIdx != 0)\n    {\n        Texture2D<float4> g_emissive = ResourceDescriptorHeap[g_local.EmissiveDIDescHeapIdx];\n        float3 le = g_emissive[DTid.xy].rgb;\n        color += le;\n    }\n\n    if (IS_CB_FLAG_SET(CB_COMPOSIT_FLAGS::INDIRECT) && !flags.emissive && g_local.IndirectDescHeapIdx != 0)\n    {\n        Texture2D<float4> g_indirect = ResourceDescriptorHeap[g_local.IndirectDescHeapIdx];\n        float3 li = g_indirect[DTid.xy].rgb;\n        color += li;\n    }\n\n    color /= numFramesAccumulated;\n\n    if (IS_CB_FLAG_SET(CB_COMPOSIT_FLAGS::INSCATTERING))\n    {\n        GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::DEPTH];\n        const float z_view = g_depth[DTid.xy];\n\n        if (z_view > 1e-4f)\n        {\n            float2 posTS = (DTid.xy + 0.5f) / float2(g_frame.RenderWidth, g_frame.RenderHeight);\n            float p = pow(max(z_view - g_local.VoxelGridNearZ, 0.0f) / \n                (g_local.VoxelGridFarZ - g_local.VoxelGridNearZ), 1.0f / g_local.DepthMappingExp);\n        \n            //float p = linearDepth / g_local.VoxelGridDepth;\n            //p /= exp(-1.0 + p);\n        \n            Texture3D<half4> g_voxelGrid = ResourceDescriptorHeap[g_local.InscatteringDescHeapIdx];\n            float3 posCube = float3(posTS, p);\n            //float3 uvw = float3(posCube.xy, p);\n            //const float3 uvw = float3(posTS, 12 / 32.0);\n        \n            half3 inscattering = g_voxelGrid.SampleLevel(g_samLinearClamp, posCube, 0.0f).rgb;\n            color += inscattering;\n        }\n    }\n\n    if (IS_CB_FLAG_SET(CB_COMPOSIT_FLAGS::VISUALIZE_LVG))\n    {\n        // int3 voxelIdx;\n        // color = 0;\n\n        // GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        //     GBUFFER_OFFSET::DEPTH];\n        // const float z_view = g_depth[DTid.xy];\n        // float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n        // const float3 pos = Math::WorldPosFromScreenSpace(DTid.xy, renderDim,\n        //     z_view, g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrViewInv, \n        //     g_frame.CurrCameraJitter);\n\n        // if(LVG::MapPosToVoxel(pos, uint3(g_local.GridDim_x, g_local.GridDim_y, g_local.GridDim_z), \n        //     float3(g_local.Extents_x, g_local.Extents_y, g_local.Extents_z), g_frame.CurrView, \n        //     voxelIdx, g_local.Offset_y))\n        // {\n        //     GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        //         GBUFFER_OFFSET::BASE_COLOR];\n        //     float3 baseColor = g_baseColor[DTid.xy].rgb;\n\n        //     uint3 c = RNG::PCG3d(voxelIdx);\n        //     color = baseColor * 0.1 + MapIdxToColor(c.x) * 0.05;\n        // }\n    }\n\n    g_composited[DTid.xy].xyz = color;\n}"
  },
  {
    "path": "Source/ZetaRenderPass/Compositing/Compositing_Common.h",
    "content": "#ifndef COMPOSITING_H\n#define COMPOSITING_H\n\n#include \"../../ZetaCore/Core/HLSLCompat.h\"\n\n#define COMPOSITING_THREAD_GROUP_DIM_X 8u\n#define COMPOSITING_THREAD_GROUP_DIM_Y 8u\n\n#define FIREFLY_FILTER_THREAD_GROUP_DIM_X 16u\n#define FIREFLY_FILTER_THREAD_GROUP_DIM_Y 8u\n\nnamespace CB_COMPOSIT_FLAGS\n{\n    static constexpr uint32_t SKY_DI = 1 << 1;\n    static constexpr uint32_t INDIRECT = 1 << 2;\n    static constexpr uint32_t INSCATTERING = 1 << 4;\n    static constexpr uint32_t EMISSIVE_DI = 1 << 5;\n    static constexpr uint32_t VISUALIZE_LVG = 1 << 6;\n};\n\nstruct cbCompositing\n{\n    uint32_t InscatteringDescHeapIdx;\n    uint32_t SkyDIDescHeapIdx;\n    uint32_t EmissiveDIDescHeapIdx;\n    uint32_t IndirectDescHeapIdx;\n    uint32_t OutputUAVDescHeapIdx;\n\n    float DepthMappingExp;\n    float VoxelGridNearZ;\n    float VoxelGridFarZ;\n\n    uint32_t Flags;\n};\n\nstruct cbFireflyFilter\n{\n    uint32_t CompositedUAVDescHeapIdx;\n};\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/Compositing/FireflyFilter.hlsl",
    "content": "#include \"Compositing_Common.h\"\n#include \"../Common/FrameConstants.h\"\n#include \"../Common/StaticTextureSamplers.hlsli\"\n#include \"../Common/GBuffers.hlsli\"\n#include \"../../ZetaCore/Core/Material.h\"\n#include \"../Common/RT.hlsli\"\n#include \"../Common/Volumetric.hlsli\"\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFireflyFilter> g_local : register(b0);\nConstantBuffer<cbFrameConstants> g_frame : register(b1);\n\n//--------------------------------------------------------------------------------------\n// Helper Functions\n//--------------------------------------------------------------------------------------\n\nfloat GeometryTest(float sampleLinearDepth, float2 sampleUV, float3 centerNormal, \n    float3 centerPos, float centerLinearDepth)\n{\n    float3 samplePos = Math::WorldPosFromUV(sampleUV,\n        float2(g_frame.RenderWidth, g_frame.RenderHeight),\n        sampleLinearDepth, g_frame.TanHalfFOV, g_frame.AspectRatio,\n        g_frame.CurrViewInv, g_frame.CurrCameraJitter);\n    \n    float planeDist = dot(centerNormal, samplePos - centerPos);\n    float weight = abs(planeDist) <= 0.01 * centerLinearDepth;\n    \n    return weight;\n}\n\n// Ref: P. Kozlowski and T. Cheblokov, \"ReLAX: A Denoiser Tailored to Work with the ReSTIR Algorithm,\" GTC, 2021.\nfloat3 FilterFirefly(RWTexture2D<float4> g_input, float3 currColor, int2 DTid, int2 GTid, \n    float linearDepth, float3 normal, float3 pos)\n{\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + GBUFFER_OFFSET::DEPTH];\n\n    float minLum = FLT_MAX;\n    float maxLum = 0.0;\n    float3 minColor = currColor;\n    float3 maxColor = 0.0.xxx;\n    float currLum = Math::Luminance(currColor);\n    const uint2 renderDim = uint2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float2 rcpRenderDim = 1.0f / float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    \n    [unroll]\n    for (int i = -1; i <= 1; i++)\n    {\n        [unroll]\n        for (int j = -1; j <= 1; j++)\n        {\n            if (i == 0 && j == 0)\n                continue;\n            \n            int2 addr = int2(DTid.x + j, DTid.y + i);\n            if (any(addr) < 0 || any(addr >= renderDim))\n                continue;\n            \n            const float neighborLinearDepth = g_depth[addr];\n            if (neighborLinearDepth == FLT_MAX)\n                continue;\n            \n            float2 neighborUV = (addr + 0.5) * rcpRenderDim;\n#if 0\n            if (!GeometryTest(neighborLinearDepth, neighborUV, normal, pos, linearDepth))\n                continue;\n#endif\n            float3 neighborColor = g_input[addr].rgb;\n            float neighborLum = Math::Luminance(neighborColor);\n\n            if (neighborLum < minLum)\n            {\n                minLum = neighborLum;\n                minColor = neighborColor;\n            }\n            else if (neighborLum > maxLum)\n            {\n                maxLum = neighborLum;\n                maxColor = neighborColor;\n            }\n        }\n    }\n    \n    float3 ret = currLum < minLum ? minColor : (currLum > maxLum ? maxColor : currColor);\n    ret = minLum <= maxLum ? ret : currColor;\n    \n    return ret;\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(FIREFLY_FILTER_THREAD_GROUP_DIM_X, FIREFLY_FILTER_THREAD_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint Gidx : SV_GroupIndex)\n{\n    if (DTid.x >= g_frame.RenderWidth || DTid.y >= g_frame.RenderHeight)\n        return;\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + GBUFFER_OFFSET::DEPTH];\n    const float z_view = g_depth[DTid.xy];\n    \n    RWTexture2D<float4> g_composited = ResourceDescriptorHeap[g_local.CompositedUAVDescHeapIdx];\n    float3 color = g_composited[DTid.xy].rgb;\n    \n    if (z_view == FLT_MAX)\n    {\n        g_composited[DTid.xy].rgb = color;\n        return;\n    }\n\n    const float3 pos = Math::WorldPosFromScreenSpace(DTid.xy,\n        float2(g_frame.RenderWidth, g_frame.RenderHeight), z_view, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrViewInv, \n        g_frame.CurrCameraJitter);\n    \n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_normal[DTid.xy]);\n\n    color = FilterFirefly(g_composited, color, DTid.xy, GTid.xy, z_view, normal, pos);\n    g_composited[DTid.xy].rgb = color;\n}"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/CMakeLists.txt",
    "content": "set(RP_SKY_DI_DIR ${ZETA_RENDER_PASS_DIR}/DirectLighting/Sky)\nset(RP_EMISSIVE_DI_DIR ${ZETA_RENDER_PASS_DIR}/DirectLighting/Emissive)\nset(RP_DI_SRC\n    ${RP_SKY_DI_DIR}/PairwiseMIS.hlsli\n    ${RP_SKY_DI_DIR}/Params.hlsli\n    ${RP_SKY_DI_DIR}/Resampling.hlsli\n    ${RP_SKY_DI_DIR}/Reservoir.hlsli\n\t${RP_SKY_DI_DIR}/SkyDI.cpp\n    ${RP_SKY_DI_DIR}/SkyDI.h\n    ${RP_SKY_DI_DIR}/SkyDI_Temporal.hlsl\n    ${RP_SKY_DI_DIR}/SkyDI_Spatial.hlsl\n    ${RP_SKY_DI_DIR}/SkyDI_Common.h\n    ${RP_EMISSIVE_DI_DIR}/DirectLighting.cpp\n    ${RP_EMISSIVE_DI_DIR}/DirectLighting.h\n    ${RP_EMISSIVE_DI_DIR}/DirectLighting_Common.h\n    ${RP_EMISSIVE_DI_DIR}/PairwiseMIS.hlsli\n    ${RP_EMISSIVE_DI_DIR}/Params.hlsli\n    ${RP_EMISSIVE_DI_DIR}/Resampling.hlsli\n    ${RP_EMISSIVE_DI_DIR}/Reservoir.hlsli\n    ${RP_EMISSIVE_DI_DIR}/ReSTIR_DI_Temporal.hlsl\n    ${RP_EMISSIVE_DI_DIR}/ReSTIR_DI_Temporal_WPS.hlsl\n    ${RP_EMISSIVE_DI_DIR}/ReSTIR_DI_Spatial.hlsl\n    ${RP_EMISSIVE_DI_DIR}/Util.hlsli)\nset(RP_DI_SRC ${RP_DI_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Emissive/DirectLighting.cpp",
    "content": "#include \"DirectLighting.h\"\n#include <Core/CommandList.h>\n#include <Scene/SceneCore.h>\n#include <Support/Param.h>\n#include <Support/Task.h>\n#include \"../Assets/Font/IconsFontAwesome6.h\"\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Core::Direct3DUtil;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::RT;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::App;\n\n//--------------------------------------------------------------------------------------\n// DirectLighting\n//--------------------------------------------------------------------------------------\n\nDirectLighting::DirectLighting()\n    : RenderPassBase(NUM_CBV, NUM_SRV, NUM_UAV, NUM_GLOBS, NUM_CONSTS)\n{\n    // frame constants\n    m_rootSig.InitAsCBV(0, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::FRAME_CONSTANTS_BUFFER);\n\n    // root constants\n    m_rootSig.InitAsConstants(1, NUM_CONSTS, 1);\n\n    // BVH\n    m_rootSig.InitAsBufferSRV(2, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::RT_SCENE_BVH_CURR);\n    // BVH\n    m_rootSig.InitAsBufferSRV(3, 1, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::RT_SCENE_BVH_PREV);\n\n    // emissive triangles\n    m_rootSig.InitAsBufferSRV(4, 2, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::EMISSIVE_TRIANGLE_BUFFER);\n\n    // alias table\n    m_rootSig.InitAsBufferSRV(5, 3, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::EMISSIVE_TRIANGLE_ALIAS_TABLE);\n\n    // sample set SRV\n    m_rootSig.InitAsBufferSRV(6, 4, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::PRESAMPLED_EMISSIVE_SETS,\n        true);\n\n    // mesh buffer\n    m_rootSig.InitAsBufferSRV(7, 5, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::RT_FRAME_MESH_INSTANCES_CURR);\n}\n\nvoid DirectLighting::InitPSOs()\n{\n    constexpr D3D12_ROOT_SIGNATURE_FLAGS flags =\n        D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;\n\n    auto samplers = App::GetRenderer().GetStaticSamplers();\n    RenderPassBase::InitRenderPass(\"DirectLighting\", flags, samplers);\n\n    TaskSet ts;\n\n    for (int i = 0; i < (int)SHADER::COUNT; i++)\n    {\n        StackStr(buff, n, \"RDI_shader_%d\", i);\n\n        ts.EmplaceTask(buff, [i, this]()\n            {\n                m_psoLib.CompileComputePSO_MT(i, m_rootSigObj.Get(),\n                    COMPILED_CS[i]);\n            });\n    }\n\n    ts.Sort();\n    ts.Finalize();\n    App::Submit(ZetaMove(ts));\n}\n\nvoid DirectLighting::Init()\n{\n    InitPSOs();\n\n    memset(&m_cbSpatioTemporal, 0, sizeof(m_cbSpatioTemporal));\n    m_cbSpatioTemporal.M_max = DefaultParamVals::M_MAX;\n    m_cbSpatioTemporal.Alpha_min = DefaultParamVals::ROUGHNESS_MIN * DefaultParamVals::ROUGHNESS_MIN;\n    SET_CB_FLAG(m_cbSpatioTemporal, CB_RDI_FLAGS::STOCHASTIC_SPATIAL, true);\n    SET_CB_FLAG(m_cbSpatioTemporal, CB_RDI_FLAGS::EXTRA_DISOCCLUSION_SAMPLING, true);\n\n    m_descTable = App::GetRenderer().GetGpuDescriptorHeap().Allocate((int)DESC_TABLE::COUNT);\n    CreateOutputs();\n\n    ParamVariant doTemporal;\n    doTemporal.InitBool(ICON_FA_FILM \" Renderer\", \"Direct Lighting (Emissive)\", \"Temporal Resample\",\n        fastdelegate::MakeDelegate(this, &DirectLighting::TemporalResamplingCallback), m_temporalResampling);\n    App::AddParam(doTemporal);\n\n    ParamVariant doSpatial;\n    doSpatial.InitBool(ICON_FA_FILM \" Renderer\", \"Direct Lighting (Emissive)\", \"Spatial Resample\",\n        fastdelegate::MakeDelegate(this, &DirectLighting::SpatialResamplingCallback), m_spatialResampling);\n    App::AddParam(doSpatial);\n\n    ParamVariant maxTemporalM;\n    maxTemporalM.InitInt(ICON_FA_FILM \" Renderer\", \"Direct Lighting (Emissive)\", \"M_max\",\n        fastdelegate::MakeDelegate(this, &DirectLighting::MaxTemporalMCallback),\n        m_cbSpatioTemporal.M_max, 1, 30, 1);\n    App::AddParam(maxTemporalM);\n\n    ParamVariant extraDissocclusion;\n    extraDissocclusion.InitBool(ICON_FA_FILM \" Renderer\", \"Direct Lighting (Emissive)\", \"Extra Sampling (Disocclusion)\",\n        fastdelegate::MakeDelegate(this, &DirectLighting::ExtraSamplesDisocclusionCallback), \n        IS_CB_FLAG_SET(m_cbSpatioTemporal, CB_RDI_FLAGS::EXTRA_DISOCCLUSION_SAMPLING));\n    App::AddParam(extraDissocclusion);\n\n    ParamVariant stochasticSpatial;\n    stochasticSpatial.InitBool(ICON_FA_FILM \" Renderer\", \"Direct Lighting (Emissive)\", \"Stochastic Spatial\",\n        fastdelegate::MakeDelegate(this, &DirectLighting::StochasticSpatialCallback), \n        IS_CB_FLAG_SET(m_cbSpatioTemporal, CB_RDI_FLAGS::STOCHASTIC_SPATIAL));\n    App::AddParam(stochasticSpatial);\n\n    ParamVariant alphaMin;\n    alphaMin.InitFloat(ICON_FA_FILM \" Renderer\", \"Direct Lighting (Emissive)\", \"Alpha_min\",\n        fastdelegate::MakeDelegate(this, &DirectLighting::AlphaMinCallback),\n        DefaultParamVals::ROUGHNESS_MIN, 0.0f, 1.0f, 1e-2f);\n    App::AddParam(alphaMin);\n\n    App::AddShaderReloadHandler(\"ReSTIR_DI\", fastdelegate::MakeDelegate(this, \n        &DirectLighting::ReloadTemporal));\n\n    m_isTemporalReservoirValid = false;\n}\n\nvoid DirectLighting::OnWindowResized()\n{\n    CreateOutputs();\n    m_isTemporalReservoirValid = false;\n    m_currTemporalIdx = 0;\n}\n\nvoid DirectLighting::ResetTemporal()\n{\n    m_isTemporalReservoirValid = false;\n    m_currTemporalIdx = 0;\n    SET_CB_FLAG(m_cbSpatioTemporal, CB_RDI_FLAGS::RESET_TEMPORAL_TEXTURES, true);\n}\n\nvoid DirectLighting::Render(CommandList& cmdList)\n{\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT ||\n        cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE, \"Invalid downcast\");\n    ComputeCmdList& computeCmdList = static_cast<ComputeCmdList&>(cmdList);\n\n    Assert(!m_preSampling || (m_cbSpatioTemporal.NumSampleSets && m_cbSpatioTemporal.SampleSetSize),\n        \"Light presampling is enabled, but the number and size of sets haven't been set.\");\n\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n    const uint32_t w = renderer.GetRenderWidth();\n    const uint32_t h = renderer.GetRenderHeight();\n\n    computeCmdList.SetRootSignature(m_rootSig, m_rootSigObj.Get());\n\n    const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_DI_TEMPORAL_GROUP_DIM_X);\n    const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_DI_TEMPORAL_GROUP_DIM_Y);\n\n    const bool doTemporal = m_isTemporalReservoirValid && m_temporalResampling;\n    const bool doSpatial = doTemporal && m_spatialResampling;\n\n    SET_CB_FLAG(m_cbSpatioTemporal, CB_RDI_FLAGS::TEMPORAL_RESAMPLE, doTemporal);\n    SET_CB_FLAG(m_cbSpatioTemporal, CB_RDI_FLAGS::SPATIAL_RESAMPLE, doSpatial);\n\n    m_cbSpatioTemporal.DispatchDimX = (uint16_t)dispatchDimX;\n    m_cbSpatioTemporal.DispatchDimY = (uint16_t)dispatchDimY;\n    m_cbSpatioTemporal.NumGroupsInTile = RESTIR_DI_TILE_WIDTH * m_cbSpatioTemporal.DispatchDimY;\n\n    // Initial candidates and temporal\n    {\n        computeCmdList.PIXBeginEvent(\"ReSTIR_DI_Temporal\");\n        const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"ReSTIR_DI_Temporal\");\n\n        SmallVector<D3D12_TEXTURE_BARRIER, SystemAllocator, Reservoir::NUM * 2> barriers;\n\n        // Current reservoirs into UAV\n        if (m_reservoir[m_currTemporalIdx].Layout != D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS)\n        {\n            barriers.push_back(TextureBarrier_SrvToUavNoSync(\n                m_reservoir[m_currTemporalIdx].A.Resource()));\n            barriers.push_back(TextureBarrier_SrvToUavNoSync(\n                m_reservoir[m_currTemporalIdx].B.Resource()));\n\n            m_reservoir[m_currTemporalIdx].Layout = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS;\n        }\n\n        // Temporal reservoirs into SRV\n        if (doTemporal)\n        {\n            if (m_reservoir[1 - m_currTemporalIdx].Layout ==\n                D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS)\n            {\n                barriers.push_back(TextureBarrier_UavToSrvNoSync(\n                    m_reservoir[1 - m_currTemporalIdx].A.Resource()));\n                barriers.push_back(TextureBarrier_UavToSrvNoSync(\n                    m_reservoir[1 - m_currTemporalIdx].B.Resource()));\n\n                m_reservoir[1 - m_currTemporalIdx].Layout =\n                    D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE;\n            }\n        }\n\n        if (!barriers.empty())\n            computeCmdList.ResourceBarrier(barriers.data(), (UINT)barriers.size());\n\n        auto srvAIdx = m_currTemporalIdx == 1 ? DESC_TABLE::RESERVOIR_0_A_SRV :\n            DESC_TABLE::RESERVOIR_1_A_SRV;\n        auto uavAIdx = m_currTemporalIdx == 1 ? DESC_TABLE::RESERVOIR_1_A_UAV :\n            DESC_TABLE::RESERVOIR_0_A_UAV;\n\n        m_cbSpatioTemporal.PrevReservoir_A_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)srvAIdx);\n        m_cbSpatioTemporal.CurrReservoir_A_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)uavAIdx);\n\n        m_rootSig.SetRootConstants(0, sizeof(m_cbSpatioTemporal) / sizeof(DWORD), &m_cbSpatioTemporal);\n        m_rootSig.End(computeCmdList);\n\n        auto sh = m_preSampling ? SHADER::TEMPORAL_LIGHT_PRESAMPLING : SHADER::TEMPORAL;\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)sh));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n\n        gpuTimer.EndQuery(computeCmdList, queryIdx);\n        cmdList.PIXEndEvent();\n    }\n\n    // Spatial\n    if (doSpatial)\n    {\n        computeCmdList.PIXBeginEvent(\"ReSTIR_DI_Spatial\");\n        const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"ReSTIR_DI_Spatial\");\n\n        D3D12_TEXTURE_BARRIER barriers[Reservoir::NUM];\n\n        // current reservoirs into UAV\n        barriers[0] = TextureBarrier_UavToSrvWithSync(m_reservoir[m_currTemporalIdx].A.Resource());\n        barriers[1] = TextureBarrier_UavToSrvWithSync(m_reservoir[m_currTemporalIdx].B.Resource());\n        computeCmdList.ResourceBarrier(barriers, ZetaArrayLen(barriers));\n\n        m_reservoir[m_currTemporalIdx].Layout = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE;\n\n        auto srvAIdx = m_currTemporalIdx == 1 ? DESC_TABLE::RESERVOIR_1_A_SRV :\n            DESC_TABLE::RESERVOIR_0_A_SRV;\n\n        m_cbSpatioTemporal.CurrReservoir_A_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)srvAIdx);\n\n        m_rootSig.SetRootConstants(0, sizeof(m_cbSpatioTemporal) / sizeof(DWORD), &m_cbSpatioTemporal);\n        m_rootSig.End(computeCmdList);\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::SPATIAL));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n\n        gpuTimer.EndQuery(computeCmdList, queryIdx);\n        cmdList.PIXEndEvent();\n    }\n\n    m_isTemporalReservoirValid = true;\n    m_currTemporalIdx = 1 - m_currTemporalIdx;\n    SET_CB_FLAG(m_cbSpatioTemporal, CB_RDI_FLAGS::RESET_TEMPORAL_TEXTURES, false);\n}\n\nvoid DirectLighting::CreateOutputs()\n{\n    auto& renderer = App::GetRenderer();\n    const auto w = renderer.GetRenderWidth();\n    const auto h = renderer.GetRenderHeight();\n\n    constexpr int N = 2 * Reservoir::NUM + 1 + 1;\n    PlacedResourceList<N> list;\n\n    // reservoirs\n    for (int i = 0; i < 2; i++)\n    {\n        list.PushTex2D(ResourceFormats::RESERVOIR_A, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats::RESERVOIR_B, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n    }\n\n    // target\n    list.PushTex2D(ResourceFormats::TARGET, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n    // final\n    list.PushTex2D(ResourceFormats::FINAL, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n    list.End();\n\n    m_resHeap = GpuMemory::GetResourceHeap(list.TotalSizeInBytes());\n    auto allocs = list.AllocInfos();\n    int currRes = 0;\n\n    auto func = [this, w, h](Texture& tex, DXGI_FORMAT format, const char* baseName, int idx,\n        const char* subName, const D3D12_RESOURCE_ALLOCATION_INFO1& allocInfo,\n        int srvIdx, int uavIdx, int descOffset, D3D12_BARRIER_LAYOUT layout)\n        {\n            StackStr(name, N, \"%s_%d_%s\", baseName, idx, subName);\n            tex = GpuMemory::GetPlacedTexture2D(name, w, h, format, m_resHeap.Heap(), allocInfo.Offset,\n                layout, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n            Direct3DUtil::CreateTexture2DSRV(tex, m_descTable.CPUHandle(srvIdx + descOffset));\n            Direct3DUtil::CreateTexture2DUAV(tex, m_descTable.CPUHandle(uavIdx + descOffset));\n        };\n\n    static_assert((int)(DESC_TABLE::RESERVOIR_0_A_SRV) + 1 == (int)DESC_TABLE::RESERVOIR_0_B_SRV);\n    static_assert((int)(DESC_TABLE::RESERVOIR_0_A_UAV) + 1 == (int)DESC_TABLE::RESERVOIR_0_B_UAV);\n    static_assert((int)(DESC_TABLE::RESERVOIR_1_A_SRV) + 1 == (int)DESC_TABLE::RESERVOIR_1_B_SRV);\n    static_assert((int)(DESC_TABLE::RESERVOIR_1_A_UAV) + 1 == (int)DESC_TABLE::RESERVOIR_1_B_UAV);\n\n    const D3D12_BARRIER_LAYOUT initLayout[2] = { D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS,\n        m_temporalResampling ?\n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE :\n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS };\n\n    // reservoirs\n    for (int i = 0; i < 2; i++)\n    {\n        const int descOffset = i * Reservoir::NUM * 2;\n        const auto layout = initLayout[i];\n\n        func(m_reservoir[i].A, ResourceFormats::RESERVOIR_A,\n            \"RDI_Reservoir\", i, \"A\", allocs[currRes++],\n            (int)DESC_TABLE::RESERVOIR_0_A_SRV, (int)DESC_TABLE::RESERVOIR_0_A_UAV,\n            descOffset, layout);\n        func(m_reservoir[i].B, ResourceFormats::RESERVOIR_B,\n            \"RDI_Reservoir\", i, \"B\", allocs[currRes++],\n            (int)DESC_TABLE::RESERVOIR_0_B_SRV, (int)DESC_TABLE::RESERVOIR_0_B_UAV,\n            descOffset, layout);\n\n        m_reservoir[i].Layout = initLayout[i];\n    }\n\n    // target\n    m_target = GpuMemory::GetPlacedTexture2D(\"RDI_target\", w, h, ResourceFormats::TARGET,\n        m_resHeap.Heap(), allocs[currRes++].Offset,\n        D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS,\n        TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n    // final\n    m_final = GpuMemory::GetPlacedTexture2D(\"RDI_Final\", w, h, ResourceFormats::FINAL,\n        m_resHeap.Heap(), allocs[currRes++].Offset,\n        D3D12_RESOURCE_STATE_COMMON,\n        TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n    Direct3DUtil::CreateTexture2DUAV(m_target, m_descTable.CPUHandle((int)DESC_TABLE::TARGET_UAV));\n    Direct3DUtil::CreateTexture2DUAV(m_final, m_descTable.CPUHandle((int)DESC_TABLE::FINAL_UAV));\n\n    // Following never change, so can be set only once\n    m_cbSpatioTemporal.TargetDescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n        (int)DESC_TABLE::TARGET_UAV);\n    m_cbSpatioTemporal.FinalDescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n        (int)DESC_TABLE::FINAL_UAV);\n}\n\nvoid DirectLighting::TemporalResamplingCallback(const Support::ParamVariant& p)\n{\n    m_temporalResampling = p.GetBool();\n    App::GetScene().SceneModified();\n}\n\nvoid DirectLighting::SpatialResamplingCallback(const Support::ParamVariant& p)\n{\n    m_spatialResampling = p.GetBool();\n    App::GetScene().SceneModified();\n}\n\nvoid DirectLighting::MaxTemporalMCallback(const Support::ParamVariant& p)\n{\n    m_cbSpatioTemporal.M_max = (uint16_t)p.GetInt().m_value;\n    App::GetScene().SceneModified();\n}\n\nvoid DirectLighting::ExtraSamplesDisocclusionCallback(const Support::ParamVariant& p)\n{\n    SET_CB_FLAG(m_cbSpatioTemporal, CB_RDI_FLAGS::EXTRA_DISOCCLUSION_SAMPLING, p.GetBool());\n    App::GetScene().SceneModified();\n}\n\nvoid DirectLighting::StochasticSpatialCallback(const Support::ParamVariant& p)\n{\n    SET_CB_FLAG(m_cbSpatioTemporal, CB_RDI_FLAGS::STOCHASTIC_SPATIAL, p.GetBool());\n    App::GetScene().SceneModified();\n}\n\nvoid DirectLighting::AlphaMinCallback(const Support::ParamVariant& p)\n{\n    float newVal = p.GetFloat().m_value;\n    m_cbSpatioTemporal.Alpha_min = newVal * newVal;\n\n    App::GetScene().SceneModified();\n}\n\nvoid DirectLighting::ReloadTemporal()\n{\n    const int i = m_preSampling ? (int)SHADER::TEMPORAL_LIGHT_PRESAMPLING :\n        (int)SHADER::TEMPORAL;\n\n    m_psoLib.Reload(i, m_rootSigObj.Get(), m_preSampling ?\n        \"DirectLighting\\\\Emissive\\\\ReSTIR_DI_Temporal_WPS.hlsl\" :\n        \"DirectLighting\\\\Emissive\\\\ReSTIR_DI_Temporal.hlsl\");\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Emissive/DirectLighting.h",
    "content": "#pragma once\n\n#include \"../../RenderPass.h\"\n#include <Core/GpuMemory.h>\n#include \"DirectLighting_Common.h\"\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n    struct RenderNodeHandle;\n}\n\nnamespace ZetaRay::Support\n{\n    struct ParamVariant;\n}\n\nnamespace ZetaRay::RenderPass\n{\n    enum class DIRECT_SHADER\n    {\n        TEMPORAL,\n        TEMPORAL_LIGHT_PRESAMPLING,\n        SPATIAL,\n        COUNT\n    };\n\n    struct DirectLighting final : public RenderPassBase<(int)DIRECT_SHADER::COUNT>\n    {\n        enum class SHADER_OUT_RES\n        {\n            FINAL,\n            COUNT\n        };\n\n        DirectLighting();\n        ~DirectLighting() = default;\n\n        void InitPSOs();\n        void Init();\n        void OnWindowResized();\n        void ResetTemporal();\n        void SetLightPresamplingParams(bool enabled, int numSampleSets, int sampleSetSize)\n        {\n            Assert(!enabled || (numSampleSets > 0 && sampleSetSize > 0), \n                \"Presampling is enabled, but the number of sample sets is zero.\");\n\n            m_preSampling = enabled;\n            m_cbSpatioTemporal.NumSampleSets = enabled ? (uint16_t)numSampleSets : 0;\n            m_cbSpatioTemporal.SampleSetSize = enabled ? (uint16_t)sampleSetSize : 0;\n        }\n        const Core::GpuMemory::Texture& GetOutput(SHADER_OUT_RES i) const\n        {\n            Assert(i == SHADER_OUT_RES::FINAL, \"Invalid shader output.\");\n            return m_final;\n        }\n        void Render(Core::CommandList& cmdList);\n\n    private:\n        static constexpr int NUM_CBV = 1;\n        static constexpr int NUM_SRV = 6;\n        static constexpr int NUM_UAV = 0;\n        static constexpr int NUM_GLOBS = 7;\n        static constexpr int NUM_CONSTS = (int)(sizeof(cb_ReSTIR_DI) / sizeof(DWORD));\n        using SHADER = DIRECT_SHADER;\n\n        struct ResourceFormats\n        {\n            static constexpr DXGI_FORMAT RESERVOIR_A = DXGI_FORMAT_R32G32B32A32_UINT;\n            static constexpr DXGI_FORMAT RESERVOIR_B = DXGI_FORMAT_R32G32_FLOAT;\n            static constexpr DXGI_FORMAT TARGET = DXGI_FORMAT_R16G16B16A16_FLOAT;\n            static constexpr DXGI_FORMAT FINAL = DXGI_FORMAT_R32G32B32A32_FLOAT;\n        };\n\n        enum class DESC_TABLE\n        {\n            RESERVOIR_0_A_SRV,\n            RESERVOIR_0_B_SRV,\n            RESERVOIR_0_A_UAV,\n            RESERVOIR_0_B_UAV,\n            //\n            RESERVOIR_1_A_SRV,\n            RESERVOIR_1_B_SRV,\n            RESERVOIR_1_A_UAV,\n            RESERVOIR_1_B_UAV,\n            //\n            TARGET_UAV,\n            FINAL_UAV,\n            //\n            COUNT\n        };\n\n        struct DefaultParamVals\n        {\n            static constexpr int M_MAX = 20;\n            // Use half-vector copy for anything lower\n            static constexpr float ROUGHNESS_MIN = 0.05f;\n        };\n\n        inline static constexpr const char* COMPILED_CS[(int)SHADER::COUNT] = {\n            \"ReSTIR_DI_Temporal_cs.cso\",\n            \"ReSTIR_DI_Temporal_WPS_cs.cso\",\n            \"ReSTIR_DI_Spatial_cs.cso\"\n        };\n\n        struct Reservoir\n        {\n            static constexpr int NUM = 2;\n\n            // Texture2D<uint4>: ((Li.g << 16 | Li.r), (M << 16 | Li.b), (bary.y << 16 | bary.x), W)\n            Core::GpuMemory::Texture A;\n            // Texture2D<uint>: (lightIdx)\n            Core::GpuMemory::Texture B;\n\n            D3D12_BARRIER_LAYOUT Layout;\n        };\n\n        void CreateOutputs();\n\n        // param callbacks\n        void TemporalResamplingCallback(const Support::ParamVariant& p);\n        void SpatialResamplingCallback(const Support::ParamVariant& p);\n        void MaxTemporalMCallback(const Support::ParamVariant& p);\n        void ExtraSamplesDisocclusionCallback(const Support::ParamVariant& p);\n        void StochasticSpatialCallback(const Support::ParamVariant& p);\n        void AlphaMinCallback(const Support::ParamVariant& p);\n\n        // shader reload\n        void ReloadTemporal();\n\n        Core::DescriptorTable m_descTable;\n        Reservoir m_reservoir[2];\n        Core::GpuMemory::ResourceHeap m_resHeap;\n        Core::GpuMemory::Texture m_target;\n        Core::GpuMemory::Texture m_final;\n\n        int m_currTemporalIdx = 0;\n        bool m_isTemporalReservoirValid = false;\n        bool m_temporalResampling = true;\n        bool m_spatialResampling = true;\n        bool m_preSampling = false;\n\n        cb_ReSTIR_DI m_cbSpatioTemporal;\n    };\n}"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Emissive/DirectLighting_Common.h",
    "content": "#ifndef DIRECT_LIGHTING_COMMON_H\n#define DIRECT_LIGHTING_COMMON_H\n\n#include \"../../../ZetaCore/RayTracing/RtCommon.h\"\n\n#define RESTIR_DI_TEMPORAL_GROUP_DIM_X 8u\n#define RESTIR_DI_TEMPORAL_GROUP_DIM_Y 8u\n\n#define RESTIR_DI_TILE_WIDTH 16\n#define RESTIR_DI_LOG2_TILE_WIDTH 4\n\nnamespace CB_RDI_FLAGS\n{\n    static constexpr uint32_t TEMPORAL_RESAMPLE = 1 << 0;\n    static constexpr uint32_t SPATIAL_RESAMPLE = 1 << 1;\n    static constexpr uint32_t STOCHASTIC_SPATIAL = 1 << 2;\n    static constexpr uint32_t EXTRA_DISOCCLUSION_SAMPLING = 1 << 3;\n    static constexpr uint32_t RESET_TEMPORAL_TEXTURES = 1 << 4;\n};\n\nstruct cb_ReSTIR_DI\n{\n    uint32_t PrevReservoir_A_DescHeapIdx;\n    uint32_t CurrReservoir_A_DescHeapIdx;\n\n    uint32_t TargetDescHeapIdx;\n    uint32_t FinalDescHeapIdx;\n\n    float Alpha_min;\n    uint32_t Flags;\n    uint32_t M_max;\n    uint32_t NumSampleSets;\n    uint32_t SampleSetSize;\n    uint16_t DispatchDimX;\n    uint16_t DispatchDimY;\n    uint16_t NumGroupsInTile;\n    uint16_t pad;\n};\n\n#endif\n"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Emissive/PairwiseMIS.hlsli",
    "content": "#ifndef RESTIR_DI_PAIRWISE_MIS_H\n#define RESTIR_DI_PAIRWISE_MIS_H\n\n#include \"Util.hlsli\"\n\nnamespace RDI_Util\n{\n    // Ref: Bitterli, Benedikt, \"Correlations and Reuse for Fast and Accurate Physically Based Light Transport\" (2022). Ph.D Dissertation.\n    // https://digitalcommons.dartmouth.edu/dissertations/77\n    struct PairwiseMIS\n    {    \n        static PairwiseMIS Init(uint16_t numStrategies, Reservoir r_c)\n        {\n            PairwiseMIS ret;\n            ret.r_s = Reservoir::Init();\n            ret.m_c = 1.0f;\n            ret.M_s = r_c.M;\n            ret.k = numStrategies;\n\n            return ret;\n        }\n\n        float Compute_m_i(Reservoir r_c, Reservoir r_i, float targetLum, float jacobian)\n        {\n            const float p_i_y_i = r_i.W > 0 ? r_i.w_sum / r_i.W : 0;\n            const float p_c_y_i = targetLum;\n            float numerator = r_i.M * p_i_y_i;\n            float denom = (numerator / jacobian) + ((float)r_c.M / this.k) * p_c_y_i;\n            float m_i = denom > 0 ? numerator / denom : 0;\n\n            return m_i;\n        }\n\n        void Update_m_c(Reservoir r_c, Reservoir r_i, float targetLum, float jacobian)\n        {\n            const float p_i_y_c = targetLum;\n            const float p_c_y_c = Math::Luminance(r_c.target);\n\n            const float numerator = r_i.M * p_i_y_c * jacobian;\n            const float denom = numerator + ((float)r_c.M / this.k) * p_c_y_c;\n            // Note: denom can never be zero, otherwise r_c didn't have a valid sample\n            // and this function shouldn't have been called\n            this.m_c += 1 - (numerator / denom);\n        }\n\n        void Stream(Reservoir r_c, float3 pos_c, float3 normal_c, BSDF::ShadingData surface_c, \n            Reservoir r_i, float3 pos_i, float3 normal_i, BSDF::ShadingData surface_i, \n            float alpha_min, ConstantBuffer<cbFrameConstants> g_frame, \n            RaytracingAccelerationStructure g_bvh, \n            StructuredBuffer<RT::EmissiveTriangle> g_emissives, \n            StructuredBuffer<RT::MeshInstance> g_frameMeshData,\n            inout RNG rng)\n        {\n            float3 target_c_y_i = 0;\n            float3 target_i_y_c = 0.0;\n            float m_i = 0;\n\n            // m_i\n            if(r_i.lightIdx != UINT32_MAX)\n            {\n                float jacobian_i_to_c = 0;\n\n                if(IsShiftInvertible(r_i, surface_c, alpha_min))\n                {\n                    float3 wh_c = Math::FromTangentFrameToWorld(normal_c, r_i.wh_local);\n                    float3 wh_i = Math::FromTangentFrameToWorld(normal_i, r_i.wh_local);\n                    float whdotwo_i = abs(dot(surface_i.wo, wh_i));\n                    float whdotwo_c = abs(dot(surface_c.wo, wh_c));\n                    jacobian_i_to_c = whdotwo_i > 0 ? whdotwo_c / whdotwo_i : 0;\n                    jacobian_i_to_c = r_c.halfVectorCopyShift ? jacobian_i_to_c : 1;\n\n#if USE_HALF_VECTOR_COPY_SHIFT == 1\n                    if(r_i.halfVectorCopyShift)\n                    {\n                        float3 wi_c = reflect(-surface_c.wo, wh_c);\n\n                        BSDFHitInfo hitInfo = FindClosestHit(pos_c, normal_c, wi_c, g_bvh, \n                            g_frameMeshData, surface_c.Transmissive());\n                        if(hitInfo.hit)\n                        {\n                            RT::EmissiveTriangle emissive = g_emissives[hitInfo.emissiveTriIdx];\n                            float3 le = Light::Le_EmissiveTriangle(emissive, hitInfo.bary, \n                                g_frame.EmissiveMapsDescHeapOffset);\n\n                            const float3 vtx1 = Light::DecodeEmissiveTriV1(emissive);\n                            const float3 vtx2 = Light::DecodeEmissiveTriV2(emissive);\n                            float3 lightNormal = cross(vtx1 - emissive.Vtx0, vtx2 - emissive.Vtx0);\n                            float twoArea = length(lightNormal);\n                            lightNormal = dot(lightNormal, lightNormal) == 0 ? 0 : lightNormal / twoArea;\n                            lightNormal = emissive.IsDoubleSided() && dot(-wi_c, lightNormal) < 0 ? \n                                -lightNormal : lightNormal;\n\n                            // Light is backfacing\n                            if(dot(-wi_c, lightNormal) > 0)\n                            {\n                                float dwdA = saturate(dot(lightNormal, -wi_c)) / (hitInfo.t * hitInfo.t);\n                                target_c_y_i = le * dwdA;\n                            }\n\n                            surface_c.SetWi(wi_c, normal_c);\n                        }\n                    }\n                    else\n#endif\n                    {\n                        EmissiveData emissive_i = EmissiveData::Init(r_i.lightIdx, r_i.bary, g_emissives);\n                        emissive_i.SetSurfacePos(pos_c);\n                        float dwdA = emissive_i.dWdA();\n\n                        surface_c.SetWi(emissive_i.wi, normal_c);\n                        target_c_y_i = r_i.le * dwdA;\n                        if(dot(target_c_y_i, target_c_y_i) > 0)\n                        {\n                            target_c_y_i *= RtRayQuery::Visibility_Segment(pos_c, emissive_i.wi, emissive_i.t, normal_c, \n                                emissive_i.ID, g_bvh, surface_c.Transmissive());\n                        }\n                    }\n\n                    target_c_y_i *= BSDF::Unified(surface_c).f;\n                }\n\n                const float targetLum = Math::Luminance(target_c_y_i);\n                m_i = Compute_m_i(r_c, r_i, targetLum, jacobian_i_to_c);\n            }\n\n            // m_c\n            float jacobian_c_to_i = 0;\n\n            if(r_c.lightIdx != UINT32_MAX)\n            {\n                if(IsShiftInvertible(r_c, surface_i, alpha_min))\n                {\n                    float3 wh_i = Math::FromTangentFrameToWorld(normal_i, r_c.wh_local);\n                    float3 wh_c = Math::FromTangentFrameToWorld(normal_c, r_c.wh_local);\n                    float whdotwo_i = abs(dot(surface_i.wo, wh_i));\n                    float whdotwo_c = abs(dot(surface_c.wo, wh_c));\n                    jacobian_c_to_i = whdotwo_c == 0 ? 0 : whdotwo_i / whdotwo_c;\n                    jacobian_c_to_i = r_c.halfVectorCopyShift ? jacobian_c_to_i : 1;\n\n#if USE_HALF_VECTOR_COPY_SHIFT == 1\n                    if(r_i.halfVectorCopyShift)\n                    {\n                        float3 wi_i = reflect(-surface_i.wo, wh_i);\n\n                        BSDFHitInfo hitInfo = FindClosestHit(pos_i, normal_i, wi_i, g_bvh, \n                            g_frameMeshData, surface_i.Transmissive());\n                        if(hitInfo.hit)\n                        {\n                            RT::EmissiveTriangle emissive = g_emissives[hitInfo.emissiveTriIdx];\n                            float3 le = Light::Le_EmissiveTriangle(emissive, hitInfo.bary, \n                                g_frame.EmissiveMapsDescHeapOffset);\n\n                            const float3 vtx1 = Light::DecodeEmissiveTriV1(emissive);\n                            const float3 vtx2 = Light::DecodeEmissiveTriV2(emissive);\n                            float3 lightNormal = cross(vtx1 - emissive.Vtx0, vtx2 - emissive.Vtx0);\n                            float twoArea = length(lightNormal);\n                            lightNormal = dot(lightNormal, lightNormal) == 0 ? 0 : lightNormal / twoArea;\n                            lightNormal = emissive.IsDoubleSided() && dot(-wi_i, lightNormal) < 0 ? \n                                -lightNormal : lightNormal;\n\n                            if(dot(-wi_i, lightNormal) > 0)\n                            {\n                                float dwdA = saturate(dot(lightNormal, -wi_i)) / (hitInfo.t * hitInfo.t);\n                                target_i_y_c = le * dwdA;\n                            }\n\n                            surface_i.SetWi(wi_i, normal_i);\n                        }\n                    }\n                    else\n#endif\n                    {\n                        float3 wi_i = r_c.lightPos - pos_i;\n                        const bool isZero = dot(wi_i, wi_i) == 0;\n                        float t_i = isZero ? 0 : length(wi_i);\n                        wi_i = isZero ? 0 : wi_i / t_i;\n                        surface_i.SetWi(wi_i, normal_i);\n\n                        const float3 lightNormal = dot(r_c.lightNormal, -wi_i) < 0 && r_c.doubleSided ?\n                            -r_c.lightNormal : r_c.lightNormal;\n                        const float cosThetaPrime = saturate(dot(lightNormal, -wi_i));\n                        const float dwdA = isZero ? 0 : cosThetaPrime / (t_i * t_i);\n                        target_i_y_c = r_c.le * dwdA;\n\n                        if(dot(target_i_y_c, target_i_y_c) > 0)\n                        {\n                            target_i_y_c *= RtRayQuery::Visibility_Segment(pos_i, wi_i, t_i, normal_i, \n                                r_c.lightID, g_bvh, surface_i.Transmissive());\n                        }\n                    }\n                }\n\n                target_i_y_c *= BSDF::Unified(surface_i).f;\n            }\n\n            const float targetLum = Math::Luminance(target_i_y_c);\n            Update_m_c(r_c, r_i, targetLum, jacobian_c_to_i);\n\n            if(r_i.lightIdx != UINT32_MAX)\n            {\n                const float w_i = m_i * Math::Luminance(target_c_y_i) * r_i.W;\n\n                if (this.r_s.Update(w_i, r_i.halfVectorCopyShift, r_i.wh_local, 0 /*unused*/, \n                    r_i.lobe, r_i.le, r_i.lightIdx, r_i.bary, rng))\n                {\n                    r_s.target = target_c_y_i;\n                }\n            }\n\n            this.M_s += r_i.M;\n        }\n\n        void End(Reservoir r_c, inout RNG rng)\n        {\n            // w_sum = Luminance(target) * W\n            const float w_c = this.m_c * r_c.w_sum;\n            if (this.r_s.Update(w_c, r_c.halfVectorCopyShift, r_c.wh_local, 0 /*unused*/, \n                r_c.lobe, r_c.le, r_c.lightIdx, r_c.bary, rng))\n            {\n                r_s.target = r_c.target;\n            }\n\n            this.r_s.M = this.M_s;\n            const float targetLum = Math::Luminance(r_s.target);\n            this.r_s.W = targetLum > 0 ? this.r_s.w_sum / (targetLum * (1 + this.k)) : 0;\n        }\n\n        Reservoir r_s;\n        float m_c;\n        half M_s;\n        uint16_t k;\n    };\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Emissive/Params.hlsli",
    "content": "#ifndef RESTIR_DI_PARAMS_H\n#define RESTIR_DI_PARAMS_H\n\n#define NUM_LIGHT_CANDIDATES 3\n#define EXTRA_BSDF_SAMPLE_HIGHLY_GLOSSY 1\n#define MIN_NUM_SPATIAL_SAMPLES 1\n#define NUM_EXTRA_SPATIAL_SAMPLES 1\n#define PROB_EXTRA_SPATIAL_SAMPLES 0.6\n#define MAX_NUM_SPATIAL_SAMPLES 4\n#define SPATIAL_SEARCH_RADIUS 16\n#define APPROXIMATE_EMISSIVE_SHADOW_RAY 1\n#define USE_HALF_VECTOR_COPY_SHIFT 0\n\n// Heuristics for deciding when to reuse between different pixels (temporal or spatial neighbors)\n#define MAX_PLANE_DIST_REUSE 1e-1\n#define MIN_NORMAL_SIMILARITY_REUSE 0.906307787    // within 25 degrees\n#define MAX_ROUGHNESS_DIFF_REUSE 0.15f\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Emissive/ReSTIR_DI_Spatial.hlsl",
    "content": "#include \"Resampling.hlsli\"\n#include \"../../Common/Common.hlsli\"\n#include \"../../Common/BSDFSampling.hlsli\"\n\n#define THREAD_GROUP_SWIZZLING 1\n\nusing namespace RtRayQuery;\nusing namespace RDI_Util;\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_ReSTIR_DI> g_local : register(b1);\nRaytracingAccelerationStructure g_bvh : register(t0);\nStructuredBuffer<RT::EmissiveTriangle> g_emissives : register(t2);\nStructuredBuffer<RT::MeshInstance> g_frameMeshData : register(t5);\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(RESTIR_DI_TEMPORAL_GROUP_DIM_X, RESTIR_DI_TEMPORAL_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID)\n{\n#if THREAD_GROUP_SWIZZLING\n    uint16_t2 swizzledGid;\n\n    const uint2 swizzledDTid = Common::SwizzleThreadGroup(DTid, Gid, GTid, \n        uint16_t2(RESTIR_DI_TEMPORAL_GROUP_DIM_X, RESTIR_DI_TEMPORAL_GROUP_DIM_Y),\n        g_local.DispatchDimX, \n        RESTIR_DI_TILE_WIDTH, \n        RESTIR_DI_LOG2_TILE_WIDTH, \n        g_local.NumGroupsInTile,\n        swizzledGid);\n#else\n    const uint2 swizzledDTid = DTid.xy;\n    const uint2 swizzledGid = Gid.xy;\n#endif\n\n    if (swizzledDTid.x >= g_frame.RenderWidth || swizzledDTid.y >= g_frame.RenderHeight)\n        return;\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr = g_metallicRoughness[swizzledDTid];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n\n    if (flags.invalid)\n        return;\n\n    if(flags.emissive)\n    {\n        GBUFFER_EMISSIVE_COLOR g_emissiveColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::EMISSIVE_COLOR];\n        float3 le = g_emissiveColor[swizzledDTid].rgb;\n\n        RWTexture2D<float4> g_final = ResourceDescriptorHeap[g_local.FinalDescHeapIdx];\n\n        if(g_frame.Accumulate && g_frame.CameraStatic)\n        {\n            float3 prev = g_final[swizzledDTid].rgb;\n            g_final[swizzledDTid].rgb = prev + le;\n        }\n        else\n            g_final[swizzledDTid].rgb = le;\n\n        return;\n    }\n\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_normal[swizzledDTid.xy]);\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float z_view = g_depth[swizzledDTid];\n    \n    float2 lensSample = 0;\n    float3 origin = g_frame.CameraPos;\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(swizzledDTid.xyx).zy, g_frame.FrameNum);\n        lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample *= g_frame.LensRadius;\n    }\n\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float3 pos = Math::WorldPosFromScreenSpace2(swizzledDTid, renderDim, z_view, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n        g_frame.DoF, lensSample, g_frame.FocusDepth, origin);\n\n    GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n    const float4 baseColor = flags.subsurface ? g_baseColor[swizzledDTid] :\n        float4(g_baseColor[swizzledDTid].rgb, 0);\n\n    float eta_curr = ETA_AIR;\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(flags.transmissive)\n    {\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        float ior = g_ior[swizzledDTid];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    float coat_weight = 0;\n    float3 coat_color = 0.0f;\n    float coat_roughness = 0;\n    float coat_ior = DEFAULT_ETA_COAT;\n\n    if(flags.coated)\n    {\n        GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::COAT];\n        uint3 packed = g_coat[swizzledDTid].xyz;\n\n        GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n        coat_weight = coat.weight;\n        coat_color = coat.color;\n        coat_roughness = coat.roughness;\n        coat_ior = coat.ior;\n    }\n\n    const float3 wo = normalize(origin - pos);\n    BSDF::ShadingData surface = BSDF::ShadingData::Init(normal, wo, flags.metallic, mr.y, \n        baseColor.xyz, eta_curr, eta_next, flags.transmissive, flags.trDepthGt0, (half)baseColor.w,\n        coat_weight, coat_color, coat_roughness, coat_ior);\n\n    // Group-uniform index so that every thread in this group uses the same set\n    RNG rng_group = RNG::Init(Gid.xy, g_frame.FrameNum);\n    const uint sampleSetIdx = rng_group.UniformUintBounded_Faster(g_local.NumSampleSets);\n\n    RNG rng_thread = RNG::Init(swizzledDTid, g_frame.FrameNum);\n\n    Reservoir r = Reservoir::Load(swizzledDTid, g_local.CurrReservoir_A_DescHeapIdx, \n        g_local.CurrReservoir_A_DescHeapIdx + 1);\n    bool disoccluded = false;\n\n    if(r.lightIdx != UINT32_MAX)\n    {\n        RT::EmissiveTriangle tri = g_emissives[r.lightIdx];\n        r.lightID = tri.ID;\n\n        const float3 vtx1 = Light::DecodeEmissiveTriV1(tri);\n        const float3 vtx2 = Light::DecodeEmissiveTriV2(tri);\n        r.lightPos = (1.0f - r.bary.x - r.bary.y) * tri.Vtx0 + r.bary.x * vtx1 + r.bary.y * vtx2;\n\n        r.lightNormal = cross(vtx1 - tri.Vtx0, vtx2 - tri.Vtx0);\n        r.lightNormal = dot(r.lightNormal, r.lightNormal) == 0 ? r.lightNormal : \n            normalize(r.lightNormal);\n        r.doubleSided = tri.IsDoubleSided();\n\n        r.LoadTarget(swizzledDTid, g_local.TargetDescHeapIdx);\n        disoccluded = r.target.x < 0 || r.target.y < 0 || r.target.z < 0;\n        r.target = abs(r.target);\n    }\n\n    if(IS_CB_FLAG_SET(CB_RDI_FLAGS::EXTRA_DISOCCLUSION_SAMPLING))\n    {\n        // Skip thin geometry such as grass or fences\n        disoccluded = disoccluded && (WaveActiveSum(disoccluded) > 3);\n    }\n\n    // Since spatial samples are expensive, take extra samples stochastically\n    // per thread group for better coherency\n    int numSamples = !IS_CB_FLAG_SET(CB_RDI_FLAGS::STOCHASTIC_SPATIAL) || (rng_group.Uniform() < PROB_EXTRA_SPATIAL_SAMPLES) ? \n        MIN_NUM_SPATIAL_SAMPLES + NUM_EXTRA_SPATIAL_SAMPLES : \n        MIN_NUM_SPATIAL_SAMPLES;\n    numSamples = !disoccluded ? numSamples : MAX_NUM_SPATIAL_SAMPLES;\n\n    RDI_Util::SpatialResample(swizzledDTid, numSamples, SPATIAL_SEARCH_RADIUS, pos, \n        normal, z_view, mr.y, surface, g_local.Alpha_min, g_local.CurrReservoir_A_DescHeapIdx, \n        g_local.CurrReservoir_A_DescHeapIdx + 1, g_frame, g_bvh, g_emissives, g_frameMeshData,\n        r, rng_thread);\n\n    float3 li = r.target * r.W;\n    li = any(isnan(li)) ? 0 : li;\n    RWTexture2D<float4> g_final = ResourceDescriptorHeap[g_local.FinalDescHeapIdx];\n\n    if(g_frame.Accumulate && g_frame.CameraStatic && g_frame.NumFramesCameraStatic > 1)\n    {\n        float3 prev = g_final[swizzledDTid].rgb;\n        g_final[swizzledDTid].rgb = prev + li;\n    }\n    else\n        g_final[swizzledDTid].rgb = li;\n}"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Emissive/ReSTIR_DI_Temporal.hlsl",
    "content": "#include \"Resampling.hlsli\"\n#include \"../../Common/Common.hlsli\"\n#include \"../../Common/BSDFSampling.hlsli\"\n\n#define THREAD_GROUP_SWIZZLING 1\n\nusing namespace RtRayQuery;\nusing namespace RDI_Util;\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_ReSTIR_DI> g_local : register(b1);\nRaytracingAccelerationStructure g_bvh : register(t0);\nRaytracingAccelerationStructure g_bvh_prev : register(t1);\nStructuredBuffer<RT::EmissiveTriangle> g_emissives : register(t2);\nStructuredBuffer<RT::EmissiveLumenAliasTableEntry> g_aliasTable : register(t3);\n#ifdef USE_PRESAMPLED_SETS \nStructuredBuffer<RT::PresampledEmissiveTriangle> g_sampleSets : register(t4);\n#endif\nStructuredBuffer<RT::MeshInstance> g_frameMeshData : register(t5);\n\n//--------------------------------------------------------------------------------------\n// Helper functions\n//--------------------------------------------------------------------------------------\n\nReservoir RIS_InitialCandidates(uint2 DTid, float3 pos, float3 normal, float roughness,\n    BSDF::ShadingData surface, uint sampleSetIdx, int numBsdfSamples, inout RNG rng)\n{\n    Reservoir r = Reservoir::Init();\n\n    const bool specular = surface.GlossSpecular() && (surface.metallic || surface.specTr) && \n        (!surface.Coated() || surface.CoatSpecular());\n    const int numLightSamples = !specular ? NUM_LIGHT_CANDIDATES : 0;\n\n    // BSDF sampling\n    [loop]\n    for (int s_b = 0; s_b < numBsdfSamples; s_b++)\n    {\n        BSDF::BSDFSample bsdfSample = BSDF::SampleBSDF_NoDiffuse(normal, surface, rng);\n        float3 wi = bsdfSample.wi;\n        float pdf_w = bsdfSample.pdf;\n#if USE_HALF_VECTOR_COPY_SHIFT == 1\n        // i.e. Glossy reflection or coat with lobe roughness below threshold\n        const bool useHalfVecShift = BSDF::LobeAlpha(surface, bsdfSample.lobe) <= g_local.Alpha_min;\n#else\n        const bool useHalfVecShift = false;\n#endif\n\n        // check if closest hit is a light source\n        BSDFHitInfo hitInfo = FindClosestHit(pos, normal, wi, g_bvh, g_frameMeshData, \n            surface.Transmissive());\n\n        float w_b = 0;\n        float3 le = 0;\n        float3 lightNormal = 0;\n        float3 target = 0;\n        uint emissiveID = UINT32_MAX;\n        bool doubleSided = false;\n\n        if (hitInfo.hit)\n        {\n            RT::EmissiveTriangle emissive = g_emissives[hitInfo.emissiveTriIdx];\n            le = Light::Le_EmissiveTriangle(emissive, hitInfo.bary, \n                g_frame.EmissiveMapsDescHeapOffset);\n\n            const float3 vtx1 = Light::DecodeEmissiveTriV1(emissive);\n            const float3 vtx2 = Light::DecodeEmissiveTriV2(emissive);\n            lightNormal = cross(vtx1 - emissive.Vtx0, vtx2 - emissive.Vtx0);\n            float twoArea = length(lightNormal);\n            lightNormal = dot(lightNormal, lightNormal) == 0 ? 0 : lightNormal / twoArea;\n            lightNormal = emissive.IsDoubleSided() && dot(-wi, lightNormal) < 0 ? -lightNormal : lightNormal;\n            doubleSided = emissive.IsDoubleSided();\n            emissiveID = emissive.ID;\n\n            // Light is backfacing\n            if(dot(-wi, lightNormal) > 0)\n            {\n                const float lightSourcePdf = g_aliasTable[hitInfo.emissiveTriIdx].CachedP_Orig;\n                const float pdf_light = lightSourcePdf * (1.0f / (0.5f * twoArea));\n\n                // solid angle measure to area measure\n                const float dwdA = saturate(dot(lightNormal, -wi)) / (hitInfo.t * hitInfo.t);\n                pdf_w *= dwdA;\n\n                // Balance Heuristic\n                const bool sampleIsSpecular = \n                    (surface.GlossSpecular() && bsdfSample.lobe == BSDF::LOBE::GLOSSY_R) || \n                    (surface.CoatSpecular() && bsdfSample.lobe == BSDF::LOBE::COAT);\n                float denom = numBsdfSamples * pdf_w + !sampleIsSpecular * numLightSamples * pdf_light;\n                // pdf_a in m_i's numerator and w_i's denominator cancel out\n                const float m_i = 1.0f / denom; \n\n                // target = Le * BSDF(wi, wo) * |ndotwi|\n                // source = P(wi)\n                target = le * bsdfSample.f * dwdA;\n                w_b = m_i * Math::Luminance(target);\n            }\n        }\n\n        if (r.Update(w_b, useHalfVecShift, wi, surface.wo, normal, bsdfSample.lobe, le, \n            hitInfo.emissiveTriIdx, hitInfo.bary, rng))\n        {\n            r.target = target;\n            r.lightID = emissiveID;\n            r.lightPos = hitInfo.lightPos;\n            r.lightNormal = lightNormal;\n            r.doubleSided = doubleSided;\n        }\n    }\n\n    // light sampling\n    [loop]\n    for (int s_l = 0; s_l < numLightSamples; s_l++)\n    {\n        // sample a light source relative to its power\n#ifdef USE_PRESAMPLED_SETS\n        RT::PresampledEmissiveTriangle tri = Light::SamplePresampledSet(sampleSetIdx, g_sampleSets, \n            g_local.SampleSetSize, rng);\n\n        Light::EmissiveTriSample lightSample;\n        lightSample.pos = tri.pos;\n        lightSample.normal = Math::DecodeOct32(tri.normal);\n        lightSample.bary = Math::DecodeUNorm2(tri.bary);\n\n        float3 le = tri.le;\n        const float pdf_light = tri.pdf;\n        const uint emissiveIdx = tri.idx;\n        const uint lightID = tri.ID;\n        const bool doubleSided = tri.twoSided;\n\n        if(tri.twoSided && dot(pos - tri.pos, lightSample.normal) < 0)\n            lightSample.normal = -lightSample.normal;\n#else\n        Light::AliasTableSample entry = Light::AliasTableSample::get(g_aliasTable, \n            g_frame.NumEmissiveTriangles, rng);\n        RT::EmissiveTriangle tri = g_emissives[entry.idx];\n        Light::EmissiveTriSample lightSample = Light::EmissiveTriSample::get(pos, tri, rng);\n\n        float3 le = Light::Le_EmissiveTriangle(tri, lightSample.bary, g_frame.EmissiveMapsDescHeapOffset);\n        const float pdf_light = entry.pdf * lightSample.pdf;\n        const uint emissiveIdx = entry.idx;\n        const uint lightID = tri.ID;\n        const bool doubleSided = tri.IsDoubleSided();\n#endif\n\n        float3 target = 0;\n        float3 wi = lightSample.pos - pos;\n        const bool isZero = dot(wi, wi) == 0;\n        const float t = isZero ? 0 : length(wi);\n        wi = isZero ? wi : wi / t;\n        const float dwdA = isZero ? 0 : saturate(dot(lightSample.normal, -wi)) / (t * t);\n        surface.SetWi(wi, normal);\n\n        // skip backfacing lights\n        if(dot(lightSample.normal, -wi) > 0)\n        {\n            target = le * BSDF::Unified(surface).f * dwdA;\n            if (dot(target, target) > 0)\n            {\n                target *= Visibility_Segment(pos, wi, t, normal, lightID, g_bvh, \n                    surface.Transmissive());\n            }\n        }\n\n        // pdf_light in m_i's numerator and w_i's denominator cancel out\n        const float denom = numLightSamples * pdf_light + \n            numBsdfSamples * BSDF::BSDFSamplerPdf_NoDiffuse(normal, surface, wi) * dwdA;\n        const float m_l = denom > 0 ? 1.0f / denom : 0;\n        const float w_l = m_l * Math::Luminance(target);\n\n        if (r.Update(w_l, le, emissiveIdx, lightSample.bary, rng))\n        {\n            r.target = target;\n            r.lightID = lightID;\n            r.lightNormal = lightSample.normal;\n            r.lightPos = lightSample.pos;\n            r.doubleSided = doubleSided;\n        }\n    }\n\n    float targetLum = Math::Luminance(r.target);\n    r.W = targetLum > 0.0 ? r.w_sum / targetLum : 0.0;\n\n    return r;\n}\n\nReservoir EstimateDirectLighting(uint2 DTid, float3 pos, float3 normal, float z_view, \n    float roughness, uint sampleSetIdx, BSDF::ShadingData surface, RNG rng_group,\n    RNG rng_thread)\n{\n    // Light sampling is less effective for glossy surfaces or when light source is close to surface\n    const int numBsdfSamples = EXTRA_BSDF_SAMPLE_HIGHLY_GLOSSY && !surface.GlossSpecular() && roughness < 0.3 ? \n        2 : \n        1;\n\n    Reservoir r = RIS_InitialCandidates(DTid, pos, normal, roughness, surface, sampleSetIdx,\n        numBsdfSamples, rng_thread);\n\n    if (IS_CB_FLAG_SET(CB_RDI_FLAGS::TEMPORAL_RESAMPLE)) \n    {\n        GBUFFER_MOTION_VECTOR g_motionVector = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::MOTION_VECTOR];\n        float2 motionVec = g_motionVector[DTid];\n        const float2 currUV = (DTid + 0.5f) / float2(g_frame.RenderWidth, g_frame.RenderHeight);\n        float2 prevUV = currUV - motionVec;\n\n        TemporalCandidate temporalCandidate = FindTemporalCandidate(DTid, pos, \n            normal, z_view, roughness, surface, prevUV, g_frame, rng_thread);\n\n        if (temporalCandidate.valid)\n        {\n            TemporalResample1(pos, normal, surface, g_local.Alpha_min, \n                temporalCandidate, g_local.PrevReservoir_A_DescHeapIdx, \n                g_local.PrevReservoir_A_DescHeapIdx + 1, g_frame, \n                g_bvh, g_bvh_prev, g_emissives, g_frameMeshData,\n                r, rng_thread);\n        }\n\n        if(IS_CB_FLAG_SET(CB_RDI_FLAGS::SPATIAL_RESAMPLE))\n        {\n            bool disoccluded = !temporalCandidate.valid && (dot(motionVec, motionVec) > 0);\n            r.target = disoccluded ? -r.target : r.target;\n            r.WriteTarget(DTid, g_local.TargetDescHeapIdx);\n        }\n    }\n\n    if (IS_CB_FLAG_SET(CB_RDI_FLAGS::TEMPORAL_RESAMPLE) ||\n        IS_CB_FLAG_SET(CB_RDI_FLAGS::RESET_TEMPORAL_TEXTURES)) \n    {\n        // Note: Results are improved when spatial doesn't feed into next frame's \n        // temporal reservoirs. May need to revisit in the future.\n        r.Write(DTid, g_local.CurrReservoir_A_DescHeapIdx,\n            g_local.CurrReservoir_A_DescHeapIdx + 1, (uint16)g_local.M_max);\n    }\n\n    return r;\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(RESTIR_DI_TEMPORAL_GROUP_DIM_X, RESTIR_DI_TEMPORAL_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID)\n{\n#if THREAD_GROUP_SWIZZLING\n    uint16_t2 swizzledGid;\n\n    const uint2 swizzledDTid = Common::SwizzleThreadGroup(DTid, Gid, GTid, \n        uint16_t2(RESTIR_DI_TEMPORAL_GROUP_DIM_X, RESTIR_DI_TEMPORAL_GROUP_DIM_Y),\n        g_local.DispatchDimX, \n        RESTIR_DI_TILE_WIDTH, \n        RESTIR_DI_LOG2_TILE_WIDTH, \n        g_local.NumGroupsInTile,\n        swizzledGid);\n#else\n    const uint2 swizzledDTid = DTid.xy;\n    const uint2 swizzledGid = Gid.xy;\n#endif\n\n    if (swizzledDTid.x >= g_frame.RenderWidth || swizzledDTid.y >= g_frame.RenderHeight)\n        return;\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr = g_metallicRoughness[swizzledDTid];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n\n    RWTexture2D<float4> g_final = ResourceDescriptorHeap[g_local.FinalDescHeapIdx];\n\n    if (flags.invalid)\n    {\n        if(g_frame.Accumulate && g_frame.CameraStatic)\n        {\n            float3 prev = g_final[swizzledDTid].rgb;\n            g_final[swizzledDTid].xyz = prev * (g_frame.NumFramesCameraStatic > 1) + \n                Light::Le_SkyWithSunDisk(swizzledDTid, g_frame);\n        }\n        else\n            g_final[swizzledDTid].xyz = 0;\n\n        return;\n    }\n\n    if(flags.emissive && !IS_CB_FLAG_SET(CB_RDI_FLAGS::SPATIAL_RESAMPLE))\n    {\n        GBUFFER_EMISSIVE_COLOR g_emissiveColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::EMISSIVE_COLOR];\n        float3 le = g_emissiveColor[swizzledDTid].rgb;\n\n        if(g_frame.Accumulate && g_frame.CameraStatic)\n        {\n            float3 prev = g_final[swizzledDTid].rgb;\n            g_final[swizzledDTid].rgb = prev + le;\n        }\n        else\n            g_final[swizzledDTid].rgb = le;\n\n        return;\n    }\n\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_normal[swizzledDTid.xy]);\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float z_view = g_depth[swizzledDTid];\n\n    float2 lensSample = 0;\n    float3 origin = g_frame.CameraPos;\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(swizzledDTid.xyx).zy, g_frame.FrameNum);\n        lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample *= g_frame.LensRadius;\n    }\n\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float3 pos = Math::WorldPosFromScreenSpace2(swizzledDTid, renderDim, z_view, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n        g_frame.DoF, lensSample, g_frame.FocusDepth, origin);\n\n    GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n    const float4 baseColor = flags.subsurface ? g_baseColor[swizzledDTid] :\n        float4(g_baseColor[swizzledDTid].rgb, 0);\n\n    float eta_curr = ETA_AIR;\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(flags.transmissive)\n    {\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        float ior = g_ior[swizzledDTid];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    float coat_weight = 0;\n    float3 coat_color = 0.0f;\n    float coat_roughness = 0;\n    float coat_ior = DEFAULT_ETA_COAT;\n\n    if(flags.coated)\n    {\n        GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::COAT];\n        uint3 packed = g_coat[swizzledDTid].xyz;\n\n        GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n        coat_weight = coat.weight;\n        coat_color = coat.color;\n        coat_roughness = coat.roughness;\n        coat_ior = coat.ior;\n    }\n\n    const float3 wo = normalize(origin - pos);\n    BSDF::ShadingData surface = BSDF::ShadingData::Init(normal, wo, flags.metallic, mr.y, \n        baseColor.xyz, eta_curr, eta_next, flags.transmissive, flags.trDepthGt0, (half)baseColor.w,\n        coat_weight, coat_color, coat_roughness, coat_ior);\n\n    // Group-uniform index so that every thread in this group uses the same set\n    RNG rng_group = RNG::Init(Gid.xy, g_frame.FrameNum);\n    const uint sampleSetIdx = rng_group.UniformUintBounded_Faster(g_local.NumSampleSets);\n\n    RNG rng_thread = RNG::Init(swizzledDTid, g_frame.FrameNum);\n\n    Reservoir r = EstimateDirectLighting(swizzledDTid, pos, normal, z_view, mr.y, \n        sampleSetIdx, surface, rng_group, rng_thread);\n\n    if(!IS_CB_FLAG_SET(CB_RDI_FLAGS::SPATIAL_RESAMPLE) || !IS_CB_FLAG_SET(CB_RDI_FLAGS::TEMPORAL_RESAMPLE))\n    {\n        float3 li = r.target * r.W;\n        li = any(isnan(li)) ? 0 : li;\n        RWTexture2D<float4> g_final = ResourceDescriptorHeap[g_local.FinalDescHeapIdx];\n\n        if(g_frame.Accumulate && g_frame.CameraStatic && g_frame.NumFramesCameraStatic > 1)\n        {\n            float3 prev = g_final[swizzledDTid].rgb;\n            g_final[swizzledDTid].rgb = prev + li;\n        }\n        else\n            g_final[swizzledDTid].rgb = li;\n    }\n}"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Emissive/ReSTIR_DI_Temporal_WPS.hlsl",
    "content": "#define USE_PRESAMPLED_SETS\n#include \"ReSTIR_DI_Temporal.hlsl\""
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Emissive/Resampling.hlsli",
    "content": "#ifndef RESTIR_DI_RESAMPLING_H\n#define RESTIR_DI_RESAMPLING_H\n\n#include \"Params.hlsli\"\n#include \"PairwiseMIS.hlsli\"\n#include \"../../Common/GBuffers.hlsli\"\n\nnamespace RDI_Util\n{\n    struct TemporalCandidate\n    {\n        static TemporalCandidate Init()\n        {\n            TemporalCandidate ret;\n            ret.valid = false;\n        \n            return ret;\n        }\n\n        BSDF::ShadingData surface;\n        float3 pos;\n        float3 normal;\n        int16_t2 posSS;\n        bool valid;\n    };\n\n    bool PlaneHeuristic(float3 samplePos, float3 currNormal, float3 currPos, float linearDepth,\n        float tolerance = MAX_PLANE_DIST_REUSE)\n    {\n        float planeDist = dot(currNormal, samplePos - currPos);\n        bool weight = abs(planeDist) <= tolerance * linearDepth;\n\n        return weight;\n    }\n\n    TemporalCandidate FindTemporalCandidate(uint2 DTid, float3 pos, float3 normal, float z_view, \n        float roughness, BSDF::ShadingData surface, float2 prevUV, ConstantBuffer<cbFrameConstants> g_frame, \n        inout RNG rng)\n    {\n        TemporalCandidate candidate = RDI_Util::TemporalCandidate::Init();\n\n        if (any(prevUV < 0.0f.xx) || any(prevUV > 1.0f.xx))\n            return candidate;\n\n        const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n        const int2 prevPixel = prevUV * renderDim;\n\n        GBUFFER_METALLIC_ROUGHNESS g_prevMR = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n            GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n        const float2 prevMR = g_prevMR[prevPixel];\n        GBuffer::Flags prevFlags = GBuffer::DecodeMetallic(prevMR.x);\n\n        if(prevFlags.invalid || \n            prevFlags.emissive || \n            (abs(prevMR.y - roughness) > MAX_ROUGHNESS_DIFF_REUSE) || \n            (prevFlags.metallic != surface.metallic) ||\n            (prevFlags.transmissive != surface.specTr))\n            return candidate;\n\n        float2 prevLensSample = 0;\n        float3 prevOrigin = float3(g_frame.PrevViewInv._m03, g_frame.PrevViewInv._m13, \n            g_frame.PrevViewInv._m23);\n        if(g_frame.DoF)\n        {\n            RNG rngDoF = RNG::Init(RNG::PCG3d(prevPixel.xyx).zy, g_frame.FrameNum - 1);\n            prevLensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n            prevLensSample *= g_frame.LensRadius;\n        }\n\n        GBUFFER_DEPTH g_prevDepth = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n            GBUFFER_OFFSET::DEPTH];\n        const float prevViewDepth = g_prevDepth[prevPixel];\n        const float3 prevPos = Math::WorldPosFromScreenSpace2(prevPixel, renderDim, prevViewDepth, \n            g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.PrevCameraJitter, \n            g_frame.PrevView[0].xyz, g_frame.PrevView[1].xyz, g_frame.PrevView[2].xyz, \n            g_frame.DoF, prevLensSample, g_frame.FocusDepth, prevOrigin);\n\n        if(!RDI_Util::PlaneHeuristic(prevPos, normal, pos, prevViewDepth, MAX_PLANE_DIST_REUSE))\n            return candidate;\n\n        GBUFFER_NORMAL g_prevNormal = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n            GBUFFER_OFFSET::NORMAL];\n        const float3 prevNormal = Math::DecodeUnitVector(g_prevNormal[prevPixel]);\n            \n        float prevEta_next = DEFAULT_ETA_MAT;\n\n        if(prevFlags.transmissive)\n        {\n            GBUFFER_IOR g_prevIOR = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n                GBUFFER_OFFSET::IOR];\n\n            float ior = g_prevIOR[prevPixel];\n            prevEta_next = GBuffer::DecodeIOR(ior);\n        }\n\n        GBUFFER_BASE_COLOR g_prevBaseColor = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n            GBUFFER_OFFSET::BASE_COLOR];\n        const float4 prevBaseColor = prevFlags.subsurface ? g_prevBaseColor[prevPixel] :\n            float4(g_prevBaseColor[prevPixel].rgb, 0);\n\n        float prev_coat_weight = 0;\n        float3 prev_coat_color = 0.0f;\n        float prev_coat_roughness = 0;\n        float prev_coat_ior = DEFAULT_ETA_COAT;\n\n        if(prevFlags.coated)\n        {\n            GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n                GBUFFER_OFFSET::COAT];\n            uint3 packed = g_coat[prevPixel].xyz;\n\n            GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n            prev_coat_weight = coat.weight;\n            prev_coat_color = coat.color;\n            prev_coat_roughness = coat.roughness;\n            prev_coat_ior = coat.ior;\n        }\n\n        const float3 wo = normalize(prevOrigin - prevPos);\n        candidate.surface = BSDF::ShadingData::Init(prevNormal, wo, prevFlags.metallic, \n            prevMR.y, prevBaseColor.rgb, ETA_AIR, prevEta_next, prevFlags.transmissive, \n            prevFlags.trDepthGt0, (half)prevBaseColor.w, prev_coat_weight, prev_coat_color, \n            prev_coat_roughness, prev_coat_ior);\n        candidate.posSS = (int16_t2)prevPixel;\n        candidate.pos = prevPos;\n        candidate.normal = prevNormal;\n        candidate.valid = true;\n\n        return candidate;\n    }\n\n    float OffsetPathTarget_CtT(Reservoir r_curr, float alpha_min, TemporalCandidate candidate, \n        float3 wh, ConstantBuffer<cbFrameConstants> g_frame,\n        RaytracingAccelerationStructure g_bvh_prev,\n        StructuredBuffer<RT::EmissiveTriangle> g_emissives,\n        StructuredBuffer<RT::MeshInstance> g_frameMeshData)\n    {\n        if(!IsShiftInvertible(r_curr, candidate.surface, alpha_min))\n            return 0;\n\n        float3 target_offset = 0;\n        float3 wi_offset;\n        float t_offset = 0;\n        uint lightID = UINT32_MAX;\n\n#if USE_HALF_VECTOR_COPY_SHIFT == 1\n        if(r_curr.halfVectorCopyShift)\n        {\n            wi_offset = reflect(-candidate.surface.wo, wh);\n            BSDFHitInfo hitInfo = FindClosestHit(candidate.pos, candidate.normal, wi_offset, g_bvh_prev, \n                g_frameMeshData, candidate.surface.Transmissive());\n\n            if(!hitInfo.hit)\n                return 0;\n\n            RT::EmissiveTriangle emissive = g_emissives[hitInfo.emissiveTriIdx];\n            float3 le = Light::Le_EmissiveTriangle(emissive, hitInfo.bary, \n                g_frame.EmissiveMapsDescHeapOffset);\n\n            const float3 vtx1 = Light::DecodeEmissiveTriV1(emissive);\n            const float3 vtx2 = Light::DecodeEmissiveTriV2(emissive);\n            float3 lightNormal = cross(vtx1 - emissive.Vtx0, vtx2 - emissive.Vtx0);\n            float twoArea = length(lightNormal);\n            lightNormal = dot(lightNormal, lightNormal) == 0 ? 0 : lightNormal / twoArea;\n            lightNormal = emissive.IsDoubleSided() && dot(-wi_offset, lightNormal) < 0 ? \n                -lightNormal : lightNormal;\n\n            if(dot(-wi_offset, lightNormal) > 0)\n            {\n                float dwdA = saturate(dot(lightNormal, -wi_offset)) / (hitInfo.t * hitInfo.t);\n                target_offset = le * dwdA;\n            }\n\n            candidate.surface.SetWi(wi_offset, candidate.normal);\n        }\n        else\n#endif\n        {\n            wi_offset = r_curr.lightPos - candidate.pos;\n            const bool isZero = dot(wi_offset, wi_offset) == 0;\n            t_offset = isZero ? 0 : length(wi_offset);\n            wi_offset = isZero ? wi_offset : wi_offset / t_offset;\n            candidate.surface.SetWi(wi_offset, candidate.normal);\n\n            float3 lightNormal = r_curr.lightNormal;\n            if(r_curr.doubleSided && dot(-wi_offset, lightNormal) < 0)\n                lightNormal = -lightNormal;\n\n            float cosThetaPrime = saturate(dot(lightNormal, -wi_offset));\n            const float dwdA = isZero ? 0 : cosThetaPrime / (t_offset * t_offset);\n            target_offset = r_curr.le * dwdA;\n        }\n\n        target_offset *= BSDF::Unified(candidate.surface).f;\n        float targetLum_offset = Math::Luminance(target_offset);\n\n        if(!r_curr.halfVectorCopyShift && targetLum_offset > 0)\n        {\n            targetLum_offset *= RtRayQuery::Visibility_Segment(candidate.pos, wi_offset, t_offset, \n                candidate.normal, r_curr.lightID, g_bvh_prev, candidate.surface.Transmissive());\n        }\n\n        return targetLum_offset;\n    }\n\n    float3 OffsetPathTarget_TtC(Reservoir r_prev, float3 pos, float3 normal, float alpha_min,\n        BSDF::ShadingData surface, float3 wh, ConstantBuffer<cbFrameConstants> g_frame,\n        RaytracingAccelerationStructure g_bvh,\n        StructuredBuffer<RT::EmissiveTriangle> g_emissives,\n        StructuredBuffer<RT::MeshInstance> g_frameMeshData)\n    {\n        if(!IsShiftInvertible(r_prev, surface, alpha_min))\n            return 0;\n\n        float3 target_offset = 0;\n        float3 wi_offset;\n        float t_offset = 0;\n        uint lightID = UINT32_MAX;\n\n#if USE_HALF_VECTOR_COPY_SHIFT == 1\n        if(r_prev.halfVectorCopyShift)\n        {\n            wi_offset = reflect(-surface.wo, wh);\n\n            BSDFHitInfo hitInfo = FindClosestHit(pos, normal, wi_offset, g_bvh, \n                g_frameMeshData, surface.Transmissive());\n\n            if(!hitInfo.hit)\n                return 0;\n\n            RT::EmissiveTriangle emissive = g_emissives[hitInfo.emissiveTriIdx];\n            float3 le = Light::Le_EmissiveTriangle(emissive, hitInfo.bary, \n                g_frame.EmissiveMapsDescHeapOffset);\n\n            const float3 vtx1 = Light::DecodeEmissiveTriV1(emissive);\n            const float3 vtx2 = Light::DecodeEmissiveTriV2(emissive);\n            float3 lightNormal = cross(vtx1 - emissive.Vtx0, vtx2 - emissive.Vtx0);\n            float twoArea = length(lightNormal);\n            lightNormal = dot(lightNormal, lightNormal) == 0 ? 0 : lightNormal / twoArea;\n            lightNormal = emissive.IsDoubleSided() && dot(-wi_offset, lightNormal) < 0 ? \n                -lightNormal : lightNormal;\n\n            // Light is backfacing\n            if(dot(-wi_offset, lightNormal) > 0)\n            {\n                float dwdA = saturate(dot(lightNormal, -wi_offset)) / (hitInfo.t * hitInfo.t);\n                target_offset = le * dwdA;\n            }\n\n            surface.SetWi(wi_offset, normal);\n        }\n        else\n#endif\n        {\n            EmissiveData prevEmissive = EmissiveData::Init(r_prev.lightIdx, r_prev.bary, g_emissives);\n            prevEmissive.SetSurfacePos(pos);\n            wi_offset = prevEmissive.wi;\n            t_offset = prevEmissive.t;\n            lightID = prevEmissive.ID;\n            float dwdA = prevEmissive.dWdA();\n\n            surface.SetWi(prevEmissive.wi, normal);\n            target_offset = r_prev.le * dwdA;\n        }\n\n        target_offset *= BSDF::Unified(surface).f;\n        if(!r_prev.halfVectorCopyShift && dot(target_offset, target_offset) > 0)\n        {\n            target_offset *= RtRayQuery::Visibility_Segment(pos, wi_offset, t_offset, normal, \n                lightID, g_bvh, surface.Transmissive());\n        }\n\n        return target_offset;\n    }\n\n    void TemporalResample1(float3 pos, float3 normal, BSDF::ShadingData surface, \n        float alpha_min, TemporalCandidate candidate, uint prevReservoir_A_DescHeapIdx, \n        uint prevReservoir_B_DescHeapIdx, ConstantBuffer<cbFrameConstants> g_frame, \n        RaytracingAccelerationStructure g_bvh, RaytracingAccelerationStructure g_bvh_prev,\n        StructuredBuffer<RT::EmissiveTriangle> g_emissives,\n        StructuredBuffer<RT::MeshInstance> g_frameMeshData,\n        inout Reservoir r_curr, inout RNG rng)\n    {\n        Reservoir r_prev = Reservoir::Load(candidate.posSS,\n            prevReservoir_A_DescHeapIdx, prevReservoir_B_DescHeapIdx);\n        const uint16 newM = r_curr.M + r_prev.M;\n\n        // Shift from current pixel to temporal\n        if(r_curr.w_sum != 0)\n        {\n            float3 wh_prev = Math::FromTangentFrameToWorld(candidate.normal, r_curr.wh_local);\n            float whdotwo = abs(dot(candidate.surface.wo, wh_prev));\n            float jacobian = r_curr.partialJacobian == 0 ? 0 : whdotwo / r_curr.partialJacobian;\n            jacobian = r_curr.halfVectorCopyShift ? jacobian : 1;\n\n            float targetLum_prev = OffsetPathTarget_CtT(r_curr, alpha_min, candidate, wh_prev, \n                g_frame, g_bvh_prev, g_emissives, g_frameMeshData);\n            const float numerator = r_curr.M * Math::Luminance(r_curr.target);\n            const float denom = numerator + r_prev.M * targetLum_prev * jacobian;\n            const float m_curr = denom > 0 ? numerator / denom : 0;\n            r_curr.w_sum *= m_curr;\n        }\n\n        // Shift from temporal to current\n        if(r_prev.lightIdx != UINT32_MAX)\n        {\n            float3 wh_curr = Math::FromTangentFrameToWorld(normal, r_prev.wh_local);\n            float3 wh_prev = Math::FromTangentFrameToWorld(candidate.normal, r_prev.wh_local);\n            float whdotwo_prev = abs(dot(candidate.surface.wo, wh_prev));\n            float whdotwo_curr = abs(dot(surface.wo, wh_curr));\n            float jacobian = whdotwo_prev > 0 ? whdotwo_curr / whdotwo_prev : 0;\n            jacobian = r_prev.halfVectorCopyShift ? jacobian : 1;\n\n            const float3 target_curr = OffsetPathTarget_TtC(r_prev, pos, normal, alpha_min, surface,\n                wh_curr, g_frame, g_bvh, g_emissives, g_frameMeshData);\n            const float targetLum_curr = Math::Luminance(target_curr);\n\n            // w_prev becomes zero and only M needs to be updated, which is done at the end anyway\n            if(targetLum_curr > 0)\n            {\n                const float targetLum_prev = r_prev.W > 0 ? r_prev.w_sum / r_prev.W : 0;\n                // Balance Heuristic\n                const float numerator = r_prev.M * targetLum_prev;\n                const float denom = numerator / jacobian + r_curr.M * targetLum_curr;\n                const float m_prev = denom > 0 ? numerator / denom : 0;\n                const float w_prev = m_prev * targetLum_curr * r_prev.W;\n\n                if (r_curr.Update(w_prev, r_prev.halfVectorCopyShift, r_prev.wh_local, whdotwo_curr, \n                    r_prev.lobe, r_prev.le, r_prev.lightIdx, r_prev.bary, rng))\n                {\n                    r_curr.target = target_curr;\n                }\n            }\n        }\n\n        float targetLum = Math::Luminance(r_curr.target);\n        r_curr.W = targetLum > 0.0 ? r_curr.w_sum / targetLum : 0.0;\n        r_curr.M = newM;\n    }\n\n    void SpatialResample(uint2 DTid, int numSamples, float radius, float3 pos, float3 normal, \n        float z_view, float roughness, BSDF::ShadingData surface, float alpha_min, \n        uint reservoir_A_DescHeapIdx, uint reservoir_B_DescHeapIdx, \n        ConstantBuffer<cbFrameConstants> g_frame, \n        RaytracingAccelerationStructure g_bvh, \n        StructuredBuffer<RT::EmissiveTriangle> g_emissives, \n        StructuredBuffer<RT::MeshInstance> g_frameMeshData,\n        inout Reservoir r, inout RNG rng)\n    {\n        static const half2 k_samples[32] =\n        {\n            half2(0.620442, 0.900394),\n            half2(0.444621, 0.939978),\n            half2(0.455839, 0.748007),\n            half2(0.764451, 0.802669),\n            half2(0.670828, 0.696273),\n            half2(0.222218, 0.77409),\n            half2(0.50221, 0.525416),\n            half2(0.362746, 0.651879),\n            half2(0.629943, 0.519856),\n            half2(0.572175, 0.370443),\n            half2(0.347296, 0.420629),\n            half2(0.284706, 0.54219),\n            half2(0.127776, 0.611066),\n            half2(0.882008, 0.65589),\n            half2(0.778418, 0.515129),\n            half2(0.210426, 0.218347),\n            half2(0.0992503, 0.412867),\n            half2(0.334951, 0.269779),\n            half2(0.490129, 0.225641),\n            half2(0.675389, 0.149382),\n            half2(0.803938, 0.345802),\n            half2(0.979837, 0.401849),\n            half2(0.984763, 0.574738),\n            half2(0.218297, 0.355557),\n            half2(0.367467, 0.0574971),\n            half2(0.567781, 0.0132011),\n            half2(0.814379, 0.183564),\n            half2(0.00541991, 0.531187),\n            half2(0.924393, 0.261443),\n            half2(0.287806, 0.952222),\n            half2(0.679866, 0.288912),\n            half2(0.341006, 0.827133)\n        };\n\n        GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::NORMAL];\n        GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::DEPTH];\n        GBUFFER_METALLIC_ROUGHNESS g_mr = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n        GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::BASE_COLOR];\n\n        // rotate sample sequence per pixel\n        const float u0 = rng.Uniform();\n        const int offset = (int)(rng.UniformUintBounded_Faster(8));\n        const float theta = u0 * TWO_PI;\n        const float sinTheta = sin(theta);\n        const float cosTheta = cos(theta);\n\n        const uint2 renderDim = uint2(g_frame.RenderWidth, g_frame.RenderHeight);\n        PairwiseMIS pairwiseMIS = PairwiseMIS::Init((uint16_t)numSamples, r);\n\n        float3 samplePos[MAX_NUM_SPATIAL_SAMPLES];\n        float3 sampleOrigin[MAX_NUM_SPATIAL_SAMPLES];\n        int16_t2 samplePosSS[MAX_NUM_SPATIAL_SAMPLES];\n        bool sampleMetallic[MAX_NUM_SPATIAL_SAMPLES];\n        float sampleRoughness[MAX_NUM_SPATIAL_SAMPLES];\n        bool sampleTr[MAX_NUM_SPATIAL_SAMPLES];\n        bool sampleSubsurf[MAX_NUM_SPATIAL_SAMPLES];\n        bool sampleCoated[MAX_NUM_SPATIAL_SAMPLES];\n        uint16_t k = 0;\n\n        [loop]\n        for (int i = 0; i < numSamples; i++)\n        {\n            float2 sampleUV = k_samples[(offset + i) & 31];\n            float2 rotated;\n            rotated.x = dot(sampleUV, float2(cosTheta, -sinTheta));\n            rotated.y = dot(sampleUV, float2(sinTheta, cosTheta));\n            rotated *= radius;\n            const uint2 posSS_i = (uint2)round(float2(DTid) + rotated);\n\n            if (Math::IsWithinBounds(posSS_i, renderDim))\n            {\n                const float2 mr_i = g_mr[posSS_i];\n                GBuffer::Flags flags_i = GBuffer::DecodeMetallic(mr_i.x);\n\n                if(flags_i.invalid || flags_i.emissive)\n                    continue;\n\n                const float depth_i = g_depth[posSS_i];\n                float2 lensSample = 0;\n                float3 origin_i = g_frame.CameraPos;\n                if(g_frame.DoF)\n                {\n                    RNG rngDoF = RNG::Init(RNG::PCG3d(posSS_i.xyx).zy, g_frame.FrameNum);\n                    lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n                    lensSample *= g_frame.LensRadius;\n                }\n\n                float3 pos_i = Math::WorldPosFromScreenSpace2(posSS_i, renderDim, depth_i, \n                    g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n                    g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n                    g_frame.DoF, lensSample, g_frame.FocusDepth, origin_i);\n\n                bool valid = PlaneHeuristic(pos_i, normal, pos, z_view);\n                valid = valid && (abs(mr_i.y - roughness) < MAX_ROUGHNESS_DIFF_REUSE);\n\n                if (!valid)\n                    continue;\n\n                samplePos[k] = pos_i;\n                sampleOrigin[k] = origin_i;\n                samplePosSS[k] = (int16_t2)posSS_i;\n                sampleMetallic[k] = flags_i.metallic;\n                sampleRoughness[k] = mr_i.y;\n                sampleTr[k] = flags_i.transmissive;\n                sampleSubsurf[k] = flags_i.subsurface;\n                sampleCoated[k] = flags_i.coated;\n\n                k++;\n            }\n        }\n\n        pairwiseMIS.k = k;\n\n        for (int i = 0; i < k; i++)\n        {\n            const float3 sampleNormal = Math::DecodeUnitVector(g_normal[samplePosSS[i]]);\n            const float4 sampleBaseColor = sampleSubsurf[i] ? g_baseColor[samplePosSS[i]] :\n                float4(g_baseColor[samplePosSS[i]].rgb, 0);\n\n            float sampleEta_next = DEFAULT_ETA_MAT;\n\n            if(sampleTr[i])\n            {\n                GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n                    GBUFFER_OFFSET::IOR];\n\n                float ior = g_ior[samplePosSS[i]];\n                sampleEta_next = GBuffer::DecodeIOR(ior);\n            }\n\n            float sample_coat_weight = 0;\n            float3 sample_coat_color = 0.0f;\n            float sample_coat_roughness = 0;\n            float sample_coat_ior = DEFAULT_ETA_COAT;\n\n            if(sampleCoated[i])\n            {\n                GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n                    GBUFFER_OFFSET::COAT];\n                uint3 packed = g_coat[samplePosSS[i]].xyz;\n\n                GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n                sample_coat_weight = coat.weight;\n                sample_coat_color = coat.color;\n                sample_coat_roughness = coat.roughness;\n                sample_coat_ior = coat.ior;\n            }\n\n            const float3 wo_i = normalize(sampleOrigin[i] - samplePos[i]);\n            BSDF::ShadingData surface_i = BSDF::ShadingData::Init(sampleNormal, wo_i,\n                sampleMetallic[i], sampleRoughness[i], sampleBaseColor.xyz, ETA_AIR,\n                sampleEta_next, sampleTr[i], false, (half)sampleBaseColor.w, sample_coat_weight, \n                sample_coat_color, sample_coat_roughness, sample_coat_ior);\n\n            Reservoir r_spatial = Reservoir::Load(samplePosSS[i], reservoir_A_DescHeapIdx, \n                reservoir_B_DescHeapIdx);\n\n            pairwiseMIS.Stream(r, pos, normal, surface, r_spatial, samplePos[i], sampleNormal, \n                surface_i, alpha_min, g_frame, g_bvh, g_emissives, g_frameMeshData, rng);\n        }\n\n        pairwiseMIS.End(r, rng);\n        r = pairwiseMIS.r_s;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Emissive/Reservoir.hlsli",
    "content": "#ifndef RESTIR_DI_RESERVOIR_H\n#define RESTIR_DI_RESERVOIR_H\n\n#include \"DirectLighting_Common.h\"\n#include \"../../Common/Sampling.hlsli\"\n#include \"../../Common/BSDF.hlsli\"\n\nnamespace RDI_Util\n{\n    struct Reservoir\n    {\n        static Reservoir Init()\n        {\n            Reservoir ret;\n\n            ret.le = 0;\n            ret.M = 0;\n            ret.w_sum = 0;\n            ret.W = 0;\n            ret.lightIdx = UINT32_MAX;\n            ret.bary = 0;\n            ret.halfVectorCopyShift = false;\n            ret.lobe = BSDF::LOBE::ALL;\n\n            ret.partialJacobian = 1;\n            ret.target = 0;\n            ret.lightID = UINT32_MAX;\n\n            return ret;\n        }\n\n        bool Update(float weight, float3 le, uint lightIdx, float2 bary, inout RNG rng)\n        {\n            if(isnan(weight))\n                return false;\n\n            this.M += 1;\n\n            if(weight == 0)\n                return false;\n\n            this.w_sum += weight;\n\n            if (rng.Uniform() < (weight / this.w_sum))\n            {\n                this.le = le;\n                this.lightIdx = lightIdx;\n                this.bary = bary;\n                this.halfVectorCopyShift = false;\n                this.lobe = BSDF::LOBE::ALL;\n\n                return true;\n            }\n\n            return false;\n        }\n\n        bool Update(float weight, bool halfVecShift, float3 wi, float3 wo, float3 normal, \n            BSDF::LOBE lb, float3 le, uint lightIdx, float2 bary, inout RNG rng)\n        {\n            if(isnan(weight))\n                return false;\n\n            this.M += 1;\n\n            if(weight == 0)\n                return false;\n\n            this.w_sum += weight;\n\n            if (rng.Uniform() < (weight / this.w_sum))\n            {\n                this.le = le;\n                this.lightIdx = lightIdx;\n                this.bary = bary;\n                this.halfVectorCopyShift = halfVecShift;\n                this.lobe = lb;\n\n                // Sample uses half-vector copy shift\n                if(halfVecShift)\n                {\n                    float3 wh = normalize(wo + wi);\n                    this.wh_local = Math::WorldToTangentFrame(normal, wh);\n                    this.partialJacobian = abs(dot(wh, wo));\n                }\n\n                return true;\n            }\n\n            return false;\n        }\n\n        bool Update(float weight, bool halfVecShift, float3 wh, float whdotwo, BSDF::LOBE lb, \n            float3 le, uint lightIdx, float2 bary, inout RNG rng)\n        {\n            if(isnan(weight))\n                return false;\n\n            this.M += 1;\n\n            if(weight == 0)\n                return false;\n\n            this.w_sum += weight;\n\n            if (rng.Uniform() < (weight / this.w_sum))\n            {\n                this.le = le;\n                this.lightIdx = lightIdx;\n                this.bary = bary;\n                this.halfVectorCopyShift = halfVecShift;\n                this.lobe = lb;\n                this.wh_local = wh;\n                this.partialJacobian = whdotwo;\n\n                return true;\n            }\n\n            return false;\n        }\n\n        void LoadTarget(uint2 DTid, uint uavIdx)\n        {\n            RWTexture2D<float4> g_target = ResourceDescriptorHeap[uavIdx];\n            this.target = g_target[DTid].xyz;\n        }\n\n        void WriteTarget(uint2 DTid, uint uavIdx)\n        {\n            RWTexture2D<float4> g_target = ResourceDescriptorHeap[uavIdx];\n            this.target = Math::Sanitize(this.target);\n            g_target[DTid].xyz = this.target;\n        }\n\n        static Reservoir Load(uint2 DTid, uint inputAIdx, uint inputBIdx)\n        {\n            Texture2D<uint4> g_reservoir_A = ResourceDescriptorHeap[inputAIdx];\n            Texture2D<float2> g_reservoir_B = ResourceDescriptorHeap[inputBIdx];\n\n            const uint4 resA = g_reservoir_A[DTid];\n            const float2 resB = g_reservoir_B[DTid];\n            const float3 le = asfloat16(uint16_t3(resA.y & 0xffff, resA.y >> 16, resA.z & 0xffff));\n            const uint16_t2 bary_or_wh = uint16_t2(resA.x & 0xffff, resA.x >> 16);\n            const uint metadata = resA.z >> 16;\n\n            Reservoir ret = Reservoir::Init();\n            ret.M = (uint16)(metadata & 0x1f);\n            ret.w_sum = resB.x;\n            ret.W = resB.y;\n            ret.le = le;\n            ret.lightIdx = resA.w;\n            ret.bary = Math::DecodeUNorm2(bary_or_wh);\n            ret.partialJacobian = 1;\n            ret.lightPos = 0;\n\n#if USE_HALF_VECTOR_COPY_SHIFT == 1\n            ret.halfVectorCopyShift = (metadata >> 5) & 0x1;\n            ret.lobe = BSDF::LobeFromValue((metadata >> 6) & 0x7);\n            ret.wh_local = Math::DecodeOct32(bary_or_wh);\n#else\n            ret.halfVectorCopyShift = false;\n            ret.lobe = BSDF::LOBE::ALL;\n            ret.wh_local = 0;\n#endif\n\n            return ret;\n        }\n\n        void Write(uint2 DTid, uint outputAIdx, uint outputBIdx, uint16 M_max)\n        {\n            RWTexture2D<uint4> g_outReservoir_A = ResourceDescriptorHeap[outputAIdx];\n            RWTexture2D<float2> g_outReservoir_B = ResourceDescriptorHeap[outputBIdx];\n\n            uint16_t3 le = asuint16(half3(this.le));\n            uint16 M_capped = min(this.M, M_max);\n\n#if USE_HALF_VECTOR_COPY_SHIFT == 1\n            uint metadata = M_capped |\n                (uint(this.halfVectorCopyShift) << 5) |\n                (uint(BSDF::LobeToValue(this.lobe)) << 6);\n            uint16_t2 bary_or_wh = this.halfVectorCopyShift ? \n                Math::EncodeOct32(this.wh_local) : \n                Math::EncodeAsUNorm2(this.bary);\n#else\n            uint metadata = M_capped;\n            uint16_t2 bary_or_wh = Math::EncodeAsUNorm2(this.bary);\n#endif\n            uint a_x = (uint(bary_or_wh.y) << 16) | bary_or_wh.x;\n            uint a_y = (uint(le.y) << 16) | le.x;\n            uint a_z = (metadata << 16) | le.z;\n            uint a_w = this.lightIdx;\n\n            g_outReservoir_A[DTid] = uint4(a_x, a_y, a_z, a_w);\n            g_outReservoir_B[DTid] = float2(this.w_sum, this.W);\n        }\n\n        float w_sum;\n        float W;\n        float3 le;\n        uint lightIdx;\n        float2 bary;\n        uint16_t M;\n        bool halfVectorCopyShift;\n        BSDF::LOBE lobe;\n\n        float3 target;\n        uint lightID;\n        float3 lightPos;\n        float3 lightNormal;\n        bool doubleSided;\n        float3 wh_local;\n        float partialJacobian;\n    };\n\n    bool IsShiftInvertible(Reservoir r_base, BSDF::ShadingData surface_offset, float alpha_min)\n    {\n#if USE_HALF_VECTOR_COPY_SHIFT == 1\n        return !r_base.halfVectorCopyShift ||\n            (BSDF::IsLobeValid(surface_offset, r_base.lobe) &&\n            (BSDF::LobeAlpha(surface_offset, r_base.lobe) <= alpha_min));\n#else\n        return true;\n#endif\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Emissive/Util.hlsli",
    "content": "#ifndef RESTIR_DI_UTIL_H\n#define RESTIR_DI_UTIL_H\n\n#include \"DirectLighting_Common.h\"\n#include \"Reservoir.hlsli\"\n#include \"../../Common/LightSource.hlsli\"\n#include \"../../Common/RayQuery.hlsli\"\n\nnamespace RDI_Util\n{\n    struct EmissiveData\n    {\n        static EmissiveData Init(uint lightIdx, float2 bary, StructuredBuffer<RT::EmissiveTriangle> g_emissives)\n        {\n            EmissiveData ret;\n\n            RT::EmissiveTriangle tri = g_emissives[lightIdx];\n            ret.ID = tri.ID;\n\n            const float3 vtx1 = Light::DecodeEmissiveTriV1(tri);\n            const float3 vtx2 = Light::DecodeEmissiveTriV2(tri);\n            ret.lightPos = (1.0f - bary.x - bary.y) * tri.Vtx0 + bary.x * vtx1 + bary.y * vtx2;\n\n            ret.lightNormal = cross(vtx1 - tri.Vtx0, vtx2 - tri.Vtx0);\n            ret.lightNormal = dot(ret.lightNormal, ret.lightNormal) == 0 ? ret.lightNormal : \n                normalize(ret.lightNormal);\n            // ret.lightNormal = tri.IsDoubleSided() && dot(-ret.wi, ret.lightNormal) < 0 ? \n            //     ret.lightNormal * -1.0f : ret.lightNormal;\n            ret.doubleSided = tri.IsDoubleSided();\n\n            return ret;\n        }\n\n        void SetSurfacePos(float3 pos)\n        {\n            this.wi = this.lightPos - pos;\n            this.t = dot(this.wi, this.wi) == 0 ? 0 : length(wi);\n            this.wi = this.t == 0 ? 0 : this.wi / this.t;\n            this.lightNormal = this.doubleSided && dot(-this.wi, this.lightNormal) < 0 ? \n                -this.lightNormal : this.lightNormal;\n        }\n\n        float dWdA()\n        {\n            float cosThetaPrime = saturate(dot(this.lightNormal, -this.wi));\n            float dWdA = this.t == 0 ? 0 : cosThetaPrime / (this.t * this.t);\n\n            return dWdA;\n        }\n\n        float3 wi;\n        float t;\n        uint ID;\n        float3 lightPos;\n        float3 lightNormal;\n        bool doubleSided;\n    };\n\n    struct BSDFHitInfo\n    {\n        uint emissiveTriIdx;\n        float2 bary;\n        float3 lightPos;\n        float t;\n        bool hit;\n    };\n\n    BSDFHitInfo FindClosestHit(float3 pos, float3 normal, float3 wi, RaytracingAccelerationStructure g_bvh, \n        StructuredBuffer<RT::MeshInstance> g_frameMeshData, bool transmissive)\n    {\n        BSDFHitInfo ret;\n        ret.hit = false;\n\n        float ndotwi = dot(normal, wi);\n        if(ndotwi == 0)\n            return ret;\n\n        bool wiBackface = ndotwi < 0;\n\n        if(wiBackface)\n        {\n            if(transmissive)\n                normal *= -1;\n            else\n                return ret;\n        }\n\n        const float3 adjustedOrigin = RT::OffsetRayRTG(pos, normal);\n\n        RayQuery<RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES | RAY_FLAG_FORCE_OPAQUE> rayQuery;\n\n        RayDesc ray;\n        ray.Origin = adjustedOrigin;\n        ray.TMin = wiBackface ? 3e-4 : 0;\n        ray.TMax = FLT_MAX;\n        ray.Direction = wi;\n\n        rayQuery.TraceRayInline(g_bvh, RAY_FLAG_NONE, RT_AS_SUBGROUP::ALL, ray);\n        rayQuery.Proceed();\n\n        if (rayQuery.CommittedStatus() == COMMITTED_TRIANGLE_HIT)\n        {\n            const uint meshIdx = rayQuery.CommittedGeometryIndex() + rayQuery.CommittedInstanceID();\n            const RT::MeshInstance meshData = g_frameMeshData[NonUniformResourceIndex(meshIdx)];\n\n            if (meshData.BaseEmissiveTriOffset == UINT32_MAX)\n                return ret;\n\n            ret.emissiveTriIdx = meshData.BaseEmissiveTriOffset + rayQuery.CommittedPrimitiveIndex();\n            ret.bary = rayQuery.CommittedTriangleBarycentrics();\n            ret.lightPos = mad(rayQuery.CommittedRayT(), rayQuery.WorldRayDirection(), \n                rayQuery.WorldRayOrigin());\n            ret.t = rayQuery.CommittedRayT();\n            ret.hit = true;\n\n            return ret;\n        }\n\n        return ret;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Sky/PairwiseMIS.hlsli",
    "content": "#ifndef SKY_DI_PAIRWISE_MIS_H\n#define SKY_DI_PAIRWISE_MIS_H\n\n#include \"Reservoir.hlsli\"\n#include \"../../Common/RayQuery.hlsli\"\n\nnamespace SkyDI_Util\n{\n    // Ref: Bitterli, Benedikt, \"Correlations and Reuse for Fast and Accurate Physically Based Light Transport\" (2022). Ph.D Dissertation.\n    // https://digitalcommons.dartmouth.edu/dissertations/77\n    struct PairwiseMIS\n    {    \n        static PairwiseMIS Init(uint16_t numStrategies, Reservoir r_c)\n        {\n            PairwiseMIS ret;\n            ret.r_s = Reservoir::Init();\n            ret.m_c = 1.0f;\n            ret.M_s = r_c.M;\n            ret.k = numStrategies;\n\n            return ret;\n        }\n\n        float Compute_m_i(Reservoir r_c, float targetLum, Reservoir r_i, \n            float jacobian)\n        {\n            const float p_i_y_i = r_i.W > 0 ? r_i.w_sum / r_i.W : 0;\n            const float p_c_y_i = targetLum;\n            float numerator = r_i.M * p_i_y_i;\n            float denom = (numerator / jacobian) + ((float)r_c.M / this.k) * p_c_y_i;\n            float m_i = denom > 0 ? numerator / denom : 0;\n\n            return m_i;\n        }\n\n        void Update_m_c(Reservoir r_c, Reservoir r_i, float targetLum, float jacobian)\n        {\n            const float p_i_y_c = targetLum;\n            const float p_c_y_c = Math::Luminance(r_c.target);\n\n            const float numerator = r_i.M * p_i_y_c * jacobian;\n            const float denom = numerator + ((float)r_c.M / this.k) * p_c_y_c;\n            // Note: denom can never be zero, otherwise r_c didn't have a valid sample\n            // and this function shouldn't have been called\n            this.m_c += 1 - (numerator / denom);\n        }\n\n        void Stream(Reservoir r_c, float3 pos_c, float3 normal_c, BSDF::ShadingData surface_c, \n            Reservoir r_i, float3 pos_i, float3 normal_i, BSDF::ShadingData surface_i, \n            float alpha_min, RaytracingAccelerationStructure g_bvh, \n            ConstantBuffer<cbFrameConstants> g_frame, inout RNG rng)\n        {\n            // Shift from pixel i to center\n            float m_i = 0;\n            float3 target_c_y_i = 0;\n\n            if(r_i.IsValid())\n            {\n                float3 wi_offset = r_i.wx;\n                float jacobian = 1;\n\n                if(IsShiftInvertible(r_i, surface_c, alpha_min))\n                {\n                    if(r_i.halfVectorCopyShift)\n                    {\n                        float3 wh_local = r_i.wx;\n                        float3 wh_c = Math::FromTangentFrameToWorld(normal_c, wh_local);\n                        float3 wh_i = Math::FromTangentFrameToWorld(normal_i, wh_local);\n\n                        wi_offset = reflect(-surface_c.wo, wh_c);\n                        float whdotwo_i = abs(dot(surface_i.wo, wh_i));\n                        jacobian = whdotwo_i > 0 ? abs(dot(surface_c.wo, wh_c)) / whdotwo_i : 1;\n                    }\n\n                    surface_c.SetWi(wi_offset, normal_c);\n\n                    const float3 le = r_i.lightType == Light::TYPE::SKY ? \n                        Light::Le_Sky(wi_offset, g_frame.EnvMapDescHeapOffset) :\n                        Light::Le_Sun(pos_c, g_frame);\n                    target_c_y_i = le * BSDF::Unified(surface_c).f;\n\n                    if(dot(target_c_y_i, target_c_y_i) > 0)\n                    {\n                        target_c_y_i *= RtRayQuery::Visibility_Ray(pos_c, wi_offset, normal_c, \n                            g_bvh, surface_c.Transmissive());\n                    }\n                }\n\n                const float targetLum = Math::Luminance(target_c_y_i);\n                m_i = Compute_m_i(r_c, targetLum, r_i, jacobian);\n            }\n\n            // Shift center to pixel i\n            float3 target_i_y_c = 0;\n            float jacobian = 1;\n            \n            if(r_c.IsValid())\n            {\n                float3 wi_offset = r_c.wx;\n\n                if(IsShiftInvertible(r_c, surface_i, alpha_min))\n                {\n                    if(r_c.halfVectorCopyShift)\n                    {\n                        float3 wh_local = r_c.wx;\n                        float3 wh_i = Math::FromTangentFrameToWorld(normal_i, wh_local);\n\n                        wi_offset = reflect(-surface_i.wo, wh_i);\n                        float whdotwo_i = abs(dot(surface_i.wo, wh_i));\n                        jacobian = whdotwo_i > 0 ? abs(dot(surface_i.wo, wh_i)) / r_c.partialJacobian : 1;\n                    }\n\n                    surface_i.SetWi(wi_offset, normal_i);\n\n                    const float3 le = r_c.lightType == Light::TYPE::SKY ? \n                        Light::Le_Sky(wi_offset, g_frame.EnvMapDescHeapOffset) :\n                        Light::Le_Sun(pos_i, g_frame);\n                    target_i_y_c = le * BSDF::Unified(surface_i).f;\n\n                    if(dot(target_i_y_c, target_i_y_c) > 0)\n                    {\n                        target_i_y_c *= RtRayQuery::Visibility_Ray(pos_i, wi_offset, normal_i, \n                            g_bvh, surface_i.Transmissive());\n                    }\n                }\n            }\n\n            const float targetLum = Math::Luminance(target_i_y_c);\n            Update_m_c(r_c, r_i, targetLum, jacobian);\n\n            if(r_i.IsValid())\n            {\n                const float w_i = m_i * Math::Luminance(target_c_y_i) * r_i.W;\n\n                this.r_s.Update(w_i, r_i.wx, r_i.lightType, r_i.lobe, r_i.halfVectorCopyShift, \n                    surface_c.whdotwo, target_c_y_i, rng);\n            }\n\n            this.M_s += r_i.M;\n        }\n\n        void End(Reservoir r_c, inout RNG rng)\n        {\n            // w_sum = Luminance(target) * W\n            const float w_c = this.m_c * r_c.w_sum;\n            this.r_s.Update(w_c, r_c.wx, r_c.lightType, r_c.lobe, r_c.halfVectorCopyShift, \n                r_c.partialJacobian, r_c.target, rng);\n            this.r_s.M = this.M_s;\n\n            const float targetLum = Math::Luminance(r_s.target);\n            this.r_s.W = targetLum > 0 ? this.r_s.w_sum / (targetLum * (1 + this.k)) : 0;\n        }\n\n        Reservoir r_s;\n        float m_c;\n        uint16 M_s;\n        uint16 k;\n    };\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Sky/Params.hlsli",
    "content": "#ifndef SKY_DI_PARAMS_H\n#define SKY_DI_PARAMS_H\n\n#define MAX_PLANE_DIST_REUSE 5e-1\n#define MIN_NORMAL_SIMILARITY_REUSE 0.906307787    // within 25 degrees\n#define MAX_ROUGHNESS_DIFF_REUSE 0.1f\n#define NUM_SPATIAL_SAMPLES 2\n#define SPATIAL_SEARCH_RADIUS 16\n#define APPROXIMATE_EMISSIVE_SHADOW_RAY 1\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Sky/Resampling.hlsli",
    "content": "#ifndef SKY_DI_RESAMPLING_H\n#define SKY_DI_RESAMPLING_H\n\n#include \"Params.hlsli\"\n#include \"PairwiseMIS.hlsli\"\n#include \"../../Common/GBuffers.hlsli\"\n#include \"../../Common/BSDFSampling.hlsli\"\n\nnamespace SkyDI_Util\n{\n    struct TemporalCandidate\n    {\n        static TemporalCandidate Init()\n        {\n            TemporalCandidate ret;\n            ret.valid = false;\n\n            return ret;\n        }\n\n        BSDF::ShadingData surface;\n        float3 pos;\n        float3 normal;\n        int16_t2 posSS;\n        bool valid;\n    };\n\n    bool PlaneHeuristic(float3 samplePos, float3 currNormal, float3 currPos, float z_view,\n        float tolerance = MAX_PLANE_DIST_REUSE)\n    {\n        float planeDist = dot(currNormal, samplePos - currPos);\n        bool weight = abs(planeDist) <= tolerance * z_view;\n\n        return weight;\n    }\n\n    TemporalCandidate FindTemporalCandidate(uint2 DTid, float3 pos, float3 normal, float z_view, \n        float roughness, BSDF::ShadingData surface, ConstantBuffer<cbFrameConstants> g_frame)\n    {\n        TemporalCandidate candidate = TemporalCandidate::Init();\n\n        GBUFFER_MOTION_VECTOR g_motionVector = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::MOTION_VECTOR];\n        const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n        const float2 motionVec = g_motionVector[DTid];\n        const float2 currUV = (DTid + 0.5f) / renderDim;\n        const float2 prevUV = currUV - motionVec;\n        const int2 prevPixel = prevUV * renderDim;\n\n        if (any(prevUV < 0.0f.xx) || any(prevUV > 1.0f.xx))\n            return candidate;\n\n        GBUFFER_METALLIC_ROUGHNESS g_prevMR = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n            GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n        const float2 prevMR = g_prevMR[prevPixel];\n        GBuffer::Flags prevFlags = GBuffer::DecodeMetallic(prevMR.x);\n\n        // Skip if not on the same surface\n        if(prevFlags.invalid || \n            prevFlags.emissive || \n            (abs(prevMR.y - roughness) > 0.3) || \n            (prevFlags.metallic != surface.metallic) ||\n            (prevFlags.transmissive != surface.specTr))\n            return candidate;\n\n        float2 prevLensSample = 0;\n        float3 prevOrigin = float3(g_frame.PrevViewInv._m03, g_frame.PrevViewInv._m13, \n            g_frame.PrevViewInv._m23);\n        if(g_frame.DoF)\n        {\n            RNG rngDoF = RNG::Init(RNG::PCG3d(prevPixel.xyx).zy, g_frame.FrameNum - 1);\n            prevLensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n            prevLensSample *= g_frame.LensRadius;\n        }\n\n        // plane-based heuristic\n        GBUFFER_DEPTH g_prevDepth = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n            GBUFFER_OFFSET::DEPTH];\n        const float prevViewDepth = g_prevDepth[prevPixel];\n        const float3 prevPos = Math::WorldPosFromScreenSpace2(prevPixel, renderDim, prevViewDepth, \n            g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.PrevCameraJitter, \n            g_frame.PrevView[0].xyz, g_frame.PrevView[1].xyz, g_frame.PrevView[2].xyz, \n            g_frame.DoF, prevLensSample, g_frame.FocusDepth, prevOrigin);\n\n        if(!PlaneHeuristic(prevPos, normal, pos, z_view, MAX_PLANE_DIST_REUSE))\n            return candidate;\n\n        GBUFFER_NORMAL g_prevNormal = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n            GBUFFER_OFFSET::NORMAL];\n        const float3 prevNormal = Math::DecodeUnitVector(g_prevNormal[prevPixel]);\n\n        float prevEta_next = DEFAULT_ETA_MAT;\n\n        if(prevFlags.transmissive)\n        {\n            GBUFFER_IOR g_prevIOR = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n                GBUFFER_OFFSET::IOR];\n\n            float ior = g_prevIOR[prevPixel];\n            prevEta_next = GBuffer::DecodeIOR(ior);\n        }\n\n        GBUFFER_BASE_COLOR g_prevBaseColor = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n            GBUFFER_OFFSET::BASE_COLOR];\n        const float4 prevBaseColor = prevFlags.subsurface ? g_prevBaseColor[prevPixel] :\n            float4(g_prevBaseColor[prevPixel].rgb, 0);\n\n        float prev_coat_weight = 0;\n        float3 prev_coat_color = 0.0f;\n        float prev_coat_roughness = 0;\n        float prev_coat_ior = DEFAULT_ETA_COAT;\n\n        if(prevFlags.coated)\n        {\n            GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n                GBUFFER_OFFSET::COAT];\n            uint3 packed = g_coat[prevPixel].xyz;\n\n            GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n            prev_coat_weight = coat.weight;\n            prev_coat_color = coat.color;\n            prev_coat_roughness = coat.roughness;\n            prev_coat_ior = coat.ior;\n        }\n\n        const float3 wo = normalize(prevOrigin - prevPos);\n        candidate.surface = BSDF::ShadingData::Init(prevNormal, wo, prevFlags.metallic, \n            prevMR.y, prevBaseColor.rgb, ETA_AIR, prevEta_next, prevFlags.transmissive, \n            prevFlags.trDepthGt0, (half)prevBaseColor.w, prev_coat_weight, prev_coat_color, \n            prev_coat_roughness, prev_coat_ior);\n        candidate.posSS = (int16_t2)prevPixel;\n        candidate.pos = prevPos;\n        candidate.normal = prevNormal;\n        candidate.valid = true;\n\n        return candidate;\n    }\n\n    void TemporalResample(TemporalCandidate candidate, float3 pos, float3 normal,\n        BSDF::ShadingData surface, uint prevReservoir_A_DescHeapIdx, uint prevReservoir_B_DescHeapIdx, \n        uint prevReservoir_C_DescHeapIdx, float alpha_min, RaytracingAccelerationStructure g_bvh,\n        RaytracingAccelerationStructure g_bvh_prev, ConstantBuffer<cbFrameConstants> g_frame, \n        inout Reservoir r, inout RNG rng)\n    {\n        Reservoir r_prev = Reservoir::Load(candidate.posSS, \n            prevReservoir_A_DescHeapIdx, prevReservoir_B_DescHeapIdx,\n            prevReservoir_C_DescHeapIdx);\n\n        // Lower confidence due to visibility change\n        r_prev.M = (r.lightType == Light::TYPE::SUN) && g_frame.SunMoved ? (uint16)0 : r_prev.M;\n        const uint16 newM = r.M + r_prev.M;\n\n        // Shift from current pixel to temporal\n        if(r.w_sum != 0)\n        {\n            float targetLum_prev = 0;\n            float3 wi_offset = r.wx; \n            float jacobian = 1;\n\n            if(IsShiftInvertible(r, candidate.surface, alpha_min))\n            {\n                if(r.halfVectorCopyShift)\n                {\n                    float3 wh_local = r.wx;\n                    float3 wh_t = Math::FromTangentFrameToWorld(candidate.normal, wh_local);\n\n                    wi_offset = reflect(-candidate.surface.wo, wh_t);\n                    jacobian = r.partialJacobian == 0 ? 0 : \n                        abs(dot(candidate.surface.wo, wh_t)) / r.partialJacobian;\n                }\n\n                candidate.surface.SetWi(wi_offset, candidate.normal);\n\n                const float3 le = r.lightType == Light::TYPE::SKY ? \n                    Light::Le_Sky(wi_offset, g_frame.EnvMapDescHeapOffset) :\n                    Light::Le_Sun(candidate.pos, g_frame);\n                const float3 target_prev = le * BSDF::Unified(candidate.surface).f;\n                targetLum_prev = Math::Luminance(target_prev);\n\n                if(targetLum_prev > 0)\n                {\n                    targetLum_prev *= RtRayQuery::Visibility_Ray(candidate.pos, wi_offset, candidate.normal, \n                        g_bvh_prev, candidate.surface.Transmissive());\n                }\n            }\n\n            const float numerator = r.M * Math::Luminance(r.target);\n            const float denom = numerator + r_prev.M * targetLum_prev * jacobian;\n            const float m_curr = denom > 0 ? numerator / denom : 0;\n            r.w_sum *= m_curr;\n        }\n\n        // Shift from temporal to current\n        if(r_prev.IsValid() && r_prev.M > 0)\n        {\n            float3 wi_offset = r_prev.wx;\n            float jacobian = 1;\n            float3 target_curr = 0;\n\n            if(IsShiftInvertible(r_prev, surface, alpha_min))\n            {\n                if(r_prev.halfVectorCopyShift)\n                {\n                    float3 wh_local = r_prev.wx;\n                    float3 wh_c = Math::FromTangentFrameToWorld(normal, wh_local);\n                    float3 wh_t = Math::FromTangentFrameToWorld(candidate.normal, wh_local);\n\n                    wi_offset = reflect(-surface.wo, wh_c);\n                    float whdotwo_t = abs(dot(candidate.surface.wo, wh_t));\n                    jacobian = whdotwo_t > 0 ? abs(dot(surface.wo, wh_c)) / whdotwo_t : 1;\n                }\n\n                surface.SetWi(wi_offset, normal);\n\n                const float3 le = r_prev.lightType == Light::TYPE::SKY ? \n                    Light::Le_Sky(wi_offset, g_frame.EnvMapDescHeapOffset) :\n                    Light::Le_Sun(pos, g_frame);\n                target_curr = le * BSDF::Unified(surface).f;\n            }\n            \n            // w_prev becomes zero and only M needs to be updated, which is done at the end anyway\n            if(dot(target_curr, target_curr) > 0)\n            {\n                if(RtRayQuery::Visibility_Ray(pos, wi_offset, normal, g_bvh, surface.Transmissive()))\n                {\n                    const float targetLum_curr = Math::Luminance(target_curr);\n                    const float targetLum_prev = r_prev.W > 0 ? r_prev.w_sum / r_prev.W : 0;\n                    const float numerator = r_prev.M * targetLum_prev;\n                    const float denom = numerator / jacobian + r.M * targetLum_curr;\n                    // Balance Heuristic\n                    const float m_prev = denom > 0 ? numerator / denom : 0;\n                    const float w_prev = m_prev * targetLum_curr * r_prev.W;\n\n                    // float3 wh_local = WorldToTangentFrame(normal, wh_c);\n                    // float3 wh_local = r_prev.wx;\n                    // float3 wx = r_prev.halfVectorCopyShift ? wh_local : wi_offset;\n\n                    r.Update(w_prev, r_prev.wx, r_prev.lightType, r_prev.lobe, r_prev.halfVectorCopyShift, \n                        surface.whdotwo, target_curr, rng);\n                }\n            }\n        }\n\n        float targetLum = Math::Luminance(r.target);\n        r.W = targetLum > 0.0 ? r.w_sum / targetLum : 0.0;\n        r.M = newM;\n    }\n\n    void SpatialResample(uint2 DTid, float3 pos, float3 normal, float z_view, \n        float roughness, BSDF::ShadingData surface, uint reservoir_A_DescHeapIdx, \n        uint reservoir_B_DescHeapIdx, uint reservoir_C_DescHeapIdx, float alpha_min, \n        RaytracingAccelerationStructure g_bvh, ConstantBuffer<cbFrameConstants> g_frame, \n        inout Reservoir r_c, inout RNG rng)\n    {\n        static const half2 k_samples[16] =\n        {\n            half2(-0.899423, 0.365076),\n            half2(-0.744442, -0.124006),\n            half2(-0.229714, 0.245876),\n            half2(-0.545186, 0.741148),\n            half2(-0.156274, -0.336366),\n            half2(0.468400, 0.348798),\n            half2(0.035776, 0.606928),\n            half2(-0.208966, 0.904852),\n            half2(-0.491070, -0.484810),\n            half2(0.162490, -0.081156),\n            half2(0.232062, -0.851382),\n            half2(0.641310, -0.162124),\n            half2(0.320798, 0.922460),\n            half2(0.959086, 0.263642),\n            half2(0.531136, -0.519002),\n            half2(-0.223014, -0.774740)\n        };\n\n        GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::DEPTH];\n        GBUFFER_METALLIC_ROUGHNESS g_mr = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n\n        // rotate sample sequence per pixel\n        const float u0 = rng.Uniform();\n        const int offset = (int)rng.UniformUintBounded_Faster(16);\n        const float theta = u0 * TWO_PI;\n        const float sinTheta = sin(theta);\n        const float cosTheta = cos(theta);\n\n        const uint2 renderDim = uint2(g_frame.RenderWidth, g_frame.RenderHeight);\n        PairwiseMIS pairwiseMIS = PairwiseMIS::Init(NUM_SPATIAL_SAMPLES, r_c);\n\n        float3 samplePos[NUM_SPATIAL_SAMPLES];\n        float3 sampleOrigin[NUM_SPATIAL_SAMPLES];\n        int16_t2 samplePosSS[NUM_SPATIAL_SAMPLES];\n        bool sampleMetallic[NUM_SPATIAL_SAMPLES];\n        float sampleRoughness[NUM_SPATIAL_SAMPLES];\n        bool sampleTr[NUM_SPATIAL_SAMPLES];\n        bool sampleSubsurf[NUM_SPATIAL_SAMPLES];\n        bool sampleCoated[NUM_SPATIAL_SAMPLES];\n        uint16 k = 0;\n\n        [loop]\n        for (int i = 0; i < NUM_SPATIAL_SAMPLES; i++)\n        {\n            float2 sampleUV = k_samples[(offset + i) & 15];\n            float2 rotated;\n            rotated.x = dot(sampleUV, float2(cosTheta, -sinTheta));\n            rotated.y = dot(sampleUV, float2(sinTheta, cosTheta));\n            rotated *= SPATIAL_SEARCH_RADIUS;\n            const int2 posSS_i = round(float2(DTid) + rotated);\n\n            if (Math::IsWithinBounds(posSS_i, (int2)renderDim))\n            {\n                const float2 mr_i = g_mr[posSS_i];\n                GBuffer::Flags flags_i = GBuffer::DecodeMetallic(mr_i.x);\n\n                if (flags_i.invalid || flags_i.emissive)\n                    continue;\n\n                const float depth_i = g_depth[posSS_i];\n                float2 lensSample = 0;\n                float3 origin_i = g_frame.CameraPos;\n                if(g_frame.DoF)\n                {\n                    RNG rngDoF = RNG::Init(RNG::PCG3d(posSS_i.xyx).zy, g_frame.FrameNum);\n                    lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n                    lensSample *= g_frame.LensRadius;\n                }\n\n                float3 pos_i = Math::WorldPosFromScreenSpace2(posSS_i, renderDim, depth_i, \n                    g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n                    g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n                    g_frame.DoF, lensSample, g_frame.FocusDepth, origin_i);\n\n                bool valid = PlaneHeuristic(pos_i, normal, pos, z_view);\n                valid = valid && (abs(mr_i.y - roughness) < MAX_ROUGHNESS_DIFF_REUSE);\n\n                if (!valid)\n                    continue;\n\n                samplePos[k] = pos_i;\n                sampleOrigin[k] = origin_i;\n                samplePosSS[k] = (int16_t2)posSS_i;\n                sampleMetallic[k] = flags_i.metallic;\n                sampleRoughness[k] = mr_i.y;\n                sampleTr[k] = flags_i.transmissive;\n                sampleSubsurf[k] = flags_i.subsurface;\n                sampleCoated[k] = flags_i.coated;\n\n                k++;\n            }\n        }\n\n        pairwiseMIS.k = k;\n\n        for (int i = 0; i < k; i++)\n        {\n            GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n                GBUFFER_OFFSET::NORMAL];\n            const float3 sampleNormal = Math::DecodeUnitVector(g_normal[samplePosSS[i]]);\n\n            GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n                GBUFFER_OFFSET::BASE_COLOR];\n            const float4 sampleBaseColor = sampleSubsurf[i] ? g_baseColor[samplePosSS[i]] :\n                float4(g_baseColor[samplePosSS[i]].rgb, 0);\n\n            float sampleEta_next = DEFAULT_ETA_MAT;\n\n            if(sampleTr[i])\n            {\n                GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n                    GBUFFER_OFFSET::IOR];\n\n                float ior = g_ior[samplePosSS[i]];\n                sampleEta_next = GBuffer::DecodeIOR(ior);\n            }\n\n            float sample_coat_weight = 0;\n            float3 sample_coat_color = 0.0f;\n            float sample_coat_roughness = 0;\n            float sample_coat_ior = DEFAULT_ETA_COAT;\n\n            if(sampleCoated[i])\n            {\n                GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n                    GBUFFER_OFFSET::COAT];\n                uint3 packed = g_coat[samplePosSS[i]].xyz;\n\n                GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n                sample_coat_weight = coat.weight;\n                sample_coat_color = coat.color;\n                sample_coat_roughness = coat.roughness;\n                sample_coat_ior = coat.ior;\n            }\n\n            const float3 wo_i = normalize(sampleOrigin[i] - samplePos[i]);\n            BSDF::ShadingData surface_i = BSDF::ShadingData::Init(sampleNormal, wo_i,\n                sampleMetallic[i], sampleRoughness[i], sampleBaseColor.xyz, ETA_AIR,\n                sampleEta_next, sampleTr[i], false, (half)sampleBaseColor.w, sample_coat_weight, \n                sample_coat_color, sample_coat_roughness, sample_coat_ior);\n\n            Reservoir r_spatial = Reservoir::Load(samplePosSS[i], \n                reservoir_A_DescHeapIdx, reservoir_B_DescHeapIdx,\n                reservoir_C_DescHeapIdx);\n\n            pairwiseMIS.Stream(r_c, pos, normal, surface, r_spatial, samplePos[i], \n                sampleNormal, surface_i, alpha_min, g_bvh, g_frame, rng);\n        }\n\n        pairwiseMIS.End(r_c, rng);\n        r_c = pairwiseMIS.r_s;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Sky/Reservoir.hlsli",
    "content": "#ifndef SKY_DI_RESERVOIR_H\n#define SKY_DI_RESERVOIR_H\n\n#include \"SkyDI_Common.h\"\n#include \"Util.hlsli\"\n\nnamespace SkyDI_Util\n{\n    struct Reservoir\n    {\n        static Reservoir Init()\n        {\n            Reservoir res;\n            res.M = 0;\n            res.w_sum = 0;\n            res.W = 0;\n            res.wx = 0.0;\n            res.target = 0;\n            res.lightType = Light::TYPE::NONE;\n            res.partialJacobian = 1;\n            res.halfVectorCopyShift = false;\n            res.lobe = BSDF::LOBE::ALL;\n\n            return res;\n        }\n\n        static Reservoir Load(uint2 DTid, uint inputAIdx, uint inputBIdx, uint inputCIdx)\n        {\n            Texture2D<uint> g_reservoir_A = ResourceDescriptorHeap[inputAIdx];\n            Texture2D<uint2> g_reservoir_B = ResourceDescriptorHeap[inputBIdx];\n            Texture2D<float2> g_reservoir_C = ResourceDescriptorHeap[inputCIdx];\n\n            Reservoir ret = Reservoir::Init();\n            const uint metadata = g_reservoir_A[DTid];\n            ret.M = (uint16)(metadata & 0xf);\n\n            bool wSumGt0 = (metadata >> 7) > 0;\n            if(!wSumGt0)\n                return ret;\n\n            ret.lightType = (metadata >> 4) & 0x1 ? Light::TYPE::SKY : Light::TYPE::SUN;\n            ret.halfVectorCopyShift = (metadata >> 5) & 0x1;\n            bool lobeIsCoat = (metadata >> 6) & 0x1;\n            if(ret.halfVectorCopyShift)\n                ret.lobe = lobeIsCoat ? BSDF::LOBE::COAT : BSDF::LOBE::GLOSSY_R;\n            else\n                ret.lobe = BSDF::LOBE::ALL;\n\n            uint16_t2 temp = (uint16_t2)g_reservoir_B[DTid];\n            ret.wx = Math::DecodeOct32(temp);\n\n            const float2 weights = g_reservoir_C[DTid];\n            ret.w_sum = weights.x;\n            ret.W = weights.y;\n\n            return ret;\n        }\n\n        void LoadTarget(uint2 DTid, uint uavIdx)\n        {\n            RWTexture2D<float4> g_target = ResourceDescriptorHeap[uavIdx];\n            this.target = g_target[DTid].xyz;\n        }\n\n        bool IsValid()\n        {\n            // return dot(this.wx, this.wx) != 0;\n            return this.w_sum > 0;\n        }\n\n        bool Update(float weight, float3 wi, float3 wo, float3 normal, Light::TYPE lt, BSDF::LOBE lb, \n            bool halfVecShift, float3 target, inout RNG rng)\n        {\n            if(isnan(weight))\n                return false;\n\n            this.M += 1;\n\n            if(weight == 0)\n                return false;\n\n            this.w_sum += weight;\n\n            if (rng.Uniform() < (weight / this.w_sum))\n            {\n                this.target = target;\n                this.lightType = lt;\n                this.lobe = lb;\n                this.halfVectorCopyShift = halfVecShift;\n\n                // Sample uses half-vector copy shift\n                if(halfVecShift)\n                {\n                    float3 wh = normalize(wo + wi);\n                    float3 wh_local = Math::WorldToTangentFrame(normal, wh);\n\n                    this.wx = wh_local;\n                    this.partialJacobian = abs(dot(wh, wo));\n                }\n                else\n                    this.wx = wi;\n\n                return true;\n            }\n\n            return false;\n        }\n\n        bool Update(float weight, float3 wi_or_wh, Light::TYPE lt, BSDF::LOBE lb, \n            bool halfVecShift, float whdotwo, float3 target, inout RNG rng)\n        {\n            if(isnan(weight))\n                return false;\n\n            this.M += 1;\n\n            if(weight == 0)\n                return false;\n\n            this.w_sum += weight;\n\n            if (rng.Uniform() < (weight / this.w_sum))\n            {\n                this.wx = wi_or_wh;\n                this.target = target;\n                this.lightType = lt;\n                this.lobe = lb;\n                this.halfVectorCopyShift = halfVecShift;\n                this.partialJacobian = whdotwo;\n\n                return true;\n            }\n\n            return false;\n        }\n\n        void WriteTarget(uint2 DTid, uint uavIdx)\n        {\n            RWTexture2D<float4> g_target = ResourceDescriptorHeap[uavIdx];\n            this.target = Math::Sanitize(this.target);\n            g_target[DTid].xyz = this.target;\n        }\n\n        void Write(uint2 DTid, uint outputAIdx, uint outputBIdx, uint outputCIdx, \n            uint M_max)\n        {\n            RWTexture2D<uint> g_outReservoir_A = ResourceDescriptorHeap[outputAIdx];\n            RWTexture2D<uint2> g_outReservoir_B = ResourceDescriptorHeap[outputBIdx];\n            RWTexture2D<float2> g_outReservoir_C = ResourceDescriptorHeap[outputCIdx];\n\n            // metadata\n            uint M_capped = min(this.M, M_max) & 0xf;\n            bool wSumGt0 = this.w_sum > 0;\n            uint metadata = M_capped | \n                (uint(this.lightType == Light::TYPE::SKY) << 4) |\n                (uint(this.halfVectorCopyShift) << 5) |\n                (uint(this.lobe == BSDF::LOBE::COAT) << 6) |\n                (uint(wSumGt0) << 7);\n            g_outReservoir_A[DTid] = metadata;\n\n            if(!wSumGt0)\n                return;\n\n            g_outReservoir_B[DTid] = Math::EncodeOct32(this.wx);\n            g_outReservoir_C[DTid] = float2(this.w_sum, this.W);\n        }\n\n        float w_sum;\n        float W;\n        // Either wi or wh\n        float3 wx;\n        float3 target;\n        float partialJacobian;\n        bool halfVectorCopyShift;\n        uint16 M;\n        BSDF::LOBE lobe;\n        Light::TYPE lightType;\n    };\n\n    bool IsShiftInvertible(Reservoir r_base, BSDF::ShadingData surface_offset, float alpha_min)\n    {\n        return !r_base.halfVectorCopyShift ||\n            (BSDF::IsLobeValid(surface_offset, r_base.lobe) &&\n            (BSDF::LobeAlpha(surface_offset, r_base.lobe) <= alpha_min));\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Sky/SkyDI.cpp",
    "content": "#include \"SkyDI.h\"\n#include <Core/CommandList.h>\n#include <Scene/SceneCore.h>\n#include <Support/Param.h>\n#include <Support/Task.h>\n#include \"../Assets/Font/IconsFontAwesome6.h\"\n\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Core::Direct3DUtil;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Util;\n\n//--------------------------------------------------------------------------------------\n// SkyDI\n//--------------------------------------------------------------------------------------\n\nSkyDI::SkyDI()\n    : RenderPassBase(NUM_CBV, NUM_SRV, NUM_UAV, NUM_GLOBS, NUM_CONSTS)\n{\n    // root constants\n    m_rootSig.InitAsConstants(0, NUM_CONSTS, 1);\n\n    // frame constants\n    m_rootSig.InitAsCBV(1, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::FRAME_CONSTANTS_BUFFER);\n\n    // BVH\n    m_rootSig.InitAsBufferSRV(2, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::RT_SCENE_BVH_CURR);\n    // BVH\n    m_rootSig.InitAsBufferSRV(3, 1, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::RT_SCENE_BVH_PREV);\n}\n\nvoid SkyDI::InitPSOs()\n{\n    constexpr D3D12_ROOT_SIGNATURE_FLAGS flags =\n        D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;\n\n    auto samplers = App::GetRenderer().GetStaticSamplers();\n    RenderPassBase::InitRenderPass(\"SkyDI\", flags, samplers);\n\n    TaskSet ts;\n\n    for (int i = 0; i < (int)SHADER::COUNT; i++)\n    {\n        StackStr(buff, n, \"SkyDI_shader_%d\", i);\n\n        ts.EmplaceTask(buff, [i, this]()\n            {\n                m_psoLib.CompileComputePSO_MT(i, m_rootSigObj.Get(),\n                    COMPILED_CS[i]);\n            });\n    }\n\n    WaitObject waitObj;\n    ts.Sort();\n    ts.Finalize(&waitObj);\n    App::Submit(ZetaMove(ts));\n}\n\nvoid SkyDI::Init()\n{\n    InitPSOs();\n\n    memset(&m_cbSpatioTemporal, 0, sizeof(m_cbSpatioTemporal));\n    m_cbSpatioTemporal.M_max = DefaultParamVals::M_MAX_SKY | (DefaultParamVals::M_MAX_SUN << 16);\n    m_cbSpatioTemporal.Alpha_min = DefaultParamVals::ROUGHNESS_MIN * DefaultParamVals::ROUGHNESS_MIN;\n\n    m_descTable = App::GetRenderer().GetGpuDescriptorHeap().Allocate((int)DESC_TABLE::COUNT);\n    CreateOutputs();\n\n    ParamVariant doTemporal;\n    doTemporal.InitBool(ICON_FA_FILM \" Renderer\", \"Direct Lighting (Sky)\", \"Temporal Resample\",\n        fastdelegate::MakeDelegate(this, &SkyDI::TemporalResamplingCallback), m_temporalResampling);\n    App::AddParam(doTemporal);\n\n    ParamVariant doSpatial;\n    doSpatial.InitBool(ICON_FA_FILM \" Renderer\", \"Direct Lighting (Sky)\", \"Spatial Resample\",\n        fastdelegate::MakeDelegate(this, &SkyDI::SpatialResamplingCallback), m_spatialResampling);\n    App::AddParam(doSpatial);\n\n    ParamVariant m_max_sky;\n    m_max_sky.InitInt(ICON_FA_FILM \" Renderer\", \"Direct Lighting (Sky)\", \"M_max (Sky)\",\n        fastdelegate::MakeDelegate(this, &SkyDI::MaxMSkyCallback),\n        DefaultParamVals::M_MAX_SKY, 1, 15, 1);\n    App::AddParam(m_max_sky);\n\n    ParamVariant m_max_sun;\n    m_max_sun.InitInt(ICON_FA_FILM \" Renderer\", \"Direct Lighting (Sky)\", \"M_max (Sun)\",\n        fastdelegate::MakeDelegate(this, &SkyDI::MaxMSunCallback),\n        DefaultParamVals::M_MAX_SUN, 1, 15, 1);\n    App::AddParam(m_max_sun);\n\n    ParamVariant alphaMin;\n    alphaMin.InitFloat(ICON_FA_FILM \" Renderer\", \"Direct Lighting (Sky)\", \"Alpha_min\",\n        fastdelegate::MakeDelegate(this, &SkyDI::AlphaMinCallback),\n        DefaultParamVals::ROUGHNESS_MIN, 0.0f, 1.0f, 1e-2f);\n    App::AddParam(alphaMin);\n\n    App::AddShaderReloadHandler(\"SkyDI (Temporal)\", fastdelegate::MakeDelegate(this, &SkyDI::ReloadTemporalPass));\n    App::AddShaderReloadHandler(\"SkyDI (Spatial)\", fastdelegate::MakeDelegate(this, &SkyDI::ReloadSpatialPass));\n\n    m_isTemporalReservoirValid = false;\n}\n\nvoid SkyDI::OnWindowResized()\n{\n    CreateOutputs();\n    m_isTemporalReservoirValid = false;\n    m_currTemporalIdx = 0;\n}\n\nvoid SkyDI::ResetTemporal()\n{\n    m_isTemporalReservoirValid = false;\n    m_currTemporalIdx = 0;\n    SET_CB_FLAG(m_cbSpatioTemporal, CB_SKY_DI_FLAGS::RESET_TEMPORAL_TEXTURES, true);\n}\n\nvoid SkyDI::Render(CommandList& cmdList)\n{\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT ||\n        cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE, \"Invalid downcast\");\n    ComputeCmdList& computeCmdList = static_cast<ComputeCmdList&>(cmdList);\n\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n    const uint32_t w = renderer.GetRenderWidth();\n    const uint32_t h = renderer.GetRenderHeight();\n\n    computeCmdList.SetRootSignature(m_rootSig, m_rootSigObj.Get());\n\n    const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, SKY_DI_GROUP_DIM_X);\n    const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, SKY_DI_GROUP_DIM_Y);\n\n    const bool doTemporal = m_isTemporalReservoirValid && m_temporalResampling;\n    const bool doSpatial = doTemporal && m_spatialResampling;\n\n    SET_CB_FLAG(m_cbSpatioTemporal, CB_SKY_DI_FLAGS::TEMPORAL_RESAMPLE, doTemporal);\n    SET_CB_FLAG(m_cbSpatioTemporal, CB_SKY_DI_FLAGS::SPATIAL_RESAMPLE, doSpatial);\n\n    m_cbSpatioTemporal.DispatchDimX = (uint16_t)dispatchDimX;\n    m_cbSpatioTemporal.DispatchDimY = (uint16_t)dispatchDimY;\n    m_cbSpatioTemporal.NumGroupsInTile = SKY_DI_TILE_WIDTH * m_cbSpatioTemporal.DispatchDimY;\n\n    // Initial candidates and temporal\n    {\n        computeCmdList.PIXBeginEvent(\"SkyDI_Temporal\");\n        const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"SkyDI_Temporal\");\n\n        SmallVector<D3D12_TEXTURE_BARRIER, SystemAllocator, Reservoir::NUM * 2> barriers;\n\n        // Current reservoirs into UAV\n        if (m_reservoir[m_currTemporalIdx].Layout != D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS)\n        {\n            barriers.push_back(TextureBarrier_SrvToUavNoSync(\n                m_reservoir[m_currTemporalIdx].A.Resource()));\n            barriers.push_back(TextureBarrier_SrvToUavNoSync(\n                m_reservoir[m_currTemporalIdx].B.Resource()));\n            barriers.push_back(TextureBarrier_SrvToUavNoSync(\n                m_reservoir[m_currTemporalIdx].C.Resource()));\n\n            m_reservoir[m_currTemporalIdx].Layout = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS;\n        }\n\n        // Temporal reservoirs into SRV\n        if (doTemporal)\n        {\n            if (m_reservoir[1 - m_currTemporalIdx].Layout == \n                D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS)\n            {\n                barriers.push_back(TextureBarrier_UavToSrvNoSync(\n                    m_reservoir[1 - m_currTemporalIdx].A.Resource()));\n                barriers.push_back(TextureBarrier_UavToSrvNoSync(\n                    m_reservoir[1 - m_currTemporalIdx].B.Resource()));\n                barriers.push_back(TextureBarrier_UavToSrvNoSync(\n                    m_reservoir[1 - m_currTemporalIdx].C.Resource()));\n\n                m_reservoir[1 - m_currTemporalIdx].Layout = \n                    D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE;\n            }\n        }\n\n        if(!barriers.empty())\n            computeCmdList.ResourceBarrier(barriers.data(), (UINT)barriers.size());\n\n        auto srvAIdx = m_currTemporalIdx == 1 ? DESC_TABLE::RESERVOIR_0_A_SRV : \n            DESC_TABLE::RESERVOIR_1_A_SRV;\n        auto uavAIdx = m_currTemporalIdx == 1 ? DESC_TABLE::RESERVOIR_1_A_UAV : \n            DESC_TABLE::RESERVOIR_0_A_UAV;\n\n        m_cbSpatioTemporal.PrevReservoir_A_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)srvAIdx);\n        m_cbSpatioTemporal.CurrReservoir_A_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)uavAIdx);\n\n        m_rootSig.SetRootConstants(0, sizeof(m_cbSpatioTemporal) / sizeof(DWORD), &m_cbSpatioTemporal);\n        m_rootSig.End(computeCmdList);\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::SKY_DI_TEMPORAL));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n\n        gpuTimer.EndQuery(computeCmdList, queryIdx);\n        cmdList.PIXEndEvent();\n    }\n\n    // Spatial\n    if (doSpatial)\n    {\n        computeCmdList.PIXBeginEvent(\"SkyDI_Spatial\");\n        const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"SkyDI_Spatial\");\n\n        D3D12_TEXTURE_BARRIER barriers[Reservoir::NUM];\n\n        // current reservoirs into UAV\n        barriers[0] = TextureBarrier_UavToSrvWithSync(m_reservoir[m_currTemporalIdx].A.Resource());\n        barriers[1] = TextureBarrier_UavToSrvWithSync(m_reservoir[m_currTemporalIdx].B.Resource());\n        barriers[2] = TextureBarrier_UavToSrvWithSync(m_reservoir[m_currTemporalIdx].C.Resource());\n        computeCmdList.ResourceBarrier(barriers, ZetaArrayLen(barriers));\n\n        m_reservoir[m_currTemporalIdx].Layout = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE;\n\n        auto srvAIdx = m_currTemporalIdx == 1 ? DESC_TABLE::RESERVOIR_1_A_SRV :\n            DESC_TABLE::RESERVOIR_0_A_SRV;\n\n        m_cbSpatioTemporal.CurrReservoir_A_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)srvAIdx);\n\n        m_rootSig.SetRootConstants(0, sizeof(m_cbSpatioTemporal) / sizeof(DWORD), &m_cbSpatioTemporal);\n        m_rootSig.End(computeCmdList);\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::SKY_DI_SPATIAL));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n\n        gpuTimer.EndQuery(computeCmdList, queryIdx);\n        cmdList.PIXEndEvent();\n    }\n\n    m_isTemporalReservoirValid = true;\n    m_currTemporalIdx = 1 - m_currTemporalIdx;\n    SET_CB_FLAG(m_cbSpatioTemporal, CB_SKY_DI_FLAGS::RESET_TEMPORAL_TEXTURES, false);\n}\n\nvoid SkyDI::CreateOutputs()\n{\n    auto& renderer = App::GetRenderer();\n    const auto w = renderer.GetRenderWidth();\n    const auto h = renderer.GetRenderHeight();\n\n    constexpr int N = 2 * Reservoir::NUM + 1 + 1;\n    PlacedResourceList<N> list;\n\n    // reservoirs\n    for (int i = 0; i < 2; i++)\n    {\n        list.PushTex2D(ResourceFormats::RESERVOIR_A, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats::RESERVOIR_B, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats::RESERVOIR_C, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n    }\n\n    // target\n    list.PushTex2D(ResourceFormats::TARGET, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n    // final\n    list.PushTex2D(ResourceFormats::FINAL, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n    list.End();\n\n    m_resHeap = GpuMemory::GetResourceHeap(list.TotalSizeInBytes());\n    auto allocs = list.AllocInfos();\n    int currRes = 0;\n\n    auto func = [this, w, h](Texture& tex, DXGI_FORMAT format, const char* baseName, int idx,\n        const char* subName, const D3D12_RESOURCE_ALLOCATION_INFO1& allocInfo,\n        int srvIdx, int uavIdx, int descOffset, D3D12_BARRIER_LAYOUT layout)\n        {\n            StackStr(name, N, \"%s_%d_%s\", baseName, idx, subName);\n            tex = GpuMemory::GetPlacedTexture2D(name, w, h, format, m_resHeap.Heap(), allocInfo.Offset,\n                layout, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n            Direct3DUtil::CreateTexture2DSRV(tex, m_descTable.CPUHandle(srvIdx + descOffset));\n            Direct3DUtil::CreateTexture2DUAV(tex, m_descTable.CPUHandle(uavIdx + descOffset));\n        };\n\n    static_assert((int)(DESC_TABLE::RESERVOIR_0_A_SRV) + 1 == (int)DESC_TABLE::RESERVOIR_0_B_SRV);\n    static_assert((int)(DESC_TABLE::RESERVOIR_0_A_SRV) + 2 == (int)DESC_TABLE::RESERVOIR_0_C_SRV);\n    static_assert((int)(DESC_TABLE::RESERVOIR_0_A_UAV) + 1 == (int)DESC_TABLE::RESERVOIR_0_B_UAV);\n    static_assert((int)(DESC_TABLE::RESERVOIR_0_A_UAV) + 2 == (int)DESC_TABLE::RESERVOIR_0_C_UAV);\n    static_assert((int)(DESC_TABLE::RESERVOIR_1_A_SRV) + 1 == (int)DESC_TABLE::RESERVOIR_1_B_SRV);\n    static_assert((int)(DESC_TABLE::RESERVOIR_1_A_SRV) + 2 == (int)DESC_TABLE::RESERVOIR_1_C_SRV);\n    static_assert((int)(DESC_TABLE::RESERVOIR_1_A_UAV) + 1 == (int)DESC_TABLE::RESERVOIR_1_B_UAV);\n    static_assert((int)(DESC_TABLE::RESERVOIR_1_A_UAV) + 2 == (int)DESC_TABLE::RESERVOIR_1_C_UAV);\n\n    const D3D12_BARRIER_LAYOUT initLayout[2] = { D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS,\n        m_temporalResampling ?\n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE :\n            D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS };\n    \n    for (int i = 0; i < 2; i++)\n    {\n        const int descOffset = i * Reservoir::NUM * 2;\n        const auto layout = initLayout[i];\n\n        func(m_reservoir[i].A, ResourceFormats::RESERVOIR_A,\n            \"SkyDI_Reservoir\", i, \"A\", allocs[currRes++],\n            (int)DESC_TABLE::RESERVOIR_0_A_SRV, (int)DESC_TABLE::RESERVOIR_0_A_UAV,\n            descOffset, layout);\n        func(m_reservoir[i].B, ResourceFormats::RESERVOIR_B,\n            \"SkyDI_Reservoir\", i, \"B\", allocs[currRes++],\n            (int)DESC_TABLE::RESERVOIR_0_B_SRV, (int)DESC_TABLE::RESERVOIR_0_B_UAV,\n            descOffset, layout);\n        func(m_reservoir[i].C, ResourceFormats::RESERVOIR_C,\n            \"SkyDI_Reservoir\", i, \"C\", allocs[currRes++],\n            (int)DESC_TABLE::RESERVOIR_0_C_SRV, (int)DESC_TABLE::RESERVOIR_0_C_UAV,\n            descOffset, layout);\n\n        m_reservoir[i].Layout = initLayout[i];\n    }\n\n    m_target = GpuMemory::GetPlacedTexture2D(\"SkyDI_target\", w, h, ResourceFormats::TARGET, \n        m_resHeap.Heap(), allocs[currRes++].Offset,\n        D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS,\n        TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n    m_final = GpuMemory::GetPlacedTexture2D(\"SkyDI_final\", w, h, ResourceFormats::FINAL, \n        m_resHeap.Heap(), allocs[currRes++].Offset,\n        D3D12_RESOURCE_STATE_COMMON,\n        TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n    Direct3DUtil::CreateTexture2DUAV(m_target, m_descTable.CPUHandle((int)DESC_TABLE::TARGET_UAV));\n    Direct3DUtil::CreateTexture2DUAV(m_final, m_descTable.CPUHandle((int)DESC_TABLE::FINAL_UAV));\n\n    // Following never change, so can be set only once\n    m_cbSpatioTemporal.TargetDescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n        (int)DESC_TABLE::TARGET_UAV);\n    m_cbSpatioTemporal.FinalDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((\n        int)DESC_TABLE::FINAL_UAV);\n}\n\nvoid SkyDI::TemporalResamplingCallback(const Support::ParamVariant& p)\n{\n    m_temporalResampling = p.GetBool();\n    App::GetScene().SceneModified();\n}\n\nvoid SkyDI::SpatialResamplingCallback(const Support::ParamVariant& p)\n{\n    m_spatialResampling = p.GetBool();\n    App::GetScene().SceneModified();\n}\n\nvoid SkyDI::MaxMSkyCallback(const Support::ParamVariant& p)\n{\n    m_cbSpatioTemporal.M_max = (m_cbSpatioTemporal.M_max & 0xffff0000) | p.GetInt().m_value;\n    App::GetScene().SceneModified();\n}\n\nvoid SkyDI::MaxMSunCallback(const Support::ParamVariant& p)\n{\n    m_cbSpatioTemporal.M_max = (m_cbSpatioTemporal.M_max & 0xffff) | (p.GetInt().m_value << 16);\n    App::GetScene().SceneModified();\n}\n\nvoid SkyDI::AlphaMinCallback(const Support::ParamVariant& p)\n{\n    float newVal = p.GetFloat().m_value;\n    m_cbSpatioTemporal.Alpha_min = newVal * newVal;\n    App::GetScene().SceneModified();\n}\n\nvoid SkyDI::ReloadTemporalPass()\n{\n    const int i = (int)SHADER::SKY_DI_TEMPORAL;\n    m_psoLib.Reload(i, m_rootSigObj.Get(), \"DirectLighting\\\\Sky\\\\SkyDI_Temporal.hlsl\");\n}\n\nvoid SkyDI::ReloadSpatialPass()\n{\n    const int i = (int)SHADER::SKY_DI_SPATIAL;\n    m_psoLib.Reload(i, m_rootSigObj.Get(), \"DirectLighting\\\\Sky\\\\SkyDI_Spatial.hlsl\");\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Sky/SkyDI.h",
    "content": "#pragma once\n\n#include \"../../RenderPass.h\"\n#include <Core/GpuMemory.h>\n#include \"SkyDI_Common.h\"\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n}\n\nnamespace ZetaRay::Support\n{\n    struct ParamVariant;\n}\n\nnamespace ZetaRay::RenderPass\n{\n    enum class SKY_DI_SHADER\n    {\n        SKY_DI_TEMPORAL,\n        SKY_DI_SPATIAL,\n        COUNT\n    };\n\n    struct SkyDI final : public RenderPassBase<(int)SKY_DI_SHADER::COUNT>\n    {\n        enum class SHADER_OUT_RES\n        {\n            DENOISED,\n            COUNT\n        };\n\n        SkyDI();\n        ~SkyDI() = default;\n\n        void InitPSOs();\n        void Init();\n        void OnWindowResized();\n        void ResetTemporal();\n        const Core::GpuMemory::Texture& GetOutput(SHADER_OUT_RES i) const\n        {\n            Assert(i == SHADER_OUT_RES::DENOISED, \"Invalid shader output.\");\n            return m_final;\n        }\n        void Render(Core::CommandList& cmdList);\n\n    private:\n        static constexpr int NUM_CBV = 1;\n        static constexpr int NUM_SRV = 2;\n        static constexpr int NUM_UAV = 0;\n        static constexpr int NUM_GLOBS = 3;\n        static constexpr int NUM_CONSTS = (int)(sizeof(cb_SkyDI) / sizeof(DWORD));\n        using SHADER = SKY_DI_SHADER;\n\n        struct ResourceFormats\n        {\n            static constexpr DXGI_FORMAT RESERVOIR_A = DXGI_FORMAT_R8_UINT;\n            static constexpr DXGI_FORMAT RESERVOIR_B = DXGI_FORMAT_R16G16_UINT;\n            static constexpr DXGI_FORMAT RESERVOIR_C = DXGI_FORMAT_R32G32_FLOAT;\n            static constexpr DXGI_FORMAT TARGET = DXGI_FORMAT_R16G16B16A16_FLOAT;\n            static constexpr DXGI_FORMAT FINAL = DXGI_FORMAT_R32G32B32A32_FLOAT;\n        };\n\n        enum class DESC_TABLE\n        {\n            RESERVOIR_0_A_SRV,\n            RESERVOIR_0_B_SRV,\n            RESERVOIR_0_C_SRV,\n            RESERVOIR_0_A_UAV,\n            RESERVOIR_0_B_UAV,\n            RESERVOIR_0_C_UAV,\n            //\n            RESERVOIR_1_A_SRV,\n            RESERVOIR_1_B_SRV,\n            RESERVOIR_1_C_SRV,\n            RESERVOIR_1_A_UAV,\n            RESERVOIR_1_B_UAV,\n            RESERVOIR_1_C_UAV,\n            TARGET_UAV,\n            FINAL_UAV,\n            //\n            COUNT\n        };\n\n        struct DefaultParamVals\n        {\n            static constexpr int M_MAX_SKY = 15;\n            static constexpr int M_MAX_SUN = 3;\n            // Use half-vector copy for anything lower\n            static constexpr float ROUGHNESS_MIN = 0.35f;\n        };\n\n        inline static constexpr const char* COMPILED_CS[(int)SHADER::COUNT] = {\n            \"SkyDI_Temporal_cs.cso\",\n            \"SkyDI_Spatial_cs.cso\"\n        };\n\n        struct Reservoir\n        {\n            static constexpr int NUM = 3;\n\n            // Texture2D<uint>: (metadata)\n            Core::GpuMemory::Texture A;\n            // Texture2D<uint2>: wi\n            Core::GpuMemory::Texture B;\n            // Texture2D<float2>: (w_sum, W)\n            Core::GpuMemory::Texture C;\n\n            D3D12_BARRIER_LAYOUT Layout;\n        };\n\n        void CreateOutputs();\n\n        void TemporalResamplingCallback(const Support::ParamVariant& p);\n        void SpatialResamplingCallback(const Support::ParamVariant& p);\n        void MaxMSkyCallback(const Support::ParamVariant& p);\n        void MaxMSunCallback(const Support::ParamVariant& p);\n        void AlphaMinCallback(const Support::ParamVariant& p);\n\n        // shader reload\n        void ReloadTemporalPass();\n        void ReloadSpatialPass();\n\n        Reservoir m_reservoir[2];\n        Core::GpuMemory::ResourceHeap m_resHeap;\n        Core::GpuMemory::Texture m_target;\n        Core::GpuMemory::Texture m_final;\n        int m_currTemporalIdx = 0;\n        bool m_temporalResampling = true;\n        bool m_spatialResampling = true;\n        bool m_isTemporalReservoirValid = false;\n\n        Core::DescriptorTable m_descTable;\n\n        cb_SkyDI m_cbSpatioTemporal;\n    };\n}"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Sky/SkyDI_Common.h",
    "content": "#ifndef SKY_DI_COMMON_H\n#define SKY_DI_COMMON_H\n\n#include \"../../../ZetaCore/Core/HLSLCompat.h\"\n\n#define SKY_DI_GROUP_DIM_X 8u\n#define SKY_DI_GROUP_DIM_Y 8u\n\n#define SKY_DI_TILE_WIDTH 8\n#define SKY_DI_LOG2_TILE_WIDTH 3\n\nnamespace CB_SKY_DI_FLAGS\n{\n    static constexpr uint32_t TEMPORAL_RESAMPLE = 1 << 0;\n    static constexpr uint32_t SPATIAL_RESAMPLE = 1 << 1;\n    static constexpr uint32_t RESET_TEMPORAL_TEXTURES = 1 << 2;\n};\n\nstruct cb_SkyDI\n{\n    uint32_t PrevReservoir_A_DescHeapIdx;\n    uint32_t CurrReservoir_A_DescHeapIdx;\n    uint32_t TargetDescHeapIdx;\n    uint32_t FinalDescHeapIdx;\n\n    float Alpha_min;\n    uint32 M_max;\n    uint32_t Flags;\n    uint16_t DispatchDimX;\n    uint16_t DispatchDimY;\n    uint16_t NumGroupsInTile;\n    uint16_t pad;\n};\n\n#endif\n"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Sky/SkyDI_Spatial.hlsl",
    "content": "#include \"Resampling.hlsli\"\n\n#define THREAD_GROUP_SWIZZLING 1\n\nusing namespace SkyDI_Util;\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_SkyDI> g_local : register(b1);\nRaytracingAccelerationStructure g_bvh : register(t0);\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(SKY_DI_GROUP_DIM_X, SKY_DI_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID)\n{\n#if THREAD_GROUP_SWIZZLING\n    uint2 swizzledGid;\n\n    uint2 swizzledDTid = Common::SwizzleThreadGroup(DTid, Gid, GTid, \n        uint2(SKY_DI_GROUP_DIM_X, SKY_DI_GROUP_DIM_Y),\n        g_local.DispatchDimX, \n        SKY_DI_TILE_WIDTH, \n        SKY_DI_LOG2_TILE_WIDTH, \n        g_local.NumGroupsInTile,\n        swizzledGid);\n#else\n    const uint2 swizzledDTid = DTid.xy;\n    const uint2 swizzledGid = Gid.xy;\n#endif\n\n    if (swizzledDTid.x >= g_frame.RenderWidth || swizzledDTid.y >= g_frame.RenderHeight)\n        return;\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr = g_metallicRoughness[swizzledDTid];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n\n    if (flags.invalid || flags.emissive)\n        return;\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float z_view = g_depth[swizzledDTid];\n    \n    float2 lensSample = 0;\n    float3 origin = g_frame.CameraPos;\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(swizzledDTid.xyx).zy, g_frame.FrameNum);\n        lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample *= g_frame.LensRadius;\n    }\n\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float3 pos = Math::WorldPosFromScreenSpace2(swizzledDTid, renderDim, z_view, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n        g_frame.DoF, lensSample, g_frame.FocusDepth, origin);\n\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_normal[swizzledDTid]);\n\n    GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n    const float4 baseColor = flags.subsurface ? g_baseColor[swizzledDTid] :\n        float4(g_baseColor[swizzledDTid].rgb, 0);\n\n    float eta_curr = ETA_AIR;\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(flags.transmissive)\n    {\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        float ior = g_ior[swizzledDTid];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    float coat_weight = 0;\n    float3 coat_color = 0.0f;\n    float coat_roughness = 0;\n    float coat_ior = DEFAULT_ETA_COAT;\n\n    if(flags.coated)\n    {\n        GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::COAT];\n        uint3 packed = g_coat[swizzledDTid].xyz;\n\n        GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n        coat_weight = coat.weight;\n        coat_color = coat.color;\n        coat_roughness = coat.roughness;\n        coat_ior = coat.ior;\n    }\n\n    const float3 wo = normalize(origin - pos);\n    BSDF::ShadingData surface = BSDF::ShadingData::Init(normal, wo, flags.metallic, mr.y, \n        baseColor.xyz, eta_curr, eta_next, flags.transmissive, flags.trDepthGt0, (half)baseColor.w,\n        coat_weight, coat_color, coat_roughness, coat_ior);\n\n    RNG rng = RNG::Init(RNG::PCG3d(swizzledDTid.yxx).yz, g_frame.FrameNum);\n\n    Reservoir r = Reservoir::Load(swizzledDTid, \n        g_local.CurrReservoir_A_DescHeapIdx, g_local.CurrReservoir_A_DescHeapIdx + 1,\n        g_local.CurrReservoir_A_DescHeapIdx + 2);\n    r.LoadTarget(swizzledDTid, g_local.TargetDescHeapIdx);\n\n    SpatialResample(swizzledDTid, pos, normal, z_view, mr.y, surface, \n        g_local.CurrReservoir_A_DescHeapIdx, \n        g_local.CurrReservoir_A_DescHeapIdx + 1, \n        g_local.CurrReservoir_A_DescHeapIdx + 2, \n        g_local.Alpha_min, g_bvh, g_frame, r, rng);\n\n    {\n        float3 ld = r.target * r.W;\n        ld = any(isnan(ld)) ? 0 : ld;\n        RWTexture2D<float4> g_final = ResourceDescriptorHeap[g_local.FinalDescHeapIdx];\n\n        if(g_frame.Accumulate && g_frame.CameraStatic && g_frame.NumFramesCameraStatic > 1)\n        {\n            float3 prev = g_final[swizzledDTid].rgb;\n            g_final[swizzledDTid].rgb = prev + ld;\n        }\n        else\n            g_final[swizzledDTid].rgb = ld;\n    }\n}"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Sky/SkyDI_Temporal.hlsl",
    "content": "#include \"Resampling.hlsli\"\n\n#define THREAD_GROUP_SWIZZLING 1\n\nusing namespace SkyDI_Util;\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_SkyDI> g_local : register(b1);\nRaytracingAccelerationStructure g_bvh : register(t0);\nRaytracingAccelerationStructure g_bvh_prev : register(t1);\n\n//--------------------------------------------------------------------------------------\n// Helper functions\n//--------------------------------------------------------------------------------------\n\nReservoir RIS_InitialCandidates(uint2 DTid, float3 pos, float3 normal, \n    BSDF::ShadingData surface, inout RNG rng)\n{\n    Reservoir r = Reservoir::Init();\n    SkyIncidentRadiance leFunc = SkyIncidentRadiance::Init(g_frame.EnvMapDescHeapOffset);\n\n    // Sample sun\n#if 1\n    {\n        Light::SunSample sunSample = Light::SunSample::get(-g_frame.SunDir, \n            g_frame.SunCosAngularRadius, normal, surface, rng);\n        float3 wi_s = sunSample.wi;\n\n        float3 target = 0;\n        const bool trace = \n            // Sun below the horizon\n            (wi_s.y > 0) &&\n            // Sun hits the backside of non-transmissive surface\n            ((dot(wi_s, normal) > 0) || surface.Transmissive()) &&\n            // Make sure BSDF samples are within the valid range\n            (dot(wi_s, -g_frame.SunDir) >= g_frame.SunCosAngularRadius);\n\n        if(trace && (dot(sunSample.f, sunSample.f) > 0))\n        {\n            bool visible = RtRayQuery::Visibility_Ray(pos, wi_s, normal, g_bvh, surface.Transmissive());\n            if(visible)\n                target = Light::Le_Sun(pos, g_frame) * sunSample.f;\n        }\n\n        const float targetLum = Math::Luminance(target);\n#if 0\n        const float w_s = targetLum / sunSample.pdf;\n#else\n        float ndotwi = saturate(dot(wi_s, normal));\n        const float pdf_e = ndotwi * ONE_OVER_PI;\n        const float pdf_s = BSDF::BSDFSamplerPdf(normal, surface, wi_s, leFunc, rng);\n        const float w_s = RT::BalanceHeuristic3(1, pdf_e, pdf_s, targetLum);\n#endif\n        r.Update(w_s, wi_s, Light::TYPE::SUN, BSDF::LOBE::ALL, false, /*unused*/ 1, \n            target, rng);\n    }\n#endif\n\n    // MIS for sky -- take a light sample and a BSDF sample\n\n    // Since sky is low frequency, use cosine-weighted hemisphere sampling as \n    // a proxy for light sampling\n    const bool specular = surface.GlossSpecular() && (surface.metallic || surface.specTr) && \n        (!surface.Coated() || surface.CoatSpecular());\n\n    if(!specular)\n    {\n        const float2 u = rng.Uniform2D();\n        float pdf_e;\n        float3 wi_e = BSDF::SampleDiffuse(normal, u, pdf_e);\n        const float3 le = Light::Le_Sky(wi_e, g_frame.EnvMapDescHeapOffset);\n        surface.SetWi(wi_e, normal);\n\n        float3 target = le * BSDF::Unified(surface).f;\n        if(dot(target, target) > 0)\n            target *= RtRayQuery::Visibility_Ray(pos, wi_e, normal, g_bvh, surface.Transmissive());\n\n        // Balance Heuristic\n        const float targetLum = Math::Luminance(target);\n        const float pdf_b = BSDF::BSDFSamplerPdf(normal, surface, wi_e, leFunc, rng);\n        const float w_e = RT::BalanceHeuristic(pdf_e, pdf_b, targetLum);\n\n        r.Update(w_e, wi_e, Light::TYPE::SKY, BSDF::LOBE::ALL, false, /*unused*/ 1, \n            target, rng);\n    }\n\n    // Sample BSDF\n    {\n        BSDF::BSDFSample bsdfSample = BSDF::SampleBSDF(normal, surface, leFunc, rng);\n\n        float3 wi_b = bsdfSample.wi;\n        float pdf_b = bsdfSample.pdf;\n\n        float3 target = bsdfSample.f;\n        if(dot(target, target) > 0)\n            target *= RtRayQuery::Visibility_Ray(pos, wi_b, normal, g_bvh, surface.Transmissive());\n\n        // Balance Heuristic\n        const float targetLum = Math::Luminance(target);\n        float ndotwi = saturate(dot(wi_b, normal));\n        const float pdf_e = ndotwi * ONE_OVER_PI;\n        const float w_b = RT::BalanceHeuristic(pdf_b, pdf_e, targetLum);\n        // i.e. Glossy reflection or coat with lobe roughness below threshold\n        const bool useHalfVecShift = BSDF::LobeAlpha(surface, bsdfSample.lobe) <= g_local.Alpha_min;\n\n        r.Update(w_b, wi_b, surface.wo, normal, Light::TYPE::SKY, bsdfSample.lobe, \n            useHalfVecShift, target, rng);\n    }\n\n    float targetLum = Math::Luminance(r.target);\n    r.W = targetLum > 0.0 ? r.w_sum / targetLum : 0.0;\n\n    return r;\n}\n\nReservoir InitialCandidatesAndTemporalReuse(uint2 DTid, float3 pos, float3 normal, float z_view, \n    float roughness, BSDF::ShadingData surface, inout RNG rng)\n{\n    Reservoir r = RIS_InitialCandidates(DTid, pos, normal, surface, rng);\n\n    if (IS_CB_FLAG_SET(CB_SKY_DI_FLAGS::TEMPORAL_RESAMPLE)) \n    {\n        TemporalCandidate candidate = FindTemporalCandidate(DTid, pos, normal, z_view, \n            roughness, surface, g_frame);\n\n        if(candidate.valid)\n        {\n            TemporalResample(candidate, pos, normal, surface, \n                g_local.PrevReservoir_A_DescHeapIdx, \n                g_local.PrevReservoir_A_DescHeapIdx + 1,\n                g_local.PrevReservoir_A_DescHeapIdx + 2, \n                g_local.Alpha_min, g_bvh, g_bvh_prev, \n                g_frame, r, rng);\n        }\n\n        if(IS_CB_FLAG_SET(CB_SKY_DI_FLAGS::SPATIAL_RESAMPLE))\n            r.WriteTarget(DTid, g_local.TargetDescHeapIdx);\n    }\n\n    if (IS_CB_FLAG_SET(CB_SKY_DI_FLAGS::TEMPORAL_RESAMPLE) || \n        IS_CB_FLAG_SET(CB_SKY_DI_FLAGS::RESET_TEMPORAL_TEXTURES))\n    {\n        const uint M_max = r.lightType == Light::TYPE::SKY ? g_local.M_max & 0xffff : \n            g_local.M_max >> 16;\n        r.Write(DTid, g_local.CurrReservoir_A_DescHeapIdx,\n            g_local.CurrReservoir_A_DescHeapIdx + 1, \n            g_local.CurrReservoir_A_DescHeapIdx + 2,\n            M_max);\n    }\n\n    return r;\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(SKY_DI_GROUP_DIM_X, SKY_DI_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID)\n{\n#if THREAD_GROUP_SWIZZLING\n    uint16_t2 swizzledGid;\n\n    uint2 swizzledDTid = Common::SwizzleThreadGroup(DTid, Gid, GTid, \n        uint16_t2(SKY_DI_GROUP_DIM_X, SKY_DI_GROUP_DIM_Y),\n        g_local.DispatchDimX, \n        SKY_DI_TILE_WIDTH, \n        SKY_DI_LOG2_TILE_WIDTH, \n        g_local.NumGroupsInTile,\n        swizzledGid);\n#else\n    const uint2 swizzledDTid = DTid.xy;\n    const uint2 swizzledGid = Gid.xy;\n#endif\n\n    if (swizzledDTid.x >= g_frame.RenderWidth || swizzledDTid.y >= g_frame.RenderHeight)\n        return;\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr = g_metallicRoughness[swizzledDTid];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n\n    RWTexture2D<float4> g_final = ResourceDescriptorHeap[g_local.FinalDescHeapIdx];\n\n    if (flags.invalid)\n    {\n        if(g_frame.Accumulate && g_frame.CameraStatic)\n        {\n            float3 prev = g_final[swizzledDTid].rgb;\n            g_final[swizzledDTid].xyz = prev * (g_frame.NumFramesCameraStatic > 1) + \n                Light::Le_SkyWithSunDisk(swizzledDTid, g_frame);\n        }\n        else\n            g_final[swizzledDTid].xyz = 0;\n\n        return;\n    }\n\n    if(flags.emissive)\n    {\n        GBUFFER_EMISSIVE_COLOR g_emissiveColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::EMISSIVE_COLOR];\n        float3 le = g_emissiveColor[swizzledDTid].rgb;\n\n        RWTexture2D<float4> g_final = ResourceDescriptorHeap[g_local.FinalDescHeapIdx];\n\n        if(g_frame.Accumulate && g_frame.CameraStatic)\n        {\n            float3 prev = g_final[swizzledDTid].rgb;\n            g_final[swizzledDTid].rgb = prev + le;\n        }\n        else\n            g_final[swizzledDTid].rgb = le;\n\n        return;\n    }\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float z_view = g_depth[swizzledDTid];\n    \n    float2 lensSample = 0;\n    float3 origin = g_frame.CameraPos;\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(swizzledDTid.xyx).zy, g_frame.FrameNum);\n        lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample *= g_frame.LensRadius;\n    }\n\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float3 pos = Math::WorldPosFromScreenSpace2(swizzledDTid, renderDim, z_view, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n        g_frame.DoF, lensSample, g_frame.FocusDepth, origin);\n\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_normal[swizzledDTid]);\n\n    GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n    const float4 baseColor = flags.subsurface ? g_baseColor[swizzledDTid] :\n        float4(g_baseColor[swizzledDTid].rgb, 0);\n\n    float eta_curr = ETA_AIR;\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(flags.transmissive)\n    {\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        float ior = g_ior[swizzledDTid];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    float coat_weight = 0;\n    float3 coat_color = 0.0f;\n    float coat_roughness = 0;\n    float coat_ior = DEFAULT_ETA_COAT;\n\n    if(flags.coated)\n    {\n        GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::COAT];\n        uint3 packed = g_coat[swizzledDTid].xyz;\n\n        GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n        coat_weight = coat.weight;\n        coat_color = coat.color;\n        coat_roughness = coat.roughness;\n        coat_ior = coat.ior;\n    }\n\n    const float3 wo = normalize(origin - pos);\n    BSDF::ShadingData surface = BSDF::ShadingData::Init(normal, wo, flags.metallic, mr.y, \n        baseColor.xyz, eta_curr, eta_next, flags.transmissive, flags.trDepthGt0, (half)baseColor.w,\n        coat_weight, coat_color, coat_roughness, coat_ior);\n\n    RNG rng = RNG::Init(RNG::PCG3d(swizzledDTid.yxx).yz, g_frame.FrameNum);\n\n    SkyDI_Util::Reservoir r = InitialCandidatesAndTemporalReuse(swizzledDTid, pos, normal, \n        z_view, mr.y, surface, rng);\n\n    if(!IS_CB_FLAG_SET(CB_SKY_DI_FLAGS::SPATIAL_RESAMPLE) || !IS_CB_FLAG_SET(CB_SKY_DI_FLAGS::TEMPORAL_RESAMPLE))\n    {\n        float3 ld = r.target * r.W;\n        ld = any(isnan(ld)) ? 0 : ld;\n\n        if(g_frame.Accumulate && g_frame.CameraStatic && g_frame.NumFramesCameraStatic > 1)\n        {\n            float3 prev = g_final[swizzledDTid].rgb;\n            g_final[swizzledDTid].rgb = prev + ld;\n        }\n        else\n            g_final[swizzledDTid].rgb = ld;\n    }\n}"
  },
  {
    "path": "Source/ZetaRenderPass/DirectLighting/Sky/Util.hlsli",
    "content": "#ifndef SKY_DI_UTIL_H\n#define SKY_DI_UTIL_H\n\n#include \"../../Common/LightSource.hlsli\"\n\nnamespace SkyDI_Util\n{\n    struct SkyIncidentRadiance \n    {\n        static SkyIncidentRadiance Init(uint descHeapOffset)\n        {\n            SkyIncidentRadiance ret;\n            ret.skyViewDescHeapOffset = descHeapOffset;\n            return ret;\n        }\n\n        float3 operator()(float3 w)\n        {\n            return Light::Le_Sky(w, skyViewDescHeapOffset);\n        }\n\n        uint skyViewDescHeapOffset;\n    };\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/Display/CMakeLists.txt",
    "content": "set(RP_DISPLAY_DIR ${ZETA_RENDER_PASS_DIR}/Display)\nset(RP_DISPLAY_SRC\n    ${RP_DISPLAY_DIR}/Display.cpp\n    ${RP_DISPLAY_DIR}/Display.h\n    ${RP_DISPLAY_DIR}/Display.hlsl\n    ${RP_DISPLAY_DIR}/Tonemap.hlsli\n    ${RP_DISPLAY_DIR}/Display_Common.h)\n\nset(RP_DISPLAY_SRC ${RP_DISPLAY_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaRenderPass/Display/Display.cpp",
    "content": "#include \"Display.h\"\n#include <Core/CommandList.h>\n#include <Core/RenderGraph.h>\n#include <Scene/SceneCore.h>\n#include <Scene/Camera.h>\n#include <Support/Param.h>\n#include <Support/Task.h>\n#include <Math/MatrixFuncs.h>\n#include <App/Log.h>\n#include \"../Assets/Font/IconsFontAwesome6.h\"\n\n#if defined(__clang__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wmissing-field-initializers\"\n#endif\n#define STB_IMAGE_WRITE_IMPLEMENTATION\n#include <stb/stb_image_write.h>\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Core::Direct3DUtil;\n\n//--------------------------------------------------------------------------------------\n// DisplayPass\n//--------------------------------------------------------------------------------------\n\nDisplayPass::DisplayPass()\n    : RenderPassBase(NUM_CBV, NUM_SRV, NUM_UAV, NUM_GLOBS, NUM_CONSTS)\n{\n    // frame constants\n    m_rootSig.InitAsCBV(0, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::FRAME_CONSTANTS_BUFFER);\n\n    // root constants\n    m_rootSig.InitAsConstants(1, NUM_CONSTS, 1);\n}\n\nvoid DisplayPass::InitPSOs()\n{\n    constexpr D3D12_ROOT_SIGNATURE_FLAGS flags =\n        D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |\n        D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;\n\n    auto& renderer = App::GetRenderer();\n    auto samplers = renderer.GetStaticSamplers();\n    RenderPassBase::InitRenderPass(\"Display\", flags, samplers);\n    CreatePSOs();\n}\n\nvoid DisplayPass::Init()\n{\n    InitPSOs();\n\n    memset(&m_cbLocal, 0, sizeof(m_cbLocal));\n    m_cbLocal.DisplayOption = (uint16_t)DisplayOption::DEFAULT;\n    m_cbLocal.Tonemapper = (uint16_t)Tonemapper::NEUTRAL;\n    m_cbLocal.Saturation = 1.0f;\n    m_cbLocal.AgXExp = 1.0f;\n    m_cbLocal.RoughnessTh = 1.0f;\n    m_cbLocal.AutoExposure = true;\n\n    ParamVariant p1;\n    p1.InitEnum(ICON_FA_FILM \" Renderer\", \"Display\", \"Output\", \n        fastdelegate::MakeDelegate(this, &DisplayPass::DisplayOptionCallback),\n        Params::DisplayOptions, ZetaArrayLen(Params::DisplayOptions), m_cbLocal.DisplayOption);\n    App::AddParam(p1);\n\n    ParamVariant p2;\n    p2.InitEnum(ICON_FA_FILM \" Renderer\", \"Display\", \"View Transform\", \n        fastdelegate::MakeDelegate(this, &DisplayPass::TonemapperCallback),\n        Params::Tonemappers, ZetaArrayLen(Params::Tonemappers), m_cbLocal.Tonemapper);\n    App::AddParam(p2);\n\n    ParamVariant p3;\n    p3.InitBool(ICON_FA_FILM \" Renderer\", \"Auto Exposure\", \"Enable\", \n        fastdelegate::MakeDelegate(this, &DisplayPass::AutoExposureCallback),\n        m_cbLocal.AutoExposure);\n    App::AddParam(p3);\n\n    if (m_cbLocal.Tonemapper != (uint16_t)Tonemapper::AgX_DEFAULT &&\n        m_cbLocal.Tonemapper != (uint16_t)Tonemapper::AgX_GOLDEN &&\n        m_cbLocal.Tonemapper != (uint16_t)Tonemapper::AgX_PUNCHY)\n    {\n        ParamVariant p7;\n        p7.InitFloat(ICON_FA_FILM \" Renderer\", \"Display\", \"Saturation\", \n            fastdelegate::MakeDelegate(this, &DisplayPass::SaturationCallback), \n            1, 0.5, 1.5f, 1e-2f);\n        App::AddParam(p7);\n    }\n\n    if (m_cbLocal.Tonemapper == (uint16_t)Tonemapper::AgX_CUSTOM)\n    {\n        ParamVariant p4;\n        p4.InitFloat(ICON_FA_FILM \" Renderer\", \"Display\", \"Exponent\",\n            fastdelegate::MakeDelegate(this, &DisplayPass::AgxExpCallback),\n            1, 0.0, 5.0f, 1e-2f);\n        App::AddParam(p4);\n    }\n\n    App::Filesystem::Path p(App::GetAssetDir());\n    p.Append(\"LUT\\\\tony_mc_mapface.dds\");\n    auto err = GpuMemory::GetTexture3DFromDisk(p.Get(), m_lut);\n    Check(err == LOAD_DDS_RESULT::SUCCESS, \"Error loading DDS texture from path %s: %d\", \n        p.Get(), err);\n\n    auto& renderer = App::GetRenderer();\n    m_descTable = renderer.GetGpuDescriptorHeap().Allocate(DESC_TABLE::COUNT);\n    Direct3DUtil::CreateTexture3DSRV(m_lut, m_descTable.CPUHandle(DESC_TABLE::TONEMAPPER_LUT_SRV));\n\n    D3D12_CLEAR_VALUE clearVal;\n    clearVal.Format = DXGI_FORMAT_R8_UNORM;\n    clearVal.Color[0] = 0;\n    clearVal.Color[1] = 0;\n    clearVal.Color[2] = 0;\n    clearVal.Color[3] = 0;\n    m_pickMask = GpuMemory::GetTexture2D(\"PickMask\", renderer.GetRenderWidth(), renderer.GetRenderHeight(),\n        DXGI_FORMAT_R8_UNORM, D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE, \n        TEXTURE_FLAGS::ALLOW_RENDER_TARGET, 1, &clearVal);\n    m_rtvDescTable = renderer.GetRtvDescriptorHeap().Allocate(1);\n    Direct3DUtil::CreateRTV(m_pickMask, m_rtvDescTable.CPUHandle(0));\n    Direct3DUtil::CreateTexture2DSRV(m_pickMask, m_descTable.CPUHandle(DESC_TABLE::PICK_MASK_SRV));\n}\n\nvoid DisplayPass::SetPickData(const Core::RenderNodeHandle& producerHandle,\n    Core::GpuMemory::ReadbackHeapBuffer* readback,\n    fastdelegate::FastDelegate0<> dlg)\n{\n    Assert(producerHandle.IsValid(), \"Invalid handle.\");\n    Assert(readback, \"Readback buffer was NULL.\");\n    m_producerHandle = producerHandle.Val;\n    m_readback = readback;\n    m_pickDlg = dlg;\n}\n\nvoid DisplayPass::ClearPick()\n{\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Display\", \"Wireframe\");\n}\n\nvoid DisplayPass::CaptureScreen()\n{\n    Assert(!m_captureScreen, \"Duplicate call.\");\n\n    auto& renderer = App::GetRenderer();\n    auto* device = renderer.GetDevice();\n    auto& backBuffer = renderer.GetCurrentBackBuffer();\n    auto desc = backBuffer.Desc();\n\n    UINT64 totalResourceSize = 0;\n    UINT64 rowSizeInBytes = 0;\n    UINT rowCount = 0;\n    device->GetCopyableFootprints(&desc, 0, 1, 0, nullptr,\n        &rowCount, &rowSizeInBytes, &totalResourceSize);\n\n    // From MS docs: \"... a Texture2D resource has a width of 32 and bytes per pixel of 4,\n    // then pRowSizeInBytes returns 128. pRowSizeInBytes should not be confused with row pitch, \n    // as examining pLayouts and getting the row pitch from that will give you 256 as it is \n    // aligned to D3D12_TEXTURE_DATA_PITCH_ALIGNMENT.\"\n    const uint32_t rowPitch = (uint32_t)Math::AlignUp(rowSizeInBytes, \n        (uint64_t)D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);\n    const uint32_t sizeInBytes = rowPitch * desc.Height;\n    m_screenCaptureReadback = GpuMemory::GetReadbackHeapBuffer(sizeInBytes);\n\n    m_backBufferFoorprint.Format = desc.Format;\n    m_backBufferFoorprint.Width = (UINT)desc.Width;\n    m_backBufferFoorprint.Height = (UINT)desc.Height;\n    m_backBufferFoorprint.Depth = 1;\n    m_backBufferFoorprint.RowPitch = rowPitch;\n\n    m_captureScreen = true;\n}\n\nvoid DisplayPass::Render(CommandList& cmdList)\n{\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT, \"Invalid downcast\");\n    GraphicsCmdList& directCmdList = static_cast<GraphicsCmdList&>(cmdList);\n\n    Assert(m_compositedSrvDescHeapIdx != UINT32_MAX, \"Gpu Desc Idx hasn't been set.\");\n    Assert(m_cbLocal.ExposureDescHeapIdx > 0, \"Gpu Desc Idx hasn't been set.\");\n\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n    auto& scene = App::GetScene();\n\n    directCmdList.PIXBeginEvent(\"Display\");\n    const uint32_t queryIdx = gpuTimer.BeginQuery(directCmdList, \"Display\");\n\n    directCmdList.SetRootSignature(m_rootSig, m_rootSigObj.Get());\n    directCmdList.SetPipelineState(m_psoLib.GetPSO((int)DISPLAY_SHADER::DISPLAY));\n\n    m_cbLocal.LUTDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE::TONEMAPPER_LUT_SRV);\n    m_cbLocal.InputDescHeapIdx = m_compositedSrvDescHeapIdx;\n    m_rootSig.SetRootConstants(0, sizeof(cbDisplayPass) / sizeof(DWORD), &m_cbLocal);\n    m_rootSig.End(directCmdList);\n\n    if (RenderNodeHandle(m_producerHandle).IsValid())\n    {\n        const uint64_t fence = scene.GetRenderGraph()->GetCompletionFence(\n            RenderNodeHandle(m_producerHandle));\n        Assert(fence != UINT64_MAX, \"Invalid fence value.\");\n\n        // Wait on a background thread for GPU to finish copying to readback buffer\n        Task t(\"WaitForGBuffer\", TASK_PRIORITY::BACKGROUND, [this, fence]()\n            {\n                //HANDLE fenceEvent = CreateEventA(nullptr, false, false, nullptr);\n                //CheckWin32(fenceEvent);\n\n                App::GetRenderer().WaitForDirectQueueFenceCPU(fence);\n                //App::GetRenderer().WaitForDirectQueueFenceCPU(fence, fenceEvent);\n                //CloseHandle(fenceEvent);\n\n                ReadbackPickIdx();\n            });\n\n        App::SubmitBackground(ZetaMove(t));\n\n        m_producerHandle = RenderNodeHandle::INVALID_HANDLE;\n        m_pickDlg();\n    }\n\n    D3D12_VIEWPORT viewports[1] = { renderer.GetDisplayViewport() };\n    D3D12_RECT scissors[1] = { renderer.GetDisplayScissor() };\n    directCmdList.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);\n    directCmdList.RSSetViewportsScissorsRects(1, viewports, scissors);\n    Assert(m_cpuDescs[(int)SHADER_IN_CPU_DESC::RTV].ptr > 0, \"RTV hasn't been set.\");\n    directCmdList.OMSetRenderTargets(1, &m_cpuDescs[(int)SHADER_IN_CPU_DESC::RTV], true, nullptr);\n    directCmdList.DrawInstanced(3, 1, 0, 0);\n\n    if (auto picks = scene.GetPickedInstances().m_span; !picks.empty())\n        DrawPicked(directCmdList, picks);\n\n    if (m_captureScreen)\n    {\n        ID3D12Resource* backbuffer = const_cast<Texture&>(renderer.GetCurrentBackBuffer()).Resource();\n        directCmdList.ResourceBarrier(backbuffer,\n            D3D12_RESOURCE_STATE_RENDER_TARGET,\n            D3D12_RESOURCE_STATE_COPY_SOURCE);\n\n        D3D12_TEXTURE_COPY_LOCATION srcLocation = {};\n        srcLocation.pResource = backbuffer;\n        srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;\n        srcLocation.SubresourceIndex = 0;\n\n        D3D12_TEXTURE_COPY_LOCATION dstLocation = {};\n        dstLocation.pResource = m_screenCaptureReadback.Resource();\n        dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;\n        dstLocation.PlacedFootprint.Footprint = m_backBufferFoorprint;\n\n        // Copy the texture\n        directCmdList.CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, nullptr);\n\n        directCmdList.ResourceBarrier(backbuffer,\n            D3D12_RESOURCE_STATE_COPY_SOURCE,\n            D3D12_RESOURCE_STATE_RENDER_TARGET);\n\n        // Wait on a background thread for GPU to finish copying to readback buffer\n        Task t(\"WaitForCapture\", TASK_PRIORITY::BACKGROUND, [this]()\n            {\n                WaitObject waitObj;\n                App::GetScene().GetRenderGraph()->SetFrameSubmissionWaitObj(waitObj);\n                waitObj.Wait();\n\n                const uint64_t fence = App::GetScene().GetRenderGraph()->GetFrameCompletionFence();\n                Assert(fence != UINT64_MAX, \"Invalid fence value.\");\n\n                App::GetRenderer().WaitForDirectQueueFenceCPU(fence);\n                ReadbackScreenCapture();\n            });\n\n        App::SubmitBackground(ZetaMove(t));\n\n        m_captureScreen = false;\n    }\n\n    gpuTimer.EndQuery(directCmdList, queryIdx);\n    directCmdList.PIXEndEvent();\n}\n\nvoid DisplayPass::DrawPicked(GraphicsCmdList& cmdList, Span<uint64_t> picks)\n{\n    Assert(!picks.empty(), \"Invalid argument.\");\n    const auto& camera = App::GetCamera();\n    auto& frustum = camera.GetCameraFrustumViewSpace();\n    auto viewInv = camera.GetViewInv();\n\n    // Transform view frustum from view space into world space\n    v_float4x4 vM = load4x4(const_cast<float4x4a&>(viewInv));\n    v_ViewFrustum vFrustum(const_cast<ViewFrustum&>(frustum));\n    vFrustum = transform(vM, vFrustum);\n\n    for (auto ID : picks)\n    {\n        v_AABB vBox(App::GetScene().GetAABB(ID));\n        v_float4x4 vW = load4x3(App::GetScene().GetToWorld(ID));\n        vBox = transform(vW, vBox);\n\n        // Skip if outside the view frustum\n        if (instersectFrustumVsAABB(vFrustum, vBox) == COLLISION_TYPE::DISJOINT)\n            continue;\n\n        // Draw mask\n        {\n            auto& scene = App::GetScene();\n            auto meshID = scene.GetInstanceMeshID(ID);\n            auto* mesh = scene.GetMesh(meshID).value();\n            float4x3 toWorld = scene.GetToWorld(ID);\n\n            const Camera& cam = App::GetCamera();\n            v_float4x4 vView = load4x4(const_cast<float4x4a&>(cam.GetCurrView()));\n            v_float4x4 vProj = load4x4(const_cast<float4x4a&>(cam.GetProj()));\n            v_float4x4 vVP = mul(vView, vProj);\n            v_float4x4 vW2 = load4x3(toWorld);\n            v_float4x4 vWVP = mul(vW2, vVP);\n            float4x4a wvp = store(vWVP);\n\n            cbDrawPicked cb;\n            cb.row0 = wvp.m[0];\n            cb.row1 = wvp.m[1];\n            cb.row2 = wvp.m[2];\n            cb.row3 = wvp.m[3];\n\n            const Buffer& sceneVB = App::GetScene().GetMeshVB();\n            const Buffer& sceneIB = App::GetScene().GetMeshIB();\n\n            D3D12_VERTEX_BUFFER_VIEW vbv;\n            vbv.StrideInBytes = sizeof(Vertex);\n            vbv.BufferLocation = sceneVB.GpuVA() + mesh->m_vtxBuffStartOffset * sizeof(Vertex);\n            vbv.SizeInBytes = mesh->m_numVertices * sizeof(Vertex);\n\n            D3D12_INDEX_BUFFER_VIEW ibv;\n            ibv.Format = DXGI_FORMAT_R32_UINT;\n            ibv.BufferLocation = sceneIB.GpuVA() + mesh->m_idxBuffStartOffset * sizeof(uint32);\n            ibv.SizeInBytes = mesh->m_numIndices * sizeof(uint32);\n\n            auto layoutToRT = TextureBarrier(m_pickMask.Resource(),\n                D3D12_BARRIER_SYNC_NONE,\n                D3D12_BARRIER_SYNC_DRAW,\n                D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE,\n                D3D12_BARRIER_LAYOUT_RENDER_TARGET,\n                D3D12_BARRIER_ACCESS_NO_ACCESS,\n                D3D12_BARRIER_ACCESS_RENDER_TARGET);\n            cmdList.ResourceBarrier(layoutToRT);\n\n            auto* pso = m_wireframe ? m_psoLib.GetPSO((int)DISPLAY_SHADER::DRAW_PICKED_WIREFRAME) :\n                m_psoLib.GetPSO((int)DISPLAY_SHADER::DRAW_PICKED);\n            cmdList.SetPipelineState(pso);\n            cmdList.IASetVertexAndIndexBuffers(vbv, ibv);\n            auto cpuHandle = m_rtvDescTable.CPUHandle(0);\n            cmdList.OMSetRenderTargets(1, &cpuHandle, true, nullptr);\n\n            cmdList.ClearRenderTargetView(cpuHandle, 0, 0, 0, 0);\n\n            m_rootSig.SetRootConstants(0, sizeof(cbDrawPicked) / sizeof(uint32), &cb);\n            m_rootSig.End(cmdList);\n\n            cmdList.DrawIndexedInstanced(mesh->m_numIndices,\n                1,\n                0,\n                0,\n                0);\n        }\n\n        // Sobel\n        {\n            cmdList.SetPipelineState(m_psoLib.GetPSO((int)DISPLAY_SHADER::SOBEL));\n            cmdList.OMSetRenderTargets(1, &m_cpuDescs[(int)SHADER_IN_CPU_DESC::RTV], true, nullptr);\n\n            auto syncDrawAndLayoutToRead = TextureBarrier(m_pickMask.Resource(),\n                D3D12_BARRIER_SYNC_DRAW,\n                D3D12_BARRIER_SYNC_PIXEL_SHADING,\n                D3D12_BARRIER_LAYOUT_RENDER_TARGET,\n                D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE,\n                D3D12_BARRIER_ACCESS_RENDER_TARGET,\n                D3D12_BARRIER_ACCESS_SHADER_RESOURCE);\n            cmdList.ResourceBarrier(syncDrawAndLayoutToRead);\n\n            cbSobel cb;\n            cb.MaskDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE::PICK_MASK_SRV);\n            cb.Wireframe = m_wireframe;\n\n            m_rootSig.SetRootConstants(0, sizeof(cbSobel) / sizeof(uint32), &cb);\n            m_rootSig.End(cmdList);\n\n            cmdList.DrawInstanced(3, 1, 0, 0);\n        }\n    }\n}\n\nvoid DisplayPass::CreatePSOs()\n{\n    // Display\n    {\n        DXGI_FORMAT rtvFormats[1] = { Constants::BACK_BUFFER_FORMAT };\n        D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = Direct3DUtil::GetPSODesc(nullptr,\n            1, rtvFormats);\n\n        // no blending required\n\n        // disable depth testing and writing\n        psoDesc.DepthStencilState.DepthEnable = false;\n        psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;\n        psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;\n\n        // disable triangle culling\n        psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;\n\n        m_psoLib.CompileGraphicsPSO((int)DISPLAY_SHADER::DISPLAY,\n            psoDesc,\n            m_rootSigObj.Get(),\n            COMPILED_VS[(int)DISPLAY_SHADER::DISPLAY],\n            COMPILED_PS[(int)DISPLAY_SHADER::DISPLAY]);\n    }\n\n    // Draw mask\n    {\n        D3D12_INPUT_ELEMENT_DESC inputElements[] =\n        {\n            { \"POSITION\", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, \n                D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n            { \"TEXUV\", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, \n                D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n            { \"NORMAL\", 0, DXGI_FORMAT_R16G16_SINT, 0, D3D12_APPEND_ALIGNED_ELEMENT, \n                D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n            { \"TANGENT\", 0, DXGI_FORMAT_R16G16_SINT, 0, D3D12_APPEND_ALIGNED_ELEMENT, \n                D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }\n        };\n\n        D3D12_INPUT_LAYOUT_DESC inputLayout = D3D12_INPUT_LAYOUT_DESC{ .pInputElementDescs = inputElements, \n            .NumElements = ZetaArrayLen(inputElements) };\n\n        DXGI_FORMAT rtvFormats[1] = { DXGI_FORMAT_R8_UNORM };\n        D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = Direct3DUtil::GetPSODesc(&inputLayout,\n            1, rtvFormats);\n\n        // disable triangle culling\n        psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;\n\n        // disable depth testing and writing\n        psoDesc.DepthStencilState.DepthEnable = false;\n        psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;\n        psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;\n\n        m_psoLib.CompileGraphicsPSO((int)DISPLAY_SHADER::DRAW_PICKED,\n            psoDesc,\n            m_rootSigObj.Get(),\n            COMPILED_VS[(int)DISPLAY_SHADER::DRAW_PICKED],\n            COMPILED_PS[(int)DISPLAY_SHADER::DRAW_PICKED]);\n\n        psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;\n\n        m_psoLib.CompileGraphicsPSO((int)DISPLAY_SHADER::DRAW_PICKED_WIREFRAME,\n            psoDesc,\n            m_rootSigObj.Get(),\n            COMPILED_VS[(int)DISPLAY_SHADER::DRAW_PICKED],\n            COMPILED_PS[(int)DISPLAY_SHADER::DRAW_PICKED]);\n    }\n\n    // Sobel\n    {\n        DXGI_FORMAT rtvFormats[1] = { Constants::BACK_BUFFER_FORMAT };\n        D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = Direct3DUtil::GetPSODesc(nullptr,\n            1, rtvFormats);\n\n        // disable depth testing and writing\n        psoDesc.DepthStencilState.DepthEnable = false;\n        psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;\n        psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;\n\n        // disable triangle culling\n        psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;\n\n        m_psoLib.CompileGraphicsPSO((int)DISPLAY_SHADER::SOBEL,\n            psoDesc,\n            m_rootSigObj.Get(),\n            COMPILED_VS[(int)DISPLAY_SHADER::SOBEL],\n            COMPILED_PS[(int)DISPLAY_SHADER::SOBEL]);\n    }\n}\n\nvoid DisplayPass::ReadbackPickIdx()\n{\n    Assert(m_readback, \"Readback buffer hasn't been set.\");\n    auto& scene = App::GetScene();\n    auto pickWasDisabled = scene.GetPickedInstances().m_span.empty();\n    m_readback->Map();\n\n    uint32* data = reinterpret_cast<uint32*>(m_readback->MappedMemory());\n    uint32 rtMeshIdx;\n    memcpy(&rtMeshIdx, data, sizeof(uint32));\n\n    m_readback->Unmap();\n    m_readback = nullptr;\n\n    if (rtMeshIdx == UINT32_MAX)\n        return;\n\n    auto id = scene.GetIDFromRtMeshIdx(rtMeshIdx);\n    scene.SetPickedInstance(id);\n\n    if (pickWasDisabled)\n    {\n        ParamVariant p;\n        p.InitBool(ICON_FA_FILM \" Renderer\", \"Display\", \"Wireframe\",\n            fastdelegate::MakeDelegate(this, &DisplayPass::WireframeCallback),\n            m_wireframe);\n        App::AddParam(p);\n    }\n}\n\nvoid DisplayPass::ReadbackScreenCapture()\n{\n    Assert(m_screenCaptureReadback.IsInitialized(), \"Readback buffer hasn't been initialized.\");\n\n    m_screenCaptureReadback.Map();\n    uint32_t* data = reinterpret_cast<uint32_t*>(m_screenCaptureReadback.MappedMemory());\n\n    SYSTEMTIME st;\n    GetLocalTime(&st);\n    StackStr(currTime, N1, \"%u_%u_%u_%u_%u_%u\", st.wYear, st.wMonth, st.wDay, \n        st.wHour, st.wMinute, st.wSecond);\n\n    uint32_t hash = Util::XXH3_64_To_32(XXH3_64bits(currTime, N1));\n    StackStr(filename, N2, \"capture_%u.png\", hash);\n\n    int res = stbi_write_png(filename, m_backBufferFoorprint.Width, m_backBufferFoorprint.Height,\n        4, data, m_backBufferFoorprint.RowPitch);\n    Check(res != 0, \"stbi_write_png() failed.\");\n\n    m_screenCaptureReadback.Unmap();\n    m_screenCaptureReadback.Reset(false);\n\n    LOG_UI_INFO(\"Screenshot saved to: %s.\\n\", filename);\n}\n\nvoid DisplayPass::DisplayOptionCallback(const ParamVariant& p)\n{\n    m_cbLocal.DisplayOption = (uint16_t)p.GetEnum().m_curr;\n\n    if (m_cbLocal.DisplayOption == (uint32)DisplayOption::ROUGHNESS_TH)\n    {\n        ParamVariant p1;\n        p1.InitFloat(ICON_FA_FILM \" Renderer\", \"Display\", \"Roughness (Th)\",\n            fastdelegate::MakeDelegate(this, &DisplayPass::RoughnessThCallback),\n            1, 0.0, 1.0f, 1e-2f);\n        App::AddParam(p1);\n    }\n    else\n        App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Display\", \"Roughness (Th)\");\n}\n\nvoid DisplayPass::TonemapperCallback(const Support::ParamVariant& p)\n{\n    m_cbLocal.Tonemapper = (uint16_t)p.GetEnum().m_curr;\n\n    if (m_cbLocal.Tonemapper == (uint16_t)Tonemapper::AgX_CUSTOM)\n    {\n        ParamVariant p1;\n        p1.InitFloat(ICON_FA_FILM \" Renderer\", \"Display\", \"Exponent\",\n            fastdelegate::MakeDelegate(this, &DisplayPass::AgxExpCallback),\n            1, 0.0, 5.0f, 1e-2f);\n        App::AddParam(p1);\n    }\n    else\n        App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Display\", \"Exponent\");\n\n    if (m_cbLocal.Tonemapper == (uint16_t)Tonemapper::AgX_DEFAULT ||\n        m_cbLocal.Tonemapper == (uint16_t)Tonemapper::AgX_GOLDEN ||\n        m_cbLocal.Tonemapper == (uint16_t)Tonemapper::AgX_PUNCHY)\n    {\n        App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Display\", \"Saturation\");\n    }\n    else\n    {\n        ParamVariant p2;\n        p2.InitFloat(ICON_FA_FILM \" Renderer\", \"Display\", \"Saturation\",\n            fastdelegate::MakeDelegate(this, &DisplayPass::SaturationCallback),\n            1, 0.5, 1.5f, 1e-2f);\n        App::TryAddParam(p2);\n    }\n}\n\nvoid DisplayPass::SaturationCallback(const Support::ParamVariant& p)\n{\n    m_cbLocal.Saturation = p.GetFloat().m_value;\n}\n\nvoid DisplayPass::AgxExpCallback(const Support::ParamVariant& p)\n{\n    m_cbLocal.AgXExp = p.GetFloat().m_value;\n}\n\nvoid DisplayPass::AutoExposureCallback(const Support::ParamVariant& p)\n{\n    m_cbLocal.AutoExposure = p.GetBool();\n}\n\nvoid DisplayPass::RoughnessThCallback(const Support::ParamVariant& p)\n{\n    m_cbLocal.RoughnessTh = p.GetFloat().m_value;\n}\n\nvoid DisplayPass::WireframeCallback(const Support::ParamVariant& p)\n{\n    m_wireframe = p.GetBool();\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/Display/Display.h",
    "content": "#pragma once\n\n#include \"../RenderPass.h\"\n#include <Core/GpuMemory.h>\n#include <Scene/SceneCommon.h>\n#include \"Display_Common.h\"\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n    class GraphicsCmdList;\n    struct RenderNodeHandle;\n}\n\nnamespace ZetaRay::Core::GpuMemory\n{\n    struct ReadbackHeapBuffer;\n}\n\nnamespace ZetaRay::Support\n{\n    struct ParamVariant;\n}\n\nnamespace ZetaRay::RenderPass\n{\n    enum class DISPLAY_SHADER\n    {\n        DISPLAY,\n        DRAW_PICKED,\n        DRAW_PICKED_WIREFRAME,\n        SOBEL,\n        COUNT\n    };\n\n    struct DisplayPass final : public RenderPassBase<(int)DISPLAY_SHADER::COUNT>\n    {\n        enum class SHADER_IN_CPU_DESC\n        {\n            RTV,\n            COUNT\n        };\n\n        enum class SHADER_IN_GPU_DESC\n        {\n            COMPOSITED,\n            EXPOSURE,\n            COUNT\n        };\n\n        DisplayPass();\n        ~DisplayPass() = default;\n\n        void InitPSOs();\n        void Init();\n        void SetCpuDescriptor(SHADER_IN_CPU_DESC i, D3D12_CPU_DESCRIPTOR_HANDLE h)\n        {\n            Assert((int)i < (int)SHADER_IN_CPU_DESC::COUNT, \"out-of-bound access.\");\n            m_cpuDescs[(int)i] = h;\n        }\n        void SetGpuDescriptor(SHADER_IN_GPU_DESC i, uint32_t dechHeapIdx)\n        {\n            Assert((int)i < (int)SHADER_IN_GPU_DESC::COUNT, \"out-of-bound access.\");\n            switch (i)\n            {\n            case SHADER_IN_GPU_DESC::COMPOSITED:\n                m_compositedSrvDescHeapIdx = dechHeapIdx;\n                break;\n            case SHADER_IN_GPU_DESC::EXPOSURE:\n                m_cbLocal.ExposureDescHeapIdx = dechHeapIdx;\n                break;\n            default:\n                break;\n            }\n        }\n        void SetPickData(const Core::RenderNodeHandle& producerHandle, \n            Core::GpuMemory::ReadbackHeapBuffer* readback,\n            fastdelegate::FastDelegate0<> dlg);\n        void ClearPick();\n        void CaptureScreen();\n        void Render(Core::CommandList& cmdList);\n\n    private:\n        static constexpr int NUM_CBV = 1;\n        static constexpr int NUM_SRV = 0;\n        static constexpr int NUM_UAV = 0;\n        static constexpr int NUM_GLOBS = 1;\n        static constexpr int NUM_CONSTS = (int)Math::Max((sizeof(cbDisplayPass) / sizeof(DWORD)),\n            sizeof(cbDrawPicked) / sizeof(DWORD));\n\n        enum DESC_TABLE\n        {\n            TONEMAPPER_LUT_SRV,\n            PICK_MASK_SRV,\n            COUNT\n        };\n\n        struct Params\n        {\n            inline static const char* DisplayOptions[] = { \"Default\", \"BaseColor\", \"Normal\",\n                \"Metalness-Roughness\", \"Coat (Weight)\", \"Coat (Color)\", \"Roughness (Threshold)\", \n                \"Emission\", \"Transmission\", \"Depth\" };\n            static_assert((int)DisplayOption::COUNT == ZetaArrayLen(DisplayOptions), \"enum <-> strings mismatch.\");\n\n            inline static const char* Tonemappers[] = { \"None\", \"Neutral\", \"AgX (Default)\", \"AgX (Golden)\", \n                \"AgX (Punchy)\", \"AgX (Custom)\" };\n            static_assert((int)Tonemapper::COUNT == ZetaArrayLen(Tonemappers), \"enum <-> strings mismatch.\");\n        };\n\n        inline static constexpr const char* COMPILED_VS[(int)DISPLAY_SHADER::COUNT] = { \n            \"Display_vs.cso\",\n            \"DrawPicked_vs.cso\",\n            \"DrawPicked_vs.cso\",\n            \"Sobel_vs.cso\"\n        };\n        inline static constexpr const char* COMPILED_PS[(int)DISPLAY_SHADER::COUNT] = { \n            \"Display_ps.cso\" ,\n            \"DrawPicked_ps.cso\", \n            \"DrawPicked_ps.cso\", \n            \"Sobel_ps.cso\" \n        };\n\n        void DrawPicked(Core::GraphicsCmdList& cmdList, Util::Span<uint64_t> picks);\n        void CreatePSOs();\n        void ReadbackPickIdx();\n        void ReadbackScreenCapture();\n\n        // parameter callbacks\n        void DisplayOptionCallback(const Support::ParamVariant& p);\n        void TonemapperCallback(const Support::ParamVariant& p);\n        void SaturationCallback(const Support::ParamVariant& p);\n        void AgxExpCallback(const Support::ParamVariant& p);\n        void AutoExposureCallback(const Support::ParamVariant& p);\n        void RoughnessThCallback(const Support::ParamVariant& p);\n        void WireframeCallback(const Support::ParamVariant& p);\n\n        Core::GpuMemory::Texture m_lut;\n        Core::DescriptorTable m_descTable;\n        D3D12_CPU_DESCRIPTOR_HANDLE m_cpuDescs[(int)SHADER_IN_CPU_DESC::COUNT] = { 0 };\n        cbDisplayPass m_cbLocal;\n        uint32_t m_compositedSrvDescHeapIdx = UINT32_MAX;\n        Core::DescriptorTable m_rtvDescTable;\n        // Picking data\n        int m_producerHandle = -1;\n        Core::GpuMemory::ReadbackHeapBuffer* m_readback = nullptr;\n        fastdelegate::FastDelegate0<> m_pickDlg;\n        Core::GpuMemory::Texture m_pickMask;\n        bool m_wireframe = false;\n        // Screen capture data\n        Core::GpuMemory::ReadbackHeapBuffer m_screenCaptureReadback;\n        D3D12_SUBRESOURCE_FOOTPRINT m_backBufferFoorprint;\n        bool m_captureScreen = false;\n    };\n}"
  },
  {
    "path": "Source/ZetaRenderPass/Display/Display.hlsl",
    "content": "#include \"Display_Common.h\"\n#include \"Tonemap.hlsli\"\n#include \"../Common/Math.hlsli\"\n#include \"../Common/FrameConstants.h\"\n#include \"../Common/GBuffers.hlsli\"\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cbDisplayPass> g_local : register(b1);\n\n//--------------------------------------------------------------------------------------\n// Helper structs\n//--------------------------------------------------------------------------------------\n\nstruct VSOut\n{\n    float4 PosSS : SV_Position;\n    float2 TexCoord : TEXCOORD;\n};\n\n//--------------------------------------------------------------------------------------\n// Vertex Shader\n//--------------------------------------------------------------------------------------\n\nVSOut mainVS(uint vertexID : SV_VertexID)\n{\n    VSOut vsout;\n\n    vsout.TexCoord = float2((vertexID << 1) & 2, vertexID & 2);\n    vsout.PosSS = float4(vsout.TexCoord.x * 2 - 1, -vsout.TexCoord.y * 2 + 1, 0, 1);\n\n    return vsout;\n}\n\n//--------------------------------------------------------------------------------------\n// Pixel Shader\n//--------------------------------------------------------------------------------------\n\nfloat4 mainPS(VSOut psin) : SV_Target\n{\n    const float2 uv = psin.PosSS.xy / float2(g_frame.DisplayWidth, g_frame.DisplayHeight);\n\n    Texture2D<float4> g_composited = ResourceDescriptorHeap[g_local.InputDescHeapIdx];\n    // float3 composited = g_composited[psin.PosSS.xy].rgb;\n    float3 composited = g_composited.SampleLevel(g_samPointClamp, uv, 0).rgb;\n    float3 display = composited;\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + GBUFFER_OFFSET::DEPTH];\n    float z = g_depth.SampleLevel(g_samPointClamp, uv, 0);\n    if(g_local.DisplayOption != (int)DisplayOption::DEFAULT && z == FLT_MAX)\n        return 0;\n\n    if(g_local.AutoExposure)\n    {\n        Texture2D<float2> g_exposure = ResourceDescriptorHeap[g_local.ExposureDescHeapIdx];\n        const float exposure = g_exposure[int2(0, 0)].x;\n        const float3 exposedColor = composited * exposure;\n        display = exposedColor;\n    }\n\n    if (g_local.Tonemapper == (int) Tonemapper::NEUTRAL)\n    {\n        display = Tonemap::tony_mc_mapface(display, g_local.LUTDescHeapIdx);\n        float3 desaturation = Math::Luminance(display);\n        display = Math::Lerp(desaturation, display, g_local.Saturation);\n    }\n    else if (g_local.Tonemapper == (int) Tonemapper::AgX_DEFAULT)\n        display = Tonemap::AgX_Default(display);\n    else if (g_local.Tonemapper == (int) Tonemapper::AgX_GOLDEN)\n        display = Tonemap::AgX_Golden(display);\n    else if (g_local.Tonemapper == (int) Tonemapper::AgX_PUNCHY)\n        display = Tonemap::AgX_Punchy(display);\n    else if (g_local.Tonemapper == (int) Tonemapper::AgX_CUSTOM)\n        display = Tonemap::AgX_Custom(display, g_local.Saturation, g_local.AgXExp);\n\n    if (g_local.DisplayOption == (int) DisplayOption::DEPTH)\n    {\n        float z_ndc = z = g_frame.CameraNear / z;\n        display = z_ndc;\n    }\n    else if (g_local.DisplayOption == (int) DisplayOption::NORMAL)\n    {\n        GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + GBUFFER_OFFSET::NORMAL];\n        float2 encodedNormal = g_normal.SampleLevel(g_samPointClamp, uv, 0);\n        display = Math::DecodeUnitVector(encodedNormal.xy);\n        display = display * 0.5 + 0.5;\n    }\n    else if (g_local.DisplayOption == (int) DisplayOption::BASE_COLOR)\n    {\n        GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::BASE_COLOR];\n        display = g_baseColor.SampleLevel(g_samPointClamp, uv, 0).xyz;\n    }\n    else if (g_local.DisplayOption == (int) DisplayOption::METALNESS_ROUGHNESS)\n    {\n        GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n        float2 mr = g_metallicRoughness.SampleLevel(g_samPointClamp, uv, 0);\n        GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n        mr.x = flags.metallic;\n\n        display = float3(mr, 0.0f);\n    }\n    else if (g_local.DisplayOption == (int) DisplayOption::COAT_WEIGHT)\n    {\n        GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n        float2 mr = g_metallicRoughness.SampleLevel(g_samPointClamp, uv, 0);\n        GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n        display = 0;\n\n        if(flags.coated)\n        {\n            GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n                GBUFFER_OFFSET::COAT];\n            uint3 packed = g_coat[psin.PosSS.xy].xyz;\n            GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n            display = coat.weight;\n        }\n    }\n    else if (g_local.DisplayOption == (int) DisplayOption::COAT_COLOR)\n    {\n        GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n        float2 mr = g_metallicRoughness.SampleLevel(g_samPointClamp, uv, 0);\n        GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n        display = 0;\n\n        if(flags.coated)\n        {\n            GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n                GBUFFER_OFFSET::COAT];\n            uint3 packed = g_coat[psin.PosSS.xy].xyz;\n            GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n            display = coat.color;\n        }\n    }\n    else if (g_local.DisplayOption == (int) DisplayOption::ROUGHNESS_TH)\n    {\n        GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n        float r = g_metallicRoughness.SampleLevel(g_samPointClamp, uv, 0).y;\n\n        display = (r >= g_local.RoughnessTh) * float3(0.26, 0.014, 0.021);\n    }\n    else if (g_local.DisplayOption == (int) DisplayOption::EMISSIVE)\n    {\n        GBUFFER_EMISSIVE_COLOR g_emissiveColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::EMISSIVE_COLOR];\n        GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::BASE_COLOR];\n\n        GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n        float m = g_metallicRoughness.SampleLevel(g_samPointClamp, uv, 0).x;\n        GBuffer::Flags flags = GBuffer::DecodeMetallic(m);\n\n        display = flags.emissive ? g_emissiveColor.SampleLevel(g_samPointClamp, uv, 0).rgb :\n            g_baseColor.SampleLevel(g_samPointClamp, uv, 0).xyz * 0.005;\n    }\n    else if (g_local.DisplayOption == (int) DisplayOption::TRANSMISSION)\n    {\n        GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n        float m = g_metallicRoughness.SampleLevel(g_samPointClamp, uv, 0).x;\n        GBuffer::Flags flags = GBuffer::DecodeMetallic(m);\n\n        display = float3(flags.transmissive, !flags.transmissive, 0);\n    }\n\n    return float4(display, 1.0f);\n}"
  },
  {
    "path": "Source/ZetaRenderPass/Display/Display_Common.h",
    "content": "#ifndef DISPLAY_PASS_H\n#define DISPLAY_PASS_H\n\n#include \"../../ZetaCore/Core/HLSLCompat.h\"\n\nenum class DisplayOption\n{\n    DEFAULT,\n    BASE_COLOR,\n    NORMAL,\n    METALNESS_ROUGHNESS,\n    COAT_WEIGHT,\n    COAT_COLOR,\n    ROUGHNESS_TH,\n    EMISSIVE,\n    TRANSMISSION,\n    DEPTH,\n    COUNT\n};\n\nenum class Tonemapper\n{\n    NONE,\n    NEUTRAL,\n    AgX_DEFAULT,\n    AgX_GOLDEN,\n    AgX_PUNCHY,\n    AgX_CUSTOM,\n    COUNT\n};\n\nstruct cbDisplayPass\n{\n    uint16_t DisplayOption;\n    uint16_t Tonemapper;\n    uint16_t AutoExposure;\n    uint16_t pad;\n\n    uint32_t InputDescHeapIdx;\n    uint32_t ExposureDescHeapIdx;\n    uint32_t LUTDescHeapIdx;\n\n    float Saturation;\n    float AgXExp;\n    float RoughnessTh;\n};\n\nstruct cbDrawPicked\n{\n    float4_ row0;\n    float4_ row1;\n    float4_ row2;\n    float4_ row3;\n};\n\nstruct cbSobel\n{\n    uint32_t MaskDescHeapIdx;\n    uint32_t Wireframe;\n};\n\n#endif\n"
  },
  {
    "path": "Source/ZetaRenderPass/Display/DrawPicked.hlsl",
    "content": "#include \"../Common/FrameConstants.h\"\n#include \"Display_Common.h\"\n\n//--------------------------------------------------------------------------------------\n// Helper structs\n//--------------------------------------------------------------------------------------\n\nstruct VSIn\n{\n    float3 PosL : POSITION;\n    float2 TexUV : TEXUV;\n    int2 NormalL : NORMAL;\n    int2 TangentU : TANGENT;\n};\n\nstruct VSOut\n{\n    float4 PosSS : SV_Position;\n};\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cbDrawPicked> g_local : register(b1);\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\nVSOut mainVS(VSIn vsin)\n{\n    VSOut vsout;\n\n    float4x4 WVP = float4x4(g_local.row0, g_local.row1, g_local.row2, g_local.row3);\n    vsout.PosSS = mul(float4(vsin.PosL, 1.0f), WVP);\n\n    return vsout;\n}\n\nfloat mainPS(VSOut psin) : SV_Target\n{\n    return 1;\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/Display/Sobel.hlsl",
    "content": "#include \"Display_Common.h\"\n#include \"../Common/Math.hlsli\"\n#include \"../Common/FrameConstants.h\"\n#include \"../Common/GBuffers.hlsli\"\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cbSobel> g_local : register(b1);\n\n//--------------------------------------------------------------------------------------\n// Helper structs\n//--------------------------------------------------------------------------------------\n\nstruct VSOut\n{\n    float4 PosSS : SV_Position;\n    float2 TexCoord : TEXCOORD;\n};\n\n//--------------------------------------------------------------------------------------\n// Vertex Shader\n//--------------------------------------------------------------------------------------\n\nfloat Sobel(int2 DTid, Texture2D<float> g_mask)\n{\n    float3 gradientX = -1.0f * g_mask[int2(DTid.x - 1, DTid.y - 1)] -\n        2.0f * g_mask[int2(DTid.x - 1, DTid.y)] -\n        1.0f * g_mask[int2(DTid.x - 1, DTid.y + 1)] +\n        1.0f * g_mask[int2(DTid.x + 1, DTid.y - 1)] +\n        2.0f * g_mask[int2(DTid.x + 1, DTid.y)] +\n        1.0f * g_mask[int2(DTid.x + 1, DTid.y + 1)];\n\n    float3 gradientY = 1.0f * g_mask[int2(DTid.x - 1, DTid.y - 1)] +\n        2.0f * g_mask[int2(DTid.x, DTid.y - 1)] +\n        1.0f * g_mask[int2(DTid.x + 1, DTid.y - 1)] -\n        1.0f * g_mask[int2(DTid.x - 1, DTid.y + 1)] -\n        2.0f * g_mask[int2(DTid.x, DTid.y + 1)] -\n        1.0f * g_mask[int2(DTid.x + 1, DTid.y + 1)];\n\n    float3 gradientMagnitude = sqrt(gradientX * gradientX + gradientY * gradientY);\n    float lum = Math::Luminance(gradientMagnitude);\n\n    return lum;\n}\n\nbool CheckNeighborHood(int2 DTid, Texture2D<float> g_mask)\n{\n    int2 renderDim = int2(g_frame.RenderWidth, g_frame.RenderHeight);\n\n    [unroll]\n    for(int i = 0; i < 3; i++)\n    {\n        [unroll]\n        for(int j = 0; j < 3; j++)\n        {\n            int2 addr = int2(DTid.x - 1 + i, DTid.y - 1 + j);\n            if(!Math::IsWithinBounds(addr, renderDim))\n                continue;\n\n            float m = g_mask[addr];\n            if(m > 0)\n                return true;\n        }\n    }\n\n    return false;\n}\n\n//--------------------------------------------------------------------------------------\n// Vertex Shader\n//--------------------------------------------------------------------------------------\n\nVSOut mainVS(uint vertexID : SV_VertexID)\n{\n    VSOut vsout;\n\n    vsout.TexCoord = float2((vertexID << 1) & 2, vertexID & 2);\n    vsout.PosSS = float4(vsout.TexCoord.x * 2 - 1, -vsout.TexCoord.y * 2 + 1, 0, 1);\n\n    return vsout;\n}\n\n//--------------------------------------------------------------------------------------\n// Pixel Shader\n//--------------------------------------------------------------------------------------\n\nfloat4 mainPS(VSOut psin) : SV_Target\n{\n    int2 DTid = psin.PosSS.xy;\n    Texture2D<float> g_mask = ResourceDescriptorHeap[g_local.MaskDescHeapIdx];\n    uint maskCenter = g_local.Wireframe ? g_mask[DTid] : 0;\n    uint mask = g_local.Wireframe ? maskCenter : CheckNeighborHood(DTid, g_mask);\n\n    // Return if mask is zero - pixel is not part of the object\n    clip(mask == 1 ? 1 : -1);\n\n    float lum = g_local.Wireframe ? 1 : Sobel(DTid, g_mask);\n\n    // Return if pixel is not on the outline\n    // clip(lum - 1e-7);\n    clip(lum > 0 ? 1 : -1);\n\n    return float4(0.913098693, 0.332451582, 0.048171822, 1);\n}"
  },
  {
    "path": "Source/ZetaRenderPass/Display/Tonemap.hlsli",
    "content": "#include \"../Common/StaticTextureSamplers.hlsli\"\n\nnamespace Tonemap\n{\n    //--------------------------------------------------------------------------------------\n    // Tony McMapface\n    // Ref: https://github.com/h3r2tic/tony-mc-mapface\n    //--------------------------------------------------------------------------------------\n\n    float3 tony_mc_mapface(float3 stimulus, uint lutDescHeapIdx)\n    {\n        // Apply a non-linear transform that the LUT is encoded with.\n        const float3 encoded = stimulus / (stimulus + 1.0);\n\n        // Align the encoded range to texel centers.\n        const float LUT_DIMS = 48.0;\n        const float3 uv = encoded * ((LUT_DIMS - 1.0) / LUT_DIMS) + 0.5 / LUT_DIMS;\n\n        // Note: for OpenGL, do `uv.y = 1.0 - uv.y`\n        Texture3D<float3> g_lut = ResourceDescriptorHeap[lutDescHeapIdx];\n        return g_lut.SampleLevel(g_samLinearClamp, uv, 0);\n    }\n\n    //--------------------------------------------------------------------------------------\n    // AgX\n    // Ref: https://iolite-engine.com/blog_posts/minimal_agx_implementation\n    //--------------------------------------------------------------------------------------\n\n    float3 agxDefaultContrastApprox(float3 x) \n    {\n        float3 x2 = x * x;\n        float3 x4 = x2 * x2;\n        float3 x6 = x4 * x2;\n\n        return -17.86  * x6 * x\n            + 78.01    * x6\n            - 126.7    * x4 * x\n            + 92.06    * x4\n            - 28.72    * x2 * x\n            + 4.361    * x2\n            - 0.1718   * x\n            + 0.002857;\n    }\n\n    float3 agxInset(float3 val) \n    {\n        const float3x3 agx_mat = float3x3(\n            0.842479062253094, 0.0423282422610123, 0.0423756549057051,\n            0.0784335999999992, 0.878468636469772, 0.0784336,\n            0.0792237451477643, 0.0791661274605434, 0.879142973793104);\n        \n        const float min_ev = -12.47393f;\n        const float max_ev = 4.026069f;\n\n        // Input transform (inset)\n        val = mul(val, agx_mat);\n    \n        // Log2 space encoding\n        val = clamp(log2(val), min_ev, max_ev);\n        val = (val - min_ev) / (max_ev - min_ev);\n\n        // Apply sigmoid function approximation\n        val = agxDefaultContrastApprox(val);\n\n        return val;\n    }\n\n    float3 agxEotf(float3 val) \n    {\n        const float3x3 agx_mat_inv = float3x3(\n            1.19687900512017, -0.0528968517574562, -0.0529716355144438,\n            -0.0980208811401368, 1.15190312990417, -0.0980434501171241,\n            -0.0990297440797205, -0.0989611768448433, 1.15107367264116);\n\n        // Inverse input transform (outset)\n        val = mul(val, agx_mat_inv);\n\n        // sRGB IEC 61966-2-1 2.2 Exponent Reference EOTF Display\n        // NOTE: We're linearizing the output here. Comment/adjust when\n        // *not* using a sRGB render target\n        val = pow(val, 2.2);\n\n        return val;\n    }\n\n    float3 agxLook(float3 val, float offset, float3 slope, float exp, float saturation)\n    {\n        const float3 lw = float3(0.2126, 0.7152, 0.0722);\n        float luma = dot(val, lw);\n        // ASC CDL\n        val = pow(val * slope + offset, exp);\n\n        return luma + saturation * (val - luma);\n    }\n\n    float3 AgX_Default(float3 value)\n    {\n        float3 tonemapped = agxInset(value);\n        tonemapped = agxEotf(tonemapped);\n\n        return tonemapped;\n    }\n\n    float3 AgX_Golden(float3 value)\n    {\n        float3 tonemapped = agxInset(value);\n        const float offset = 0.0;\n        const float3 slope = float3(1.0, 0.9, 0.5);\n        const float saturation = 0.8f;\n        const float exp = 0.8;\n        tonemapped = agxLook(tonemapped, offset, slope, exp, saturation);\n        tonemapped = agxEotf(tonemapped);\n\n        return tonemapped;\n    }\n\n    float3 AgX_Punchy(float3 value)\n    {\n        float3 tonemapped = agxInset(value);\n        const float offset = 0.0;\n        const float slope = 1.0;\n        const float saturation = 1.4f;\n        const float exp = 1.35;\n        tonemapped = agxLook(tonemapped, offset, slope, exp, saturation);\n        tonemapped = agxEotf(tonemapped);\n\n        return tonemapped;\n    }\n\n    float3 AgX_Custom(float3 value, float saturation, float exp)\n    {\n        float3 tonemapped = agxInset(value);\n        const float offset = 0.0;\n        const float slope = 1.0;\n        tonemapped = agxLook(tonemapped, offset, slope, exp, saturation);\n        tonemapped = agxEotf(tonemapped);\n\n        return tonemapped;\n    }\n}"
  },
  {
    "path": "Source/ZetaRenderPass/FSR2/CMakeLists.txt",
    "content": "set(RP_FSR2_DIR ${ZETA_RENDER_PASS_DIR}/FSR2)\nset(RP_FSR2_SRC\n    ${RP_FSR2_DIR}/FSR2.cpp\n    ${RP_FSR2_DIR}/FSR2.h)\nset(RP_FSR2_SRC ${RP_FSR2_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaRenderPass/FSR2/FSR2.cpp",
    "content": "#include \"FSR2.h\"\n#include <Core/RendererCore.h>\n#include <Core/CommandList.h>\n#include <App/App.h>\n#include <App/Common.h>\n#include <App/Timer.h>\n#include <algorithm>\n#include <Scene/Camera.h>\n#include <Core/PipelineStateLibrary.h>\n#include <Utility/Utility.h>\n#include <Support/Task.h>\n#include <GBuffer/GenerateDepthBuffer.h>\n\n#include <FSR2/Include/ffx_fsr2.h>\n#include <FSR2/Include/shaders/ffx_fsr2_resources.h>\n#include <FSR2/Include/dx12/shaders/ffx_fsr2_shaders_dx12.h>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::App;\nusing namespace ZetaRay::Support;\n\nnamespace\n{\n    struct ResourceData\n    {\n        D3D12_RESOURCE_STATES State;\n        DescriptorTable SrvAllMipsCpu;\n        DescriptorTable UavAllMipsCpu;\n        DescriptorTable UavAllMipsGpu;\n        bool NeedsUavBarrier = false;\n        bool RecordedClearThisFrame = false;\n    };\n\n    struct RenderPassData\n    {\n        ComPtr<ID3D12RootSignature> RootSig;\n        ID3D12PipelineState* PSO = nullptr;\n\n        DescriptorTable SrvTableGpu;\n        int SrvTableGpuNumDescs = -1;\n        DescriptorTable UavTableGpu;\n        int UavTableGpuNumDescs = -1;\n    };\n\n    struct PsoMap\n    {\n        ID3D12PipelineState* PSO;\n        FfxFsr2Pass Pass;\n    };\n\n    struct DllWrapper\n    {\n        using fp_Fsr2ContextCreate = FfxErrorCode(*)(FfxFsr2Context* context, const FfxFsr2ContextDescription* contextDescription);\n        using fp_Fsr2ContextDestroy = FfxErrorCode(*)(FfxFsr2Context* context);\n        using fp_Fsr2ContextDispatch = FfxErrorCode(*)(FfxFsr2Context* context, const FfxFsr2DispatchDescription* dispatchDescription);\n        using fp_Fsr2GetPermBlobByIdx = Fsr2ShaderBlobDX12(*)(FfxFsr2Pass passId, uint32_t permutationOptions);\n\n        void Load()\n        {\n            m_fsrLib = LoadLibraryExA(\"ffx_fsr2_api_x64\", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);\n            CheckWin32(m_fsrLib);\n            m_fsrDxLib = LoadLibraryExA(\"ffx_fsr2_api_dx12_x64\", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);\n            CheckWin32(m_fsrDxLib);\n\n#if defined(__clang__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wcast-function-type-mismatch\"\n#endif\n            FpCreate = reinterpret_cast<fp_Fsr2ContextCreate>(GetProcAddress(m_fsrLib, \"ffxFsr2ContextCreate\"));\n            CheckWin32(FpCreate);\n            FpDestroy = reinterpret_cast<fp_Fsr2ContextDestroy>(GetProcAddress(m_fsrLib, \"ffxFsr2ContextDestroy\"));\n            CheckWin32(FpDestroy);\n            FpDispatch = reinterpret_cast<fp_Fsr2ContextDispatch>(GetProcAddress(m_fsrLib, \"ffxFsr2ContextDispatch\"));\n            CheckWin32(FpDispatch);\n            FpGetShaderPermutation = reinterpret_cast<fp_Fsr2GetPermBlobByIdx>(GetProcAddress(m_fsrDxLib, \"fsr2GetPermutationBlobByIndexDX12\"));\n            CheckWin32(FpGetShaderPermutation);\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n        }\n\n        void Free()\n        {\n            if (m_fsrLib)\n                FreeLibrary(m_fsrLib);\n            if (m_fsrDxLib)\n                FreeLibrary(m_fsrDxLib);\n\n            FpCreate = nullptr;\n            FpDestroy = nullptr;\n            FpDispatch = nullptr;\n            FpGetShaderPermutation = nullptr;\n        }\n\n        HMODULE m_fsrLib;\n        HMODULE m_fsrDxLib;\n\n        fp_Fsr2ContextCreate FpCreate = nullptr;\n        fp_Fsr2ContextDestroy FpDestroy = nullptr;\n        fp_Fsr2ContextDispatch FpDispatch = nullptr;\n        fp_Fsr2GetPermBlobByIdx FpGetShaderPermutation = nullptr;\n    };\n\n    //\n    // Data\n    //\n    struct FSR2_Data\n    {\n        FSR2_Data()\n            : m_psoLib(m_psoCache)\n        {\n        }\n\n        static constexpr uint32_t FLAGS = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE |\n            FFX_FSR2_ENABLE_DEPTH_INVERTED |\n            FFX_FSR2_ENABLE_DEPTH_INFINITE;\n\n        static constexpr uint32_t APP_CONTROLLED_RES_IDS[] =\n        {\n            FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_COLOR,\n            FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS,\n            FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_DEPTH,\n            FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_EXPOSURE,\n            FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT\n        };\n\n        static constexpr uint32_t NUM_APP_CONTROLLED_RESOURCES = ZetaArrayLen(APP_CONTROLLED_RES_IDS);\n\n        static constexpr int MAX_BARRIERS = 16;\n        static constexpr int MAX_SAMPLERS = 2;\n        static constexpr int MAX_DESC_RANGES = 2;\n        static constexpr int MAX_ROOT_PARAMS = 10;\n        static constexpr int MAX_NUM_CONST_BUFFERS = 2;\n\n        FfxFsr2Context m_ctx;\n\n        UploadHeapBuffer m_uploadHeapBuffs[FFX_FSR2_RESOURCE_IDENTIFIER_COUNT];\n        Buffer m_defaultHeapBuffs[FFX_FSR2_RESOURCE_IDENTIFIER_COUNT];\n        Texture m_textures[FFX_FSR2_RESOURCE_IDENTIFIER_COUNT];\n        ResourceData m_resData[FFX_FSR2_RESOURCE_IDENTIFIER_COUNT];\n\n        bool m_reset = true;\n\n        RenderPassData m_passes[FFX_FSR2_PASS_COUNT];\n        PsoMap m_psoToPassMap[FFX_FSR2_PASS_COUNT];\n        int m_currMapIdx = 0;\n\n        ComputeCmdList* m_cmdList = nullptr;\n\n        // app-controlled resources\n        ID3D12Resource* m_color = nullptr;\n        ID3D12Resource* m_depth = nullptr;\n        ID3D12Resource* m_motionVec = nullptr;\n        ID3D12Resource* m_exposure = nullptr;\n\n        PipelineStateLibrary m_psoLib;\n        DllWrapper m_dll;\n        GenerateRasterDepth m_rasterDepth;\n\n        ID3D12PipelineState* m_psoCache[FFX_FSR2_PASS_COUNT] = { 0 };\n    };\n\n    FSR2_Data* g_fsr2Data = nullptr;\n\n    D3D12_RESOURCE_STATES GetD3D12State(FfxResourceStates fsrState)\n    {\n        switch (fsrState)\n        {\n        case FFX_RESOURCE_STATE_UNORDERED_ACCESS:\n            return D3D12_RESOURCE_STATE_UNORDERED_ACCESS;\n        case FFX_RESOURCE_STATE_COMPUTE_READ:\n            return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;\n        case FFX_RESOURCE_STATE_COPY_SRC:\n            return D3D12_RESOURCE_STATE_COPY_SOURCE;\n        case FFX_RESOURCE_STATE_COPY_DEST:\n            return D3D12_RESOURCE_STATE_COPY_DEST;\n        case FFX_RESOURCE_STATE_GENERIC_READ:\n            return D3D12_RESOURCE_STATE_GENERIC_READ;\n        default:\n            Assert(false, \"Unknown state\");\n            return D3D12_RESOURCE_STATE_COMMON;\n        }\n    }\n\n    const char* GetFsrErrorMsg(FfxErrorCode err)\n    {\n        if (err == FFX_ERROR_INVALID_POINTER)\n            return \"The operation failed due to an invalid pointer\";\n        else if (err == FFX_ERROR_INVALID_ALIGNMENT)\n            return \"The operation failed due to an invalid alignment.\";\n        else if (err == FFX_ERROR_INVALID_SIZE)\n            return \"The operation failed due to an invalid size.\";\n        else if (err == FFX_EOF)\n            return \"The end of the file was encountered.\";\n        else if (err == FFX_ERROR_INVALID_PATH)\n            return \"The operation failed because the specified path was invalid.\";\n        else if (err == FFX_ERROR_EOF)\n            return \"The operation failed because end of file was reached.\";\n        else if (err == FFX_ERROR_MALFORMED_DATA)\n            return \"The operation failed because of some malformed data.\";\n        else if (err == FFX_ERROR_OUT_OF_MEMORY)\n            return \"The operation failed because it ran out memory.\";\n        else if (err == FFX_ERROR_INCOMPLETE_INTERFACE)\n            return \"The operation failed because the interface was not fully configured.\";\n        else if (err == FFX_ERROR_INVALID_ENUM)\n            return \"The operation failed because of an invalid enumeration value.\";\n        else if (err == FFX_ERROR_INVALID_ARGUMENT)\n            return \"The operation failed because an argument was invalid.\";\n        else if (err == FFX_ERROR_OUT_OF_RANGE)\n            return \"The operation failed because a value was out of range.\";\n        else if (err == FFX_ERROR_NULL_DEVICE)\n            return \"The operation failed because a device was null.\";\n        else if (err == FFX_ERROR_BACKEND_API_ERROR)\n            return \"The operation failed because the backend API returned an error code.\";\n        else if (err == FFX_ERROR_INSUFFICIENT_MEMORY)\n            return \"The operation failed because there was not enough memory.\";\n\n        return \"Unknown error.\";\n    }\n\n    DXGI_FORMAT ToDXGIFormat(FfxSurfaceFormat surfaceFormat)\n    {\n        switch (surfaceFormat)\n        {\n        case(FFX_SURFACE_FORMAT_R32G32B32A32_TYPELESS):\n            return DXGI_FORMAT_R32G32B32A32_TYPELESS;\n        case(FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT):\n            return DXGI_FORMAT_R32G32B32A32_FLOAT;\n        case(FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT):\n            return DXGI_FORMAT_R16G16B16A16_FLOAT;\n        case(FFX_SURFACE_FORMAT_R16G16B16A16_UNORM):\n            return DXGI_FORMAT_R16G16B16A16_UNORM;\n        case(FFX_SURFACE_FORMAT_R32G32_FLOAT):\n            return DXGI_FORMAT_R32G32_FLOAT;\n        case(FFX_SURFACE_FORMAT_R32_UINT):\n            return DXGI_FORMAT_R32_UINT;\n        case(FFX_SURFACE_FORMAT_R8G8B8A8_TYPELESS):\n            return DXGI_FORMAT_R8G8B8A8_TYPELESS;\n        case(FFX_SURFACE_FORMAT_R8G8B8A8_UNORM):\n            return DXGI_FORMAT_R8G8B8A8_UNORM;\n        case(FFX_SURFACE_FORMAT_R11G11B10_FLOAT):\n            return DXGI_FORMAT_R11G11B10_FLOAT;\n        case(FFX_SURFACE_FORMAT_R16G16_FLOAT):\n            return DXGI_FORMAT_R16G16_FLOAT;\n        case(FFX_SURFACE_FORMAT_R16G16_UINT):\n            return DXGI_FORMAT_R16G16_UINT;\n        case(FFX_SURFACE_FORMAT_R16_FLOAT):\n            return DXGI_FORMAT_R16_FLOAT;\n        case(FFX_SURFACE_FORMAT_R16_UINT):\n            return DXGI_FORMAT_R16_UINT;\n        case(FFX_SURFACE_FORMAT_R16_UNORM):\n            return DXGI_FORMAT_R16_UNORM;\n        case(FFX_SURFACE_FORMAT_R16_SNORM):\n            return DXGI_FORMAT_R16_SNORM;\n        case(FFX_SURFACE_FORMAT_R8_UNORM):\n            return DXGI_FORMAT_R8_UNORM;\n        case(FFX_SURFACE_FORMAT_R8_UINT):\n            return DXGI_FORMAT_R8_UINT;\n        case(FFX_SURFACE_FORMAT_R8G8_UNORM):\n            return DXGI_FORMAT_R8G8_UNORM;\n        case(FFX_SURFACE_FORMAT_R32_FLOAT):\n            return DXGI_FORMAT_R32_FLOAT;\n        default:\n            return DXGI_FORMAT_UNKNOWN;\n        }\n    }\n\n    void RecordClearJob(const FfxClearFloatJobDescription& job)\n    {\n        Assert(g_fsr2Data->m_cmdList, \"Command list was NULL\");\n        Assert(job.target.internalIndex < FFX_FSR2_RESOURCE_IDENTIFIER_COUNT, \"Unknown resource\");\n\n        for (uint32_t i = 0; i < g_fsr2Data->NUM_APP_CONTROLLED_RESOURCES; i++)\n            Assert(job.target.internalIndex != (int)g_fsr2Data->APP_CONTROLLED_RES_IDS[i], \"This resource is controlled by the App.\");\n\n        if (g_fsr2Data->m_resData[job.target.internalIndex].RecordedClearThisFrame)\n            return;\n\n        Texture& t = g_fsr2Data->m_textures[job.target.internalIndex];\n        Assert(t.IsInitialized(), \"Texture hasn't been created yet.\");\n\n        auto& uavDescTableCpu = g_fsr2Data->m_resData[job.target.internalIndex].UavAllMipsCpu;\n        auto& uavDescTableGpu = g_fsr2Data->m_resData[job.target.internalIndex].UavAllMipsGpu;\n\n        const auto desc = t.Resource()->GetDesc();\n        Assert(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, \"UAV access is not allowed for this resource\");\n\n        if (uavDescTableCpu.IsEmpty())\n        {\n            uavDescTableCpu = App::GetRenderer().GetCbvSrvUavDescriptorHeapCpu().Allocate(desc.MipLevels);\n\n            for (uint32_t i = 0; i < desc.MipLevels; i++)\n                Direct3DUtil::CreateTexture2DUAV(t, uavDescTableCpu.CPUHandle(i), DXGI_FORMAT_UNKNOWN, i);\n        }\n\n        if (uavDescTableGpu.IsEmpty())\n        {\n            uavDescTableGpu = App::GetRenderer().GetGpuDescriptorHeap().Allocate(desc.MipLevels);\n\n            for (uint32_t i = 0; i < desc.MipLevels; i++)\n                Direct3DUtil::CreateTexture2DUAV(t, uavDescTableGpu.CPUHandle(i), DXGI_FORMAT_UNKNOWN, i);\n        }\n\n        if (job.target.internalIndex == FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT)\n        {\n            Assert(g_fsr2Data->m_resData[job.target.internalIndex].State == D3D12_RESOURCE_STATE_UNORDERED_ACCESS,\n                \"upscaled color should always be in UAV state\");\n        }\n        else if (g_fsr2Data->m_resData[job.target.internalIndex].State != D3D12_RESOURCE_STATE_UNORDERED_ACCESS)\n        {\n            auto barrier = Direct3DUtil::TransitionBarrier(t.Resource(), g_fsr2Data->m_resData[job.target.internalIndex].State,\n                D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n\n            // TODO barriers should be batched\n            g_fsr2Data->m_cmdList->ResourceBarrier(&barrier, 1);\n\n            g_fsr2Data->m_resData[job.target.internalIndex].State = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;\n        }\n\n        g_fsr2Data->m_cmdList->ClearUnorderedAccessViewFloat(uavDescTableGpu.GPUHandle(0),\n            uavDescTableCpu.CPUHandle(0),\n            t.Resource(),\n            job.color[0], job.color[1], job.color[2], job.color[3]);\n\n        g_fsr2Data->m_resData[job.target.internalIndex].NeedsUavBarrier = true;\n        g_fsr2Data->m_resData[job.target.internalIndex].RecordedClearThisFrame = true;\n    }\n\n    void RecordComputeJob(const FfxComputeJobDescription& job)\n    {\n        Assert(g_fsr2Data->m_cmdList, \"Command list was NULL\");\n\n        g_fsr2Data->m_cmdList->SetRootSignature(reinterpret_cast<ID3D12RootSignature*>(job.pipeline.rootSignature));\n        g_fsr2Data->m_cmdList->SetPipelineState(reinterpret_cast<ID3D12PipelineState*>(job.pipeline.pipeline));\n\n        auto& renderer = App::GetRenderer();\n        auto* device = renderer.GetDevice();\n        const auto idx = BinarySearch(Span(g_fsr2Data->m_psoToPassMap),\n            reinterpret_cast<ID3D12PipelineState*>(job.pipeline.pipeline),\n            [](const PsoMap& p) {return p.PSO; }, 0, FFX_FSR2_PASS_COUNT - 1);\n\n        Assert(idx != -1, \"Given PSO was not found\");\n\n        const FfxFsr2Pass pass = g_fsr2Data->m_psoToPassMap[idx].Pass;\n        Assert(pass < FFX_FSR2_PASS_COUNT, \"Invalid pass\");\n\n        auto& passData = g_fsr2Data->m_passes[pass];\n\n        D3D12_RESOURCE_BARRIER barriers[g_fsr2Data->MAX_BARRIERS];\n        int currBarrierIdx = 0;\n\n        g_fsr2Data->m_passes[pass].SrvTableGpu = renderer.GetGpuDescriptorHeap().Allocate(\n            g_fsr2Data->m_passes[pass].SrvTableGpuNumDescs);\n\n        g_fsr2Data->m_passes[pass].UavTableGpu = renderer.GetGpuDescriptorHeap().Allocate(\n            g_fsr2Data->m_passes[pass].UavTableGpuNumDescs);\n\n        // UAVs\n        for (uint32_t i = 0; i < job.pipeline.uavCount; i++)\n        {\n            const uint32_t uavResIdx = job.uavs[i].internalIndex;\n            Assert(uavResIdx < FFX_FSR2_RESOURCE_IDENTIFIER_COUNT, \"Unknown resource\");\n            //Assert(job.pipeline.uavResourceBindings[i].resourceIdentifier == uavResIdx + job.uavMip[i], \"Unexpected mismatch\");\n\n            auto& uavAllMips = g_fsr2Data->m_resData[uavResIdx].UavAllMipsCpu;\n\n            {\n                Texture& t = g_fsr2Data->m_textures[uavResIdx];\n                Assert(t.Resource(), \"Texture2D hasn't been created yet.\");\n\n                const auto desc = t.Resource()->GetDesc();\n                Assert(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, \"UAV access is not allowed for this resource\");\n\n                if (uavAllMips.IsEmpty())\n                    uavAllMips = App::GetRenderer().GetCbvSrvUavDescriptorHeapCpu().Allocate(desc.MipLevels);\n\n                for (uint32_t j = 0; j < desc.MipLevels; j++)\n                    Direct3DUtil::CreateTexture2DUAV(t, uavAllMips.CPUHandle(j), DXGI_FORMAT_UNKNOWN, j);\n            }\n\n            if ((g_fsr2Data->m_resData[uavResIdx].State & D3D12_RESOURCE_STATE_UNORDERED_ACCESS) == 0)\n            {\n                Texture& t = g_fsr2Data->m_textures[uavResIdx];\n\n                barriers[currBarrierIdx++] = Direct3DUtil::TransitionBarrier(t.Resource(),\n                    g_fsr2Data->m_resData[uavResIdx].State,\n                    D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n\n                g_fsr2Data->m_resData[uavResIdx].State = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;\n            }\n            // TODO only necessary if there's been a clear operation on this resource in this frame\n            else if (g_fsr2Data->m_resData[uavResIdx].NeedsUavBarrier)\n            {\n                Texture& t = g_fsr2Data->m_textures[uavResIdx];\n                barriers[currBarrierIdx++] = Direct3DUtil::UAVBarrier(t.Resource());\n\n                g_fsr2Data->m_resData[uavResIdx].NeedsUavBarrier = false;\n            }\n\n            const int uavBindSlot = job.pipeline.uavResourceBindings[i].slotIndex;\n\n            device->CopyDescriptorsSimple(1,\n                passData.UavTableGpu.CPUHandle(uavBindSlot),\n                uavAllMips.CPUHandle(job.uavMip[i]),\n                D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);\n        }\n\n        uint32_t currRootParam = 0;\n        g_fsr2Data->m_cmdList->SetRootDescriptorTable(currRootParam++, passData.UavTableGpu.GPUHandle(0));\n\n        // SRVs\n        for (uint32_t i = 0; i < job.pipeline.srvCount; i++)\n        {\n            const uint32_t srvResIdx = job.srvs[i].internalIndex;\n            Assert(srvResIdx < FFX_FSR2_RESOURCE_IDENTIFIER_COUNT, \"Unknown resource\");\n            //Assert(job.pipeline.srvResourceBindings[i].resourceIdentifier == srvResIdx, \"Unexpected mismatch\");\n\n            auto& srv = g_fsr2Data->m_resData[srvResIdx].SrvAllMipsCpu;\n            if (srv.IsEmpty())\n            {\n                srv = App::GetRenderer().GetCbvSrvUavDescriptorHeapCpu().Allocate(1);\n\n                Texture& t = g_fsr2Data->m_textures[srvResIdx];\n                Assert(t.IsInitialized(), \"Texture2D hasn't been created yet.\");\n                Direct3DUtil::CreateTexture2DSRV(t, srv.CPUHandle(0));\n            }\n\n            if ((g_fsr2Data->m_resData[srvResIdx].State & D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE) == 0)\n            {\n                Texture& t = g_fsr2Data->m_textures[srvResIdx];\n\n                barriers[currBarrierIdx++] = Direct3DUtil::TransitionBarrier(t.Resource(),\n                    g_fsr2Data->m_resData[srvResIdx].State,\n                    D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n\n                g_fsr2Data->m_resData[srvResIdx].State = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;\n            }\n\n            const int srvBindSlot = job.pipeline.srvResourceBindings[i].slotIndex;\n\n            device->CopyDescriptorsSimple(1,\n                passData.SrvTableGpu.CPUHandle(srvBindSlot),\n                srv.CPUHandle(0),\n                D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);\n        }\n\n        g_fsr2Data->m_cmdList->SetRootDescriptorTable(currRootParam++, passData.SrvTableGpu.GPUHandle(0));\n\n        // root constants\n        for (uint32_t currRootConstantIdx = 0; currRootConstantIdx < job.pipeline.constCount; ++currRootConstantIdx)\n        {\n            g_fsr2Data->m_cmdList->SetRoot32BitConstants(currRootParam + currRootConstantIdx,\n                job.cbs[currRootConstantIdx].uint32Size,\n                job.cbs[currRootConstantIdx].data,\n                0);\n        }\n\n        if (currBarrierIdx)\n            g_fsr2Data->m_cmdList->ResourceBarrier(barriers, currBarrierIdx);\n\n        g_fsr2Data->m_cmdList->Dispatch(job.dimensions[0], job.dimensions[1], job.dimensions[2]);\n    }\n\n    //\n    // Callbacks\n    //\n    FfxErrorCode Fsr2CreateBackendContext(FfxFsr2Interface* backendInterface, FfxDevice device)\n    {\n        return FFX_OK;\n    }\n\n    FfxErrorCode Fsr2DestroyBackendContext(FfxFsr2Interface* backendInterface)\n    {\n        return FFX_OK;\n    }\n\n    FfxErrorCode Fsr2GetDeviceCapabilities(FfxFsr2Interface* backendInterface,\n        FfxDeviceCapabilities* outDeviceCapabilities, FfxDevice device)\n    {\n        // support for following three was checked during app init\n        outDeviceCapabilities->minimumSupportedShaderModel = FFX_SHADER_MODEL_6_6;\n        outDeviceCapabilities->raytracingSupported = true;\n        outDeviceCapabilities->fp16Supported = true;\n\n        auto* d3dDevice = App::GetRenderer().GetDevice();\n\n        // lane counts\n        D3D12_FEATURE_DATA_D3D12_OPTIONS1 options1;\n        CheckHR(d3dDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS1, &options1, sizeof(options1)));\n\n        outDeviceCapabilities->waveLaneCountMin = options1.WaveLaneCountMin;\n        outDeviceCapabilities->waveLaneCountMax = options1.WaveLaneCountMax;\n\n        return FFX_OK;\n    }\n\n    FfxErrorCode Fsr2CreateResource(FfxFsr2Interface* backendInterface,\n        const FfxCreateResourceDescription* resDesc, FfxResourceInternal* outResource)\n    {\n        Assert(resDesc->id < FFX_FSR2_RESOURCE_IDENTIFIER_COUNT, \"invalid resource ID\");\n\n        for (uint32_t i = 0; i < g_fsr2Data->NUM_APP_CONTROLLED_RESOURCES; i++)\n            Assert(resDesc->id != g_fsr2Data->APP_CONTROLLED_RES_IDS[i], \"This resource is created by the App.\");\n\n        // upload buffer\n        if (resDesc->heapType == FFX_HEAP_TYPE_UPLOAD)\n        {\n            Assert(resDesc->initalState == FFX_RESOURCE_STATE_GENERIC_READ,\n                \"Upload heap buffer must be GENERIC_READ at all times\");\n\n            auto buff = GpuMemory::GetUploadHeapBuffer(resDesc->initDataSize);\n            buff.Copy(0, resDesc->initDataSize, resDesc->initData);\n\n            g_fsr2Data->m_uploadHeapBuffs[resDesc->id] = ZetaMove(buff);\n            outResource->internalIndex = resDesc->id;\n\n            g_fsr2Data->m_resData[resDesc->id].State = D3D12_RESOURCE_STATE_GENERIC_READ;\n\n            return FFX_OK;\n        }\n\n        // committed resource\n        char resName[64];\n        Common::WideToCharStr(resDesc->name, resName);\n\n        const bool allowUAV = resDesc->usage & FFX_RESOURCE_USAGE_UAV;\n        const bool allowRT = resDesc->usage & FFX_RESOURCE_USAGE_RENDERTARGET;\n        const D3D12_RESOURCE_STATES state = GetD3D12State(resDesc->initalState);\n        uint8_t textureFlags = 0;\n        textureFlags = allowUAV ? textureFlags | TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS : textureFlags;\n        textureFlags = allowRT ? textureFlags | TEXTURE_FLAGS::ALLOW_RENDER_TARGET : textureFlags;\n        //const DXGI_FORMAT fmt = GetDXGIFormat(resDesc->resourceDescription.format);\n\n        if (resDesc->resourceDescription.type == FFX_RESOURCE_TYPE_BUFFER)\n        {\n            Assert(resDesc->usage != FFX_RESOURCE_USAGE_RENDERTARGET,\n                \"Buffers can't be used as render targets.\");\n\n            if (resDesc->initData)\n            {\n                g_fsr2Data->m_defaultHeapBuffs[resDesc->id] = GpuMemory::GetDefaultHeapBufferAndInit(resName,\n                    state, allowUAV,\n                    MemoryRegion{ .Data = resDesc->initData, .SizeInBytes = resDesc->initDataSize });\n            }\n            else\n            {\n                g_fsr2Data->m_defaultHeapBuffs[resDesc->id] = GpuMemory::GetDefaultHeapBuffer(resName,\n                    resDesc->initDataSize, state, allowUAV);\n            }\n\n            outResource->internalIndex = resDesc->id;\n        }\n        else if (resDesc->resourceDescription.type == FFX_RESOURCE_TYPE_TEXTURE2D)\n        {\n            const DXGI_FORMAT fmt = ToDXGIFormat(resDesc->resourceDescription.format);\n            Assert(fmt != DXGI_FORMAT_UNKNOWN, \"Invalid Texture2D format.\");\n\n            if (resDesc->initData)\n            {\n                g_fsr2Data->m_textures[resDesc->id] = GpuMemory::GetTexture2DAndInit(resName,\n                    resDesc->resourceDescription.width,\n                    resDesc->resourceDescription.height,\n                    fmt,\n                    state,\n                    reinterpret_cast<uint8_t*>(resDesc->initData),\n                    textureFlags);\n            }\n            else\n            {\n                g_fsr2Data->m_textures[resDesc->id] = GpuMemory::GetTexture2D(resName,\n                    resDesc->resourceDescription.width,\n                    resDesc->resourceDescription.height,\n                    fmt,\n                    state,\n                    textureFlags,\n                    (uint16_t)resDesc->resourceDescription.mipCount);\n            }\n\n            outResource->internalIndex = resDesc->id;\n        }\n        else if (resDesc->resourceDescription.type == FFX_RESOURCE_TYPE_TEXTURE3D)\n        {\n            const DXGI_FORMAT fmt = ToDXGIFormat(resDesc->resourceDescription.format);\n            Assert(!resDesc->initData, \"Initializing Texture3D from CPU side is not supported.\");\n            Assert(fmt != DXGI_FORMAT_UNKNOWN, \"Invalid Texture2D format.\");\n\n            g_fsr2Data->m_textures[resDesc->id] = GpuMemory::GetTexture3D(resName,\n                resDesc->resourceDescription.width,\n                resDesc->resourceDescription.height,\n                (uint16_t)resDesc->resourceDescription.depth,\n                fmt,\n                state,\n                textureFlags,\n                (uint16_t)resDesc->resourceDescription.mipCount);\n\n            outResource->internalIndex = resDesc->id;\n        }\n\n        g_fsr2Data->m_resData[resDesc->id].State = state;\n\n        return FFX_OK;\n    }\n\n    FfxErrorCode Fsr2RegisterResource(FfxFsr2Interface* backendInterface, const FfxResource* inResource,\n        FfxResourceInternal* outResource)\n    {\n        if (inResource->resource == nullptr)\n            outResource->internalIndex = FFX_FSR2_RESOURCE_IDENTIFIER_NULL;\n        else if (reinterpret_cast<const ID3D12Resource*>(inResource->resource) == g_fsr2Data->m_color)\n            outResource->internalIndex = FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_COLOR;\n        else if (reinterpret_cast<const ID3D12Resource*>(inResource->resource) == g_fsr2Data->m_depth)\n            outResource->internalIndex = FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_DEPTH;\n        else if (reinterpret_cast<const ID3D12Resource*>(inResource->resource) == g_fsr2Data->m_motionVec)\n            outResource->internalIndex = FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS;\n        else if (reinterpret_cast<const ID3D12Resource*>(inResource->resource) == g_fsr2Data->m_exposure)\n            outResource->internalIndex = FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_EXPOSURE;\n        else if (reinterpret_cast<const ID3D12Resource*>(inResource->resource) == g_fsr2Data->m_textures[FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT].Resource())\n            outResource->internalIndex = FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT;\n\n        return FFX_OK;\n    }\n\n    FfxErrorCode Fsr2UnregisterResources(FfxFsr2Interface* backendInterface)\n    {\n        return FFX_OK;\n    }\n\n    FfxResourceDescription Fsr2GetResourceDescription(FfxFsr2Interface* backendInterface,\n        FfxResourceInternal resource)\n    {\n        Assert(resource.internalIndex < FFX_FSR2_RESOURCE_IDENTIFIER_COUNT, \"Unknown resource idx\");\n\n        FfxResourceDescription ret{};\n\n        if (resource.internalIndex == FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_COLOR)\n        {\n            Assert(g_fsr2Data->m_color, \"Color input hasn't been set.\");\n            auto desc = g_fsr2Data->m_color->GetDesc();\n\n            ret.type = FFX_RESOURCE_TYPE_TEXTURE2D;\n            ret.mipCount = desc.MipLevels;\n            ret.width = (uint32_t)desc.Width;\n            ret.height = (uint32_t)desc.Height;\n            ret.depth = desc.DepthOrArraySize;\n            ret.flags = FFX_RESOURCE_FLAGS_NONE;\n\n            return ret;\n        }\n        else if (resource.internalIndex == FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_DEPTH)\n        {\n            Assert(g_fsr2Data->m_depth, \"Depth buffer input hasn't been set.\");\n            auto desc = g_fsr2Data->m_depth->GetDesc();\n\n            ret.type = FFX_RESOURCE_TYPE_TEXTURE2D;\n            ret.mipCount = desc.MipLevels;\n            ret.width = (uint32_t)desc.Width;\n            ret.height = (uint32_t)desc.Height;\n            ret.depth = desc.DepthOrArraySize;\n            ret.flags = FFX_RESOURCE_FLAGS_NONE;\n\n            return ret;\n        }\n        else if (resource.internalIndex == FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS)\n        {\n            Assert(g_fsr2Data->m_motionVec, \"Motion vector input hasn't been set.\");\n            auto desc = g_fsr2Data->m_motionVec->GetDesc();\n\n            ret.type = FFX_RESOURCE_TYPE_TEXTURE2D;\n            ret.mipCount = desc.MipLevels;\n            ret.width = (uint32_t)desc.Width;\n            ret.height = (uint32_t)desc.Height;\n            ret.depth = desc.DepthOrArraySize;\n            ret.flags = FFX_RESOURCE_FLAGS_NONE;\n\n            return ret;\n        }\n        else if (resource.internalIndex == FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_EXPOSURE)\n        {\n            Assert(g_fsr2Data->m_exposure, \"Exposure input hasn't been set.\");\n            auto desc = g_fsr2Data->m_exposure->GetDesc();\n\n            ret.type = FFX_RESOURCE_TYPE_TEXTURE2D;\n            ret.mipCount = desc.MipLevels;\n            ret.width = (uint32_t)desc.Width;\n            ret.height = (uint32_t)desc.Height;\n            ret.depth = desc.DepthOrArraySize;\n            ret.flags = FFX_RESOURCE_FLAGS_NONE;\n\n            return ret;\n        }\n\n        if (g_fsr2Data->m_textures[resource.internalIndex].IsInitialized())\n        {\n            auto desc = g_fsr2Data->m_textures[resource.internalIndex].Desc();\n\n            ret.type = desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D ? FFX_RESOURCE_TYPE_TEXTURE2D : FFX_RESOURCE_TYPE_TEXTURE3D;\n            ret.mipCount = desc.MipLevels;\n            ret.width = (uint32_t)desc.Width;\n            ret.height = (uint32_t)desc.Height;\n            ret.depth = desc.DepthOrArraySize;\n            ret.flags = FFX_RESOURCE_FLAGS_NONE;\n        }\n        else if (g_fsr2Data->m_defaultHeapBuffs[resource.internalIndex].IsInitialized())\n        {\n            auto desc = g_fsr2Data->m_defaultHeapBuffs[resource.internalIndex].Desc();\n\n            ret.type = FFX_RESOURCE_TYPE_BUFFER;\n            ret.mipCount = desc.MipLevels;\n            ret.width = (uint32_t)desc.Width;\n            ret.height = (uint32_t)desc.Height;\n            ret.depth = desc.DepthOrArraySize;\n            ret.flags = FFX_RESOURCE_FLAGS_NONE;\n        }\n        else\n            Assert(false, \"Resource not found.\");\n\n        return ret;\n    }\n\n    FfxErrorCode Fsr2DestroyResource(FfxFsr2Interface* backendInterface, FfxResourceInternal resource)\n    {\n        Assert(resource.internalIndex < FFX_FSR2_RESOURCE_IDENTIFIER_COUNT, \"Unknown resource idx\");\n\n        if (g_fsr2Data->m_textures[resource.internalIndex].IsInitialized())\n            g_fsr2Data->m_textures[resource.internalIndex].Reset();\n        else if (g_fsr2Data->m_defaultHeapBuffs[resource.internalIndex].IsInitialized())\n            g_fsr2Data->m_defaultHeapBuffs[resource.internalIndex].Reset();\n        else if (g_fsr2Data->m_uploadHeapBuffs[resource.internalIndex].IsInitialized())\n            g_fsr2Data->m_uploadHeapBuffs[resource.internalIndex].Reset();\n\n        return FFX_OK;\n    }\n\n    FfxErrorCode Fsr2CreatePipeline(FfxFsr2Interface* backendInterface, FfxFsr2Pass pass,\n        const FfxPipelineDescription* psoDesc, FfxPipelineState* outPipeline)\n    {\n        Assert(pass < FfxFsr2Pass::FFX_FSR2_PASS_COUNT, \"Invalid FSR2 pass\");\n        Assert(psoDesc->samplerCount <= FSR2_Data::MAX_SAMPLERS, \"Number of static samplers exceeded maximum.\");\n        Assert(psoDesc->rootConstantBufferCount <= FSR2_Data::MAX_NUM_CONST_BUFFERS, \"Number of constant buffers exceeded maximum\");\n\n        if (g_fsr2Data->m_passes[pass].PSO && g_fsr2Data->m_passes[pass].RootSig)\n        {\n            outPipeline->pipeline = g_fsr2Data->m_passes[pass].PSO;\n            return FFX_OK;\n        }\n\n        uint32_t flags = 0;\n        flags |= FSR2_SHADER_PERMUTATION_HDR_COLOR_INPUT;\n        flags |= FSR2_SHADER_PERMUTATION_LOW_RES_MOTION_VECTORS;\n        flags |= FSR2_SHADER_PERMUTATION_DEPTH_INVERTED;\n        flags |= FSR2_SHADER_PERMUTATION_USE_LANCZOS_TYPE;\n        flags |= FSR2_SHADER_PERMUTATION_ALLOW_FP16;\n\n        // load shader blob\n        Fsr2ShaderBlobDX12 shaderBlob = g_fsr2Data->m_dll.FpGetShaderPermutation(pass, flags);\n        Assert(shaderBlob.data && shaderBlob.size > 0, \"Retrieving FSR2 shader failed.\");\n\n        // static samplers\n        if (!g_fsr2Data->m_passes[pass].RootSig.Get())\n        {\n            D3D12_STATIC_SAMPLER_DESC samplers[FSR2_Data::MAX_SAMPLERS];\n\n            const D3D12_STATIC_SAMPLER_DESC pointClampSamplerDesc\n            {\n                D3D12_FILTER_MIN_MAG_MIP_POINT,\n                D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n                D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n                D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n                0,\n                16,\n                D3D12_COMPARISON_FUNC_NEVER,\n                D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK,\n                0.f,\n                D3D12_FLOAT32_MAX,\n                2, // s2\n                0,\n                D3D12_SHADER_VISIBILITY_ALL,\n            };\n\n            const D3D12_STATIC_SAMPLER_DESC linearClampSamplerDesc\n            {\n                D3D12_FILTER_MIN_MAG_MIP_LINEAR,\n                D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n                D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n                D3D12_TEXTURE_ADDRESS_MODE_CLAMP,\n                0,\n                16,\n                D3D12_COMPARISON_FUNC_NEVER,\n                D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK,\n                0.f,\n                D3D12_FLOAT32_MAX,\n                3, // s3\n                0,\n                D3D12_SHADER_VISIBILITY_ALL,\n            };\n\n            for (uint32_t currentSamplerIndex = 0; currentSamplerIndex < psoDesc->samplerCount; ++currentSamplerIndex)\n            {\n                samplers[currentSamplerIndex] = psoDesc->samplers[currentSamplerIndex] == FFX_FILTER_TYPE_POINT ?\n                    pointClampSamplerDesc :\n                    linearClampSamplerDesc;\n                samplers[currentSamplerIndex].ShaderRegister = currentSamplerIndex;\n            }\n\n            // root signature\n            // param[0] --> UAV desc. table of size FFX_FSR2_RESOURCE_IDENTIFIER_COUNT\n            // param[1] --> SRV desc. table of size FFX_FSR2_RESOURCE_IDENTIFIER_COUNT\n            D3D12_ROOT_PARAMETER rootParams[FSR2_Data::MAX_ROOT_PARAMS];\n            D3D12_DESCRIPTOR_RANGE descRange[FSR2_Data::MAX_DESC_RANGES];\n\n            // UAV desc. table\n            descRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;\n            descRange[0].NumDescriptors = FFX_FSR2_RESOURCE_IDENTIFIER_COUNT;\n            descRange[0].BaseShaderRegister = 0;\n            descRange[0].RegisterSpace = 0;\n            descRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;\n\n            // SRV desc. table\n            descRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;\n            descRange[1].NumDescriptors = FFX_FSR2_RESOURCE_IDENTIFIER_COUNT;\n            descRange[1].BaseShaderRegister = 0;\n            descRange[1].RegisterSpace = 0;\n            descRange[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;\n\n            // root params\n            int currRootParam = 0;\n\n            rootParams[currRootParam].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;\n            rootParams[currRootParam].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;\n            rootParams[currRootParam].DescriptorTable.NumDescriptorRanges = 1;\n            rootParams[currRootParam].DescriptorTable.pDescriptorRanges = &descRange[0];\n            currRootParam++;\n\n            rootParams[currRootParam].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;\n            rootParams[currRootParam].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;\n            rootParams[currRootParam].DescriptorTable.NumDescriptorRanges = 1;\n            rootParams[currRootParam].DescriptorTable.pDescriptorRanges = &descRange[1];\n            currRootParam++;\n\n            for (uint32_t currRootConstantIdx = 0; currRootConstantIdx < psoDesc->rootConstantBufferCount; ++currRootConstantIdx)\n            {\n                rootParams[currRootParam].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;\n                rootParams[currRootParam].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;\n                rootParams[currRootParam].Constants.Num32BitValues = psoDesc->rootConstantBufferSizes[currRootConstantIdx];\n                rootParams[currRootParam].Constants.ShaderRegister = currRootConstantIdx;\n                rootParams[currRootParam].Constants.RegisterSpace = 0;\n\n                currRootParam++;\n            }\n\n            D3D12_ROOT_SIGNATURE_DESC rootSigDesc;\n            rootSigDesc.NumParameters = currRootParam;\n            rootSigDesc.pParameters = rootParams;\n            rootSigDesc.NumStaticSamplers = (UINT)psoDesc->samplerCount;\n            rootSigDesc.pStaticSamplers = samplers;\n            rootSigDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;\n\n            ComPtr<ID3DBlob> outBlob, errorBlob;\n            HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1_0, outBlob.GetAddressOf(), errorBlob.GetAddressOf());\n            Check(SUCCEEDED(hr), \"D3D12SerializeVersionedRootSignature() failed: %s\", (char*)errorBlob->GetBufferPointer());\n\n            auto* device = App::GetRenderer().GetDevice();\n            CheckHR(device->CreateRootSignature(0, outBlob->GetBufferPointer(), outBlob->GetBufferSize(),\n                IID_PPV_ARGS(g_fsr2Data->m_passes[pass].RootSig.GetAddressOf())));\n        }\n\n        // output\n        outPipeline->rootSignature = g_fsr2Data->m_passes[pass].RootSig.Get();\n        outPipeline->uavCount = shaderBlob.uavCount;\n        outPipeline->srvCount = shaderBlob.srvCount;\n        outPipeline->constCount = shaderBlob.cbvCount;\n\n        int maxSrvSlot = -1;\n\n        for (uint32_t srvIndex = 0; srvIndex < outPipeline->srvCount; ++srvIndex)\n        {\n            outPipeline->srvResourceBindings[srvIndex].slotIndex = shaderBlob.boundSRVResources[srvIndex];\n\n            wchar_t buff[128];\n            Common::CharToWideStr(shaderBlob.boundSRVResourceNames[srvIndex], buff);\n            wcscpy_s(outPipeline->srvResourceBindings[srvIndex].name, buff);\n\n            maxSrvSlot = Math::Max(maxSrvSlot, (int)shaderBlob.boundSRVResources[srvIndex]);\n        }\n\n        if (maxSrvSlot >= 0)\n            g_fsr2Data->m_passes[pass].SrvTableGpuNumDescs = maxSrvSlot + 1;\n        //g_fsr2Data->m_passes[pass].SrvTableGpu = App::GetRenderer().GetCbvSrvUavDescriptorHeapGpu().Allocate(maxSrvSlot + 1);\n\n        int maxUavSlot = -1;\n\n        for (uint32_t uavIndex = 0; uavIndex < outPipeline->uavCount; ++uavIndex)\n        {\n            outPipeline->uavResourceBindings[uavIndex].slotIndex = shaderBlob.boundUAVResources[uavIndex];\n\n            wchar_t buff[128];\n            Common::CharToWideStr(shaderBlob.boundUAVResourceNames[uavIndex], buff);\n            wcscpy_s(outPipeline->uavResourceBindings[uavIndex].name, buff);\n\n            maxUavSlot = Math::Max(maxUavSlot, (int)shaderBlob.boundUAVResources[uavIndex]);\n        }\n\n        if (maxUavSlot >= 0)\n            g_fsr2Data->m_passes[pass].UavTableGpuNumDescs = maxUavSlot + 1;\n        //g_fsr2Data->m_passes[pass].UavTableGpu = App::GetRenderer().GetCbvSrvUavDescriptorHeapGpu().Allocate(maxUavSlot + 1);\n\n        for (uint32_t cbIndex = 0; cbIndex < outPipeline->constCount; ++cbIndex)\n        {\n            outPipeline->cbResourceBindings[cbIndex].slotIndex = shaderBlob.boundCBVResources[cbIndex];\n\n            wchar_t buff[128];\n            Common::CharToWideStr(shaderBlob.boundCBVResourceNames[cbIndex], buff);\n            wcscpy_s(outPipeline->cbResourceBindings[cbIndex].name, buff);\n        }\n\n        // check if PSO already exists in PSO lib\n        g_fsr2Data->m_passes[pass].PSO = g_fsr2Data->m_psoLib.CompileComputePSO(pass,\n            g_fsr2Data->m_passes[pass].RootSig.Get(),\n            MutableSpan(shaderBlob.data, shaderBlob.size));\n\n        // to figure out each PSO corresponds to which pass\n        Assert(g_fsr2Data->m_currMapIdx < FFX_FSR2_PASS_COUNT, \"Invalid pass idx\");\n        g_fsr2Data->m_psoToPassMap[g_fsr2Data->m_currMapIdx++] = PsoMap{ .PSO = g_fsr2Data->m_passes[pass].PSO, .Pass = pass };\n\n        outPipeline->pipeline = g_fsr2Data->m_passes[pass].PSO;\n\n        return FFX_OK;\n    }\n\n    FfxErrorCode Fsr2DestroyPipeline(FfxFsr2Interface* backendInterface, FfxPipelineState* pipeline)\n    {\n        return FFX_OK;\n    }\n\n    FfxErrorCode Fsr2ScheduleGpuJob(FfxFsr2Interface* backendInterface,\n        const FfxGpuJobDescription* job)\n    {\n        switch (job->jobType)\n        {\n        case FFX_GPU_JOB_CLEAR_FLOAT:\n            RecordClearJob(job->clearJobDescriptor);\n            break;\n        case FFX_GPU_JOB_COMPUTE:\n            RecordComputeJob(job->computeJobDescriptor);\n            break;\n        default:\n            Assert(false, \"Copy job should not reach here.\");\n            break;\n        }\n\n        return FFX_OK;\n    }\n\n    FfxErrorCode Fsr2ExecuteGpuJobs(FfxFsr2Interface* backendInterface, FfxCommandList commandList)\n    {\n        return FFX_OK;\n    }\n\n    /*    void LogMsg(FfxFsr2MsgType type, const wchar_t* message)\n        {\n            char msga[512];\n            Common::WideToCharStr(message, msga);\n            LOG_UI_WARNING(\"FSR2 [%s]: %s\", type == FFX_FSR2_MESSAGE_TYPE_ERROR ? \"Error\" : \"Warning\", msga);\n        }*/\n}\n\n#ifndef NDEBUG  \n#ifndef CheckFSR\n#define CheckFSR(x)                                                                                                                     \\\n    {                                                                                                                                   \\\n        FfxErrorCode err = (x);                                                                                                         \\\n        if (err != FFX_OK)                                                                                                              \\\n        {                                                                                                                               \\\n            char buff[256];                                                                                                             \\\n            stbsp_snprintf(buff, 256, \"%s: %d\\nFSR call %s\\n failed with error:\\n%s\", __FILE__,  __LINE__, #x, GetFsrErrorMsg(err));    \\\n            MessageBoxA(nullptr, buff, \"Fatal Error\", MB_ICONERROR | MB_OK);                                                            \\\n            __debugbreak();                                                                                                             \\\n        }                                                                                                                               \\\n    }\n#endif\n#else\n#ifndef CheckFSR\n#define CheckFSR(x)                                                                                                                     \\\n    {                                                                                                                                   \\\n        FfxErrorCode err = (x);                                                                                                         \\\n        if (err != FFX_OK)                                                                                                              \\\n        {                                                                                                                               \\\n            char buff[256];                                                                                                             \\\n            stbsp_snprintf(buff, 256, \"%s: %d\\nFSR call %s\\n failed with error:\\n%s\", __FILE__,  __LINE__, #x, GetFsrErrorMsg(err));    \\\n            MessageBoxA(nullptr, buff, \"Fatal Error\", MB_ICONERROR | MB_OK);                                                            \\\n            exit(EXIT_FAILURE);                                                                                                         \\\n        }                                                                                                                               \\\n    }\n#endif\n#endif\n\n//--------------------------------------------------------------------------------------\n// FSR2\n//--------------------------------------------------------------------------------------\n\nFSR2Pass::~FSR2Pass()\n{\n    Reset();\n}\n\nvoid FSR2Pass::Init()\n{\n    Assert(!g_fsr2Data, \"attempting to double-init.\");\n    Assert(!m_initialized, \"attempting to double-init.\");\n\n    auto& renderer = App::GetRenderer();\n    const int dw = renderer.GetDisplayWidth();\n    const int dh = renderer.GetDisplayHeight();\n\n    m_initialized = false;\n    m_displayWidth = (uint16_t)dw;\n    m_displayHeight = (uint16_t)dh;\n}\n\nvoid FSR2Pass::Activate()\n{\n    Assert(!g_fsr2Data, \"attempting to double-init.\");\n    Assert(!m_initialized, \"attempting to double-init.\");\n\n    g_fsr2Data = new FSR2_Data;\n\n    auto& renderer = App::GetRenderer();\n\n    FfxFsr2Interface fsr2Interface;\n    fsr2Interface.fpCreateBackendContext = Fsr2CreateBackendContext;\n    fsr2Interface.fpGetDeviceCapabilities = Fsr2GetDeviceCapabilities;\n    fsr2Interface.fpDestroyBackendContext = Fsr2DestroyBackendContext;\n    fsr2Interface.fpCreateResource = Fsr2CreateResource;\n    fsr2Interface.fpRegisterResource = Fsr2RegisterResource;\n    fsr2Interface.fpUnregisterResources = Fsr2UnregisterResources;\n    fsr2Interface.fpGetResourceDescription = Fsr2GetResourceDescription;\n    fsr2Interface.fpDestroyResource = Fsr2DestroyResource;\n    fsr2Interface.fpCreatePipeline = Fsr2CreatePipeline;\n    fsr2Interface.fpDestroyPipeline = Fsr2DestroyPipeline;\n    fsr2Interface.fpScheduleGpuJob = Fsr2ScheduleGpuJob;\n    fsr2Interface.fpExecuteGpuJobs = Fsr2ExecuteGpuJobs;\n    fsr2Interface.scratchBuffer = nullptr;\n    fsr2Interface.scratchBufferSize = 0;\n\n    FfxFsr2ContextDescription ctxDesc;\n    ctxDesc.flags = g_fsr2Data->FLAGS;\n    ctxDesc.maxRenderSize.width = renderer.GetRenderWidth();\n    ctxDesc.maxRenderSize.height = renderer.GetRenderHeight();\n    ctxDesc.displaySize.width = renderer.GetDisplayWidth();\n    ctxDesc.displaySize.height = renderer.GetDisplayHeight();\n    ctxDesc.callbacks = fsr2Interface;\n    ctxDesc.device = App::GetRenderer().GetDevice();\n    //ctxDesc.fpMessage = LogMsg;\n    ctxDesc.fpMessage = nullptr;\n\n    // initialize the PSO library (must be called before ffxFsr2ContextCreate)\n    memset(g_fsr2Data->m_psoToPassMap, 0, sizeof(PsoMap) * FFX_FSR2_PASS_COUNT);\n    g_fsr2Data->m_psoLib.Init(\"FSR2\");\n\n    g_fsr2Data->m_dll.Load();\n\n    CheckFSR(g_fsr2Data->m_dll.FpCreate(&g_fsr2Data->m_ctx, &ctxDesc));\n\n    // upscaled output texture\n    Assert(!g_fsr2Data->m_textures[FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT].IsInitialized(), \"Output is app-controlled.\");\n    g_fsr2Data->m_textures[FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT] = GpuMemory::GetTexture2D(\"UpscaledColor\",\n        m_displayWidth,\n        m_displayHeight,\n        DXGI_FORMAT_R16G16B16A16_FLOAT,\n        D3D12_RESOURCE_STATE_COMMON,\n        TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n    // render graph performs the transition to UAV prior to recording\n    g_fsr2Data->m_resData[FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT].State = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;\n\n    const int rw = renderer.GetRenderWidth();\n    const int rh = renderer.GetRenderHeight();\n    g_fsr2Data->m_rasterDepth.Resize(rw, rh);\n\n    Assert(g_fsr2Data->m_currMapIdx == FFX_FSR2_PASS_COUNT, \"Unaccounted PSOs.\");\n    std::sort(g_fsr2Data->m_psoToPassMap, g_fsr2Data->m_psoToPassMap + FFX_FSR2_PASS_COUNT,\n        [](const PsoMap& p1, const PsoMap& p2)\n        {\n            return p1.PSO < p2.PSO;\n        });\n\n    m_initialized = true;\n}\n\nvoid FSR2Pass::OnWindowResized()\n{\n    Assert(IsInitialized(), \"FSR2 backend hasn't been initialized.\");\n\n    auto& renderer = App::GetRenderer();\n    const int dw = renderer.GetDisplayWidth();\n    const int dh = renderer.GetDisplayHeight();\n\n    if (dw == m_displayWidth && dh == m_displayHeight)\n        return;\n\n    Reset();\n    Init();\n}\n\nvoid FSR2Pass::Reset()\n{\n    if (IsInitialized())\n    {\n        //CheckFSR(ffxFsr2ContextDestroy(&g_fsr2Data->m_ctx));\n        CheckFSR(g_fsr2Data->m_dll.FpDestroy(&g_fsr2Data->m_ctx));\n        g_fsr2Data->m_dll.Free();\n\n        // make sure GPU is finished with related resources before deleting the data\n        Task t(\"DestructWithGuard for FSR2 context\", TASK_PRIORITY::BACKGROUND, [res = g_fsr2Data]()\n            {\n                ComPtr<ID3D12Fence> fenceDirect;\n                ComPtr<ID3D12Fence> fenceCompute;\n\n                auto* device = App::GetRenderer().GetDevice();\n                CheckHR(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fenceDirect.GetAddressOf())));\n                CheckHR(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fenceCompute.GetAddressOf())));\n\n                App::GetRenderer().SignalComputeQueue(fenceCompute.Get(), 1);\n                App::GetRenderer().SignalDirectQueue(fenceDirect.Get(), 1);\n\n                HANDLE handleCompute = CreateEventA(nullptr, false, false, nullptr);\n                CheckWin32(handleCompute);\n                HANDLE handleDirect = CreateEventA(nullptr, false, false, nullptr);\n                CheckWin32(handleDirect);\n\n                CheckHR(fenceCompute->SetEventOnCompletion(1, handleCompute));\n                CheckHR(fenceDirect->SetEventOnCompletion(1, handleDirect));\n\n                HANDLE handles[] = { handleCompute, handleDirect };\n\n                WaitForMultipleObjects(2, handles, true, INFINITE);\n                CloseHandle(handleDirect);\n                CloseHandle(handleCompute);\n\n                // safe to release, no need to wait\n                for (int i = 0; i < FFX_FSR2_RESOURCE_IDENTIFIER_COUNT; i++)\n                    res->m_textures[i].Reset(false);\n\n                delete res;\n            });\n\n        App::SubmitBackground(ZetaMove(t));\n\n        g_fsr2Data = nullptr;\n        m_initialized = false;\n    }\n}\n\nvoid FSR2Pass::Render(CommandList& cmdList)\n{\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT ||\n        cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE, \"Invalid downcast\");\n\n    ComputeCmdList& computeCmdList = static_cast<ComputeCmdList&>(cmdList);\n\n    Assert(m_inputResources[(int)SHADER_IN_RES::COLOR], \"Color input res hasn't been set.\");\n    Assert(m_inputResources[(int)SHADER_IN_RES::DEPTH], \"Depth buffer res hasn't been set.\");\n    Assert(m_inputResources[(int)SHADER_IN_RES::MOTION_VECTOR], \"Motion vectors res hasn't been set.\");\n    Assert(m_inputResources[(int)SHADER_IN_RES::EXPOSURE], \"Exposure res hasn't been set.\");\n\n    computeCmdList.PIXBeginEvent(\"FSR2\");\n\n    g_fsr2Data->m_cmdList = &static_cast<ComputeCmdList&>(cmdList);\n    g_fsr2Data->m_color = m_inputResources[(int)SHADER_IN_RES::COLOR];\n    g_fsr2Data->m_depth = g_fsr2Data->m_rasterDepth.m_depthBuffer.Resource();\n    g_fsr2Data->m_motionVec = m_inputResources[(int)SHADER_IN_RES::MOTION_VECTOR];\n    g_fsr2Data->m_exposure = m_inputResources[(int)SHADER_IN_RES::EXPOSURE];\n\n    auto func = [](ID3D12Resource* res, DescriptorTable& descTable)\n        {\n            auto* device = App::GetRenderer().GetDevice();\n            auto desc = res->GetDesc();\n\n            //if(descTable.IsEmpty())\n            descTable = App::GetRenderer().GetCbvSrvUavDescriptorHeapCpu().Allocate(1);\n\n            D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc{};\n            srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;\n            srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;\n            srvDesc.Texture2D.MostDetailedMip = 0;\n            srvDesc.Texture2D.PlaneSlice = 0;\n            srvDesc.Texture2D.ResourceMinLODClamp = 0;\n            srvDesc.Texture2D.MipLevels = desc.MipLevels;\n            srvDesc.Format = desc.Format == DXGI_FORMAT_D32_FLOAT ? DXGI_FORMAT_R32_FLOAT : desc.Format;\n\n            device->CreateShaderResourceView(res, &srvDesc, descTable.CPUHandle(0));\n        };\n\n    func(g_fsr2Data->m_color, g_fsr2Data->m_resData[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_COLOR].SrvAllMipsCpu);\n    func(g_fsr2Data->m_depth, g_fsr2Data->m_resData[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_DEPTH].SrvAllMipsCpu);\n    func(g_fsr2Data->m_motionVec, g_fsr2Data->m_resData[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS].SrvAllMipsCpu);\n    func(g_fsr2Data->m_exposure, g_fsr2Data->m_resData[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_EXPOSURE].SrvAllMipsCpu);\n\n    g_fsr2Data->m_resData[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_COLOR].State = D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;\n    g_fsr2Data->m_resData[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_DEPTH].State = D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;\n    g_fsr2Data->m_resData[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS].State = D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;\n    g_fsr2Data->m_resData[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_EXPOSURE].State = D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;\n    // render graph performs the transition to UAV prior to recording\n    g_fsr2Data->m_resData[FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT].State = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;\n\n    const auto& camera = App::GetCamera();\n\n    FfxFsr2DispatchDescription params{};\n    params.color.resource = g_fsr2Data->m_color;\n    params.color.state = FFX_RESOURCE_STATE_COMPUTE_READ;\n    params.depth.resource = g_fsr2Data->m_depth;\n    params.depth.state = FFX_RESOURCE_STATE_COMPUTE_READ;\n    params.depth.isDepth = true;\n    params.motionVectors.resource = g_fsr2Data->m_motionVec;\n    params.motionVectors.state = FFX_RESOURCE_STATE_COMPUTE_READ;\n    params.output.resource = g_fsr2Data->m_textures[FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT].Resource();\n    params.output.state = FFX_RESOURCE_STATE_UNORDERED_ACCESS;\n    params.exposure.resource = g_fsr2Data->m_exposure;\n    params.exposure.state = FFX_RESOURCE_STATE_COMPUTE_READ;\n    params.jitterOffset.x = -camera.GetCurrJitter().x;\n    params.jitterOffset.y = -camera.GetCurrJitter().y;\n    params.cameraNear = FLT_MAX;\n    params.cameraFar = camera.GetNearZ();\n    params.cameraFovAngleVertical = camera.GetFOV();\n    params.motionVectorScale.x = -(float)App::GetRenderer().GetRenderWidth();\n    params.motionVectorScale.y = -(float)App::GetRenderer().GetRenderHeight();\n    params.reset = g_fsr2Data->m_reset;\n    params.enableSharpening = false;\n    params.sharpness = 0.0f;\n    params.frameTimeDelta = (float)(App::GetTimer().GetElapsedTime() * 1000);\n    params.preExposure = 1.0f;\n    params.renderSize.width = App::GetRenderer().GetRenderWidth();\n    params.renderSize.height = App::GetRenderer().GetRenderHeight();\n    params.viewSpaceToMetersFactor = 1.0f;\n\n    g_fsr2Data->m_reset = false;\n\n    auto& gpuTimer = App::GetRenderer().GetGpuTimer();\n\n    // record the timestamp prior to execution\n    const uint32_t queryIdx = gpuTimer.BeginQuery(*g_fsr2Data->m_cmdList, \"FSR2\");\n\n    g_fsr2Data->m_rasterDepth.Render(*g_fsr2Data->m_cmdList);\n\n    //CheckFSR(ffxFsr2ContextDispatch(&g_fsr2Data->m_ctx, &params));\n    CheckFSR(g_fsr2Data->m_dll.FpDispatch(&g_fsr2Data->m_ctx, &params));\n\n    // record the timestamp after execution\n    gpuTimer.EndQuery(*g_fsr2Data->m_cmdList, queryIdx);\n\n    g_fsr2Data->m_cmdList = nullptr;\n\n    for (int i = 0; i < FFX_FSR2_RESOURCE_IDENTIFIER_COUNT; i++)\n    {\n        // clear the UAV barrier flags\n        g_fsr2Data->m_resData[i].NeedsUavBarrier = false;\n\n        // proper cpu-gpu sync. is done automatically\n        if (!g_fsr2Data->m_resData[i].UavAllMipsGpu.IsEmpty())\n            g_fsr2Data->m_resData[i].UavAllMipsGpu.Reset();\n\n        g_fsr2Data->m_resData[i].RecordedClearThisFrame = false;\n    }\n\n    computeCmdList.PIXEndEvent();\n}\n\nconst Texture& FSR2Pass::GetOutput(SHADER_OUT_RES res)\n{\n    Assert(g_fsr2Data, \"g_fsr2Data is NULL.\");\n    Assert(g_fsr2Data->m_textures[FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT].IsInitialized(), \"Texture hasn't been initialized.\");\n    return g_fsr2Data->m_textures[FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT];\n}"
  },
  {
    "path": "Source/ZetaRenderPass/FSR2/FSR2.h",
    "content": "#pragma once\n\n#include \"../RenderPass.h\"\n#include <Core/GpuMemory.h>\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n}\n\nnamespace ZetaRay::RenderPass\n{\n    struct FSR2Pass\n    {\n        enum class SHADER_IN_RES\n        {\n            COLOR,\n            DEPTH,\n            MOTION_VECTOR,\n            EXPOSURE,\n            COUNT\n        };\n\n        enum class SHADER_OUT_RES\n        {\n            UPSCALED,\n            COUNT\n        };\n\n        FSR2Pass() = default;\n        ~FSR2Pass();\n\n        FSR2Pass(FSR2Pass&&) = delete;\n        FSR2Pass& operator=(FSR2Pass&&) = delete;\n\n        void Init();\n        bool IsInitialized() { return m_initialized; }\n        void Activate();\n        void OnWindowResized();\n        void SetInput(SHADER_IN_RES i, ID3D12Resource* res)\n        {\n            Assert((int)i < (int)SHADER_IN_RES::COUNT, \"out-of-bound access.\");\n\n            switch (i)\n            {\n            case SHADER_IN_RES::COLOR:\n                m_inputResources[(int)SHADER_IN_RES::COLOR] = res;\n                break;\n            case SHADER_IN_RES::DEPTH:\n                m_inputResources[(int)SHADER_IN_RES::DEPTH] = res;\n                break;\n            case SHADER_IN_RES::MOTION_VECTOR:\n                m_inputResources[(int)SHADER_IN_RES::MOTION_VECTOR] = res;\n                break;\n            case SHADER_IN_RES::EXPOSURE:\n                m_inputResources[(int)SHADER_IN_RES::EXPOSURE] = res;\n                break;\n            default:\n                break;\n            }\n        }\n        const Core::GpuMemory::Texture& GetOutput(SHADER_OUT_RES res);\n\n        void Reset();\n        void Render(Core::CommandList& cmdList);\n\n    private:\n        ID3D12Resource* m_inputResources[(int)SHADER_IN_RES::COUNT] = { 0 };\n        uint16_t m_displayWidth = 0;\n        uint16_t m_displayHeight = 0;\n        bool m_initialized = false;\n    };\n}"
  },
  {
    "path": "Source/ZetaRenderPass/GBuffer/CMakeLists.txt",
    "content": "set(RP_GBUFFER_RT_DIR ${ZETA_RENDER_PASS_DIR}/GBuffer)\nset(RP_GBUFFER_RT_SRC\n    ${RP_GBUFFER_RT_DIR}/GBufferRT.cpp\n    ${RP_GBUFFER_RT_DIR}/GBufferRT.h\n    ${RP_GBUFFER_RT_DIR}/GBufferRT_Common.h\n    ${RP_GBUFFER_RT_DIR}/GBufferRT_Inline.hlsl\n    ${RP_GBUFFER_RT_DIR}/GBufferRT.hlsli\n    ${RP_GBUFFER_RT_DIR}/GenerateDepthBuffer.h\n    ${RP_GBUFFER_RT_DIR}/GenerateDepthBuffer.cpp\n    ${RP_GBUFFER_RT_DIR}/GenerateDepthBuffer.hlsl)\nset(RP_GBUFFER_RT_SRC ${RP_GBUFFER_RT_SRC} PARENT_SCOPE)\n"
  },
  {
    "path": "Source/ZetaRenderPass/GBuffer/GBufferRT.cpp",
    "content": "#include \"GBufferRT.h\"\n#include <Core/CommandList.h>\n#include <Support/Param.h>\n#include <App/Filesystem.h>\n#include <Scene/SceneCore.h>\n\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::Direct3DUtil;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::RT;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::App;\nusing namespace ZetaRay::Util;\n\n//--------------------------------------------------------------------------------------\n// GBufferRT\n//--------------------------------------------------------------------------------------\n\nGBufferRT::GBufferRT()\n    : RenderPassBase(NUM_CBV, NUM_SRV, NUM_UAV, NUM_GLOBS, NUM_CONSTS)\n{\n    // frame constants\n    m_rootSig.InitAsCBV(0, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::FRAME_CONSTANTS_BUFFER);\n\n    // root constants\n    m_rootSig.InitAsConstants(1, NUM_CONSTS, 1);\n\n    // BVH\n    m_rootSig.InitAsBufferSRV(2, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::RT_SCENE_BVH_CURR);\n\n    // mesh buffer\n    m_rootSig.InitAsBufferSRV(3, 1, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::RT_FRAME_MESH_INSTANCES_CURR);\n\n    // scene VB\n    m_rootSig.InitAsBufferSRV(4, 2, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::SCENE_VERTEX_BUFFER);\n\n    // scene IB\n    m_rootSig.InitAsBufferSRV(5, 3, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::SCENE_INDEX_BUFFER);\n\n    // material buffer\n    m_rootSig.InitAsBufferSRV(6, 4, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::MATERIAL_BUFFER);\n\n    // pick buffer\n    m_rootSig.InitAsBufferUAV(7, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_VOLATILE, nullptr, true);\n}\n\nvoid GBufferRT::InitPSOs()\n{\n    constexpr D3D12_ROOT_SIGNATURE_FLAGS flags =\n        D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;\n\n    auto samplers = App::GetRenderer().GetStaticSamplers();\n    RenderPassBase::InitRenderPass(\"GBuffer\", flags, samplers);\n\n    for (int i = 0; i < (int)GBUFFER_SHADER::COUNT; i++)\n        m_psoLib.CompileComputePSO(i, m_rootSigObj.Get(), COMPILED_CS[i]);\n}\n\nvoid GBufferRT::Init()\n{\n    InitPSOs();\n\n    memset(&m_cbLocal, 0, sizeof(m_cbLocal));\n    m_cbLocal.PickedPixelX = UINT16_MAX;\n\n    //ParamVariant p1;\n    //p1.InitEnum(\"Renderer\", \"G-Buffer\", \"Mipmap Selection\", fastdelegate::MakeDelegate(this, &GBufferRT::MipmapSelectionCallback),\n    //    DefaultParamVals::TextureFilter, (int)TextureFilter::COUNT, m_localCB.MipmapSelection);\n    //App::AddParam(p1);\n\n    m_pickedInstance = GpuMemory::GetDefaultHeapBuffer(\"PickIdx\", sizeof(uint32), false, true);\n    m_readbackBuffer = GpuMemory::GetReadbackHeapBuffer(sizeof(uint32));\n\n    App::AddShaderReloadHandler(\"GBuffer\", fastdelegate::MakeDelegate(this, &GBufferRT::ReloadShader));\n}\n\nvoid GBufferRT::Render(CommandList& cmdList)\n{\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT ||\n        cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE, \"Invalid downcast\");\n    ComputeCmdList& computeCmdList = static_cast<ComputeCmdList&>(cmdList);\n\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n    const uint32_t w = renderer.GetRenderWidth();\n    const uint32_t h = renderer.GetRenderHeight();\n\n    computeCmdList.PIXBeginEvent(\"G-Buffer\");\n    const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"G-Buffer\");\n\n    computeCmdList.SetRootSignature(m_rootSig, m_rootSigObj.Get());\n\n    const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, GBUFFER_RT_GROUP_DIM_X);\n    const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, GBUFFER_RT_GROUP_DIM_Y);\n\n    m_cbLocal.DispatchDimX = (uint16_t)dispatchDimX;\n    m_cbLocal.DispatchDimY = (uint16_t)dispatchDimY;\n    m_cbLocal.NumGroupsInTile = GBUFFER_RT_TILE_WIDTH * m_cbLocal.DispatchDimY;\n\n    const bool hasPick = m_cbLocal.PickedPixelX != UINT16_MAX;\n\n    if (hasPick)\n    {\n        auto barrier = BufferBarrier(m_pickedInstance.Resource(),\n            D3D12_BARRIER_SYNC_NONE,\n            D3D12_BARRIER_SYNC_COMPUTE_SHADING,\n            D3D12_BARRIER_ACCESS_NO_ACCESS,\n            D3D12_BARRIER_ACCESS_UNORDERED_ACCESS);\n        computeCmdList.ResourceBarrier(barrier);\n\n        m_rootSig.SetRootUAV(7, m_pickedInstance.GpuVA());\n    }\n\n    m_rootSig.SetRootConstants(0, sizeof(m_cbLocal) / sizeof(DWORD), &m_cbLocal);\n    m_rootSig.End(computeCmdList);\n\n    computeCmdList.SetPipelineState(m_psoLib.GetPSO(0));\n    computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n\n    if (hasPick)\n    {\n        auto syncWrite = BufferBarrier(m_pickedInstance.Resource(),\n            D3D12_BARRIER_SYNC_COMPUTE_SHADING,\n            D3D12_BARRIER_SYNC_COPY,\n            D3D12_BARRIER_ACCESS_UNORDERED_ACCESS,\n            D3D12_BARRIER_ACCESS_COPY_SOURCE);\n        computeCmdList.ResourceBarrier(syncWrite);\n\n        computeCmdList.CopyBufferRegion(m_readbackBuffer.Resource(),\n            0,\n            m_pickedInstance.Resource(),\n            0,\n            sizeof(uint32));\n    }\n\n    gpuTimer.EndQuery(computeCmdList, queryIdx);\n    cmdList.PIXEndEvent();\n}\n\nvoid GBufferRT::ReloadShader()\n{\n    m_psoLib.Reload((int)GBUFFER_SHADER::GBUFFER, m_rootSigObj.Get(), \n        \"GBuffer\\\\GBufferRT_Inline.hlsl\");\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/GBuffer/GBufferRT.h",
    "content": "#pragma once\n\n#include \"../RenderPass.h\"\n#include <Core/GpuMemory.h>\n#include \"GBufferRT_Common.h\"\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n}\n\nnamespace ZetaRay::Support\n{\n    struct ParamVariant;\n}\n\nnamespace ZetaRay::RenderPass\n{\n    enum class GBUFFER_SHADER\n    {\n        GBUFFER,\n        COUNT\n    };\n\n    struct GBufferRT : public RenderPassBase<(int)GBUFFER_SHADER::COUNT>\n    {\n        GBufferRT();\n        ~GBufferRT() = default;\n\n        GBufferRT(GBufferRT&&) = delete;\n        GBufferRT& operator=(GBufferRT&&) = delete;\n\n        void InitPSOs();\n        void Init();\n        void SetGBufferUavDescTableGpuHeapIdx(uint32_t descHeapIdx) { m_cbLocal.UavTableDescHeapIdx = descHeapIdx; }\n        ZetaInline void PickPixel(uint16 pixelX, uint16 pixelY)\n        {\n            m_cbLocal.PickedPixelX = pixelX;\n            m_cbLocal.PickedPixelY = pixelY;\n        }\n        ZetaInline bool HasPendingPick() const { return m_cbLocal.PickedPixelX != UINT16_MAX; }\n        ZetaInline void ClearPick()\n        {\n            m_cbLocal.PickedPixelX = UINT16_MAX;\n        }\n        Core::GpuMemory::ReadbackHeapBuffer& GetPickReadbackBuffer() { return m_readbackBuffer; }\n        void Render(Core::CommandList& cmdList);\n\n    private:\n        static constexpr int NUM_CBV = 1;\n        static constexpr int NUM_SRV = 5;\n        static constexpr int NUM_UAV = 1;\n        static constexpr int NUM_GLOBS = 6;\n        static constexpr int NUM_CONSTS = (int)(sizeof(cbGBufferRt) / sizeof(DWORD));\n\n        inline static constexpr const char* COMPILED_CS[(int)GBUFFER_SHADER::COUNT] = {\n            \"GBufferRT_Inline_cs.cso\"\n        };\n\n        void ReloadShader();\n\n        Core::GpuMemory::Buffer m_pickedInstance;\n        Core::GpuMemory::ReadbackHeapBuffer m_readbackBuffer;\n        //ComPtr<ID3D12StateObject> m_rtPSO;\n        //ShaderTable m_shaderTable;\n        cbGBufferRt m_cbLocal;\n    };\n}"
  },
  {
    "path": "Source/ZetaRenderPass/GBuffer/GBufferRT.hlsli",
    "content": "#include \"GBufferRT_Common.h\"\n#include \"../Common/FrameConstants.h\"\n#include \"../Common/StaticTextureSamplers.hlsli\"\n#include \"../Common/GBuffers.hlsli\"\n#include \"../Common/RT.hlsli\"\n\nnamespace GBufferRT\n{\n    // Rate of change of texture uv coordinates w.r.t. screen space\n    // Ref: M. Pharr, W. Jakob, and G. Humphreys, Physically Based Rendering, Morgan Kaufmann, 2016.\n    float4 UVDifferentials(int2 DTid, float3 origin, float3 dir, float2 jitter, \n        bool thinLens, float2 lensSample, float focusDepth, float t, float3 dpdu, \n        float3 dpdv, ConstantBuffer<cbFrameConstants> g_frame)\n    {\n        // 1. Form auxiliary rays offset one pixel to right and above of camera ray (r_x and r_y).\n        // 2. Form tangent plane at hit point (P).\n        // 3. Approximae surface around hit point using a first-order approximation at P. Hit \n        //    points for auxiliary rays can be solved for using the ray-plane intersection \n        //    algorithm (denote by p_x and p_y).\n        // 4. Each triangle can be described as a parametric surface p = f(u, v). Since triangle \n        //    is planar, the first-order approximation is exact:\n        //          p' - p0 = [dpdu dpdv] duv\n        // 5. Since dpdu and dpdv for the hit triangle are known, by replacing p_x and p_y for p' \n        //    in above, ddx(uv) and ddy(uv) can be approximated by solving the linear system.\n\n        // determinant of square matrix A^T A\n        float dpduDotdpdu = dot(dpdu, dpdu);\n        float dpdvDotdpdv = dot(dpdv, dpdv);\n        float dpduDotdpdv = dot(dpdu, dpdv);\n        float det = dpduDotdpdu * dpdvDotdpdv - dpduDotdpdv * dpduDotdpdv;\n        // A^T A is not invertible\n        if (abs(det) < 1e-7f)\n            return 0;\n\n        // form ray differentials\n        float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n\n        float3 dir_cs_x = RT::GeneratePinholeCameraRay_CS(int2(DTid.x + 1, DTid.y), \n            renderDim, g_frame.AspectRatio, g_frame.TanHalfFOV, \n            g_frame.CurrCameraJitter);\n        float3 dir_cs_y = RT::GeneratePinholeCameraRay_CS(int2(DTid.x, DTid.y - 1), \n            renderDim, g_frame.AspectRatio, g_frame.TanHalfFOV, \n            g_frame.CurrCameraJitter);\n\n        // change ray directions given the lens sample\n        if(thinLens)\n        {\n            float3 focalPoint_x = focusDepth * dir_cs_x;\n            dir_cs_x = focalPoint_x - float3(lensSample, 0);\n\n            float3 focalPoint_y = focusDepth * dir_cs_y;\n            dir_cs_y = focalPoint_y - float3(lensSample, 0);\n        }\n\n        // camera space to world space\n        float3 dir_x = mad(dir_cs_x.x, g_frame.CurrView[0].xyz, \n            mad(dir_cs_x.y, g_frame.CurrView[1].xyz, dir_cs_x.z * g_frame.CurrView[2].xyz));\n        dir_x = normalize(dir_x);\n\n        float3 dir_y = mad(dir_cs_y.x, g_frame.CurrView[0].xyz, \n            mad(dir_cs_y.y, g_frame.CurrView[1].xyz, dir_cs_y.z * g_frame.CurrView[2].xyz));\n        dir_y = normalize(dir_y);\n\n        // compute intersection with tangent plane at hit point for camera ray\n        float3 faceNormal = normalize(cross(dpdu, dpdv));\n        float3 p = origin + t * dir;\n        float d = -dot(faceNormal, p);\n        float numerator = -dot(faceNormal, origin) - d;\n        \n        // compute intersection with tangent plane for ray differentials\n        float denom_x = dot(faceNormal, dir_x);\n        denom_x = (denom_x < 0 ? -1 : 1) * max(abs(denom_x), 1e-8);\n        float t_x = numerator / denom_x;\n        float3 p_x = origin + t_x * dir_x;\n\n        float denom_y = dot(faceNormal, dir_y);\n        denom_y = (denom_y < 0 ? -1 : 1) * max(abs(denom_y), 1e-8);\n        float t_y = numerator / denom_y;\n        float3 p_y = origin + t_y * dir_y;\n\n        // since the linear system described above is overdetermined, calculate\n        // the least-squares solution (denote by x_hat), which minimizes the L2-norm \n        // of A x_hat - b when there's no solution:\n        //      x_hat = (A^TA)^-1 A^T b\n        // where A = [dpdu dpdv] and b = delta_p\n\n        // division by determinant happens below\n        float2x2 A_T_A_Inv = float2x2(dpdvDotdpdv, -dpduDotdpdv,\n                                     -dpduDotdpdv, dpduDotdpdu);\n        float3 dpdx = p_x - p;\n        float2 A_Txb_x = float2(dot(dpdu, dpdx), dot(dpdv, dpdx));\n        float2 grads_x = mul(A_T_A_Inv, A_Txb_x) / det;\n\n        float3 dpdy = p_y - p;\n        float2 A_Txb_y = float2(dot(dpdu, dpdy), dot(dpdv, dpdy));\n        float2 grads_y = mul(A_T_A_Inv, A_Txb_y) / det;\n\n        // return clamp(float4(grads_x, grads_y), 1e-7, 1e7);\n        return float4(grads_x, grads_y);\n    }\n\n    void WriteToGBuffers(uint2 DTid, float t, float3 normal, float3 baseColor, float flags, \n        float roughness,float3 emissive, float2 motionVec, bool transmissive, float ior, \n        float subsurface, float coat_weight, float3 coat_color, float coat_roughness,\n        float coat_ior, float3 dpdu, float3 dpdv, float3 dndu, float3 dndv, \n        ConstantBuffer<cbGBufferRt> g_local)\n    {\n        RWTexture2D<float> g_outDepth = \n            ResourceDescriptorHeap[g_local.UavTableDescHeapIdx + (int)UAV_DESC_TABLE::DEPTH];\n        g_outDepth[DTid] = t;\n\n        RWTexture2D<float2> g_outNormal = \n            ResourceDescriptorHeap[g_local.UavTableDescHeapIdx + (int)UAV_DESC_TABLE::NORMAL];\n        g_outNormal[DTid] = Math::EncodeUnitVector(normal);\n\n        RWTexture2D<float4> g_outBaseColor = ResourceDescriptorHeap[g_local.UavTableDescHeapIdx];\n        if(subsurface > 0)\n            g_outBaseColor[DTid] = float4(baseColor, subsurface);\n        else\n            g_outBaseColor[DTid].rgb = baseColor;\n\n        RWTexture2D<float2> g_outMetallicRoughness = \n            ResourceDescriptorHeap[g_local.UavTableDescHeapIdx + (int)UAV_DESC_TABLE::METALLIC_ROUGHNESS];\n        g_outMetallicRoughness[DTid] = float2(flags, roughness);\n\n        if(dot(emissive, emissive) > 0)\n        {\n            RWTexture2D<float3> g_outEmissive = \n                ResourceDescriptorHeap[g_local.UavTableDescHeapIdx + (int)UAV_DESC_TABLE::EMISSIVE];\n            // R11G11B10 doesn't have a sign bit, make sure passed value is non-negative\n            g_outEmissive[DTid] = max(0, emissive);\n        }\n\n        if(transmissive)\n        {\n            RWTexture2D<float> g_outIOR = \n                ResourceDescriptorHeap[g_local.UavTableDescHeapIdx + (int)UAV_DESC_TABLE::IOR];\n            float ior_unorm = GBuffer::EncodeIOR(ior);\n            g_outIOR[DTid] = ior_unorm;\n        }\n\n        if(coat_weight > 0)\n        {\n            RWTexture2D<uint4> g_outCoat = \n                ResourceDescriptorHeap[g_local.UavTableDescHeapIdx + (int)UAV_DESC_TABLE::COAT];\n\n            uint3 packed;\n            uint c = Math::Float3ToRGB8(coat_color);\n            packed.x = (c & 0xffff);\n            packed.y = (c >> 16) | (Math::FloatToUNorm8(coat_weight) << 8);\n\n            float normalized = GBuffer::EncodeIOR(coat_ior);\n            packed.z = Math::FloatToUNorm8(coat_roughness) | (Math::FloatToUNorm8(normalized) << 8);\n\n            g_outCoat[DTid].xyz = packed;\n        }\n\n        RWTexture2D<float2> g_outMotion = \n            ResourceDescriptorHeap[g_local.UavTableDescHeapIdx + (int)UAV_DESC_TABLE::MOTION_VECTOR];\n        g_outMotion[DTid] = motionVec;\n\n        RWTexture2D<uint4> g_outTriGeo_A = \n            ResourceDescriptorHeap[g_local.UavTableDescHeapIdx + (int)UAV_DESC_TABLE::TRI_DIFF_GEO_A];\n        RWTexture2D<uint2> g_outTriGeo_B = \n            ResourceDescriptorHeap[g_local.UavTableDescHeapIdx + (int)UAV_DESC_TABLE::TRI_DIFF_GEO_B];\n        uint3 dpdu_h = asuint16(half3(dpdu));\n        uint3 dpdv_h = asuint16(half3(dpdv));\n        uint3 dndu_h = asuint16(half3(dndu));\n        uint3 dndv_h = asuint16(half3(dndv));\n\n        g_outTriGeo_A[DTid] = uint4(dpdu_h.x | (dpdu_h.y << 16),\n            dpdu_h.z | (dpdv_h.x << 16),\n            dpdv_h.y | (dpdv_h.z << 16),\n            dndu_h.x | (dndu_h.y << 16));\n        g_outTriGeo_B[DTid] = uint2(dndu_h.z | (dndv_h.x << 16), dndv_h.y | (dndv_h.z << 16));\n    }\n\n    void ApplyTextureMaps(uint2 DTid, float z_view, float3 wo, float2 uv, uint matIdx, \n        float3 geoNormal, float3 tangent, float2 motionVec, float4 grads, float3 dpdu, \n        float3 dpdv, float3 dndu, float3 dndv, ConstantBuffer<cbFrameConstants> g_frame, \n        ConstantBuffer<cbGBufferRt> g_local, StructuredBuffer<Material> g_materials)\n    {\n        const Material mat = g_materials[NonUniformResourceIndex(matIdx)];\n        // Apply negative mip bias when upscaling\n        grads *= g_frame.CameraRayUVGradsScale;\n\n        float3 baseColor = mat.GetBaseColorFactor();\n        float3 emissiveColor = mat.GetEmissiveFactor();\n        float normalScale = mat.GetNormalScale();\n        float metallic = mat.Metallic() ? 1.0f : 0.0f;\n        float alphaCutoff = mat.GetAlphaCutoff();\n        float roughness = mat.GetSpecularRoughness();\n        float3 shadingNormal = geoNormal;\n\n        const uint32_t baseColorTex = mat.GetBaseColorTex();\n        const uint32_t normalTex = mat.GetNormalTex();\n        const uint32_t metallicRoughnessTex = mat.GetMetallicRoughnessTex();\n\n        if (baseColorTex != Material::INVALID_ID)\n        {\n            uint offset = NonUniformResourceIndex(g_frame.BaseColorMapsDescHeapOffset + \n                baseColorTex);\n            BASE_COLOR_MAP g_baseCol = ResourceDescriptorHeap[offset];\n            baseColor *= g_baseCol.SampleGrad(g_samAnisotropicWrap, uv, grads.xy, grads.zw).rgb;\n        }\n\n        // avoid normal mapping if tangent = (0, 0, 0), which results in NaN\n        if (normalTex != Material::INVALID_ID && abs(dot(tangent, tangent)) > 1e-6)\n        {\n            uint offset = NonUniformResourceIndex(g_frame.NormalMapsDescHeapOffset + normalTex);\n            NORMAL_MAP g_normalMap = ResourceDescriptorHeap[offset];\n            float2 bump2 = g_normalMap.SampleGrad(g_samAnisotropicWrap, uv, grads.xy, grads.zw);\n\n            shadingNormal = Math::TangentSpaceToWorldSpace(bump2, tangent, geoNormal, \n                normalScale);\n        }\n\n        // reverse normal for double-sided meshes if facing away from camera\n        if (mat.DoubleSided() && dot(wo, geoNormal) < 0)\n        {\n            shadingNormal *= -1;\n            dndu *= -1;\n            dndv *= -1;\n        }\n\n        // Neighborhood around surface point (approximated by tangent plane from geometry normal) is visible, \n        // yet camera would be behind the tangent plane formed by bumped normal -- this can cause black spots \n        // as brdf evaluates to 0 in these regions. To mitigate the issue, rotate the bumped normal towards\n        // wo until their dot product becomes greater than zero:\n        //\n        // 1. Project bumped normal onto plane formed by normal vector wo\n        // 2. Slightly rotate the projection towards wo so that their dot product becomes greater than zero\n#if 1\n        if(dot(wo, geoNormal) > 0 && dot(wo, shadingNormal) < 0)\n        {\n            wo = normalize(wo);\n            shadingNormal = shadingNormal - dot(shadingNormal, wo) * wo;\n            shadingNormal = 1e-4f * wo + shadingNormal;\n            shadingNormal = normalize(shadingNormal);\n        }\n#endif\n\n        if (metallicRoughnessTex != Material::INVALID_ID)\n        {\n            uint offset = NonUniformResourceIndex(g_frame.MetallicRoughnessMapsDescHeapOffset + \n                metallicRoughnessTex);\n            METALLIC_ROUGHNESS_MAP g_metallicRoughnessMap = ResourceDescriptorHeap[offset];\n            float2 mr = g_metallicRoughnessMap.SampleGrad(g_samAnisotropicWrap, uv, grads.xy, grads.zw);\n\n            metallic *= mr.x;\n            roughness *= mr.y;\n        }\n\n        uint32_t emissiveTex = mat.GetEmissiveTex();\n        float emissiveStrength = (float)mat.GetEmissiveStrength();\n\n        if (emissiveTex != Material::INVALID_ID)\n        {\n            uint offset = NonUniformResourceIndex(g_frame.EmissiveMapsDescHeapOffset + emissiveTex);\n            EMISSIVE_MAP g_emissiveMap = ResourceDescriptorHeap[offset];\n            emissiveColor *= g_emissiveMap.SampleLevel(g_samLinearWrap, uv, 0).xyz;\n        }\n\n        emissiveColor *= emissiveStrength;\n\n        // encode metalness along with some other stuff\n        bool transmissive = mat.Transmissive();\n        float ior = mat.GetSpecularIOR();\n        float trDepth = transmissive ? (float)mat.GetTransmissionDepth() : 0;\n        float subsurface = mat.ThinWalled() ? (float)mat.GetSubsurface() : 0;\n        float coat_weight = mat.GetCoatWeight();\n        float3 coat_color = mat.GetCoatColor();\n        float coat_roughness = mat.GetCoatRoughness();\n        float coat_ior = mat.GetCoatIOR();\n        float encoded = GBuffer::EncodeMetallic(metallic, transmissive, emissiveColor, \n            trDepth, subsurface, coat_weight);\n\n        WriteToGBuffers(DTid, z_view, shadingNormal, baseColor.rgb, encoded, \n            roughness, emissiveColor, motionVec, transmissive, ior, subsurface, \n            coat_weight, coat_color, coat_roughness, coat_ior,\n            dpdu, dpdv, dndu, dndv, g_local);\n    }\n}"
  },
  {
    "path": "Source/ZetaRenderPass/GBuffer/GBufferRT_Common.h",
    "content": "#ifndef GBUFFER_RT_COMMON_H\n#define GBUFFER_RT_COMMON_H\n\n#include \"../../ZetaCore/Core/HLSLCompat.h\"\n\n#define GBUFFER_RT_GROUP_DIM_X 8u\n#define GBUFFER_RT_GROUP_DIM_Y 8u\n\n#define GBUFFER_RT_TILE_WIDTH 16\n#define GBUFFER_RT_LOG2_TILE_WIDTH 4\n\nenum class UAV_DESC_TABLE\n{\n    BASE_COLOR,\n    NORMAL,\n    METALLIC_ROUGHNESS,\n    MOTION_VECTOR,\n    EMISSIVE,\n    IOR,\n    COAT,\n    DEPTH,\n    TRI_DIFF_GEO_A,\n    TRI_DIFF_GEO_B,\n    COUNT\n};\n\nstruct cbGBufferRt\n{\n    uint32_t UavTableDescHeapIdx;\n\n    uint16_t PickedPixelX;\n    uint16_t PickedPixelY;\n    uint16_t DispatchDimX;\n    uint16_t DispatchDimY;\n    uint16_t NumGroupsInTile;\n    uint16_t pad;\n};\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/GBuffer/GBufferRT_Inline.hlsl",
    "content": "#include \"GBufferRT.hlsli\"\n#include \"../Common/Common.hlsli\"\n#include \"../Common/Sampling.hlsli\"\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cbGBufferRt> g_local : register(b1);\nRaytracingAccelerationStructure g_bvh : register(t0);\nStructuredBuffer<RT::MeshInstance> g_frameMeshData : register(t1);\nStructuredBuffer<Vertex> g_sceneVertices : register(t2);\nStructuredBuffer<uint> g_sceneIndices : register(t3);\nStructuredBuffer<Material> g_materials : register(t4);\nRWStructuredBuffer<uint> g_pick : register(u0);\n\n//--------------------------------------------------------------------------------------\n// Helper functions\n//--------------------------------------------------------------------------------------\n\nstruct RayPayload\n{\n    float t;\n    float3 normal;\n    float3 tangent;\n    float2 uv;\n    uint matIdx;\n    float2 prevPosNDC;\n    float3 dpdu;\n    float3 dpdv;\n    float3 dndu;\n    float3 dndv;\n    uint hitMeshIdx;\n};\n\nbool TestOpacity(uint geoIdx, uint instanceID, uint primIdx, float2 bary)\n{\n    const RT::MeshInstance meshData = g_frameMeshData[NonUniformResourceIndex(geoIdx + instanceID)];\n\n    float2 alphaFactor_cutoff = Math::UnpackRG(meshData.AlphaFactor_Cutoff);\n    if(alphaFactor_cutoff.y == 1.0)\n        return false;\n\n    float alpha = alphaFactor_cutoff.x;\n\n    if(meshData.BaseColorTex != UINT16_MAX)\n    {\n        uint tri = primIdx * 3;\n        tri += meshData.BaseIdxOffset;\n        uint i0 = g_sceneIndices[NonUniformResourceIndex(tri)] + meshData.BaseVtxOffset;\n        uint i1 = g_sceneIndices[NonUniformResourceIndex(tri + 1)] + meshData.BaseVtxOffset;\n        uint i2 = g_sceneIndices[NonUniformResourceIndex(tri + 2)] + meshData.BaseVtxOffset;\n\n        Vertex V0 = g_sceneVertices[NonUniformResourceIndex(i0)];\n        Vertex V1 = g_sceneVertices[NonUniformResourceIndex(i1)];\n        Vertex V2 = g_sceneVertices[NonUniformResourceIndex(i2)];\n\n        float2 uv = V0.TexUV + bary.x * (V1.TexUV - V0.TexUV) + bary.y * (V2.TexUV - V0.TexUV);\n\n        uint descHeadpIdx = NonUniformResourceIndex(g_frame.BaseColorMapsDescHeapOffset + meshData.BaseColorTex);\n        BASE_COLOR_MAP g_baseCol = ResourceDescriptorHeap[descHeadpIdx];\n        alpha *= g_baseCol.SampleLevel(g_samLinearWrap, uv, 0).a;\n    }\n\n    if (alpha < alphaFactor_cutoff.y) \n        return false;\n\n    return true;\n}\n\nRayPayload TracePrimaryHit(float3 origin, float3 dir)\n{\n    RayDesc cameraRay;\n    cameraRay.Origin = origin;\n    cameraRay.TMin = 0;\n    cameraRay.TMax = FLT_MAX;\n    cameraRay.Direction = dir;\n\n    RayQuery<RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES> rayQuery;\n    rayQuery.TraceRayInline(g_bvh, RAY_FLAG_NONE, RT_AS_SUBGROUP::ALL, cameraRay);\n\n    while(rayQuery.Proceed())\n    {\n        if(rayQuery.CandidateType() == CANDIDATE_NON_OPAQUE_TRIANGLE)\n        {\n            if(TestOpacity(rayQuery.CandidateGeometryIndex(), \n                rayQuery.CandidateInstanceID(), \n                rayQuery.CandidatePrimitiveIndex(), \n                rayQuery.CandidateTriangleBarycentrics()))\n            {\n                rayQuery.CommitNonOpaqueTriangleHit();\n            }\n        }\n    }\n\n    RayPayload payload;\n    payload.t = FLT_MAX;\n\n    if (rayQuery.CommittedStatus() == COMMITTED_TRIANGLE_HIT)\n    {\n        uint meshIdx = rayQuery.CommittedGeometryIndex() + rayQuery.CommittedInstanceID();\n        uint primIdx = rayQuery.CommittedPrimitiveIndex();\n        float2 bary = rayQuery.CommittedTriangleBarycentrics();\n\n        const RT::MeshInstance meshData = g_frameMeshData[NonUniformResourceIndex(meshIdx)];\n\n        payload.t = rayQuery.CommittedRayT();\n        payload.matIdx = meshData.MatIdx;\n        payload.hitMeshIdx = meshIdx;\n\n        uint tri = primIdx * 3;\n        tri += meshData.BaseIdxOffset;\n        uint i0 = g_sceneIndices[NonUniformResourceIndex(tri)] + meshData.BaseVtxOffset;\n        uint i1 = g_sceneIndices[NonUniformResourceIndex(tri + 1)] + meshData.BaseVtxOffset;\n        uint i2 = g_sceneIndices[NonUniformResourceIndex(tri + 2)] + meshData.BaseVtxOffset;\n\n        Vertex V0 = g_sceneVertices[NonUniformResourceIndex(i0)];\n        Vertex V1 = g_sceneVertices[NonUniformResourceIndex(i1)];\n        Vertex V2 = g_sceneVertices[NonUniformResourceIndex(i2)];\n\n        float4 q = Math::DecodeNormalized4(meshData.Rotation);\n        // due to quantization, it's necessary to renormalize\n        q = normalize(q);\n\n        // texture UV coords\n        float2 uv = V0.TexUV + bary.x * (V1.TexUV - V0.TexUV) + bary.y * (V2.TexUV - V0.TexUV);\n        payload.uv = uv;\n\n        // normal\n        float3 v0_n = Math::DecodeOct32(V0.NormalL);\n        float3 v1_n = Math::DecodeOct32(V1.NormalL);\n        float3 v2_n = Math::DecodeOct32(V2.NormalL);\n        float3 normal = v0_n + bary.x * (v1_n - v0_n) + bary.y * (v2_n - v0_n);\n        // transform normal using the inverse transpose\n        // (M^-1)^T = ((RS)^-1)^T\n        //          = (S^-1 R^-1)^T\n        //          = (R^T)^T (S^-1)^T\n        //          = R S^-1\n        const float3 scaleInv = 1.0f / meshData.Scale;\n        normal *= scaleInv;\n        normal = Math::RotateVector(normal, q);\n        normal = normalize(normal);\n        payload.normal = normal;\n\n        // tangent vector\n        float3 v0_t = Math::DecodeOct32(V0.TangentU);\n        float3 v1_t = Math::DecodeOct32(V1.TangentU);\n        float3 v2_t = Math::DecodeOct32(V2.TangentU);\n        float3 tangent = v0_t + bary.x * (v1_t - v0_t) + bary.y * (v2_t - v0_t);\n        tangent *= meshData.Scale;\n        tangent = Math::RotateVector(tangent, q);\n        tangent = normalize(tangent);\n        payload.tangent = tangent;\n\n        // triangle geometry differentials are needed for ray differentials\n        float3 v0W = Math::TransformTRS(V0.PosL, meshData.Translation, q, meshData.Scale);\n        float3 v1W = Math::TransformTRS(V1.PosL, meshData.Translation, q, meshData.Scale);\n        float3 v2W = Math::TransformTRS(V2.PosL, meshData.Translation, q, meshData.Scale);\n\n        float3 n0W = v0_n * scaleInv;\n        n0W = Math::RotateVector(n0W, q);\n        n0W = normalize(n0W);\n\n        float3 n1W = v1_n * scaleInv;\n        n1W = Math::RotateVector(n1W, q);\n        n1W = normalize(n1W);\n\n        float3 n2W = v2_n * scaleInv;\n        n2W = Math::RotateVector(n2W, q);\n        n2W = normalize(n2W);\n\n        Math::TriDifferentials triDiffs = Math::TriDifferentials::Compute(v0W, v1W, v2W, \n            n0W, n1W, n2W,\n            V0.TexUV, V1.TexUV, V2.TexUV);\n\n        payload.dpdu = triDiffs.dpdu;\n        payload.dpdv = triDiffs.dpdv;\n        payload.dndu = triDiffs.dndu;\n        payload.dndv = triDiffs.dndv;\n        \n        // motion vector\n        float3 hitPos = mad(rayQuery.WorldRayDirection(), rayQuery.CommittedRayT(), \n            rayQuery.WorldRayOrigin());\n        float3 posL = Math::InverseTransformTRS(hitPos, meshData.Translation, q, meshData.Scale);\n        float3 prevTranslation = meshData.Translation - meshData.dTranslation;\n        float4 q_prev = Math::DecodeNormalized4(meshData.PrevRotation);\n        // due to quantization, it's necessary to renormalize\n        q_prev = normalize(q_prev);\n        float3 pos_prev = Math::TransformTRS(posL, prevTranslation, q_prev, meshData.PrevScale);\n        float3 posV_prev = mul(g_frame.PrevView, float4(pos_prev, 1.0f));\n        float2 posNDC_prev = posV_prev.xy / (posV_prev.z * g_frame.TanHalfFOV);\n        posNDC_prev.x /= g_frame.AspectRatio;\n        payload.prevPosNDC = posNDC_prev;\n    }\n\n    return payload;\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(GBUFFER_RT_GROUP_DIM_X, GBUFFER_RT_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID)\n{\n    if (DTid.x >= g_frame.RenderWidth || DTid.y >= g_frame.RenderHeight)\n        return;\n\n    float2 lensSample = 0;\n    float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    float3 rayDirCS = RT::GeneratePinholeCameraRay_CS(DTid.xy, renderDim,\n        g_frame.AspectRatio, g_frame.TanHalfFOV, g_frame.CurrCameraJitter);\n    float3 rayOrigin = g_frame.CameraPos;\n\n    if(g_frame.DoF)\n    {\n        RNG rng = RNG::Init(RNG::PCG3d(DTid.xyx).zy, g_frame.FrameNum);\n        lensSample = Sampling::UniformSampleDiskConcentric(rng.Uniform2D());\n        lensSample *= g_frame.LensRadius;\n        // Camera space to world space\n        rayOrigin += mad(lensSample.x, g_frame.CurrView[0].xyz, lensSample.y * g_frame.CurrView[1].xyz);\n\n#if 0\n        // rayDirCS.z = 1\n        float t = g_frame.FocusDepth / rayDirCS.z;\n        float3 focalPoint = t * rayDirCS;\n#else\n        float3 focalPoint = g_frame.FocusDepth * rayDirCS;\n#endif\n        rayDirCS = focalPoint - float3(lensSample, 0);\n    }\n\n    // Camera space to world space\n    float3 rayDir = mad(rayDirCS.x, g_frame.CurrView[0].xyz, \n        mad(rayDirCS.y, g_frame.CurrView[1].xyz, rayDirCS.z * g_frame.CurrView[2].xyz));\n    rayDir = normalize(rayDir);\n\n    RayPayload rayPayload = TracePrimaryHit(rayOrigin, rayDir);\n\n    if(g_local.PickedPixelX == DTid.x && g_local.PickedPixelY == DTid.y)\n        g_pick[0] = rayPayload.t != FLT_MAX ? rayPayload.hitMeshIdx : UINT32_MAX;\n\n    // ray missed the scene\n    if(rayPayload.t == FLT_MAX)\n    {\n        RWTexture2D<float> g_depth = ResourceDescriptorHeap[g_local.UavTableDescHeapIdx + (int)UAV_DESC_TABLE::DEPTH];\n        g_depth[DTid.xy] = FLT_MAX;\n\n        RWTexture2D<float2> g_metallicRoughness = \n            ResourceDescriptorHeap[g_local.UavTableDescHeapIdx + (int)UAV_DESC_TABLE::METALLIC_ROUGHNESS];\n        g_metallicRoughness[DTid.xy].x = 4.0f / 255.0f;\n\n        // just the camera motion\n        RWTexture2D<float2> g_outMotion = \n            ResourceDescriptorHeap[g_local.UavTableDescHeapIdx + (int)UAV_DESC_TABLE::MOTION_VECTOR];\n        float3 prevCameraPos = float3(g_frame.PrevViewInv._m03, g_frame.PrevViewInv._m13, \n            g_frame.PrevViewInv._m23);\n        float3 motion = g_frame.CameraPos - prevCameraPos;\n        float2 motionNDC = motion.z > 0 ? motion.xy / (motion.z * g_frame.TanHalfFOV) : 0;\n        motionNDC.x /= g_frame.AspectRatio;\n        float2 motionUV = Math::UVFromNDC(motionNDC);\n        g_outMotion[DTid.xy] = motionUV;\n\n        return;\n    }\n\n    float2 currUV = (DTid.xy + 0.5) / renderDim;\n    float2 prevUV = Math::UVFromNDC(rayPayload.prevPosNDC) - (g_frame.CurrCameraJitter / renderDim);\n    float2 motionVec = currUV - prevUV;\n\n    // Rate of change of texture uv coords w.r.t. screen space. Needed for texture filtering.\n    float4 grads = GBufferRT::UVDifferentials(DTid.xy, rayOrigin, rayDir, g_frame.CurrCameraJitter, \n        g_frame.DoF, lensSample, g_frame.FocusDepth, rayPayload.t, rayPayload.dpdu, \n        rayPayload.dpdv, g_frame);\n\n    // Instead of hit distance, save view z for slightly faster position reconstruction\n    float3 pos = mad(rayPayload.t, rayDir, rayOrigin);\n    float3 posV = mul(g_frame.CurrView, float4(pos, 1.0f));\n    float z = g_frame.DoF ? rayPayload.t : posV.z;\n    float3 wo = rayOrigin - pos;\n\n    GBufferRT::ApplyTextureMaps(DTid.xy, z, wo, rayPayload.uv, rayPayload.matIdx, \n        rayPayload.normal, rayPayload.tangent, motionVec, grads, rayPayload.dpdu, \n        rayPayload.dpdv, rayPayload.dndu, rayPayload.dndv, g_frame, \n        g_local, g_materials);\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/GBuffer/GenerateDepthBuffer.cpp",
    "content": "#include \"GenerateDepthBuffer.h\"\n#include <Core/RendererCore.h>\n#include <Core/CommandList.h>\n#include <Scene/SceneRenderer.h>\n#include <Support/Param.h>\n\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Scene;\n\n//--------------------------------------------------------------------------------------\n// GenerateDepthBuffer\n//--------------------------------------------------------------------------------------\n\nGenerateRasterDepth::GenerateRasterDepth()\n    : RenderPassBase(NUM_CBV, NUM_SRV, NUM_UAV, NUM_GLOBS, NUM_CONSTS)\n{\n    // root constants\n    m_rootSig.InitAsConstants(0, 1, 0);\n\n    // frame constants\n    m_rootSig.InitAsCBV(1, 1, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        Scene::GlobalResource::FRAME_CONSTANTS_BUFFER);\n\n    RenderPassBase::InitRenderPass(\"RasterDepth\", D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED);\n\n    m_psoLib.CompileComputePSO(0, m_rootSigObj.Get(), COMPILED_CS);\n    m_descTable = App::GetRenderer().GetGpuDescriptorHeap().Allocate(1);\n}\n\nvoid GenerateRasterDepth::Resize(uint32_t w, uint32_t h)\n{\n    m_depthBuffer = GpuMemory::GetTexture2D(\"RasterDepth\",\n        w,\n        h,\n        DXGI_FORMAT_R32_FLOAT,\n        D3D12_RESOURCE_STATE_COMMON,\n        TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n    Direct3DUtil::CreateTexture2DUAV(m_depthBuffer, m_descTable.CPUHandle(0));\n}\n\nvoid GenerateRasterDepth::Render(ComputeCmdList& computeCmdList)\n{\n    computeCmdList.PIXBeginEvent(\"GenerateRasterDepth\");\n\n    computeCmdList.SetRootSignature(m_rootSig, m_rootSigObj.Get());\n\n    const uint32_t w = App::GetRenderer().GetRenderWidth();\n    const uint32_t h = App::GetRenderer().GetRenderHeight();\n\n    const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, 8u);\n    const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, 8u);\n\n    computeCmdList.ResourceBarrier(m_depthBuffer.Resource(),\n        D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,\n        D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n\n    const uint32_t descHeapIdx = m_descTable.GPUDescriptorHeapIndex();\n\n    m_rootSig.SetRootConstants(0, 1, &descHeapIdx);\n    m_rootSig.End(computeCmdList);\n\n    computeCmdList.SetPipelineState(m_psoLib.GetPSO(0));\n    computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n\n    computeCmdList.ResourceBarrier(m_depthBuffer.Resource(),\n        D3D12_RESOURCE_STATE_UNORDERED_ACCESS,\n        D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n\n    computeCmdList.PIXEndEvent();\n}"
  },
  {
    "path": "Source/ZetaRenderPass/GBuffer/GenerateDepthBuffer.h",
    "content": "#pragma once\n\n#include \"../RenderPass.h\"\n#include <Core/GpuMemory.h>\n#include <Core/DescriptorHeap.h>\n\nnamespace ZetaRay::Core\n{\n    class ComputeCmdList;\n}\n\nnamespace ZetaRay::RenderPass\n{\n    struct GenerateRasterDepth final : public RenderPassBase<1>\n    {\n        static constexpr int NUM_CBV = 1;\n        static constexpr int NUM_SRV = 0;\n        static constexpr int NUM_UAV = 0;\n        static constexpr int NUM_GLOBS = 1;\n        static constexpr int NUM_CONSTS = 1;\n\n        GenerateRasterDepth();\n        ~GenerateRasterDepth() = default;\n\n        GenerateRasterDepth(GenerateRasterDepth&&) = delete;\n        GenerateRasterDepth& operator=(GenerateRasterDepth&&) = delete;\n\n        void Resize(uint32_t w, uint32_t h);\n        void Render(Core::ComputeCmdList& computeCmdList);\n\n        inline static constexpr const char* COMPILED_CS = \"GenerateDepthBuffer_cs.cso\";\n\n        Core::GpuMemory::Texture m_depthBuffer;\n        Core::DescriptorTable m_descTable;\n    };\n}"
  },
  {
    "path": "Source/ZetaRenderPass/GBuffer/GenerateDepthBuffer.hlsl",
    "content": "#include \"../Common/FrameConstants.h\"\n#include \"../Common/GBuffers.hlsli\"\n#include \"../Common/Math.hlsli\"\n\nstruct cbGenerateDepthBuffer\n{\n    uint UavDescHeapIdx;\n};\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbGenerateDepthBuffer> g_local : register(b0);\nConstantBuffer<cbFrameConstants> g_frame : register(b1);\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(8, 8, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID)\n{\n    if (DTid.x >= g_frame.RenderWidth || DTid.y >= g_frame.RenderHeight)\n        return;\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + GBUFFER_OFFSET::DEPTH];\n    const float depth = g_depth[DTid.xy];\n\n    RWTexture2D<float> g_rasterDepthBuffer = ResourceDescriptorHeap[g_local.UavDescHeapIdx];\n    float ndcDepth = depth == FLT_MAX ? 0 : g_frame.CameraNear / depth;\n    g_rasterDepthBuffer[DTid.xy].r = ndcDepth;\n}"
  },
  {
    "path": "Source/ZetaRenderPass/GUI/CMakeLists.txt",
    "content": "set(RP_GUI_DIR ${ZETA_RENDER_PASS_DIR}/GUI)\nset(RP_GUI_SRC\n    ${RP_GUI_DIR}/GuiPass.cpp\n    ${RP_GUI_DIR}/GuiPass.h\n    ${RP_GUI_DIR}/ImGui.hlsl\n    ${RP_GUI_DIR}/GuiPass_Common.h)\nset(RP_GUI_SRC ${RP_GUI_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaRenderPass/GUI/GuiPass.cpp",
    "content": "#include \"GuiPass.h\"\n#include <Core/CommandList.h>\n#include <Support/Param.h>\n#include <Support/Stat.h>\n#include <Scene/SceneCore.h>\n#include <Scene/Camera.h>\n#include <App/Timer.h>\n#include <Utility/SynchronizedView.h>\n#include <Math/CollisionFuncs.h>\n#include <Math/Quaternion.h>\n\n#include <ImGui/imgui.h>\n#include <ImGui/implot.h>\n#include <ImGui/ImGuizmo.h>\n#include <algorithm>\n\n#include \"../Assets/Font/IconsFontAwesome6.h\"\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Core::Direct3DUtil;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Model;\n\nnamespace\n{\n    void AddParamRange(MutableSpan<ParamVariant> params, int offset, int count)\n    {\n        // Sort by name among current subgroup\n        std::sort(params.begin() + offset, params.begin() + offset + count, \n            [](const ParamVariant& p1, const ParamVariant& p2)\n            {\n                return strcmp(p1.GetName(), p2.GetName()) < 0;\n            });\n\n        for (int p = offset; p < offset + count; p++)\n        {\n            ParamVariant& param = params[p];\n\n            if (param.GetType() == PARAM_TYPE::PT_enum)\n            {\n                auto& fp = param.GetEnum();\n                int idx = fp.m_curr;\n                if(ImGui::Combo(param.GetName(), &idx, fp.m_values, fp.m_num))\n                    param.SetEnum(idx);\n            }\n            else if (param.GetType() == PARAM_TYPE::PT_float)\n            {\n                auto& fp = param.GetFloat();\n                float v = fp.m_value;\n\n                auto flags = (int)ImGuiSliderFlags_None;\n                //if ((fp.m_max - fp.m_min) / Math::Max(fp.m_min, 1e-6f) >= 1000.0f)\n                if (fp.m_stepSize <= 1e-3f)\n                    flags |= ImGuiSliderFlags_Logarithmic;\n\n                if(ImGui::SliderFloat(param.GetName(), &v, fp.m_min, fp.m_max, \"%.5f\", flags))\n                    param.SetFloat(v);\n            }\n            else if (param.GetType() == PARAM_TYPE::PT_int)\n            {\n                auto& ip = param.GetInt();\n                int v = ip.m_value;\n\n                if (ImGui::SliderInt(param.GetName(), &v, ip.m_min, ip.m_max))\n                    param.SetInt(v);\n            }\n            else if (param.GetType() == PARAM_TYPE::PT_float2)\n            {\n                auto& fp = param.GetFloat2();\n                float2 v = fp.m_value;\n\n                if (ImGui::SliderFloat2(param.GetName(), reinterpret_cast<float*>(&v), fp.m_min, fp.m_max, \"%.2f\"))\n                    param.SetFloat2(v);\n            }            \n            else if (param.GetType() == PARAM_TYPE::PT_float3)\n            {\n                auto& fp = param.GetFloat3();\n                float3 v = fp.m_value;\n\n                if (ImGui::SliderFloat3(param.GetName(), reinterpret_cast<float*>(&v), fp.m_min, fp.m_max, \"%.2f\"))\n                    param.SetFloat3(v);\n            }\n            else if (param.GetType() == PARAM_TYPE::PT_unit_dir)\n            {\n                auto& fp = param.GetUnitDir();\n                float pitch = fp.m_pitch;\n                float yaw = fp.m_yaw;\n\n                ImGui::Text(\"%s\", param.GetName());\n                bool changed = false;\n\n                if (ImGui::SliderFloat(\"pitch\", reinterpret_cast<float*>(&pitch), 0, PI, \"%.4f\"))\n                    changed = true;\n                if (ImGui::SliderFloat(\"yaw\", reinterpret_cast<float*>(&yaw), 0.0f, TWO_PI, \"%.4f\"))\n                    changed = true;\n\n                if(changed)\n                    param.SetUnitDir(pitch, yaw);\n            }\n            else if (param.GetType() == PARAM_TYPE::PT_color)\n            {\n                auto& fp = param.GetColor();\n                float3 v = fp.m_value;\n\n                if (ImGui::ColorEdit3(param.GetName(), reinterpret_cast<float*>(&v)))\n                    param.SetColor(v);\n            }\n            else if (param.GetType() == PARAM_TYPE::PT_bool)\n            {\n                bool v = param.GetBool();\n\n                if (ImGui::Checkbox(param.GetName(), &v))\n                    param.SetBool(v);\n            }\n        }\n    }\n\n    void DrawAxis(const float3& pos, const float3& xAxis, const float3& zAxis, const float3& xColor,\n        const float3& zColor, float lineWidth)\n    {\n        // axis\n        float axis_x[2];\n        float axis_y[2];\n\n        float arrow_x[3];\n        float arrow_y[3];\n\n        // arrow tip\n        constexpr float arrowLenX = 0.25f;\n        constexpr float arrowLenY = 0.25f;\n\n        // rotate and plot\n        auto func = [&](const float3& color)\n            {\n                float2 rotMatCol1 = float2(xAxis.x, xAxis.z);\n                float2 rotMatCol2 = float2(zAxis.x, zAxis.z);\n\n                float2 rotated = arrow_x[0] * rotMatCol1 + arrow_y[0] * rotMatCol2;\n                arrow_x[0] = pos.x + rotated.x;\n                arrow_y[0] = pos.z + rotated.y;\n\n                rotated = arrow_x[2] * rotMatCol1 + arrow_y[2] * rotMatCol2;\n                arrow_x[2] = pos.x + rotated.x;\n                arrow_y[2] = pos.z + rotated.y;\n\n                ImPlot::SetNextLineStyle(ImVec4(color.x, color.y, color.z, 1.0f), lineWidth);\n                ImPlot::PlotLine(\"\", arrow_x, arrow_y, ZetaArrayLen(arrow_x));\n            };\n\n        // starting point\n        axis_x[0] = pos.x;\n        axis_y[0] = pos.z;\n\n        // end point\n        axis_x[1] = pos.x + zAxis.x;\n        axis_y[1] = pos.z + zAxis.z;\n\n        ImPlot::SetNextLineStyle(ImVec4(zColor.x, zColor.y, zColor.z, 1.0f), lineWidth);\n        ImPlot::PlotLine(\"Z\", axis_x, axis_y, ZetaArrayLen(axis_x));\n\n        // Z axis\n        // starting point\n        arrow_x[0] = 0.0f - arrowLenX;\n        arrow_y[0] = 1.0f - arrowLenY;\n        // middle point\n        arrow_x[1] = axis_x[1];\n        arrow_y[1] = axis_y[1];\n        // end point\n        arrow_x[2] = 0.0f + arrowLenX;\n        arrow_y[2] = 1.0f - arrowLenY;\n\n        func(zColor);\n\n        // X axis\n        // end point\n        axis_x[1] = pos.x + xAxis.x;\n        axis_y[1] = pos.z + xAxis.z;\n        ImPlot::SetNextLineStyle(ImVec4(xColor.x, xColor.y, xColor.z, 1.0f), lineWidth);\n        ImPlot::PlotLine(\"X\", axis_x, axis_y, ZetaArrayLen(axis_x));\n\n        // starting point\n        arrow_x[0] = 1.0f - arrowLenX;\n        arrow_y[0] = 0.0f + arrowLenY;\n        // middle point\n        arrow_x[1] = axis_x[1];\n        arrow_y[1] = axis_y[1];\n        // end point\n        arrow_x[2] = 1.0f - arrowLenX;\n        arrow_y[2] = 0.0f - arrowLenY;\n\n        func(xColor);\n    }\n\n    void ShowStyles()\n    {\n        if (ImGui::BeginTabItem(\"Colors\"))\n        {\n            ImGuiStyle& style = ImGui::GetStyle();\n\n            static int output_dest = 0;\n            static bool output_only_modified = true;\n\n            static ImGuiTextFilter filter;\n            filter.Draw(\"Filter colors\", ImGui::GetFontSize() * 16);\n\n            static ImGuiColorEditFlags alpha_flags = 0;\n\n            ImGui::PushItemWidth(-160);\n            for (int i = 0; i < ImGuiCol_COUNT; i++)\n            {\n                const char* name = ImGui::GetStyleColorName(i);\n                if (!filter.PassFilter(name))\n                    continue;\n                ImGui::PushID(i);\n                ImGui::ColorEdit4(\"##color\", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);\n                ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);\n                ImGui::TextUnformatted(name);\n                ImGui::PopID();\n            }\n\n            ImGui::PopItemWidth();\n            ImGui::EndTabItem();\n        }\n\n        if (ImGui::BeginTabItem(\"Sizes\"))\n        {\n            ImGuiStyle& style = ImGui::GetStyle();\n\n            ImGui::Text(\"Main\");\n            ImGui::SliderFloat2(\"WindowPadding\", (float*)&style.WindowPadding, 0.0f, 20.0f, \"%.0f\");\n            ImGui::SliderFloat2(\"FramePadding\", (float*)&style.FramePadding, 0.0f, 20.0f, \"%.0f\");\n            ImGui::SliderFloat2(\"CellPadding\", (float*)&style.CellPadding, 0.0f, 20.0f, \"%.0f\");\n            ImGui::SliderFloat2(\"ItemSpacing\", (float*)&style.ItemSpacing, 0.0f, 20.0f, \"%.0f\");\n            ImGui::SliderFloat2(\"ItemInnerSpacing\", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, \"%.0f\");\n            ImGui::SliderFloat2(\"TouchExtraPadding\", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, \"%.0f\");\n            ImGui::SliderFloat(\"IndentSpacing\", &style.IndentSpacing, 0.0f, 30.0f, \"%.0f\");\n            ImGui::SliderFloat(\"ScrollbarSize\", &style.ScrollbarSize, 1.0f, 20.0f, \"%.0f\");\n            ImGui::SliderFloat(\"GrabMinSize\", &style.GrabMinSize, 1.0f, 20.0f, \"%.0f\");\n            ImGui::Text(\"Borders\");\n            ImGui::SliderFloat(\"WindowBorderSize\", &style.WindowBorderSize, 0.0f, 1.0f, \"%.0f\");\n            ImGui::SliderFloat(\"ChildBorderSize\", &style.ChildBorderSize, 0.0f, 1.0f, \"%.0f\");\n            ImGui::SliderFloat(\"PopupBorderSize\", &style.PopupBorderSize, 0.0f, 1.0f, \"%.0f\");\n            ImGui::SliderFloat(\"FrameBorderSize\", &style.FrameBorderSize, 0.0f, 1.0f, \"%.0f\");\n            ImGui::SliderFloat(\"TabBorderSize\", &style.TabBorderSize, 0.0f, 1.0f, \"%.0f\");\n            ImGui::Text(\"Rounding\");\n            ImGui::SliderFloat(\"WindowRounding\", &style.WindowRounding, 0.0f, 12.0f, \"%.0f\");\n            ImGui::SliderFloat(\"ChildRounding\", &style.ChildRounding, 0.0f, 12.0f, \"%.0f\");\n            ImGui::SliderFloat(\"FrameRounding\", &style.FrameRounding, 0.0f, 12.0f, \"%.0f\");\n            ImGui::SliderFloat(\"PopupRounding\", &style.PopupRounding, 0.0f, 12.0f, \"%.0f\");\n            ImGui::SliderFloat(\"ScrollbarRounding\", &style.ScrollbarRounding, 0.0f, 12.0f, \"%.0f\");\n            ImGui::SliderFloat(\"GrabRounding\", &style.GrabRounding, 0.0f, 12.0f, \"%.0f\");\n            ImGui::SliderFloat(\"LogSliderDeadzone\", &style.LogSliderDeadzone, 0.0f, 12.0f, \"%.0f\");\n            ImGui::SliderFloat(\"TabRounding\", &style.TabRounding, 0.0f, 12.0f, \"%.0f\");\n            ImGui::Text(\"Alignment\");\n            ImGui::SliderFloat2(\"WindowTitleAlign\", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, \"%.2f\");\n            int window_menu_button_position = style.WindowMenuButtonPosition + 1;\n            ImGui::Combo(\"ColorButtonPosition\", (int*)&style.ColorButtonPosition, \"Left\\0Right\\0\");\n            ImGui::SliderFloat2(\"ButtonTextAlign\", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, \"%.2f\");\n            ImGui::SliderFloat2(\"SelectableTextAlign\", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, \"%.2f\");\n            ImGui::Text(\"Safe Area Padding\");\n            ImGui::SliderFloat2(\"DisplaySafeAreaPadding\", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, \"%.0f\");\n\n            ImGui::EndTabItem();\n        }\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// GuiPass\n//--------------------------------------------------------------------------------------\n\nGuiPass::GuiPass()\n    : RenderPassBase(NUM_CBV, NUM_SRV, NUM_UAV, NUM_GLOBS, NUM_CONSTS)\n{}\n\nvoid GuiPass::Init()\n{\n    ImGuiIO& io = ImGui::GetIO();\n    io.ConfigWindowsResizeFromEdges = true;\n\n    // Root signature\n    {\n        m_rootSig.InitAsConstants(0, sizeof(cbGuiPass) / sizeof(DWORD), 0);\n\n        constexpr D3D12_ROOT_SIGNATURE_FLAGS flags =\n            D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |\n            D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS |\n            D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;\n\n        auto samplers = App::GetRenderer().GetStaticSamplers();\n        RenderPassBase::InitRenderPass(\"GuiPass\", flags, samplers);\n    }\n\n    // PSO\n    {\n        // Create the input layout\n        D3D12_INPUT_ELEMENT_DESC local_layout[] =\n        {\n            { \"POSITION\", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n            { \"TEXCOORD\", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT,  D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n            { \"COLOR\", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0,D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n        };\n\n        // RTV & DSV formats\n        D3D12_INPUT_LAYOUT_DESC inputLayout = { local_layout, 3 };\n        DXGI_FORMAT rtv[1] = { Constants::BACK_BUFFER_FORMAT };\n\n        D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = Direct3DUtil::GetPSODesc(&inputLayout,\n            1, rtv);\n\n        // blending\n        psoDesc.BlendState.RenderTarget[0].BlendEnable = true;\n        psoDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;\n        psoDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;\n        psoDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;\n        psoDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;\n        psoDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;\n        psoDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;\n        psoDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;\n\n        // rasterizer \n        psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;\n\n        // depth/stencil\n        psoDesc.DepthStencilState.DepthEnable = false;\n        psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;\n        psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;\n\n        m_psoLib.CompileGraphicsPSO(0, psoDesc, m_rootSigObj.Get(), COMPILED_VS[0], COMPILED_PS[0]);\n    }\n\n    auto* ctx = ImGui::GetCurrentContext();\n    ImGuizmo::SetImGuiContext(ctx);\n    ImGuizmo::AllowAxisFlip(false);\n}\n\nvoid GuiPass::OnWindowResized()\n{\n    m_appWndSizeChanged = true;\n}\n\nvoid GuiPass::UpdateBuffers()\n{\n    ImDrawData* draw_data = ImGui::GetDrawData();\n    const int currOutIdx = App::GetRenderer().GetCurrentBackBufferIndex();\n\n    // Avoid rendering when minimized\n    if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)\n        return;\n\n    auto& fr = m_imguiFrameBuffs[currOutIdx];\n\n    // Create and grow vertex/index buffers if needed\n    if (!fr.VertexBuffer.IsInitialized() || fr.NumVertices < draw_data->TotalVtxCount)\n    {\n        fr.NumVertices = draw_data->TotalVtxCount + 5000;\n        fr.VertexBuffer = GpuMemory::GetUploadHeapBuffer(fr.NumVertices * sizeof(ImDrawVert));\n    }\n\n    // Upload vertex data into a single contiguous GPU buffer\n    uint32_t offset = 0;\n\n    for (int n = 0; n < draw_data->CmdListsCount; n++)\n    {\n        const ImDrawList* cmd_list = draw_data->CmdLists[n];\n        fr.VertexBuffer.Copy(offset, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), \n            cmd_list->VtxBuffer.Data);\n        offset += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert);\n    }\n\n    if (!fr.IndexBuffer.IsInitialized() || fr.NumIndices < draw_data->TotalIdxCount)\n    {\n        //SafeRelease(fr->IndexBuffer);\n        fr.NumIndices = draw_data->TotalIdxCount + 10000;\n        fr.IndexBuffer = GpuMemory::GetUploadHeapBuffer(fr.NumIndices * sizeof(ImDrawIdx));\n    }\n\n    // Upload index data into a single contiguous GPU buffer\n    offset = 0;\n\n    for (int n = 0; n < draw_data->CmdListsCount; n++)\n    {\n        const ImDrawList* cmd_list = draw_data->CmdLists[n];\n        fr.IndexBuffer.Copy(offset, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), \n            cmd_list->IdxBuffer.Data);\n        offset += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx);\n    }\n}\n\nvoid GuiPass::Render(CommandList& cmdList)\n{\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT, \"Invalid downcast\");\n    GraphicsCmdList& directCmdList = static_cast<GraphicsCmdList&>(cmdList);\n\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n\n    directCmdList.PIXBeginEvent(\"ImGui\");\n    const uint32_t queryIdx = gpuTimer.BeginQuery(directCmdList, \"ImGui\");\n\n    directCmdList.SetRootSignature(m_rootSig, m_rootSigObj.Get());\n    directCmdList.SetPipelineState(m_psoLib.GetPSO(0));\n\n    RenderUI();\n\n    ImGui::Render();\n    UpdateBuffers();\n\n    const int currBackBuffIdx = renderer.GetCurrentBackBufferIndex();\n\n    // Rendering\n    ImDrawData* draw_data = ImGui::GetDrawData();\n    auto& fr = m_imguiFrameBuffs[currBackBuffIdx];\n\n    // Setup desired DX state\n    // Setup orthographic projection matrix into our constant buffer\n    // Our visible imgui space lies from draw_data->DisplayPos (top left) to \n    // draw_data->DisplayPos+data_data->DisplaySize (bottom right).\n    cbGuiPass cb;\n\n    {\n        float L = draw_data->DisplayPos.x;\n        float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;\n        float T = draw_data->DisplayPos.y;\n        float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;\n        float mvp[4][4] =\n        {\n            { 2.0f / (R - L),   0.0f,           0.0f,       0.0f },\n            { 0.0f,         2.0f / (T - B),     0.0f,       0.0f },\n            { 0.0f,         0.0f,           0.5f,       0.0f },\n            { (R + L) / (L - R),  (T + B) / (B - T),    0.5f,       1.0f },\n        };\n        memcpy(&cb.WVP, mvp, sizeof(mvp));\n    }\n\n    void* userData = ImGui::GetIO().UserData;\n    memcpy(&cb.FontTex, &userData, sizeof(cb.FontTex));\n\n    D3D12_VIEWPORT viewports[1] = { renderer.GetDisplayViewport() };\n    directCmdList.RSSetViewports(1, viewports);\n\n    m_rootSig.SetRootConstants(0, sizeof(cb) / sizeof(DWORD), &cb);\n    m_rootSig.End(directCmdList);\n\n    // Bind shader and vertex buffers\n    unsigned int stride = sizeof(ImDrawVert);\n    unsigned int offset = 0;\n    D3D12_VERTEX_BUFFER_VIEW vbv{};\n    vbv.BufferLocation = fr.VertexBuffer.GpuVA() + offset;\n    vbv.SizeInBytes = fr.NumVertices * stride;\n    vbv.StrideInBytes = stride;\n\n    D3D12_INDEX_BUFFER_VIEW ibv{};\n    ibv.BufferLocation = fr.IndexBuffer.GpuVA();\n    ibv.SizeInBytes = fr.NumIndices * sizeof(ImDrawIdx);\n    ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;\n\n    directCmdList.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);\n    directCmdList.IASetVertexAndIndexBuffers(vbv, ibv);\n\n    Assert(m_cpuDescriptors[SHADER_IN_CPU_DESC::RTV].ptr > 0, \"RTV hasn't been set.\");\n    directCmdList.OMSetRenderTargets(1, &m_cpuDescriptors[SHADER_IN_CPU_DESC::RTV], true, nullptr);\n\n    // Setup blend factor\n    directCmdList.OMSetBlendFactor(0.0f, 0.0f, 0.0f, 0.0f);\n\n    // Render command lists\n    // (Because we merged all buffers into a single one, we maintain our own offset into them)\n    int global_vtx_offset = 0;\n    int global_idx_offset = 0;\n    ImVec2 clip_off = draw_data->DisplayPos;\n\n    for (int n = 0; n < draw_data->CmdListsCount; n++)\n    {\n        const ImDrawList* cmd_list = draw_data->CmdLists[n];\n        for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)\n        {\n            const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];\n\n            // Project scissor/clipping rectangles into framebuffer space\n            ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);\n            ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);\n            if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)\n                continue;\n\n            // Apply Scissor/clipping rectangle, Bind texture, Draw\n            const D3D12_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };\n            directCmdList.RSSetScissorRects(1, &r);\n\n            directCmdList.DrawIndexedInstanced(pcmd->ElemCount, 1,\n                pcmd->IdxOffset + global_idx_offset,\n                pcmd->VtxOffset + global_vtx_offset,\n                0);\n        }\n\n        global_idx_offset += cmd_list->IdxBuffer.Size;\n        global_vtx_offset += cmd_list->VtxBuffer.Size;\n    }\n\n    gpuTimer.EndQuery(directCmdList, queryIdx);\n\n    // HACK this is the last RenderPass, transition to PRESENT can be done here\n    directCmdList.ResourceBarrier(const_cast<Texture&>(renderer.GetCurrentBackBuffer()).Resource(),\n        D3D12_RESOURCE_STATE_RENDER_TARGET,\n        D3D12_RESOURCE_STATE_PRESENT);\n\n    directCmdList.PIXEndEvent();\n}\n\nvoid GuiPass::RenderUI()\n{\n    ImGuizmo::BeginFrame();\n\n    RenderToolbar();\n\n    if (!m_hideUI)\n    {\n        SceneCore& scene = App::GetScene();\n        TriangleMesh instanceMesh;\n        float4x4a W;\n        uint64_t firstPicked = Scene::INVALID_INSTANCE;\n\n        if (auto picks = scene.GetPickedInstances(); !picks.m_span.empty())\n        {\n            firstPicked = picks.m_span[0];\n\n            W = float4x4a(scene.GetToWorld(firstPicked));\n            instanceMesh = *scene.GetInstanceMesh(firstPicked).value();\n\n            if (m_gizmoActive)\n                RenderGizmo(picks.m_span, instanceMesh, W);\n        }\n\n        RenderSettings(firstPicked, instanceMesh, W);\n        RenderMainHeader();\n    }\n\n    m_firstTime = false;\n    m_appWndSizeChanged = false;\n}\n\nvoid GuiPass::RenderToolbar()\n{\n    ImGuiStyle& style = ImGui::GetStyle();\n    ImGui::PushStyleColor(ImGuiCol_ButtonHovered,\n        ImVec4(0.09521219013259f, 0.09521219013259f, 0.09521219013259f, 1.0f));\n    ImGui::PushStyleColor(ImGuiCol_ButtonActive,\n        ImVec4(0.0630100295f, 0.168269396f, 0.45078584552f, 1.0f));\n    ImGui::PushStyleColor(ImGuiCol_Button,\n        ImVec4(0.039556837f, 0.039556837f, 0.039556837f, 0.87f));\n    ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, 1));\n    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(1, 1));\n\n    ImGui::SetNextWindowPos(ImVec2((float)5.0f, m_headerWndHeight + 10.0f), ImGuiCond_Always);\n    ImGui::SetNextWindowSize(ImVec2(60.0f, 250.0f), ImGuiCond_Always);\n\n    ImGui::Begin(\"Toolbar\", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |\n        ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground);\n\n    ImGui::PopStyleVar();\n\n    ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, 1));\n\n    if (!m_hideUI)\n    {\n        const bool wasGizmoActive = m_gizmoActive;\n\n        if (!wasGizmoActive)\n            ImGui::PushStyleColor(ImGuiCol_Button, style.Colors[ImGuiCol_ButtonActive]);\n\n        if (ImGui::Button(ICON_FA_ARROW_POINTER \"##65\", ImVec2(40.0f, 40.0f)))\n            m_gizmoActive = !m_gizmoActive;\n        ImGui::SetItemTooltip(\"Select\");\n\n        if (!wasGizmoActive)\n            ImGui::PopStyleColor();\n\n        const bool isTranslation = m_gizmoActive && (m_currGizmoOperation == ImGuizmo::OPERATION::TRANSLATE);\n        const bool isRotation = m_gizmoActive && (m_currGizmoOperation == ImGuizmo::OPERATION::ROTATE);\n        const bool isScale = m_gizmoActive && (m_currGizmoOperation == ImGuizmo::OPERATION::SCALE);\n\n        if (isTranslation)\n            ImGui::PushStyleColor(ImGuiCol_Button, style.Colors[ImGuiCol_ButtonActive]);\n\n        if (ImGui::Button(ICON_FA_UP_DOWN_LEFT_RIGHT \"##3\", ImVec2(40.0f, 40.0f)))\n        {\n            m_currGizmoOperation = ImGuizmo::OPERATION::TRANSLATE;\n            m_gizmoActive = true;\n        }\n        ImGui::SetItemTooltip(\"Move (G)\");\n\n        if (isTranslation)\n            ImGui::PopStyleColor();\n\n        if (isRotation)\n            ImGui::PushStyleColor(ImGuiCol_Button, style.Colors[ImGuiCol_ButtonActive]);\n\n        if (ImGui::Button(ICON_FA_ARROWS_ROTATE \"##4\", ImVec2(40.0f, 40.0f)))\n        {\n            m_currGizmoOperation = ImGuizmo::OPERATION::ROTATE;\n            m_gizmoActive = true;\n        }\n        ImGui::SetItemTooltip(\"Rotate (R)\");\n\n        if (isRotation)\n            ImGui::PopStyleColor();\n\n        if (isScale)\n            ImGui::PushStyleColor(ImGuiCol_Button, style.Colors[ImGuiCol_ButtonActive]);\n\n        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, 2));\n\n        if (ImGui::Button(ICON_FA_ARROW_UP_RIGHT_FROM_SQUARE \"##5\", ImVec2(40.0f, 40.0f)))\n        {\n            m_currGizmoOperation = ImGuizmo::OPERATION::SCALE;\n            m_gizmoActive = true;\n        }\n        ImGui::SetItemTooltip(\"Scale (S)\");\n\n        if (isScale)\n            ImGui::PopStyleColor();\n\n        ImGui::PopStyleVar();\n\n        if (ImGui::IsKeyPressed(ImGuiKey_G))\n        {\n            m_currGizmoOperation = ImGuizmo::TRANSLATE;\n            m_gizmoActive = true;\n        }\n        else if (ImGui::IsKeyPressed(ImGuiKey_R))\n        {\n            m_currGizmoOperation = ImGuizmo::ROTATE;\n            m_gizmoActive = true;\n        }\n        else if (ImGui::IsKeyPressed(ImGuiKey_C))\n        {\n            m_currGizmoOperation = ImGuizmo::SCALE;\n            m_gizmoActive = true;\n        }\n    }\n\n    const char* icon = !m_hideUI ? ICON_FA_TOGGLE_ON \"##1\" : ICON_FA_TOGGLE_OFF \"##1\";\n    if (ImGui::Button(icon, ImVec2(40.0f, 40.0f)) ||\n        ImGui::IsKeyPressed(ImGuiKey_H))\n        m_hideUI = !m_hideUI;\n    ImGui::SetItemTooltip(\"Show/Hide UI (H)\");\n\n    if (ImGui::Button(ICON_FA_CAMERA_RETRO \"##2\", ImVec2(40.0f, 40.0f)))\n        App::GetScene().CaptureScreen();\n    ImGui::SetItemTooltip(\"Take Screenshot\");\n\n    ImGui::PopStyleColor(3);\n    ImGui::PopStyleVar(2);\n\n    ImGui::End();\n}\n\nvoid GuiPass::RenderSettings(uint64 pickedID, const TriangleMesh& mesh, const float4x4a& W)\n{ \n    const int displayWidth = App::GetRenderer().GetDisplayWidth();\n    const int displayHeight = App::GetRenderer().GetDisplayHeight();\n\n    // Round to nearest\n    const int wndSizeX = (int)std::fmaf((float)displayWidth, m_dbgWndWidthPct, 0.5f);\n    const int wndSizeY = (int)std::fmaf((float)displayHeight, m_dbgWndHeightPct, 0.5f);\n    const int wndPosX = displayWidth - wndSizeX;\n    m_headerWndWidth = wndPosX;\n\n    ImGui::SetNextWindowPos(ImVec2((float)wndPosX, 0.0f), ImGuiCond_Always);\n    ImGui::SetNextWindowSize(ImVec2((float)wndSizeX, (float)wndSizeY), ImGuiCond_Always);\n    // Hide resize grip\n    ImGuiStyle& style = ImGui::GetStyle();\n    ImGui::PushStyleColor(ImGuiCol_ResizeGrip, 0);\n    ImGui::PushStyleColor(ImGuiCol_ResizeGripHovered, 0);\n    ImGui::PushStyleColor(ImGuiCol_ResizeGripActive, 0);\n    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10.0f, style.WindowPadding.y));\n\n    if (ImGui::Begin(ICON_FA_WRENCH \" Settings\", nullptr, ImGuiWindowFlags_HorizontalScrollbar |\n        ImGuiWindowFlags_NoMove))\n    {\n        m_dbgWndWidthPct = ImGui::GetWindowWidth() / (float)displayWidth;\n        m_dbgWndHeightPct = !ImGui::IsWindowCollapsed() ? ImGui::GetWindowHeight() / (float)displayHeight :\n            m_dbgWndHeightPct;\n\n        if (ImGui::CollapsingHeader(ICON_FA_INFO \"  Info\", ImGuiTreeNodeFlags_None))\n        {\n            InfoTab();\n            ImGui::Text(\"\");\n        }\n\n        if (ImGui::CollapsingHeader(ICON_FA_CAMERA \"  Camera\", ImGuiTreeNodeFlags_None))\n        {\n            CameraTab();\n            ImGui::Text(\"\");\n        }\n\n        {\n            ParameterTab();\n        }\n\n        if (pickedID != Scene::INVALID_INSTANCE)\n        {\n            if (ImGui::CollapsingHeader(ICON_FA_CUBE \"  Object\"))\n            {\n                PickedWorldTransform(pickedID, mesh, W);\n                ImGui::Text(\"\");\n            }\n\n            if (ImGui::CollapsingHeader(ICON_FA_PALETTE \"  Material\"))\n            {\n                PickedMaterial(pickedID);\n                ImGui::Text(\"\");\n            }\n        }\n\n        //if (ImGui::CollapsingHeader(\"Style\", ImGuiTreeNodeFlags_None))\n        //{\n        //    if (ImGui::BeginTabBar(\"##tabs\", ImGuiTabBarFlags_None))\n        //    {\n        //        ShowStyles();\n        //        ImGui::EndTabBar();\n        //    }\n\n        //    ImGui::Text(\"\");\n        //}\n\n        if (ImGui::CollapsingHeader(ICON_FA_ROTATE_RIGHT \"  Shader Hot-Reload\", ImGuiTreeNodeFlags_None))\n        {\n            ShaderReloadTab();\n            ImGui::Text(\"\");\n        }\n\n        RenderProfiler();\n    }\n\n    ImGui::PopStyleVar();\n    ImGui::PopStyleColor(3);\n    ImGui::End();\n}\n\nvoid GuiPass::RenderProfiler()\n{\n    auto& timer = App::GetTimer();\n    auto& scene = App::GetScene();;\n\n    if (ImGui::CollapsingHeader(ICON_FA_CHART_LINE \"  Stats\", ImGuiTreeNodeFlags_None))\n    {\n        ImGui::Text(\"Frame %llu\", timer.GetTotalFrameCount());\n        ImGui::SeparatorText(\"Performance\");\n\n        auto func = [](Stat& s)\n            {\n                switch (s.GetType())\n                {\n                case Stat::ST_TYPE::ST_INT:\n                    ImGui::Text(\"\\t%s: %d\", s.GetName(), s.GetInt());\n                    break;\n\n                case Stat::ST_TYPE::ST_UINT:\n                    ImGui::Text(\"\\t%s: %u\", s.GetName(), s.GetUInt());\n                    break;\n\n                case Stat::ST_TYPE::ST_FLOAT:\n                    ImGui::Text(\"\\t%s: %.2f\", s.GetName(), s.GetFloat());\n                    break;\n\n                case Stat::ST_TYPE::ST_UINT64:\n                    ImGui::Text(\"\\t%s: %llu\", s.GetName(), s.GetUInt64());\n                    break;\n\n                case Stat::ST_TYPE::ST_RATIO:\n                {\n                    uint32_t num;\n                    uint32_t total;\n                    s.GetRatio(num, total);\n\n                    ImGui::Text(\"\\t%s: %u/%u\", s.GetName(), num, total);\n                }\n                break;\n\n                default:\n                    break;\n                }\n            };\n\n        for (auto s : App::GetStats().m_span)\n            func(s);\n\n        ImGui::SeparatorText(\"Scene\");\n        ImGui::Text(\"\\t#Instances: %u\", (uint32_t)scene.TotalNumInstances());\n        ImGui::Text(\"\\t#Meshes: %u\", (uint32_t)scene.TotalNumMeshes());\n        ImGui::Text(\"\\t#Triangles: %u\", (uint32_t)scene.TotalNumTriangles());\n        ImGui::Text(\"\\t#Materials: %u\", (uint32_t)scene.TotalNumMaterials());\n        ImGui::Text(\"\\t#Emissive Instances: %u\", (uint32_t)scene.NumEmissiveInstances());\n        ImGui::Text(\"\\t#Emissive Triangles: %u\", (uint32_t)scene.NumEmissiveTriangles());\n\n        ImGui::Text(\"\");\n    }\n\n    if (ImGui::CollapsingHeader(ICON_FA_CLOCK \"  GPU Timings\", ImGuiTreeNodeFlags_DefaultOpen))\n    {\n        auto frameTimeHist = App::GetFrameTimeHistory();\n        const float w = ImGui::GetWindowWidth();\n\n        float maxTime = 0.0f;\n        for (auto f : frameTimeHist)\n            maxTime = Math::Max(maxTime, f);\n\n        if (ImPlot::BeginPlot(\"Frame Time\", ImVec2(w * m_frameHistWidthPct, 150.0f), ImPlotFlags_NoLegend))\n        {\n            ImPlot::SetupAxes(\"Moving Window\", \"Time (ms)\", 0, ImPlotAxisFlags_NoHighlight);\n            ImPlot::SetupAxesLimits(0, (double)frameTimeHist.size(), 0, maxTime + 1.0, ImGuiCond_Always);\n            //ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);\n            ImPlot::PushStyleColor(ImPlotCol_Line, ImVec4(85 / 255.0f, 85 / 255.0f, 85 / 255.0f, 1.0f));\n\n            ImGuiStyle& style = ImGui::GetStyle();\n            ImVec4* colors = style.Colors;\n            const auto wndCol = colors[ImGuiCol_WindowBg];\n\n            ImPlot::PushStyleColor(ImPlotCol_FrameBg, wndCol);\n            ImPlot::PlotLine(\"\", frameTimeHist.data(), (int)frameTimeHist.size());\n            ImPlot::PopStyleColor();\n            ImPlot::EndPlot();\n        }\n\n        ImGui::Text(\"\");\n\n        GpuTimingsTab();\n    }\n}\n\nvoid GuiPass::RenderLogWindow()\n{\n    ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.014286487f, 0.014286487f, 0.0142864870f, 0.995f));\n    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(15, 15));\n    // Hide resize grip\n    ImGui::PushStyleColor(ImGuiCol_ResizeGrip, 0);\n    ImGui::PushStyleColor(ImGuiCol_ResizeGripHovered, 0);\n    ImGui::PushStyleColor(ImGuiCol_ResizeGripActive, 0);\n\n    const int displayHeight = App::GetRenderer().GetDisplayHeight();\n    const int wndSizeY = (int)std::fmaf((float)displayHeight, m_logWndHeightPct, 0.5f);\n    ImGui::SetNextWindowSize(ImVec2((float)m_headerWndWidth, (float)wndSizeY), ImGuiCond_Always);\n    ImGui::SetNextWindowPos(ImVec2(0, (float)m_headerWndHeight), ImGuiCond_Always);\n\n    ImGui::Begin(\"Logs\", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove);\n\n    m_logWndHeightPct = ImGui::GetWindowHeight() / (float)displayHeight;\n\n    auto& frameLogs = App::GetLogs().View();\n    ImGui::Text(\"#Items: %d\\t\", (int)frameLogs.size());\n    ImGui::SameLine();\n\n    if (ImGui::Button(ICON_FA_TRASH_CAN \"  Clear\"))\n        frameLogs.clear();\n\n    ImGui::SameLine();\n\n    if (ImGui::Button(ICON_FA_XMARK \"  Close\"))\n        m_manuallyCloseLogsTab = true;\n\n    ImGui::Separator();\n\n    ImGui::BeginChild(\"scrolling\", ImVec2(0, 0), false, ImGuiChildFlags_AlwaysUseWindowPadding);\n\n    // TODO consider using ImGuiListClipper\n    for (auto& msg : frameLogs)\n    {\n        ImVec4 color = msg.Type == App::LogMessage::INFO ? ImVec4(0.3f, 0.4f, 0.5f, 1.0f) :\n            ImVec4(0.4f, 0.2f, 0.2f, 1.0f);\n        ImGui::TextColored(color, msg.Msg);\n    }\n\n    ImGui::PopStyleVar();\n    ImGui::PopStyleColor(4);\n\n    if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY())\n        ImGui::SetScrollHereY(1.0f);\n\n    ImGui::EndChild();\n\n    ImGui::End();\n}\n\nvoid GuiPass::RenderMainHeader()\n{\n    ImGuiStyle& style = ImGui::GetStyle();\n    ImGui::PushStyleColor(ImGuiCol_Tab, style.Colors[ImGuiCol_WindowBg]);\n    ImGui::PushStyleColor(ImGuiCol_TabSelected,\n        ImVec4(0.0295568369f, 0.0295568369f, 0.0295568369f, 1.0f));\n    ImGui::PushStyleColor(ImGuiCol_TabHovered, \n        ImVec4(0.05098039215f, 0.05490196078f, 0.05490196078f, 1.0f));\n\n    ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(15, style.ItemInnerSpacing.y));\n    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, style.WindowPadding.y));\n\n    const int displayHeight = App::GetRenderer().GetDisplayHeight();\n    const int wndHeight = (int)std::fmaf(m_headerWndHeightPct, (float)displayHeight, 0.5f);\n\n    ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiCond_Always);\n    ImGui::SetNextWindowSize(ImVec2((float)m_headerWndWidth, (float)wndHeight), ImGuiCond_Always);\n\n    ImGui::Begin(\"Main\", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | \n        ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize);\n\n    m_headerWndHeight = (int)ImGui::GetWindowHeight();\n\n    ImGui::Text(\"        \");\n    ImGui::SameLine();\n    ImGui::BeginTabBar(\"Header\", ImGuiTabBarFlags_None);\n\n    auto flags = ImGuiTabItemFlags_None;\n    if (m_manuallyCloseLogsTab)\n    {\n        flags = ImGuiTabItemFlags_SetSelected;\n        m_manuallyCloseLogsTab = false;\n    }\n    const bool showMainWnd = ImGui::BeginTabItem(ICON_FA_DISPLAY \"        Main        \", \n        nullptr, flags);\n    if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNone))\n    {\n        ImGui::PopStyleVar();\n        ImGui::SetTooltip(\"Scene View\");\n        ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, style.WindowPadding.y));\n    }\n\n    if (showMainWnd)\n        ImGui::EndTabItem();\n\n    const bool renderGraphTab = ImGui::BeginTabItem(ICON_FA_SHARE_NODES \"        Render Graph        \");\n\n    if (ImGui::IsItemHovered())\n    {\n        ImGui::PopStyleVar();\n        ImGui::SetTooltip(\"Render Graph Visualization (Use RMB for panning).\");\n        ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, style.WindowPadding.y));\n    }\n\n    if (renderGraphTab)\n    {\n        const float headerWndHeight = ImGui::GetWindowHeight();\n\n        ImGui::SetNextWindowSize(ImVec2((float)m_headerWndWidth, displayHeight - headerWndHeight),\n            ImGuiCond_Once);\n        ImGui::SetNextWindowPos(ImVec2(0, headerWndHeight), ImGuiCond_Always);\n\n        ImGui::Begin(\" \", nullptr, ImGuiWindowFlags_NoMove);\n        App::GetScene().DebugDrawRenderGraph();\n        ImGui::End();\n\n        ImGui::EndTabItem();\n    }\n\n    flags = ImGuiTabItemFlags_None;\n\n    // Open the logs tabs whene there are new warnings\n    if(!m_logsTabOpen)\n    {\n        auto& logs = App::GetLogs().View();\n        const int numLogs = (int)logs.size();\n\n        if (numLogs != m_prevNumLogs)\n        {\n            for (int i = m_prevNumLogs; i < numLogs; i++)\n            {\n                if (logs[i].Type == App::LogMessage::WARNING)\n                {\n                    flags = ImGuiTabItemFlags_SetSelected;\n                    break;\n                }\n            }\n        }\n\n        m_prevNumLogs = numLogs;\n    }\n\n    m_logsTabOpen = ImGui::BeginTabItem(ICON_FA_TERMINAL \"        Logs        \",\n        nullptr, flags);\n    if(m_logsTabOpen)\n    {\n        RenderLogWindow();\n        ImGui::EndTabItem();\n    }\n\n    ImGui::EndTabBar();\n\n    ImGui::PopStyleColor(3);\n    ImGui::PopStyleVar(2);\n\n    ImGui::End();\n}\n\nvoid GuiPass::RenderGizmo(Span<uint64_t> pickedIDs, const TriangleMesh& mesh, const float4x4a& W)\n{\n    if (!ImGuizmo::IsUsingAny())\n    {\n        const auto& camera = App::GetCamera();\n        auto& frustum = camera.GetCameraFrustumViewSpace();\n        auto viewInv = camera.GetViewInv();\n\n        // Transform view frustum from view space into world space\n        v_float4x4 vViewInv = load4x4(const_cast<float4x4a&>(viewInv));\n        v_ViewFrustum vFrustum(const_cast<ViewFrustum&>(frustum));\n        vFrustum = transform(vViewInv, vFrustum);\n\n        v_float4x4 vW = load4x4(W);\n        v_AABB vBox(mesh.m_AABB);\n        vBox = transform(vW, vBox);\n\n        // Avoid drawing the gizmo if picked instance is outside the frustum\n        if (instersectFrustumVsAABB(vFrustum, vBox) == COLLISION_TYPE::DISJOINT)\n            return;\n    }\n\n    ImGuiIO& io = ImGui::GetIO();\n    ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);\n\n    float3 dt;\n    float4x4a dr;\n    float3 ds;\n    float4x4a W_new = W;\n    bool modified = ImGuizmo::Manipulate(static_cast<ImGuizmo::OPERATION>(m_currGizmoOperation), \n        ImGuizmo::WORLD, W_new, dt, dr, ds, nullptr);\n\n    if (modified)\n    {\n        for(auto ID : pickedIDs)\n            App::GetScene().TransformInstance(ID, dt, float3x3(dr), ds);\n    }\n}\n\nvoid GuiPass::InfoTab()\n{\n    const float pad = 128.0f * App::GetDPIScaling();\n\n    auto& renderer = App::GetRenderer();\n    ImGui::Text(\" - Device:\");\n    ImGui::SameLine(pad);\n    ImGui::Text(\"%s\", renderer.GetDeviceDescription());\n    ImGui::Text(\" - Render Resolution:\");\n    ImGui::SameLine(pad);\n    ImGui::Text(\"%d x %d\", renderer.GetRenderWidth(), \n        renderer.GetRenderHeight());\n    ImGui::Text(\" - Display Resolution:\");\n    ImGui::SameLine(pad);\n    ImGui::Text(\"%d x %d (%u DPI)\", renderer.GetDisplayWidth(), \n        renderer.GetDisplayHeight(), App::GetDPI());\n}\n\nvoid GuiPass::CameraTab()\n{\n    const Camera& camera = App::GetCamera();\n    float3 camPos = camera.GetPos();\n    float3 viewBasisX = camera.GetBasisX();\n    float3 viewBasisY = camera.GetBasisY();\n    float3 viewBasisZ = camera.GetBasisZ();\n\n    const float pad = 220.0f * App::GetDPIScaling();\n    ImGui::Text(\" - Camera Position: (%.3f, %.3f, %.3f)\", camPos.x, camPos.y, camPos.z);\n    ImGui::SameLine(pad);\n    if (ImGui::Button(ICON_FA_COPY \" Copy##0\"))\n    {\n        StackStr(buffer, n, \"%.4f, %.4f, %.4f\", camPos.x, camPos.y, camPos.z);\n        App::CopyToClipboard(buffer);\n    }\n    ImGui::SetItemTooltip(\"Copy vector to clipboard\");\n\n    ImGui::Text(\" - View Basis X: (%.3f, %.3f, %.3f)\", viewBasisX.x, viewBasisX.y, viewBasisX.z);\n    ImGui::Text(\" - View Basis Y: (%.3f, %.3f, %.3f)\", viewBasisY.x, viewBasisY.y, viewBasisY.z);\n    ImGui::Text(\" - View Basis Z: (%.3f, %.3f, %.3f)\", viewBasisZ.x, viewBasisZ.y, viewBasisZ.z);\n    ImGui::SameLine(pad);\n    if (ImGui::Button(ICON_FA_COPY \" Copy##1\"))\n    {\n        StackStr(buffer, n, \"%.4f, %.4f, %.4f\", viewBasisZ.x, viewBasisZ.y, viewBasisZ.z);\n        App::CopyToClipboard(buffer);\n    }\n    ImGui::SetItemTooltip(\"Copy vector to clipboard\");\n\n    ImGui::Text(\" - Aspect Ratio: %f\", camera.GetAspectRatio());\n\n    constexpr int plotFlags = ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect | ImPlotFlags_NoMouseText | ImPlotFlags_Equal;\n\n    if (ImPlot::BeginPlot(\"Camera Coordinate System\", ImVec2(250.0f, 250.0f), plotFlags))\n    {\n        const float3 pos = camera.GetPos();\n        constexpr int axisFlags = ImPlotAxisFlags_Lock | ImPlotAxisFlags_NoHighlight;\n        ImPlot::SetupAxes(\"X\", \"Z\", axisFlags, axisFlags);\n        ImPlot::SetupAxesLimits(pos.x - 3, pos.x + 3, pos.z - 3, pos.z + 3, ImGuiCond_Always);\n\n        ImGuiStyle& style = ImGui::GetStyle();\n        ImVec4* colors = style.Colors;\n        const auto wndCol = colors[ImGuiCol_WindowBg];\n        ImPlot::PushStyleColor(ImPlotCol_FrameBg, wndCol);\n\n        const float3 xAxis = camera.GetBasisX();\n        const float3 zAxis = camera.GetBasisZ();\n        DrawAxis(pos, xAxis, zAxis, float3(0.99f, 0.15f, 0.05f), float3(0.1f, 0.5f, 0.99f), 3.0f);\n\n        ImPlot::PopStyleColor();\n        ImPlot::EndPlot();\n    }\n\n    ImGui::SeparatorText(\"Parameters\");\n\n    {\n        auto params = App::GetParams();\n\n        // Partition by \"Scene\"\n        auto firstNonScene = std::partition(params.m_span.begin(), params.m_span.end(), \n            [](const ParamVariant& p)\n            {\n                return strcmp(p.GetGroup(), ICON_FA_LANDMARK \" Scene\") == 0;\n            });\n        // Partition by \"Camera\"\n        auto firstNonCamera = std::partition(params.m_span.begin(), firstNonScene, \n            [](const ParamVariant& p)\n            {\n                return strcmp(p.GetSubGroup(), \"Camera\") == 0;\n            });\n        const int numCameraParams = (int)(firstNonCamera - params.m_span.data());\n        if (numCameraParams == 0)\n            return;\n\n        std::sort(params.m_span.begin(), firstNonCamera,\n            [](const ParamVariant& p1, const ParamVariant& p2)\n            {\n                return strcmp(p1.GetSubSubGroup(), p2.GetSubSubGroup()) < 0;\n            });\n\n        char curr[ParamVariant::MAX_SUBSUBGROUP_LEN];\n        size_t len = strlen(params.m_span[0].GetSubSubGroup());\n        memcpy(curr, params.m_span[0].GetSubSubGroup(), len);\n        curr[len] = '\\0';\n        int beg = 0;\n        int i = 0;\n\n        for (i = 0; i < numCameraParams; i++)\n        {\n            if (strcmp(params.m_span[i].GetSubSubGroup(), curr) != 0)\n            {\n                if (ImGui::TreeNodeEx(curr))\n                {\n                    AddParamRange(params.m_span, beg, (int)(i - beg));\n                    ImGui::TreePop();\n                }\n\n                len = strlen(params.m_span[i].GetSubSubGroup());\n                memcpy(curr, params.m_span[i].GetSubSubGroup(), len);\n                curr[len] = '\\0';\n                beg = i;\n            }\n        }\n\n        if (ImGui::TreeNodeEx(curr))\n        {\n            AddParamRange(params.m_span, beg, i - beg);\n            ImGui::TreePop();\n        }\n    }\n}\n\nvoid GuiPass::ParameterTab()\n{\n    auto params = App::GetParams();\n    char currGroup[ParamVariant::MAX_GROUP_LEN];\n\n    ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.55f);\n\n    // Sort by group\n    std::sort(params.m_span.begin(), params.m_span.end(), \n        [](const ParamVariant& p1, const ParamVariant& p2)\n        {\n            return strcmp(p1.GetGroup(), p2.GetGroup()) < 0;\n        });\n\n    for (int currGroupIdx = 0; currGroupIdx < (int)params.m_span.size();)\n    {\n        ParamVariant& currParam_g = params.m_span[currGroupIdx];\n        const size_t groupLen = strlen(currParam_g.GetGroup());\n        memcpy(currGroup, currParam_g.GetGroup(), groupLen);\n        currGroup[groupLen] = '\\0';\n\n        // Find the range of parameters for this group\n        int nextGroupIdx = currGroupIdx;\n        while (nextGroupIdx < params.m_span.size() && \n            (strcmp(params.m_span[nextGroupIdx].GetGroup(), currGroup) == 0))\n            nextGroupIdx++;\n\n        if (ImGui::CollapsingHeader(currParam_g.GetGroup(), ImGuiTreeNodeFlags_DefaultOpen))\n        {\n            char currSubGroup[ParamVariant::MAX_SUBGROUP_LEN];\n\n            // Sort by subgroup among current group\n            std::sort(params.m_span.begin() + currGroupIdx, params.m_span.begin() + nextGroupIdx,\n                [](const ParamVariant& p1, const ParamVariant& p2)\n                {\n                    return strcmp(p1.GetSubGroup(), p2.GetSubGroup()) < 0;\n                });\n\n            // Add the parameters in this subgroup\n            for (int currSubgroupIdx = currGroupIdx; currSubgroupIdx < nextGroupIdx;)\n            {\n                ParamVariant& currParam_s = params.m_span[currSubgroupIdx];\n                const char* subGroupName = currParam_s.GetSubGroup();\n                const size_t subGroupLen = strlen(subGroupName);\n                memcpy(currSubGroup, subGroupName, subGroupLen);\n                currSubGroup[subGroupLen] = '\\0';\n\n                int nextSubgroupIdx = currSubgroupIdx;\n                while (nextSubgroupIdx < params.m_span.size() &&\n                    (strcmp(params.m_span[nextSubgroupIdx].GetSubGroup(), currSubGroup) == 0))\n                    nextSubgroupIdx++;\n\n                if (strcmp(subGroupName, \"Camera\") == 0)\n                {\n                    currSubgroupIdx = nextSubgroupIdx;\n                    continue;\n                }\n\n                if (ImGui::TreeNode(currParam_s.GetSubGroup()))\n                {\n                    char currSubsubGroup[ParamVariant::MAX_SUBSUBGROUP_LEN];\n\n                    // If there are no subsubgroups, show everything in just one subgroup\n                    // instead of a subgroup with one empty subsubgroup\n                    bool hasSubsubgroups = false;\n                    for (int i = currSubgroupIdx; i < nextSubgroupIdx; i++)\n                    {\n                        if (params.m_span[i].GetSubSubGroup()[0] != '\\0')\n                        {\n                            hasSubsubgroups = true;\n                            break;\n                        }\n                    }\n\n                    // Sort by subsubgroup among current subgroup\n                    std::sort(params.m_span.begin() + currSubgroupIdx, params.m_span.begin() + nextSubgroupIdx,\n                        [](const ParamVariant& p1, const ParamVariant& p2)\n                        {\n                            return strcmp(p1.GetSubSubGroup(), p2.GetSubSubGroup()) < 0;\n                        });\n\n                    if (hasSubsubgroups)\n                    {\n                        for (int currSubsubgroupIdx = currSubgroupIdx; currSubsubgroupIdx < nextSubgroupIdx;)\n                        {\n                            ParamVariant& currParam_ss = params.m_span[currSubsubgroupIdx];\n                            const size_t subSubgroupLen = strlen(currParam_ss.GetSubSubGroup());\n                            memcpy(currSubsubGroup, currParam_ss.GetSubSubGroup(), subSubgroupLen);\n                            currSubsubGroup[subSubgroupLen] = '\\0';\n\n                            int nextSubsubgroupIdx = currSubsubgroupIdx;\n                            while (nextSubsubgroupIdx < params.m_span.size() &&\n                                (strcmp(params.m_span[nextSubsubgroupIdx].GetSubSubGroup(), currSubsubGroup) == 0))\n                                nextSubsubgroupIdx++;\n\n                            if (subSubgroupLen > 0)\n                            {\n                                ImGui::SeparatorText(currParam_ss.GetSubSubGroup());\n                                AddParamRange(params.m_span, currSubsubgroupIdx, nextSubsubgroupIdx - currSubsubgroupIdx);\n                            }\n                            else\n                                AddParamRange(params.m_span, currSubsubgroupIdx, nextSubsubgroupIdx - currSubsubgroupIdx);\n\n                            currSubsubgroupIdx = nextSubsubgroupIdx;\n                        }\n                    }\n                    else\n                        AddParamRange(params.m_span, currSubgroupIdx, nextSubgroupIdx - currSubgroupIdx);\n\n                    ImGui::TreePop();\n                }\n\n                currSubgroupIdx = nextSubgroupIdx;\n            }\n\n            ImGui::Text(\"\");\n        }\n\n        currGroupIdx = nextGroupIdx;\n    }\n\n    ImGui::PopItemWidth();\n}\n\nvoid GuiPass::GpuTimingsTab()\n{\n        auto timings = App::GetRenderer().GetGpuTimer().GetFrameTimings();\n        if(timings.empty())\n        {\n            m_gpuTimings.clear();\n            return;\n        }\n\n        // Temporary copy of previous timings needed for shuffling\n        SmallVector<RenderPassTiming, App::FrameAllocator> prev;\n        prev.append_range(m_gpuTimings.begin(), m_gpuTimings.end());\n\n        m_gpuTimings.resize(timings.size());\n\n        // timings is sorted, so insertion happens in sorted order\n        for(size_t i = 0; i < timings.size(); i++)\n        {\n            auto it = std::lower_bound(prev.begin(), prev.end(), timings[i], \n                [](const RenderPassTiming& item, const GpuTimer::Timing& key)\n                {\n                    return strcmp(item.Name, key.Name) < 0;\n                });\n\n            if(it == prev.end())\n                _mm256_store_ps(m_gpuTimings[i].Delta, _mm256_setzero_ps());\n            else\n            {\n                // Shift right\n                auto idx = it - prev.begin();\n                memcpy(m_gpuTimings[i].Delta + 1, prev[idx].Delta, sizeof(float) * 7);\n            }\n\n            memcpy(m_gpuTimings[i].Name, timings[i].Name, GpuTimer::Timing::MAX_NAME_LENGTH);\n            m_gpuTimings[i].Delta[0] = (float)timings[i].Delta;\n        }\n\n    constexpr ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_ScrollX | \n        ImGuiTableFlags_Hideable | ImGuiTableFlags_RowBg | ImGuiTableFlags_PadOuterX | \n        ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingStretchProp;\n\n    // When using ScrollX or ScrollY we need to specify a size for our table container!\n    // Otherwise by default the table will fit all available space, like a BeginChild() call.\n    const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();\n    ImVec2 outer_size = ImVec2(0, TEXT_BASE_HEIGHT * 11);\n    if (ImGui::BeginTable(\"table_scrolly\", 2, flags, outer_size))\n    {\n        ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible\n\n        ImGui::TableSetupColumn(\"\\t\\tRender Pass\", ImGuiTableColumnFlags_None);\n        ImGui::TableSetupColumn(\"\\t\\tDelta (ms)\", ImGuiTableColumnFlags_None);\n        ImGui::TableHeadersRow();\n\n        for (int row = 0; row < (int)m_gpuTimings.size(); row++)\n        {\n            ImGui::TableNextRow();\n\n            ImGui::TableSetColumnIndex(0);\n            ImGui::Text(\" %s\", m_gpuTimings[row].Name);\n\n            ImGui::TableSetColumnIndex(1);\n\n            float sum = 0.0f;\n            for(int i = 0; i < RenderPassTiming::WND_LEN; i++)\n                sum += m_gpuTimings[row].Delta[i];\n\n            ImGui::Text(\"\\t\\t\\t%.3f\", sum / RenderPassTiming::WND_LEN);\n        }\n\n        ImGui::EndTable();\n    }\n}\n\nvoid GuiPass::ShaderReloadTab()\n{\n    auto handlers = App::GetShaderReloadHandlers();\n\n    if (!handlers.m_span.empty())\n    {\n        std::sort(handlers.m_span.begin(), handlers.m_span.end(), \n            [](const App::ShaderReloadHandler& lhs, const App::ShaderReloadHandler& rhs)\n            {\n                return strcmp(lhs.Name, rhs.Name) < 0;\n            });\n    }\n\n    ImGui::Text(\"Select a shader to reload:\");\n\n    // TODO m_currShader becomes invalid when there's been a change in reloadHandlers \n    if (ImGui::BeginCombo(\"Shader\", m_currShader >= 0 ? handlers.m_span[m_currShader].Name : \"None\", 0))\n    {\n        int i = 0;\n\n        for (auto& handler : handlers.m_span)\n        {\n            bool selected = (m_currShader == i);\n            if (ImGui::Selectable(handler.Name, selected))\n                m_currShader = i;\n\n            if (selected)\n                ImGui::SetItemDefaultFocus();\n\n            i++;\n        }\n\n        ImGui::EndCombo();\n    }\n\n    if (m_currShader == -1)\n        ImGui::BeginDisabled();\n\n    if (ImGui::Button(\"Reload\"))\n        handlers.m_span[m_currShader].Dlg();\n\n    if (m_currShader == -1)\n        ImGui::EndDisabled();\n}\n\nvoid GuiPass::PickedWorldTransform(uint64 pickedID, const TriangleMesh& mesh, const float4x4a& W)\n{\n    // Instance info\n    if (ImGui::TreeNodeEx(\"Info\", ImGuiTreeNodeFlags_NoTreePushOnOpen))\n    {\n        const float pad = 96.0f * App::GetDPIScaling();\n\n        ImGui::Text(\" - ID:\");\n        ImGui::SameLine(pad);\n        ImGui::Text(\"%llu\", pickedID);\n        ImGui::Text(\" - #Vertices:\");\n        ImGui::SameLine(pad);\n        ImGui::Text(\"%u\", mesh.m_numVertices);\n        ImGui::Text(\" - #Triangles:\");\n        ImGui::SameLine(pad);\n        ImGui::Text(\"%u\", mesh.m_numIndices / 3);\n        ImGui::Text(\" - Material ID:\");\n        ImGui::SameLine(pad);\n        ImGui::Text(\"%u\", mesh.m_materialID);\n        ImGui::Text(\"\");\n    }\n\n    bool modified = false;\n    auto& scene = App::GetScene();\n    AffineTransformation prevTr = AffineTransformation::GetIdentity();\n    AffineTransformation newTr = AffineTransformation::GetIdentity();\n\n    if (ImGui::TreeNodeEx(\"Transformation\", ImGuiTreeNodeFlags_NoTreePushOnOpen))\n    {\n        const bool isLocal = m_transform == TRANSFORMATION::LOCAL;\n\n        if (isLocal)\n        {\n            prevTr = scene.GetLocalTransform(pickedID);\n            newTr = prevTr;\n        }\n        else\n        {\n            v_float4x4 vW = load4x4(W);\n\n            float4a s;\n            float4a r;\n            float4a t;\n            decomposeSRT(vW, s, r, t);\n\n            newTr.Translation = t.xyz();\n            newTr.Rotation = r;\n            newTr.Scale = s.xyz();\n        }\n\n        auto axisOrQuatXyz = newTr.Rotation.xyz();\n        float angle_r = newTr.Rotation.w;\n        float angle_d = newTr.Rotation.w;\n        if (m_rotationMode == ROTATION_MODE::AXIS_ANGLE)\n        {\n            quaternionToAxisAngle(newTr.Rotation, axisOrQuatXyz, angle_r);\n            angle_d = RadiansToDegrees(angle_r);\n        }\n\n        // Transformation mode\n        {\n            const float pad = 48.0f * App::GetDPIScaling();\n            const char* modes[] = { \"Local\", \"World\" };\n            ImGui::Text(\"\");\n            ImGui::SameLine(pad);\n            ImGui::Text(\"Mode\");\n            ImGui::SameLine();\n            ImGui::Combo(\"##20\", (int*)&m_transform, modes, ZetaArrayLen(modes));\n        }\n\n        if (!isLocal)\n            ImGui::BeginDisabled();\n\n        // Translation\n        {\n            ImGui::Text(\"Translation X\");\n            ImGui::SameLine();\n            if (ImGui::SliderFloat(\"##0\", &newTr.Translation.x, -50.0f, 50.0f, \"%.2f\"))\n                modified = true;\n\n            const float pad = 69.6f * App::GetDPIScaling();\n            ImGui::Text(\"\");\n            ImGui::SameLine(pad);\n            ImGui::Text(\"Y\");\n            ImGui::SameLine();\n            if (ImGui::SliderFloat(\"##1\", &newTr.Translation.y, -15.0f, 15.0f, \"%.2f\"))\n                modified = true;\n\n            ImGui::Text(\"\");\n            ImGui::SameLine(pad);\n            ImGui::Text(\"Z\");\n            ImGui::SameLine();\n            if (ImGui::SliderFloat(\"##2\", &newTr.Translation.z, -50.0f, 50.0f, \"%.2f\"))\n                modified = true;\n        }\n\n        // Rotation\n        {\n            // When angle = 0 or 2 PI, setting axis results in a zero quaternion and would\n            // have the effect of UI change not applying. As a workaround use a small\n            // angle =~ zero.\n            constexpr float MIN_ANGLE = 1e-5f;\n            constexpr float MAX_ANGLE = TWO_PI - 1e-5f;\n\n            auto getQuat = [](float3& n, float theta)\n                {\n                    n.normalize();\n                    theta = Min(theta, MAX_ANGLE);\n                    theta = Max(theta, MIN_ANGLE);\n                    return float4(n * sinf(0.5f * theta), cosf(0.5f * theta));\n                };\n\n            const float pad_x = 21.6f * App::GetDPIScaling();\n            ImGui::Text(\"\");\n            ImGui::SameLine(pad_x);\n            ImGui::Text(\"Rotation X\");\n            ImGui::SameLine();\n            if (ImGui::SliderFloat(\"##4\", &axisOrQuatXyz.x, -1.0f, 1.0f, \"%.3f\", ImGuiSliderFlags_AlwaysClamp))\n            {\n                if (m_rotationMode == ROTATION_MODE::AXIS_ANGLE)\n                    newTr.Rotation = getQuat(axisOrQuatXyz, angle_r);\n                else\n                {\n                    newTr.Rotation = float4(axisOrQuatXyz, prevTr.Rotation.w);\n                    newTr.Rotation.normalize();\n                }\n\n                modified = true;\n            }\n\n            const float pad_y = 69.6f * App::GetDPIScaling();\n            ImGui::Text(\"\");\n            ImGui::SameLine(pad_y);\n            ImGui::Text(\"Y\");\n            ImGui::SameLine();\n            if (ImGui::SliderFloat(\"##5\", &axisOrQuatXyz.y, -1.0f, 1.0f, \"%.3f\", ImGuiSliderFlags_AlwaysClamp))\n            {\n                if (m_rotationMode == ROTATION_MODE::AXIS_ANGLE)\n                    newTr.Rotation = getQuat(axisOrQuatXyz, angle_r);\n                else\n                {\n                    newTr.Rotation = float4(axisOrQuatXyz, prevTr.Rotation.w);\n                    newTr.Rotation.normalize();\n                }\n\n                modified = true;\n            }\n\n            const float pad_z = 68.8f * App::GetDPIScaling();\n            ImGui::Text(\"\");\n            ImGui::SameLine(pad_z);\n            ImGui::Text(\"Z\");\n            ImGui::SameLine();\n            if (ImGui::SliderFloat(\"##6\", &axisOrQuatXyz.z, -1.0f, 1.0f, \"%.3f\", ImGuiSliderFlags_AlwaysClamp))\n            {\n                if (m_rotationMode == ROTATION_MODE::AXIS_ANGLE)\n                    newTr.Rotation = newTr.Rotation = getQuat(axisOrQuatXyz, angle_r);\n                else\n                {\n                    newTr.Rotation = float4(axisOrQuatXyz, prevTr.Rotation.w);\n                    newTr.Rotation.normalize();\n                }\n\n                modified = true;\n            }\n\n            const float pad_w = 65.6f * App::GetDPIScaling();\n            ImGui::Text(\"\");\n            ImGui::SameLine(pad_w);\n            ImGui::Text(\"W\");\n            ImGui::SameLine();\n            const float range_min = m_rotationMode == ROTATION_MODE::AXIS_ANGLE ? 0.0f : -1.0f;\n            const float range_max = m_rotationMode == ROTATION_MODE::AXIS_ANGLE ? 360.0f : 1.0f;\n            float* w = m_rotationMode == ROTATION_MODE::AXIS_ANGLE ? &angle_d : &newTr.Rotation.w;\n            if (ImGui::SliderFloat(\"##7\", w, range_min, range_max, \"%.3f\", ImGuiSliderFlags_AlwaysClamp))\n            {\n                if (m_rotationMode == ROTATION_MODE::AXIS_ANGLE)\n                {\n                    angle_r = DegreesToRadians(angle_d);\n                    angle_r = Min(angle_r, MAX_ANGLE);\n                    angle_r = Max(angle_r, MIN_ANGLE);\n                    newTr.Rotation = float4(axisOrQuatXyz * sinf(0.5f * angle_r), cosf(0.5f * angle_r));\n                }\n                else\n                    newTr.Rotation.normalize();\n\n                modified = true;\n            }\n\n            const float pad_m = 48.0f * App::GetDPIScaling();\n            const char* modes[] = { \"Axis Angle\", \"Quaternion (XYZW)\" };\n            ImGui::Text(\"\");\n            ImGui::SameLine(pad_m);\n            ImGui::Text(\"Mode\");\n            ImGui::SameLine();\n            ImGui::Combo(\"##10\", (int*)&m_rotationMode, modes, ZetaArrayLen(modes));\n        }\n\n        // Scale\n        {\n            // To avoid scale = 0\n            constexpr float MIN_SCALE_RATIO = 1e-3f;\n\n            const float pad_x = 37.6f * App::GetDPIScaling();\n            ImGui::Text(\"\");\n            ImGui::SameLine(pad_x);\n            ImGui::Text(\"Scale X\");\n            ImGui::SameLine();\n            if (ImGui::SliderFloat(\"##11\", &newTr.Scale.x, MIN_SCALE_RATIO, 20.0f, \"%.3f\"))\n            {\n                // Clamp from below but not above\n                newTr.Scale.x = Max(MIN_SCALE_RATIO, newTr.Scale.x);\n                modified = true;\n            }\n\n            const float pad_y = 69.6f * App::GetDPIScaling();\n            ImGui::Text(\"\");\n            ImGui::SameLine(pad_y);\n            ImGui::Text(\"Y\");\n            ImGui::SameLine();\n            if (ImGui::SliderFloat(\"##12\", &newTr.Scale.y, MIN_SCALE_RATIO, 20.0f, \"%.3f\"))\n            {\n                newTr.Scale.y = Max(MIN_SCALE_RATIO, newTr.Scale.y);\n                modified = true;\n            }\n\n            const float pad_z = 68.8f * App::GetDPIScaling();\n            ImGui::Text(\"\");\n            ImGui::SameLine(pad_z);\n            ImGui::Text(\"Z\");\n            ImGui::SameLine();\n            if (ImGui::SliderFloat(\"##13\", &newTr.Scale.z, MIN_SCALE_RATIO, 20.0f, \"%.3f\"))\n            {\n                newTr.Scale.z = Max(MIN_SCALE_RATIO, newTr.Scale.z);\n                modified = true;\n            }\n        }\n\n        if (!isLocal)\n            ImGui::EndDisabled();\n    }\n\n    if (modified)\n    {\n        v_float4x4 vR_new = rotationMatFromQuat(loadFloat4(newTr.Rotation));\n        v_float4x4 vR_prev = rotationMatFromQuat(loadFloat4(prevTr.Rotation));\n        // Inverse of existing rotation\n        v_float4x4 vR_prev_inv = transpose(vR_prev);\n        vR_new = mul(vR_prev_inv, vR_new);\n        float3x3 R = float3x3(store(vR_new));\n\n        scene.TransformInstance(pickedID, newTr.Translation - prevTr.Translation,\n            R, \n            newTr.Scale / prevTr.Scale);\n    }\n}\n\nvoid GuiPass::PickedMaterial(uint64 pickedID)\n{\n    const bool pickChangedFromLastTime = m_lastPickedID != pickedID;\n    m_lastPickedID = pickedID;\n\n    auto& scene = App::GetScene();\n    const auto meshID = scene.GetInstanceMeshID(pickedID);\n    const auto& mesh = *scene.GetMesh(meshID).value();\n    Material mat = *scene.GetMaterial(mesh.m_materialID).value();\n    bool modified = false;\n    constexpr ImVec4 texturedCol = ImVec4(0.9587256f, 0.76055556f, 0.704035435f, 1);\n\n    if (ImGui::TreeNode(\"Base\"))\n    {\n        float3 color = mat.GetBaseColorFactor();\n        const bool baseColorTextured = mat.GetBaseColorTex() != Material::INVALID_ID;\n        const bool mrTextured = mat.GetMetallicRoughnessTex() != Material::INVALID_ID;\n        bool metallic = mat.Metallic();\n\n        if (baseColorTextured)\n            ImGui::PushStyleColor(ImGuiCol_Text, texturedCol);\n\n        if (ImGui::ColorEdit3(\"Color\", reinterpret_cast<float*>(&color), ImGuiColorEditFlags_Float))\n        {\n            mat.SetBaseColorFactor(color);\n            modified = true;\n        }\n\n        if (baseColorTextured)\n            ImGui::PopStyleColor();\n\n        if (mrTextured)\n            ImGui::PushStyleColor(ImGuiCol_Text, texturedCol);\n\n        const bool disabled = mat.Transmissive();\n        if (disabled)\n            ImGui::BeginDisabled();\n\n        if (ImGui::Checkbox(\"Metallic\", &metallic))\n        {\n            mat.SetMetallic(metallic);\n            modified = true;\n        }\n\n        if (disabled)\n            ImGui::EndDisabled();\n\n        if (mrTextured)\n            ImGui::PopStyleColor();\n\n        ImGui::TreePop();\n    }\n\n    if (ImGui::TreeNode(\"Specular\"))\n    {\n        float roughness = mat.GetSpecularRoughness();\n        float ior = mat.GetSpecularIOR();\n        const bool mrTextured = mat.GetMetallicRoughnessTex() != Material::INVALID_ID;\n\n        if (mrTextured)\n            ImGui::PushStyleColor(ImGuiCol_Text, texturedCol);\n\n        if (ImGui::SliderFloat(\"Roughness\", &roughness, 0.0f, 1.0f, \"%.2f\"))\n        {\n            mat.SetSpecularRoughness(roughness);\n            modified = true;\n        }\n\n        if (mrTextured)\n            ImGui::PopStyleColor();\n\n        if (ImGui::SliderFloat(\"IOR\", &ior, MIN_IOR, MAX_IOR, \"%.2f\"))\n        {\n            mat.SetSpecularIOR(ior);\n            modified = true;\n        }\n\n        ImGui::TreePop();\n    }\n\n    if (ImGui::TreeNode(\"Transmission\"))\n    {\n        bool transmissive = mat.Transmissive();\n        const bool baseColorTextured = mat.GetBaseColorTex() != Material::INVALID_ID;\n        float3 color = mat.GetBaseColorFactor();\n        float depth = HalfToFloat(mat.GetTransmissionDepth().x);\n        const bool disabled = mat.Metallic() || mat.ThinWalled();\n\n        if (disabled)\n            ImGui::BeginDisabled();\n\n        if (ImGui::Checkbox(\"Transmissive\", &transmissive))\n        {\n            mat.SetTransmission(transmissive ? 1.0f : 0.0f);\n            modified = true;\n        }\n\n        if (baseColorTextured)\n            ImGui::PushStyleColor(ImGuiCol_Text, texturedCol);\n\n        if (ImGui::ColorEdit3(\"Color\", reinterpret_cast<float*>(&color), ImGuiColorEditFlags_Float))\n        {\n            mat.SetBaseColorFactor(color);\n            modified = true;\n        }\n\n        if (baseColorTextured)\n            ImGui::PopStyleColor();\n\n        if (ImGui::SliderFloat(\"Depth\", &depth, 0.0f, 10.0f, \"%.3f\", ImGuiSliderFlags_Logarithmic))\n        {\n            mat.SetTransmissionDepth(depth);\n            modified = true;\n        }\n\n        if (disabled)\n            ImGui::EndDisabled();\n\n        ImGui::TreePop();\n    }\n\n    if (ImGui::TreeNode(\"Subsurface\"))\n    {\n        float subsurface = mat.GetSubsurface();\n        const bool disabled = mat.Metallic() || mat.Transmissive() || !mat.ThinWalled();\n\n        if (disabled)\n            ImGui::BeginDisabled();\n\n        if (ImGui::SliderFloat(\"Weight\", &subsurface, 0.0f, 1.0f, \"%.2f\"))\n        {\n            mat.SetSubsurface(subsurface);\n            modified = true;\n        }\n\n        if (disabled)\n            ImGui::EndDisabled();\n\n        ImGui::TreePop();\n    }\n\n    if (ImGui::TreeNode(\"Coat\"))\n    {\n        float weight = mat.GetCoatWeight();\n        float3 color = mat.GetCoatColor();\n        float roughness = mat.GetCoatRoughness();\n        float ior = mat.GetCoatIOR();\n\n        if (ImGui::SliderFloat(\"Weight\", &weight, 0.0f, 1.0f, \"%.2f\"))\n        {\n            mat.SetCoatWeight(weight);\n            modified = true;\n        }\n\n        if (ImGui::ColorEdit3(\"Color\", reinterpret_cast<float*>(&color), ImGuiColorEditFlags_Float))\n        {\n            mat.SetCoatColor(color);\n            modified = true;\n        }\n\n        if (ImGui::SliderFloat(\"Roughness\", &roughness, 0.0f, 1.0f, \"%.2f\"))\n        {\n            mat.SetCoatRoughness(roughness);\n            modified = true;\n        }\n\n        if (ImGui::SliderFloat(\"IOR\", &ior, MIN_IOR, MAX_IOR, \"%.2f\"))\n        {\n            mat.SetCoatIOR(ior);\n            modified = true;\n        }\n\n        ImGui::TreePop();\n    }\n\n    float3 emissiveFactor = mat.GetEmissiveFactor();\n    float emissiveStrength = HalfToFloat(mat.GetEmissiveStrength().x);\n    bool colorEditFinished = false;\n    bool strEditFinished = false;\n\n    if (ImGui::TreeNode(\"Emission\"))\n    {\n        const bool textured = mat.GetEmissiveTex() != Material::INVALID_ID;\n\n        if (!mat.Emissive())\n            ImGui::BeginDisabled();\n\n        const float3 oldColor = emissiveFactor;\n        const float oldStr = emissiveStrength;\n\n        if (textured)\n            ImGui::PushStyleColor(ImGuiCol_Text, texturedCol);\n\n        const char* modes[] = { \"(Linear) RGB\", \"Temperature\" };\n        m_emissiveColorMode = pickChangedFromLastTime ? EMISSIVE_COLOR_MODE::RGB : m_emissiveColorMode;\n        bool colorModeChanged = ImGui::Combo(\"Color Mode\", (int*)&m_emissiveColorMode, modes, ZetaArrayLen(modes));\n        bool switchedToTemperature = false;\n\n        if (m_emissiveColorMode == EMISSIVE_COLOR_MODE::RGB)\n        {\n            if (ImGui::ColorEdit3(\"Color\", reinterpret_cast<float*>(&emissiveFactor), ImGuiColorEditFlags_Float))\n            {\n                float3 diff = oldColor - emissiveFactor;\n\n                // Avoid spamming update when difference is close to zero\n                if (diff.dot(diff) > 1e-5)\n                {\n                    mat.SetEmissiveFactor(emissiveFactor);\n                    modified = true;\n                    m_pendingEmissiveUpdate = true;\n                }\n            }\n        }\n        else\n        {\n            switchedToTemperature = colorModeChanged;\n            m_currColorTemperature = switchedToTemperature ? DEFAULT_COLOR_TEMPERATURE : \n                m_currColorTemperature;\n            if (switchedToTemperature || ImGui::SliderFloat(\"Temperature\", &m_currColorTemperature, 1000, 40000, \"%.2f\"))\n            {\n                emissiveFactor = sRGBToLinear(ColorTemperatureTosRGB(m_currColorTemperature));\n                float3 diff = oldColor - emissiveFactor;\n\n                // Avoid spamming update when difference is close to zero\n                if (diff.dot(diff) > 1e-5)\n                {\n                    mat.SetEmissiveFactor(emissiveFactor);\n                    modified = true;\n                    m_pendingEmissiveUpdate = true;\n                }\n            }\n        }\n\n        colorEditFinished = switchedToTemperature || ImGui::IsItemDeactivatedAfterEdit();\n\n        if (textured)\n            ImGui::PopStyleColor();\n\n        if (ImGui::SliderFloat(\"Strength\", &emissiveStrength, 0, 50, \"%.3f\"))\n        {\n            if (fabsf(oldStr - emissiveStrength) > 1e-2)\n            {\n                mat.SetEmissiveStrength(emissiveStrength);\n                modified = true;\n                m_pendingEmissiveUpdate = true;\n            }\n        }\n\n        strEditFinished = ImGui::IsItemDeactivatedAfterEdit();\n\n        if (!mat.Emissive())\n            ImGui::EndDisabled();\n\n        ImGui::TreePop();\n    }\n\n    if (ImGui::TreeNode(\"Geometry\"))\n    {\n        bool doubleSided = mat.DoubleSided();\n        bool thinWalled = mat.ThinWalled();\n\n        if (ImGui::Checkbox(\"Double Sided\", &doubleSided))\n        {\n            mat.SetDoubleSided(doubleSided);\n            modified = true;\n        }\n\n        const bool disabled = mat.Transmissive() || !mat.DoubleSided();\n        if (disabled)\n            ImGui::BeginDisabled();\n\n        if (ImGui::Checkbox(\"Thin Walled\", &thinWalled))\n        {\n            mat.SetThinWalled(thinWalled);\n            modified = true;\n        }\n\n        if (disabled)\n            ImGui::EndDisabled();\n\n        ImGui::TreePop();\n    }\n\n    if (modified)\n        scene.UpdateMaterial(mesh.m_materialID, mat);\n\n    // Defer update to when user has stopped editing\n    if (m_pendingEmissiveUpdate && (colorEditFinished || strEditFinished))\n    {\n        scene.UpdateEmissiveMaterial(pickedID, emissiveFactor, emissiveStrength);\n        m_pendingEmissiveUpdate = false;\n    }\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/GUI/GuiPass.h",
    "content": "#pragma once\n\n#include \"../RenderPass.h\"\n#include <Core/GpuMemory.h>\n#include <Core/GpuTimer.h>\n#include <Scene/SceneCommon.h>\n#include \"GuiPass_Common.h\"\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n}\n\nnamespace ZetaRay::Model\n{\n    struct TriangleMesh;\n}\n\nnamespace ZetaRay::RenderPass\n{\n    struct GuiPass final : public RenderPassBase<1>\n    {\n        enum SHADER_IN_CPU_DESC\n        {\n            RTV,\n            COUNT\n        };\n\n        GuiPass();\n        ~GuiPass() = default;\n\n        void Init();\n        void OnWindowResized();\n        void SetCPUDescriptor(int i, D3D12_CPU_DESCRIPTOR_HANDLE h)\n        {\n            Assert(i < SHADER_IN_CPU_DESC::COUNT, \"out-of-bound access.\");\n            m_cpuDescriptors[i] = h;\n        }\n        void Render(Core::CommandList& cmdList);\n\n    private:\n        static constexpr int NUM_CBV = 0;\n        static constexpr int NUM_SRV = 0;\n        static constexpr int NUM_UAV = 0;\n        static constexpr int NUM_GLOBS = 0;\n        static constexpr int NUM_CONSTS = sizeof(cbGuiPass) / sizeof(DWORD);\n\n        inline static constexpr const char* COMPILED_VS[] = { \"ImGui_vs.cso\" };\n        inline static constexpr const char* COMPILED_PS[] = { \"ImGui_ps.cso\" };\n\n        void UpdateBuffers();\n        void RenderUI();\n        void RenderSettings(uint64 pickedID, const Model::TriangleMesh& mesh, \n            const Math::float4x4a& W);\n        void RenderProfiler();\n        void RenderLogWindow();\n        void RenderMainHeader();\n        void RenderToolbar();\n        void RenderGizmo(Util::Span<uint64> pickedIDs, const Model::TriangleMesh& mesh, \n            const Math::float4x4a& W);\n        void InfoTab();\n        void CameraTab();\n        void ParameterTab();\n        void GpuTimingsTab();\n        void ShaderReloadTab();\n        void PickedMaterial(uint64 pickedID);\n        void PickedWorldTransform(uint64 pickedID, const Model::TriangleMesh& mesh, \n            const Math::float4x4a& W);\n\n        struct ImGuiFrameBufferData\n        {\n            Core::GpuMemory::UploadHeapBuffer IndexBuffer;\n            Core::GpuMemory::UploadHeapBuffer VertexBuffer;\n            int NumIndices = 10000;\n            int NumVertices = 5000;\n        };\n\n        struct alignas(32) RenderPassTiming\n        {\n            RenderPassTiming()\n            {\n                Name[0] = '\\0';\n            }\n\n            static constexpr int WND_LEN = 8;\n\n            float Delta[WND_LEN];\n            char Name[Core::GpuTimer::Timing::MAX_NAME_LENGTH];\n        };\n\n        Util::SmallVector<RenderPassTiming, Support::SystemAllocator, 32> m_gpuTimings;\n        ImGuiFrameBufferData m_imguiFrameBuffs[Core::Constants::NUM_BACK_BUFFERS];\n        D3D12_CPU_DESCRIPTOR_HANDLE m_cpuDescriptors[SHADER_IN_CPU_DESC::COUNT] = { 0 };\n\n        int m_currShader = -1;\n        float m_dbgWndWidthPct = 0.21f;\n        float m_dbgWndHeightPct = 1.0f;\n        int m_headerWndWidth = 0;\n        int m_headerWndHeight = 0;\n        float m_logWndHeightPct = 0.21f;\n        static constexpr float m_headerWndHeightPct = 0.02f;\n        static constexpr float m_frameHistWidthPct = 0.9f;\n        bool m_firstTime = true;\n        bool m_logsTabOpen = true;\n        bool m_manuallyCloseLogsTab = false;\n        bool m_pendingEmissiveUpdate = false;\n        bool m_appWndSizeChanged = false;\n        bool m_hideUI = false;\n        int m_prevNumLogs = 0;\n        uint64_t m_lastPickedID = Scene::INVALID_INSTANCE;\n\n        enum class EMISSIVE_COLOR_MODE\n        {\n            RGB,\n            TEMPERATURE\n        };\n\n        enum class ROTATION_MODE\n        {\n            AXIS_ANGLE,\n            QUATERNION\n        };\n\n        enum class TRANSFORMATION\n        {\n            LOCAL,\n            WORLD\n        };\n\n        ROTATION_MODE m_rotationMode = ROTATION_MODE::AXIS_ANGLE;\n        TRANSFORMATION m_transform = TRANSFORMATION::LOCAL;\n        EMISSIVE_COLOR_MODE m_emissiveColorMode = EMISSIVE_COLOR_MODE::RGB;\n        static constexpr float DEFAULT_COLOR_TEMPERATURE = 6500.0f;\n        float m_currColorTemperature = DEFAULT_COLOR_TEMPERATURE;\n\n        // ImGuizmo::TRANSLATE\n        uint32_t m_currGizmoOperation = 7;\n        bool m_gizmoActive = false;\n        //ImGuizmo::MODE m_currGizmoMode = ImGuizmo::WORLD;\n    };\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/GUI/GuiPass_Common.h",
    "content": "#ifndef GUI_PASS_H\n#define GUI_PASS_H\n\n#include \"../../ZetaCore/Core/HLSLCompat.h\"\n\nstruct cbGuiPass\n{\n    float4x4_ WVP;\n\n    // Texture2D<float4>\n    uint32_t FontTex;\n    uint32_t pad[3];\n};\n\n#endif \n"
  },
  {
    "path": "Source/ZetaRenderPass/GUI/ImGui.hlsl",
    "content": "#include \"../Common/StaticTextureSamplers.hlsli\"\n#include \"GuiPass_Common.h\"\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbGuiPass> g_local : register(b0);\n\n//--------------------------------------------------------------------------------------\n// Layouts\n//--------------------------------------------------------------------------------------\n\nstruct VS_INPUT\n{\n    float2 pos : POSITION;\n    float2 uv  : TEXCOORD;\n    float4 col : COLOR;\n};\n\nstruct PS_INPUT\n{\n    float4 pos : SV_POSITION;\n    float4 col : COLOR;\n    float2 uv  : TEXCOORD;\n};\n\n//--------------------------------------------------------------------------------------\n// main\n//--------------------------------------------------------------------------------------\n\nPS_INPUT mainVS(VS_INPUT input)\n{\n    PS_INPUT output;\n    output.pos = mul(g_local.WVP, float4(input.pos.xy, 0.f, 1.f));\n    output.col = input.col;\n    output.uv = input.uv;\n    return output;\n}\n\nfloat4 mainPS(PS_INPUT input) : SV_Target\n{\n    Texture2D<float4> texture0 = ResourceDescriptorHeap[g_local.FontTex];\n    float4 out_col = input.col * texture0.Sample(g_samImgUi, input.uv);\n    return out_col;\n}"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/CMakeLists.txt",
    "content": "set(RP_IND_LIGHTING_DIR ${ZETA_RENDER_PASS_DIR}/IndirectLighting)\nset(RP_IND_LIGHTING_SRC\n\t${RP_IND_LIGHTING_DIR}/IndirectLighting.cpp\n    ${RP_IND_LIGHTING_DIR}/IndirectLighting.h\n    ${RP_IND_LIGHTING_DIR}/IndirectLighting_Common.h\n    ${RP_IND_LIGHTING_DIR}/NEE.hlsli\n    ${RP_IND_LIGHTING_DIR}/PathTracer/Variants/PathTracer_WoPS.hlsl\n    ${RP_IND_LIGHTING_DIR}/PathTracer/Variants/PathTracer_WPS.hlsl\n    ${RP_IND_LIGHTING_DIR}/PathTracer/Params.hlsli\n    ${RP_IND_LIGHTING_DIR}/PathTracer/PathTracer.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_GI/Params.hlsli\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_GI/ReSTIR_GI_NEE.hlsli\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_GI/PairwiseMIS.hlsli\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_GI/PathTracing.hlsli\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_GI/Resampling.hlsli\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_GI/Reservoir.hlsli\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_GI/Variants/ReSTIR_GI_WoPS.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_GI/Variants/ReSTIR_GI_WPS.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_GI/Variants/ReSTIR_GI_LVG.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_GI/ReSTIR_GI.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/Params.hlsli\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/Reservoir.hlsli\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/Shift.hlsli\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/Util.hlsli\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/ReSTIR_PT_NEE.hlsli\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/ReSTIR_PT_PathTrace.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/ReSTIR_PT_Sort.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/Variants/ReSTIR_PT_Sort_TtC.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/Variants/ReSTIR_PT_Sort_CtS.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/Variants/ReSTIR_PT_Sort_StC.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/ReSTIR_PT_Replay.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/Variants/ReSTIR_PT_Replay_TtC.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/Variants/ReSTIR_PT_Replay_CtS.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/Variants/ReSTIR_PT_Replay_StC.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/ReSTIR_PT_Reconnect_CtT.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/ReSTIR_PT_Reconnect_TtC.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/ReSTIR_PT_Reconnect_CtS.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/ReSTIR_PT_Reconnect_StC.hlsl\n    ${RP_IND_LIGHTING_DIR}/ReSTIR_PT/ReSTIR_PT_SpatialSearch.hlsl)\nset(RP_IND_LIGHTING_SRC ${RP_IND_LIGHTING_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/IndirectLighting.cpp",
    "content": "#include \"IndirectLighting.h\"\n#include <Core/CommandList.h>\n#include <Core/SharedShaderResources.h>\n#include <Support/Param.h>\n#include <Scene/SceneCore.h>\n#include <Support/Task.h>\n#include \"../Assets/Font/IconsFontAwesome6.h\"\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Core::Direct3DUtil;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Util;\n\nnamespace\n{\n    constexpr int EnumToSamplerIdx(TEXTURE_FILTER f)\n    {\n        if (f == TEXTURE_FILTER::MIP0)\n            return 0;\n        if (f == TEXTURE_FILTER::TRI_LINEAR)\n            return 3;\n        if (f == TEXTURE_FILTER::ANISOTROPIC_2X)\n            return 6;\n        if (f == TEXTURE_FILTER::ANISOTROPIC_4X)\n            return 7;\n\n        return 5;\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// IndirectLighting\n//--------------------------------------------------------------------------------------\n\nIndirectLighting::IndirectLighting()\n    : RenderPassBase(NUM_CBV, NUM_SRV, NUM_UAV, NUM_GLOBS, NUM_CONSTS)\n{\n    // frame constants\n    m_rootSig.InitAsCBV(0, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::FRAME_CONSTANTS_BUFFER);\n\n    // root constants\n    m_rootSig.InitAsConstants(1, NUM_CONSTS, 1, 0);\n\n    // BVH\n    m_rootSig.InitAsBufferSRV(2, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC);\n\n    // mesh buffer\n    m_rootSig.InitAsBufferSRV(3, 1, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE);\n\n    // scene VB\n    m_rootSig.InitAsBufferSRV(4, 2, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::SCENE_VERTEX_BUFFER);\n\n    // scene IB\n    m_rootSig.InitAsBufferSRV(5, 3, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::SCENE_INDEX_BUFFER);\n\n    // material buffer\n    m_rootSig.InitAsBufferSRV(6, 4, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::MATERIAL_BUFFER);\n\n    // emissive triangles\n    m_rootSig.InitAsBufferSRV(7, 5, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::EMISSIVE_TRIANGLE_BUFFER,\n        true);\n\n    // sample sets\n    m_rootSig.InitAsBufferSRV(8, 6, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::PRESAMPLED_EMISSIVE_SETS,\n        true);\n\n    // alias table\n    m_rootSig.InitAsBufferSRV(9, 7, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::EMISSIVE_TRIANGLE_ALIAS_TABLE,\n        true);\n\n    // light voxel grid/path state\n    m_rootSig.InitAsBufferSRV(10, 8, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        nullptr,\n        true);\n}\n\nvoid IndirectLighting::InitPSOs()\n{\n    constexpr D3D12_ROOT_SIGNATURE_FLAGS flags =\n        D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |\n        D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;\n\n    auto samplers = App::GetRenderer().GetStaticSamplers();\n    RenderPassBase::InitRenderPass(\"IndirectLighting\", flags, samplers);\n\n    constexpr int NumTaskSets = CeilUnsignedIntDiv((int)SHADER::COUNT,\n        TaskSet::MAX_NUM_TASKS);\n    TaskSet ts[NumTaskSets];\n    int i = 0;\n\n    for (int t = 0; t < NumTaskSets; t++)\n    {\n        for (; i < Min(TaskSet::MAX_NUM_TASKS * (t + 1), (int)SHADER::COUNT); i++)\n        {\n            StackStr(buff, n, \"IndirectShader_%d\", i);\n\n            ts[t].EmplaceTask(buff, [i, this]()\n                {\n                    m_psoLib.CompileComputePSO_MT(i, m_rootSigObj.Get(),\n                        COMPILED_CS[i]);\n                });\n        }\n\n        ts[t].Sort();\n        ts[t].Finalize();\n        App::Submit(ZetaMove(ts[t]));\n    }\n}\n\nvoid IndirectLighting::Init(INTEGRATOR method)\n{\n    InitPSOs();\n\n    memset(&m_cbRGI, 0, sizeof(m_cbRGI));\n    memset(&m_cbRPT_PathTrace, 0, sizeof(m_cbRPT_PathTrace));\n    memset(&m_cbRPT_Reuse, 0, sizeof(m_cbRPT_Reuse));\n    m_cbRGI.M_max = DefaultParamVals::M_MAX;\n    m_cbRPT_PathTrace.Alpha_min = m_cbRPT_Reuse.Alpha_min =\n        DefaultParamVals::ROUGHNESS_MIN * DefaultParamVals::ROUGHNESS_MIN;\n    m_cbRGI.MaxNonTrBounces = DefaultParamVals::MAX_NON_TR_BOUNCES;\n    m_cbRGI.MaxGlossyTrBounces = DefaultParamVals::MAX_GLOSSY_TR_BOUNCES;\n    m_cbRPT_PathTrace.TexFilterDescHeapIdx = EnumToSamplerIdx(DefaultParamVals::TEX_FILTER);\n    m_cbRPT_PathTrace.Packed = m_cbRPT_Reuse.Packed = DefaultParamVals::MAX_NON_TR_BOUNCES |\n        (DefaultParamVals::MAX_GLOSSY_TR_BOUNCES << PACKED_INDEX::NUM_GLOSSY_BOUNCES) |\n        (DefaultParamVals::M_MAX << PACKED_INDEX::MAX_TEMPORAL_M) |\n        (DefaultParamVals::M_MAX_SPATIAL << PACKED_INDEX::MAX_SPATIAL_M) |\n        (m_cbRPT_PathTrace.TexFilterDescHeapIdx << PACKED_INDEX::TEX_FILTER);\n    m_cbRGI.TexFilterDescHeapIdx = m_cbRPT_PathTrace.TexFilterDescHeapIdx;\n\n    SET_CB_FLAG(m_cbRGI, CB_IND_FLAGS::RUSSIAN_ROULETTE, DefaultParamVals::RUSSIAN_ROULETTE);\n    SET_CB_FLAG(m_cbRPT_PathTrace, CB_IND_FLAGS::RUSSIAN_ROULETTE, DefaultParamVals::RUSSIAN_ROULETTE);\n    SET_CB_FLAG(m_cbRPT_Reuse, CB_IND_FLAGS::RUSSIAN_ROULETTE, DefaultParamVals::RUSSIAN_ROULETTE);\n    SET_CB_FLAG(m_cbRPT_PathTrace, CB_IND_FLAGS::SORT_TEMPORAL, true);\n    SET_CB_FLAG(m_cbRPT_Reuse, CB_IND_FLAGS::SORT_TEMPORAL, true);\n    SET_CB_FLAG(m_cbRPT_Reuse, CB_IND_FLAGS::SORT_SPATIAL, true);\n    SET_CB_FLAG(m_cbRPT_Reuse, CB_IND_FLAGS::BOILING_SUPPRESSION, DefaultParamVals::BOILING_SUPPRESSION);\n\n    ParamVariant rr;\n    rr.InitBool(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Russian Roulette\",\n        fastdelegate::MakeDelegate(this, &IndirectLighting::RussianRouletteCallback),\n        DefaultParamVals::RUSSIAN_ROULETTE, \"Path Sampling\");\n    App::AddParam(rr);\n\n    ParamVariant maxDiffuseBounces;\n    maxDiffuseBounces.InitInt(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Max Bounces (Non Tr.)\",\n        fastdelegate::MakeDelegate(this, &IndirectLighting::MaxNonTrBouncesCallback),\n        DefaultParamVals::MAX_NON_TR_BOUNCES, 1, 8, 1, \"Path Sampling\");\n    App::AddParam(maxDiffuseBounces);\n\n    ParamVariant maxTransmissionBounces;\n    maxTransmissionBounces.InitInt(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Max Bounces (Transmissive)\",\n        fastdelegate::MakeDelegate(this, &IndirectLighting::MaxGlossyTrBouncesCallback),\n        DefaultParamVals::MAX_GLOSSY_TR_BOUNCES, 1, 8, 1, \"Path Sampling\");\n    App::AddParam(maxTransmissionBounces);\n\n    //ParamVariant pathRegularization;\n    //pathRegularization.InitBool(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Path Regularization\",\n    //    fastdelegate::MakeDelegate(this, &IndirectLighting::PathRegularizationCallback),\n    //    DefaultParamVals::PATH_REGULARIZATION, \"Path Sampling\");\n    //App::AddParam(pathRegularization);\n\n    ParamVariant texFilter;\n    texFilter.InitEnum(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Texture Filter\",\n        fastdelegate::MakeDelegate(this, &IndirectLighting::TexFilterCallback),\n        Params::TextureFilter, ZetaArrayLen(Params::TextureFilter), (uint32)DefaultParamVals::TEX_FILTER);\n    App::AddParam(texFilter);\n\n    m_method = method;\n    m_doTemporalResampling = method == INTEGRATOR::PATH_TRACING ? false : m_doTemporalResampling;\n\n    ResetIntegrator(true, false);\n}\n\nvoid IndirectLighting::OnWindowResized()\n{\n    // Since window was resized, recreate all resources, but leave the existing parameters\n    // and shader reload handlers\n    ResetIntegrator(true, true);\n    m_isTemporalReservoirValid = false;\n    m_currTemporalIdx = 0;\n}\n\nvoid IndirectLighting::ResetTemporal()\n{\n    m_isTemporalReservoirValid = false;\n    m_currTemporalIdx = 0;\n    SET_CB_FLAG(m_cbRGI, CB_IND_FLAGS::RESET_TEMPORAL_TEXTURES, true);\n    SET_CB_FLAG(m_cbRPT_PathTrace, CB_IND_FLAGS::RESET_TEMPORAL_TEXTURES, true);\n}\n\nvoid IndirectLighting::SetMethod(INTEGRATOR method)\n{\n    const auto old = m_method;\n    m_method = method;\n    m_doTemporalResampling = method == INTEGRATOR::PATH_TRACING ? false : m_doTemporalResampling;\n\n    if (old != m_method)\n    {\n        if (old == INTEGRATOR::ReSTIR_GI)\n            ReleaseReSTIR_GI();\n        else if (old == INTEGRATOR::ReSTIR_PT)\n            ReleaseReSTIR_PT();\n\n        ResetIntegrator(false, false);\n    }\n}\n\nvoid IndirectLighting::RenderPathTracer(Core::ComputeCmdList& computeCmdList)\n{\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n    const uint32_t w = renderer.GetRenderWidth();\n    const uint32_t h = renderer.GetRenderHeight();\n\n    computeCmdList.PIXBeginEvent(\"PathTracer\");\n    const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"PathTracer\");\n\n    const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_GI_TEMPORAL_GROUP_DIM_X);\n    const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_GI_TEMPORAL_GROUP_DIM_Y);\n    m_cbRGI.DispatchDimX_NumGroupsInTile = ((RESTIR_GI_TEMPORAL_TILE_WIDTH * dispatchDimY) << 16) | dispatchDimX;\n\n    Assert(!m_preSampling || m_cbRGI.SampleSetSize_NumSampleSets, \"Presampled set params haven't been set.\");\n\n    const auto& bvh = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n        GlobalResource::RT_SCENE_BVH_CURR);\n    const auto& meshInstances = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n        GlobalResource::RT_FRAME_MESH_INSTANCES_CURR);\n\n    m_rootSig.SetRootSRV(2, bvh->GpuVA());\n    m_rootSig.SetRootSRV(3, meshInstances->GpuVA());\n\n    m_cbRGI.FinalDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE_RGI::FINAL_UAV);\n    m_rootSig.SetRootConstants(0, sizeof(m_cbRGI) / sizeof(DWORD), &m_cbRGI);\n    m_rootSig.End(computeCmdList);\n\n    auto sh = App::GetScene().EmissiveLighting() ? SHADER::PATH_TRACER_WoPS :\n        SHADER::PATH_TRACER;\n    if (m_preSampling)\n        sh = SHADER::PATH_TRACER_WPS;\n\n    computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)sh));\n    computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n\n    gpuTimer.EndQuery(computeCmdList, queryIdx);\n    computeCmdList.PIXEndEvent();\n}\n\nvoid IndirectLighting::RenderReSTIR_GI(ComputeCmdList& computeCmdList)\n{\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n    const uint32_t w = renderer.GetRenderWidth();\n    const uint32_t h = renderer.GetRenderHeight();\n\n    // Spatio-temporal reuse\n    {\n        computeCmdList.PIXBeginEvent(\"ReSTIR_GI\");\n        const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"ReSTIR_GI\");\n\n        SmallVector<D3D12_TEXTURE_BARRIER, SystemAllocator, Reservoir_RGI::NUM * 2 + 2> textureBarriers;\n\n        // Current temporal reservoir into UAV\n        ID3D12Resource* currReservoirs[Reservoir_RGI::NUM] = { m_reservoir_RGI[m_currTemporalIdx].A.Resource(),\n            m_reservoir_RGI[m_currTemporalIdx].B.Resource(),\n            m_reservoir_RGI[m_currTemporalIdx].C.Resource() };\n\n        for (int i = 0; i < ZetaArrayLen(currReservoirs); i++)\n            textureBarriers.push_back(TextureBarrier_SrvToUavNoSync(currReservoirs[i]));\n\n        // Previous temporal reservoirs into SRV\n        if (m_isTemporalReservoirValid)\n        {\n            ID3D12Resource* prevReservoirs[Reservoir_RGI::NUM] = { m_reservoir_RGI[1 - m_currTemporalIdx].A.Resource(),\n                m_reservoir_RGI[1 - m_currTemporalIdx].B.Resource(),\n                m_reservoir_RGI[1 - m_currTemporalIdx].C.Resource() };\n\n            for (int i = 0; i < ZetaArrayLen(prevReservoirs); i++)\n                textureBarriers.push_back(TextureBarrier_UavToSrvNoSync(prevReservoirs[i]));\n        }\n\n        computeCmdList.ResourceBarrier(textureBarriers.data(), (UINT)textureBarriers.size());\n\n        const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_GI_TEMPORAL_GROUP_DIM_X);\n        const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_GI_TEMPORAL_GROUP_DIM_Y);\n        m_cbRGI.DispatchDimX_NumGroupsInTile = ((RESTIR_GI_TEMPORAL_TILE_WIDTH * dispatchDimY) << 16) | dispatchDimX;\n\n        SET_CB_FLAG(m_cbRGI, CB_IND_FLAGS::TEMPORAL_RESAMPLE, m_doTemporalResampling && m_isTemporalReservoirValid);\n        //SET_CB_FLAG(m_cbRGI, CB_IND_FLAGS::SPATIAL_RESAMPLE, m_doSpatialResampling && m_isTemporalReservoirValid);\n        Assert(!m_preSampling || m_cbRGI.SampleSetSize_NumSampleSets, \"Presampled set params haven't been set.\");\n\n        auto srvAIdx = m_currTemporalIdx == 1 ? DESC_TABLE_RGI::RESERVOIR_0_A_SRV : DESC_TABLE_RGI::RESERVOIR_1_A_SRV;\n        auto srvBIdx = m_currTemporalIdx == 1 ? DESC_TABLE_RGI::RESERVOIR_0_B_SRV : DESC_TABLE_RGI::RESERVOIR_1_B_SRV;\n        auto srvCIdx = m_currTemporalIdx == 1 ? DESC_TABLE_RGI::RESERVOIR_0_C_SRV : DESC_TABLE_RGI::RESERVOIR_1_C_SRV;\n        auto uavAIdx = m_currTemporalIdx == 1 ? DESC_TABLE_RGI::RESERVOIR_1_A_UAV : DESC_TABLE_RGI::RESERVOIR_0_A_UAV;\n        auto uavBIdx = m_currTemporalIdx == 1 ? DESC_TABLE_RGI::RESERVOIR_1_B_UAV : DESC_TABLE_RGI::RESERVOIR_0_B_UAV;\n        auto uavCIdx = m_currTemporalIdx == 1 ? DESC_TABLE_RGI::RESERVOIR_1_C_UAV : DESC_TABLE_RGI::RESERVOIR_0_C_UAV;\n\n        m_cbRGI.PrevReservoir_A_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)srvAIdx);\n        m_cbRGI.PrevReservoir_B_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)srvBIdx);\n        m_cbRGI.PrevReservoir_C_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)srvCIdx);\n        m_cbRGI.CurrReservoir_A_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)uavAIdx);\n        m_cbRGI.CurrReservoir_B_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)uavBIdx);\n        m_cbRGI.CurrReservoir_C_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)uavCIdx);\n\n        m_cbRGI.FinalDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE_RGI::FINAL_UAV);\n\n        const auto& bvh = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n            GlobalResource::RT_SCENE_BVH_CURR);\n        const auto& meshInstances = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n            GlobalResource::RT_FRAME_MESH_INSTANCES_CURR);\n\n        m_rootSig.SetRootSRV(2, bvh->GpuVA());\n        m_rootSig.SetRootSRV(3, meshInstances->GpuVA());\n\n        if (m_useLVG)\n        {\n            SharedShaderResources& shared = App::GetRenderer().GetSharedShaderResources();\n            constexpr auto id = GlobalResource::LIGHT_VOXEL_GRID;\n            const auto idHash = XXH3_64bits(id, strlen(id));\n\n            auto* lvg = shared.GetDefaultHeapBuffer(idHash);\n            m_rootSig.SetRootSRV(8, lvg->GpuVA());\n        }\n\n        m_rootSig.SetRootConstants(0, sizeof(m_cbRGI) / sizeof(DWORD), &m_cbRGI);\n        m_rootSig.End(computeCmdList);\n\n        auto sh = App::GetScene().EmissiveLighting() ? SHADER::ReSTIR_GI_WoPS :\n            SHADER::ReSTIR_GI;\n        if (m_preSampling)\n            sh = m_useLVG ? SHADER::ReSTIR_GI_LVG : SHADER::ReSTIR_GI_WPS;\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)sh));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n\n        gpuTimer.EndQuery(computeCmdList, queryIdx);\n        computeCmdList.PIXEndEvent();\n    }\n}\n\nvoid IndirectLighting::ReSTIR_PT_Temporal(ComputeCmdList& computeCmdList,\n    Span<ID3D12Resource*> currReservoirs)\n{\n    Assert(currReservoirs.size() == Reservoir_RPT::NUM, \"Invalid #reservoirs.\");\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n    const uint32_t w = renderer.GetRenderWidth();\n    const uint32_t h = renderer.GetRenderHeight();\n    const bool emissive = App::GetScene().EmissiveLighting();\n\n    computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Temporal\");\n    const uint32_t allQueryIdx = gpuTimer.BeginQuery(computeCmdList, \"ReSTIR_PT_Temporal\");\n\n    // Sort - TtC\n    {\n#ifndef NDEBUG\n        computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Sort_TtC\");\n#endif\n        const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_SORT_GROUP_DIM_X * 2);\n        const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_SORT_GROUP_DIM_Y * 2);\n\n        cb_ReSTIR_PT_Sort cb;\n        cb.DispatchDimX = dispatchDimX;\n        cb.DispatchDimY = dispatchDimY;\n        cb.Reservoir_A_DescHeapIdx = m_cbRPT_Reuse.PrevReservoir_A_DescHeapIdx;\n        cb.MapDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE_RPT::THREAD_MAP_NtC_UAV);\n        cb.Flags = m_cbRPT_Reuse.Flags;\n\n        m_rootSig.SetRootConstants(0, sizeof(cb) / sizeof(DWORD), &cb);\n        m_rootSig.End(computeCmdList);\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::ReSTIR_PT_SORT_TtC));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n#ifndef NDEBUG\n        computeCmdList.PIXEndEvent();\n#endif\n    }\n\n    // UAV barriers for current frame's reservoirs\n    {\n        D3D12_TEXTURE_BARRIER barriers[Reservoir_RPT::NUM];\n\n        for (int i = 0; i < currReservoirs.size(); i++)\n            barriers[i] = UAVBarrier1(currReservoirs[i]);\n\n        computeCmdList.ResourceBarrier(barriers, ZetaArrayLen(barriers));\n    }\n\n    // Sort - CtT\n    {\n#ifndef NDEBUG\n        computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Sort_CtT\");\n#endif\n        const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_SORT_GROUP_DIM_X * 2);\n        const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_SORT_GROUP_DIM_Y * 2);\n\n        cb_ReSTIR_PT_Sort cb;\n        cb.DispatchDimX = dispatchDimX;\n        cb.DispatchDimY = dispatchDimY;\n        cb.Reservoir_A_DescHeapIdx = m_cbRPT_PathTrace.Reservoir_A_DescHeapIdx;\n        cb.MapDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE_RPT::THREAD_MAP_CtN_UAV);\n        cb.Flags = m_cbRPT_Reuse.Flags;\n\n        m_rootSig.SetRootConstants(0, sizeof(cb) / sizeof(DWORD), &cb);\n        m_rootSig.End(computeCmdList);\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::ReSTIR_PT_SORT_CtT));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n#ifndef NDEBUG\n        computeCmdList.PIXEndEvent();\n#endif\n    }\n\n    // Thread maps into SRV\n    {\n        D3D12_TEXTURE_BARRIER barriers[(int)SHIFT::COUNT];\n        barriers[(int)SHIFT::CtN] = TextureBarrier_UavToSrvWithSync(m_threadMap[(int)SHIFT::CtN].Resource());\n        barriers[(int)SHIFT::NtC] = TextureBarrier_UavToSrvWithSync(m_threadMap[(int)SHIFT::NtC].Resource());\n\n        computeCmdList.ResourceBarrier(barriers, ZetaArrayLen(barriers));\n    }\n\n    // Replay - CtT\n    {\n#ifndef NDEBUG\n        computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Replay_CtT\");\n#endif\n        const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_REPLAY_GROUP_DIM_X);\n        const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_REPLAY_GROUP_DIM_Y);\n\n        m_cbRPT_Reuse.RBufferA_CtN_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n            (int)DESC_TABLE_RPT::RBUFFER_A_CtN_UAV);\n        m_cbRPT_Reuse.RBufferA_NtC_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n            (int)DESC_TABLE_RPT::RBUFFER_A_NtC_UAV);\n\n        const auto& bvh = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n            GlobalResource::RT_SCENE_BVH_PREV);\n        const auto& meshInstances = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n            GlobalResource::RT_FRAME_MESH_INSTANCES_PREV);\n\n        m_rootSig.SetRootSRV(2, bvh->GpuVA());\n        m_rootSig.SetRootSRV(3, meshInstances->GpuVA());\n        m_rootSig.SetRootConstants(0, sizeof(m_cbRPT_Reuse) / sizeof(DWORD), &m_cbRPT_Reuse);\n        m_rootSig.End(computeCmdList);\n\n        auto sh = emissive ? SHADER::ReSTIR_PT_REPLAY_CtT_E : SHADER::ReSTIR_PT_REPLAY_CtT;\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)sh));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n#ifndef NDEBUG\n        computeCmdList.PIXEndEvent();\n#endif\n    }\n\n    // Replay - TtC\n    {\n#ifndef NDEBUG\n        computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Replay_TtC\");\n#endif\n        const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_REPLAY_GROUP_DIM_X);\n        const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_REPLAY_GROUP_DIM_Y);\n\n        const auto& bvh = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n            GlobalResource::RT_SCENE_BVH_CURR);\n        const auto& meshInstances = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n            GlobalResource::RT_FRAME_MESH_INSTANCES_CURR);\n\n        m_rootSig.SetRootSRV(2, bvh->GpuVA());\n        m_rootSig.SetRootSRV(3, meshInstances->GpuVA());\n        m_rootSig.End(computeCmdList);\n\n        auto sh = emissive ? SHADER::ReSTIR_PT_REPLAY_TtC_E : SHADER::ReSTIR_PT_REPLAY_TtC;\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)sh));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n#ifndef NDEBUG\n        computeCmdList.PIXEndEvent();\n#endif\n    }\n\n    // Set SRVs for replay buffers\n    m_cbRPT_Reuse.RBufferA_CtN_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n        (int)DESC_TABLE_RPT::RBUFFER_A_CtN_SRV);\n    m_cbRPT_Reuse.RBufferA_NtC_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n        (int)DESC_TABLE_RPT::RBUFFER_A_NtC_SRV);\n\n    // r-buffers into SRV\n    {\n        D3D12_TEXTURE_BARRIER barriers[RBuffer::NUM * (int)SHIFT::COUNT];\n\n        // CtN replay buffers into SRV\n        barriers[0] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::CtN].A.Resource());\n        barriers[1] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::CtN].B.Resource());\n        barriers[2] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::CtN].C.Resource());\n        barriers[3] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::CtN].D.Resource());\n\n        // NtC replay buffers into SRV\n        barriers[4] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::NtC].A.Resource());\n        barriers[5] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::NtC].B.Resource());\n        barriers[6] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::NtC].C.Resource());\n        barriers[7] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::NtC].D.Resource());\n\n        computeCmdList.ResourceBarrier(barriers, ZetaArrayLen(barriers));\n    }\n\n    // Reconnect CtT\n    {\n#ifndef NDEBUG\n        computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Reconnect_CtT\");\n#endif\n        const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_TEMPORAL_GROUP_DIM_X);\n        const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_TEMPORAL_GROUP_DIM_Y);\n        m_cbRPT_Reuse.DispatchDimX_NumGroupsInTile = ((RESTIR_PT_TILE_WIDTH * dispatchDimY) << 16) | dispatchDimX;\n\n        const auto& bvh = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n            GlobalResource::RT_SCENE_BVH_PREV);\n        const auto& meshInstances = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n            GlobalResource::RT_FRAME_MESH_INSTANCES_PREV);\n\n        m_rootSig.SetRootSRV(2, bvh->GpuVA());\n        m_rootSig.SetRootSRV(3, meshInstances->GpuVA());\n        m_rootSig.SetRootConstants(0, sizeof(m_cbRPT_Reuse) / sizeof(DWORD), &m_cbRPT_Reuse);\n        m_rootSig.End(computeCmdList);\n\n        auto sh = emissive ? SHADER::ReSTIR_PT_RECONNECT_CtT_E : SHADER::ReSTIR_PT_RECONNECT_CtT;\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)sh));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n#ifndef NDEBUG\n        computeCmdList.PIXEndEvent();\n#endif\n    }\n\n    // Reconnect TtC\n    {\n#ifndef NDEBUG\n        computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Reconnect_TtC\");\n#endif\n        D3D12_TEXTURE_BARRIER uavBarriers[2];\n\n        // UAV barriers for current frame's reservoir B\n        uavBarriers[0] = UAVBarrier1(currReservoirs[1]);\n        // UAV barriers for target\n        uavBarriers[1] = UAVBarrier1(m_rptTarget.Resource());\n\n        computeCmdList.ResourceBarrier(uavBarriers, ZetaArrayLen(uavBarriers));\n\n        const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_TEMPORAL_GROUP_DIM_X);\n        const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_TEMPORAL_GROUP_DIM_Y);\n\n        const auto& bvh = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n            GlobalResource::RT_SCENE_BVH_CURR);\n        const auto& meshInstances = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n            GlobalResource::RT_FRAME_MESH_INSTANCES_CURR);\n\n        m_rootSig.SetRootSRV(2, bvh->GpuVA());\n        m_rootSig.SetRootSRV(3, meshInstances->GpuVA());\n        m_rootSig.End(computeCmdList);\n\n        auto sh = emissive ? SHADER::ReSTIR_PT_RECONNECT_TtC_E : SHADER::ReSTIR_PT_RECONNECT_TtC;\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)sh));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n#ifndef NDEBUG\n        computeCmdList.PIXEndEvent();\n#endif\n    }\n\n    gpuTimer.EndQuery(computeCmdList, allQueryIdx);\n    computeCmdList.PIXEndEvent();\n}\n\nvoid IndirectLighting::ReSTIR_PT_Spatial(ComputeCmdList& computeCmdList,\n    Span<ID3D12Resource*> currTemporalReservoirs,\n    Span<ID3D12Resource*> prevTemporalReservoirs)\n{\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n    const uint32_t w = renderer.GetRenderWidth();\n    const uint32_t h = renderer.GetRenderHeight();\n    const bool emissive = App::GetScene().EmissiveLighting();\n\n    // Current frame's temporal reservoirs become the inputs, previous\n    // frame temporal reservoirs become the outputs\n    auto inputs = currTemporalReservoirs;\n    auto outputs = prevTemporalReservoirs;\n\n    computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Spatial\");\n    const uint32_t allQueryIdx = gpuTimer.BeginQuery(computeCmdList, \"ReSTIR_PT_Spatial\");\n\n    for (int pass = 0; pass < m_numSpatialPasses; pass++)\n    {\n        m_cbRPT_Reuse.Packed = m_cbRPT_Reuse.Packed & ~0xf000;\n        m_cbRPT_Reuse.Packed |= ((m_numSpatialPasses << 14) | (pass << 12));\n\n        // Search for reusable spatial neighbor\n        {\n#ifndef NDEBUG\n            computeCmdList.PIXBeginEvent(\"ReSTIR_PT_SpatialSearch\");\n#endif\n            const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_SPATIAL_SEARCH_GROUP_DIM_X);\n            const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_SPATIAL_SEARCH_GROUP_DIM_Y);\n\n            cb_ReSTIR_PT_SpatialSearch cb;\n            cb.DispatchDimX_NumGroupsInTile = ((RESTIR_PT_TILE_WIDTH * dispatchDimY) << 16) | dispatchDimX;\n            cb.OutputDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE_RPT::SPATIAL_NEIGHBOR_UAV);\n            cb.Flags = m_cbRPT_Reuse.Flags;\n\n            m_rootSig.SetRootConstants(0, sizeof(cb) / sizeof(DWORD), &cb);\n            m_rootSig.End(computeCmdList);\n\n            computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::ReSTIR_PT_SPATIAL_SEARCH));\n            computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n#ifndef NDEBUG\n            computeCmdList.PIXEndEvent();\n#endif\n        }\n\n        // Barriers\n        {\n            constexpr int N = Reservoir_RPT::NUM * 2 +      // reservoirs\n                1 +                                         // spatial neighbor\n                RBuffer::NUM * (int)SHIFT::COUNT +          // r-buffers\n                (int)SHIFT::COUNT +                         // thread maps\n                1;                                          // target\n            SmallVector<D3D12_TEXTURE_BARRIER, SystemAllocator, N> barriers;\n\n            // Output reservoirs into UAV\n            for (int i = 0; i < Reservoir_RPT::NUM; i++)\n                barriers.push_back(TextureBarrier_SrvToUavWithSync(outputs[i]));\n\n            // Input reservoirs into SRV\n            for (int i = 0; i < Reservoir_RPT::NUM; i++)\n                barriers.push_back(TextureBarrier_UavToSrvWithSync(inputs[i]));\n\n            // Spatial neighbor idx into SRV\n            barriers.push_back(TextureBarrier_UavToSrvWithSync(m_spatialNeighbor.Resource()));\n\n            // r-buffers into UAV\n            for (int i = 0; i < (int)SHIFT::COUNT; i++)\n            {\n                barriers.push_back(TextureBarrier_SrvToUavWithSync(m_rbuffer[i].A.Resource()));\n                barriers.push_back(TextureBarrier_SrvToUavWithSync(m_rbuffer[i].B.Resource()));\n                barriers.push_back(TextureBarrier_SrvToUavWithSync(m_rbuffer[i].C.Resource()));\n                barriers.push_back(TextureBarrier_SrvToUavWithSync(m_rbuffer[i].D.Resource()));\n            }\n\n            // Thread maps into UAV\n            if (IS_CB_FLAG_SET(m_cbRPT_Reuse, CB_IND_FLAGS::SORT_SPATIAL))\n            {\n                barriers.push_back(TextureBarrier_SrvToUavWithSync(m_threadMap[(int)SHIFT::NtC].Resource()));\n                barriers.push_back(TextureBarrier_SrvToUavWithSync(m_threadMap[(int)SHIFT::CtN].Resource()));\n            }\n\n            // UAV barrier for target\n            barriers.push_back(UAVBarrier1(m_rptTarget.Resource()));\n\n            computeCmdList.ResourceBarrier(barriers.data(), (UINT)barriers.size());\n\n            // Update layout\n            m_reservoir_RPT[m_currTemporalIdx].Layout = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE;\n            m_reservoir_RPT[1 - m_currTemporalIdx].Layout = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS;\n            m_currTemporalIdx = 1 - m_currTemporalIdx;\n        }\n\n        // Sort - CtS\n        if (IS_CB_FLAG_SET(m_cbRPT_Reuse, CB_IND_FLAGS::SORT_SPATIAL))\n        {\n#ifndef NDEBUG\n            computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Sort_CtS\");\n#endif\n            const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_SORT_GROUP_DIM_X * 2);\n            const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_SORT_GROUP_DIM_Y * 2);\n\n            cb_ReSTIR_PT_Sort cb;\n            cb.DispatchDimX = dispatchDimX;\n            cb.DispatchDimY = dispatchDimY;\n            cb.Reservoir_A_DescHeapIdx = m_cbRPT_Reuse.Reservoir_A_DescHeapIdx;\n            cb.MapDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE_RPT::THREAD_MAP_CtN_UAV);\n            cb.Flags = m_cbRPT_Reuse.Flags;\n\n            m_rootSig.SetRootConstants(0, sizeof(cb) / sizeof(DWORD), &cb);\n            m_rootSig.End(computeCmdList);\n\n            computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::ReSTIR_PT_SORT_CtS));\n            computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n#ifndef NDEBUG\n            computeCmdList.PIXEndEvent();\n#endif\n        }\n\n        // Sort - StC\n        if (IS_CB_FLAG_SET(m_cbRPT_Reuse, CB_IND_FLAGS::SORT_SPATIAL))\n        {\n#ifndef NDEBUG\n            computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Sort_StC\");\n#endif\n            const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_SORT_GROUP_DIM_X * 2);\n            const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_SORT_GROUP_DIM_Y * 2);\n\n            cb_ReSTIR_PT_Sort cb;\n            cb.DispatchDimX = dispatchDimX;\n            cb.DispatchDimY = dispatchDimY;\n            cb.Reservoir_A_DescHeapIdx = m_cbRPT_Reuse.Reservoir_A_DescHeapIdx;\n            cb.SpatialNeighborHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE_RPT::SPATIAL_NEIGHBOR_SRV);\n            cb.MapDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE_RPT::THREAD_MAP_NtC_UAV);\n            cb.Flags = m_cbRPT_Reuse.Flags;\n\n            m_rootSig.SetRootConstants(0, sizeof(cb) / sizeof(DWORD), &cb);\n            m_rootSig.End(computeCmdList);\n\n            computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::ReSTIR_PT_SORT_StC));\n            computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n#ifndef NDEBUG\n            computeCmdList.PIXEndEvent();\n#endif\n        }\n\n        // Replay - CtS\n        {\n#ifndef NDEBUG\n            computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Replay_CtS\");\n#endif\n            // Thread maps into SRV\n            if (IS_CB_FLAG_SET(m_cbRPT_Reuse, CB_IND_FLAGS::SORT_SPATIAL))\n            {\n                D3D12_TEXTURE_BARRIER barriers[(int)SHIFT::COUNT];\n                barriers[(int)SHIFT::CtN] = TextureBarrier_UavToSrvWithSync(m_threadMap[(int)SHIFT::CtN].Resource());\n                barriers[(int)SHIFT::NtC] = TextureBarrier_UavToSrvWithSync(m_threadMap[(int)SHIFT::NtC].Resource());\n\n                computeCmdList.ResourceBarrier(barriers, ZetaArrayLen(barriers));\n            }\n\n            const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_REPLAY_GROUP_DIM_X);\n            const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_REPLAY_GROUP_DIM_Y);\n\n            m_cbRPT_Reuse.RBufferA_CtN_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n                (int)DESC_TABLE_RPT::RBUFFER_A_CtN_UAV);\n            m_cbRPT_Reuse.RBufferA_NtC_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n                (int)DESC_TABLE_RPT::RBUFFER_A_NtC_UAV);\n\n            m_rootSig.SetRootConstants(0, sizeof(m_cbRPT_Reuse) / sizeof(DWORD), &m_cbRPT_Reuse);\n            m_rootSig.End(computeCmdList);\n\n            auto sh = emissive ? SHADER::ReSTIR_PT_REPLAY_CtS_E : SHADER::ReSTIR_PT_REPLAY_CtS;\n            computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)sh));\n            computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n#ifndef NDEBUG\n            computeCmdList.PIXEndEvent();\n#endif\n        }\n\n        // Replay - StC\n        {\n#ifndef NDEBUG\n            computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Replay_StC\");\n#endif\n            const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_REPLAY_GROUP_DIM_X);\n            const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_REPLAY_GROUP_DIM_Y);\n\n            auto sh = emissive ? SHADER::ReSTIR_PT_REPLAY_StC_E : SHADER::ReSTIR_PT_REPLAY_StC;\n            computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)sh));\n            computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n#ifndef NDEBUG\n            computeCmdList.PIXEndEvent();\n#endif\n        }\n\n        // r-buffers into SRV\n        {\n            D3D12_TEXTURE_BARRIER barriers[RBuffer::NUM * (int)SHIFT::COUNT];\n\n            // CtN \n            barriers[0] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::CtN].A.Resource());\n            barriers[1] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::CtN].B.Resource());\n            barriers[2] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::CtN].C.Resource());\n            barriers[3] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::CtN].D.Resource());\n\n            // NtC\n            barriers[4] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::NtC].A.Resource());\n            barriers[5] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::NtC].B.Resource());\n            barriers[6] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::NtC].C.Resource());\n            barriers[7] = TextureBarrier_UavToSrvWithSync(m_rbuffer[(int)SHIFT::NtC].D.Resource());\n\n            computeCmdList.ResourceBarrier(barriers, ZetaArrayLen(barriers));\n\n            // Set SRVs for replay buffers\n            m_cbRPT_Reuse.RBufferA_CtN_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n                (int)DESC_TABLE_RPT::RBUFFER_A_CtN_SRV);\n            m_cbRPT_Reuse.RBufferA_NtC_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n                (int)DESC_TABLE_RPT::RBUFFER_A_NtC_SRV);\n        }\n\n        // Reconnect CtS\n        {\n#ifndef NDEBUG\n            computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Reconnect_CtS\");\n#endif\n            const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_SPATIAL_GROUP_DIM_X);\n            const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_SPATIAL_GROUP_DIM_Y);\n\n            m_cbRPT_Reuse.DispatchDimX_NumGroupsInTile = ((RESTIR_PT_TILE_WIDTH * dispatchDimY) << 16) | dispatchDimX;\n            m_rootSig.SetRootConstants(0, sizeof(m_cbRPT_Reuse) / sizeof(DWORD), &m_cbRPT_Reuse);\n            m_rootSig.End(computeCmdList);\n\n            auto sh = emissive ? SHADER::ReSTIR_PT_RECONNECT_CtS_E : SHADER::ReSTIR_PT_RECONNECT_CtS;\n            computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)sh));\n            computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n#ifndef NDEBUG\n            computeCmdList.PIXEndEvent();\n#endif\n        }\n\n        // Reconnect StC\n        {\n#ifndef NDEBUG\n            computeCmdList.PIXBeginEvent(\"ReSTIR_PT_Reconnect_StC\");\n#endif\n            // UAV barriers for output reservoir B\n            D3D12_TEXTURE_BARRIER uavBarrier = UAVBarrier1(outputs[1]);\n            computeCmdList.ResourceBarrier(uavBarrier);\n\n            const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_SPATIAL_GROUP_DIM_X);\n            const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_SPATIAL_GROUP_DIM_Y);\n\n            auto sh = emissive ? SHADER::ReSTIR_PT_RECONNECT_StC_E : SHADER::ReSTIR_PT_RECONNECT_StC;\n            computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)sh));\n            computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n#ifndef NDEBUG\n            computeCmdList.PIXEndEvent();\n#endif\n        }\n\n        // Prepare for next iteration (if any)\n        if (pass == 0 && m_numSpatialPasses == 2)\n        {\n            // Spatial neighbor idx into UAV\n            auto barrier = TextureBarrier_SrvToUavWithSync(m_spatialNeighbor.Resource());\n            computeCmdList.ResourceBarrier(barrier);\n\n            // Swap input and output reservoirs\n            std::swap(m_cbRPT_Reuse.PrevReservoir_A_DescHeapIdx,\n                m_cbRPT_Reuse.Reservoir_A_DescHeapIdx);\n            std::swap(inputs, outputs);\n        }\n    }\n\n    gpuTimer.EndQuery(computeCmdList, allQueryIdx);\n    computeCmdList.PIXEndEvent();\n}\n\nvoid IndirectLighting::RenderReSTIR_PT(Core::ComputeCmdList& computeCmdList)\n{\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n    const uint32_t w = renderer.GetRenderWidth();\n    const uint32_t h = renderer.GetRenderHeight();\n\n    ID3D12Resource* currReservoirs[Reservoir_RPT::NUM] = { m_reservoir_RPT[m_currTemporalIdx].A.Resource(),\n        m_reservoir_RPT[m_currTemporalIdx].B.Resource(),\n        m_reservoir_RPT[m_currTemporalIdx].C.Resource(),\n        m_reservoir_RPT[m_currTemporalIdx].D.Resource(),\n        m_reservoir_RPT[m_currTemporalIdx].E.Resource(),\n        m_reservoir_RPT[m_currTemporalIdx].F.Resource(),\n        m_reservoir_RPT[m_currTemporalIdx].G.Resource() };\n\n    ID3D12Resource* prevReservoirs[Reservoir_RPT::NUM] = { m_reservoir_RPT[1 - m_currTemporalIdx].A.Resource(),\n        m_reservoir_RPT[1 - m_currTemporalIdx].B.Resource(),\n        m_reservoir_RPT[1 - m_currTemporalIdx].C.Resource(),\n        m_reservoir_RPT[1 - m_currTemporalIdx].D.Resource(),\n        m_reservoir_RPT[1 - m_currTemporalIdx].E.Resource(),\n        m_reservoir_RPT[1 - m_currTemporalIdx].F.Resource(),\n        m_reservoir_RPT[1 - m_currTemporalIdx].G.Resource() };\n\n    auto srvAIdx = m_currTemporalIdx == 1 ? DESC_TABLE_RPT::RESERVOIR_0_A_SRV :\n        DESC_TABLE_RPT::RESERVOIR_1_A_SRV;\n    auto uavAIdx = m_currTemporalIdx == 1 ? DESC_TABLE_RPT::RESERVOIR_1_A_UAV :\n        DESC_TABLE_RPT::RESERVOIR_0_A_UAV;\n\n    const bool doTemporal = m_doTemporalResampling && m_isTemporalReservoirValid;\n    const bool doSpatial = (m_numSpatialPasses > 0) && doTemporal;\n\n    // Initial candidates\n    {\n        computeCmdList.PIXBeginEvent(\"ReSTIR_PT_PathTrace\");\n        const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"ReSTIR_PT_PathTrace\");\n\n        constexpr int N = Reservoir_RPT::NUM * 2 +      // reservoir\n            RBuffer::NUM * (int)SHIFT::COUNT +          // r-buffers\n            (int)SHIFT::COUNT +                         // thread maps\n            1;                                          // spatial neighbor\n        SmallVector<D3D12_TEXTURE_BARRIER, SystemAllocator, N> textureBarriers;\n\n        // Current reservoirs into UAV\n        if (m_reservoir_RPT[m_currTemporalIdx].Layout != D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS)\n        {\n            for (int i = 0; i < ZetaArrayLen(currReservoirs); i++)\n                textureBarriers.push_back(TextureBarrier_SrvToUavNoSync(currReservoirs[i]));\n\n            m_reservoir_RPT[m_currTemporalIdx].Layout = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS;\n        }\n\n        if (doTemporal)\n        {\n            // Temporal reservoirs into SRV\n            if (m_reservoir_RPT[1 - m_currTemporalIdx].Layout == D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS)\n            {\n                for (int i = 0; i < ZetaArrayLen(prevReservoirs); i++)\n                    textureBarriers.push_back(TextureBarrier_UavToSrvNoSync(prevReservoirs[i]));\n\n                m_reservoir_RPT[1 - m_currTemporalIdx].Layout = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE;\n            }\n\n            // r-buffers into UAV\n            for (int i = 0; i < (int)SHIFT::COUNT; i++)\n            {\n                textureBarriers.push_back(TextureBarrier_SrvToUavNoSync(m_rbuffer[i].A.Resource()));\n                textureBarriers.push_back(TextureBarrier_SrvToUavNoSync(m_rbuffer[i].B.Resource()));\n                textureBarriers.push_back(TextureBarrier_SrvToUavNoSync(m_rbuffer[i].C.Resource()));\n                textureBarriers.push_back(TextureBarrier_SrvToUavNoSync(m_rbuffer[i].D.Resource()));\n            }\n\n            // Thread maps into UAV\n            textureBarriers.push_back(TextureBarrier_SrvToUavNoSync(m_threadMap[(int)SHIFT::CtN].Resource()));\n            textureBarriers.push_back(TextureBarrier_SrvToUavNoSync(m_threadMap[(int)SHIFT::NtC].Resource()));\n\n            if (doSpatial)\n                textureBarriers.push_back(TextureBarrier_SrvToUavNoSync(m_spatialNeighbor.Resource()));\n        }\n\n        if (!textureBarriers.empty())\n            computeCmdList.ResourceBarrier(textureBarriers.data(), (UINT)textureBarriers.size());\n\n        const uint32_t dispatchDimX = CeilUnsignedIntDiv(w, RESTIR_PT_PATH_TRACE_GROUP_DIM_X);\n        const uint32_t dispatchDimY = CeilUnsignedIntDiv(h, RESTIR_PT_PATH_TRACE_GROUP_DIM_Y);\n\n        SET_CB_FLAG(m_cbRPT_PathTrace, CB_IND_FLAGS::TEMPORAL_RESAMPLE, doTemporal);\n        SET_CB_FLAG(m_cbRPT_PathTrace, CB_IND_FLAGS::SPATIAL_RESAMPLE, doSpatial);\n        SET_CB_FLAG(m_cbRPT_Reuse, CB_IND_FLAGS::SPATIAL_RESAMPLE, doSpatial);\n        Assert(!m_preSampling || m_cbRPT_PathTrace.SampleSetSize_NumSampleSets,\n            \"Presampled set params haven't been set.\");\n\n        m_cbRPT_PathTrace.DispatchDimX_NumGroupsInTile = ((RESTIR_PT_TILE_WIDTH * dispatchDimY) << 16) | dispatchDimX;\n        m_cbRPT_PathTrace.Reservoir_A_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)uavAIdx);\n\n        const auto& bvh = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n            GlobalResource::RT_SCENE_BVH_CURR);\n        const auto& meshInstances = renderer.GetSharedShaderResources().GetDefaultHeapBuffer(\n            GlobalResource::RT_FRAME_MESH_INSTANCES_CURR);\n\n        m_rootSig.SetRootSRV(2, bvh->GpuVA());\n        m_rootSig.SetRootSRV(3, meshInstances->GpuVA());\n        m_rootSig.SetRootConstants(0, sizeof(m_cbRPT_PathTrace) / sizeof(DWORD), &m_cbRPT_PathTrace);\n        m_rootSig.End(computeCmdList);\n\n        auto sh = App::GetScene().EmissiveLighting() ? SHADER::ReSTIR_PT_PATH_TRACE_WoPS :\n            SHADER::ReSTIR_PT_PATH_TRACE;\n        sh = m_preSampling ? SHADER::ReSTIR_PT_PATH_TRACE_WPS : sh;\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)sh));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n\n        gpuTimer.EndQuery(computeCmdList, queryIdx);\n        computeCmdList.PIXEndEvent();\n    }\n\n    if (doTemporal)\n    {\n        // Since reservoir descriptors were allocated consecutively, filling just\n        // the heap index for A is enough\n        m_cbRPT_Reuse.PrevReservoir_A_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)srvAIdx);\n        m_cbRPT_Reuse.Reservoir_A_DescHeapIdx = m_cbRPT_PathTrace.Reservoir_A_DescHeapIdx;\n\n        ReSTIR_PT_Temporal(computeCmdList, currReservoirs);\n    }\n\n    if (doSpatial)\n        ReSTIR_PT_Spatial(computeCmdList, currReservoirs, prevReservoirs);\n}\n\nvoid IndirectLighting::Render(CommandList& cmdList)\n{\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT ||\n        cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE, \"Invalid downcast\");\n    ComputeCmdList& computeCmdList = static_cast<ComputeCmdList&>(cmdList);\n\n    computeCmdList.SetRootSignature(m_rootSig, m_rootSigObj.Get());\n\n    if (m_method == INTEGRATOR::ReSTIR_PT)\n        RenderReSTIR_PT(computeCmdList);\n    else if (m_method == INTEGRATOR::ReSTIR_GI)\n        RenderReSTIR_GI(computeCmdList);\n    else\n        RenderPathTracer(computeCmdList);\n\n    m_isTemporalReservoirValid = true;\n    m_currTemporalIdx = 1 - m_currTemporalIdx;\n    SET_CB_FLAG(m_cbRPT_PathTrace, CB_IND_FLAGS::RESET_TEMPORAL_TEXTURES, false);\n    SET_CB_FLAG(m_cbRGI, CB_IND_FLAGS::RESET_TEMPORAL_TEXTURES, false);\n}\n\nvoid IndirectLighting::SwitchToReSTIR_PT(bool skipNonResources)\n{\n    auto& renderer = App::GetRenderer();\n    const auto w = renderer.GetRenderWidth();\n    const auto h = renderer.GetRenderHeight();\n\n    // Make sure offset between index 0 and index 1 descriptors is always the same\n    static_assert((int)(DESC_TABLE_RPT::RESERVOIR_0_B_SRV) +\n        Reservoir_RPT::NUM * 2 == (int)DESC_TABLE_RPT::RESERVOIR_1_B_SRV);\n    static_assert((int)(DESC_TABLE_RPT::RESERVOIR_0_C_UAV) +\n        Reservoir_RPT::NUM * 2 == (int)DESC_TABLE_RPT::RESERVOIR_1_C_UAV);\n\n    // Reservoirs (double buffered) + 2 thread maps + 2 r-buffers\n    constexpr int N = 2 * Reservoir_RPT::NUM + \n        (int)SHIFT::COUNT + \n        2 + \n        (int)SHIFT::COUNT * RBuffer::NUM;\n    PlacedResourceList<N> list;\n\n    for (int i = 0; i < 2; i++)\n    {\n        list.PushTex2D(ResourceFormats_RPT::RESERVOIR_A, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats_RPT::RESERVOIR_B, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats_RPT::RESERVOIR_C, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats_RPT::RESERVOIR_D, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats_RPT::RESERVOIR_E, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats_RPT::RESERVOIR_F, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats_RPT::RESERVOIR_G, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n    }\n\n    for (int i = 0; i < (int)SHIFT::COUNT; i++)\n        list.PushTex2D(ResourceFormats_RPT::THREAD_MAP, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n    list.PushTex2D(ResourceFormats_RPT::SPATIAL_NEIGHBOR, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n    list.PushTex2D(ResourceFormats_RPT::TARGET, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n    for (int i = 0; i < (int)SHIFT::COUNT; i++)\n    {\n        list.PushTex2D(ResourceFormats_RPT::RBUFFER_A, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats_RPT::RBUFFER_B, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats_RPT::RBUFFER_C, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats_RPT::RBUFFER_D, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n    }\n\n    list.End();\n\n    m_resHeap = GpuMemory::GetResourceHeap(list.TotalSizeInBytes());\n    auto allocs = list.AllocInfos();\n    int currRes = 0;\n    const auto initState0 = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS;\n    const auto initState1 = m_doTemporalResampling ?\n        D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE :\n        D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS;\n\n    auto func = [this, w, h](Texture& tex, DXGI_FORMAT format, const char* baseName, int idx,\n        const char* subName, const D3D12_RESOURCE_ALLOCATION_INFO1& allocInfo,\n        int srvIdx, int uavIdx, int descOffset, D3D12_BARRIER_LAYOUT layout)\n        {\n            StackStr(name, N, \"%s_%d_%s\", baseName, idx, subName);\n            tex = GpuMemory::GetPlacedTexture2D(name, w, h, format, m_resHeap.Heap(), allocInfo.Offset,\n                layout, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n            if (srvIdx != -1)\n                Direct3DUtil::CreateTexture2DSRV(tex, m_descTable.CPUHandle(srvIdx + descOffset));\n\n            Direct3DUtil::CreateTexture2DUAV(tex, m_descTable.CPUHandle(uavIdx + descOffset));\n        };\n\n    // Reservoirs\n    for (int i = 0; i < 2; i++)\n    {\n        const auto state = i == 0 ? initState0 : initState1;\n        const int descOffset = i * Reservoir_RPT::NUM * 2;\n\n        func(m_reservoir_RPT[i].A, ResourceFormats_RPT::RESERVOIR_A,\n            \"RPT_Reservoir\", i, \"A\", allocs[currRes++],\n            (int)DESC_TABLE_RPT::RESERVOIR_0_A_SRV, (int)DESC_TABLE_RPT::RESERVOIR_0_A_UAV,\n            descOffset, state);\n        func(m_reservoir_RPT[i].B, ResourceFormats_RPT::RESERVOIR_B,\n            \"RPT_Reservoir\", i, \"B\", allocs[currRes++],\n            (int)DESC_TABLE_RPT::RESERVOIR_0_B_SRV, (int)DESC_TABLE_RPT::RESERVOIR_0_B_UAV,\n            descOffset, state);\n        func(m_reservoir_RPT[i].C, ResourceFormats_RPT::RESERVOIR_C,\n            \"RPT_Reservoir\", i, \"C\", allocs[currRes++],\n            (int)DESC_TABLE_RPT::RESERVOIR_0_C_SRV, (int)DESC_TABLE_RPT::RESERVOIR_0_C_UAV,\n            descOffset, state);\n        func(m_reservoir_RPT[i].D, ResourceFormats_RPT::RESERVOIR_D,\n            \"RPT_Reservoir\", i, \"D\", allocs[currRes++],\n            (int)DESC_TABLE_RPT::RESERVOIR_0_D_SRV, (int)DESC_TABLE_RPT::RESERVOIR_0_D_UAV,\n            descOffset, state);\n        func(m_reservoir_RPT[i].E, ResourceFormats_RPT::RESERVOIR_E,\n            \"RPT_Reservoir\", i, \"E\", allocs[currRes++],\n            (int)DESC_TABLE_RPT::RESERVOIR_0_E_SRV, (int)DESC_TABLE_RPT::RESERVOIR_0_E_UAV,\n            descOffset, state);\n        func(m_reservoir_RPT[i].F, ResourceFormats_RPT::RESERVOIR_F,\n            \"RPT_Reservoir\", i, \"F\", allocs[currRes++],\n            (int)DESC_TABLE_RPT::RESERVOIR_0_F_SRV, (int)DESC_TABLE_RPT::RESERVOIR_0_F_UAV,\n            descOffset, state);\n        func(m_reservoir_RPT[i].G, ResourceFormats_RPT::RESERVOIR_G,\n            \"RPT_Reservoir\", i, \"G\", allocs[currRes++],\n            (int)DESC_TABLE_RPT::RESERVOIR_0_G_SRV, (int)DESC_TABLE_RPT::RESERVOIR_0_G_UAV,\n            descOffset, state);\n    }\n\n    m_reservoir_RPT[0].Layout = initState0;\n    m_reservoir_RPT[1].Layout = initState1;\n\n    // Thread Maps\n    for (int i = 0; i < (int)SHIFT::COUNT; i++)\n    {\n        const int descOffset = i * (int)SHIFT::COUNT;\n\n        func(m_threadMap[i], ResourceFormats_RPT::THREAD_MAP,\n            \"RPT_Map\", i, \"\", allocs[currRes++],\n            (int)DESC_TABLE_RPT::THREAD_MAP_CtN_SRV, (int)DESC_TABLE_RPT::THREAD_MAP_CtN_UAV,\n            descOffset, D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE);\n    }\n\n    // Spatial neighbor \n    func(m_spatialNeighbor, ResourceFormats_RPT::SPATIAL_NEIGHBOR,\n        \"RPT_SpatialNeighbor\", 0, \"\", allocs[currRes++],\n        (int)DESC_TABLE_RPT::SPATIAL_NEIGHBOR_SRV, (int)DESC_TABLE_RPT::SPATIAL_NEIGHBOR_UAV,\n        0, D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE);\n\n    // Target\n    func(m_rptTarget, ResourceFormats_RPT::TARGET, \"RPT_Target\", 0, \"\",\n        allocs[currRes++], -1, (int)DESC_TABLE_RPT::TARGET_UAV, 0,\n        D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS);\n\n    // R-Buffers\n    // Make sure offset between CtN and NtC descriptors is always the same\n    static_assert((int)(DESC_TABLE_RPT::RBUFFER_A_CtN_SRV) +\n        RBuffer::NUM * 2 == (int)DESC_TABLE_RPT::RBUFFER_A_NtC_SRV);\n    static_assert((int)(DESC_TABLE_RPT::RBUFFER_B_CtN_UAV) +\n        RBuffer::NUM * 2 == (int)DESC_TABLE_RPT::RBUFFER_B_NtC_UAV);\n    static_assert((int)(DESC_TABLE_RPT::RBUFFER_C_CtN_UAV) +\n        RBuffer::NUM * 2 == (int)DESC_TABLE_RPT::RBUFFER_C_NtC_UAV);\n    static_assert((int)(DESC_TABLE_RPT::RBUFFER_D_CtN_UAV) +\n        RBuffer::NUM * 2 == (int)DESC_TABLE_RPT::RBUFFER_D_NtC_UAV);\n\n    for (int i = 0; i < (int)SHIFT::COUNT; i++)\n    {\n        const int descOffset = i * RBuffer::NUM * 2;\n        const auto layout = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE;\n\n        func(m_rbuffer[i].A, ResourceFormats_RPT::RBUFFER_A,\n            \"RPT_RBuffer\", i, i == (int)SHIFT::CtN ? \"A_CtN\" : \"A_NtC\",\n            allocs[currRes++],\n            (int)DESC_TABLE_RPT::RBUFFER_A_CtN_SRV,\n            (int)DESC_TABLE_RPT::RBUFFER_A_CtN_UAV,\n            descOffset, layout);\n        func(m_rbuffer[i].B, ResourceFormats_RPT::RBUFFER_B,\n            \"RPT_RBuffer\", i, i == (int)SHIFT::CtN ? \"B_CtN\" : \"B_NtC\",\n            allocs[currRes++],\n            (int)DESC_TABLE_RPT::RBUFFER_B_CtN_SRV,\n            (int)DESC_TABLE_RPT::RBUFFER_B_CtN_UAV,\n            descOffset, layout);\n        func(m_rbuffer[i].C, ResourceFormats_RPT::RBUFFER_C,\n            \"RPT_RBuffer\", i, i == (int)SHIFT::CtN ? \"C_CtN\" : \"C_NtC\",\n            allocs[currRes++],\n            (int)DESC_TABLE_RPT::RBUFFER_C_CtN_SRV,\n            (int)DESC_TABLE_RPT::RBUFFER_C_CtN_UAV,\n            descOffset, layout);\n        func(m_rbuffer[i].D, ResourceFormats_RPT::RBUFFER_D,\n            \"RPT_RBuffer\", i, i == (int)SHIFT::CtN ? \"D_CtN\" : \"D_NtC\",\n            allocs[currRes++],\n            (int)DESC_TABLE_RPT::RBUFFER_D_CtN_SRV,\n            (int)DESC_TABLE_RPT::RBUFFER_D_CtN_UAV,\n            descOffset, layout);\n    }\n\n    // Final\n    Direct3DUtil::CreateTexture2DUAV(m_final, m_descTable.CPUHandle((int)DESC_TABLE_RPT::FINAL_UAV));\n\n    // Following never change, so can be set only once\n    m_cbRPT_PathTrace.TargetDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE_RPT::TARGET_UAV);\n    m_cbRPT_Reuse.ThreadMap_NtC_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n        (int)DESC_TABLE_RPT::THREAD_MAP_NtC_SRV);\n    m_cbRPT_PathTrace.Final = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE_RPT::FINAL_UAV);\n    m_cbRPT_Reuse.ThreadMap_CtN_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n        (int)DESC_TABLE_RPT::THREAD_MAP_CtN_SRV);\n    m_cbRPT_Reuse.ThreadMap_NtC_DescHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n        (int)DESC_TABLE_RPT::THREAD_MAP_NtC_SRV);\n    m_cbRPT_Reuse.SpatialNeighborHeapIdx = m_descTable.GPUDescriptorHeapIndex(\n        (int)DESC_TABLE_RPT::SPATIAL_NEIGHBOR_SRV);\n    m_cbRPT_Reuse.TargetDescHeapIdx = m_cbRPT_PathTrace.TargetDescHeapIdx;\n    m_cbRPT_Reuse.FinalDescHeapIdx = m_cbRPT_PathTrace.Final;\n\n    // Add ReSTIR PT parameters and shader reload handlers\n    if (!skipNonResources)\n    {\n        App::AddShaderReloadHandler(\"ReSTIR_PT_PathTrace\", \n            fastdelegate::MakeDelegate(this, &IndirectLighting::ReloadRPT_PathTrace));\n        App::AddShaderReloadHandler(\"ReSTIR_PT_Temporal\", \n            fastdelegate::MakeDelegate(this, &IndirectLighting::ReloadRPT_Temporal));\n        App::AddShaderReloadHandler(\"ReSTIR_PT_Spatial\", \n            fastdelegate::MakeDelegate(this, &IndirectLighting::ReloadRPT_Spatial));\n\n        ParamVariant alphaMin;\n        alphaMin.InitFloat(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Alpha_min\",\n            fastdelegate::MakeDelegate(this, &IndirectLighting::AlphaMinCallback),\n            DefaultParamVals::ROUGHNESS_MIN, 0.0f, 1.0f, 1e-2f, \"Reuse\");\n        App::AddParam(alphaMin);\n\n        ParamVariant p2;\n        p2.InitEnum(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Debug View\",\n            fastdelegate::MakeDelegate(this, &IndirectLighting::DebugViewCallback),\n            Params::DebugView, ZetaArrayLen(Params::DebugView), 0, \"Reuse\");\n        App::AddParam(p2);\n\n        ParamVariant doSpatial;\n        doSpatial.InitInt(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Spatial Resample\",\n            fastdelegate::MakeDelegate(this, &IndirectLighting::SpatialResamplingCallback),\n            m_numSpatialPasses, 0, 2, 1, \"Reuse\");\n        App::AddParam(doSpatial);\n\n        ParamVariant sortTemporal;\n        sortTemporal.InitBool(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Sort (Temporal)\",\n            fastdelegate::MakeDelegate(this, &IndirectLighting::SortTemporalCallback), true, \"Reuse\");\n        App::AddParam(sortTemporal);\n\n        ParamVariant sortSpatial;\n        sortSpatial.InitBool(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Sort (Spatial)\",\n            fastdelegate::MakeDelegate(this, &IndirectLighting::SortSpatialCallback), true, \"Reuse\");\n        App::AddParam(sortSpatial);\n\n        ParamVariant doTemporal;\n        doTemporal.InitBool(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Temporal Resample\",\n            fastdelegate::MakeDelegate(this, &IndirectLighting::TemporalResamplingCallback),\n            m_doTemporalResampling, \"Reuse\");\n        App::AddParam(doTemporal);\n\n        ParamVariant maxTemporalM;\n        maxTemporalM.InitInt(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"M_max (Temporal)\",\n            fastdelegate::MakeDelegate(this, &IndirectLighting::M_maxTCallback),\n            DefaultParamVals::M_MAX, 1, 15, 1, \"Reuse\");\n        App::AddParam(maxTemporalM);\n\n        ParamVariant maxSpatialM;\n        maxSpatialM.InitInt(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"M_max (Spatial)\",\n            fastdelegate::MakeDelegate(this, &IndirectLighting::M_maxSCallback),\n            DefaultParamVals::M_MAX_SPATIAL, 1, 12, 1, \"Reuse\");\n        App::AddParam(maxSpatialM);\n\n        ParamVariant suppressOutliers;\n        suppressOutliers.InitBool(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Boiling Suppression\",\n            fastdelegate::MakeDelegate(this, &IndirectLighting::BoilingSuppressionCallback),\n            DefaultParamVals::BOILING_SUPPRESSION, \"Reuse\");\n        App::AddParam(suppressOutliers);\n    }\n}\n\nvoid IndirectLighting::ReleaseReSTIR_PT()\n{\n    // Release resources\n    for (int i = 0; i < 2; i++)\n    {\n        m_reservoir_RPT[i].A.Reset();\n        m_reservoir_RPT[i].B.Reset();\n        m_reservoir_RPT[i].C.Reset();\n        m_reservoir_RPT[i].D.Reset();\n        m_reservoir_RPT[i].E.Reset();\n        m_reservoir_RPT[i].F.Reset();\n\n        m_rbuffer[i].A.Reset();\n        m_rbuffer[i].B.Reset();\n        m_rbuffer[i].C.Reset();\n        m_rbuffer[i].D.Reset();\n\n        m_threadMap[i].Reset();\n    }\n\n    m_spatialNeighbor.Reset();\n    m_rptTarget.Reset();\n    m_resHeap.Reset();\n\n    // Remove parameters and shader reload handlers\n    App::RemoveShaderReloadHandler(\"ReSTIR_PT_PathTrace\");\n    App::RemoveShaderReloadHandler(\"ReSTIR_PT_Temporal\");\n    App::RemoveShaderReloadHandler(\"ReSTIR_PT_Spatial\");\n    App::RemoveShaderReloadHandler(\"ReSTIR_PT_SpatialSearch\");\n\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Alpha_min\");\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Debug View\");\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"M_max (Temporal)\");\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"M_max (Spatial)\");\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Spatial Resample\");\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Sort (Temporal)\");\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Sort (Spatial)\");\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Temporal Resample\");\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Boiling Suppression\");\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Lower M-cap Disoccluded\");\n}\n\nvoid IndirectLighting::SwitchToReSTIR_GI(bool skipNonResources)\n{\n    auto& renderer = App::GetRenderer();\n    const auto w = renderer.GetRenderWidth();\n    const auto h = renderer.GetRenderHeight();\n\n    // Create reservoirs and their descriptors\n    static_assert((int)(DESC_TABLE_RGI::RESERVOIR_0_A_SRV) +\n        Reservoir_RGI::NUM * 2 == (int)DESC_TABLE_RGI::RESERVOIR_1_A_SRV);\n    static_assert((int)(DESC_TABLE_RGI::RESERVOIR_0_A_UAV) +\n        Reservoir_RGI::NUM * 2 == (int)DESC_TABLE_RGI::RESERVOIR_1_A_UAV);\n\n    PlacedResourceList<2 * Reservoir_RGI::NUM > list;\n\n    for (int i = 0; i < 2; i++)\n    {\n        list.PushTex2D(ResourceFormats_RGI::RESERVOIR_A, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats_RGI::RESERVOIR_B, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n        list.PushTex2D(ResourceFormats_RGI::RESERVOIR_C, w, h, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n    }\n\n    list.End();\n\n    m_resHeap = GpuMemory::GetResourceHeap(list.TotalSizeInBytes());\n    auto allocs = list.AllocInfos();\n    int currRes = 0;\n\n    auto func = [this, w, h](Texture& tex, DXGI_FORMAT format, const char* baseName, int idx,\n        const char* subName, const D3D12_RESOURCE_ALLOCATION_INFO1& allocInfo,\n        int srvIdx, int uavIdx, int descOffset, D3D12_BARRIER_LAYOUT layout)\n        {\n            StackStr(name, N, \"%s_%d_%s\", baseName, idx, subName);\n            tex = GpuMemory::GetPlacedTexture2D(name, w, h, format, m_resHeap.Heap(), allocInfo.Offset,\n                layout, TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n            Direct3DUtil::CreateTexture2DSRV(tex, m_descTable.CPUHandle(srvIdx + descOffset));\n            Direct3DUtil::CreateTexture2DUAV(tex, m_descTable.CPUHandle(uavIdx + descOffset));\n        };\n\n    // Reservoirs\n    for (int i = 0; i < 2; i++)\n    {\n        const auto layout = D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE;\n        const int descOffset = i * Reservoir_RGI::NUM * 2;\n\n        func(m_reservoir_RGI[i].A, ResourceFormats_RGI::RESERVOIR_A,\n            \"RGI_Reservoir\", i, \"A\", allocs[currRes++],\n            (int)DESC_TABLE_RGI::RESERVOIR_0_A_SRV, (int)DESC_TABLE_RGI::RESERVOIR_0_A_UAV,\n            descOffset, layout);\n        func(m_reservoir_RGI[i].B, ResourceFormats_RGI::RESERVOIR_B,\n            \"RGI_Reservoir\", i, \"B\", allocs[currRes++],\n            (int)DESC_TABLE_RGI::RESERVOIR_0_B_SRV, (int)DESC_TABLE_RGI::RESERVOIR_0_B_UAV,\n            descOffset, layout);\n        func(m_reservoir_RGI[i].C, ResourceFormats_RGI::RESERVOIR_C,\n            \"RGI_Reservoir\", i, \"C\", allocs[currRes++],\n            (int)DESC_TABLE_RGI::RESERVOIR_0_C_SRV, (int)DESC_TABLE_RGI::RESERVOIR_0_C_UAV,\n            descOffset, layout);\n    }\n\n    // Final\n    Direct3DUtil::CreateTexture2DUAV(m_final, m_descTable.CPUHandle((int)DESC_TABLE_RGI::FINAL_UAV));\n\n    SET_CB_FLAG(m_cbRGI, CB_IND_FLAGS::STOCHASTIC_MULTI_BOUNCE, DefaultParamVals::STOCHASTIC_MULTI_BOUNCE);\n\n    // Add ReSTIR GI parameters and shader reload handlers\n    if (!skipNonResources)\n    {\n        ParamVariant stochasticMultibounce;\n        stochasticMultibounce.InitBool(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Stochastic Multi-bounce\",\n            fastdelegate::MakeDelegate(this, &IndirectLighting::StochasticMultibounceCallback),\n            DefaultParamVals::STOCHASTIC_MULTI_BOUNCE, \"Path Sampling\");\n        App::AddParam(stochasticMultibounce);\n\n        ParamVariant doTemporal;\n        doTemporal.InitBool(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Temporal Resample\",\n            fastdelegate::MakeDelegate(this, &IndirectLighting::TemporalResamplingCallback),\n            m_doTemporalResampling, \"Reuse\");\n        App::AddParam(doTemporal);\n\n        ParamVariant maxM;\n        maxM.InitInt(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"M_max (Temporal)\",\n            fastdelegate::MakeDelegate(this, &IndirectLighting::M_maxTCallback),\n            DefaultParamVals::M_MAX, 1, 15, 1, \"Reuse\");\n        App::AddParam(maxM);\n\n        ParamVariant suppressOutliers;\n        suppressOutliers.InitBool(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Boiling Suppression\",\n            fastdelegate::MakeDelegate(this, &IndirectLighting::BoilingSuppressionCallback),\n            DefaultParamVals::BOILING_SUPPRESSION, \"Reuse\");\n        App::AddParam(suppressOutliers);\n\n        App::AddShaderReloadHandler(\"ReSTIR_GI\", fastdelegate::MakeDelegate(this, &IndirectLighting::ReloadRGI));\n    }\n}\n\nvoid IndirectLighting::ReleaseReSTIR_GI()\n{\n    for (int i = 0; i < 2; i++)\n    {\n        m_reservoir_RGI[i].A.Reset();\n        m_reservoir_RGI[i].B.Reset();\n        m_reservoir_RGI[i].C.Reset();\n    }\n\n    m_resHeap.Reset();\n\n    App::RemoveShaderReloadHandler(\"ReSTIR_GI\");\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Stochastic Multi-bounce\");\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"M_max (Temporal)\");\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Boiling Suppression\");\n    App::RemoveParam(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Temporal Resample\");\n}\n\nvoid IndirectLighting::SwitchToPathTracer(bool skipNonResources)\n{\n    Direct3DUtil::CreateTexture2DUAV(m_final, m_descTable.CPUHandle((int)DESC_TABLE_RGI::FINAL_UAV));\n}\n\nvoid IndirectLighting::ResetIntegrator(bool resetAllResources, bool skipNonResources)\n{\n    auto& renderer = App::GetRenderer();\n    const auto w = renderer.GetRenderWidth();\n    const auto h = renderer.GetRenderHeight();\n\n    m_descTable = renderer.GetGpuDescriptorHeap().Allocate(m_method == INTEGRATOR::ReSTIR_PT ?\n        (int)DESC_TABLE_RPT::COUNT : (int)DESC_TABLE_RGI::COUNT);\n\n    if (resetAllResources || !m_final.IsInitialized())\n    {\n        m_final = GpuMemory::GetTexture2D(\"IndirectFinal\",\n            w, h,\n            ResourceFormats_RGI::FINAL,\n            D3D12_RESOURCE_STATE_COMMON,\n            TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n    }\n\n    if (m_method == INTEGRATOR::ReSTIR_PT)\n        SwitchToReSTIR_PT(skipNonResources);\n    else if (m_method == INTEGRATOR::ReSTIR_GI)\n        SwitchToReSTIR_GI(skipNonResources);\n    else\n        SwitchToPathTracer(skipNonResources);\n\n    m_isTemporalReservoirValid = false;\n    m_currTemporalIdx = 0;\n}\n\nvoid IndirectLighting::MaxNonTrBouncesCallback(const Support::ParamVariant& p)\n{\n    const auto newVal = (uint16_t)p.GetInt().m_value;\n    m_cbRGI.MaxNonTrBounces = newVal;\n    constexpr uint32 ONES_COMP = ~(0xfu << PACKED_INDEX::NUM_DIFFUSE_BOUNCES);\n    m_cbRPT_PathTrace.Packed = m_cbRPT_PathTrace.Packed & ONES_COMP;\n    m_cbRPT_PathTrace.Packed |= newVal;\n    m_cbRPT_Reuse.Packed = m_cbRPT_PathTrace.Packed;\n\n    App::GetScene().SceneModified();\n}\n\nvoid IndirectLighting::MaxGlossyTrBouncesCallback(const Support::ParamVariant& p)\n{\n    const auto newVal = (uint16_t)p.GetInt().m_value;\n    m_cbRGI.MaxGlossyTrBounces = newVal;\n    constexpr uint32 ONES_COMP = ~(0xfu << PACKED_INDEX::NUM_GLOSSY_BOUNCES);\n    m_cbRPT_PathTrace.Packed = m_cbRPT_PathTrace.Packed & ONES_COMP;\n    m_cbRPT_PathTrace.Packed |= (newVal << PACKED_INDEX::NUM_GLOSSY_BOUNCES);\n    m_cbRPT_Reuse.Packed = m_cbRPT_PathTrace.Packed;\n\n    App::GetScene().SceneModified();\n}\n\nvoid IndirectLighting::StochasticMultibounceCallback(const Support::ParamVariant& p)\n{\n    SET_CB_FLAG(m_cbRGI, CB_IND_FLAGS::STOCHASTIC_MULTI_BOUNCE, p.GetBool());\n    SET_CB_FLAG(m_cbRPT_PathTrace, CB_IND_FLAGS::STOCHASTIC_MULTI_BOUNCE, p.GetBool());\n\n    App::GetScene().SceneModified();\n}\n\nvoid IndirectLighting::RussianRouletteCallback(const Support::ParamVariant& p)\n{\n    SET_CB_FLAG(m_cbRGI, CB_IND_FLAGS::RUSSIAN_ROULETTE, p.GetBool());\n    SET_CB_FLAG(m_cbRPT_PathTrace, CB_IND_FLAGS::RUSSIAN_ROULETTE, p.GetBool());\n\n    App::GetScene().SceneModified();\n}\n\nvoid IndirectLighting::TemporalResamplingCallback(const Support::ParamVariant& p)\n{\n    m_doTemporalResampling = p.GetBool();\n    App::GetScene().SceneModified();\n}\n\nvoid IndirectLighting::SpatialResamplingCallback(const Support::ParamVariant& p)\n{\n    m_numSpatialPasses = p.GetInt().m_value;\n    App::GetScene().SceneModified();\n}\n\nvoid IndirectLighting::M_maxTCallback(const Support::ParamVariant& p)\n{\n    auto newM = (uint16_t)p.GetInt().m_value;\n    m_cbRGI.M_max = newM;\n    constexpr uint32 ONES_COMP = ~(0xfu << PACKED_INDEX::MAX_TEMPORAL_M);\n    m_cbRPT_PathTrace.Packed = (m_cbRPT_PathTrace.Packed & ONES_COMP);\n    m_cbRPT_PathTrace.Packed |= (newM << PACKED_INDEX::MAX_TEMPORAL_M);\n    m_cbRPT_Reuse.Packed = m_cbRPT_PathTrace.Packed;\n\n    App::GetScene().SceneModified();\n}\n\nvoid IndirectLighting::M_maxSCallback(const Support::ParamVariant& p)\n{\n    auto newM = (uint16_t)p.GetInt().m_value;\n    constexpr uint32 ONES_COMP = ~(0xfu << PACKED_INDEX::MAX_SPATIAL_M);\n    m_cbRPT_PathTrace.Packed = (m_cbRPT_PathTrace.Packed & ONES_COMP);\n    m_cbRPT_PathTrace.Packed |= (newM << PACKED_INDEX::MAX_SPATIAL_M);\n    m_cbRPT_Reuse.Packed = m_cbRPT_PathTrace.Packed;\n\n    App::GetScene().SceneModified();\n}\n\nvoid IndirectLighting::DebugViewCallback(const Support::ParamVariant& p)\n{\n    auto newVal = (uint16_t)p.GetEnum().m_curr;\n    constexpr uint32 ONES_COMP = ~(0xf << PACKED_INDEX::DEBUG_VIEW);\n    m_cbRPT_PathTrace.Packed = (m_cbRPT_PathTrace.Packed & ONES_COMP);\n    m_cbRPT_PathTrace.Packed |= (newVal << PACKED_INDEX::DEBUG_VIEW);\n    m_cbRPT_Reuse.Packed = m_cbRPT_PathTrace.Packed;\n}\n\nvoid IndirectLighting::SortTemporalCallback(const Support::ParamVariant& p)\n{\n    SET_CB_FLAG(m_cbRPT_PathTrace, CB_IND_FLAGS::SORT_TEMPORAL, p.GetBool());\n    SET_CB_FLAG(m_cbRPT_Reuse, CB_IND_FLAGS::SORT_TEMPORAL, p.GetBool());\n}\n\nvoid IndirectLighting::SortSpatialCallback(const Support::ParamVariant& p)\n{\n    SET_CB_FLAG(m_cbRPT_Reuse, CB_IND_FLAGS::SORT_SPATIAL, p.GetBool());\n}\n\nvoid IndirectLighting::TexFilterCallback(const Support::ParamVariant& p)\n{\n    auto newVal = EnumToSamplerIdx((TEXTURE_FILTER)p.GetEnum().m_curr);\n    constexpr uint32 ONES_COMP = ~(0xfu << PACKED_INDEX::TEX_FILTER);\n    m_cbRPT_PathTrace.TexFilterDescHeapIdx = newVal;\n    m_cbRPT_PathTrace.Packed = (m_cbRPT_PathTrace.Packed & ONES_COMP);\n    m_cbRPT_PathTrace.Packed |= (newVal << PACKED_INDEX::TEX_FILTER);\n    m_cbRPT_Reuse.Packed = m_cbRPT_PathTrace.Packed;\n\n    App::GetScene().SceneModified();\n}\n\nvoid IndirectLighting::BoilingSuppressionCallback(const Support::ParamVariant& p)\n{\n    SET_CB_FLAG(m_cbRGI, CB_IND_FLAGS::BOILING_SUPPRESSION, p.GetBool());\n    SET_CB_FLAG(m_cbRPT_PathTrace, CB_IND_FLAGS::BOILING_SUPPRESSION, p.GetBool());\n    SET_CB_FLAG(m_cbRPT_Reuse, CB_IND_FLAGS::BOILING_SUPPRESSION, p.GetBool());\n\n    App::GetScene().SceneModified();\n}\n\nvoid IndirectLighting::PathRegularizationCallback(const Support::ParamVariant& p)\n{\n    SET_CB_FLAG(m_cbRGI, CB_IND_FLAGS::PATH_REGULARIZATION, p.GetBool());\n    SET_CB_FLAG(m_cbRPT_PathTrace, CB_IND_FLAGS::PATH_REGULARIZATION, p.GetBool());\n    SET_CB_FLAG(m_cbRPT_Reuse, CB_IND_FLAGS::PATH_REGULARIZATION, p.GetBool());\n\n    App::GetScene().SceneModified();\n}\n\nvoid IndirectLighting::AlphaMinCallback(const Support::ParamVariant& p)\n{\n    float newVal = p.GetFloat().m_value;\n    m_cbRPT_PathTrace.Alpha_min = m_cbRPT_Reuse.Alpha_min = \n        newVal * newVal;\n\n    App::GetScene().SceneModified();\n}\n\nvoid IndirectLighting::ReloadRGI()\n{\n    auto sh = SHADER::ReSTIR_GI;\n    const char* p = \"IndirectLighting\\\\ReSTIR_GI\\\\ReSTIR_GI.hlsl\";\n\n    if (App::GetScene().EmissiveLighting())\n    {\n        p = \"IndirectLighting\\\\ReSTIR_GI\\\\Variants\\\\ReSTIR_GI_WoPS.hlsl\";\n        sh = SHADER::ReSTIR_GI_WoPS;\n\n        if (m_preSampling)\n        {\n            p = \"IndirectLighting\\\\ReSTIR_GI\\\\Variants\\\\ReSTIR_GI_WPS.hlsl\";\n            sh = SHADER::ReSTIR_GI_WPS;\n\n            if (m_useLVG)\n            {\n                p = \"IndirectLighting\\\\ReSTIR_GI\\\\Variants\\\\ReSTIR_GI_LVG.hlsl\";\n                sh = SHADER::ReSTIR_GI_LVG;\n            }\n        }\n    }\n\n    const int i = (int)sh;\n    m_psoLib.Reload(i, m_rootSigObj.Get(), p);\n}\n\nvoid IndirectLighting::ReloadRPT_PathTrace()\n{\n    auto sh = SHADER::ReSTIR_PT_PATH_TRACE;\n    const char* p = \"IndirectLighting\\\\ReSTIR_PT\\\\ReSTIR_PT_PathTrace.hlsl\";\n\n    if (App::GetScene().EmissiveLighting())\n    {\n        p = \"IndirectLighting\\\\ReSTIR_PT\\\\Variants\\\\ReSTIR_PT_PathTrace_WoPS.hlsl\";\n        sh = SHADER::ReSTIR_PT_PATH_TRACE_WoPS;\n\n        if (m_preSampling)\n        {\n            p = \"IndirectLighting\\\\ReSTIR_PT\\\\Variants\\\\ReSTIR_PT_PathTrace_WPS.hlsl\";\n            sh = SHADER::ReSTIR_PT_PATH_TRACE_WPS;\n        }\n    }\n\n    const int i = (int)sh;\n    m_psoLib.Reload(i, m_rootSigObj.Get(), p);\n}\n\nvoid IndirectLighting::ReloadRPT_Temporal()\n{\n    TaskSet ts;\n\n    ts.EmplaceTask(\"Reload_Reconnect_CtT\", [this]()\n        {\n            auto sh = SHADER::ReSTIR_PT_RECONNECT_CtT;\n            const char* p = \"IndirectLighting\\\\ReSTIR_PT\\\\ReSTIR_PT_Reconnect_CtT.hlsl\";\n\n            if (App::GetScene().EmissiveLighting())\n            {\n                sh = SHADER::ReSTIR_PT_RECONNECT_CtT_E;\n                p = \"IndirectLighting\\\\ReSTIR_PT\\\\Variants\\\\ReSTIR_PT_Reconnect_CtT_E.hlsl\";\n            }\n\n            const int i = (int)sh;\n            m_psoLib.Reload(i, m_rootSigObj.Get(), p, false);\n        });\n\n    ts.EmplaceTask(\"Reload_Reconnect_TtC\", [this]()\n        {\n            auto sh = SHADER::ReSTIR_PT_RECONNECT_TtC;\n            const char* p = \"IndirectLighting\\\\ReSTIR_PT\\\\ReSTIR_PT_Reconnect_TtC.hlsl\";\n\n            if (App::GetScene().EmissiveLighting())\n            {\n                sh = SHADER::ReSTIR_PT_RECONNECT_TtC_E;\n                p = \"IndirectLighting\\\\ReSTIR_PT\\\\Variants\\\\ReSTIR_PT_Reconnect_TtC_E.hlsl\";\n            }\n\n            const int i = (int)sh;\n            m_psoLib.Reload(i, m_rootSigObj.Get(), p, false);\n        });\n\n    ts.EmplaceTask(\"Reload_Replay_CtT\", [this]()\n        {\n            auto sh = SHADER::ReSTIR_PT_REPLAY_CtT;\n            const char* p = \"IndirectLighting\\\\ReSTIR_PT\\\\ReSTIR_PT_Replay.hlsl\";\n\n            if (App::GetScene().EmissiveLighting())\n            {\n                sh = SHADER::ReSTIR_PT_REPLAY_CtT_E;\n                p = \"IndirectLighting\\\\ReSTIR_PT\\\\Variants\\\\ReSTIR_PT_Replay_E.hlsl\";\n            }\n\n            const int i = (int)sh;\n            m_psoLib.Reload(i, m_rootSigObj.Get(), p, false);\n        });\n\n    WaitObject waitObj;\n    ts.Sort();\n    ts.Finalize(&waitObj);\n    App::Submit(ZetaMove(ts));\n\n    auto sh = SHADER::ReSTIR_PT_REPLAY_TtC;\n    const char* p = \"IndirectLighting\\\\ReSTIR_PT\\\\Variants\\\\ReSTIR_PT_Replay_TtC.hlsl\";\n\n    if (App::GetScene().EmissiveLighting())\n    {\n        sh = SHADER::ReSTIR_PT_REPLAY_TtC_E;\n        p = \"IndirectLighting\\\\ReSTIR_PT\\\\Variants\\\\ReSTIR_PT_Replay_TtC_E.hlsl\";\n    }\n\n    const int i = (int)sh;\n    m_psoLib.Reload(i, m_rootSigObj.Get(), p, false);\n\n    waitObj.Wait();\n}\n\nvoid IndirectLighting::ReloadRPT_Spatial()\n{\n    TaskSet ts;\n\n    ts.EmplaceTask(\"Reload_Reconnect_CtS\", [this]()\n        {\n            auto sh = SHADER::ReSTIR_PT_RECONNECT_CtS;\n            const char* p = \"IndirectLighting\\\\ReSTIR_PT\\\\ReSTIR_PT_Reconnect_CtS.hlsl\";\n\n            if (App::GetScene().EmissiveLighting())\n            {\n                sh = SHADER::ReSTIR_PT_RECONNECT_CtS_E;\n                p = \"IndirectLighting\\\\ReSTIR_PT\\\\Variants\\\\ReSTIR_PT_Reconnect_CtS_E.hlsl\";\n            }\n\n            const int i = (int)sh;\n            m_psoLib.Reload(i, m_rootSigObj.Get(), p, false);\n        });\n\n    ts.EmplaceTask(\"Reload_Reconnect_StC\", [this]()\n        {\n            auto sh = SHADER::ReSTIR_PT_RECONNECT_StC;\n            const char* p = \"IndirectLighting\\\\ReSTIR_PT\\\\ReSTIR_PT_Reconnect_StC.hlsl\";\n\n            if (App::GetScene().EmissiveLighting())\n            {\n                sh = SHADER::ReSTIR_PT_RECONNECT_StC_E;\n                p = \"IndirectLighting\\\\ReSTIR_PT\\\\Variants\\\\ReSTIR_PT_Reconnect_StC_E.hlsl\";\n            }\n\n            const int i = (int)sh;\n            m_psoLib.Reload(i, m_rootSigObj.Get(), p, false);\n        });\n\n    ts.EmplaceTask(\"Reload_Replay_CtS\", [this]()\n        {\n            auto sh = SHADER::ReSTIR_PT_REPLAY_CtS;\n            const char* p = \"IndirectLighting\\\\ReSTIR_PT\\\\Variants\\\\ReSTIR_PT_Replay_CtS.hlsl\";\n\n            if (App::GetScene().EmissiveLighting())\n            {\n                sh = SHADER::ReSTIR_PT_REPLAY_CtS_E;\n                p = \"IndirectLighting\\\\ReSTIR_PT\\\\Variants\\\\ReSTIR_PT_Replay_CtS_E.hlsl\";\n            }\n\n            const int i = (int)sh;\n            m_psoLib.Reload(i, m_rootSigObj.Get(), p, false);\n        });\n\n    WaitObject waitObj;\n    ts.Sort();\n    ts.Finalize(&waitObj);\n    App::Submit(ZetaMove(ts));\n\n    auto sh = SHADER::ReSTIR_PT_REPLAY_StC;\n    const char* p = \"IndirectLighting\\\\ReSTIR_PT\\\\Variants\\\\ReSTIR_PT_Replay_StC.hlsl\";\n\n    if (App::GetScene().EmissiveLighting())\n    {\n        sh = SHADER::ReSTIR_PT_REPLAY_StC_E;\n        p = \"IndirectLighting\\\\ReSTIR_PT\\\\Variants\\\\ReSTIR_PT_Replay_StC_E.hlsl\";\n    }\n\n    const int i = (int)sh;\n    m_psoLib.Reload(i, m_rootSigObj.Get(), p, false);\n\n    waitObj.Wait();\n}\n\nvoid IndirectLighting::ReloadRPT_SpatialSearch()\n{\n    const int i = (int)SHADER::ReSTIR_PT_SPATIAL_SEARCH;\n    m_psoLib.Reload(i, m_rootSigObj.Get(), \n        \"IndirectLighting\\\\ReSTIR_PT\\\\ReSTIR_PT_SpatialSearch.hlsl\");\n}\n\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/IndirectLighting.h",
    "content": "#pragma once\n\n#include \"../RenderPass.h\"\n#include <Core/GpuMemory.h>\n#include \"IndirectLighting_Common.h\"\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n    class ComputeCmdList;\n}\n\nnamespace ZetaRay::Support\n{\n    struct ParamVariant;\n}\n\nnamespace ZetaRay::RenderPass\n{\n    enum class INDIRECT_SHADER\n    {\n        PATH_TRACER,\n        PATH_TRACER_WoPS,\n        PATH_TRACER_WPS,\n        ReSTIR_GI,\n        ReSTIR_GI_WoPS,\n        ReSTIR_GI_WPS,\n        ReSTIR_GI_LVG,\n        ReSTIR_PT_PATH_TRACE,\n        ReSTIR_PT_PATH_TRACE_WoPS,\n        ReSTIR_PT_PATH_TRACE_WPS,\n        ReSTIR_PT_SORT_CtT,\n        ReSTIR_PT_SORT_TtC,\n        ReSTIR_PT_SORT_CtS,\n        ReSTIR_PT_SORT_StC,\n        ReSTIR_PT_REPLAY_CtT,\n        ReSTIR_PT_REPLAY_CtT_E,\n        ReSTIR_PT_REPLAY_TtC,\n        ReSTIR_PT_REPLAY_TtC_E,\n        ReSTIR_PT_REPLAY_CtS,\n        ReSTIR_PT_REPLAY_CtS_E,\n        ReSTIR_PT_REPLAY_StC,\n        ReSTIR_PT_REPLAY_StC_E,\n        ReSTIR_PT_RECONNECT_CtT,\n        ReSTIR_PT_RECONNECT_CtT_E,\n        ReSTIR_PT_RECONNECT_TtC,\n        ReSTIR_PT_RECONNECT_TtC_E,\n        ReSTIR_PT_RECONNECT_CtS,\n        ReSTIR_PT_RECONNECT_CtS_E,\n        ReSTIR_PT_RECONNECT_StC,\n        ReSTIR_PT_RECONNECT_StC_E,\n        ReSTIR_PT_SPATIAL_SEARCH,\n        COUNT\n    };\n\n    struct IndirectLighting final : public RenderPassBase<(int)INDIRECT_SHADER::COUNT>\n    {\n        enum class SHADER_OUT_RES\n        {\n            FINAL,\n            COUNT\n        };\n\n        enum class INTEGRATOR : uint8_t\n        {\n            PATH_TRACING,\n            ReSTIR_GI,\n            ReSTIR_PT,\n            COUNT\n        };\n\n        IndirectLighting();\n        ~IndirectLighting() = default;\n\n        void InitPSOs();\n        void Init(INTEGRATOR method);\n        void OnWindowResized();\n        void ResetTemporal();\n        void SetMethod(INTEGRATOR method);\n        void SetLightPresamplingParams(bool enable, int numSampleSets, int sampleSetSize)\n        {\n            Assert(!enable || (numSampleSets > 0 && sampleSetSize > 0), \"Presampling is enabled, but the number of sample sets is zero.\");\n\n            m_preSampling = enable;\n            m_cbRGI.SampleSetSize_NumSampleSets = enable ? (numSampleSets << 16) | sampleSetSize : 0;\n            m_cbRPT_PathTrace.SampleSetSize_NumSampleSets = m_cbRGI.SampleSetSize_NumSampleSets;\n        }\n        void SetLightVoxelGridParams(bool enabled, const Math::uint3& dim, \n            const Math::float3& extents, float offset_y)\n        {\n            Assert(!enabled || (dim.x > 0 && dim.y > 0 && dim.z > 0\n                && extents.x > 0 && extents.y > 0 && extents.z > 0), \"LVG is enabled, but the dimension is invalid.\");\n            Assert(!enabled || m_preSampling, \"LVG can't be used while light presampling is disabled.\");\n\n            m_useLVG = enabled;\n            m_cbRGI.GridDim_xy = (dim.y << 16) | dim.x;\n            m_cbRGI.GridDim_z = dim.z;\n\n            Math::half4 extH(extents.x, extents.y, extents.z, offset_y);\n            m_cbRGI.Extents_xy = (extH.y << 16) | extH.x;\n            m_cbRGI.Extents_z_Offset_y = (extH.w << 16) | extH.z;\n        }\n        const Core::GpuMemory::Texture& GetOutput(SHADER_OUT_RES i) const\n        {\n            Assert(i == SHADER_OUT_RES::FINAL, \"Invalid shader output.\");\n            return m_final;\n        }\n        void Render(Core::CommandList& cmdList);\n\n    private:\n        static constexpr int NUM_CBV = 1;\n        static constexpr int NUM_SRV = 9;\n        static constexpr int NUM_UAV = 0;\n        static constexpr int NUM_GLOBS = 10;\n        static constexpr int NUM_CONSTS = (int)Math::Max(sizeof(cb_ReSTIR_GI) / sizeof(DWORD),\n            Math::Max(sizeof(cb_ReSTIR_PT_PathTrace) / sizeof(DWORD),\n                      sizeof(cb_ReSTIR_PT_Reuse) / sizeof(DWORD)));\n        using SHADER = RenderPass::INDIRECT_SHADER;\n\n        struct ResourceFormats_RGI\n        {\n            static constexpr DXGI_FORMAT RESERVOIR_A = DXGI_FORMAT_R32G32B32A32_FLOAT;\n            static constexpr DXGI_FORMAT RESERVOIR_B = DXGI_FORMAT_R16G16B16A16_FLOAT;\n            static constexpr DXGI_FORMAT RESERVOIR_C = DXGI_FORMAT_R32G32B32A32_FLOAT;\n            static constexpr DXGI_FORMAT FINAL = DXGI_FORMAT_R32G32B32A32_FLOAT;\n        };\n\n        struct ResourceFormats_RPT\n        {\n            static constexpr DXGI_FORMAT RESERVOIR_A = DXGI_FORMAT_R8G8B8A8_UINT;\n            static constexpr DXGI_FORMAT RESERVOIR_B = DXGI_FORMAT_R32G32_FLOAT;\n            static constexpr DXGI_FORMAT RESERVOIR_C = DXGI_FORMAT_R32G32B32A32_UINT;\n            static constexpr DXGI_FORMAT RESERVOIR_D = DXGI_FORMAT_R32G32B32A32_UINT;\n            static constexpr DXGI_FORMAT RESERVOIR_E = DXGI_FORMAT_R16_FLOAT;\n            static constexpr DXGI_FORMAT RESERVOIR_F = DXGI_FORMAT_R32G32_FLOAT;\n            static constexpr DXGI_FORMAT RESERVOIR_G = DXGI_FORMAT_R32G32_UINT;\n            static constexpr DXGI_FORMAT SPATIAL_NEIGHBOR = DXGI_FORMAT_R8G8_UINT;\n            static constexpr DXGI_FORMAT THREAD_MAP = DXGI_FORMAT_R16_UINT;\n            static constexpr DXGI_FORMAT RBUFFER_A = DXGI_FORMAT_R16G16B16A16_FLOAT;\n            static constexpr DXGI_FORMAT RBUFFER_B = DXGI_FORMAT_R32G32B32A32_UINT;\n            static constexpr DXGI_FORMAT RBUFFER_C = DXGI_FORMAT_R32G32B32A32_UINT;\n            static constexpr DXGI_FORMAT RBUFFER_D = DXGI_FORMAT_R16_UINT;\n            static constexpr DXGI_FORMAT TARGET = DXGI_FORMAT_R32G32B32A32_FLOAT;\n        };\n\n        enum class DESC_TABLE_RGI\n        {\n            RESERVOIR_0_A_SRV,\n            RESERVOIR_0_B_SRV,\n            RESERVOIR_0_C_SRV,\n            RESERVOIR_0_A_UAV,\n            RESERVOIR_0_B_UAV,\n            RESERVOIR_0_C_UAV,\n            //\n            RESERVOIR_1_A_SRV,\n            RESERVOIR_1_B_SRV,\n            RESERVOIR_1_C_SRV,\n            RESERVOIR_1_A_UAV,\n            RESERVOIR_1_B_UAV,\n            RESERVOIR_1_C_UAV,\n            //\n            FINAL_UAV,\n            //\n            COUNT\n        };\n\n        enum class DESC_TABLE_RPT\n        {\n            RESERVOIR_0_A_SRV,\n            RESERVOIR_0_B_SRV,\n            RESERVOIR_0_C_SRV,\n            RESERVOIR_0_D_SRV,\n            RESERVOIR_0_E_SRV,\n            RESERVOIR_0_F_SRV,\n            RESERVOIR_0_G_SRV,\n            RESERVOIR_0_A_UAV,\n            RESERVOIR_0_B_UAV,\n            RESERVOIR_0_C_UAV,\n            RESERVOIR_0_D_UAV,\n            RESERVOIR_0_E_UAV,\n            RESERVOIR_0_F_UAV,\n            RESERVOIR_0_G_UAV,\n            //\n            RESERVOIR_1_A_SRV,\n            RESERVOIR_1_B_SRV,\n            RESERVOIR_1_C_SRV,\n            RESERVOIR_1_D_SRV,\n            RESERVOIR_1_E_SRV,\n            RESERVOIR_1_F_SRV,\n            RESERVOIR_1_G_SRV,\n            RESERVOIR_1_A_UAV,\n            RESERVOIR_1_B_UAV,\n            RESERVOIR_1_C_UAV,\n            RESERVOIR_1_D_UAV,\n            RESERVOIR_1_E_UAV,\n            RESERVOIR_1_F_UAV,\n            RESERVOIR_1_G_UAV,\n            //\n            RBUFFER_A_CtN_SRV,\n            RBUFFER_B_CtN_SRV,\n            RBUFFER_C_CtN_SRV,\n            RBUFFER_D_CtN_SRV,\n            RBUFFER_A_CtN_UAV,\n            RBUFFER_B_CtN_UAV,\n            RBUFFER_C_CtN_UAV,\n            RBUFFER_D_CtN_UAV,\n            RBUFFER_A_NtC_SRV,\n            RBUFFER_B_NtC_SRV,\n            RBUFFER_C_NtC_SRV,\n            RBUFFER_D_NtC_SRV,\n            RBUFFER_A_NtC_UAV,\n            RBUFFER_B_NtC_UAV,\n            RBUFFER_C_NtC_UAV,\n            RBUFFER_D_NtC_UAV,\n            //\n            THREAD_MAP_CtN_SRV,\n            THREAD_MAP_CtN_UAV,\n            THREAD_MAP_NtC_SRV,\n            THREAD_MAP_NtC_UAV,\n            //\n            SPATIAL_NEIGHBOR_SRV,\n            SPATIAL_NEIGHBOR_UAV,\n            //\n            TARGET_UAV,\n            //\n            FINAL_UAV,\n            //\n            COUNT\n        };\n\n        struct DefaultParamVals\n        {\n            static constexpr int M_MAX = 10;\n            static constexpr int M_MAX_SPATIAL = 8;\n            static constexpr int MAX_NON_TR_BOUNCES = 3;\n            static constexpr int MAX_GLOSSY_TR_BOUNCES = 4;\n            static constexpr bool RUSSIAN_ROULETTE = true;\n            static constexpr bool STOCHASTIC_MULTI_BOUNCE = true;\n            static constexpr bool BOILING_SUPPRESSION = true;\n            static constexpr bool PATH_REGULARIZATION = false;\n            static constexpr float ROUGHNESS_MIN = 0.175f;\n            static constexpr float D_MIN = 1e-4f;\n            static constexpr TEXTURE_FILTER TEX_FILTER = TEXTURE_FILTER::ANISOTROPIC_4X;\n        };\n\n        struct Params\n        {\n            inline static const char* DebugView[] = { \"None\", \"K\", \"Case\",\n                \"Found Connection\", \"Connection Lobe (k - 1)\", \"Connection Lobe (k)\"};\n            static_assert((int)RPT_DEBUG_VIEW::COUNT == ZetaArrayLen(DebugView), \"enum <-> strings mismatch.\");\n\n            inline static const char* TextureFilter[] = { \"Mip 0\", \"Tri-linear\", \"Anisotropic (2x)\", \n                \"Anisotropic (4x)\", \"Anisotropic (16x)\" };\n            static_assert((int)TEXTURE_FILTER::COUNT == ZetaArrayLen(TextureFilter), \"enum <-> strings mismatch.\");\n        };\n\n        inline static constexpr const char* COMPILED_CS[(int)SHADER::COUNT] = {\n            \"PathTracer_cs.cso\",\n            \"PathTracer_WoPS_cs.cso\",\n            \"PathTracer_WPS_cs.cso\",\n            \"ReSTIR_GI_cs.cso\",\n            \"ReSTIR_GI_WoPS_cs.cso\",\n            \"ReSTIR_GI_WPS_cs.cso\",\n            \"ReSTIR_GI_LVG_cs.cso\",\n            \"ReSTIR_PT_PathTrace_cs.cso\",\n            \"ReSTIR_PT_PathTrace_WoPS_cs.cso\",\n            \"ReSTIR_PT_PathTrace_WPS_cs.cso\",\n            \"ReSTIR_PT_Sort_cs.cso\",\n            \"ReSTIR_PT_Sort_TtC_cs.cso\",\n            \"ReSTIR_PT_Sort_CtS_cs.cso\",\n            \"ReSTIR_PT_Sort_StC_cs.cso\",\n            \"ReSTIR_PT_Replay_cs.cso\",\n            \"ReSTIR_PT_Replay_E_cs.cso\",\n            \"ReSTIR_PT_Replay_TtC_cs.cso\",\n            \"ReSTIR_PT_Replay_TtC_E_cs.cso\",\n            \"ReSTIR_PT_Replay_CtS_cs.cso\",\n            \"ReSTIR_PT_Replay_CtS_E_cs.cso\",\n            \"ReSTIR_PT_Replay_StC_cs.cso\",\n            \"ReSTIR_PT_Replay_StC_E_cs.cso\",\n            \"ReSTIR_PT_Reconnect_CtT_cs.cso\",\n            \"ReSTIR_PT_Reconnect_CtT_E_cs.cso\",\n            \"ReSTIR_PT_Reconnect_TtC_cs.cso\",\n            \"ReSTIR_PT_Reconnect_TtC_E_cs.cso\",\n            \"ReSTIR_PT_Reconnect_CtS_cs.cso\",\n            \"ReSTIR_PT_Reconnect_CtS_E_cs.cso\",\n            \"ReSTIR_PT_Reconnect_StC_cs.cso\",\n            \"ReSTIR_PT_Reconnect_StC_E_cs.cso\",\n            \"ReSTIR_PT_SpatialSearch_cs.cso\"\n        };\n\n        struct Reservoir_RGI\n        {\n            static constexpr int NUM = 3;\n\n            // Texture2D<float4>: (pos, ID)\n            Core::GpuMemory::Texture A;\n            // Texture2D<half4>: (Lo, M)\n            Core::GpuMemory::Texture B;\n            // Texture2D<uint4>: (w_sum, W, normal)\n            Core::GpuMemory::Texture C;\n        };\n\n        struct Reservoir_RPT\n        {\n            static constexpr int NUM = 7;\n\n            // Texture2D<uint8_t2>: (metadata)\n            Core::GpuMemory::Texture A;\n            // Texture2D<float2>: (w_sum, W)\n            Core::GpuMemory::Texture B;\n            // Texture2D<uint4>: (jacobian, seed_replay, ID, x_k.x)\n            Core::GpuMemory::Texture C;\n            // Texture2D<uint4>: (x_k.yz, w_k, L.rg | seed_nee)\n            Core::GpuMemory::Texture D;\n            // Texture2D<half>: (L.b)\n            Core::GpuMemory::Texture E;\n            // Texture2D<float2>: (lightPdf, lightNormal/dwdA)\n            Core::GpuMemory::Texture F;\n            // Texture2D<uint>: (seed_nee)\n            Core::GpuMemory::Texture G;\n\n            D3D12_BARRIER_LAYOUT Layout;\n        };\n\n        enum class SHIFT\n        {\n            CtN = 0,\n            NtC,\n            COUNT\n        };\n\n        struct RBuffer\n        {\n            static constexpr int NUM = 4;\n\n            Core::GpuMemory::Texture A;\n            Core::GpuMemory::Texture B;\n            Core::GpuMemory::Texture C;\n            Core::GpuMemory::Texture D;\n        };\n\n        void ResetIntegrator(bool resetAllResources, bool skipNonResources);\n        void SwitchToReSTIR_PT(bool skipNonResources);\n        void ReleaseReSTIR_PT();\n        void SwitchToReSTIR_GI(bool skipNonResources);\n        void ReleaseReSTIR_GI();\n        void SwitchToPathTracer(bool skipNonResources);\n        void RenderPathTracer(Core::ComputeCmdList& computeCmdList);\n        void RenderReSTIR_GI(Core::ComputeCmdList& computeCmdList);\n        void RenderReSTIR_PT(Core::ComputeCmdList& computeCmdList);\n        void ReSTIR_PT_Temporal(Core::ComputeCmdList& computeCmdList, \n            Util::Span<ID3D12Resource*> currReservoirs);\n        void ReSTIR_PT_Spatial(Core::ComputeCmdList& computeCmdList, \n            Util::Span<ID3D12Resource*> currReservoirs,\n            Util::Span<ID3D12Resource*> prevReservoirs);\n\n        // param callbacks\n        void MaxNonTrBouncesCallback(const Support::ParamVariant& p);\n        void MaxGlossyTrBouncesCallback(const Support::ParamVariant& p);\n        void StochasticMultibounceCallback(const Support::ParamVariant& p);\n        void RussianRouletteCallback(const Support::ParamVariant& p);\n        void TemporalResamplingCallback(const Support::ParamVariant& p);\n        void SpatialResamplingCallback(const Support::ParamVariant& p);\n        void M_maxTCallback(const Support::ParamVariant& p);\n        void M_maxSCallback(const Support::ParamVariant& p);\n        void BoilingSuppressionCallback(const Support::ParamVariant& p);\n        void PathRegularizationCallback(const Support::ParamVariant& p);\n        void AlphaMinCallback(const Support::ParamVariant& p);\n        void DebugViewCallback(const Support::ParamVariant& p);\n        void SortTemporalCallback(const Support::ParamVariant& p);\n        void SortSpatialCallback(const Support::ParamVariant& p);\n        void TexFilterCallback(const Support::ParamVariant& p);\n\n        // shader reload\n        void ReloadRGI();\n        void ReloadRPT_PathTrace();\n        void ReloadRPT_Temporal();\n        void ReloadRPT_Spatial();\n        void ReloadRPT_SpatialSearch();\n\n        Core::DescriptorTable m_descTable;\n        Core::GpuMemory::ResourceHeap m_resHeap;\n        Reservoir_RGI m_reservoir_RGI[2];\n        Reservoir_RPT m_reservoir_RPT[2];\n        RBuffer m_rbuffer[(int)SHIFT::COUNT];\n        Core::GpuMemory::Texture m_threadMap[(int)SHIFT::COUNT];\n        Core::GpuMemory::Texture m_spatialNeighbor;\n        Core::GpuMemory::Texture m_rptTarget;\n        Core::GpuMemory::Texture m_final;\n\n        int m_currTemporalIdx = 0;\n        int m_numSpatialPasses = 1;\n        bool m_isTemporalReservoirValid = false;\n        bool m_isDnsrTemporalCacheValid = false;\n        bool m_doTemporalResampling = true;\n        bool m_preSampling = false;\n        bool m_useLVG = false;\n        INTEGRATOR m_method = INTEGRATOR::COUNT;\n\n        cb_ReSTIR_GI m_cbRGI;\n        cb_ReSTIR_PT_PathTrace m_cbRPT_PathTrace;\n        cb_ReSTIR_PT_Reuse m_cbRPT_Reuse;\n    };\n}"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/IndirectLighting_Common.h",
    "content": "#ifndef INDIRECT_LIGHTING_COMMON_H\n#define INDIRECT_LIGHTING_COMMON_H\n\n#include \"../../ZetaCore/Core/HLSLCompat.h\"\n\n#define RESTIR_GI_TEMPORAL_GROUP_DIM_X 8u\n#define RESTIR_GI_TEMPORAL_GROUP_DIM_Y 8u\n\n#define RESTIR_GI_TEMPORAL_TILE_WIDTH 16\n#define RESTIR_GI_TEMPORAL_LOG2_TILE_WIDTH 4\n\n#define RESTIR_PT_PATH_TRACE_GROUP_DIM_X 16u\n#define RESTIR_PT_PATH_TRACE_GROUP_DIM_Y 8u\n\n#define RESTIR_PT_TILE_WIDTH 16\n#define RESTIR_PT_LOG2_TILE_WIDTH 4\n\n#define RESTIR_PT_TEMPORAL_GROUP_DIM_X 16u\n#define RESTIR_PT_TEMPORAL_GROUP_DIM_Y 8u\n\n#define RESTIR_PT_REPLAY_GROUP_DIM_X 16u\n#define RESTIR_PT_REPLAY_GROUP_DIM_Y 8u\n\n#define RESTIR_PT_SORT_GROUP_DIM_X 16u\n#define RESTIR_PT_SORT_GROUP_DIM_Y 16u\n#define LOG_RESTIR_PT_SORT_GROUP_DIM 4\n\n#define RESTIR_PT_SPATIAL_SEARCH_GROUP_DIM_X 8u\n#define RESTIR_PT_SPATIAL_SEARCH_GROUP_DIM_Y 8u\n\n#define RESTIR_PT_SPATIAL_GROUP_DIM_X 8u\n#define RESTIR_PT_SPATIAL_GROUP_DIM_Y 8u\n\nnamespace CB_IND_FLAGS\n{\n    static constexpr uint32_t TEMPORAL_RESAMPLE = 1 << 0;\n    static constexpr uint32_t SPATIAL_RESAMPLE = 1 << 1;\n    static constexpr uint32_t STOCHASTIC_MULTI_BOUNCE = 1 << 2;\n    static constexpr uint32_t RUSSIAN_ROULETTE = 1 << 3;\n    static constexpr uint32_t BOILING_SUPPRESSION = 1 << 4;\n    static constexpr uint32_t PATH_REGULARIZATION = 1 << 5;\n    static constexpr uint32_t SORT_TEMPORAL = 1 << 6;\n    static constexpr uint32_t SORT_SPATIAL = 1 << 7;\n    static constexpr uint32_t RESET_TEMPORAL_TEXTURES = 1 << 8;\n};\n\nnamespace PACKED_INDEX\n{\n    // DebugView << 24 | M_max << 20 | M_max << 16 | #Spatial << 14 | SpatialPass << 12 | Glossy << 4 | Diffuse\n    static constexpr uint32_t NUM_DIFFUSE_BOUNCES = 0;\n    static constexpr uint32_t NUM_GLOSSY_BOUNCES = 4;\n    static constexpr uint32_t MAX_TEMPORAL_M = 16;\n    static constexpr uint32_t MAX_SPATIAL_M = 20;\n    static constexpr uint32_t TEX_FILTER = 24;\n    static constexpr uint32_t DEBUG_VIEW = 28;\n};\n\nenum class RPT_DEBUG_VIEW\n{\n    NONE,\n    K,\n    CASE,\n    FOUND_CONNECTION,\n    CONNECTION_LOBE_K_MIN_1,\n    CONNECTION_LOBE_K,\n    COUNT\n};\n\nenum class TEXTURE_FILTER\n{\n    MIP0,\n    TRI_LINEAR,\n    ANISOTROPIC_2X,\n    ANISOTROPIC_4X,\n    ANISOTROPIC_16X,\n    COUNT\n};\n\nstruct cb_ReSTIR_GI\n{\n    uint32_t PrevReservoir_A_DescHeapIdx;\n    uint32_t PrevReservoir_B_DescHeapIdx;\n    uint32_t PrevReservoir_C_DescHeapIdx;\n    uint32_t CurrReservoir_A_DescHeapIdx;\n    uint32_t CurrReservoir_B_DescHeapIdx;\n    uint32_t CurrReservoir_C_DescHeapIdx;\n\n    uint32_t FinalDescHeapIdx;\n\n    uint32_t Flags;\n    uint32_t DispatchDimX_NumGroupsInTile;\n    uint32_t SampleSetSize_NumSampleSets;\n    uint32_t Extents_xy;\n    uint32_t Extents_z_Offset_y;\n    uint32_t GridDim_xy;\n    uint32_t GridDim_z;\n \n    uint32_t M_max;\n    uint32_t MaxNonTrBounces;\n    uint32_t MaxGlossyTrBounces;\n    uint32_t TexFilterDescHeapIdx;\n};\n\nstruct cb_ReSTIR_PT_PathTrace\n{\n    uint32_t Reservoir_A_DescHeapIdx;\n    uint32_t TargetDescHeapIdx;\n    uint32_t Final;\n\n    uint32_t Flags;\n    uint32_t DispatchDimX_NumGroupsInTile;\n    uint32_t SampleSetSize_NumSampleSets;\n \n    uint32_t Packed;\n    float Alpha_min;\n    uint32_t TexFilterDescHeapIdx;\n};\n\nstruct cb_ReSTIR_PT_Reuse\n{\n    // Since reservoir descriptors were allocated consecutively, knowing\n    // the desc. heap index for A, others can be derived as:\n    //  - B = A + 1\n    //  - C = A + 2\n    //  - D = A + 3\n    //  - E = A + 4\n    //  - F = A + 5\n    uint32_t PrevReservoir_A_DescHeapIdx;\n    uint32_t Reservoir_A_DescHeapIdx;\n    uint32_t ThreadMap_CtN_DescHeapIdx;\n    uint32_t ThreadMap_NtC_DescHeapIdx;\n    uint32_t RBufferA_CtN_DescHeapIdx;\n    uint32_t RBufferA_NtC_DescHeapIdx;\n    uint32_t SpatialNeighborHeapIdx;\n    uint32_t TargetDescHeapIdx;\n    uint32_t FinalDescHeapIdx;\n\n    uint32_t Flags;\n    uint32_t DispatchDimX_NumGroupsInTile;\n \n    uint32_t Packed;\n    float Alpha_min;\n};\n\nstruct cb_ReSTIR_PT_Sort\n{\n    uint32_t Reservoir_A_DescHeapIdx;\n    uint32_t SpatialNeighborHeapIdx;\n    uint32_t MapDescHeapIdx;\n    uint32_t Flags;\n\n    uint32_t DispatchDimX;\n    uint32_t DispatchDimY;\n};\n\nstruct cb_ReSTIR_PT_SpatialSearch\n{\n    uint32_t DispatchDimX_NumGroupsInTile;\n    uint32_t Packed;\n    uint32_t OutputDescHeapIdx;\n    uint32_t Flags;\n};\n\n#endif\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/NEE.hlsli",
    "content": "#ifndef RESTIR_NEE_H\n#define RESTIR_NEE_H\n\n#include \"../Common/GBuffers.hlsli\"\n#include \"../Common/LightVoxelGrid.hlsli\"\n#include \"../Common/RayQuery.hlsli\"\n#include \"../Common/BSDFSampling.hlsli\"\n\nnamespace ReSTIR_Util\n{\n    struct Globals\n    {\n        RaytracingAccelerationStructure bvh;\n        StructuredBuffer<RT::MeshInstance> frameMeshData;\n        StructuredBuffer<Vertex> vertices;\n        StructuredBuffer<uint> indices;\n        StructuredBuffer<Material> materials;\n        StructuredBuffer<RT::EmissiveTriangle> emissives;\n        StructuredBuffer<RT::PresampledEmissiveTriangle> sampleSets;\n        StructuredBuffer<RT::EmissiveLumenAliasTableEntry> aliasTable;\n        StructuredBuffer<RT::VoxelSample> lvg;\n        uint16 maxNumBounces;\n        uint16 sampleSetSize;\n        uint16_t3 gridDim;\n        half3 extents;\n        half offset_y;\n        bool russianRoulette;\n    };\n\n    struct DirectLightingEstimate\n    {\n        static DirectLightingEstimate Init()\n        {\n            DirectLightingEstimate ret;\n            ret.ld = 0;     // le x BSDF x cos(theta) x dwdA / pdf\n            ret.le = 0;\n            ret.wi = 0;\n            ret.pdf_solidAngle = 0;\n            ret.dwdA = 1;\n            ret.lt = Light::TYPE::NONE;\n            ret.ID = UINT32_MAX;\n            ret.pos = 0;\n            ret.pdf_light = 0;\n            ret.twoSided = true;\n\n            return ret;\n        }\n\n        bool Empty()\n        {\n            return this.lt == Light::TYPE::NONE;\n        }\n\n        float3 ld;\n        float3 le;\n        float3 wi;\n        float3 pos;\n        float3 normal;\n        float pdf_solidAngle;\n        float dwdA;\n        Light::TYPE lt;\n        BSDF::LOBE lobe;\n        uint ID;\n        // p(lightSource, lightPos)\n        float pdf_light;\n        bool twoSided;\n    };\n\n    struct SkyIncidentRadiance \n    {\n        static SkyIncidentRadiance Init(uint descHeapOffset)\n        {\n            SkyIncidentRadiance ret;\n            ret.skyViewDescHeapOffset = descHeapOffset;\n            return ret;\n        }\n\n        float3 operator()(float3 w)\n        {\n            return Light::Le_Sky(w, skyViewDescHeapOffset);\n        }\n\n        uint skyViewDescHeapOffset;\n    };\n\n    template<bool TestVisibility>\n    DirectLightingEstimate NEE_Sun(float3 pos, float3 normal, BSDF::ShadingData surface, \n        RaytracingAccelerationStructure g_bvh, ConstantBuffer<cbFrameConstants> g_frame, \n        inout RNG rng)\n    {\n        DirectLightingEstimate ret = DirectLightingEstimate::Init();\n        ret.pdf_solidAngle = 1;\n        ret.dwdA = 1;\n        ret.lt = Light::TYPE::SUN;\n        ret.lobe = BSDF::LOBE::ALL;\n\n#if SUN_DISK_SAMPLING == 1\n        float3 bsdfxCosTheta;\n        float pdf;\n        float3 wi = Light::SampleSunDirection(-g_frame.SunDir, g_frame.SunCosAngularRadius, \n            normal, surface, bsdfxCosTheta, pdf, rng);\n#else\n        float3 wi = -g_frame.SunDir;\n        surface.SetWi(wi, normal);\n        float3 bsdfxCosTheta = BSDF::Unified(surface).f;\n#endif\n\n        if(dot(bsdfxCosTheta, bsdfxCosTheta) == 0)\n            return ret;\n\n        if(TestVisibility)\n        {\n            if (!RtRayQuery::Visibility_Ray(pos, wi, normal, g_bvh, surface.Transmissive()))\n                return ret;\n        }\n\n        float3 le = Light::Le_Sun(pos, g_frame);\n        ret.ld = bsdfxCosTheta * le;\n        ret.le = le;\n        ret.wi = wi;\n\n        return ret;\n    }\n\n    template<bool TestVisibility>\n    DirectLightingEstimate NEE_Sky(float3 pos, float3 normal, BSDF::ShadingData surface, \n        RaytracingAccelerationStructure g_bvh, uint skyViewDescHeapOffset, inout RNG rng)\n    {\n        // Weighted reservoir sampling to sample Le x BSDF, with BSDF lobes as source distributions\n        SkyIncidentRadiance leFunc = SkyIncidentRadiance::Init(skyViewDescHeapOffset);\n        BSDF::BSDFSample bsdfSample = BSDF::SampleBSDF(normal, surface, leFunc, rng);\n\n        DirectLightingEstimate ret = DirectLightingEstimate::Init();\n        ret.dwdA = 1;\n        ret.lt = Light::TYPE::SKY;\n        ret.lobe = bsdfSample.lobe;\n        ret.wi = bsdfSample.wi;\n        // = Le * BSDF(wi) / pdf\n        ret.ld = bsdfSample.bsdfOverPdf;\n        ret.pdf_solidAngle = bsdfSample.pdf;\n        // ret.le = Light::Le_Sky(ret.wi, skyViewDescHeapOffset);\n\n        if(TestVisibility)\n        {\n            if(dot(ret.ld, ret.ld) > 0)\n                ret.ld *= RtRayQuery::Visibility_Ray(pos, ret.wi, normal, g_bvh, surface.Transmissive());\n        }\n\n        return ret;\n    }\n\n    template<int NumSamples>\n    DirectLightingEstimate NEE_Emissive(float3 pos, float3 normal, BSDF::ShadingData surface, \n        uint sampleSetIdx, uint numEmissives, ReSTIR_Util::Globals globals, \n        uint emissiveMapsDescHeapOffset, inout RNG rng)\n    {\n        DirectLightingEstimate ret = DirectLightingEstimate::Init();\n\n        [loop]\n        for (int s_l = 0; s_l < NumSamples; s_l++)\n        {\n#if defined(USE_PRESAMPLED_SETS)\n            RT::PresampledEmissiveTriangle tri = Light::SamplePresampledSet(sampleSetIdx, globals.sampleSets, \n                globals.sampleSetSize, rng);\n\n            Light::EmissiveTriSample lightSample;\n            lightSample.pos = tri.pos;\n            lightSample.normal = Math::DecodeOct32(tri.normal);\n            lightSample.bary = Math::DecodeUNorm2(tri.bary);\n\n            float3 le = tri.le;\n            const float lightPdf = tri.pdf;\n            const uint emissiveIdx = tri.idx;\n            const uint lightID = tri.ID;\n\n            if(tri.twoSided && dot(pos - tri.pos, lightSample.normal) < 0)\n                lightSample.normal *= -1;\n#else\n            Light::AliasTableSample entry = Light::AliasTableSample::get(globals.aliasTable, \n                numEmissives, rng);\n            RT::EmissiveTriangle tri = globals.emissives[entry.idx];\n            Light::EmissiveTriSample lightSample = Light::EmissiveTriSample::get(pos, tri, rng);\n\n            float3 le = Light::Le_EmissiveTriangle(tri, lightSample.bary, emissiveMapsDescHeapOffset);\n            const float lightPdf = entry.pdf * lightSample.pdf;\n            const uint lightID = tri.ID;\n#endif\n\n            const float t = length(lightSample.pos - pos);\n            const float3 wi = (lightSample.pos - pos) / t;\n\n            if(dot(lightSample.normal, -wi) > 0)\n            {\n                const float dwdA = saturate(dot(lightSample.normal, -wi)) / (t * t);\n\n                surface.SetWi(wi, normal);\n                float3 ld = le * BSDF::Unified(surface).f * dwdA;\n                    \n                if (Math::Luminance(ld) > 1e-6)\n                {\n                    ld *= RtRayQuery::Visibility_Segment(pos, wi, t, normal, lightID, \n                        globals.bvh, surface.Transmissive());\n                }\n\n                ret.ld += ld / lightPdf;\n                ret.le = le;\n                ret.wi = wi;\n                ret.pdf_solidAngle = lightPdf / dwdA;\n                ret.dwdA = dwdA;\n                ret.ID = lightID;\n                ret.pos = lightSample.pos;\n                ret.normal = lightSample.normal;\n                ret.pdf_light = lightPdf;\n            }\n        }\n\n        ret.lt = Light::TYPE::EMISSIVE;\n        ret.lobe = BSDF::LOBE::ALL;\n        ret.ld /= NumSamples;\n\n        return ret;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/PathTracer/Params.hlsli",
    "content": "#ifndef PATH_TRACER_PARAMS_H\n#define PATH_TRACER_PARAMS_H\n\n// Minimum number of bounces before performing Russian Roulette\n#define MIN_NUM_BOUNCES_RUSSIAN_ROULETTE 3\n\n// Probability of next event estimation with sun vs sky\n#define P_SUN_VS_SKY 0.65\n\n// Use multiple importance sampling for direct lighting. Reduces noise (especially for \n// smoother surface) with a moderate performance cost.\n#define USE_MIS 1\n\n// When disabled, direct lighting uses MIS just for the first indirect hit and \n// power sampling for the subsequent hits. Improves performance at the expense \n// of quality.\n#define MIS_ALL_BOUNCES 1\n#define MIS_NUM_LIGHT_SAMPLES 1\n#define MIS_NON_DIFFUSE_BSDF_SAMPLING 0\n\n// When enabled, sun is treated as a disk area light with radius based on the \n// sun angular diameter, otherwise a directional light. Has minimal impact on \n// quality and performance.\n#define SUN_DISK_SAMPLING 0\n\n// When true, uses less precise but faster-to-trace shadow rays\n#define APPROXIMATE_EMISSIVE_SHADOW_RAY 0\n\n// When true, account for transmittance of rays travelling in homogeneous mediums\n// (Currently limited to interior of translucent objects)\n#define ACCOUNT_FOR_TRANSMITTANCE 1\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/PathTracer/PathTracer.hlsl",
    "content": "#ifndef NEE_EMISSIVE\n#define NEE_EMISSIVE 0\n#endif\n\n#include \"Params.hlsli\"\n#include \"../ReSTIR_GI/PathTracing.hlsli\"\n#include \"../../Common/Common.hlsli\"\n\n#define THREAD_GROUP_SWIZZLING 1\n\nusing namespace RtRayQuery;\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_ReSTIR_GI> g_local : register(b1);\nRaytracingAccelerationStructure g_bvh : register(t0);\nStructuredBuffer<RT::MeshInstance> g_frameMeshData : register(t1);\nStructuredBuffer<Vertex> g_vertices : register(t2);\nStructuredBuffer<uint> g_indices : register(t3);\nStructuredBuffer<Material> g_materials : register(t4);\n#if NEE_EMISSIVE == 1\nStructuredBuffer<RT::EmissiveTriangle> g_emissives : register(t5);\nStructuredBuffer<RT::PresampledEmissiveTriangle> g_sampleSets : register(t6);\nStructuredBuffer<RT::EmissiveLumenAliasTableEntry> g_aliasTable : register(t7);\n#endif\n\n//--------------------------------------------------------------------------------------\n// Utility Functions\n//--------------------------------------------------------------------------------------\n\nReSTIR_Util::Globals InitGlobals(bool transmissive)\n{\n    ReSTIR_Util::Globals globals;\n    globals.bvh = g_bvh;\n    globals.frameMeshData = g_frameMeshData;\n    globals.vertices = g_vertices;\n    globals.indices = g_indices;\n    globals.materials = g_materials;\n    globals.maxNumBounces = transmissive ? (uint16_t)g_local.MaxGlossyTrBounces :\n        (uint16_t)g_local.MaxNonTrBounces;\n    globals.russianRoulette = IS_CB_FLAG_SET(CB_IND_FLAGS::RUSSIAN_ROULETTE);\n\n#if NEE_EMISSIVE == 1\n    globals.emissives = g_emissives;\n    globals.sampleSets = g_sampleSets;\n    globals.aliasTable = g_aliasTable;\n    globals.sampleSetSize = (uint16_t)(g_local.SampleSetSize_NumSampleSets & 0xffff);\n#endif\n\n    return globals;\n}\n\nfloat3 EstimateIndirectLighting(uint2 DTid, float3 origin, float2 lensSample, float3 pos, \n    float3 normal, float ior, BSDF::ShadingData surface, ReSTIR_Util::Globals globals, \n    inout RNG rngThread, inout RNG rngGroup)\n{\n    // Use the same sample set for all the threads in this group\n    const uint sampleSetIdx = rngGroup.UniformUintBounded_Faster(g_local.SampleSetSize_NumSampleSets >> 16);\n\n    BSDF::BSDFSample bsdfSample = BSDF::SampleBSDF(normal, surface, rngThread);\n    if(bsdfSample.pdf == 0)\n        return 0;\n\n    Hit hitInfo = Hit::FindClosest<true, true>(pos, normal, bsdfSample.wi, globals.bvh, \n        globals.frameMeshData, globals.vertices, globals.indices, \n        surface.Transmissive());\n\n    if(!hitInfo.hit)\n        return 0;\n\n    GBUFFER_TRI_DIFF_GEO_A g_triA = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::TRI_DIFF_GEO_A];\n    GBUFFER_TRI_DIFF_GEO_B g_triB = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::TRI_DIFF_GEO_B];\n    const uint4 packed_a = g_triA[DTid];\n    const uint2 packed_b = g_triB[DTid];\n\n    Math::TriDifferentials triDiffs = Math::TriDifferentials::Unpack(packed_a, packed_b);\n    float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n\n    RT::RayDifferentials rd = RT::RayDifferentials::Init(DTid, renderDim, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, \n        g_frame.CurrView[2].xyz, g_frame.DoF, g_frame.FocusDepth, \n        lensSample, origin);\n\n    float3 dpdx;\n    float3 dpdy;\n    rd.dpdx_dpdy(pos, normal, dpdx, dpdy);\n    rd.ComputeUVDifferentials(dpdx, dpdy, triDiffs.dpdu, triDiffs.dpdv);\n\n    rd.UpdateRays(pos, normal, bsdfSample.wi, surface.wo, triDiffs, \n        dpdx, dpdy, dot(bsdfSample.wi, normal) < 0, surface.eta);\n\n    SamplerState samp = SamplerDescriptorHeap[g_local.TexFilterDescHeapIdx];\n    float3 li = ReSTIR_RT::PathTrace(pos, normal, ior, sampleSetIdx, bsdfSample, \n        hitInfo, rd, g_frame, globals, samp, rngThread, rngGroup);\n\n    if(dot(li, li) > 0)\n    {\n        surface.SetWi(bsdfSample.wi, normal);\n        li *= bsdfSample.bsdfOverPdf;\n    }\n\n    return li;\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(RESTIR_GI_TEMPORAL_GROUP_DIM_X, RESTIR_GI_TEMPORAL_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID)\n{\n#if THREAD_GROUP_SWIZZLING == 1\n    uint16_t2 swizzledGid;\n\n    uint2 swizzledDTid = Common::SwizzleThreadGroup(DTid, Gid, GTid, \n        uint16_t2(RESTIR_GI_TEMPORAL_GROUP_DIM_X, RESTIR_GI_TEMPORAL_GROUP_DIM_Y),\n        uint16_t(g_local.DispatchDimX_NumGroupsInTile & 0xffff), \n        RESTIR_GI_TEMPORAL_TILE_WIDTH, \n        RESTIR_GI_TEMPORAL_LOG2_TILE_WIDTH, \n        uint16_t(g_local.DispatchDimX_NumGroupsInTile >> 16),\n        swizzledGid);\n#else\n    const uint2 swizzledDTid = DTid.xy;\n    const uint2 swizzledGid = Gid.xy;\n#endif\n    \n    if (swizzledDTid.x >= g_frame.RenderWidth || swizzledDTid.y >= g_frame.RenderHeight)\n        return;\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr = g_metallicRoughness[swizzledDTid];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n\n    RWTexture2D<float4> g_final = ResourceDescriptorHeap[g_local.FinalDescHeapIdx];\n\n    if (flags.invalid || flags.emissive)\n    {\n        if(!g_frame.Accumulate || !g_frame.CameraStatic)\n            g_final[swizzledDTid].rgb = 0;\n    \n        return;\n    }\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float z_view = g_depth[swizzledDTid];\n\n    float2 lensSample = 0;\n    float3 origin = g_frame.CameraPos;\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(swizzledDTid.xyx).zy, g_frame.FrameNum);\n        lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample *= g_frame.LensRadius;\n    }\n\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float3 pos = Math::WorldPosFromScreenSpace2(swizzledDTid, renderDim, z_view, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n        g_frame.DoF, lensSample, g_frame.FocusDepth, origin);\n\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_normal[swizzledDTid.xy]);\n\n    GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n    const float3 baseColor = g_baseColor[swizzledDTid].rgb;\n\n    float eta_curr = ETA_AIR;\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(flags.transmissive)\n    {\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        float ior = g_ior[swizzledDTid];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    const float3 wo = normalize(origin - pos);\n    BSDF::ShadingData surface = BSDF::ShadingData::Init(normal, wo, flags.metallic, mr.y, baseColor, \n        eta_curr, eta_next, flags.transmissive, flags.trDepthGt0);\n\n    // Per-group RNG\n    RNG rngGroup = RNG::Init(swizzledGid ^ 61, g_frame.FrameNum);\n    // Per-thread RNG\n    RNG rngThread = RNG::Init(uint2(swizzledDTid.x ^ 511, swizzledDTid.y ^ 31), g_frame.FrameNum);\n\n    ReSTIR_Util::Globals globals = InitGlobals(flags.transmissive);\n\n    float3 li = EstimateIndirectLighting(swizzledDTid, origin, lensSample, pos, \n        normal, eta_next, surface, globals, rngThread, rngGroup);\n    li = any(isnan(li)) ? 0 : li;\n\n    if(g_frame.Accumulate && g_frame.CameraStatic)\n    {\n        float3 prev = g_final[swizzledDTid].rgb;\n        g_final[swizzledDTid].rgb = prev + li;\n    }\n    else\n        g_final[swizzledDTid].rgb = li;\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/PathTracer/Variants/PathTracer_WPS.hlsl",
    "content": "#define USE_PRESAMPLED_SETS\n// A current limitation is lack of a way to effectively choose between emissive meshes and sun \n// or sky for NEE. Effective importance sampling requires visibility information at the shading \n// point (e.g. a room where the sun can't reach). For now, just manually pick between them.\n#define NEE_EMISSIVE 1\n#include \"../PathTracer.hlsl\""
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/PathTracer/Variants/PathTracer_WoPS.hlsl",
    "content": "// A current limitation is lack of a way to effectively choose between emissive meshes and sun \n// or sky for NEE. Effective importance sampling requires visibility information at the shading \n// point (e.g. a room where the sun can't reach). For now, just manually pick between them.\n#define NEE_EMISSIVE 1\n#include \"../PathTracer.hlsl\""
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_GI/PairwiseMIS.hlsli",
    "content": "#ifndef RESTIR_GI_PAIRWISE_MIS_H\n#define RESTIR_GI_PAIRWISE_MIS_H\n\nnamespace RGI_Util\n{\n    // Ref: Bitterli, Benedikt, \"Correlations and Reuse for Fast and Accurate Physically Based Light Transport\" (2022). Ph.D Dissertation.\n    // https://digitalcommons.dartmouth.edu/dissertations/77\n    struct PairwiseMIS\n    {    \n        static PairwiseMIS Init(uint16_t numSamples, RGI_Util::Reservoir r_c)\n        {\n            PairwiseMIS ret;\n\n            ret.r_s = RGI_Util::Reservoir::Init();\n            ret.m_c = 1.0f;\n            ret.M_s = r_c.M;\n            ret.k = numSamples;\n\n            return ret;\n        }\n\n        float Compute_m_i(RGI_Util::Reservoir r_c, float targetLum, RGI_Util::Reservoir r_i, \n            float jacobianNeighborToCurr)\n        {\n            // TODO following seems to be the correct term to use, but for some reason gives terrible results\n#if 0\n            const float p_i_y_i = r_i.W > 0 ? r_i.w_sum / r_i.W : 0;\n#else\n            const float p_i_y_i = r_i.W > 0 ? (r_i.M * r_i.w_sum) / r_i.W : 0;\n#endif\n\n            const float p_c_y_i = targetLum * r_c.M;\n            // Jacobian term in the numerator cancels out with the same term in the resampling weight\n            float numerator = r_i.M * p_i_y_i;\n            float denom = numerator / jacobianNeighborToCurr + (r_c.M / this.k) * p_c_y_i;\n            float m_i = denom > 0 ? numerator / denom : 0;\n\n            return m_i;\n        }\n\n        void Update_m_c(RGI_Util::Reservoir r_c, RGI_Util::Reservoir r_i, float3 brdfCosTheta_i, \n            float jacobianCurrToNeighbor)\n        {\n            if(!r_i.IsValid())\n            {\n                this.m_c += 1;\n                return;\n            }\n\n            const float target_i = Math::Luminance(r_c.Lo * brdfCosTheta_i);\n            const float p_i_y_c = target_i * jacobianCurrToNeighbor;\n\n            const float p_c_y_c = Math::Luminance(r_c.target_z);\n\n            const float numerator = r_i.M * p_i_y_c;\n            const bool denomGt0 = (p_c_y_c + numerator) > 0; \n            this.m_c += denomGt0 ? 1 - numerator / (numerator + (r_c.M / this.k) * p_c_y_c) : 1;\n        }\n\n        void Stream(RGI_Util::Reservoir r_c, float3 posW_c, float3 normal_c, float linearDepth_c, \n            BSDF::ShadingData surface_c, RGI_Util::Reservoir r_i, float3 posW_i, float3 normal_i, \n            BSDF::ShadingData surface_i, RaytracingAccelerationStructure g_bvh, inout RNG rng)\n        {\n            float3 target_curr;\n            float m_i;\n\n            // m_i\n            if(r_i.IsValid())\n            {\n                float3 wi = r_i.pos - posW_c;\n                float t = length(wi);\n                wi /= t;\n\n                surface_c.SetWi(wi, normal_c);\n                const float3 brdfCosTheta_c = BSDF::CombinedBRDF(surface_c);\n                target_curr = r_i.Lo * brdfCosTheta_c;\n\n                if(Math::Luminance(target_curr) > 1e-5)\n                    target_curr *= RGI_Trace::Visibility_Segment(posW_c, wi, t, normal_c, r_i.ID, g_bvh);\n\n                const float targetLum = Math::Luminance(target_curr);\n                const float J_temporal_to_curr = JacobianReconnectionShift(r_i.normal, posW_c, posW_i, r_i.pos);\n                m_i = Compute_m_i(r_c, targetLum, r_i, J_temporal_to_curr);\n            }\n\n            float3 brdfCosTheta_i;\n            float J_curr_to_temporal;\n\n            // m_c\n            if(r_c.IsValid())\n            {\n                float3 wi = r_c.pos - posW_i;\n                float t = length(wi);\n                wi /= t;\n\n                surface_i.SetWi(wi, normal_i);\n                brdfCosTheta_i = BSDF::CombinedBRDF(surface_i);\n\n                if(Math::Luminance(r_c.Lo * brdfCosTheta_i) > 1e-5)\n                    brdfCosTheta_i *= RGI_Trace::Visibility_Segment(posW_i, wi, t, normal_i, r_c.ID, g_bvh);\n\n                J_curr_to_temporal = JacobianReconnectionShift(r_c.normal, posW_i, posW_c, r_c.pos);\n            }    \n\n            Update_m_c(r_c, r_i, brdfCosTheta_i, J_curr_to_temporal);\n\n            if(r_i.IsValid())\n            {\n                // Jacobian term cancels out with the same term in m_i's numerator\n                const float w_i = m_i * Math::Luminance(target_curr) * r_i.W;\n                this.r_s.Update(w_i, r_i.pos, r_i.normal, r_i.ID, r_i.Lo, target_curr, rng);\n            }\n\n            this.M_s += r_i.M;\n        }\n\n        void End(RGI_Util::Reservoir r_c, float3 posW_c, inout RNG rng)\n        {\n            float3 wi = r_c.pos - posW_c;\n            float t = length(wi);\n            wi /= t;\n            const float w_c = Math::Luminance(r_c.target_z) * r_c.W * this.m_c;\n            this.r_s.Update(w_c, r_c.pos, r_c.normal, r_c.ID, r_c.Lo, r_c.target_z, rng);\n\n            this.r_s.M = this.M_s;\n            const float targetLum = Math::Luminance(r_s.target_z);\n            this.r_s.W = targetLum > 0 ? this.r_s.w_sum / (targetLum * (1 + this.k)) : 0;\n            // TODO investigate\n            this.r_s.W = isnan(this.r_s.W) ? 0 : this.r_s.W;\n        }\n\n        RGI_Util::Reservoir r_s;\n        float m_c;\n        uint16_t M_s;\n        uint16_t k;\n    };\n\n    void SpatialResample(uint2 DTid, uint16_t numSamples, float radius, float3 posW, \n        float3 normal, float z_view, float roughness, BSDF::ShadingData surface, \n        uint prevReservoir_A_DescHeapIdx, uint prevReservoir_B_DescHeapIdx, uint prevReservoir_C_DescHeapIdx, \n        ConstantBuffer<cbFrameConstants> g_frame, RaytracingAccelerationStructure g_bvh, \n        inout Reservoir r, inout RNG rng)\n    {\n        static const half2 k_hammersley[8] =\n        {\n            half2(0.0, -0.7777777777777778),\n            half2(-0.5, -0.5555555555555556),\n            half2(0.5, -0.33333333333333337),\n            half2(-0.75, -0.11111111111111116),\n            half2(0.25, 0.11111111111111116),\n            half2(-0.25, 0.33333333333333326),\n            half2(0.75, 0.5555555555555556),\n            half2(-0.875, 0.7777777777777777)\n        };\n\n        GBUFFER_NORMAL g_prevNormal = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + GBUFFER_OFFSET::NORMAL];\n        GBUFFER_DEPTH g_prevDepth = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + GBUFFER_OFFSET::DEPTH];\n        GBUFFER_METALLIC_ROUGHNESS g_prevMetallicRoughness = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n            GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n        GBUFFER_BASE_COLOR g_prevBaseColor = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n            GBUFFER_OFFSET::BASE_COLOR];\n\n        // rotate sample sequence per pixel\n        const float u0 = rng.Uniform();\n        const uint offset = rng.UniformUintBounded_Faster(8);\n        const float theta = u0 * TWO_PI;\n        const float sinTheta = sin(theta);\n        const float cosTheta = cos(theta);\n        const int2 renderDim = int2(g_frame.RenderWidth, g_frame.RenderHeight);\n        numSamples = min(numSamples, 2);\n        PairwiseMIS pairwiseMIS = PairwiseMIS::Init(numSamples, r);\n\n        float3 samplePosW[2];\n        int16_t2 samplePosSS[2];\n        float sampleRoughness[2];\n        bool sampleMetallic[2];\n        float3 sampleNormal[2];\n        uint16_t k = 0;\n\n        for (int i = 0; i < 4; i++)\n        {\n            float2 sampleUV = k_hammersley[(offset + i) & 7];\n            float2 rotated;\n            rotated.x = dot(sampleUV, float2(cosTheta, -sinTheta));\n            rotated.y = dot(sampleUV, float2(sinTheta, cosTheta));\n            rotated *= radius;\n            const int2 posSS_i = round(float2(DTid) + rotated);\n\n            if (Math::IsWithinBounds(posSS_i, renderDim))\n            {\n                const float depth_i = g_prevDepth[posSS_i];\n                if (depth_i == FLT_MAX)\n                    continue;\n\n                float3 posW_i = Math::WorldPosFromScreenSpace(posSS_i, renderDim,\n                    depth_i, g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.PrevViewInv, \n                    g_frame.PrevCameraJitter, g_frame.CameraNear);\n                bool valid = PlaneHeuristic(posW_i, normal, posW, z_view);\n\n                const float2 mr_i = g_prevMetallicRoughness[posSS_i];\n                \n                bool metallic_i;\n                bool emissive_i;\n                GBuffer::DecodeMetallicEmissive(mr_i.x, metallic_i, emissive_i);\n\n                const float3 normal_i = Math::DecodeUnitVector(g_prevNormal[samplePosSS[i]]);\n\n                // normal heuristic\n                const float normalSimilarity = dot(normal_i, normal);\n                // roughness heuristic\n                const float roughnessDiff = abs(mr_i.y - roughness);\n\n                valid = valid && !emissive_i && \n                    normalSimilarity > 0.0 && \n                    roughnessDiff < 0.2;\n\n                if (!valid)\n                    continue;\n\n                samplePosW[k] = posW_i;\n                samplePosSS[k] = (int16_t2)posSS_i;\n                sampleMetallic[k] = metallic_i;\n                sampleRoughness[k] = mr_i.y;\n                sampleNormal[k] = normal_i;\n                k++;\n\n                if(k == numSamples)\n                    break;\n            }\n        }\n\n        const float3 prevCameraPos = float3(g_frame.PrevViewInv._m03, g_frame.PrevViewInv._m13, g_frame.PrevViewInv._m23);\n        pairwiseMIS.k = k;\n\n        for (int i = 0; i < k; i++)\n        {\n            const float3 sampleBaseColor = g_prevBaseColor[samplePosSS[i]].rgb;\n\n            const float3 wo_i = normalize(prevCameraPos - samplePosW[i]);\n            BSDF::ShadingData surface_i = BSDF::ShadingData::Init(sampleNormal[i], wo_i,\n                sampleMetallic[i], sampleRoughness[i], sampleBaseColor);\n\n            Reservoir neighbor = PartialReadReservoir_Reuse(samplePosSS[i],\n                prevReservoir_A_DescHeapIdx,\n                prevReservoir_B_DescHeapIdx);\n            PartialReadReservoir_ReuseRest(samplePosSS[i], prevReservoir_C_DescHeapIdx, neighbor);\n\n            pairwiseMIS.Stream(r, posW, normal, z_view, surface, neighbor, samplePosW[i], \n                sampleNormal[i], surface_i, g_bvh, rng);\n        }\n\n        pairwiseMIS.End(r, posW, rng);\n        r = pairwiseMIS.r_s;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_GI/Params.hlsli",
    "content": "#ifndef RESTIR_GI_PARAMS_H\n#define RESTIR_GI_PARAMS_H\n\n// Minimum number of bounces before performing Russian Roulette\n#define MIN_NUM_BOUNCES_RUSSIAN_ROULETTE 3\n\n// Probability of next event estimation with sun vs sky\n#define P_SUN_VS_SKY 0.65\n\n// Use multiple importance sampling for direct lighting. Reduces noise (especially for \n// smoother surface) with a moderate performance cost.\n#define USE_MIS 1\n\n// Number of light samples for area sampling in NEE. Higher (up to four)\n// reduces noise but with a significant performance cost.\n#define NEE_NUM_LIGHT_SAMPLES 1\n\n// When disabled, direct lighting uses MIS just for the first indirect hit \n// and power sampling for the subsequent hits. Improves performance at the \n// expense of quality.\n#define MIS_ALL_BOUNCES 0\n#define MIS_NUM_LIGHT_SAMPLES 1\n#define MIS_NON_DIFFUSE_BSDF_SAMPLING 1\n\n// When enabled, sun is treated as a disk area light with radius based on the \n// sun angular diameter, otherwise a directional light. Has minimal impact on \n// quality and performance.\n#define SUN_DISK_SAMPLING 0\n\n// When true, uses less precise but faster-to-trace shadow rays\n#define APPROXIMATE_EMISSIVE_SHADOW_RAY 1\n\n// When true, account for transmittance of rays travelling in homogeneous mediums\n// (Currently limited to interior of translucent objects)\n#define ACCOUNT_FOR_TRANSMITTANCE 0\n\n// Maximum roughness to use virtual motion instead of surface motion for temporal resampling\n#define MAX_ROUGHNESS_VIRTUAL_MOTION 0.075\n\n// Some resampling parameters\n#define MAX_PLANE_DIST_REUSE 0.005\n#define MIN_NORMAL_SIMILARITY_REUSE_TEMPORAL 0.906307787    // within 15 degrees\n#define MAX_ROUGHNESS_DIFF_REUSE 0.05f\n#define NUM_TEMPORAL_SEARCH_ITER 3\n#define TEMPORAL_SEARCH_RADIUS 16\n#define MIN_NUM_SPATIAL_SAMPLES 1\n#define SPATIAL_SEARCH_RADIUS 32\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_GI/PathTracing.hlsli",
    "content": "#ifndef RESTIR_GI_PATH_TRACING_H\n#define RESTIR_GI_PATH_TRACING_H\n\n#include \"../IndirectLighting_Common.h\"\n#include \"../../Common/BSDFSampling.hlsli\"\n#include \"ReSTIR_GI_NEE.hlsli\"\n\nnamespace ReSTIR_RT\n{\n    float3 PathTrace(float3 pos, float3 normal, float ior, uint sampleSetIdx, \n        BSDF::BSDFSample bsdfSample, RtRayQuery::Hit hitInfo, RT::RayDifferentials rd,\n        ConstantBuffer<cbFrameConstants> g_frame, ReSTIR_Util::Globals globals,\n        SamplerState samp, inout RNG rngThread, inout RNG rngGroup)\n    {\n        float3 li = 0.0;\n        float3 throughput = 1.0f;\n        float eta_curr = dot(normal, bsdfSample.wi) < 0 ? ior : ETA_AIR;\n        int bounce = 0;\n        bool inTranslucentMedium = dot(normal, bsdfSample.wi) < 0;\n\n        while(true)\n        {\n            float3 hitPos = mad(hitInfo.t, bsdfSample.wi, pos);\n            float3 dpdx;\n            float3 dpdy;\n            rd.dpdx_dpdy(hitPos, hitInfo.normal, dpdx, dpdy);\n            rd.ComputeUVDifferentials(dpdx, dpdy, hitInfo.triDiffs.dpdu, hitInfo.triDiffs.dpdv);\n\n            BSDF::ShadingData surface;\n            float eta_next;\n            if(!RtRayQuery::GetMaterialData(-bsdfSample.wi, globals.materials, g_frame, eta_curr, \n                rd.uv_grads, hitInfo, surface, eta_next, samp))\n            {\n                break;\n            }\n\n            // Next event estimation\n            li += throughput * RGI_Util::NEE(hitPos, hitInfo.normal, surface, sampleSetIdx, bounce, \n                g_frame, globals, rngThread).ld;\n\n#if ACCOUNT_FOR_TRANSMITTANCE == 1\n            // Beer's law\n            if(inTranslucentMedium && (surface.trDepth > 0))\n            {\n                float3 extCoeff = -log(surface.baseColor_Fr0_TrCol) / surface.trDepth;\n                throughput *= exp(-hitInfo.t * extCoeff);\n            }\n#endif\n\n            // Skip the remaining code as it won't affect li\n            if(bounce >= (globals.maxNumBounces - 1))\n                break;\n\n            // Update path vertex\n            float3 prevPos = pos;\n            pos = hitPos;\n            normal = hitInfo.normal;\n            bounce++;\n\n            // Russian Roulette\n            if(globals.russianRoulette && (bounce >= MIN_NUM_BOUNCES_RUSSIAN_ROULETTE))\n            {\n                // Test against maximum throughput across the wave\n                float waveThroughput = WaveActiveMax(Math::Luminance(throughput));\n\n                float p_terminate = max(0.05, 1 - waveThroughput);\n                if(rngGroup.Uniform() < p_terminate)\n                    break;\n                \n                throughput /= (1 - p_terminate);\n            }\n\n            bsdfSample = BSDF::BSDFSample::Init();\n            if(bounce < globals.maxNumBounces)\n                bsdfSample = BSDF::SampleBSDF(normal, surface, rngThread);\n\n            // Terminate early as extending this path won't contribute to incident radiance\n            if(Math::Luminance(bsdfSample.bsdfOverPdf) == 0)\n                break;\n\n            // Trace a ray to find next path vertex\n            hitInfo = RtRayQuery::Hit::FindClosest<false, true>(pos, normal, bsdfSample.wi, globals.bvh, \n                globals.frameMeshData, globals.vertices, globals.indices, \n                surface.Transmissive());\n\n            if(!hitInfo.hit)\n                break;\n\n            throughput *= bsdfSample.bsdfOverPdf;\n            bool transmitted = dot(normal, bsdfSample.wi) < 0;\n            eta_curr = transmitted ? (eta_curr == ETA_AIR ? eta_next : ETA_AIR) : eta_curr;\n            inTranslucentMedium = transmitted ? !inTranslucentMedium : inTranslucentMedium;\n\n            rd.UpdateRays(pos, normal, bsdfSample.wi, surface.wo, hitInfo.triDiffs, \n                dpdx, dpdy, transmitted, surface.eta);\n        }\n\n        return li;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_GI/ReSTIR_GI.hlsl",
    "content": "#ifndef NEE_EMISSIVE\n#define NEE_EMISSIVE 0\n#endif\n\n#include \"Resampling.hlsli\"\n#include \"../../Common/Common.hlsli\"\n\n#define THREAD_GROUP_SWIZZLING 1\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_ReSTIR_GI> g_local : register(b1);\nRaytracingAccelerationStructure g_bvh : register(t0);\nStructuredBuffer<RT::MeshInstance> g_frameMeshData : register(t1);\nStructuredBuffer<Vertex> g_vertices : register(t2);\nStructuredBuffer<uint> g_indices : register(t3);\nStructuredBuffer<Material> g_materials : register(t4);\n#if NEE_EMISSIVE == 1\nStructuredBuffer<RT::EmissiveTriangle> g_emissives : register(t5);\nStructuredBuffer<RT::PresampledEmissiveTriangle> g_sampleSets : register(t6);\nStructuredBuffer<RT::EmissiveLumenAliasTableEntry> g_aliasTable : register(t7);\nStructuredBuffer<RT::VoxelSample> g_lvg : register(t8);\n#endif\n\n//--------------------------------------------------------------------------------------\n// Utility Functions\n//--------------------------------------------------------------------------------------\n\nReSTIR_Util::Globals InitGlobals(bool transmissive)\n{\n    ReSTIR_Util::Globals globals;\n    globals.bvh = g_bvh;\n    globals.frameMeshData = g_frameMeshData;\n    globals.vertices = g_vertices;\n    globals.indices = g_indices;\n    globals.materials = g_materials;\n    globals.maxNumBounces = transmissive ? (uint16_t)g_local.MaxGlossyTrBounces :\n        (uint16_t)g_local.MaxNonTrBounces;\n    globals.russianRoulette = IS_CB_FLAG_SET(CB_IND_FLAGS::RUSSIAN_ROULETTE);\n\n#if NEE_EMISSIVE == 1\n    globals.emissives = g_emissives;\n    globals.sampleSets = g_sampleSets;\n    globals.aliasTable = g_aliasTable;\n    globals.sampleSetSize = (uint16_t)(g_local.SampleSetSize_NumSampleSets & 0xffff);\n    globals.lvg = g_lvg;\n    globals.gridDim = uint16_t3(g_local.GridDim_xy & 0xffff, g_local.GridDim_xy >> 16, (uint16_t)g_local.GridDim_z);\n    globals.extents = asfloat16(uint16_t3(g_local.Extents_xy & 0xffff, g_local.Extents_xy >> 16, \n            g_local.Extents_z_Offset_y & 0xffff));\n    globals.offset_y = asfloat16(uint16_t(g_local.Extents_z_Offset_y >> 16));\n\n#endif\n\n    return globals;\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(RESTIR_GI_TEMPORAL_GROUP_DIM_X, RESTIR_GI_TEMPORAL_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID)\n{\n#if THREAD_GROUP_SWIZZLING == 1\n    uint16_t2 swizzledGid;\n\n    uint2 swizzledDTid = Common::SwizzleThreadGroup(DTid, Gid, GTid, \n        uint16_t2(RESTIR_GI_TEMPORAL_GROUP_DIM_X, RESTIR_GI_TEMPORAL_GROUP_DIM_Y),\n        uint16_t(g_local.DispatchDimX_NumGroupsInTile & 0xffff), \n        RESTIR_GI_TEMPORAL_TILE_WIDTH, \n        RESTIR_GI_TEMPORAL_LOG2_TILE_WIDTH, \n        uint16_t(g_local.DispatchDimX_NumGroupsInTile >> 16),\n        swizzledGid);\n#else\n    const uint2 swizzledDTid = DTid.xy;\n    const uint2 swizzledGid = Gid.xy;\n#endif\n    \n    if (swizzledDTid.x >= g_frame.RenderWidth || swizzledDTid.y >= g_frame.RenderHeight)\n        return;\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr = g_metallicRoughness[swizzledDTid];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n\n    RWTexture2D<float4> g_final = ResourceDescriptorHeap[g_local.FinalDescHeapIdx];\n\n    if (flags.invalid || flags.emissive)\n    {\n        if(!g_frame.Accumulate || !g_frame.CameraStatic)\n            g_final[swizzledDTid].rgb = 0;\n    \n        return;\n    }\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float z_view = g_depth[swizzledDTid];\n    \n    float2 lensSample = 0;\n    float3 origin = g_frame.CameraPos;\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(swizzledDTid.xyx).zy, g_frame.FrameNum);\n        lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample *= g_frame.LensRadius;\n    }\n\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float3 pos = Math::WorldPosFromScreenSpace2(swizzledDTid, renderDim, z_view, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n        g_frame.DoF, lensSample, g_frame.FocusDepth, origin);\n\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_normal[swizzledDTid.xy]);\n\n    GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n    const float3 baseColor = g_baseColor[swizzledDTid].rgb;\n\n    float eta_curr = ETA_AIR;\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(flags.transmissive)\n    {\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        float ior = g_ior[swizzledDTid];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    const float3 wo = normalize(origin - pos);\n    BSDF::ShadingData surface = BSDF::ShadingData::Init(normal, wo, flags.metallic, mr.y, baseColor, \n        eta_curr, eta_next, flags.transmissive);\n\n    // Per-group RNG\n    RNG rngGroup = RNG::Init(swizzledGid ^ 61, g_frame.FrameNum);\n    // Per-thread RNG\n    RNG rngThread = RNG::Init(uint2(swizzledDTid.x ^ 511, swizzledDTid.y ^ 31), g_frame.FrameNum);\n\n    ReSTIR_Util::Globals globals = InitGlobals(flags.transmissive);\n\n    RGI_Util::Reservoir r = RGI_Util::EstimateIndirectLighting(swizzledDTid, origin, lensSample,\n        pos, normal, mr.y, eta_next, z_view,  surface, g_frame, g_local, globals, rngThread, rngGroup);\n\n    {\n        float3 li = r.target_z * r.W;\n        li = any(isnan(li)) ? 0 : li;\n\n        if(g_frame.Accumulate && g_frame.CameraStatic)\n        {\n            float3 prev = g_final[swizzledDTid].rgb;\n            g_final[swizzledDTid].rgb = prev + li;\n        }\n        else\n            g_final[swizzledDTid].rgb = li;\n    }\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_GI/ReSTIR_GI_NEE.hlsli",
    "content": "#ifndef RESTIR_GI_NEE_H\n#define RESTIR_GI_NEE_H\n\n#include \"../NEE.hlsli\"\n\nnamespace RGI_Util\n{\n    template<int NumLightSamples, bool skipDiffuse>\n    ReSTIR_Util::DirectLightingEstimate NEE_Emissive_MIS(float3 pos, float3 normal, \n        BSDF::ShadingData surface, uint sampleSetIdx, uint numEmissives, \n        ReSTIR_Util::Globals globals, uint emissiveMapsDescHeapOffset, inout RNG rng)\n    {\n        ReSTIR_Util::DirectLightingEstimate ret = ReSTIR_Util::DirectLightingEstimate::Init();\n\n        // Skip light sampling for specular surfaces\n        const bool specular = surface.GlossSpecular() && (surface.metallic || surface.specTr) && \n            (!surface.Coated() || surface.CoatSpecular());\n        const int numLightSamples = specular ? 0 : NumLightSamples;\n\n        // BSDF sampling\n        {\n            BSDF::BSDFSample bsdfSample;\n            if(skipDiffuse)\n                bsdfSample = BSDF::SampleBSDF_NoDiffuse(normal, surface, rng);\n            else\n                bsdfSample = BSDF::SampleBSDF(normal, surface, rng);\n\n            float3 wi = bsdfSample.wi;\n            float3 f = bsdfSample.f;\n            float wiPdf = bsdfSample.pdf;\n\n            // Check if closest hit is a light source\n            RtRayQuery::Hit_Emissive hitInfo = RtRayQuery::Hit_Emissive::FindClosest(pos, normal, \n                wi, globals.bvh, globals.frameMeshData, surface.Transmissive());\n\n            if (hitInfo.HitWasEmissive())\n            {\n                RT::EmissiveTriangle emissive = globals.emissives[hitInfo.emissiveTriIdx];\n                float3 le = Light::Le_EmissiveTriangle(emissive, hitInfo.bary, emissiveMapsDescHeapOffset);\n\n                const float3 vtx1 = Light::DecodeEmissiveTriV1(emissive);\n                const float3 vtx2 = Light::DecodeEmissiveTriV2(emissive);\n                float3 lightNormal = cross(vtx1 - emissive.Vtx0, vtx2 - emissive.Vtx0);\n                float twoArea = length(lightNormal);\n                twoArea = max(twoArea, 1e-6);\n                lightNormal = dot(lightNormal, lightNormal) == 0 ? 1.0.xxx : lightNormal / twoArea;\n                lightNormal = emissive.IsDoubleSided() && dot(-wi, lightNormal) < 0 ? \n                    -lightNormal : lightNormal;\n\n                const float lightSourcePdf = numLightSamples > 0 ?\n                    globals.aliasTable[hitInfo.emissiveTriIdx].CachedP_Orig : \n                    0;\n                const float lightPdf = lightSourcePdf * (2.0f / twoArea);\n\n                // Solid angle measure to area measure\n                float dwdA = hitInfo.t > 0 ? saturate(dot(lightNormal, -wi)) / (hitInfo.t * hitInfo.t) : 0;\n                wiPdf *= dwdA;\n\n                le *= f * dwdA;\n                ret.ld = RT::PowerHeuristic(wiPdf, lightPdf, le, 1, numLightSamples);\n            }\n        }\n\n        // Light sampling\n        [loop]\n        for (int s_l = 0; s_l < numLightSamples; s_l++)\n        {\n#if defined(USE_PRESAMPLED_SETS)\n            RT::PresampledEmissiveTriangle tri = Light::SamplePresampledSet(sampleSetIdx, globals.sampleSets, \n                globals.sampleSetSize, rng);\n\n            Light::EmissiveTriSample lightSample;\n            lightSample.pos = tri.pos;\n            lightSample.normal = Math::DecodeOct32(tri.normal);\n            lightSample.bary = Math::DecodeUNorm2(tri.bary);\n\n            float3 le = tri.le;\n            const float lightPdf = tri.pdf;\n            const uint emissiveIdx = tri.idx;\n            const uint lightID = tri.ID;\n\n            if(tri.twoSided && dot(pos - tri.pos, lightSample.normal) < 0)\n                lightSample.normal *= -1;\n#else\n            Light::AliasTableSample entry = Light::AliasTableSample::get(globals.aliasTable, \n                numEmissives, rng);\n            RT::EmissiveTriangle tri = globals.emissives[entry.idx];\n            Light::EmissiveTriSample lightSample = Light::EmissiveTriSample::get(pos, tri, rng);\n\n            float3 le = Light::Le_EmissiveTriangle(tri, lightSample.bary, emissiveMapsDescHeapOffset);\n            const float lightPdf = entry.pdf * lightSample.pdf;\n            const uint lightID = tri.ID;\n#endif\n\n            const float t = length(lightSample.pos - pos);\n            const float3 wi = (lightSample.pos - pos) / t;\n            \n            // Light normal was reversed for double-sided lights if backfacing\n            if(dot(lightSample.normal, -wi) > 0)\n            {\n                const float dwdA = saturate(dot(lightSample.normal, -wi)) / (t * t);\n\n                surface.SetWi(wi, normal);\n                le *= BSDF::Unified(surface).f * dwdA;\n                \n                if (dot(le, le) > 0)\n                    le *= RtRayQuery::Visibility_Segment(pos, wi, t, normal, lightID, globals.bvh, surface.Transmissive());\n\n                float bsdfPdf = skipDiffuse ? \n                    BSDF::BSDFSamplerPdf_NoDiffuse(normal, surface, wi) :\n                    BSDF::BSDFSamplerPdf(normal, surface, wi, rng);\n                bsdfPdf *= dwdA;\n\n                ret.ld += RT::PowerHeuristic(lightPdf, bsdfPdf, le, numLightSamples);\n            }\n        }\n\n        return ret;\n    }\n\n    ReSTIR_Util::DirectLightingEstimate NEE_Emissive_LVG(float3 pos, float3 normal, \n        BSDF::ShadingData surface, uint sampleSetIdx, uint numEmissives, int numSamples, \n        float3x4 view, ReSTIR_Util::Globals globals, uint emissiveMapsDescHeapOffset, \n        inout RNG rng)\n    {\n        ReSTIR_Util::DirectLightingEstimate ret = ReSTIR_Util::DirectLightingEstimate::Init();\n\n        [loop]\n        for (int s_l = 0; s_l < numSamples; s_l++)\n        {\n            RT::VoxelSample s;\n            Light::EmissiveTriSample lightSample;\n            float3 le;\n            float lightPdf;\n            uint lightID;\n\n            if(LVG::Sample(pos, globals.gridDim, globals.extents, 64, view, globals.lvg, s, rng, (float)globals.offset_y))\n            {\n                lightSample.pos = s.pos;\n                lightSample.normal = Math::DecodeOct32(s.normal);\n                le = s.le;\n                lightPdf = s.pdf;\n                lightID = s.ID;\n\n                if(s.twoSided && dot(lightSample.normal, pos - lightSample.pos) < 0)\n                    lightSample.normal *= -1;\n            }\n            else\n            {\n                RT::PresampledEmissiveTriangle tri = Light::SamplePresampledSet(sampleSetIdx, globals.sampleSets, \n                    globals.sampleSetSize, rng);\n\n                lightSample.pos = tri.pos;\n                lightSample.normal = Math::DecodeOct32(tri.normal);\n                lightSample.bary = Math::DecodeUNorm2(tri.bary);\n\n                le = tri.le;\n                lightPdf = tri.pdf;\n                lightID = tri.ID;\n\n                if(tri.twoSided && dot(pos - tri.pos, lightSample.normal) < 0)\n                    lightSample.normal *= -1;\n            }\n\n            const float t = length(lightSample.pos - pos);\n            const float3 wi = (lightSample.pos - pos) / t;\n            \n            if(lightID != UINT32_MAX && dot(lightSample.normal, -wi) > 0)\n            {\n                const float dwdA = saturate(dot(lightSample.normal, -wi)) / (t * t);\n\n                surface.SetWi(wi, normal);\n                le *= BSDF::Unified(surface).f * dwdA;\n                \n                if (Math::Luminance(le) > 1e-6)\n                {\n                    le *= RtRayQuery::Visibility_Segment(pos, wi, t, normal, lightID, globals.bvh, \n                        surface.Transmissive());\n                }\n\n                ret.ld += le / max(lightPdf, 1e-6);\n            }\n        }\n\n        ret.ld /= numSamples;\n\n        return ret;\n    }\n\n    ReSTIR_Util::DirectLightingEstimate NEE(float3 pos, float3 normal, BSDF::ShadingData surface, \n        uint sampleSetIdx, int bounce, ConstantBuffer<cbFrameConstants> g_frame, \n        ReSTIR_Util::Globals globals, inout RNG rngThread)\n    {\n#if NEE_EMISSIVE == 0\n        float p_sun = rngThread.Uniform();\n\n        // Sun and sky can be skipped if sun is below the horizon.\n        if(-g_frame.SunDir.y > 0)\n        {\n            // Consider the sun only if the surface is not oriented away.\n            float q = (surface.Transmissive() ? 1 : \n                dot(-g_frame.SunDir, normal) > 0) * P_SUN_VS_SKY;\n\n            if(p_sun < q)\n            {\n                ReSTIR_Util::DirectLightingEstimate ls = ReSTIR_Util::NEE_Sun<true>(pos, normal, surface, \n                    globals.bvh, g_frame, rngThread);\n                ls.ld /= q;\n                ls.pdf_solidAngle *= q;\n\n                return ls;\n            }\n\n            ReSTIR_Util::DirectLightingEstimate ls = ReSTIR_Util::NEE_Sky<true>(pos, normal, surface, \n                globals.bvh, g_frame.EnvMapDescHeapOffset, rngThread);\n            ls.ld /= (1 - q);\n            ls.pdf_solidAngle *= (1 - q);\n\n            return ls;\n        }\n\n        return ReSTIR_Util::DirectLightingEstimate::Init();\n#else\n\n#if USE_MIS == 1\n\n        if(bounce == 0)\n        {\n            return NEE_Emissive_MIS<MIS_NUM_LIGHT_SAMPLES, MIS_NON_DIFFUSE_BSDF_SAMPLING>(pos, \n                normal, surface, sampleSetIdx, g_frame.NumEmissiveTriangles, globals, \n                g_frame.EmissiveMapsDescHeapOffset, rngThread);\n        }\n        else\n        {\n#if MIS_ALL_BOUNCES == 1\n            return NEE_Emissive_MIS<1, MIS_NON_DIFFUSE_BSDF_SAMPLING>(pos, normal, \n                surface, sampleSetIdx, g_frame.NumEmissiveTriangles, globals, \n                g_frame.EmissiveMapsDescHeapOffset, rngThread);\n\n#elif defined(USE_LVG) && defined(USE_PRESAMPLED_SETS)\n            return NEE_Emissive_LVG(pos, normal, surface, sampleSetIdx, \n                g_frame.NumEmissiveTriangles, 1, g_frame.CurrView, \n                globals, g_frame.EmissiveMapsDescHeapOffset, rngThread);\n#else\n            return ReSTIR_Util::NEE_Emissive<NEE_NUM_LIGHT_SAMPLES>(pos, normal, \n                surface, sampleSetIdx, g_frame.NumEmissiveTriangles, globals, \n                g_frame.EmissiveMapsDescHeapOffset, rngThread);\n// NEE_MIS_ALL_BOUNCES\n#endif\n        }\n\n// !USE_MIS\n#else\n\n#if defined(USE_LVG)\n        const int numSamples = bounce == 0 ? 2 : 1;\n        return ReSTIR_Util::NEE_Emissive_LVG(pos, normal, surface, sampleSetIdx, \n            g_frame.NumEmissiveTriangles, numSamples, g_frame.CurrView, \n            globals, g_frame.EmissiveMapsDescHeapOffset, rngThread);\n#else\n        return ReSTIR_Util::NEE_Emissive<NEE_NUM_LIGHT_SAMPLES>(pos, normal, \n            surface, sampleSetIdx, g_frame.NumEmissiveTriangles, globals, \n            g_frame.EmissiveMapsDescHeapOffset, rngThread);\n#endif\n\n// USE_MIS\n#endif\n\n// NEE_EMISSIVE\n#endif\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_GI/Resampling.hlsli",
    "content": "#ifndef RESTIR_GI_RESAMPLING_H\n#define RESTIR_GI_RESAMPLING_H\n\n#include \"Params.hlsli\"\n#include \"PathTracing.hlsli\"\n#include \"Reservoir.hlsli\"\n\nnamespace RGI_Util\n{\n    struct TemporalSampleData\n    {\n        float3 posW;\n        float3 normal;\n        float roughness;\n        int16_t2 posSS;\n        uint16 metallic;\n        uint16 transmissive;\n        float eta_next;\n    };\n\n    template<int N>\n    struct TemporalSamples\n    {\n        static TemporalSamples Init()\n        {\n            TemporalSamples<N> ret;\n\n            for(int i = 0; i < N; i++)\n                ret.valid[i] = false;\n\n            return ret;\n        }\n\n        TemporalSampleData data[N];\n        bool valid[N];\n    };\n\n    RGI_Util::Reservoir RIS_InitialCandidates(uint2 DTid, float3 origin, float2 lensSample,\n        float3 primaryPos, float3 primaryNormal, float ior, BSDF::ShadingData primarySurface, \n        uint sampleSetIdx, ConstantBuffer<cbFrameConstants> g_frame, ReSTIR_Util::Globals globals, \n        SamplerState samp, inout RNG rngThread, inout RNG rngGroup)\n    {\n        RGI_Util::Reservoir r = RGI_Util::Reservoir::Init();\n\n        // Find sample point (second path vertex)\n        BSDF::BSDFSample bsdfSample = BSDF::SampleBSDF(primaryNormal, primarySurface, rngThread);\n        if(bsdfSample.pdf == 0)\n            return r;\n\n        GBUFFER_TRI_DIFF_GEO_A g_triA = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::TRI_DIFF_GEO_A];\n        GBUFFER_TRI_DIFF_GEO_B g_triB = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::TRI_DIFF_GEO_B];\n        const uint4 packed_a = g_triA[DTid];\n        const uint2 packed_b = g_triB[DTid];\n\n        Math::TriDifferentials triDiffs = Math::TriDifferentials::Unpack(packed_a, packed_b);\n        float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n\n        RT::RayDifferentials rd = RT::RayDifferentials::Init(DTid, renderDim, \n            g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n            g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, \n            g_frame.CurrView[2].xyz, g_frame.DoF, g_frame.FocusDepth, \n            lensSample, origin);\n\n        float3 dpdx;\n        float3 dpdy;\n        rd.dpdx_dpdy(primaryPos, primaryNormal, dpdx, dpdy);\n        rd.ComputeUVDifferentials(dpdx, dpdy, triDiffs.dpdu, triDiffs.dpdv);\n\n        rd.UpdateRays(primaryPos, primaryNormal, bsdfSample.wi, primarySurface.wo, triDiffs, \n            dpdx, dpdy, dot(bsdfSample.wi, primaryNormal) < 0, primarySurface.eta);\n\n        RtRayQuery::Hit hitInfo = RtRayQuery::Hit::FindClosest<true, true>(primaryPos, primaryNormal, \n            bsdfSample.wi, globals.bvh, globals.frameMeshData, globals.vertices, \n            globals.indices, primarySurface.Transmissive());\n\n        if(!hitInfo.hit)\n            return r;\n\n        const float3 hitPos = primaryPos + hitInfo.t * bsdfSample.wi;\n        const float3 hitNormal = hitInfo.normal;\n\n        // Path tracing loop to find incident radiance from sample point towards primary surface\n        float3 lo = ReSTIR_RT::PathTrace(primaryPos, primaryNormal, ior, sampleSetIdx, bsdfSample, \n            hitInfo, rd, g_frame, globals, samp, rngThread, rngGroup);\n\n        // target = lo * BSDF(wi, wo) * |ndotwi|\n        // source = P(wi)\n        float3 target = lo;\n\n        if(dot(lo, lo) > 0)\n        {\n            primarySurface.SetWi(bsdfSample.wi, primaryNormal);\n            target *= BSDF::Unified(primarySurface).f;\n        }\n\n        float targetLum = Math::Luminance(target);\n        float w = targetLum / max(bsdfSample.pdf, 1e-6f);\n\n        r.Update(w, hitPos, hitNormal, hitInfo.ID, lo, target, rngThread);\n\n        // = w / targetLum\n        r.W = targetLum > 0 ? 1.0 / bsdfSample.pdf : 0.0;\n\n        return r;\n    }\n\n    bool PlaneHeuristic(float3 samplePos, float3 currNormal, float3 currPos, float linearDepth, \n        float th = MAX_PLANE_DIST_REUSE)\n    {\n        float planeDist = dot(currNormal, samplePos - currPos);\n        bool onPlane = abs(planeDist) <= th * linearDepth;\n\n        return onPlane;\n    }\n\n    template<int N>\n    TemporalSamples<N> FindTemporalCandidate(uint2 DTid, float3 posW, float3 normal, float viewZ, \n        float roughness, bool transmissive, float2 prevUV, ConstantBuffer<cbFrameConstants> g_frame, \n        inout RNG rng)\n    {\n        TemporalSamples<N> candidate = RGI_Util::TemporalSamples<N>::Init();\n\n        if (any(prevUV < 0.0f.xx) || any(prevUV > 1.0f.xx))\n            return candidate;\n\n        GBUFFER_DEPTH g_prevDepth = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n            GBUFFER_OFFSET::DEPTH];\n        GBUFFER_NORMAL g_prevNormal = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n            GBUFFER_OFFSET::NORMAL];\n        GBUFFER_METALLIC_ROUGHNESS g_prevMR = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n            GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n        int2 prevPixel = prevUV * renderDim;\n        int curr = 0;\n        const float3 prevCamPos = float3(g_frame.PrevViewInv._m03, g_frame.PrevViewInv._m13, \n            g_frame.PrevViewInv._m23);\n\n        for(int i = 0; i < NUM_TEMPORAL_SEARCH_ITER; i++)\n        {\n            const float theta = rng.Uniform() * TWO_PI;\n            const float sinTheta = sin(theta);\n            const float cosTheta = cos(theta);\n            const float2 offset = TEMPORAL_SEARCH_RADIUS * float2(sinTheta, cosTheta);\n            int2 samplePosSS = prevPixel + (i > 0) * offset;\n\n            if(samplePosSS.x >= renderDim.x || samplePosSS.y >= renderDim.y)\n                continue;\n\n            if(i > 0 && samplePosSS.x == DTid.x && samplePosSS.y == DTid.y)\n                continue;\n\n            const float2 prevMR = g_prevMR[samplePosSS];\n            GBuffer::Flags prevFlags = GBuffer::DecodeMetallic(prevMR.x);\n\n            if(prevFlags.emissive)\n                continue;\n\n            // plane-based heuristic\n            float viewZ_prev = g_prevDepth[samplePosSS];\n\n            float2 lensSample = 0;\n            float3 origin = prevCamPos;\n            if(g_frame.DoF)\n            {\n                RNG rngDoF = RNG::Init(RNG::PCG3d(samplePosSS.xyx).zy, g_frame.FrameNum - 1);\n                lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n                lensSample *= g_frame.LensRadius;\n            }\n\n            float3 prevPos = Math::WorldPosFromScreenSpace2(samplePosSS, renderDim, viewZ_prev, \n                g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.PrevCameraJitter, \n                g_frame.PrevView[0].xyz, g_frame.PrevView[1].xyz, g_frame.PrevView[2].xyz, \n                g_frame.DoF, lensSample, g_frame.FocusDepth, origin);\n\n            float tolerance = MAX_PLANE_DIST_REUSE * (g_frame.DoF ? 10 : 1);\n            if(!RGI_Util::PlaneHeuristic(prevPos, normal, posW, viewZ, tolerance))\n                continue;\n\n            const float3 prevNormal = Math::DecodeUnitVector(g_prevNormal[samplePosSS]);\n            candidate.valid[curr] = dot(prevNormal, normal) > 0.1;\n\n            if(roughness < 0.5)\n            {\n                const float roughnessDiff = abs(prevMR.y - roughness);\n                candidate.valid[curr] = candidate.valid[curr] && (roughnessDiff < 0.15);\n            }\n\n            float prevEta_mat = DEFAULT_ETA_MAT;\n\n            if(prevFlags.transmissive)\n            {\n                float ior = g_ior[samplePosSS];\n                prevEta_mat = GBuffer::DecodeIOR(ior);\n            }\n\n            candidate.valid[curr] = candidate.valid[curr] && (prevFlags.transmissive == transmissive);\n            candidate.valid[curr] = g_frame.DoF ? true : candidate.valid[curr];\n\n            if(candidate.valid[curr])\n            {\n                candidate.data[curr].posSS = (int16_t2)samplePosSS;\n                candidate.data[curr].posW = prevPos;\n                candidate.data[curr].normal = prevNormal;\n                candidate.data[curr].metallic = prevFlags.metallic;\n                candidate.data[curr].roughness = prevMR.y;\n                candidate.data[curr].transmissive = prevFlags.transmissive;\n                candidate.data[curr].eta_next = prevEta_mat;\n\n                curr++;\n\n                if(curr == N)\n                    break;\n            }\n        }\n\n        return candidate;\n    }\n\n    float TargetLumAtTemporalPixel(Reservoir r_curr, TemporalSampleData candidate, \n        ConstantBuffer<cbFrameConstants> g_frame, RaytracingAccelerationStructure g_bvh, \n        bool testVisibility = true)\n    {\n        float3 wi = r_curr.pos - candidate.posW;\n        if(dot(wi, wi) == 0)\n            return 0;\n\n        float t = length(wi);\n        wi /= max(t, 1e-6);\n\n        GBUFFER_BASE_COLOR g_prevBaseColor = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n            GBUFFER_OFFSET::BASE_COLOR];\n\n        const float3 baseColor_prev = g_prevBaseColor[candidate.posSS].rgb;\n        float3 camPos_prev = float3(g_frame.PrevViewInv._m03, g_frame.PrevViewInv._m13, \n            g_frame.PrevViewInv._m23);\n        if(g_frame.DoF)\n        {\n            RNG rngDoF = RNG::Init(RNG::PCG3d(candidate.posSS.xyx).zy, g_frame.FrameNum - 1);\n            float2 lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n            lensSample *= g_frame.LensRadius;\n\n            camPos_prev += mad(lensSample.x, g_frame.PrevView[0].xyz, \n                lensSample.y * g_frame.PrevView[1].xyz);\n        }\n        const float3 wo_prev = normalize(camPos_prev - candidate.posW);\n\n        BSDF::ShadingData surface_prev = BSDF::ShadingData::Init(candidate.normal, wo_prev, \n            candidate.metallic, candidate.roughness, baseColor_prev, ETA_AIR, \n            candidate.eta_next, candidate.transmissive);\n\n        surface_prev.SetWi(wi, candidate.normal);\n        const float3 target_prev = r_curr.Lo * BSDF::Unified(surface_prev).f;\n        const float targetLum_prev = Math::Luminance(target_prev);\n\n        // Test if sample point was visible from temporal pixel. Ideally, previous frame's \n        // BVH should be used.\n        if(testVisibility && targetLum_prev > 1e-5)\n        {\n            if(!RtRayQuery::Visibility_Segment(candidate.posW, wi, t, candidate.normal, \n                r_curr.ID, g_bvh, surface_prev.Transmissive()))\n            {\n                return 0;\n            }\n        }\n\n        return targetLum_prev;\n    }\n\n    // Jacobian of path reconnection in solid angle measure, e.g. reusing a path from pixel q at pixel r\n    //        T[x1_q, x2_q, x3_q, ...] = x1_r, x2_r, x3_q, ...\n    float JacobianReconnectionShift(float3 x2_normal, float3 x1_r, float3 x1_q, float3 x2_q)\n    {\n        float3 v_r = x1_r - x2_q;\n        const float t_r2 = dot(v_r, v_r);\n        v_r = dot(v_r, v_r) == 0 ? v_r : v_r / max(sqrt(t_r2), 1e-6);\n\n        float3 v_q = x1_q - x2_q;\n        const float t_q2 = dot(v_q, v_q);\n        v_q = dot(v_q, v_q) == 0 ? v_q : v_q / max(sqrt(t_q2), 1e-6);\n\n        // phi_r is the angle between v_r and surface normal at x2_q\n        // phi_q is the angle between v_q and surface normal at x2_q\n        float cosPhi_r = dot(v_r, x2_normal);\n        float cosPhi_q = dot(v_q, x2_normal);\n\n        float j = (abs(cosPhi_r) * t_q2) / max(abs(cosPhi_q) * t_r2, 1e-6);\n        // j = clamp(j, 1e-4, 1e2);\n\n        return j;\n    }\n\n    void TemporalResample1(float3 posW, float3 normal, float roughness, BSDF::ShadingData surface, \n        uint prevReservoir_A_DescHeapIdx, uint prevReservoir_B_DescHeapIdx, uint prevReservoir_C_DescHeapIdx,\n        TemporalSampleData candidate, ConstantBuffer<cbFrameConstants> g_frame, \n        RaytracingAccelerationStructure g_bvh, inout Reservoir r, inout RNG rng)\n    {\n        Reservoir r_prev = PartialReadReservoir_Reuse(candidate.posSS,\n            prevReservoir_A_DescHeapIdx,\n            prevReservoir_B_DescHeapIdx);\n\n        const uint16_t M_new = (uint16_t)(r.M + r_prev.M);\n\n        // Target at temporal pixel with current pixel's sample\n        if(r.w_sum != 0)\n        {\n            float targetLum_prev = 0.0f;\n\n            if(r_prev.M > 0 && Math::Luminance(r.Lo) > 1e-6)\n                targetLum_prev = TargetLumAtTemporalPixel(r, candidate, g_frame, g_bvh);\n\n            const float p_curr = Math::Luminance(r.target_z);\n            // p_temporal at current reservoir's sample (r.y) is equal to p_temporal(x) where\n            // x is the input that would get mapped to r.y under the shift, followed by division \n            // by Jacobian of the mapping (J(T(x) = y)). Since J(T(x) = y) = 1 / J(T^-1(y) = x) \n            // we have\n            // p_temporal(r.y) = p_temporal(x) / J(T(x) = y)\n            //                 = p_temporal(x) * J(T^-1(y) = x)\n            const float J_curr_to_temporal = JacobianReconnectionShift(r.normal, candidate.posW, posW, r.pos);\n            const float m_curr = p_curr / max(p_curr + (float)r_prev.M * targetLum_prev * J_curr_to_temporal, 1e-6);\n            r.w_sum *= m_curr;\n        }\n\n        if(r_prev.ID == UINT32_MAX || dot(r_prev.Lo, 1) == 0)\n        {\n            float targetLum = Math::Luminance(r.target_z);\n            r.W = targetLum > 0.0 ? r.w_sum / targetLum : 0.0;\n            r.M = M_new;\n\n            return;\n        }\n\n        // target at current pixel with previous reservoir's sample\n        float3 wi = r_prev.pos - posW;\n        float t = length(wi);\n        wi /= t;\n\n        surface.SetWi(wi, normal);\n        const float3 target_curr = r_prev.Lo * BSDF::Unified(surface).f;\n        const float targetLum_curr = Math::Luminance(target_curr);\n\n        // Target at current pixel with temporal reservoir's sample\n        if(targetLum_curr > 1e-6)\n        {\n            if(RtRayQuery::Visibility_Segment(posW, wi, t, normal, r_prev.ID, g_bvh, surface.Transmissive()))\n            {\n                PartialReadReservoir_ReuseRest(candidate.posSS, prevReservoir_C_DescHeapIdx, r_prev);\n\n                const float targetLum_prev = r_prev.W > 0 ? r_prev.w_sum / r_prev.W : 0;\n                const float J_temporal_to_curr = JacobianReconnectionShift(r_prev.normal, posW, candidate.posW, r_prev.pos);\n                // J_temporal_to_curr in the numerator cancels out with the same term in w_prev\n                const float numerator = (float)r_prev.M * targetLum_prev;\n                const float denom = numerator / max(J_temporal_to_curr, 1e-6) + targetLum_curr;\n                // Balance heuristic\n                const float m_prev = numerator / max(denom, 1e-6);\n                const float w_prev = m_prev * targetLum_curr * r_prev.W;\n\n                r.Update(w_prev, r_prev.pos, r_prev.normal, r_prev.ID, r_prev.Lo, target_curr, rng);\n            }\n        }\n\n        float targetLum = Math::Luminance(r.target_z);\n        r.W = targetLum > 0.0 ? r.w_sum / targetLum : 0.0;\n        r.M = M_new;\n    }\n\n    void TemporalResample2(float3 posW, float3 normal, float roughness, BSDF::ShadingData surface, \n        uint prevReservoir_A_DescHeapIdx, uint prevReservoir_B_DescHeapIdx, uint prevReservoir_C_DescHeapIdx,\n        TemporalSampleData candidate[2], ConstantBuffer<cbFrameConstants> g_frame, RaytracingAccelerationStructure g_bvh, \n        inout Reservoir r, inout RNG rng)\n    {\n        uint16_t M_new = (uint16_t)r.M;\n        Reservoir r_prev[2];\n\n        for (int k = 0; k < 2; k++)\n        {\n            r_prev[k] = PartialReadReservoir_Reuse(candidate[k].posSS,\n                prevReservoir_A_DescHeapIdx,\n                prevReservoir_B_DescHeapIdx);\n\n            M_new += r_prev[k].M;\n        }\n    \n        // Target at temporal pixel with current pixel's sample\n        {\n            const float p_curr = Math::Luminance(r.target_z);\n            float denom = p_curr;\n\n            if(Math::Luminance(r.Lo) > 1e-5)\n            {\n                for(int p = 0; p < 2; p++)\n                {\n                    if(r_prev[p].M == 0)\n                        continue;\n\n                    float targetLum_prev = TargetLumAtTemporalPixel(r, candidate[p], g_frame, g_bvh, p != 0);\n                    float J_curr_to_temporal = JacobianReconnectionShift(r.normal, candidate[p].posW, posW, r.pos);\n                    denom += (float)r_prev[p].M * J_curr_to_temporal * targetLum_prev;\n                }\n            }\n\n            const float m_curr = denom == 0 ? 0 : p_curr / denom;\n            r.w_sum *= m_curr;\n        }\n\n        // Target at current pixel with temporal reservoir's sample\n        for(int i = 0; i < 2; i++)    \n        {\n            float3 wi = r_prev[i].pos - posW;\n            float t = all(wi == 0) ? 0 : length(wi);\n            wi /= max(t, 1e-6);\n            surface.SetWi(wi, normal);\n\n            const float3 target_curr = r_prev[i].Lo * BSDF::Unified(surface).f;\n            const float targetLum_curr = Math::Luminance(target_curr);\n    \n            // RIS weights becomes zero; then only M needs to be updated, which is done at the end anyway\n            if(targetLum_curr < 1e-5f)\n                continue;\n\n            if(RtRayQuery::Visibility_Segment(posW, wi, t, normal, r_prev[i].ID, g_bvh, surface.Transmissive()))\n            {\n                PartialReadReservoir_ReuseRest(candidate[i].posSS, prevReservoir_C_DescHeapIdx, r_prev[i]);\n\n                const float targetLum_prev = r_prev[i].W > 0 ? r_prev[i].w_sum / r_prev[i].W : 0;\n                // Balance heuristic\n                const float J_temporal_to_curr = JacobianReconnectionShift(r_prev[i].normal, posW, candidate[i].posW, r_prev[i].pos);\n                // J_temporal_to_curr in the numerator cancels out with the same term in w_prev\n                const float numerator = (float)r_prev[i].M * targetLum_prev;\n                float denom = (numerator / J_temporal_to_curr) + targetLum_curr;\n                if(r_prev[1 - i].M > 0 && targetLum_prev > 0)\n                {\n                    const float J_temporal_to_temporal = JacobianReconnectionShift(r_prev[i].normal, candidate[1 - i].posW, \n                        candidate[i].posW, r_prev[i].pos);\n                    const float targetLum_other = TargetLumAtTemporalPixel(r_prev[i], candidate[1 - i], g_frame, g_bvh);\n                    denom += (float)r_prev[1 - i].M * targetLum_other / max(J_temporal_to_temporal, 1e-6);\n                }\n\n                denom = J_temporal_to_curr == 0 ? 0 : denom;\n                const float m_prev = denom == 0 ? 0 : numerator / denom;\n                // Resampling weight\n                const float w_prev = m_prev * targetLum_curr * r_prev[i].W;\n\n                r.Update(w_prev, r_prev[i].pos, r_prev[i].normal, r_prev[i].ID, r_prev[i].Lo, target_curr, rng);\n            }\n        }\n\n        float targetLum = Math::Luminance(r.target_z);\n        r.W = targetLum > 0.0 ? r.w_sum / targetLum : 0.0;\n        r.M = M_new;\n    }\n\n    float2 VirtualMotionReproject_Refl(float3 posW, float roughness, float3 wo, float whdotwo, float ndotwo, float t,\n        float k, float z_view, ConstantBuffer<cbFrameConstants> g_frame)\n    {\n        // For a spherical mirror, the radius of curvature is defined as R = 1 / k where k denotes curvature. Then\n        //        1 / d_o + 1 / d_i = 2 / R\n        //        1 / d_o + 1 / d_i = 2k\n        // \n        // where d_i and d_o denote distance along the optical axis (surface normal) for the image and the object \n        // respectively. Let wo be the unit direction vector from the surface towards the eye, then ray \n        // distances t_i and t_o are given by\n        //        t_o = d_o / whdotwo\n        //        t_i = -d_i / whdotwo\n        //\n        // Replacing into above\n        //        t_i = t_o / (1 - 2 k whdotwo t_o)\n        //\n        // As a convention, convex and concave surfaces have negative and positive radius of curvatures respectively.\n        // Ref: https://phys.libretexts.org/Bookshelves/University_Physics/Book%3A_University_Physics_(OpenStax)/University_Physics_III_-_Optics_and_Modern_Physics_(OpenStax)/02%3A_Geometric_Optics_and_Image_Formation/2.03%3A_Spherical_Mirrors\n    \n        float pixelWidth = 2.0 * g_frame.TanHalfFOV * z_view / max(ndotwo, 1e-6);\n\n        // Curvature computation above used the opposite signs\n        k *= -1.0f;\n        k *= pixelWidth;\n        float imageDist = t / max(1.0f - 2 * k * t * whdotwo, 1e-6);\n\n        // Interpolate between virtual motion and surface motion using GGX dominant factor\n        // Ref: D. Zhdan, \"ReBLUR: A Hierarchical Recurrent Denoiser,\" in Ray Tracing Gems 2, 2021.\n        float factor = BSDF::MicrofacetBRDFGGXSmithDominantFactor(ndotwo, roughness);\n        float3 virtualPos = posW - wo * imageDist * factor;\n    \n        float2 prevUV = Math::UVFromWorldPos(virtualPos, \n            float2(g_frame.RenderWidth, g_frame.RenderHeight), \n            g_frame.TanHalfFOV,\n            g_frame.AspectRatio,\n            g_frame.PrevView);\n\n        return prevUV;\n    }\n\n    float2 VirtualMotionReproject_FlatMirror(float3 posW, float3 wo, float t, float4x4 prevViewProj)\n    {\n        float3 virtualPos = posW - wo * t;\n        float4 virtualPosNDC = mul(prevViewProj, float4(virtualPos, 1.0f));\n        float2 prevUV = Math::UVFromNDC(virtualPosNDC.xy / virtualPosNDC.w);\n\n        return prevUV;\n    }\n\n    float2 VirtualMotionReproject_Tr(float3 posW, float3 wo, float t, float3 normal, float eta,\n        float k, float z_view, float whdotwo, float ndotwo, ConstantBuffer<cbFrameConstants> g_frame)\n    {\n        float pixelWidth = 2.0 * g_frame.TanHalfFOV * z_view / max(ndotwo, 1e-6);\n        k *= -1.0f;\n        k *= pixelWidth;\n        float imageDist_tr = eta / (k * (1 - 1 / eta) - 1 / (eta * t));\n        float imageDist_refl = t / (1.0f - 2 * k * t * whdotwo);\n\n        float3 wi = refract(-wo, normal, 1 / eta);\n        // Switch to reflection for TIR\n        float3 virtualPos = dot(wi, wi) == 0 ? posW - wo * imageDist_refl : posW + wi * imageDist_tr;\n        float2 prevUV = Math::UVFromWorldPos(virtualPos, \n            float2(g_frame.RenderWidth, g_frame.RenderHeight), \n            g_frame.TanHalfFOV,\n            g_frame.AspectRatio,\n            g_frame.PrevView);\n\n        return prevUV;\n    }\n\n    // When some reservoir has a much higher weight compared to other reservoirs in its \n    // neighborhood, it can lead to artifacts that appear as bright spots. Following\n    // attempts to mitigate this issue.\n    void SuppressOutlierReservoirs(inout RGI_Util::Reservoir r)\n    {\n        float waveSum = WaveActiveSum(r.w_sum);\n        float waveAvg = (waveSum - r.w_sum) / (WaveGetLaneCount() - 1);\n        if(r.w_sum > 25 * waveAvg)\n            r.M = 1;\n    }\n\n    RGI_Util::Reservoir EstimateIndirectLighting(uint2 DTid, float3 origin, float2 lensSample,\n        float3 pos, float3 normal, float roughness, float ior, float z_view, BSDF::ShadingData surface, \n        ConstantBuffer<cbFrameConstants> g_frame, \n        ConstantBuffer<cb_ReSTIR_GI> g_local, \n        ReSTIR_Util::Globals globals, inout RNG rngThread, inout RNG rngGroup)\n    {\n        // Artifacts become noticeable in motion for specular surfaces\n        if(IS_CB_FLAG_SET(CB_IND_FLAGS::STOCHASTIC_MULTI_BOUNCE) && \n            (roughness >= 0.1 || g_frame.CameraStatic))\n        {\n            globals.maxNumBounces = rngGroup.Uniform() < 0.5 ? (uint16_t)1 : \n                globals.maxNumBounces;\n        }\n\n        // Use the same sample set for all the threads in this group\n        const uint sampleSetIdx = rngGroup.UniformUintBounded_Faster(g_local.SampleSetSize_NumSampleSets >> 16);\n        SamplerState samp = SamplerDescriptorHeap[g_local.TexFilterDescHeapIdx];\n\n        RGI_Util::Reservoir r = RGI_Util::RIS_InitialCandidates(DTid, origin, lensSample, \n            pos, normal, ior, surface, sampleSetIdx, g_frame, globals, samp, \n            rngThread, rngGroup);\n\n        if (IS_CB_FLAG_SET(CB_IND_FLAGS::TEMPORAL_RESAMPLE))\n        {            \n            // Reverse reproject current pixel\n            GBUFFER_MOTION_VECTOR g_motionVector = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n                GBUFFER_OFFSET::MOTION_VECTOR];\n            const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n            const float2 motionVec = g_motionVector[DTid];\n            const float2 currUV = (DTid + 0.5f) / renderDim;\n            const float2 prevSurfaceUV = currUV - motionVec;\n            float2 prevUV = prevSurfaceUV;\n            float3 reflectedPos = r.pos;\n\n            TemporalSamples<2> candidate = RGI_Util::FindTemporalCandidate<2>(DTid, pos, normal, \n                z_view, roughness, surface.specTr, prevUV, g_frame, rngThread);\n\n            // candidate.valid[0] = candidate.valid[0] && !r.IsValid();\n\n            // Skip temporal resampling if no valid sample is found\n            if (candidate.valid[1] && roughness > 0.05)\n            {\n                RGI_Util::TemporalResample2(pos, normal, roughness, surface,\n                    g_local.PrevReservoir_A_DescHeapIdx, g_local.PrevReservoir_B_DescHeapIdx, \n                    g_local.PrevReservoir_C_DescHeapIdx, candidate.data, g_frame, \n                    globals.bvh, r, rngThread);\n            }\n            else if (candidate.valid[0])\n            {\n                 RGI_Util::TemporalResample1(pos, normal, roughness, surface,\n                     g_local.PrevReservoir_A_DescHeapIdx, g_local.PrevReservoir_B_DescHeapIdx, \n                     g_local.PrevReservoir_C_DescHeapIdx, candidate.data[0], g_frame, \n                     globals.bvh, r, rngThread);\n            }\n\n            if(IS_CB_FLAG_SET(CB_IND_FLAGS::BOILING_SUPPRESSION))\n                SuppressOutlierReservoirs(r);\n        }\n\n        if (IS_CB_FLAG_SET(CB_IND_FLAGS::TEMPORAL_RESAMPLE) ||\n            IS_CB_FLAG_SET(CB_IND_FLAGS::RESET_TEMPORAL_TEXTURES))\n        {\n            RGI_Util::WriteReservoir(DTid, r, g_local.CurrReservoir_A_DescHeapIdx,\n                g_local.CurrReservoir_B_DescHeapIdx, g_local.CurrReservoir_C_DescHeapIdx, \n                g_local.M_max);\n        }\n\n        // if (IS_CB_FLAG_SET(CB_IND_FLAGS::SPATIAL_RESAMPLE))\n        // {\n        //     RGI_Util::SpatialResample(DTid, 1, SPATIAL_SEARCH_RADIUS, posW, normal, z_view, roughness, \n        //         surface, g_local.PrevReservoir_A_DescHeapIdx, g_local.PrevReservoir_B_DescHeapIdx, \n        //         g_local.PrevReservoir_C_DescHeapIdx, g_frame, g_bvh, r, rngThread);\n        // }\n\n        return r;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_GI/Reservoir.hlsli",
    "content": "#ifndef RESTIR_GI_RESERVOIR_H\n#define RESTIR_GI_RESERVOIR_H\n\n#include \"../IndirectLighting_Common.h\"\n#include \"../../Common/Sampling.hlsli\"\n\nnamespace RGI_Util\n{\n    struct Reservoir\n    {\n        static Reservoir Init()\n        {\n            Reservoir res;\n\n            res.pos = FLT_MAX.xxx;\n            res.normal = 0;\n            res.Lo = 0.0.xxx;\n            res.M = 0;\n            res.w_sum = 0;\n            res.W = 0;\n            res.ID = UINT32_MAX;\n            \n            return res;\n        }\n\n        static Reservoir Init(float3 vtxPos, uint16_t m, float3 Lo, uint hitID)\n        {\n            Reservoir res;\n\n            res.pos = vtxPos;\n            res.Lo = Lo;\n            res.ID = hitID;\n            res.M = m;\n            res.normal = 0;\n            res.w_sum = 0;\n            res.W = 0;\n\n            return res;\n        }\n        \n        bool Update(float weight, float3 vtxPos, float3 vtxNormal, uint vtxID, float3 vtxLo, float3 target, \n            inout RNG rng)\n        {\n            if(isnan(weight))\n                return false;\n\n            this.w_sum += weight;\n            this.M += 1;\n\n            if (rng.Uniform() < (weight / max(1e-6f, this.w_sum)))\n            {\n                this.pos = vtxPos;\n                this.normal = vtxNormal;\n                this.ID = vtxID;\n                this.Lo = vtxLo;\n                this.target_z = target;\n\n                return true;\n            }\n\n            return false;\n        }\n\n        bool IsValid()\n        {\n            return ID != UINT32_MAX;\n        }\n\n        float3 pos;\n        float3 Lo;\n\n        float3 normal;\n        float W;\n        float w_sum;\n        uint ID;\n\n        float3 target_z;\n        half M;\n    };\n\n    Reservoir PartialReadReservoir_Reuse(uint2 DTid, uint inputAIdx, uint inputBIdx)\n    {\n        Texture2D<float4> g_reservoir_A = ResourceDescriptorHeap[inputAIdx];\n        Texture2D<half4> g_reservoir_B = ResourceDescriptorHeap[inputBIdx];\n        const float4 resA = g_reservoir_A[DTid];\n        const half4 resB = g_reservoir_B[DTid];\n\n        float3 pos = resA.xyz;\n        uint hitID = asuint(resA.w);\n        float3 Lo = resB.xyz;\n        uint16_t M = (uint16_t)resB.w;\n\n        return Reservoir::Init(pos, M, Lo, hitID);\n    }\n\n    void PartialReadReservoir_ReuseRest(uint2 DTid, uint inputCIdx, inout Reservoir r)\n    {\n        Texture2D<float4> g_reservoir_C = ResourceDescriptorHeap[inputCIdx];\n        float3 resC = g_reservoir_C[DTid].xyz;\n        r.w_sum = resC.x;\n        r.W = resC.y;\n\n        uint n = asuint(resC.z);\n        uint16_t2 ns = Math::UnpackUintToUint16(n);\n        r.normal = Math::DecodeOct32(ns);\n    }\n\n    float3 PartialReadReservoir_Pos(uint2 DTid, uint inputAIdx)\n    {\n        Texture2D<float4> g_reservoir_A = ResourceDescriptorHeap[inputAIdx];\n        return g_reservoir_A[DTid].xyz;\n    }\n\n    void WriteReservoir(uint2 DTid, Reservoir r, uint outputAIdx, uint outputBIdx, uint outputCIdx, float M_max)\n    {\n        RWTexture2D<float4> g_outReservoir_A = ResourceDescriptorHeap[outputAIdx];\n        RWTexture2D<half4> g_outReservoir_B = ResourceDescriptorHeap[outputBIdx];\n        RWTexture2D<float4> g_outReservoir_C = ResourceDescriptorHeap[outputCIdx];\n\n        uint16_t2 n = Math::EncodeOct32(r.normal);\n        uint nu = n.x | (uint(n.y) << 16);\n        half M_clamped = min(r.M, (half)M_max);\n\n        float4 outA = float4(r.pos, asfloat(r.ID));\n        half4 outB = half4(r.Lo, M_clamped);\n        float3 outC = float3(r.w_sum, r.W, asfloat(nu));\n\n        g_outReservoir_A[DTid] = outA;\n        g_outReservoir_B[DTid] = outB;\n        g_outReservoir_C[DTid].xyz = outC;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_GI/Variants/ReSTIR_GI_LVG.hlsl",
    "content": "#define USE_PRESAMPLED_SETS\n#define USE_LVG\n// A current limitation is lack of a way to effectively choose between emissive meshes and sun \n// or sky for NEE. Effective importance sampling requires visibility information at the shading \n// point (e.g. a room where the sun can't reach). For now, just manually pick between them.\n#define NEE_EMISSIVE 1\n#include \"../ReSTIR_GI.hlsl\""
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_GI/Variants/ReSTIR_GI_WPS.hlsl",
    "content": "#define USE_PRESAMPLED_SETS\n// A current limitation is lack of a way to effectively choose between emissive meshes and sun \n// or sky for NEE. Effective importance sampling requires visibility information at the shading \n// point (e.g. a room where the sun can't reach). For now, just manually pick between them.\n#define NEE_EMISSIVE 1\n#include \"../ReSTIR_GI.hlsl\""
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_GI/Variants/ReSTIR_GI_WoPS.hlsl",
    "content": "// A current limitation is lack of a way to effectively choose between emissive meshes and sun \n// or sky for NEE. Effective importance sampling requires visibility information at the shading \n// point (e.g. a room where the sun can't reach). For now, just manually pick between them.\n#define NEE_EMISSIVE 1\n#include \"../ReSTIR_GI.hlsl\""
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Params.hlsli",
    "content": "#ifndef RESTIR_PT_PARAMS_H\n#define RESTIR_PT_PARAMS_H\n\n// Minimum number of bounces before performing Russian Roulette\n#define MIN_NUM_BOUNCES_RUSSIAN_ROULETTE 3\n\n// When enabled, sun is treated as a disk area light with radius based on the \n// sun angular diameter, otherwise a directional light. Has minimal impact on \n// quality and performance (currently not supported for ReSTIR PT).\n#define SUN_DISK_SAMPLING 0\n\n// When true, uses less precise but faster-to-trace shadow rays\n#define APPROXIMATE_EMISSIVE_SHADOW_RAY 1\n\n// Some resampling parameters\n#define MAX_PLANE_DIST_REUSE 1\n#define MAX_ROUGHNESS_DIFF_REUSE 0.175f\n#define MIN_NORMAL_SIMILARITY_SPATIAL_REUSE 0.9f  // ~25 degrees\n#define MAX_ROUGHNESS_DIFF_TEMPORAL_REUSE 0.3f\n#define MAX_ROUGHNESS_DIFF_SPATIAL_REUSE 0.05f\n\n// Use a lower M for less aggressive spatial reuse in following cases\n#define M_MAX_X_K_TRANSMISSIVE 4\n#define M_MAX_X_K_IN_MOTION 4\n\n#define SKY_SAMPLING_PREFER_PERFORMANCE 1\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/ReSTIR_PT_NEE.hlsli",
    "content": "#ifndef RESTIR_PT_NEE_H\n#define RESTIR_PT_NEE_H\n\n#include \"Params.hlsli\"\n#include \"../NEE.hlsli\"\n#include \"../../Common/BSDFSampling.hlsli\"\n\nnamespace RPT_Util\n{\n    ReSTIR_Util::DirectLightingEstimate NEE_NonEmissive(float3 pos, float3 normal, \n        BSDF::ShadingData surface, ConstantBuffer<cbFrameConstants> g_frame, \n        RaytracingAccelerationStructure g_bvh, inout RNG rng)\n    {\n        ReSTIR_Util::DirectLightingEstimate ret = ReSTIR_Util::DirectLightingEstimate::Init();\n        ret.dwdA = 1;\n\n        // Weighted reservoir sampling to sample Le x BSDF, with BSDF lobes as source distributions\n        ReSTIR_Util::SkyIncidentRadiance leFunc = ReSTIR_Util::SkyIncidentRadiance::Init(\n            g_frame.EnvMapDescHeapOffset);\n        const bool specular = surface.GlossSpecular() && (surface.metallic || surface.specTr) && \n            (!surface.Coated() || surface.CoatSpecular());\n\n        float w_sum = 0;\n        float3 target_z = 0;\n#if SKY_SAMPLING_PREFER_PERFORMANCE == 1\n        const float2 u_wrs = rng.Uniform2D();\n        const float2 u_d = rng.Uniform2D();\n        const float2 u_c = rng.Uniform2D();\n        const float2 u_g = rng.Uniform2D();\n        const float u_wrs_b0 = rng.Uniform();\n        const float u_wrs_b1 = rng.Uniform();\n#else\n        const float u_wrs = rng.Uniform();\n#endif\n        // Sample sun\n        {\n            const float3 wi_s = -g_frame.SunDir;\n            // Skip when Sun is below the horizon or it hits backside of non-transmissive surface\n            const bool visible = (wi_s.y > 0) &&\n                ((dot(wi_s, normal) > 0) || surface.Transmissive());\n            float pdf_b = 0;\n            float pdf_d = 0;\n\n            if(visible)\n            {\n                surface.SetWi(wi_s, normal);\n                target_z = Light::Le_Sun(pos, g_frame) * BSDF::Unified(surface).f;\n                float ndotWi = dot(wi_s, normal);\n\n#if SKY_SAMPLING_PREFER_PERFORMANCE == 1\n                pdf_b = (ndotWi < 0) && surface.ThinWalled() ? 0 : \n                    BSDF::BSDFSamplerPdf_NoDiffuse(normal, surface, wi_s, leFunc);\n                pdf_d = !specular * abs(ndotWi) * ONE_OVER_PI;\n                pdf_d *= surface.ThinWalled() ? 0.5f : ndotWi > 0;\n#else\n                pdf_s = BSDF::BSDFSamplerPdf(normal, surface, wi_s, leFunc, rng);\n#endif\n            }\n\n            w_sum = RT::BalanceHeuristic3(1, pdf_b, pdf_d, Math::Luminance(target_z));\n\n            ret.lt = Light::TYPE::SUN;\n            ret.lobe = BSDF::LOBE::ALL;\n            ret.wi = wi_s;\n        }\n\n#if SKY_SAMPLING_PREFER_PERFORMANCE == 1\n        if(!specular)\n        {\n            float pdf_e;\n            float3 wi_e = BSDF::SampleDiffuse(normal, u_d, pdf_e);\n            if(surface.ThinWalled())\n            {\n                // u_wrs_b1 is not used when surface is thin walled\n                wi_e = u_wrs_b1 > 0.5 ? -wi_e : wi_e;\n                pdf_e *= 0.5f;\n            }\n            surface.SetWi(wi_e, normal);\n            const float3 target = leFunc(wi_e) * BSDF::Unified(surface).f;\n\n            // Balance Heuristic\n            const float pdf_b = !surface.reflection && surface.ThinWalled() ? 0 :\n                BSDF::BSDFSamplerPdf_NoDiffuse(normal, surface, wi_e, leFunc);\n            const float w_e = RT::BalanceHeuristic(pdf_e, pdf_b, Math::Luminance(target));\n            w_sum += w_e;\n\n            if((w_sum > 0) && (u_wrs.y < (w_e / w_sum)))\n            {\n                ret.lt = Light::TYPE::SKY;\n                ret.lobe = BSDF::LOBE::ALL;\n                ret.wi = wi_e;\n\n                target_z = target;\n            }\n        }\n#endif\n\n        // BSDF sampling\n        {\n#if SKY_SAMPLING_PREFER_PERFORMANCE == 1\n            BSDF::BSDFSample bsdfSample = BSDF::SampleBSDF_NoDiffuse(normal, surface, \n                u_c, u_g, u_wrs_b0, u_wrs_b1, leFunc);\n            float ndotwi = dot(bsdfSample.wi, normal);\n            float pdf_e = !specular * abs(ndotwi) * ONE_OVER_PI;\n            pdf_e *= surface.ThinWalled() ? 0.5f : ndotwi > 0;\n            const float w_b = RT::BalanceHeuristic(bsdfSample.pdf, pdf_e, \n                Math::Luminance(bsdfSample.f));\n#else\n            BSDF::BSDFSample bsdfSample = BSDF::SampleBSDF(normal, surface, leFunc, rng);\n            const float w_b = Math::Luminance(bsdfSample.bsdfOverPdf);\n#endif\n            w_sum += w_b;\n\n            if((w_sum > 0) && (u_wrs.x < (w_b / w_sum)))\n            {\n                ret.lt = Light::TYPE::SKY;\n                ret.lobe = bsdfSample.lobe;\n                ret.wi = bsdfSample.wi;\n\n                target_z = bsdfSample.f;\n            }\n        }\n\n        const float targetLum = Math::Luminance(target_z);\n        ret.ld = targetLum > 0 ? target_z * w_sum / targetLum : 0;\n        ret.pdf_solidAngle = w_sum > 0 ? targetLum / w_sum : 0;\n\n        if(dot(ret.ld, ret.ld) > 0)\n            ret.ld *= RtRayQuery::Visibility_Ray(pos, ret.wi, normal, g_bvh, surface.Transmissive());\n\n        return ret;\n    }\n\n    ReSTIR_Util::DirectLightingEstimate NEE_Bsdf(float3 pos, float3 normal, \n        BSDF::ShadingData surface, int nextBounce, ReSTIR_Util::Globals globals, \n        uint emissiveMapsDescHeapOffset, out BSDF::BSDFSample bsdfSample, \n        out RtRayQuery::Hit_Emissive hitInfo, inout RNG rng)\n    {\n        ReSTIR_Util::DirectLightingEstimate ret = ReSTIR_Util::DirectLightingEstimate::Init();\n\n        // No point in light sampling for specular surfaces\n        const bool specular = surface.GlossSpecular() && (surface.metallic || surface.specTr) && \n            (!surface.Coated() || surface.CoatSpecular());\n        const int numLightSamples = specular ? 0 : 1;\n\n        // In the last iteration of path tracing loop, BSDF sampling here is just used for direct \n        // lighting. Use <= instead of < to cover that case.\n        if(nextBounce <= globals.maxNumBounces)\n            bsdfSample = BSDF::SampleBSDF(normal, surface, rng);\n\n        const float wiPdf = bsdfSample.pdf;\n        const float3 wi = bsdfSample.wi;\n        const float3 f = bsdfSample.f;\n\n        // Check if closest hit is a light source\n        hitInfo = RtRayQuery::Hit_Emissive::FindClosest(pos, normal, wi, globals.bvh, \n            globals.frameMeshData, surface.Transmissive());\n\n        if (hitInfo.HitWasEmissive())\n        {\n            RT::EmissiveTriangle emissive = globals.emissives[hitInfo.emissiveTriIdx];\n            const float3 le = Light::Le_EmissiveTriangle(emissive, hitInfo.bary, \n                emissiveMapsDescHeapOffset);\n\n            const float3 vtx1 = Light::DecodeEmissiveTriV1(emissive);\n            const float3 vtx2 = Light::DecodeEmissiveTriV2(emissive);\n            float3 lightNormal = cross(vtx1 - emissive.Vtx0, vtx2 - emissive.Vtx0);\n            float twoArea = length(lightNormal);\n            lightNormal = dot(lightNormal, lightNormal) == 0 ? 0.0 : lightNormal / twoArea;\n            lightNormal = emissive.IsDoubleSided() && (dot(-wi, lightNormal) < 0) ? \n                -lightNormal : lightNormal;\n            float lightPdf = 0;\n\n            if(!specular)\n            {\n                const float lightSourcePdf = numLightSamples > 0 ?\n                    globals.aliasTable[hitInfo.emissiveTriIdx].CachedP_Orig : \n                    0;\n                lightPdf = twoArea > 0 ? lightSourcePdf * (2.0f / twoArea) : 0;\n            }\n\n            // Solid angle measure to area measure\n            float dwdA = saturate(dot(lightNormal, -wi)) / (hitInfo.t * hitInfo.t);\n            float wiPdf_area = wiPdf * dwdA;\n            float3 ld = le * f * dwdA;\n\n            ret.ld = specular ? (wiPdf_area > 0 ? ld / wiPdf_area : 0) : \n                RT::PowerHeuristic(wiPdf_area, lightPdf, ld);\n            ret.le = le;\n            ret.wi = wi;\n            ret.pdf_solidAngle = wiPdf;\n            ret.dwdA = dwdA;\n            ret.ID = emissive.ID;\n            ret.pos = mad(hitInfo.t, wi, pos);\n            ret.normal = lightNormal;\n            ret.pdf_light = lightPdf;\n            ret.lobe = bsdfSample.lobe;\n            ret.lt = Light::TYPE::EMISSIVE;\n            ret.twoSided = emissive.IsDoubleSided();\n        }\n\n        // Last iteration -- set bsdfSample = null so that we early exit from path tracing loop\n        if(nextBounce >= globals.maxNumBounces)\n            bsdfSample.bsdfOverPdf = 0;\n\n        return ret;\n    }\n\n    ReSTIR_Util::DirectLightingEstimate NEE_Emissive(float3 pos, float3 normal, \n        BSDF::ShadingData surface, uint sampleSetIdx, uint numEmissives, int nextBounce, \n        ReSTIR_Util::Globals globals, uint emissiveMapsDescHeapOffset, inout RNG rng)\n    {\n        ReSTIR_Util::DirectLightingEstimate ret = ReSTIR_Util::DirectLightingEstimate::Init();\n        ret.lt = Light::TYPE::EMISSIVE;\n        ret.lobe = BSDF::LOBE::ALL;\n\n#if defined(USE_PRESAMPLED_SETS)\n        RT::PresampledEmissiveTriangle tri = Light::SamplePresampledSet(sampleSetIdx, globals.sampleSets, \n            globals.sampleSetSize, rng);\n\n        Light::EmissiveTriSample lightSample;\n        lightSample.pos = tri.pos;\n        lightSample.normal = Math::DecodeOct32(tri.normal);\n        lightSample.bary = Math::DecodeUNorm2(tri.bary);\n\n        float3 le = tri.le;\n        const float lightPdf = tri.pdf;\n        const uint emissiveIdx = tri.idx;\n        const uint lightID = tri.ID;\n        const bool twoSided = tri.twoSided;\n\n        if(tri.twoSided && dot(pos - tri.pos, lightSample.normal) < 0)\n            lightSample.normal *= -1;\n\n        // Deterministic RNG state regardless of USE_PRESAMPLED_SETS\n        rng.Uniform3D();\n#else\n        Light::AliasTableSample entry = Light::AliasTableSample::get(globals.aliasTable, \n            numEmissives, rng);\n        RT::EmissiveTriangle tri = globals.emissives[entry.idx];\n        Light::EmissiveTriSample lightSample = Light::EmissiveTriSample::get(pos, tri, rng);\n\n        float3 le = Light::Le_EmissiveTriangle(tri, lightSample.bary, emissiveMapsDescHeapOffset);\n        const float lightPdf = entry.pdf * lightSample.pdf;\n        const uint lightID = tri.ID;\n        const bool twoSided = tri.IsDoubleSided();\n#endif\n\n        const float t = length(lightSample.pos - pos);\n        const float3 wi = (lightSample.pos - pos) / t;\n\n        if((dot(lightSample.normal, -wi) > 0) && (t > 0))\n        {\n            const float dwdA = saturate(dot(lightSample.normal, -wi)) / (t * t);\n            surface.SetWi(wi, normal);\n            float3 ld = le * BSDF::Unified(surface).f * dwdA;\n                \n            if (dot(ld, ld) > 0)\n            {\n                ld *= RtRayQuery::Visibility_Segment(pos, wi, t, normal, lightID, \n                    globals.bvh, surface.Transmissive());\n            }\n\n            float bsdfPdf = 0;\n            if(dot(ld, ld) > 0)\n            {\n                bsdfPdf = BSDF::BSDFSamplerPdf(normal, surface, wi, rng);\n                bsdfPdf *= dwdA;\n            }\n\n            ret.ld = RT::PowerHeuristic(lightPdf, bsdfPdf, ld);\n            ret.le = le;\n            ret.wi = wi;\n            ret.pdf_solidAngle = lightPdf / dwdA;\n            ret.dwdA = dwdA;\n            ret.ID = lightID;\n            ret.pos = lightSample.pos;\n            ret.normal = lightSample.normal;\n            ret.pdf_light = lightPdf;\n            ret.twoSided = twoSided;\n        }\n\n        return ret;\n    }\n\n    template<bool TestVisibility>\n    ReSTIR_Util::DirectLightingEstimate EvalDirect_Sky(float3 pos, float3 normal, \n        BSDF::ShadingData surface, float3 wi, BSDF::LOBE lobe, uint skyViewDescHeapOffset, \n        RaytracingAccelerationStructure g_bvh, inout RNG rng)\n    {\n        ReSTIR_Util::SkyIncidentRadiance leFunc = ReSTIR_Util::SkyIncidentRadiance::Init(\n            skyViewDescHeapOffset);\n        BSDF::BSDFSamplerEval eval = BSDF::EvalBSDFSampler(normal, surface, wi, lobe, leFunc, rng);\n\n        ReSTIR_Util::DirectLightingEstimate ret;\n        // = Le(wi) * BSDF(wi) / pdf\n        ret.ld = eval.bsdfOverPdf;\n        ret.pdf_solidAngle = eval.pdf;\n\n        if(TestVisibility && (dot(ret.ld, ret.ld) > 0))\n            ret.ld *= RtRayQuery::Visibility_Ray(pos, wi, normal, g_bvh, surface.Transmissive());\n\n        return ret;\n    }\n\n    ReSTIR_Util::DirectLightingEstimate EvalDirect_Emissive_Case2(float3 pos, float3 normal, \n        BSDF::ShadingData surface, float3 wi, float3 le, float dwdA, float lightPdf, \n        BSDF::LOBE lobe, inout RNG rngReplay, inout RNG rngNEE)\n    {\n        surface.SetWi(wi, normal);\n        float3 ld = le * BSDF::Unified(surface).f * dwdA;\n\n        ReSTIR_Util::DirectLightingEstimate ret = ReSTIR_Util::DirectLightingEstimate::Init();\n        if(dot(ld, ld) == 0)\n            return ret;\n\n        if(lobe == BSDF::LOBE::ALL)\n        {\n            rngNEE.Uniform4D();\n\n            float bsdfPdf = BSDF::BSDFSamplerPdf(normal, surface, wi, rngNEE);\n            float bsdfPdf_area = bsdfPdf * dwdA;\n\n            ret.ld = RT::PowerHeuristic(lightPdf, bsdfPdf_area, ld);\n            // Jacobian of shift simplifies to 1.0 when light sampling is used\n            ret.pdf_solidAngle = 1.0f;\n        }\n        else\n        {\n            BSDF::BSDFSamplerEval eval = BSDF::EvalBSDFSampler(normal, surface, wi, lobe, rngReplay);\n\n            const bool specular = surface.GlossSpecular() && (surface.metallic || surface.specTr) && \n                (!surface.Coated() || surface.CoatSpecular());\n            float bsdfPdf_area = eval.pdf * dwdA;\n            ret.ld = specular ? (bsdfPdf_area > 0 ? ld / bsdfPdf_area : 0) : \n                RT::PowerHeuristic(bsdfPdf_area, lightPdf, ld);\n            ret.pdf_solidAngle = eval.pdf;\n        }\n\n        return ret;\n    }\n\n    ReSTIR_Util::DirectLightingEstimate EvalDirect_Emissive_Case3(float3 pos, float3 normal, \n        BSDF::ShadingData surface, float3 wi, float t, float3 le, float3 lightNormal, \n        float lightPdf, uint lightID, bool twoSided, BSDF::LOBE lobe, \n        RaytracingAccelerationStructure g_bvh, inout RNG rngReplay, inout RNG rngNEE)\n    {\n        float wiDotLightNormal = dot(lightNormal, -wi);\n        float dwdA = abs(wiDotLightNormal) / (t * t);\n\n        surface.SetWi(wi, normal);\n        float3 ld = (wiDotLightNormal > 0) || twoSided ? \n            le * BSDF::Unified(surface).f * dwdA :\n            0;\n\n        if(dot(ld, ld) > 0)\n        {\n            ld *= RtRayQuery::Visibility_Segment(pos, wi, t, normal, lightID, g_bvh, \n                surface.Transmissive());\n        }\n\n        ReSTIR_Util::DirectLightingEstimate ret = ReSTIR_Util::DirectLightingEstimate::Init();\n        if(dot(ld, ld) == 0)\n            return ret;\n\n        if(lobe == BSDF::LOBE::ALL)\n        {\n            rngNEE.Uniform4D();\n\n            float bsdfPdf = BSDF::BSDFSamplerPdf(normal, surface, wi, rngNEE);\n            float bsdfPdf_area = bsdfPdf * dwdA;\n\n            ret.ld = RT::PowerHeuristic(lightPdf, bsdfPdf_area, ld);\n            // Jacobian of shift simplifies to 1.0 when light sampling is used\n            ret.pdf_solidAngle = 1.0f;\n        }\n        else\n        {\n            BSDF::BSDFSamplerEval eval = BSDF::EvalBSDFSampler(normal, surface, wi, lobe, rngReplay);\n\n            const bool specular = surface.GlossSpecular() && (surface.metallic || surface.specTr) && \n                (!surface.Coated() || surface.CoatSpecular());\n            float bsdfPdf_area = eval.pdf * dwdA;\n            ret.ld = specular ? (bsdfPdf_area > 0 ? ld / bsdfPdf_area : 0) : \n                RT::PowerHeuristic(bsdfPdf_area, lightPdf, ld);\n            // = BSDF sampling PDF (solid angle measure) times geometry term\n            ret.pdf_solidAngle = bsdfPdf_area;\n        }\n\n        return ret;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/ReSTIR_PT_PathTrace.hlsl",
    "content": "#ifndef NEE_EMISSIVE\n#define NEE_EMISSIVE 0\n#endif\n\n#include \"../../Common/Common.hlsli\"\n#include \"Util.hlsli\"\n\n#define THREAD_GROUP_SWIZZLING 1\n\nusing namespace RtRayQuery;\nusing namespace ReSTIR_Util;\nusing namespace RPT_Util;\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_ReSTIR_PT_PathTrace> g_local : register(b1);\nRaytracingAccelerationStructure g_bvh : register(t0);\nStructuredBuffer<RT::MeshInstance> g_frameMeshData : register(t1);\nStructuredBuffer<Vertex> g_vertices : register(t2);\nStructuredBuffer<uint> g_indices : register(t3);\nStructuredBuffer<Material> g_materials : register(t4);\n#if NEE_EMISSIVE == 1\nStructuredBuffer<RT::EmissiveTriangle> g_emissives : register(t5);\nStructuredBuffer<RT::PresampledEmissiveTriangle> g_sampleSets : register(t6);\nStructuredBuffer<RT::EmissiveLumenAliasTableEntry> g_aliasTable : register(t7);\n#endif\n\n//--------------------------------------------------------------------------------------\n// Utility Functions\n//--------------------------------------------------------------------------------------\n\n// Data needed from previous hit to decide if reconnection is possible\nstruct PrevHit\n{\n    static PrevHit Init(float alpha, BSDF::LOBE lobe_prev, float3 wi, float pdf)\n    {\n        PrevHit ret;\n        ret.alpha_lobe = alpha;\n        ret.lobe = lobe_prev;\n        ret.wi = wi;\n        ret.pdf = pdf;\n\n        return ret;\n    }\n\n    float alpha_lobe;\n    float3 wi;\n    float pdf;\n    BSDF::LOBE lobe;\n};\n\nReSTIR_Util::Globals InitGlobals(bool transmissive)\n{\n    ReSTIR_Util::Globals globals;\n    globals.bvh = g_bvh;\n    globals.frameMeshData = g_frameMeshData;\n    globals.vertices = g_vertices;\n    globals.indices = g_indices;\n    globals.materials = g_materials;\n    uint maxNonTrBounces = g_local.Packed & 0xf;\n    uint maxGlossyTrBounces = (g_local.Packed >> PACKED_INDEX::NUM_GLOSSY_BOUNCES) & 0xf;\n    globals.maxNumBounces = transmissive ? (uint16_t)maxGlossyTrBounces :\n        (uint16_t)maxNonTrBounces;\n#if NEE_EMISSIVE == 1\n    globals.emissives = g_emissives;\n    globals.sampleSets = g_sampleSets;\n    globals.aliasTable = g_aliasTable;\n    globals.sampleSetSize = (uint16_t)(g_local.SampleSetSize_NumSampleSets & 0xffff);\n#endif\n\n    return globals;\n}\n\nvoid MaybeSetCase2OrCase3(int16 pathVertex, float3 pos, float3 normal, float t, \n    uint ID, uint meshIdx, BSDF::ShadingData surface, PrevHit prevHit, DirectLightingEstimate ls, \n    uint seed_nee, inout Reconnection rc)\n{\n    // Possibly update reconnection vertex (Case 2)\n    const float alpha_lobe_direct = BSDF::LobeAlpha(surface, ls.lobe);\n\n    if(rc.Empty() && RPT_Util::CanReconnect(prevHit.alpha_lobe, alpha_lobe_direct, \n        0, pos, prevHit.lobe, ls.lobe, g_local.Alpha_min))\n    {\n        rc.SetCase2(pathVertex, pos, t, normal, ID, meshIdx,\n            prevHit.wi, prevHit.lobe, prevHit.pdf, \n            ls.wi, ls.lobe, ls.pdf_solidAngle, ls.lt, ls.pdf_light, \n            ls.le, seed_nee, ls.dwdA);\n    }\n\n    // Possibly update reconnection vertex Case 3) -- If some light source is reached \n    // with no earlier reconnection found, then the light sample could be the reconnection \n    // vertex assuming the prior vertex is sufficiently rough.\n    if(rc.Empty() && (alpha_lobe_direct >= g_local.Alpha_min))\n    {\n        rc.SetCase3(pathVertex + (int16_t)1, ls.pos, ls.lt, ls.lobe, \n            ls.ID, ls.le, ls.normal, ls.pdf_solidAngle, ls.pdf_light, \n            ls.dwdA, ls.wi, ls.twoSided, seed_nee);\n    }\n}\n\ntemplate<bool Emissive>\nvoid EstimateDirectAndUpdateRC(int16 pathVertex, float3 pos, Hit hitInfo, \n    BSDF::ShadingData surface, PrevHit prevHit, float3 throughput, float3 throughput_k, \n    uint sampleSetIdx, Globals globals, inout float3 li, inout BSDF::BSDFSample bsdfSample, \n    out Hit_Emissive nextHit, inout Reconnection rc, inout Reservoir r, inout RNG rngNEE, \n    inout RNG rngReplay)\n{\n    // Path resampling:\n    //  - target = (Le * \\prod f * g) / p\n    //  - p_source = 1\n\n    if(Emissive)\n    {\n        BSDF::BSDFSample nextBsdfSample;\n        int16 nextBounce = pathVertex - (int16)1;\n\n        // BSDF sampling\n        DirectLightingEstimate ls_b = RPT_Util::NEE_Bsdf(pos, hitInfo.normal, surface, \n            nextBounce, globals, g_frame.EmissiveMapsDescHeapOffset, nextBsdfSample, \n            nextHit, rngReplay);\n\n        if(nextHit.HitWasEmissive())\n        {\n            const float3 fOverPdf = throughput * ls_b.ld;\n            li += fOverPdf;\n\n            // Case 1: For path x_0, ..., x_k, x_{k + 1}, ..., L is the radiance reflected from \n            // x_{k + 1} towards x_k. If connection becomes case 2 or case 3, it is overwritten.\n            rc.L = half3(ls_b.ld * throughput_k);\n\n            MaybeSetCase2OrCase3(pathVertex, pos, hitInfo.normal, hitInfo.t, hitInfo.ID, \n                hitInfo.meshIdx, surface, prevHit, ls_b, /*unused*/ 0, rc);\n\n            float risWeight = Math::Luminance(fOverPdf);\n            r.Update(risWeight, fOverPdf, rc, rngNEE);\n        }\n\n        // Light sampling\n        const bool specular = surface.GlossSpecular() && (surface.metallic || surface.specTr) && \n            (!surface.Coated() || surface.CoatSpecular());\n\n        if(!specular)\n        {\n            const uint seed_nee = rngNEE.State;\n            DirectLightingEstimate ls = RPT_Util::NEE_Emissive(pos, hitInfo.normal, \n                surface, sampleSetIdx, g_frame.NumEmissiveTriangles, nextBounce, globals, \n                g_frame.EmissiveMapsDescHeapOffset, rngNEE);\n\n            const float3 fOverPdf = throughput * ls.ld;\n            li += fOverPdf;\n\n            // Different (sub)path\n            if(rc.IsCase2() || rc.IsCase3())\n                rc.Clear();\n\n            // Case 1: For path x_0, ..., x_k, x_{k + 1}, ..., L is the radiance reflected from \n            // x_{k + 1} towards x_k. If connection becomes case 2 or case 3, it is overwritten.\n            rc.L = half3(ls.ld * throughput_k);\n\n            MaybeSetCase2OrCase3(pathVertex, pos, hitInfo.normal, hitInfo.t, hitInfo.ID, \n                hitInfo.meshIdx, surface, prevHit, ls, seed_nee, rc);\n\n            float risWeight = Math::Luminance(fOverPdf);\n            r.Update(risWeight, fOverPdf, rc, rngNEE);\n        }\n\n        // Use BSDF sample for next path vertex\n        bsdfSample = nextBsdfSample;\n    }\n    else\n    {\n        const uint seed_nee = rngNEE.State;\n        DirectLightingEstimate ls = RPT_Util::NEE_NonEmissive(pos, hitInfo.normal, surface, \n            g_frame, globals.bvh, rngNEE);\n\n        const float3 fOverPdf = throughput * ls.ld;\n        li += fOverPdf;\n\n        // Case 1: For path x_0, ..., x_k, x_{k + 1}, ..., L is the radiance reflected from \n        // x_{k + 1} towards x_k. If connection becomes case 2 or case 3, it is overwritten.\n        rc.L = half3(ls.ld * throughput_k);\n\n        MaybeSetCase2OrCase3(pathVertex, pos, hitInfo.normal, hitInfo.t, hitInfo.ID, \n            hitInfo.meshIdx, surface, prevHit, ls, seed_nee, rc);\n\n        float risWeight = Math::Luminance(fOverPdf);\n        r.Update(risWeight, fOverPdf, rc, rngNEE);\n    }\n}\n\nRPT_Util::Reservoir PathTrace(float3 pos, float3 normal, float ior, BSDF::ShadingData surface, \n    uint sampleSetIdx, BSDF::BSDFSample bsdfSample, RT::RayDifferentials rd, \n    Globals globals, inout RNG rngReplay, inout RNG rngThread, inout RNG rngGroup, \n    out float3 li)\n{\n    RPT_Util::Reconnection reconnection = RPT_Util::Reconnection::Init();\n    RPT_Util::Reservoir r = RPT_Util::Reservoir::Init();\n    li = 0.0;\n    int16 bounce = 0;\n    float3 throughput = bsdfSample.bsdfOverPdf;\n    PrevHit prevHit = PrevHit::Init(BSDF::LobeAlpha(surface, bsdfSample.lobe), \n        bsdfSample.lobe, bsdfSample.wi, bsdfSample.pdf);\n\n    // If ray was refracted, current IOR changes to that of hit material, otherwise\n    // current medium continues to be air\n    float eta_curr = dot(normal, bsdfSample.wi) < 0 ? ior : ETA_AIR;\n    // Product of f / p terms from x_{k + 1} onwards. Needed for case 1 connections.\n    float3 throughput_k = 1;\n    // Note: skip the first bounce for a milder impacet. May have to change in the future.\n    // bool anyGlossyBounces = bsdfSample.lobe != BSDF::LOBE::DIFFUSE_R;\n    // bool anyGlossyBounces = false;\n    bool inTranslucentMedium = eta_curr != ETA_AIR;\n    SamplerState samp = SamplerDescriptorHeap[g_local.TexFilterDescHeapIdx];\n\n#if NEE_EMISSIVE == 0\n    // unused\n    Hit_Emissive nextHit;\n#else\n    // Use the same BSDF ray used for direct lighting at previous path vertex\n    Hit_Emissive nextHit = Hit_Emissive::FindClosest(pos, normal, bsdfSample.wi, \n        globals.bvh, g_frameMeshData, surface.Transmissive());\n#endif\n\n    while(true)\n    {\n        // Skip first two vertices (camera and primary)\n        const int16 pathVertex = bounce + (int16)2;\n\n#if NEE_EMISSIVE == 0\n        Hit hitInfo = Hit::FindClosest<true, true>(pos, normal, bsdfSample.wi, g_bvh, g_frameMeshData, \n            g_vertices, g_indices, surface.Transmissive());\n#else\n        // Use the same BSDF ray used for direct lighting at previous path vertex\n        RtRayQuery::Hit hitInfo = nextHit.ToHitInfo<true>(bsdfSample.wi, g_frameMeshData, \n            g_vertices, g_indices);\n#endif\n\n        if(!hitInfo.hit)\n            break;\n\n        float3 newPos = mad(hitInfo.t, bsdfSample.wi, pos);\n        float3 dpdx;\n        float3 dpdy;\n        rd.dpdx_dpdy(newPos, hitInfo.normal, dpdx, dpdy);\n        rd.ComputeUVDifferentials(dpdx, dpdy, hitInfo.triDiffs.dpdu, hitInfo.triDiffs.dpdv);\n\n        // Fetch material at new vertex\n        float eta_next;\n        if(!RtRayQuery::GetMaterialData(-bsdfSample.wi, g_materials, g_frame, eta_curr, \n            rd.uv_grads, hitInfo, surface, eta_next, samp))\n        {\n           break;\n        }\n\n        // if(IS_CB_FLAG_SET(CB_IND_FLAGS::PATH_REGULARIZATION) && anyGlossyBounces)\n        //     surface.Regularize();\n\n        // Update vertex\n        pos = newPos;\n        normal = hitInfo.normal;\n        const float prevBsdfSamplePdf = bsdfSample.pdf;\n        const BSDF::LOBE prevBsdfSampleLobe = bsdfSample.lobe;\n        float3 tr = 1;\n\n        // Beer's law\n        if(inTranslucentMedium && (surface.trDepth > 0))\n        {\n            float3 extCoeff = -log(surface.baseColor_Fr0_TrCol) / surface.trDepth;\n            tr = exp(-hitInfo.t * extCoeff);\n            throughput *= tr;\n        }\n\n        // Direct lighting\n        EstimateDirectAndUpdateRC<NEE_EMISSIVE>(pathVertex, pos, hitInfo, surface, prevHit, \n            throughput, throughput_k, sampleSetIdx, globals, li, bsdfSample, nextHit, \n            reconnection, r, rngThread, rngReplay);\n\n        // Remaining code can be skipped in the last iteration\n        if(bounce >= (globals.maxNumBounces - 1))\n            break;\n\n        // Once one vertex x_k satisfying the reconnection conditions is found (with x_k and x_{k + 1} \n        // not on a light source), all the subsequent paths share x_k as their reconnection vertex \n        // as paths are built incrementally.\n        if(reconnection.IsCase2() || reconnection.IsCase3())\n            reconnection.Clear();\n\n        // Move to next path vertex\n        bounce++;\n\n        // Russian Roulette\n        if(IS_CB_FLAG_SET(CB_IND_FLAGS::RUSSIAN_ROULETTE) && (bounce >= MIN_NUM_BOUNCES_RUSSIAN_ROULETTE))\n        {\n            // Test against maximum throughput across the wave\n            float waveThroughput = WaveActiveMax(Math::Luminance(throughput));\n            if(waveThroughput < 1)\n            {\n                float p_terminate = max(0.05, 1 - waveThroughput);\n                if(rngGroup.Uniform() < p_terminate)\n                    break;\n                \n                throughput /= (1 - p_terminate);\n                throughput_k /= (reconnection.k <= bounce) ? (1 - p_terminate) : 1;\n            }\n        }\n\n#if NEE_EMISSIVE == 0\n        // Sample BSDF to generate new direction\n        bsdfSample = BSDF::BSDFSample::Init();\n\n        if(bounce < globals.maxNumBounces)\n            bsdfSample = BSDF::SampleBSDF(normal, surface, rngReplay);\n#endif\n\n        // Terminate early as extending this path won't contribute anything\n        if(dot(bsdfSample.bsdfOverPdf, bsdfSample.bsdfOverPdf) == 0)\n            break;\n\n        // With x_k as reconnection vertex, now we know w_k towards the non-light vertex after it\n        const float alpha_lobe = BSDF::LobeAlpha(surface, bsdfSample.lobe);\n\n        // Possibly update reconnection vertex (x_{k + 1} on a non-light vertex)\n        if(reconnection.Empty() && RPT_Util::CanReconnect(prevHit.alpha_lobe, alpha_lobe, \n            0, 0, prevHit.lobe, bsdfSample.lobe, g_local.Alpha_min))\n        {\n            reconnection.SetCase1(pathVertex, pos, hitInfo.t, hitInfo.normal, hitInfo.ID,\n                hitInfo.meshIdx, -surface.wo, prevBsdfSampleLobe, prevBsdfSamplePdf,\n                bsdfSample.wi, bsdfSample.lobe, bsdfSample.pdf);\n\n            throughput_k = 1;\n        }\n\n        // Update path throughput starting from vertex after reconnection \n        if(reconnection.k <= bounce)\n            throughput_k *= bsdfSample.bsdfOverPdf * tr;\n\n        bool transmitted = dot(normal, bsdfSample.wi) < 0;\n        throughput *= bsdfSample.bsdfOverPdf;\n        // anyGlossyBounces = anyGlossyBounces || (bsdfSample.lobe != BSDF::LOBE::DIFFUSE_R);\n\n        eta_curr = transmitted ? (eta_curr == ETA_AIR ? eta_next : ETA_AIR) : eta_curr;\n        inTranslucentMedium = eta_curr != ETA_AIR;\n        prevHit.alpha_lobe = alpha_lobe;\n        prevHit.lobe = bsdfSample.lobe;\n        prevHit.wi = bsdfSample.wi;\n        prevHit.pdf = bsdfSample.pdf;\n\n        // Given the hit point and new sample direction, update origin and direction of \n        // ray differentials accordingly\n        rd.UpdateRays(pos, normal, bsdfSample.wi, surface.wo, hitInfo.triDiffs, \n            dpdx, dpdy, transmitted, surface.eta);\n    }\n\n    return r;\n}\n\nRPT_Util::Reservoir RIS_InitialCandidates(uint2 DTid, uint2 Gid, float3 origin, \n    float2 lensSample, float3 pos, float3 normal, float ior, BSDF::ShadingData surface, \n    out float3 li)\n{\n    // Use a different index than ReSTIR DI\n    RNG rngGroup = RNG::Init(Gid, g_frame.FrameNum, 1);\n\n    const uint3 state = RNG::PCG3d(uint3(DTid, g_frame.FrameNum));\n    // Only used for BSDF sampling\n    RNG rngReplay = RNG::Init(state.x);\n    // For anything else\n    RNG rngThread = RNG::Init(state.y);\n\n    Globals globals = InitGlobals(surface.specTr);\n    BSDF::BSDFSample bsdfSample = BSDF::SampleBSDF(normal, surface, rngReplay);\n    if(dot(bsdfSample.bsdfOverPdf, bsdfSample.bsdfOverPdf) == 0)\n    {\n        li = 0;\n        return RPT_Util::Reservoir::Init();\n    }\n\n    GBUFFER_TRI_DIFF_GEO_A g_triA = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::TRI_DIFF_GEO_A];\n    GBUFFER_TRI_DIFF_GEO_B g_triB = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::TRI_DIFF_GEO_B];\n    const uint4 packed_a = g_triA[DTid];\n    const uint2 packed_b = g_triB[DTid];\n\n    Math::TriDifferentials triDiffs = Math::TriDifferentials::Unpack(packed_a, packed_b);\n    float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n\n    RT::RayDifferentials rd = RT::RayDifferentials::Init(DTid, renderDim, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, \n        g_frame.CurrView[2].xyz, g_frame.DoF, g_frame.FocusDepth, \n        lensSample, origin);\n\n    float3 dpdx;\n    float3 dpdy;\n    rd.dpdx_dpdy(pos, normal, dpdx, dpdy);\n    rd.ComputeUVDifferentials(dpdx, dpdy, triDiffs.dpdu, triDiffs.dpdv);\n\n    rd.UpdateRays(pos, normal, bsdfSample.wi, surface.wo, triDiffs, \n        dpdx, dpdy, dot(bsdfSample.wi, normal) < 0, surface.eta);\n\n    // Use the same sample set for all threads in this group\n    const uint sampleSetIdx = NEE_EMISSIVE == 1 ? \n        rngGroup.UniformUintBounded_Faster(g_local.SampleSetSize_NumSampleSets >> 16) : \n        0;\n\n    RPT_Util::Reservoir r = PathTrace(pos, normal, ior, surface, sampleSetIdx, \n        bsdfSample, rd, globals, rngReplay, rngThread, rngGroup, li);\n\n    // Remember RNG seed for replay\n    r.rc.seed_replay = state.x;\n\n    return r;\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(RESTIR_PT_PATH_TRACE_GROUP_DIM_X, RESTIR_PT_PATH_TRACE_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID)\n{\n#if THREAD_GROUP_SWIZZLING == 1\n    uint2 swizzledGid;\n    const uint2 swizzledDTid = Common::SwizzleThreadGroup(DTid, Gid, GTid, \n        uint2(RESTIR_PT_PATH_TRACE_GROUP_DIM_X, RESTIR_PT_PATH_TRACE_GROUP_DIM_Y),\n        g_local.DispatchDimX_NumGroupsInTile & 0xffff, \n        RESTIR_PT_TILE_WIDTH, \n        RESTIR_PT_LOG2_TILE_WIDTH,\n        g_local.DispatchDimX_NumGroupsInTile >> 16,\n        swizzledGid);\n#else\n    const uint2 swizzledDTid = DTid.xy;\n    const uint2 swizzledGid = Gid.xy;\n#endif\n\n    if (swizzledDTid.x >= g_frame.RenderWidth || swizzledDTid.y >= g_frame.RenderHeight)\n        return;\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr = g_metallicRoughness[swizzledDTid];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n    \n    RWTexture2D<float4> g_final = ResourceDescriptorHeap[g_local.Final];\n\n    if (flags.invalid || flags.emissive)\n    {\n        if(!g_frame.Accumulate || !g_frame.CameraStatic)\n            g_final[swizzledDTid].rgb = 0;\n    \n        return;\n    }\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float z_view = g_depth[swizzledDTid];\n\n    // Use the same lens sample that was used for this pixel's camera ray\n    float2 lensSample = 0;\n    float3 origin = g_frame.CameraPos;\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(swizzledDTid.xyx).zy, g_frame.FrameNum);\n        lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample *= g_frame.LensRadius;\n    }\n\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float3 pos = Math::WorldPosFromScreenSpace2(swizzledDTid, renderDim, z_view, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n        g_frame.DoF, lensSample, g_frame.FocusDepth, origin);\n\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_normal[swizzledDTid]);\n\n    GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n    const float4 baseColor = flags.subsurface ? g_baseColor[swizzledDTid] :\n        float4(g_baseColor[swizzledDTid].rgb, 0);\n\n    float eta_curr = ETA_AIR;\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(flags.transmissive)\n    {\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        float ior = g_ior[swizzledDTid];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    float coat_weight = 0;\n    float3 coat_color = 0.0f;\n    float coat_roughness = 0;\n    float coat_ior = DEFAULT_ETA_COAT;\n\n    if(flags.coated)\n    {\n        GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::COAT];\n        uint3 packed = g_coat[swizzledDTid].xyz;\n\n        GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n        coat_weight = coat.weight;\n        coat_color = coat.color;\n        coat_roughness = coat.roughness;\n        coat_ior = coat.ior;\n    }\n\n    const float3 wo = normalize(origin - pos);\n    BSDF::ShadingData surface = BSDF::ShadingData::Init(normal, wo, flags.metallic, mr.y, \n        baseColor.xyz, eta_curr, eta_next, flags.transmissive, flags.trDepthGt0, (half)baseColor.w,\n        coat_weight, coat_color, coat_roughness, coat_ior);\n\n    float3 li;\n    RPT_Util::Reservoir r = RIS_InitialCandidates(swizzledDTid, swizzledGid, origin, lensSample,\n        pos, normal, eta_next, surface, li);\n\n    // Since p_source = 1, weight = |target|\n    float targetLum = Math::Luminance(r.target);\n    // We have:\n    //      w_sum = \\sum m_1 f_1 / p_1 + ... + m_n f_n / p_n\n    //      W = w_sum / (m_z f_z / p_z) with z \\in {1, ..., n}.\n    // Given above, W must be >= 1, but due to round-off errors, it\n    // could become < 1.\n    r.W = targetLum > 0 ? max(r.w_sum / targetLum, 1.0f) : 0;\n\n    if(IS_CB_FLAG_SET(CB_IND_FLAGS::TEMPORAL_RESAMPLE) || \n        IS_CB_FLAG_SET(CB_IND_FLAGS::RESET_TEMPORAL_TEXTURES))\n    {\n        r.Write<NEE_EMISSIVE>(swizzledDTid, g_local.Reservoir_A_DescHeapIdx, \n            g_local.Reservoir_A_DescHeapIdx + 1, g_local.Reservoir_A_DescHeapIdx + 2, \n            g_local.Reservoir_A_DescHeapIdx + 3, g_local.Reservoir_A_DescHeapIdx + 4,\n            g_local.Reservoir_A_DescHeapIdx + 5, g_local.Reservoir_A_DescHeapIdx + 6);\n    }\n\n    if(IS_CB_FLAG_SET(CB_IND_FLAGS::TEMPORAL_RESAMPLE))\n        r.WriteTarget(swizzledDTid, g_local.TargetDescHeapIdx);\n    else\n    {\n        RPT_Util::DebugColor(r.rc, g_local.Packed, li);\n        li = any(isnan(li)) ? 0 : li;\n\n        if(g_frame.Accumulate && g_frame.CameraStatic)\n        {\n            float3 prev = g_final[swizzledDTid].rgb;\n            g_final[swizzledDTid].rgb = prev + li;\n        }\n        else\n            g_final[swizzledDTid].rgb = li;\n    }\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/ReSTIR_PT_Reconnect_CtS.hlsl",
    "content": "#ifndef NEE_EMISSIVE\n#define NEE_EMISSIVE 0\n#endif\n\n#include \"../../Common/Common.hlsli\"\n#include \"Util.hlsli\"\n\n#define THREAD_GROUP_SWIZZLING 1\n\nusing namespace ReSTIR_Util;\nusing namespace RPT_Util;\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_ReSTIR_PT_Reuse> g_local : register(b1);\nRaytracingAccelerationStructure g_bvh : register(t0);\nStructuredBuffer<RT::MeshInstance> g_frameMeshData : register(t1);\nStructuredBuffer<Vertex> g_vertices : register(t2);\nStructuredBuffer<uint> g_indices : register(t3);\nStructuredBuffer<Material> g_materials : register(t4);\n\n//--------------------------------------------------------------------------------------\n// Utility Functions\n//--------------------------------------------------------------------------------------\n\nReSTIR_Util::Globals InitGlobals(bool transmissive)\n{\n    ReSTIR_Util::Globals globals;\n    globals.bvh = g_bvh;\n    globals.frameMeshData = g_frameMeshData;\n    globals.vertices = g_vertices;\n    globals.indices = g_indices;\n    globals.materials = g_materials;\n    uint maxNonTrBounces = g_local.Packed & 0xf;\n    uint maxGlossyTrBounces = (g_local.Packed >> PACKED_INDEX::NUM_GLOSSY_BOUNCES) & 0xf;\n    globals.maxNumBounces = transmissive ? (uint16_t)maxGlossyTrBounces :\n        (uint16_t)maxNonTrBounces;\n\n    return globals;\n}\n\n// Shift base path in current pixel's domain to offset path in spatial pixel's domain\nOffsetPath ShiftCurrentToSpatial(uint2 DTid, uint2 samplePosSS, Reconnection rc_curr,\n    Globals globals)\n{\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    GBUFFER_METALLIC_ROUGHNESS g_mr = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n    GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::IOR];\n\n    const float depth_n = g_depth[samplePosSS];\n\n    float2 lensSample_n = 0;\n    float3 origin_n = g_frame.CameraPos;\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(samplePosSS.xyx).zy, g_frame.FrameNum);\n        lensSample_n = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample_n *= g_frame.LensRadius;\n    }\n\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float3 pos_n = Math::WorldPosFromScreenSpace2(samplePosSS, renderDim, depth_n, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n        g_frame.DoF, lensSample_n, g_frame.FocusDepth, origin_n);\n\n    const float2 mr_n = g_mr[samplePosSS];\n    GBuffer::Flags flags_n = GBuffer::DecodeMetallic(mr_n.x);\n\n    float3 normal_n = Math::DecodeUnitVector(g_normal[samplePosSS]);\n    float4 baseColor_n = flags_n.subsurface ? g_baseColor[samplePosSS] : \n        float4(g_baseColor[samplePosSS].rgb, 0);\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(flags_n.transmissive)\n    {\n        float ior = g_ior[samplePosSS];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    float coat_weight = 0;\n    float3 coat_color = 0.0f;\n    float coat_roughness = 0;\n    float coat_ior = DEFAULT_ETA_COAT;\n\n    if(flags_n.coated)\n    {\n        GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::COAT];\n        uint3 packed = g_coat[DTid.xy].xyz;\n\n        GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n        coat_weight = coat.weight;\n        coat_color = coat.color;\n        coat_roughness = coat.roughness;\n        coat_ior = coat.ior;\n    }\n\n    const float3 wo_n = normalize(origin_n - pos_n);\n    BSDF::ShadingData surface_n = BSDF::ShadingData::Init(normal_n, wo_n, flags_n.metallic, \n        mr_n.y, baseColor_n.rgb, ETA_AIR, eta_next, flags_n.transmissive, flags_n.trDepthGt0,\n        (half)baseColor_n.a, coat_weight, coat_color, coat_roughness, coat_ior);\n\n    Math::TriDifferentials triDiffs;\n    RT::RayDifferentials rd;\n\n    if(rc_curr.k == 2)\n    {\n        GBUFFER_TRI_DIFF_GEO_A g_triA = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::TRI_DIFF_GEO_A];\n        GBUFFER_TRI_DIFF_GEO_B g_triB = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::TRI_DIFF_GEO_B];\n        const uint4 packed_a = g_triA[samplePosSS];\n        const uint2 packed_b = g_triB[samplePosSS];\n\n        triDiffs = Math::TriDifferentials::Unpack(packed_a, packed_b);\n        float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n\n        rd = RT::RayDifferentials::Init(samplePosSS, renderDim, g_frame.TanHalfFOV, \n            g_frame.AspectRatio, g_frame.CurrCameraJitter, \n            g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, \n            g_frame.CurrView[2].xyz, g_frame.DoF, g_frame.FocusDepth, \n            lensSample_n, origin_n);\n    }\n\n    bool regularization = IS_CB_FLAG_SET(CB_IND_FLAGS::PATH_REGULARIZATION);\n\n    return RPT_Util::Shift2<NEE_EMISSIVE, true>(DTid, pos_n, normal_n, eta_next, surface_n, \n        rd, triDiffs, rc_curr, g_local.RBufferA_CtN_DescHeapIdx, \n        g_local.RBufferA_CtN_DescHeapIdx + 1, g_local.RBufferA_CtN_DescHeapIdx + 2, \n        g_local.RBufferA_CtN_DescHeapIdx + 3, g_local.Alpha_min, regularization, \n        g_frame, globals);\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(RESTIR_PT_SPATIAL_GROUP_DIM_X, RESTIR_PT_SPATIAL_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID)\n{\n#if THREAD_GROUP_SWIZZLING == 1\n    uint2 swizzledGid;\n\n    uint2 swizzledDTid = Common::SwizzleThreadGroup(DTid, Gid, GTid, \n        uint2(RESTIR_PT_SPATIAL_GROUP_DIM_X, RESTIR_PT_SPATIAL_GROUP_DIM_Y),\n        g_local.DispatchDimX_NumGroupsInTile & 0xffff, \n        RESTIR_PT_TILE_WIDTH, \n        RESTIR_PT_LOG2_TILE_WIDTH, \n        g_local.DispatchDimX_NumGroupsInTile >> 16,\n        swizzledGid);\n#else\n    uint2 swizzledDTid = DTid.xy;\n    const uint2 swizzledGid = Gid.xy;\n#endif\n\n    if (swizzledDTid.x >= g_frame.RenderWidth || swizzledDTid.y >= g_frame.RenderHeight)\n        return;\n\n    if(IS_CB_FLAG_SET(CB_IND_FLAGS::SORT_SPATIAL))\n    {\n        bool error;\n        swizzledDTid = RPT_Util::DecodeSorted(swizzledDTid, g_local.ThreadMap_CtN_DescHeapIdx, error);\n\n        if(error)\n            return;\n    }\n\n    Texture2D<uint2> g_neighbor = ResourceDescriptorHeap[g_local.SpatialNeighborHeapIdx];\n    int2 samplePos = (int2)g_neighbor[swizzledDTid];\n\n    if(samplePos.x == UINT8_MAX)\n        return;\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr = g_metallicRoughness[swizzledDTid];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n\n    if (flags.invalid || flags.emissive)\n        return;\n\n    samplePos -= RPT_Util::SPATIAL_NEIGHBOR_OFFSET;\n    samplePos += swizzledDTid;\n\n    Reservoir r_curr = Reservoir::Load_NonReconnection<Texture2D<uint4>, \n        Texture2D<float2> >(swizzledDTid, g_local.Reservoir_A_DescHeapIdx, \n        g_local.Reservoir_A_DescHeapIdx + 1);\n    Reservoir r_spatial = Reservoir::Load_Metadata<Texture2D<uint4> >(\n        samplePos, g_local.Reservoir_A_DescHeapIdx);\n\n    // Shift current reservoir's path to spatial pixel and resample\n    if((r_curr.w_sum != 0) && !r_curr.rc.Empty())\n    {\n        r_curr.Load_Reconnection<NEE_EMISSIVE, Texture2D<uint4>, Texture2D<uint4>, \n            Texture2D<half>, Texture2D<float2>, Texture2D<uint2> >(swizzledDTid, \n            g_local.Reservoir_A_DescHeapIdx + 2, \n            g_local.Reservoir_A_DescHeapIdx + 3,\n            g_local.Reservoir_A_DescHeapIdx + 4,\n            g_local.Reservoir_A_DescHeapIdx + 5,\n            g_local.Reservoir_A_DescHeapIdx + 6);\n\n        Globals globals = InitGlobals(flags.transmissive);\n        OffsetPath shift = ShiftCurrentToSpatial(swizzledDTid, samplePos, r_curr.rc, globals);\n        float target_spatial = Math::Luminance(shift.target);\n\n        if(target_spatial > 0)\n        {\n            float targetLum_curr = r_curr.W > 0 ? r_curr.w_sum / r_curr.W : 0;\n            float jacobian = r_curr.rc.partialJacobian > 0 ? \n                shift.partialJacobian / r_curr.rc.partialJacobian : 0;\n            float numerator = r_curr.M * targetLum_curr;\n            float denom = numerator + r_spatial.M * target_spatial * jacobian;\n            float m_curr = denom > 0 ? numerator / denom : 0;\n            r_curr.w_sum *= m_curr;\n        }\n\n        r_curr.WriteWSum(swizzledDTid, g_local.PrevReservoir_A_DescHeapIdx + 1);\n    }\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/ReSTIR_PT_Reconnect_CtT.hlsl",
    "content": "#ifndef NEE_EMISSIVE\n#define NEE_EMISSIVE 0\n#endif\n\n#include \"../../Common/Common.hlsli\"\n#include \"Util.hlsli\"\n\n#define THREAD_GROUP_SWIZZLING 1\n\nusing namespace ReSTIR_Util;\nusing namespace RPT_Util;\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_ReSTIR_PT_Reuse> g_local : register(b1);\nRaytracingAccelerationStructure g_bvh : register(t0);\nStructuredBuffer<RT::MeshInstance> g_frameMeshData : register(t1);\nStructuredBuffer<Vertex> g_vertices : register(t2);\nStructuredBuffer<uint> g_indices : register(t3);\nStructuredBuffer<Material> g_materials : register(t4);\n\n//--------------------------------------------------------------------------------------\n// Utility Functions\n//--------------------------------------------------------------------------------------\n\nReSTIR_Util::Globals InitGlobals(bool transmissive)\n{\n    ReSTIR_Util::Globals globals;\n    globals.bvh = g_bvh;\n    globals.frameMeshData = g_frameMeshData;\n    globals.vertices = g_vertices;\n    globals.indices = g_indices;\n    globals.materials = g_materials;\n    uint maxNonTrBounces = g_local.Packed & 0xf;\n    uint maxGlossyTrBounces = (g_local.Packed >> PACKED_INDEX::NUM_GLOSSY_BOUNCES) & 0xf;\n    globals.maxNumBounces = transmissive ? (uint16_t)maxGlossyTrBounces :\n        (uint16_t)maxNonTrBounces;\n\n    return globals;\n}\n\n// Shift base path in current pixel's domain to offset path in temporal domain\nOffsetPath ShiftCurrentToTemporal(uint2 DTid, uint2 prevPosSS, float3 origin,\n    float2 lensSample, float3 prevPos, GBuffer::Flags prevFlags, float prevRoughness,\n    Reconnection rc_curr, Globals globals)\n{\n    float eta_curr = ETA_AIR;\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(prevFlags.transmissive)\n    {\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        float ior = g_ior[prevPosSS];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    GBUFFER_NORMAL g_prevNormal = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_prevNormal[prevPosSS]);\n\n    GBUFFER_BASE_COLOR g_prevBaseColor = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n    const float4 baseColor = prevFlags.subsurface ? g_prevBaseColor[prevPosSS] :\n        float4(g_prevBaseColor[prevPosSS].rgb, 0);\n\n    float coat_weight = 0;\n    float3 coat_color = 0.0f;\n    float coat_roughness = 0;\n    float coat_ior = DEFAULT_ETA_COAT;\n\n    if(prevFlags.coated)\n    {\n        GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n            GBUFFER_OFFSET::COAT];\n        uint3 packed = g_coat[DTid.xy].xyz;\n\n        GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n        coat_weight = coat.weight;\n        coat_color = coat.color;\n        coat_roughness = coat.roughness;\n        coat_ior = coat.ior;\n    }\n\n    const float3 wo = normalize(origin - prevPos);\n    BSDF::ShadingData surface = BSDF::ShadingData::Init(normal, wo, prevFlags.metallic, \n        prevRoughness, baseColor.rgb, eta_curr, eta_next, prevFlags.transmissive, \n        prevFlags.trDepthGt0, (half)baseColor.w, coat_weight, coat_color, \n        coat_roughness, coat_ior);\n\n    Math::TriDifferentials triDiffs;\n    RT::RayDifferentials rd;\n\n    if(rc_curr.k == 2)\n    {\n        GBUFFER_TRI_DIFF_GEO_A g_triA = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n            GBUFFER_OFFSET::TRI_DIFF_GEO_A];\n        GBUFFER_TRI_DIFF_GEO_B g_triB = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n            GBUFFER_OFFSET::TRI_DIFF_GEO_B];\n        const uint4 packed_a = g_triA[prevPosSS];\n        const uint2 packed_b = g_triB[prevPosSS];\n\n        triDiffs = Math::TriDifferentials::Unpack(packed_a, packed_b);\n        float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n\n        rd = RT::RayDifferentials::Init(prevPosSS, renderDim, g_frame.TanHalfFOV, \n            g_frame.AspectRatio, g_frame.PrevCameraJitter, \n            g_frame.PrevView[0].xyz, g_frame.PrevView[1].xyz, \n            g_frame.PrevView[2].xyz, g_frame.DoF, g_frame.FocusDepth, \n            lensSample, origin);\n    }\n\n    bool regularization = IS_CB_FLAG_SET(CB_IND_FLAGS::PATH_REGULARIZATION);\n\n    return RPT_Util::Shift2<NEE_EMISSIVE, false>(DTid, prevPos, normal, eta_next, surface, \n        rd, triDiffs, rc_curr, g_local.RBufferA_CtN_DescHeapIdx, \n        g_local.RBufferA_CtN_DescHeapIdx + 1, g_local.RBufferA_CtN_DescHeapIdx + 2, \n        g_local.RBufferA_CtN_DescHeapIdx + 3, g_local.Alpha_min, regularization, \n        g_frame, globals);\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(RESTIR_PT_TEMPORAL_GROUP_DIM_X, RESTIR_PT_TEMPORAL_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID)\n{\n#if THREAD_GROUP_SWIZZLING == 1\n    uint2 swizzledGid;\n\n    uint2 swizzledDTid = Common::SwizzleThreadGroup(DTid, Gid, GTid, \n        uint2(RESTIR_PT_TEMPORAL_GROUP_DIM_X, RESTIR_PT_TEMPORAL_GROUP_DIM_Y),\n        g_local.DispatchDimX_NumGroupsInTile & 0xffff, \n        RESTIR_PT_TILE_WIDTH, \n        RESTIR_PT_LOG2_TILE_WIDTH, \n        g_local.DispatchDimX_NumGroupsInTile >> 16,\n        swizzledGid);\n#else\n    uint2 swizzledDTid = DTid.xy;\n    const uint2 swizzledGid = Gid.xy;\n#endif\n    \n    if (swizzledDTid.x >= g_frame.RenderWidth || swizzledDTid.y >= g_frame.RenderHeight)\n        return;\n\n    if(IS_CB_FLAG_SET(CB_IND_FLAGS::SORT_TEMPORAL))\n    {\n        bool error;\n        swizzledDTid = RPT_Util::DecodeSorted(swizzledDTid, g_local.ThreadMap_CtN_DescHeapIdx, error);\n\n        if(error)\n            return;\n    }\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr = g_metallicRoughness[swizzledDTid];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n\n    if (flags.invalid || flags.emissive)\n        return;\n\n    GBUFFER_MOTION_VECTOR g_motionVector = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::MOTION_VECTOR];\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float2 motionVec = g_motionVector[swizzledDTid];\n    const float2 currUV = (swizzledDTid + 0.5f) / renderDim;\n    const float2 prevUV = currUV - motionVec;\n    int2 prevPixel = prevUV * renderDim;\n\n    // No temporal history\n    if (any(prevUV < 0.0f.xx) || any(prevUV > 1.0f.xx))\n        return;\n\n    // Prepare previous pixel's geometry and material data\n    GBUFFER_DEPTH g_prevDepth = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float prevViewDepth = g_prevDepth[prevPixel];\n\n    // No temporal history\n    if(prevViewDepth == FLT_MAX)\n        return;\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float z_view = g_depth[swizzledDTid];\n\n    float2 lensSample = 0;\n    float3 origin = g_frame.CameraPos;\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(swizzledDTid.xyx).zy, g_frame.FrameNum);\n        lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample *= g_frame.LensRadius;\n    }\n\n    const float3 pos = Math::WorldPosFromScreenSpace2(swizzledDTid, renderDim, z_view, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n        g_frame.DoF, lensSample, g_frame.FocusDepth, origin);\n\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_normal[swizzledDTid]);\n\n    float2 lensSample_t = 0;\n    float3 origin_t = float3(g_frame.PrevViewInv._m03, g_frame.PrevViewInv._m13, \n        g_frame.PrevViewInv._m23);\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(prevPixel.xyx).zy, g_frame.FrameNum - 1);\n        lensSample_t = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample_t *= g_frame.LensRadius;\n    }\n\n    const float3 prevPos = Math::WorldPosFromScreenSpace2(prevPixel, renderDim, prevViewDepth, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.PrevCameraJitter, \n        g_frame.PrevView[0].xyz, g_frame.PrevView[1].xyz, g_frame.PrevView[2].xyz, \n        g_frame.DoF, lensSample_t, g_frame.FocusDepth, origin_t);\n\n    // No temporal history\n    if(!RPT_Util::PlaneHeuristic(prevPos, normal, pos, z_view, MAX_PLANE_DIST_REUSE))\n        return;\n\n    GBUFFER_METALLIC_ROUGHNESS g_prevMR = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 prevMR = g_prevMR[prevPixel];\n    GBuffer::Flags prevFlags = GBuffer::DecodeMetallic(prevMR.x);\n\n    // No temporal history\n    if(prevFlags.emissive || \n        (abs(prevMR.y - mr.y) > MAX_ROUGHNESS_DIFF_TEMPORAL_REUSE) || \n        (prevFlags.transmissive != flags.transmissive))\n        return;\n\n    Reservoir r_curr = Reservoir::Load_NonReconnection<RWTexture2D<uint4>, \n        RWTexture2D<float2> >(swizzledDTid, g_local.Reservoir_A_DescHeapIdx, \n        g_local.Reservoir_A_DescHeapIdx + 1);\n    Reservoir r_prev = Reservoir::Load_Metadata<Texture2D<uint4> >(\n        prevPixel, g_local.PrevReservoir_A_DescHeapIdx);\n\n    // Shift current reservoir's path to previous pixel and resample\n    if(r_curr.w_sum != 0 && r_prev.M > 0 && !r_curr.rc.Empty())\n    {\n        r_curr.Load_Reconnection<NEE_EMISSIVE, RWTexture2D<uint4>, RWTexture2D<uint4>, \n            RWTexture2D<half>, RWTexture2D<float2>, RWTexture2D<uint2> >(swizzledDTid, \n            g_local.Reservoir_A_DescHeapIdx + 2, \n            g_local.Reservoir_A_DescHeapIdx + 3,\n            g_local.Reservoir_A_DescHeapIdx + 4,\n            g_local.Reservoir_A_DescHeapIdx + 5,\n            g_local.Reservoir_A_DescHeapIdx + 6);\n\n        if(r_curr.rc.IsCase1() || r_curr.rc.IsCase2())\n        {\n            const RT::MeshInstance meshData = g_frameMeshData[NonUniformResourceIndex(r_curr.rc.meshIdx)];\n            float4 q_curr = Math::DecodeNormalized4(meshData.Rotation);\n            q_curr = normalize(q_curr);\n            float3 x_local = Math::InverseTransformTRS(r_curr.rc.x_k, meshData.Translation, \n                q_curr, meshData.Scale);\n\n            float3 prevTranslation = meshData.Translation - meshData.dTranslation;\n            float4 q_prev = Math::DecodeNormalized4(meshData.PrevRotation);\n            q_prev = normalize(q_prev);\n\n            r_curr.rc.x_k = Math::TransformTRS(x_local, prevTranslation, q_prev, \n                meshData.PrevScale);\n        }\n\n        Globals globals = InitGlobals(flags.transmissive);\n        OffsetPath shift = ShiftCurrentToTemporal(swizzledDTid, prevPixel, origin_t, \n            lensSample_t, prevPos, prevFlags, prevMR.y, r_curr.rc, globals);\n        float target_prev = Math::Luminance(shift.target);\n\n        // When target_prev = 0, ris weight works out to be existing w_sum, so\n        // write to memory can be skipped\n        if(target_prev > 0)\n        {\n            float targetLum_curr = r_curr.W > 0 ? r_curr.w_sum / r_curr.W : 0;\n            float jacobian = r_curr.rc.partialJacobian > 0 ? \n                shift.partialJacobian / r_curr.rc.partialJacobian : 0;\n            float m_curr = targetLum_curr / (targetLum_curr + r_prev.M * target_prev * jacobian);\n            r_curr.w_sum *= m_curr;\n\n            r_curr.WriteWSum(swizzledDTid, g_local.Reservoir_A_DescHeapIdx + 1);\n        }\n    }\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/ReSTIR_PT_Reconnect_StC.hlsl",
    "content": "#ifndef NEE_EMISSIVE\n#define NEE_EMISSIVE 0\n#endif\n\n#include \"../../Common/Common.hlsli\"\n#include \"Util.hlsli\"\n\n#define THREAD_GROUP_SWIZZLING 1\n\nusing namespace ReSTIR_Util;\nusing namespace RPT_Util;\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_ReSTIR_PT_Reuse> g_local : register(b1);\nRaytracingAccelerationStructure g_bvh : register(t0);\nStructuredBuffer<RT::MeshInstance> g_frameMeshData : register(t1);\nStructuredBuffer<Vertex> g_vertices : register(t2);\nStructuredBuffer<uint> g_indices : register(t3);\nStructuredBuffer<Material> g_materials : register(t4);\n\n//--------------------------------------------------------------------------------------\n// Utility Functions\n//--------------------------------------------------------------------------------------\n\nReSTIR_Util::Globals InitGlobals(bool transmissive)\n{\n    ReSTIR_Util::Globals globals;\n    globals.bvh = g_bvh;\n    globals.frameMeshData = g_frameMeshData;\n    globals.vertices = g_vertices;\n    globals.indices = g_indices;\n    globals.materials = g_materials;\n    uint maxNonTrBounces = g_local.Packed & 0xf;\n    uint maxGlossyTrBounces = (g_local.Packed >> PACKED_INDEX::NUM_GLOSSY_BOUNCES) & 0xf;\n    globals.maxNumBounces = transmissive ? (uint16_t)maxGlossyTrBounces :\n        (uint16_t)maxNonTrBounces;\n\n    return globals;\n}\n\n// Shift base path in spatial domain to offset path in current pixel's domain\nOffsetPath ShiftSpatialToCurrent(uint2 DTid, float3 origin, float2 lensSample, \n    float3 pos, float3 normal, float eta_next, BSDF::ShadingData surface, \n    Reconnection rc_spatial, Globals globals)\n{\n    Math::TriDifferentials triDiffs;\n    RT::RayDifferentials rd;\n\n    if(rc_spatial.k == 2)\n    {\n        GBUFFER_TRI_DIFF_GEO_A g_triA = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::TRI_DIFF_GEO_A];\n        GBUFFER_TRI_DIFF_GEO_B g_triB = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::TRI_DIFF_GEO_B];\n        const uint4 packed_a = g_triA[DTid];\n        const uint2 packed_b = g_triB[DTid];\n\n        triDiffs = Math::TriDifferentials::Unpack(packed_a, packed_b);\n        float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n\n        rd = RT::RayDifferentials::Init(DTid, renderDim, g_frame.TanHalfFOV, \n            g_frame.AspectRatio, g_frame.CurrCameraJitter, \n            g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, \n            g_frame.CurrView[2].xyz, g_frame.DoF, g_frame.FocusDepth,\n            lensSample, origin);\n    }\n\n    bool regularization = IS_CB_FLAG_SET(CB_IND_FLAGS::PATH_REGULARIZATION);\n\n    return RPT_Util::Shift2<NEE_EMISSIVE, true>(DTid, pos, normal, eta_next, surface, rd, \n        triDiffs, rc_spatial, g_local.RBufferA_NtC_DescHeapIdx, \n        g_local.RBufferA_NtC_DescHeapIdx + 1, g_local.RBufferA_NtC_DescHeapIdx + 2, \n        g_local.RBufferA_NtC_DescHeapIdx + 3, g_local.Alpha_min, regularization, \n        g_frame, globals);\n}\n\n// Copies reservoir data along with the reconnection found after temporal reuse (if any)\n// to next frame's reservoir\nvoid CopyToNextFrame(uint2 DTid, Reservoir r_curr, uint M_max)\n{\n    if(!r_curr.rc.Empty())\n    {\n        r_curr.Load_Reconnection<NEE_EMISSIVE, Texture2D<uint4>, Texture2D<uint4>, \n            Texture2D<half>, Texture2D<float2>, Texture2D<uint2> >(DTid, \n            g_local.Reservoir_A_DescHeapIdx + 2, \n            g_local.Reservoir_A_DescHeapIdx + 3,\n            g_local.Reservoir_A_DescHeapIdx + 4,\n            g_local.Reservoir_A_DescHeapIdx + 5,\n            g_local.Reservoir_A_DescHeapIdx + 6);\n\n        r_curr.Write<NEE_EMISSIVE>(DTid, g_local.PrevReservoir_A_DescHeapIdx,\n            g_local.PrevReservoir_A_DescHeapIdx + 1, g_local.PrevReservoir_A_DescHeapIdx + 2, \n            g_local.PrevReservoir_A_DescHeapIdx + 3, g_local.PrevReservoir_A_DescHeapIdx + 4, \n            g_local.PrevReservoir_A_DescHeapIdx + 5, g_local.PrevReservoir_A_DescHeapIdx + 6,\n            M_max);\n    }\n    else\n    {\n        r_curr.WriteReservoirData(DTid, g_local.PrevReservoir_A_DescHeapIdx,\n            g_local.PrevReservoir_A_DescHeapIdx + 1, M_max);\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(RESTIR_PT_SPATIAL_GROUP_DIM_X, RESTIR_PT_SPATIAL_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID)\n{\n#if THREAD_GROUP_SWIZZLING == 1\n    uint2 swizzledGid;\n\n    uint2 swizzledDTid = Common::SwizzleThreadGroup(DTid, Gid, GTid, \n        uint2(RESTIR_PT_SPATIAL_GROUP_DIM_X, RESTIR_PT_SPATIAL_GROUP_DIM_Y),\n        g_local.DispatchDimX_NumGroupsInTile & 0xffff, \n        RESTIR_PT_TILE_WIDTH, \n        RESTIR_PT_LOG2_TILE_WIDTH, \n        g_local.DispatchDimX_NumGroupsInTile >> 16,\n        swizzledGid);\n#else\n    uint2 swizzledDTid = DTid.xy;\n    const uint2 swizzledGid = Gid.xy;\n#endif\n\n    if (swizzledDTid.x >= g_frame.RenderWidth || swizzledDTid.y >= g_frame.RenderHeight)\n        return;\n\n    if(IS_CB_FLAG_SET(CB_IND_FLAGS::SORT_SPATIAL))\n    {\n        bool error;\n        swizzledDTid = RPT_Util::DecodeSorted(swizzledDTid, g_local.ThreadMap_NtC_DescHeapIdx, error);\n\n        if(error)\n            return;\n    }\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[\n        g_frame.CurrGBufferDescHeapOffset + GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr = g_metallicRoughness[swizzledDTid];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n\n    if (flags.invalid || flags.emissive)\n        return;\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float z_view = g_depth[swizzledDTid];\n\n    // Use the same lens sample that was used for this pixel's camera ray\n    float2 lensSample = 0;\n    float3 origin = g_frame.CameraPos;\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(swizzledDTid.xyx).zy, g_frame.FrameNum);\n        lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample *= g_frame.LensRadius;\n    }\n\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float3 pos = Math::WorldPosFromScreenSpace2(swizzledDTid, renderDim, z_view, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n        g_frame.DoF, lensSample, g_frame.FocusDepth, origin);\n\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_normal[swizzledDTid]);\n\n    GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n    const float4 baseColor = flags.subsurface ? g_baseColor[swizzledDTid] : \n        float4(g_baseColor[swizzledDTid].rgb, 0);\n\n    float eta_curr = ETA_AIR;\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(flags.transmissive)\n    {\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        float ior = g_ior[swizzledDTid];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    float coat_weight = 0;\n    float3 coat_color = 0.0f;\n    float coat_roughness = 0;\n    float coat_ior = DEFAULT_ETA_COAT;\n\n    if(flags.coated)\n    {\n        GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::COAT];\n        uint3 packed = g_coat[swizzledDTid].xyz;\n\n        GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n        coat_weight = coat.weight;\n        coat_color = coat.color;\n        coat_roughness = coat.roughness;\n        coat_ior = coat.ior;\n    }\n\n    const float3 wo = normalize(origin - pos);\n    BSDF::ShadingData surface = BSDF::ShadingData::Init(normal, wo, flags.metallic, \n        mr.y, baseColor.rgb, eta_curr, eta_next, flags.transmissive, flags.trDepthGt0, \n        (half)baseColor.a, coat_weight, coat_color, coat_roughness, coat_ior);\n\n    Reservoir r_curr = Reservoir::Load_NonReconnection<Texture2D<uint4>, Texture2D<float2> >(\n        swizzledDTid, g_local.Reservoir_A_DescHeapIdx, g_local.Reservoir_A_DescHeapIdx + 1);\n    r_curr.LoadTarget(swizzledDTid, g_local.TargetDescHeapIdx);\n\n    Texture2D<uint2> g_neighbor = ResourceDescriptorHeap[g_local.SpatialNeighborHeapIdx];\n    int2 samplePos = (int2)g_neighbor[swizzledDTid];\n\n    float waveSum = WaveActiveSum(r_curr.w_sum);\n    float waveAvgExclusive = (waveSum - r_curr.w_sum) / WaveGetLaneCount();\n    waveSum = WaveActiveSum(r_curr.w_sum * (samplePos.x == UINT8_MAX));\n\n    uint M_max = (g_local.Packed >> PACKED_INDEX::MAX_SPATIAL_M) & 0xf;\n    M_max = !r_curr.rc.Empty() && r_curr.rc.lobe_k_min_1 == BSDF::LOBE::GLOSSY_T ? \n        min(M_max, M_MAX_X_K_TRANSMISSIVE) : M_max;\n\n    // Couldn't find reusable spatial neighbor\n    if(samplePos.x == UINT8_MAX)\n    {\n        if(IS_CB_FLAG_SET(CB_IND_FLAGS::BOILING_SUPPRESSION))\n            RPT_Util::SuppressOutlierReservoirs(waveAvgExclusive, r_curr);\n\n        RPT_Util::WriteOutputColor(swizzledDTid, r_curr.target * r_curr.W, \n            g_local.Packed, g_local.FinalDescHeapIdx, g_frame);\n        CopyToNextFrame(swizzledDTid, r_curr, M_max);\n\n        return;\n    }\n\n    samplePos -= RPT_Util::SPATIAL_NEIGHBOR_OFFSET;\n    samplePos += swizzledDTid;\n\n    Reservoir r_spatial = Reservoir::Load_NonReconnection<Texture2D<uint4>, \n        Texture2D<float2> >(samplePos, g_local.Reservoir_A_DescHeapIdx, \n        g_local.Reservoir_A_DescHeapIdx + 1);\n\n    if((r_curr.w_sum != 0) && (r_spatial.M > 0) && !r_curr.rc.Empty())\n        r_curr.LoadWSum(swizzledDTid, g_local.PrevReservoir_A_DescHeapIdx + 1);\n\n    Globals globals = InitGlobals(flags.transmissive);\n    const uint16_t M_new = r_curr.M + r_spatial.M;\n\n    waveSum += WaveActiveSum(r_curr.w_sum * r_spatial.rc.Empty());\n\n    // Spatial neighbor can't be shifted for reuse\n    if(r_spatial.rc.Empty())\n    {\n        if(IS_CB_FLAG_SET(CB_IND_FLAGS::BOILING_SUPPRESSION))\n            RPT_Util::SuppressOutlierReservoirs(waveAvgExclusive, r_curr);\n\n        // Recompute W as w_sum may have changed after the current to spatial shift\n        float targetLum = Math::Luminance(r_curr.target);\n        r_curr.W = targetLum > 0 ? r_curr.w_sum / targetLum : 0;\n        r_curr.M = M_new;\n\n        CopyToNextFrame(swizzledDTid, r_curr, M_max);\n        RPT_Util::WriteOutputColor(swizzledDTid, r_curr.target * r_curr.W,\n            g_local.Packed, g_local.FinalDescHeapIdx, g_frame);\n\n        return;\n    }\n\n    M_max = r_spatial.rc.x_k_in_motion ? min(M_max, M_MAX_X_K_IN_MOTION) : M_max;\n    r_spatial.rc.x_k_in_motion = false;\n\n    r_spatial.Load_Reconnection<NEE_EMISSIVE, Texture2D<uint4>, Texture2D<uint4>, \n        Texture2D<half>, Texture2D<float2>, Texture2D<uint2> >(samplePos, \n        g_local.Reservoir_A_DescHeapIdx + 2, \n        g_local.Reservoir_A_DescHeapIdx + 3,\n        g_local.Reservoir_A_DescHeapIdx + 4,\n        g_local.Reservoir_A_DescHeapIdx + 5,\n        g_local.Reservoir_A_DescHeapIdx + 6);\n\n    // Shift spatial neighbor's path to current pixel and resample\n    OffsetPath shift = ShiftSpatialToCurrent(swizzledDTid, origin, lensSample,\n        pos, normal, eta_next, surface, r_spatial.rc, globals);\n\n    float targetLum_curr = Math::Luminance(shift.target);\n    float targetLum_spatial = r_spatial.W > 0 ? r_spatial.w_sum / r_spatial.W : 0;\n    float jacobian = r_spatial.rc.partialJacobian > 0 ? \n        shift.partialJacobian / r_spatial.rc.partialJacobian : 0;\n\n    bool changed = false;\n\n    // RIS weight becomes zero when target = 0\n    if(targetLum_curr > 1e-6 && jacobian > 1e-5 && jacobian < 100)\n    {\n        RNG rng = RNG::Init(RNG::PCG3d(swizzledDTid.xyy).xz, g_frame.FrameNum + 511);\n\n        // Jacobian term in numerator cancels out with the same term in w_spatial\n        float numerator = r_spatial.M * targetLum_spatial;\n        float denom = numerator / jacobian + r_curr.M * targetLum_curr;\n        // Balance heuristic\n        float m_spatial = denom > 0 ? numerator / denom : 0;\n        float w_spatial = m_spatial * r_spatial.W * targetLum_curr;\n\n        if(r_curr.Update(w_spatial, shift.target, r_spatial.rc, rng))\n        {\n            r_curr.rc.partialJacobian = shift.partialJacobian;\n            changed = true;\n        }\n    }\n\n    float targetLum = Math::Luminance(r_curr.target);\n    r_curr.W = targetLum > 0 ? r_curr.w_sum / targetLum : 0;\n    r_curr.M = M_new;\n\n    if(IS_CB_FLAG_SET(CB_IND_FLAGS::BOILING_SUPPRESSION))\n    {\n        waveSum += WaveActiveSum(r_curr.w_sum);\n        waveAvgExclusive = (waveSum - r_curr.w_sum) / WaveGetLaneCount();\n        RPT_Util::SuppressOutlierReservoirs(waveAvgExclusive, r_curr);\n    }\n\n    // If reconnection didn't change, skip writing it\n    // const uint16 passIdx = uint16((g_local.Packed >> 12) & 0x3);\n    const uint16 numPasses = 1;\n    const uint16 passIdx = 0;\n    if(changed)\n    {\n        M_max = shift.surfKMin1Tramsmissive ? min(M_max, M_MAX_X_K_TRANSMISSIVE) : M_max;\n\n        r_curr.Write<NEE_EMISSIVE>(swizzledDTid, g_local.PrevReservoir_A_DescHeapIdx,\n            g_local.PrevReservoir_A_DescHeapIdx + 1, g_local.PrevReservoir_A_DescHeapIdx + 2, \n            g_local.PrevReservoir_A_DescHeapIdx + 3, g_local.PrevReservoir_A_DescHeapIdx + 4, \n            g_local.PrevReservoir_A_DescHeapIdx + 5, g_local.PrevReservoir_A_DescHeapIdx + 6, \n            M_max);\n\n        // Skip last pass\n        if(numPasses > 1 && (passIdx + 1 != numPasses))\n            r_curr.WriteTarget(swizzledDTid, g_local.TargetDescHeapIdx);\n    }\n    else\n        CopyToNextFrame(swizzledDTid, r_curr, M_max);\n\n    float3 li = r_curr.target * r_curr.W;\n    RPT_Util::DebugColor(r_curr.rc, g_local.Packed, li);\n    RPT_Util::WriteOutputColor(swizzledDTid, li, g_local.Packed, g_local.FinalDescHeapIdx,\n         g_frame, false);\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/ReSTIR_PT_Reconnect_TtC.hlsl",
    "content": "#ifndef NEE_EMISSIVE\n#define NEE_EMISSIVE 0\n#endif\n\n#include \"../../Common/Common.hlsli\"\n#include \"Util.hlsli\"\n\n#define THREAD_GROUP_SWIZZLING 1\n\nusing namespace ReSTIR_Util;\nusing namespace RPT_Util;\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_ReSTIR_PT_Reuse> g_local : register(b1);\nRaytracingAccelerationStructure g_bvh : register(t0);\nStructuredBuffer<RT::MeshInstance> g_frameMeshData : register(t1);\nStructuredBuffer<Vertex> g_vertices : register(t2);\nStructuredBuffer<uint> g_indices : register(t3);\nStructuredBuffer<Material> g_materials : register(t4);\n\n//--------------------------------------------------------------------------------------\n// Utility Functions\n//--------------------------------------------------------------------------------------\n\nGlobals InitGlobals(bool transmissive)\n{\n    Globals globals;\n    globals.bvh = g_bvh;\n    globals.frameMeshData = g_frameMeshData;\n    globals.vertices = g_vertices;\n    globals.indices = g_indices;\n    globals.materials = g_materials;\n    uint maxNonTrBounces = g_local.Packed & 0xf;\n    uint maxGlossyTrBounces = (g_local.Packed >> PACKED_INDEX::NUM_GLOSSY_BOUNCES) & 0xf;\n    globals.maxNumBounces = transmissive ? (uint16_t)maxGlossyTrBounces :\n        (uint16_t)maxNonTrBounces;\n\n    return globals;\n}\n\n// Shift base path in temporal domain to offset path in current pixel's domain\nOffsetPath ShiftTemporalToCurrent(uint2 DTid, float3 origin, float2 lensSample,\n    float3 pos, float3 normal, GBuffer::Flags flags, float roughness, Reconnection rc_prev, \n    Globals globals)\n{\n    GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n    const float4 baseColor = flags.subsurface ? g_baseColor[DTid] : \n        float4(g_baseColor[DTid].rgb, 0);\n\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(flags.transmissive)\n    {\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        float ior = g_ior[DTid];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    float coat_weight = 0;\n    float3 coat_color = 0.0f;\n    float coat_roughness = 0;\n    float coat_ior = DEFAULT_ETA_COAT;\n\n    if(flags.coated)\n    {\n        GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::COAT];\n        uint3 packed = g_coat[DTid].xyz;\n\n        GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n        coat_weight = coat.weight;\n        coat_color = coat.color;\n        coat_roughness = coat.roughness;\n        coat_ior = coat.ior;\n    }\n\n    const float3 wo = normalize(origin - pos);\n    BSDF::ShadingData surface = BSDF::ShadingData::Init(normal, wo, flags.metallic, \n        roughness, baseColor.rgb, ETA_AIR, eta_next, flags.transmissive, flags.trDepthGt0, \n        (half)baseColor.w, coat_weight, coat_color, coat_roughness, coat_ior);\n\n    Math::TriDifferentials triDiffs;\n    RT::RayDifferentials rd = RT::RayDifferentials::Init();\n\n    if(rc_prev.k == 2)\n    {\n        GBUFFER_TRI_DIFF_GEO_A g_triA = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::TRI_DIFF_GEO_A];\n        GBUFFER_TRI_DIFF_GEO_B g_triB = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n            GBUFFER_OFFSET::TRI_DIFF_GEO_B];\n        const uint4 packed_a = g_triA[DTid];\n        const uint2 packed_b = g_triB[DTid];\n\n        triDiffs = Math::TriDifferentials::Unpack(packed_a, packed_b);\n        float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n\n        rd = RT::RayDifferentials::Init(DTid, renderDim, g_frame.TanHalfFOV, \n            g_frame.AspectRatio, g_frame.CurrCameraJitter, \n            g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, \n            g_frame.CurrView[2].xyz, g_frame.DoF, g_frame.FocusDepth, \n            lensSample, origin);\n    }\n\n    bool regularization = IS_CB_FLAG_SET(CB_IND_FLAGS::PATH_REGULARIZATION);\n\n    return RPT_Util::Shift2<NEE_EMISSIVE, true>(DTid, pos, normal, eta_next, \n        surface, rd, triDiffs, rc_prev, g_local.RBufferA_NtC_DescHeapIdx, \n        g_local.RBufferA_NtC_DescHeapIdx + 1, g_local.RBufferA_NtC_DescHeapIdx + 2, \n        g_local.RBufferA_NtC_DescHeapIdx + 3, g_local.Alpha_min, regularization, \n        g_frame, globals);\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(RESTIR_PT_TEMPORAL_GROUP_DIM_X, RESTIR_PT_TEMPORAL_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID)\n{\n#if THREAD_GROUP_SWIZZLING == 1\n    uint2 swizzledGid;\n\n    uint2 swizzledDTid = Common::SwizzleThreadGroup(DTid, Gid, GTid, \n        uint2(RESTIR_PT_TEMPORAL_GROUP_DIM_X, RESTIR_PT_TEMPORAL_GROUP_DIM_Y),\n        g_local.DispatchDimX_NumGroupsInTile & 0xffff, \n        RESTIR_PT_TILE_WIDTH, \n        RESTIR_PT_LOG2_TILE_WIDTH, \n        g_local.DispatchDimX_NumGroupsInTile >> 16,\n        swizzledGid);\n#else\n    uint2 swizzledDTid = DTid.xy;\n    const uint2 swizzledGid = Gid.xy;\n#endif\n\n    if (swizzledDTid.x >= g_frame.RenderWidth || swizzledDTid.y >= g_frame.RenderHeight)\n        return;\n\n    if(IS_CB_FLAG_SET(CB_IND_FLAGS::SORT_TEMPORAL))\n    {\n        bool error;\n        swizzledDTid = RPT_Util::DecodeSorted(swizzledDTid, g_local.ThreadMap_NtC_DescHeapIdx, error);\n\n        if(error)\n            return;\n    }\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[\n        g_frame.CurrGBufferDescHeapOffset + GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr = g_metallicRoughness[swizzledDTid];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n\n    if (flags.invalid || flags.emissive)\n        return;\n\n    RPT_Util::Reservoir r_curr = RPT_Util::Reservoir::Load_NonReconnection<\n        RWTexture2D<uint4>, RWTexture2D<float2> >(swizzledDTid, \n        g_local.Reservoir_A_DescHeapIdx, g_local.Reservoir_A_DescHeapIdx + 1);\n    r_curr.LoadTarget(swizzledDTid, g_local.TargetDescHeapIdx);\n\n    GBUFFER_MOTION_VECTOR g_motionVector = ResourceDescriptorHeap[\n        g_frame.CurrGBufferDescHeapOffset + GBUFFER_OFFSET::MOTION_VECTOR];\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float2 motionVec = g_motionVector[swizzledDTid];\n    const float2 currUV = (swizzledDTid + 0.5f) / renderDim;\n    const float2 prevUV = currUV - motionVec;\n    int2 prevPixel = prevUV * renderDim;\n\n    // No temporal history\n    if (any(prevUV < 0.0f.xx) || any(prevUV > 1.0f.xx))\n    {\n        if(!IS_CB_FLAG_SET(CB_IND_FLAGS::SPATIAL_RESAMPLE))\n        {\n            RPT_Util::WriteOutputColor(swizzledDTid, r_curr.target * r_curr.W, g_local.Packed, \n                g_local.FinalDescHeapIdx, g_frame);\n        }\n\n        return;\n    }\n\n    // Prepare previous pixel's geometry and material data\n    GBUFFER_DEPTH g_prevDepth = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float prevViewDepth = g_prevDepth[prevPixel];\n\n    // No temporal history\n    if(prevViewDepth == FLT_MAX)\n    {\n        if(!IS_CB_FLAG_SET(CB_IND_FLAGS::SPATIAL_RESAMPLE))\n        {\n            RPT_Util::WriteOutputColor(swizzledDTid, r_curr.target * r_curr.W, \n                g_local.Packed, g_local.FinalDescHeapIdx, g_frame);\n        }\n\n        return;\n    }\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float z_view = g_depth[swizzledDTid];\n\n    float2 lensSample = 0;\n    float3 origin = g_frame.CameraPos;\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(swizzledDTid.xyx).zy, g_frame.FrameNum);\n        lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample *= g_frame.LensRadius;\n    }\n\n    const float3 pos = Math::WorldPosFromScreenSpace2(swizzledDTid, renderDim, z_view, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n        g_frame.DoF, lensSample, g_frame.FocusDepth, origin);\n\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_normal[swizzledDTid]);\n\n    float2 lensSample_t = 0;\n    float3 origin_t = float3(g_frame.PrevViewInv._m03, g_frame.PrevViewInv._m13, \n        g_frame.PrevViewInv._m23);\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(prevPixel.xyx).zy, g_frame.FrameNum - 1);\n        lensSample_t = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample_t *= g_frame.LensRadius;\n    }\n\n    const float3 prevPos = Math::WorldPosFromScreenSpace2(prevPixel, renderDim, prevViewDepth, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.PrevCameraJitter, \n        g_frame.PrevView[0].xyz, g_frame.PrevView[1].xyz, g_frame.PrevView[2].xyz, \n        g_frame.DoF, lensSample_t, g_frame.FocusDepth, origin_t);\n\n    // Skip if not on the same surface\n    if(!RPT_Util::PlaneHeuristic(prevPos, normal, pos, z_view, MAX_PLANE_DIST_REUSE))\n    {\n        if(!IS_CB_FLAG_SET(CB_IND_FLAGS::SPATIAL_RESAMPLE))\n        {\n            RPT_Util::WriteOutputColor(swizzledDTid, r_curr.target * r_curr.W, \n                g_local.Packed, g_local.FinalDescHeapIdx, g_frame);\n        }\n\n        return;\n    }\n\n    GBUFFER_METALLIC_ROUGHNESS g_prevMR = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 prevMR = g_prevMR[prevPixel];\n    GBuffer::Flags prevFlags = GBuffer::DecodeMetallic(prevMR.x);\n\n    // Skip if not on the same surface\n    if(prevFlags.emissive || \n        abs(prevMR.y - mr.y) > MAX_ROUGHNESS_DIFF_TEMPORAL_REUSE || \n        (prevFlags.transmissive != flags.transmissive))\n    {\n        if(!IS_CB_FLAG_SET(CB_IND_FLAGS::SPATIAL_RESAMPLE))\n        {\n            RPT_Util::WriteOutputColor(swizzledDTid, r_curr.target * r_curr.W,\n                g_local.Packed, g_local.FinalDescHeapIdx, g_frame);\n        }\n\n        return;\n    }\n\n    Reservoir r_prev = Reservoir::Load_NonReconnection<Texture2D<uint4>, \n        Texture2D<float2> >(prevPixel, g_local.PrevReservoir_A_DescHeapIdx, \n        g_local.PrevReservoir_A_DescHeapIdx + 1);\n\n    Globals globals = InitGlobals(flags.transmissive);\n    const uint16_t M_new = r_curr.M + r_prev.M;\n\n    uint M_max = (g_local.Packed >> PACKED_INDEX::MAX_TEMPORAL_M) & 0xf;\n\n    // Temporal history can't be shifted for reuse\n    if(r_prev.rc.Empty())\n    {\n        // Recompute W as w_sum may have changed after the current to temporal shift\n        float targetLum = Math::Luminance(r_curr.target);\n        r_curr.W = targetLum > 0 ? r_curr.w_sum / targetLum : 0;\n        r_curr.M = M_new;\n\n        r_curr.WriteReservoirData2(swizzledDTid, g_local.Reservoir_A_DescHeapIdx,\n            g_local.Reservoir_A_DescHeapIdx + 1, M_max);\n\n        if(!IS_CB_FLAG_SET(CB_IND_FLAGS::SPATIAL_RESAMPLE))\n        {\n            RPT_Util::WriteOutputColor(swizzledDTid, r_curr.target * r_curr.W,\n                g_local.Packed, g_local.FinalDescHeapIdx, g_frame);\n        }\n\n        return;\n    }\n\n    r_prev.Load_Reconnection<NEE_EMISSIVE, Texture2D<uint4>, Texture2D<uint4>, \n        Texture2D<half>, Texture2D<float2>, Texture2D<uint2> >(prevPixel, \n        g_local.PrevReservoir_A_DescHeapIdx + 2, \n        g_local.PrevReservoir_A_DescHeapIdx + 3,\n        g_local.PrevReservoir_A_DescHeapIdx + 4,\n        g_local.PrevReservoir_A_DescHeapIdx + 5,\n        g_local.PrevReservoir_A_DescHeapIdx + 6);\n\n    if(r_prev.rc.IsCase1() || r_prev.rc.IsCase2())\n    {\n        const RT::MeshInstance meshData = g_frameMeshData[NonUniformResourceIndex(r_prev.rc.meshIdx)];\n        float3 prevTranslation = meshData.Translation - meshData.dTranslation;\n        float4 q_prev = Math::DecodeNormalized4(meshData.PrevRotation);\n        // due to quantization, it's necessary to renormalize\n        q_prev = normalize(q_prev);\n        float3 x_local = Math::InverseTransformTRS(r_prev.rc.x_k, prevTranslation, \n            q_prev, meshData.PrevScale);\n\n        float4 q_curr = Math::DecodeNormalized4(meshData.Rotation);\n        q_curr = normalize(q_curr);\n        r_prev.rc.x_k = Math::TransformTRS(x_local, meshData.Translation, \n            q_curr, meshData.Scale);\n\n        float4 dRot = q_prev - q_curr;\n        float3 dScale = meshData.PrevScale - meshData.Scale;\n        r_prev.rc.x_k_in_motion = dot(meshData.dTranslation, meshData.dTranslation) > 0;\n        r_prev.rc.x_k_in_motion = r_prev.rc.x_k_in_motion || dot(dRot, dRot) > 0;\n        r_prev.rc.x_k_in_motion = r_prev.rc.x_k_in_motion || dot(dScale, dScale) > 0;\n    }\n\n    // Shift temporal path to current pixel and resample\n    OffsetPath shift = ShiftTemporalToCurrent(swizzledDTid, origin, lensSample,\n        pos, normal, flags, mr.y, r_prev.rc, globals);\n\n    float targetLum_curr = Math::Luminance(shift.target);\n    float jacobian = r_prev.rc.partialJacobian > 0 ? \n        shift.partialJacobian / r_prev.rc.partialJacobian : 0;\n    bool changed = false;\n\n    // RIS weight becomes zero when target = 0, in which case only M needs to be\n    // updated\n    if(targetLum_curr > 1e-6 && jacobian > 1e-5)\n    {\n        RNG rng = RNG::Init(swizzledDTid.yx, g_frame.FrameNum + 31);\n\n        float targetLum_prev = r_prev.W > 0 ? r_prev.w_sum / r_prev.W : 0;\n        // Jacobian term in numerator cancels out with the same term in w_prev\n        float numerator = r_prev.M * targetLum_prev;\n        float denom = numerator / jacobian + targetLum_curr;\n        // Balance heuristic\n        float m_prev = denom > 0 ? numerator / denom : 0;\n        float w_prev = m_prev * r_prev.W * targetLum_curr;\n\n        if(r_curr.Update(w_prev, shift.target, r_prev.rc, rng))\n        {\n            r_curr.rc.partialJacobian = shift.partialJacobian;\n            changed = true;\n        }\n    }\n\n    float targetLum = Math::Luminance(r_curr.target);\n    r_curr.W = targetLum > 0 ? r_curr.w_sum / targetLum : 0;\n    r_curr.M = M_new;\n\n    // If reconnection didn't change, skip writing it\n    if(changed)\n    {\n        r_curr.Write<NEE_EMISSIVE>(swizzledDTid, g_local.Reservoir_A_DescHeapIdx,\n            g_local.Reservoir_A_DescHeapIdx + 1, g_local.Reservoir_A_DescHeapIdx + 2, \n            g_local.Reservoir_A_DescHeapIdx + 3, g_local.Reservoir_A_DescHeapIdx + 4, \n            g_local.Reservoir_A_DescHeapIdx + 5, g_local.Reservoir_A_DescHeapIdx + 6,\n            M_max);\n\n        if(IS_CB_FLAG_SET(CB_IND_FLAGS::SPATIAL_RESAMPLE))\n            r_curr.WriteTarget(swizzledDTid, g_local.TargetDescHeapIdx);\n    }\n    else\n    {\n        r_curr.WriteReservoirData(swizzledDTid, g_local.Reservoir_A_DescHeapIdx,\n            g_local.Reservoir_A_DescHeapIdx + 1, M_max);\n    }\n\n    if(!IS_CB_FLAG_SET(CB_IND_FLAGS::SPATIAL_RESAMPLE))\n    {\n        float3 li = r_curr.target * r_curr.W;\n        RPT_Util::DebugColor(r_curr.rc, g_local.Packed, li);\n        RPT_Util::WriteOutputColor(swizzledDTid, li, g_local.Packed, \n            g_local.FinalDescHeapIdx, g_frame, false);\n    }\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/ReSTIR_PT_Replay.hlsl",
    "content": "#ifndef NEE_EMISSIVE\n#define NEE_EMISSIVE 0\n#endif\n\n#include \"../../Common/Common.hlsli\"\n#include \"Util.hlsli\"\n\n#if !defined (TEMPORAL_TO_CURRENT) && !defined (SPATIAL_TO_CURRENT) && !defined (CURRENT_TO_SPATIAL)\n#define CURRENT_TO_TEMPORAL\n#endif\n\n#define THREAD_GROUP_SWIZZLING 0\n\nusing namespace ReSTIR_Util;\nusing namespace RPT_Util;\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_ReSTIR_PT_Reuse> g_local : register(b1);\nRaytracingAccelerationStructure g_bvh : register(t0);\nStructuredBuffer<RT::MeshInstance> g_frameMeshData : register(t1);\nStructuredBuffer<Vertex> g_vertices : register(t2);\nStructuredBuffer<uint> g_indices : register(t3);\nStructuredBuffer<Material> g_materials : register(t4);\n\n//--------------------------------------------------------------------------------------\n// Utility Functions\n//--------------------------------------------------------------------------------------\n\nReSTIR_Util::Globals InitGlobals(bool transmissive)\n{\n    ReSTIR_Util::Globals globals;\n    globals.bvh = g_bvh;\n    globals.frameMeshData = g_frameMeshData;\n    globals.vertices = g_vertices;\n    globals.indices = g_indices;\n    globals.materials = g_materials;\n    uint maxNonTrBounces = g_local.Packed & 0xf;\n    uint maxGlossyTrBounces = (g_local.Packed >> PACKED_INDEX::NUM_GLOSSY_BOUNCES) & 0xf;\n    globals.maxNumBounces = transmissive ? (uint16_t)maxGlossyTrBounces :\n        (uint16_t)maxNonTrBounces;\n\n    return globals;\n}\n\nOffsetPathContext ReplayCurrentInTemporalDomain(uint2 prevPosSS, float3 origin, \n    float2 lensSample, float3 prevPos, GBuffer::Flags prevFlags, float prevRoughness, \n    RPT_Util::Reconnection rc_curr, ReSTIR_Util::Globals globals)\n{\n    float eta_curr = ETA_AIR;\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(prevFlags.transmissive)\n    {\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        float ior = g_ior[prevPosSS];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    GBUFFER_NORMAL g_prevNormal = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_prevNormal[prevPosSS]);\n\n    GBUFFER_BASE_COLOR g_prevBaseColor = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n    const float4 baseColor = prevFlags.subsurface ? g_prevBaseColor[prevPosSS] : \n        float4(g_prevBaseColor[prevPosSS].rgb, 0);\n\n    float coat_weight = 0;\n    float3 coat_color = 0.0f;\n    float coat_roughness = 0;\n    float coat_ior = DEFAULT_ETA_COAT;\n\n    if(prevFlags.coated)\n    {\n        GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n            GBUFFER_OFFSET::COAT];\n        uint3 packed = g_coat[prevPosSS].xyz;\n\n        GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n        coat_weight = coat.weight;\n        coat_color = coat.color;\n        coat_roughness = coat.roughness;\n        coat_ior = coat.ior;\n    }\n\n    const float3 wo = normalize(origin - prevPos);\n    BSDF::ShadingData surface = BSDF::ShadingData::Init(normal, wo, prevFlags.metallic, \n        prevRoughness, baseColor.rgb, eta_curr, eta_next, prevFlags.transmissive, \n        prevFlags.trDepthGt0, (half)baseColor.a, coat_weight, coat_color,\n        coat_roughness, coat_ior);\n\n    GBUFFER_TRI_DIFF_GEO_A g_triA = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n        GBUFFER_OFFSET::TRI_DIFF_GEO_A];\n    GBUFFER_TRI_DIFF_GEO_B g_triB = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n        GBUFFER_OFFSET::TRI_DIFF_GEO_B];\n    const uint4 packed_a = g_triA[prevPosSS];\n    const uint2 packed_b = g_triB[prevPosSS];\n\n    Math::TriDifferentials triDiffs = Math::TriDifferentials::Unpack(packed_a, packed_b);\n    float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n\n    RT::RayDifferentials rd = RT::RayDifferentials::Init(prevPosSS, renderDim, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.PrevCameraJitter, \n        g_frame.PrevView[0].xyz, g_frame.PrevView[1].xyz, \n        g_frame.PrevView[2].xyz, g_frame.DoF, g_frame.FocusDepth, \n        lensSample, origin);\n\n    float3 dpdx;\n    float3 dpdy;\n    rd.dpdx_dpdy(prevPos, normal, dpdx, dpdy);\n    rd.ComputeUVDifferentials(dpdx, dpdy, triDiffs.dpdu, triDiffs.dpdv);\n\n    const bool regularization = IS_CB_FLAG_SET(CB_IND_FLAGS::PATH_REGULARIZATION);\n    const uint texFilterDescHeapIdx = (g_local.Packed >> PACKED_INDEX::TEX_FILTER) & 0xf;\n    SamplerState samp = SamplerDescriptorHeap[texFilterDescHeapIdx];\n\n    return Replay_kGt2<false>(prevPos, normal, eta_next, surface, rd, triDiffs, rc_curr, \n        g_local.Alpha_min, regularization, samp, g_frame, globals);\n}\n\nOffsetPathContext ReplayCurrentInSpatialDomain(uint2 samplePosSS, RPT_Util::Reconnection rc_curr,\n    ReSTIR_Util::Globals globals)\n{\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    GBUFFER_METALLIC_ROUGHNESS g_mr = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n\n    const float depth_n = g_depth[samplePosSS];\n\n    float2 lensSample_n = 0;\n    float3 origin_n = g_frame.CameraPos;\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(samplePosSS.xyx).zy, g_frame.FrameNum);\n        lensSample_n = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample_n *= g_frame.LensRadius;\n    }\n\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float3 pos_n = Math::WorldPosFromScreenSpace2(samplePosSS, renderDim, depth_n, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n        g_frame.DoF, lensSample_n, g_frame.FocusDepth, origin_n);\n\n    const float2 mr_n = g_mr[samplePosSS];\n    GBuffer::Flags flags_n = GBuffer::DecodeMetallic(mr_n.x);\n\n    float3 normal_n = Math::DecodeUnitVector(g_normal[samplePosSS]);\n    float4 baseColor_n = flags_n.subsurface ? g_baseColor[samplePosSS] : \n        float4(g_baseColor[samplePosSS].rgb, 0);\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(flags_n.transmissive)\n    {\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        float ior = g_ior[samplePosSS];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    float coat_weight = 0;\n    float3 coat_color = 0.0f;\n    float coat_roughness = 0;\n    float coat_ior = DEFAULT_ETA_COAT;\n\n    if(flags_n.coated)\n    {\n        GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::COAT];\n        uint3 packed = g_coat[samplePosSS].xyz;\n\n        GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n        coat_weight = coat.weight;\n        coat_color = coat.color;\n        coat_roughness = coat.roughness;\n        coat_ior = coat.ior;\n    }\n\n    const float3 wo_n = normalize(origin_n - pos_n);\n    BSDF::ShadingData surface_n = BSDF::ShadingData::Init(normal_n, wo_n, flags_n.metallic, \n        mr_n.y, baseColor_n.rgb, ETA_AIR, eta_next, flags_n.transmissive, flags_n.trDepthGt0,\n        (half)baseColor_n.a, coat_weight, coat_color, coat_roughness, coat_ior);\n\n    GBUFFER_TRI_DIFF_GEO_A g_triA = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::TRI_DIFF_GEO_A];\n    GBUFFER_TRI_DIFF_GEO_B g_triB = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::TRI_DIFF_GEO_B];\n    const uint4 packed_a = g_triA[samplePosSS];\n    const uint2 packed_b = g_triB[samplePosSS];\n\n    Math::TriDifferentials triDiffs = Math::TriDifferentials::Unpack(packed_a, packed_b);\n\n    RT::RayDifferentials rd = RT::RayDifferentials::Init(samplePosSS, renderDim, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, \n        g_frame.CurrView[2].xyz, g_frame.DoF, g_frame.FocusDepth, \n        lensSample_n, origin_n);\n\n    bool regularization = IS_CB_FLAG_SET(CB_IND_FLAGS::PATH_REGULARIZATION);\n    const uint texFilterDescHeapIdx = (g_local.Packed >> PACKED_INDEX::TEX_FILTER) & 0xf;\n    SamplerState samp = SamplerDescriptorHeap[texFilterDescHeapIdx];\n\n    return Replay_kGt2<true>(pos_n, normal_n, eta_next, surface_n, rd, triDiffs, rc_curr, \n        g_local.Alpha_min, regularization, samp, g_frame, globals);\n}\n\nOffsetPathContext ReplayInCurrent(uint2 DTid, float3 origin, float2 lensSample, float3 pos, \n    float3 normal, GBuffer::Flags flags, float roughness, Reconnection rc, Globals globals)\n{\n    GBUFFER_BASE_COLOR g_baseColor = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::BASE_COLOR];\n    const float4 baseColor = flags.subsurface ? g_baseColor[DTid] : float4(g_baseColor[DTid].rgb, 0);\n\n    float eta_curr = ETA_AIR;\n    float eta_next = DEFAULT_ETA_MAT;\n\n    if(flags.transmissive)\n    {\n        GBUFFER_IOR g_ior = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::IOR];\n\n        float ior = g_ior[DTid];\n        eta_next = GBuffer::DecodeIOR(ior);\n    }\n\n    float coat_weight = 0;\n    float3 coat_color = 1.0f;\n    float coat_roughness = 0;\n    float coat_ior = DEFAULT_ETA_COAT;\n\n    if(flags.coated)\n    {\n        GBUFFER_COAT g_coat = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n            GBUFFER_OFFSET::COAT];\n        uint3 packed = g_coat[DTid.xy].xyz;\n\n        GBuffer::Coat coat = GBuffer::UnpackCoat(packed);\n        coat_weight = coat.weight;\n        coat_color = coat.color;\n        coat_roughness = coat.roughness;\n        coat_ior = coat.ior;\n    }\n\n    const float3 wo = normalize(origin - pos);\n    BSDF::ShadingData surface = BSDF::ShadingData::Init(normal, wo, flags.metallic, \n        roughness, baseColor.rgb, eta_curr, eta_next, flags.transmissive, flags.trDepthGt0, \n        (half)baseColor.a, coat_weight, coat_color, coat_roughness, coat_ior);\n\n    GBUFFER_TRI_DIFF_GEO_A g_triA = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::TRI_DIFF_GEO_A];\n    GBUFFER_TRI_DIFF_GEO_B g_triB = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::TRI_DIFF_GEO_B];\n    const uint4 packed_a = g_triA[DTid];\n    const uint2 packed_b = g_triB[DTid];\n\n    Math::TriDifferentials triDiffs = Math::TriDifferentials::Unpack(packed_a, packed_b);\n    float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n\n    RT::RayDifferentials rd = RT::RayDifferentials::Init(DTid, renderDim, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, \n        g_frame.CurrView[2].xyz, g_frame.DoF, g_frame.FocusDepth, \n        lensSample, origin);\n\n    const bool regularization = IS_CB_FLAG_SET(CB_IND_FLAGS::PATH_REGULARIZATION);\n    const uint texFilterDescHeapIdx = (g_local.Packed >> PACKED_INDEX::TEX_FILTER) & 0xf;\n    SamplerState samp = SamplerDescriptorHeap[texFilterDescHeapIdx];\n\n    return Replay_kGt2<true>(pos, normal, eta_next, surface, rd, triDiffs, rc, g_local.Alpha_min, \n        regularization, samp, g_frame, globals);\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(RESTIR_PT_REPLAY_GROUP_DIM_X, RESTIR_PT_REPLAY_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID)\n{\n#if THREAD_GROUP_SWIZZLING == 1\n    uint2 swizzledGid;\n\n    uint2 swizzledDTid = Common::SwizzleThreadGroup(DTid, Gid, GTid, \n        uint2(RESTIR_PT_TEMPORAL_GROUP_DIM_X, RESTIR_PT_TEMPORAL_GROUP_DIM_Y),\n        g_local.DispatchDimX_NumGroupsInTile & 0xffff, \n        RESTIR_PT_TILE_WIDTH, \n        RESTIR_PT_LOG2_TILE_WIDTH, \n        g_local.DispatchDimX_NumGroupsInTile >> 16,\n        swizzledGid);\n#else\n    uint2 swizzledDTid = DTid.xy;\n    const uint2 swizzledGid = Gid.xy;\n#endif\n\n#if defined (TEMPORAL_TO_CURRENT) || defined (CURRENT_TO_TEMPORAL)\n    if(IS_CB_FLAG_SET(CB_IND_FLAGS::SORT_TEMPORAL))\n#else\n    if(IS_CB_FLAG_SET(CB_IND_FLAGS::SORT_SPATIAL))\n#endif\n    {\n#if defined (TEMPORAL_TO_CURRENT) || defined (SPATIAL_TO_CURRENT)\n        uint descHeapIdx = g_local.ThreadMap_NtC_DescHeapIdx;\n#elif defined (CURRENT_TO_TEMPORAL) || defined (CURRENT_TO_SPATIAL)\n        uint descHeapIdx = g_local.ThreadMap_CtN_DescHeapIdx;\n#else\n#error Unknown shift type\n#endif\n\n        bool error;\n        swizzledDTid = RPT_Util::DecodeSorted(swizzledDTid, descHeapIdx, error);\n\n        if(error)\n            return;\n    }\n\n    if (swizzledDTid.x >= g_frame.RenderWidth || swizzledDTid.y >= g_frame.RenderHeight)\n        return;\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr = g_metallicRoughness[swizzledDTid];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n\n    if (flags.invalid || flags.emissive)\n        return;\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float z_view = g_depth[swizzledDTid];\n\n    float2 lensSample = 0;\n    float3 origin = g_frame.CameraPos;\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(swizzledDTid.xyx).zy, g_frame.FrameNum);\n        lensSample = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample *= g_frame.LensRadius;\n    }\n\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float3 pos = Math::WorldPosFromScreenSpace2(swizzledDTid, renderDim, z_view, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrCameraJitter, \n        g_frame.CurrView[0].xyz, g_frame.CurrView[1].xyz, g_frame.CurrView[2].xyz, \n        g_frame.DoF, lensSample, g_frame.FocusDepth, origin);\n\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_normal[swizzledDTid]);\n\n#if defined (TEMPORAL_TO_CURRENT) || defined(CURRENT_TO_TEMPORAL)\n    // Check if there is valid history data for temporal reuse\n    GBUFFER_MOTION_VECTOR g_motionVector = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::MOTION_VECTOR];\n    const float2 motionVec = g_motionVector[swizzledDTid];\n    const float2 currUV = (swizzledDTid + 0.5f) / renderDim;\n    const float2 prevUV = currUV - motionVec;\n    int2 prevPixel = prevUV * renderDim;\n\n    // No temporal history\n    if (any(prevUV < 0.0f.xx) || any(prevUV > 1.0f.xx))\n        return;\n\n    GBUFFER_DEPTH g_prevDepth = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float z_view_n = g_prevDepth[prevPixel];\n\n    // No temporal history\n    if(z_view_n == FLT_MAX)\n        return;\n\n    float2 lensSample_n = 0;\n    float3 origin_n = float3(g_frame.PrevViewInv._m03, g_frame.PrevViewInv._m13, \n        g_frame.PrevViewInv._m23);\n    if(g_frame.DoF)\n    {\n        RNG rngDoF = RNG::Init(RNG::PCG3d(prevPixel.xyx).zy, g_frame.FrameNum - 1);\n        lensSample_n = Sampling::UniformSampleDiskConcentric(rngDoF.Uniform2D());\n        lensSample_n *= g_frame.LensRadius;\n    }\n\n    const float3 pos_n = Math::WorldPosFromScreenSpace2(prevPixel, renderDim, z_view_n, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.PrevCameraJitter, \n        g_frame.PrevView[0].xyz, g_frame.PrevView[1].xyz, g_frame.PrevView[2].xyz, \n        g_frame.DoF, lensSample_n, g_frame.FocusDepth, origin_n);\n\n    // No temporal history\n    if(!RPT_Util::PlaneHeuristic(pos_n, normal, pos, z_view, 0.01))\n        return;\n\n    GBUFFER_METALLIC_ROUGHNESS g_prevMR = ResourceDescriptorHeap[g_frame.PrevGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr_n = g_prevMR[prevPixel];\n    GBuffer::Flags flags_n = GBuffer::DecodeMetallic(mr_n.x);\n\n    // No temporal history\n    if(flags_n.emissive || \n        (abs(mr_n.y - mr.y) > 0.3) ||\n        (flags_n.transmissive != flags.transmissive))\n        return;\n#endif\n\n    ReSTIR_Util::Globals globals = InitGlobals(flags.transmissive);\n\n    // Replay temporal reservoir's path\n#if defined (TEMPORAL_TO_CURRENT)\n    Reservoir r_prev = Reservoir::Load_Metadata<Texture2D<uint4> >(\n        prevPixel, g_local.PrevReservoir_A_DescHeapIdx);\n\n    // If reconnection vertex exists and replay is needed\n    if(!r_prev.rc.Empty() && (r_prev.rc.k > 2))\n    {\n        r_prev.Load_Reconnection<NEE_EMISSIVE, Texture2D<uint4>, Texture2D<uint4>, \n            Texture2D<half>, Texture2D<float2>, Texture2D<uint2> >(prevPixel, \n            g_local.PrevReservoir_A_DescHeapIdx + 2, \n            g_local.PrevReservoir_A_DescHeapIdx + 3,\n            g_local.PrevReservoir_A_DescHeapIdx + 4,\n            g_local.PrevReservoir_A_DescHeapIdx + 5,\n            g_local.PrevReservoir_A_DescHeapIdx + 6);\n\n        OffsetPathContext ctx_ntc = ReplayInCurrent(swizzledDTid, origin, lensSample, \n            pos, normal, flags, mr.y, r_prev.rc, globals);\n\n        ctx_ntc.Write(swizzledDTid, g_local.RBufferA_NtC_DescHeapIdx, \n            g_local.RBufferA_NtC_DescHeapIdx + 1,\n            g_local.RBufferA_NtC_DescHeapIdx + 2, \n            g_local.RBufferA_NtC_DescHeapIdx + 3, \n            r_prev.rc.IsCase3());\n    }\n\n    // Replay spatial reservoir's path\n#elif defined(SPATIAL_TO_CURRENT)\n    Texture2D<uint2> g_neighbor = ResourceDescriptorHeap[g_local.SpatialNeighborHeapIdx];\n    int2 samplePos = (int2)g_neighbor[swizzledDTid];\n\n    if(samplePos.x == UINT8_MAX)\n        return;\n\n    samplePos -= RPT_Util::SPATIAL_NEIGHBOR_OFFSET;\n    samplePos += swizzledDTid;\n\n    Reservoir r_spatial = Reservoir::Load_Metadata<Texture2D<uint4> >(\n        samplePos, g_local.Reservoir_A_DescHeapIdx);\n\n    if(!r_spatial.rc.Empty() && (r_spatial.rc.k > 2))\n    {\n        r_spatial.Load_Reconnection<NEE_EMISSIVE, Texture2D<uint4>, Texture2D<uint4>, \n            Texture2D<half>, Texture2D<float2>, Texture2D<uint2> >(samplePos, \n            g_local.Reservoir_A_DescHeapIdx + 2, \n            g_local.Reservoir_A_DescHeapIdx + 3,\n            g_local.Reservoir_A_DescHeapIdx + 4,\n            g_local.Reservoir_A_DescHeapIdx + 5,\n            g_local.Reservoir_A_DescHeapIdx + 6);\n\n        OffsetPathContext ctx_ntc = ReplayInCurrent(swizzledDTid, origin, lensSample, \n            pos, normal, flags, mr.y, r_spatial.rc, globals);\n\n        ctx_ntc.Write(swizzledDTid, g_local.RBufferA_NtC_DescHeapIdx, \n            g_local.RBufferA_NtC_DescHeapIdx + 1,\n            g_local.RBufferA_NtC_DescHeapIdx + 2, \n            g_local.RBufferA_NtC_DescHeapIdx + 3, \n            r_spatial.rc.IsCase3());\n    }\n\n    // Replay current reservoir's path in temporal\n#elif defined(CURRENT_TO_TEMPORAL)\n    Reservoir r_curr = Reservoir::Load_Metadata<RWTexture2D<uint4> >(\n        swizzledDTid, g_local.Reservoir_A_DescHeapIdx);\n\n    if(!r_curr.rc.Empty() && (r_curr.rc.k > 2))\n    {\n        r_curr.Load_Reconnection<NEE_EMISSIVE, RWTexture2D<uint4>, RWTexture2D<uint4>, \n            RWTexture2D<half>, RWTexture2D<float2>, RWTexture2D<uint2> >(swizzledDTid, \n            g_local.Reservoir_A_DescHeapIdx + 2, \n            g_local.Reservoir_A_DescHeapIdx + 3,\n            g_local.Reservoir_A_DescHeapIdx + 4,\n            g_local.Reservoir_A_DescHeapIdx + 5,\n            g_local.Reservoir_A_DescHeapIdx + 6);\n\n        OffsetPathContext ctx_ctn = ReplayCurrentInTemporalDomain(prevPixel, origin_n, \n            lensSample_n, pos_n, flags_n, mr_n.y, r_curr.rc, globals);\n\n        ctx_ctn.Write(swizzledDTid, g_local.RBufferA_CtN_DescHeapIdx, \n            g_local.RBufferA_CtN_DescHeapIdx + 1,\n            g_local.RBufferA_CtN_DescHeapIdx + 2, \n            g_local.RBufferA_CtN_DescHeapIdx + 3, \n            r_curr.rc.IsCase3());\n    }\n\n    // Replay current reservoir's path in spatial neighbor\n#elif defined(CURRENT_TO_SPATIAL)\n    Reservoir r_curr = Reservoir::Load_Metadata<Texture2D<uint4> >(\n        swizzledDTid, g_local.Reservoir_A_DescHeapIdx);\n\n    if(!r_curr.rc.Empty() && (r_curr.rc.k > 2))\n    {\n        r_curr.Load_Reconnection<NEE_EMISSIVE, Texture2D<uint4>, Texture2D<uint4>, \n            Texture2D<half>, Texture2D<float2>, Texture2D<uint2> >(swizzledDTid, \n            g_local.Reservoir_A_DescHeapIdx + 2, \n            g_local.Reservoir_A_DescHeapIdx + 3,\n            g_local.Reservoir_A_DescHeapIdx + 4,\n            g_local.Reservoir_A_DescHeapIdx + 5,\n            g_local.Reservoir_A_DescHeapIdx + 6);\n\n        Texture2D<uint2> g_neighbor = ResourceDescriptorHeap[g_local.SpatialNeighborHeapIdx];\n        int2 samplePos = (int2)g_neighbor[swizzledDTid];\n\n        if(samplePos.x == UINT8_MAX)\n            return;\n\n        samplePos -= RPT_Util::SPATIAL_NEIGHBOR_OFFSET;\n        samplePos += swizzledDTid;\n\n        OffsetPathContext ctx_ctn = ReplayCurrentInSpatialDomain(samplePos, r_curr.rc, \n            globals);\n        ctx_ctn.Write(swizzledDTid, g_local.RBufferA_CtN_DescHeapIdx, \n            g_local.RBufferA_CtN_DescHeapIdx + 1,\n            g_local.RBufferA_CtN_DescHeapIdx + 2, \n            g_local.RBufferA_CtN_DescHeapIdx + 3, \n            r_curr.rc.IsCase3());\n    }\n#endif\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/ReSTIR_PT_Sort.hlsl",
    "content": "#include \"../../Common/Common.hlsli\"\n#include \"Util.hlsli\"\n\n#if !defined (TEMPORAL_TO_CURRENT) && !defined (SPATIAL_TO_CURRENT) && !defined (CURRENT_TO_SPATIAL)\n#define CURRENT_TO_TEMPORAL\n#endif\n\n#define COMPACTION_ONLY 0\n\nstatic const uint16_t2 GroupDim = uint16_t2(RESTIR_PT_SORT_GROUP_DIM_X, RESTIR_PT_SORT_GROUP_DIM_Y);\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_ReSTIR_PT_Sort> g_local : register(b1);\n\n//--------------------------------------------------------------------------------------\n// Utility Functions\n//--------------------------------------------------------------------------------------\n\nRPT_Util::SHIFT_ERROR FindNeighbor(uint2 DTid, out int2 neighborPixel)\n{\n    if (DTid.x >= g_frame.RenderWidth || DTid.y >= g_frame.RenderHeight)\n        return RPT_Util::SHIFT_ERROR::INVALID_PIXEL;\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float m = g_metallicRoughness[DTid].x;\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(m);\n\n    if (flags.invalid || flags.emissive)\n        return RPT_Util::SHIFT_ERROR::INVALID_PIXEL;\n\n#if defined (TEMPORAL_TO_CURRENT)\n    GBUFFER_MOTION_VECTOR g_motionVector = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::MOTION_VECTOR];\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float2 motionVec = g_motionVector[DTid];\n    const float2 currUV = (DTid + 0.5f) / renderDim;\n    const float2 prevUV = currUV - motionVec;\n    neighborPixel = prevUV * renderDim;\n\n    if (any(prevUV < 0.0f.xx) || any(prevUV > 1.0f.xx))\n        return RPT_Util::SHIFT_ERROR::NOT_FOUND;\n\n#elif defined(SPATIAL_TO_CURRENT)\n    Texture2D<uint2> g_neighbor = ResourceDescriptorHeap[g_local.SpatialNeighborHeapIdx];\n    neighborPixel = (int2)g_neighbor[DTid];\n\n    if(neighborPixel.x == UINT8_MAX) \n        return RPT_Util::SHIFT_ERROR::NOT_FOUND;\n\n    neighborPixel -= RPT_Util::SPATIAL_NEIGHBOR_OFFSET;\n    neighborPixel += DTid;\n\n#endif\n\n    return RPT_Util::SHIFT_ERROR::SUCCESS;\n}\n\nuint2 GroupIndexToGTid(uint Gidx)\n{\n    return uint2(Gidx & (2 * RESTIR_PT_SORT_GROUP_DIM_X - 1), \n        Gidx >> (LOG_RESTIR_PT_SORT_GROUP_DIM + 1));\n}\n\nvoid WriteOutput(uint2 Gid, uint2 DTid, uint2 mappedGTid, uint result)\n{\n    // Transpose the thread group index to handle another edge case for\n    // thread groups against the right image boundary\n    if((Gid.x == (g_local.DispatchDimX - 1)) && (Gid.y != (g_local.DispatchDimY - 1)))\n        mappedGTid = mappedGTid.yx;\n\n    uint2 mappedDTid = Gid * GroupDim * 2 + mappedGTid;\n\n#if defined (TEMPORAL_TO_CURRENT)\n    // Reconnect_TtC still needs to run even if motion vector is invalid and spatial is disabled\n    uint flags = IS_CB_FLAG_SET(CB_IND_FLAGS::SPATIAL_RESAMPLE) ?\n        RPT_Util::SHIFT_ERROR::INVALID_PIXEL | RPT_Util::SHIFT_ERROR::NOT_FOUND :\n        RPT_Util::SHIFT_ERROR::INVALID_PIXEL;\n    uint error = result & flags;\n#elif defined (SPATIAL_TO_CURRENT)\n    uint error = result & RPT_Util::SHIFT_ERROR::INVALID_PIXEL;\n#elif defined (CURRENT_TO_TEMPORAL) || defined (CURRENT_TO_SPATIAL)\n    uint error = result & (RPT_Util::SHIFT_ERROR::INVALID_PIXEL | RPT_Util::SHIFT_ERROR::EMPTY);\n#endif\n\n    if (mappedDTid.x < g_frame.RenderWidth && mappedDTid.y < g_frame.RenderHeight)\n        RPT_Util::EncodeSorted(DTid, mappedDTid, g_local.MapDescHeapIdx, error);\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n// (k = 2, k = 3, k = 4, k >= 5)\ngroupshared uint4 g_count;\n// No reconnection \ngroupshared uint g_skip;\n\n[numthreads(RESTIR_PT_SORT_GROUP_DIM_X, RESTIR_PT_SORT_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint Gidx : SV_GroupIndex, uint3 GTid : SV_GroupThreadID)\n{\n    if(Gidx == 0)\n    {\n        g_count = 0.xxxx;\n        g_skip = 0;\n    }\n\n    GroupMemoryBarrierWithGroupSync();\n\n    uint2 gtID[4];\n    gtID[0] = GTid.xy * 2;\n    gtID[1] = GTid.xy * 2 + uint2(1, 0);\n    gtID[2] = GTid.xy * 2 + uint2(0, 1);\n    gtID[3] = GTid.xy * 2 + uint2(1, 1);\n\n    uint2 dtID[4];\n    const uint2 groupStart = Gid.xy * GroupDim * 2;\n\n    [unroll]\n    for(int i = 0; i < 4; i++)\n        dtID[i] = groupStart + gtID[i];\n\n    bool4 skip;\n    int2 neighborPixel[4];\n    RPT_Util::SHIFT_ERROR error[4];\n\n    [unroll]\n    for(int i = 0; i < 4; i++)\n    {\n        error[i] = FindNeighbor(dtID[i], neighborPixel[i]);\n        skip[i] = error[i] != RPT_Util::SHIFT_ERROR::SUCCESS;\n    }\n\n    uint4 result = (uint4)error;\n    RPT_Util::Reservoir r_x[4];\n\n    [unroll]\n    for(int i = 0; i < 4; i++)\n        r_x[i] = RPT_Util::Reservoir::Init();\n\n#if defined (TEMPORAL_TO_CURRENT)\n    [unroll]\n    for(int i = 0; i < 4; i++)\n    {\n        if(error[i] == RPT_Util::SHIFT_ERROR::SUCCESS)\n        {\n            r_x[i] = RPT_Util::Reservoir::Load_MetadataX<Texture2D<uint4> >(neighborPixel[i], \n                g_local.Reservoir_A_DescHeapIdx);\n        }\n    }\n\n#elif defined(CURRENT_TO_TEMPORAL)\n    [unroll]\n    for(int i = 0; i < 4; i++)\n    {\n        if(error[i] == RPT_Util::SHIFT_ERROR::SUCCESS)\n        {\n            r_x[i] = RPT_Util::Reservoir::Load_MetadataX<RWTexture2D<uint4> >(dtID[i], \n                g_local.Reservoir_A_DescHeapIdx);\n        }\n    }\n\n#elif defined(CURRENT_TO_SPATIAL)\n    [unroll]\n    for(int i = 0; i < 4; i++)\n    {\n        if(error[i] == RPT_Util::SHIFT_ERROR::SUCCESS)\n        {\n            r_x[i] = RPT_Util::Reservoir::Load_MetadataX<Texture2D<uint4> >(dtID[i], \n                g_local.Reservoir_A_DescHeapIdx);\n        }\n    }\n\n#elif defined(SPATIAL_TO_CURRENT)\n    [unroll]\n    for(int i = 0; i < 4; i++)\n    {\n        if(error[i] == RPT_Util::SHIFT_ERROR::SUCCESS)\n        {\n            r_x[i] = RPT_Util::Reservoir::Load_MetadataX<Texture2D<uint4> >(neighborPixel[i], \n                g_local.Reservoir_A_DescHeapIdx);\n        }\n    }\n\n#else\n#error Undefined shift type\n#endif\n\n    [unroll]\n    for(int i = 0; i < 4; i++)\n    {\n        if(r_x[i].rc.Empty())\n        {\n            result[i] = result[i] | RPT_Util::SHIFT_ERROR::EMPTY;\n            skip[i] = true;\n        }\n    }\n\n    // Handle an edge case where for thread groups at the right and bottom \n    // image boundaries, valid threads may end up outside the screen and \n    // erroneously skipped in the subsequent passes\n    const bool againstEdge = (Gid.x == (g_local.DispatchDimX - 1)) ||\n        (Gid.y == (g_local.DispatchDimY - 1));\n    bool4 edgeCase = false;\n\n    // Make sure \"skip\" is true to avoid double counting\n    [unroll]\n    for(int i = 0; i < 4; i++)\n    {\n        if(skip[i] && againstEdge && (dtID[i].x < g_frame.RenderWidth) && (dtID[i].y < g_frame.RenderHeight))\n        {\n            result[i] = RPT_Util::SHIFT_ERROR::SUCCESS;\n            skip[i] = false;\n            edgeCase[i] = true;\n        }\n    }\n\n    bool4 kEq2;\n#if COMPACTION_ONLY == 1\n    bool4 kGe3;\n#else\n    bool4 kEq3;\n    bool4 kEq4;\n    bool4 kGe5;\n#endif\n\n    [unroll]\n    for(int i = 0; i < 4; i++)\n    {\n        kEq2[i] = !skip[i] && (r_x[i].rc.k == 2);\n#if COMPACTION_ONLY == 1\n        kGe3[i] = !skip[i] && ((r_x[i].rc.k >= 3) || edgeCase[i]);\n#else\n        kEq3[i] = !skip[i] && (r_x[i].rc.k == 3);\n        kEq4[i] = !skip[i] && (r_x[i].rc.k == 4);\n        kGe5[i] = !skip[i] && ((r_x[i].rc.k >= 5) || edgeCase[i]);\n#endif\n    }\n\n    const uint16_t wavekEq2Count = (uint16_t)WaveActiveSum(dot(1, kEq2));\n#if COMPACTION_ONLY == 1\n    const uint16_t wavekGe3Count = (uint16_t)WaveActiveSum(dot(1, kGe3));\n#else\n    const uint16_t wavekEq3Count = (uint16_t)WaveActiveSum(dot(1, kEq3));\n    const uint16_t wavekEq4Count = (uint16_t)WaveActiveSum(dot(1, kEq4));\n    const uint16_t wavekGe5Count = (uint16_t)WaveActiveSum(dot(1, kGe5));\n#endif\n    const uint16_t waveSkipCount = (uint16_t)WaveActiveSum(dot(1, skip));\n    // const uint16_t4 allCounts = uint16_t4(wavekEq2Count, wavekEq3Count, wavekEq4Count, wavekGe5Count);\n\n    uint4 waveOffsets;\n    uint skipOffset;\n\n    if(WaveGetLaneIndex() == 0)\n    {\n        InterlockedAdd(g_count.x, wavekEq2Count, waveOffsets.x);\n#if COMPACTION_ONLY == 1\n        InterlockedAdd(g_count.y, wavekGe3Count, waveOffsets.y);\n#else\n        InterlockedAdd(g_count.y, wavekEq3Count, waveOffsets.y);\n        InterlockedAdd(g_count.z, wavekEq4Count, waveOffsets.z);\n        InterlockedAdd(g_count.w, wavekGe5Count, waveOffsets.w);\n#endif\n        InterlockedAdd(g_skip, waveSkipCount, skipOffset);\n    }\n\n    GroupMemoryBarrierWithGroupSync();\n\n    waveOffsets = WaveReadLaneAt(waveOffsets, 0);\n    skipOffset = WaveReadLaneAt(skipOffset, 0);\n\n    const uint kEq2BaseOffset = waveOffsets.x;\n#if COMPACTION_ONLY == 1\n    const uint kGe3BaseOffset = g_count.x + waveOffsets.y;\n    const uint skipBaseOffset = g_count.x + g_count.y + skipOffset;\n#else\n    const uint kEq3BaseOffset = g_count.x + waveOffsets.y;\n    const uint kEq4BaseOffset = g_count.x + g_count.y + waveOffsets.z;\n    const uint kGe5BaseOffset = g_count.x + g_count.y + g_count.z + waveOffsets.w;\n    const uint skipBaseOffset = g_count.x + g_count.y + g_count.z + g_count.w + skipOffset;\n#endif\n\n    uint lanekEq2Idx = WavePrefixSum(dot(1, kEq2));\n#if COMPACTION_ONLY == 1\n    uint lanekGe3Idx = WavePrefixSum(dot(1, kGe3));\n#else\n    uint lanekEq3Idx = WavePrefixSum(dot(1, kEq3));\n    uint lanekEq4Idx = WavePrefixSum(dot(1, kEq4));\n    uint lanekGe5Idx = WavePrefixSum(dot(1, kGe5));\n#endif\n    uint laneSkipIdx = WavePrefixSum(dot(1, skip));\n\n    // One-to-one mapping for the very last thread group\n    if(Gid.x == (g_local.DispatchDimX - 1) && Gid.y == (g_local.DispatchDimY - 1))\n    {\n        [unroll]\n        for(int i = 0; i < 4; i++)\n            WriteOutput(Gid.xy, dtID[i], gtID[i], result[i]);\n\n        return;\n    }\n\n    [unroll]\n    for(int i = 0; i < 4; i++)\n    {\n        if(kEq2[i])\n        {\n            uint prefixSumIn2x2 = 0;\n            for(int j = 0; j < i; j++)\n                prefixSumIn2x2 += kEq2[j];\n\n            uint2 mappedGTid = GroupIndexToGTid(kEq2BaseOffset + lanekEq2Idx + prefixSumIn2x2);\n            WriteOutput(Gid.xy, dtID[i], mappedGTid, result[i]);\n        }\n#if COMPACTION_ONLY == 1\n        else if(kGe3[i])\n        {\n            uint prefixSumIn2x2 = 0;\n            for(int j = 0; j < i; j++)\n                prefixSumIn2x2 += kGe3[j];\n\n            uint2 mappedGTid = GroupIndexToGTid(kGe3BaseOffset + lanekGe3Idx + prefixSumIn2x2);\n            WriteOutput(Gid.xy, dtID[i], mappedGTid, result[i]);\n        }\n#else\n        else if(kEq3[i])\n        {\n            uint prefixSumIn2x2 = 0;\n            for(int j = 0; j < i; j++)\n                prefixSumIn2x2 += kEq3[j];\n\n            uint2 mappedGTid = GroupIndexToGTid(kEq3BaseOffset + lanekEq3Idx + prefixSumIn2x2);\n            WriteOutput(Gid.xy, dtID[i], mappedGTid, result[i]);\n        }\n        else if(kEq4[i])\n        {\n            uint prefixSumIn2x2 = 0;\n            for(int j = 0; j < i; j++)\n                prefixSumIn2x2 += kEq4[j];\n\n            uint2 mappedGTid = GroupIndexToGTid(kEq4BaseOffset + lanekEq4Idx + prefixSumIn2x2);\n            WriteOutput(Gid.xy, dtID[i], mappedGTid, result[i]);\n        }\n        else if(kGe5[i])\n        {\n            uint prefixSumIn2x2 = 0;\n            for(int j = 0; j < i; j++)\n                prefixSumIn2x2 += kGe5[j];\n\n            uint2 mappedGTid = GroupIndexToGTid(kGe5BaseOffset + lanekGe5Idx + prefixSumIn2x2);\n            WriteOutput(Gid.xy, dtID[i], mappedGTid, result[i]);\n        }\n#endif\n        else if(skip[i])\n        {\n            uint prefixSumIn2x2 = 0;\n            for(int j = 0; j < i; j++)\n                prefixSumIn2x2 += skip[j];\n\n            uint2 mappedGTid = GroupIndexToGTid(skipBaseOffset + laneSkipIdx + prefixSumIn2x2);\n            WriteOutput(Gid.xy, dtID[i], mappedGTid, result[i]);\n        }\n    }\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/ReSTIR_PT_SpatialSearch.hlsl",
    "content": "#include \"../IndirectLighting_Common.h\"\n#include \"Util.hlsli\"\n#include \"SampleSet.hlsli\"\n\n#define THREAD_GROUP_SWIZZLING 1\n#define SPATIAL_SEARCH_RADIUS 15\n\nusing namespace RPT_Util;\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cb_ReSTIR_PT_SpatialSearch> g_local : register(b1);\n\n//--------------------------------------------------------------------------------------\n// Utility Functions\n//--------------------------------------------------------------------------------------\n\nint2 FindSpatialNeighbor(uint2 DTid, float3 pos, float3 normal, bool metallic, float roughness,\n    bool transmissive, float viewDepth, float radius, inout RNG rng)\n{\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n\n    // rotate sample sequence per pixel\n    const float u0 = rng.Uniform();\n    const uint offset = rng.UniformUint();\n    const float theta = u0 * TWO_PI;\n    const float sinTheta = sin(theta);\n    const float cosTheta = cos(theta);\n    const int2 renderDim = int2((int)g_frame.RenderWidth, (int)g_frame.RenderHeight);\n\n    [loop]\n    for (uint i = 0; i < 3; i++)\n    {\n        const float2 sampleUV = k_samples[(offset + i) & (SAMPLE_SET_SIZE - 1)];\n        float2 rotated = float2(\n            dot(sampleUV, float2(cosTheta, -sinTheta)),\n            dot(sampleUV, float2(sinTheta, cosTheta)));\n        rotated *= radius;\n        const int2 samplePosSS = round(float2(DTid) + rotated);\n\n        if (!Math::IsWithinBounds(samplePosSS, renderDim))\n            continue;\n\n        if(samplePosSS.x == DTid.x && samplePosSS.y == DTid.y)\n            continue;\n\n        const float2 sampleMR = g_metallicRoughness[samplePosSS];\n        GBuffer::Flags sampleFlags = GBuffer::DecodeMetallic(sampleMR.x);\n\n        if(sampleFlags.invalid || sampleFlags.emissive)\n            continue;\n        if(metallic != sampleFlags.metallic)\n            continue;\n        if(transmissive != sampleFlags.transmissive)\n            continue;\n        if(abs(sampleMR.y - roughness) > MAX_ROUGHNESS_DIFF_SPATIAL_REUSE)\n            continue;\n\n        const float sampleDepth = g_depth[samplePosSS];\n        const float3 samplePos = Math::WorldPosFromScreenSpace(samplePosSS, renderDim,\n            sampleDepth, g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrViewInv, \n            g_frame.CurrCameraJitter);\n        const float3 sampleNormal = Math::DecodeUnitVector(g_normal[samplePosSS]);\n\n        if (!RPT_Util::PlaneHeuristic(samplePos, normal, pos, viewDepth, 0.01))\n            continue;\n        if(dot(sampleNormal, normal) < MIN_NORMAL_SIMILARITY_SPATIAL_REUSE)\n            continue;\n\n        return samplePosSS;\n    }\n\n    return UINT16_MAX;\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(RESTIR_PT_SPATIAL_SEARCH_GROUP_DIM_X, RESTIR_PT_SPATIAL_SEARCH_GROUP_DIM_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID)\n{\n#if THREAD_GROUP_SWIZZLING == 1\n    uint2 swizzledGid;\n\n    const uint2 swizzledDTid = Common::SwizzleThreadGroup(DTid, Gid, GTid, \n        uint2(RESTIR_PT_SPATIAL_SEARCH_GROUP_DIM_X, RESTIR_PT_SPATIAL_SEARCH_GROUP_DIM_Y),\n        g_local.DispatchDimX_NumGroupsInTile & 0xffff, \n        RESTIR_PT_TILE_WIDTH, \n        RESTIR_PT_LOG2_TILE_WIDTH, \n        g_local.DispatchDimX_NumGroupsInTile >> 16,\n        swizzledGid);\n#else\n    const uint2 swizzledDTid = DTid.xy;\n    const uint2 swizzledGid = Gid.xy;\n#endif\n\n    if (swizzledDTid.x >= g_frame.RenderWidth || swizzledDTid.y >= g_frame.RenderHeight)\n        return;\n\n    GBUFFER_METALLIC_ROUGHNESS g_metallicRoughness = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset +\n        GBUFFER_OFFSET::METALLIC_ROUGHNESS];\n    const float2 mr = g_metallicRoughness[swizzledDTid];\n    GBuffer::Flags flags = GBuffer::DecodeMetallic(mr.x);\n\n    if (flags.invalid || flags.emissive)\n        return;\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::DEPTH];\n    const float viewDepth = g_depth[swizzledDTid];\n    const float3 pos = Math::WorldPosFromScreenSpace(swizzledDTid,\n        float2(g_frame.RenderWidth, g_frame.RenderHeight), viewDepth, \n        g_frame.TanHalfFOV, g_frame.AspectRatio, g_frame.CurrViewInv, \n        g_frame.CurrCameraJitter);\n\n    GBUFFER_NORMAL g_normal = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + \n        GBUFFER_OFFSET::NORMAL];\n    const float3 normal = Math::DecodeUnitVector(g_normal[swizzledDTid]);\n\n    // const uint16 passIdx = uint16((g_local.Packed >> 12) & 0x3);\n    const uint16 passIdx = 0;\n    RNG rng = RNG::Init(RNG::PCG3d(uint3(swizzledDTid, g_frame.FrameNum + passIdx)).xy, \n        g_frame.FrameNum);\n    const uint16_t scale = (uint16_t)1;\n\n    const int2 neighbor = FindSpatialNeighbor(swizzledDTid, pos, normal, flags.metallic, \n        mr.y, flags.transmissive, viewDepth, SPATIAL_SEARCH_RADIUS * scale, rng);\n\n    // [-R_max, +R_max]\n    int2 mapped = neighbor - (int2)swizzledDTid;\n    // [SPATIAL_NEIGHBOR_OFFSET - R_max, SPATIAL_NEIGHBOR_OFFSET + R_max]\n    mapped = neighbor.x == UINT16_MAX ? UINT8_MAX : mapped + RPT_Util::SPATIAL_NEIGHBOR_OFFSET;\n\n    // Note: SPATIAL_NEIGHBOR_OFFSET must be >= R_max as output texture is unsigned\n    RWTexture2D<uint2> g_out = ResourceDescriptorHeap[g_local.OutputDescHeapIdx];\n    g_out[swizzledDTid] = mapped;\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Reservoir.hlsli",
    "content": "#ifndef RESTIR_PT_RESERVOIR_H\n#define RESTIR_PT_RESERVOIR_H\n\n#include \"../IndirectLighting_Common.h\"\n#include \"Shift.hlsli\"\n\nnamespace RPT_Util\n{\n    struct Reservoir\n    {\n        static Reservoir Init()\n        {\n            Reservoir res;\n            res.rc = Reconnection::Init();\n            res.w_sum = 0;\n            res.W = 0;\n            res.M = 0;\n            res.target = 0;\n\n            return res;\n        }\n        \n        bool Update(float weight, float3 target, Reconnection rc, inout RNG rng)\n        {\n            if(isnan(weight) || isinf(weight))\n                return false;\n\n            this.M += 1;\n\n            if(weight == 0)\n                return false;\n\n            this.w_sum += weight;\n\n            if (rng.Uniform() < (weight / this.w_sum))\n            {\n                this.rc.Clear();\n                this.rc = rc;\n                this.target = target;\n\n                return true;\n            }\n\n            return false;\n        }\n\n        template<typename TexC, typename TexD, typename TexE, typename TexG>\n        void LoadCase1(uint2 DTid, TexC g_inC, TexD g_inD, TexE g_inE, TexG g_inG)\n        {\n            uint4 inC = g_inC[DTid];\n            uint4 inD = g_inD[DTid];\n            half inE = g_inE[DTid];\n            uint inG = g_inG[DTid].y;\n\n            this.rc.partialJacobian = asfloat(inC.x);\n            this.rc.seed_replay = inC.y;\n            this.rc.ID = inC.z;\n            this.rc.w_k_lightNormal_w_sky = Math::DecodeOct32(Math::UnpackUintToUint16(inD.z));\n            this.rc.x_k = float3(asfloat(inC.w), asfloat(inD.xy));\n            this.rc.meshIdx = inG;\n\n            uint16_t2 lh = uint16_t2(inD.w & 0xffff, inD.w >> 16);\n            this.rc.L = half3(asfloat16(lh), inE);\n        }\n\n        template<bool Emissive, typename TexC, typename TexD, typename TexE, typename TexF, typename TexG>\n        void LoadCase2(uint2 DTid, TexC g_inC, TexD g_inD, TexE g_inE, TexF g_inF, TexG g_inG)\n        {\n            uint4 inC = g_inC[DTid];\n            uint4 inD = g_inD[DTid];\n\n            this.rc.partialJacobian = asfloat(inC.x);\n            this.rc.seed_replay = inC.y;\n            this.rc.ID = inC.z;\n            this.rc.x_k = float3(asfloat(inC.w), asfloat(inD.xy));\n\n            if(Emissive)\n            {\n                half inE = g_inE[DTid];\n                float2 inF = g_inF[DTid];\n                uint2 inG = g_inG[DTid];\n\n                uint16_t2 lh = uint16_t2(inD.w & 0xffff, inD.w >> 16);\n                this.rc.L = half3(asfloat16(lh), inE);\n                this.rc.w_k_lightNormal_w_sky = Math::DecodeOct32(Math::UnpackUintToUint16(inD.z));\n                this.rc.lightPdf = inF.x;\n                this.rc.dwdA = inF.y;\n                this.rc.seed_nee = inG.x;\n                this.rc.meshIdx = inG.y;\n            }\n            else\n            {\n                if(this.rc.lt_k_plus_1 == Light::TYPE::SKY)\n                {\n                    this.rc.w_k_lightNormal_w_sky = Math::DecodeOct32(Math::UnpackUintToUint16(inD.z));\n                    this.rc.seed_nee = inD.w;\n                }\n                \n                this.rc.meshIdx = g_inG[DTid].y;\n            }\n        }\n\n        template<bool Emissive, typename TexC, typename TexD, typename TexE, typename TexF>\n        void LoadCase3(uint2 DTid, TexC g_inC, TexD g_inD, TexE g_inE, TexF g_inF)\n        {\n            uint4 inC = Emissive ? g_inC[DTid] : uint4(g_inC[DTid].xyz, 0);\n            uint4 inD = Emissive ? g_inD[DTid] : uint4(0.xx, g_inD[DTid].zw);\n\n            this.rc.seed_replay = inC.y;\n            this.rc.ID = inC.z;\n\n            if(Emissive)\n            {\n                this.rc.partialJacobian = this.rc.lobe_k_min_1 == BSDF::LOBE::ALL ? \n                    1.0f : asfloat(inC.x);\n\n                half inE = g_inE[DTid];\n                float inF = g_inF[DTid].x;\n\n                this.rc.x_k = float3(asfloat(inC.w), asfloat(inD.xy));\n\n                uint16_t2 lh = uint16_t2(inD.w & 0xffff, inD.w >> 16);\n                this.rc.L = half3(asfloat16(lh), inE);\n                this.rc.lightPdf = inF.x;\n                this.rc.seed_nee = inC.x;\n                // light normal\n                this.rc.w_k_lightNormal_w_sky = Math::DecodeOct32(Math::UnpackUintToUint16(inD.z));\n            }\n            else\n            {\n                this.rc.partialJacobian = asfloat(inC.x);\n\n                if(this.rc.lt_k == Light::TYPE::SKY)\n                {\n                    this.rc.w_k_lightNormal_w_sky = Math::DecodeOct32(Math::UnpackUintToUint16(inD.z));\n                    this.rc.seed_nee = inD.w;\n                }\n            }\n        }\n\n        void UnpackMetadata(uint3 metadata)\n        {\n            uint16_t k = uint16_t(metadata.x & 0xf);\n            this.rc.k = k == Reconnection::EMPTY ? k : k + (uint16_t)2;\n            this.rc.lobe_k_min_1 = BSDF::LobeFromValue(metadata.y & 0x7);\n            this.rc.lobe_k = BSDF::LobeFromValue((metadata.y >> 3) & 0x7);\n            this.rc.lt_k = Light::TypeFromValue((metadata.y >> 6) & 0x3);\n            this.rc.lt_k_plus_1 = Light::TypeFromValue(metadata.z & 0x3);\n            this.rc.x_k_in_motion = metadata.z >> 2;\n            this.M = (uint16_t)(metadata.x >> 4);\n        }\n\n        void UnpackMetadataX(uint metadata)\n        {\n            uint16_t k = uint16_t(metadata.x & 0xf);\n            this.rc.k = k == Reconnection::EMPTY ? k : k + (uint16_t)2;\n            this.M = (uint16_t)(metadata.x >> 4);\n        }\n\n        template<typename TexA>\n        static Reservoir Load_Metadata(uint2 DTid, uint inputAIdx)\n        {\n            TexA g_inA = ResourceDescriptorHeap[inputAIdx];\n\n            Reservoir ret;\n            ret.UnpackMetadata(g_inA[DTid].xyz);\n\n            return ret;\n        }\n\n        template<typename TexA>\n        static Reservoir Load_MetadataX(uint2 DTid, uint inputAIdx)\n        {\n            TexA g_inA = ResourceDescriptorHeap[inputAIdx];\n\n            Reservoir ret;\n            ret.UnpackMetadata(g_inA[DTid].x);\n\n            return ret;\n        }\n\n        template<typename TexA, typename TexB>\n        static Reservoir Load_NonReconnection(uint2 DTid, uint inputAIdx, uint inputBIdx)\n        {\n            TexA g_inA = ResourceDescriptorHeap[inputAIdx];\n            TexB g_inB = ResourceDescriptorHeap[inputBIdx];\n\n            Reservoir ret;\n            ret.UnpackMetadata(g_inA[DTid].xyz);\n\n            float2 inB = g_inB[DTid];\n            ret.w_sum = inB.x;\n            ret.W = inB.y;\n\n            return ret;\n        }\n\n        template<bool Emissive, typename TexC, typename TexD, typename TexE, typename TexF, typename TexG>\n        void Load_Reconnection(uint2 DTid, uint inputCIdx, uint inputDIdx, uint inputEIdx, \n            uint inputFIdx, uint inputGIdx)\n        {\n            TexC g_inC = ResourceDescriptorHeap[inputCIdx];\n            TexD g_inD = ResourceDescriptorHeap[inputDIdx];\n            TexE g_inE = ResourceDescriptorHeap[inputEIdx];\n            TexF g_inF = ResourceDescriptorHeap[inputFIdx];\n            TexG g_inG = ResourceDescriptorHeap[inputGIdx];\n\n            if(this.rc.IsCase1())\n                this.LoadCase1<TexC, TexD, TexE>(DTid, g_inC, g_inD, g_inE, g_inG);\n            else if(this.rc.IsCase2())\n                this.LoadCase2<Emissive, TexC, TexD, TexE, TexF, TexG>(DTid, g_inC, g_inD, g_inE, g_inF, g_inG);\n            else\n                this.LoadCase3<Emissive, TexC, TexD, TexE, TexF>(DTid, g_inC, g_inD, g_inE, g_inF);\n        }\n\n        template<bool Emissive, typename TexA, typename TexB, typename TexC, typename TexD, \n            typename TexE, typename TexF, typename TexG>\n        static Reservoir Load(uint2 DTid, uint inputAIdx, uint inputBIdx, uint inputCIdx, \n            uint inputDIdx, uint inputEIdx, uint inputFIdx, uint inputGIdx)\n        {\n            TexA g_inA = ResourceDescriptorHeap[inputAIdx];\n            TexB g_inB = ResourceDescriptorHeap[inputBIdx];\n            TexC g_inC = ResourceDescriptorHeap[inputCIdx];\n            TexD g_inD = ResourceDescriptorHeap[inputDIdx];\n            TexE g_inE = ResourceDescriptorHeap[inputEIdx];\n            TexF g_inF = ResourceDescriptorHeap[inputFIdx];\n            TexG g_inG = ResourceDescriptorHeap[inputGIdx];\n\n            Reservoir ret;\n            ret.UnpackMetadata(g_inA[DTid].xyz);\n\n            float2 inB = g_inB[DTid];\n            ret.w_sum = inB.x;\n            ret.W = inB.y;\n\n            if(ret.rc.Empty())\n                return ret;\n  \n            if(ret.rc.IsCase1())\n                ret.LoadCase1<TexC, TexD, TexE >(DTid, g_inC, g_inD, g_inE, g_inG);\n            else if(ret.rc.IsCase2())\n                ret.LoadCase2<Emissive, TexC, TexD, TexE, TexF, TexG >(DTid, g_inC, g_inD, g_inE, g_inF, g_inG);\n            else\n                ret.LoadCase3<Emissive, TexC, TexD, TexE, TexF >(DTid, g_inC, g_inD, g_inE, g_inF);\n\n            return ret;\n        }\n\n        void LoadTarget(uint2 DTid, uint uavIdx)\n        {\n            RWTexture2D<float4> g_target = ResourceDescriptorHeap[uavIdx];\n            this.target = g_target[DTid].xyz;\n        }\n\n        void LoadWSum(uint2 DTid, uint inputBIdx)\n        {\n            RWTexture2D<float2> g_inB = ResourceDescriptorHeap[inputBIdx];\n            this.w_sum = g_inB[DTid].x;\n        }\n\n        static float LoadW(uint2 DTid, uint inputBIdx)\n        {\n            RWTexture2D<float2> g_inB = ResourceDescriptorHeap[inputBIdx];\n            return g_inB[DTid].y;\n        }\n\n        void WriteCase1(uint2 DTid, RWTexture2D<uint4> g_outC, RWTexture2D<uint4> g_outD, \n            RWTexture2D<half> g_outE, RWTexture2D<uint2> g_outG)\n        {\n            g_outC[DTid] = uint4(asuint(this.rc.partialJacobian), this.rc.seed_replay, \n                this.rc.ID, asuint(this.rc.x_k.x));\n\n            uint16_t2 temp = Math::EncodeOct32(this.rc.w_k_lightNormal_w_sky);\n            uint w_k_encoded = temp.x | (uint(temp.y) << 16);\n\n            half2 lh = this.rc.L.rg;\n            g_outD[DTid] = uint4(asuint(this.rc.x_k.yz), w_k_encoded, \n                asuint16(lh.r) | (uint(asuint16(lh.g)) << 16));\n            g_outE[DTid] = this.rc.L.b;\n            g_outG[DTid].y = this.rc.meshIdx;\n        }\n\n        template<bool Emissive>\n        void WriteCase2(uint2 DTid, RWTexture2D<uint4> g_outC, RWTexture2D<uint4> g_outD, \n            RWTexture2D<half> g_outE, RWTexture2D<float2> g_outF, RWTexture2D<uint2> g_outG)\n        {\n            g_outC[DTid] = uint4(asuint(this.rc.partialJacobian), this.rc.seed_replay, \n                this.rc.ID, asuint(this.rc.x_k.x));\n\n            uint16_t2 temp = Math::EncodeOct32(this.rc.w_k_lightNormal_w_sky);\n            uint w_k_encoded = temp.x | (uint(temp.y) << 16);\n\n            if(Emissive)\n            {\n                half2 lh = this.rc.L.rg;\n                g_outD[DTid] = uint4(asuint(this.rc.x_k.yz), w_k_encoded, \n                    asuint16(lh.r) | (uint(asuint16(lh.g)) << 16));\n                g_outE[DTid] = this.rc.L.b;\n                g_outF[DTid] = float2(this.rc.lightPdf, this.rc.dwdA);\n                g_outG[DTid] = uint2(this.rc.seed_nee, this.rc.meshIdx);\n            }\n            else\n            {\n                if(this.rc.lt_k_plus_1 == Light::TYPE::SKY)\n                    g_outD[DTid] = uint4(asuint(this.rc.x_k.yz), w_k_encoded, this.rc.seed_nee);\n                else\n                    g_outD[DTid].xy = asuint(this.rc.x_k.yz);\n\n                g_outG[DTid].y = this.rc.meshIdx;\n            }\n        }\n\n        template<bool Emissive>\n        void WriteCase3(uint2 DTid, RWTexture2D<uint4> g_outC, RWTexture2D<uint4> g_outD, \n            RWTexture2D<half> g_outE, RWTexture2D<float2> g_outF)\n        {\n            // w_sky or light normal\n            uint16_t2 temp = Math::EncodeOct32(this.rc.w_k_lightNormal_w_sky);\n            uint w_k_encoded = temp.x | (uint(temp.y) << 16);\n\n            if(Emissive)\n            {\n                // NEE seed is only needed for light sampling, jacobian is only\n                // needed for BSDF sampling\n                uint v = this.rc.lobe_k_min_1 == BSDF::LOBE::ALL ? this.rc.seed_nee :\n                    asuint(this.rc.partialJacobian);\n\n                g_outC[DTid] = uint4(v, this.rc.seed_replay, this.rc.ID, asuint(this.rc.x_k.x));\n\n                half2 lh = this.rc.L.rg;\n                g_outD[DTid] = uint4(asuint(this.rc.x_k.yz), w_k_encoded, \n                    asuint16(lh.r) | uint(asuint16(lh.g)) << 16);\n                g_outE[DTid] = this.rc.L.b;\n                g_outF[DTid].x = this.rc.lightPdf;\n            }\n            else\n            {\n                g_outC[DTid].xyz = uint3(asuint(this.rc.partialJacobian), this.rc.seed_replay, this.rc.ID);\n\n                if(this.rc.lt_k == Light::TYPE::SKY)\n                    g_outD[DTid].zw = uint2(w_k_encoded, this.rc.seed_nee);\n            }\n        }\n\n        void WriteReservoirData(uint2 DTid, uint outputAIdx, uint outputBIdx, uint M_max)\n        {\n            RWTexture2D<uint4> g_outA = ResourceDescriptorHeap[outputAIdx];\n            RWTexture2D<float2> g_outB = ResourceDescriptorHeap[outputBIdx];\n\n            uint k = this.rc.Empty() ? this.rc.k : max(this.rc.k, 2) - 2;\n            uint m = min(this.M, M_max);\n\n            g_outA[DTid].x = k | (m << 4);\n            g_outB[DTid] = float2(this.w_sum, this.W);\n        }\n\n        // Skips w_sum\n        void WriteReservoirData2(uint2 DTid, uint outputAIdx, uint outputBIdx, uint M_max)\n        {\n            RWTexture2D<uint4> g_outA = ResourceDescriptorHeap[outputAIdx];\n            RWTexture2D<float2> g_outB = ResourceDescriptorHeap[outputBIdx];\n\n            uint k = this.rc.Empty() ? this.rc.k : max(this.rc.k, 2) - 2;\n            uint m = min(this.M, M_max);\n\n            g_outA[DTid].x = k | (m << 4);\n            g_outB[DTid].y = this.W;\n        }\n\n        void WriteWSum(uint2 DTid, uint outputBIdx)\n        {\n            RWTexture2D<float2> g_outB = ResourceDescriptorHeap[outputBIdx];\n            g_outB[DTid].x = this.w_sum;\n        }\n\n        void WriteTarget(uint2 DTid, uint uavIdx)\n        {\n            RWTexture2D<float4> g_target = ResourceDescriptorHeap[uavIdx];\n            this.target = Math::Sanitize(this.target);\n            g_target[DTid].xyz = this.target;\n        }\n\n        template<bool Emissive>\n        void Write(uint2 DTid, uint outputAIdx, uint outputBIdx, uint outputCIdx, \n            uint outputDIdx, uint outputEIdx, uint outputFIdx, uint outputGIdx, \n            uint M_max = 0)\n        {\n            // (metadata)\n            RWTexture2D<uint4> g_outA = ResourceDescriptorHeap[outputAIdx];\n            // (w_sum, W)\n            RWTexture2D<float2> g_outB = ResourceDescriptorHeap[outputBIdx];\n            // (jacobian, seed_replay, ID, x_k.x)\n            RWTexture2D<uint4> g_outC = ResourceDescriptorHeap[outputCIdx];\n            // (x_k.yz, w_k/w_sky/lightNormal, L.rg | seed_nee)\n            RWTexture2D<uint4> g_outD = ResourceDescriptorHeap[outputDIdx];\n            // (L.b)\n            RWTexture2D<half> g_outE = ResourceDescriptorHeap[outputEIdx];\n            // (lightPdf, dwdA)\n            RWTexture2D<float2> g_outF = ResourceDescriptorHeap[outputFIdx];\n            // (seed_nee, meshIdx)\n            RWTexture2D<uint2> g_outG = ResourceDescriptorHeap[outputGIdx];\n\n            // A\n            uint m = M_max == 0 ? this.M : min(this.M, M_max);\n            uint k = this.rc.Empty() ? this.rc.k : max(this.rc.k, 2) - 2;\n\n            uint3 metadata;\n            metadata.x = k | (m << 4);\n            metadata.y = BSDF::LobeToValue(this.rc.lobe_k_min_1) |\n                (BSDF::LobeToValue(this.rc.lobe_k) << 3) |\n                (Light::TypeToValue(this.rc.lt_k) << 6);\n            metadata.z = Light::TypeToValue(this.rc.lt_k_plus_1) | \n                (uint(this.rc.x_k_in_motion) << 2);\n            g_outA[DTid].xyz = metadata;\n\n            // B\n            this.w_sum = Math::Sanitize(this.w_sum);\n            this.W = Math::Sanitize(this.W);\n            g_outB[DTid] = float2(this.w_sum, this.W);\n\n            if(this.rc.Empty())\n                return;\n\n            // All cases:\n            //  - metadata\n            //  - Jacobian\n            //  - seed_replay\n\n            // Case 1) x_k and x_{k + 1} not on a light source\n            //  - x_k\n            //  - ID\n            //  - L\n            //  - w_k_lightNormal_w_sky (= w_k)\n            if(this.rc.IsCase1())\n                this.WriteCase1(DTid, g_outC, g_outD, g_outE, g_outG);\n\n            // Case 2) x_{k + 1} on a light source\n            //  - x_k\n            //  - ID\n            //  - lightPdf: if x_{k + 1} is emissive\n            //  - rng_nee: if x_{k + 1} is on sky\n            //  - L: if x_{k + 1} is emissive\n            //  - w_k_lightNormal_w_sky: if x_{k + 1} is sky (= w_sky) or emissive (= w_k)\n            else if(this.rc.IsCase2())\n                this.WriteCase2<Emissive>(DTid, g_outC, g_outD, g_outE, g_outF, g_outG);\n\n            // Case 3) x_k on a light source\n            //  - x_k: if on emissive\n            //  - ID: if on emissive (= lightID)\n            //  - lightPdf: if x_k is emissive\n            //  - rng_nee: if x_k is on sky\n            //  - L: if x_k is emissive\n            //  - w_k_lightNormal_w_sky: if x_k on sky (= w_sky) or is emissive (= lightNormal)\n            else\n                this.WriteCase3<Emissive>(DTid, g_outC, g_outD, g_outE, g_outF);\n        }\n\n        float w_sum;\n        float W;\n        float3 target;\n        Reconnection rc;\n        uint16_t M;\n    };\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/SampleSet.hlsli",
    "content": "#ifndef RESTIR_PT_SAMPLE_SET_H\n#define RESTIR_PT_SAMPLE_SET_H\n\nnamespace RPT_Util\n{\n    static const int SAMPLE_SET_SIZE = 512;\n\n    static const half2 k_samples[SAMPLE_SET_SIZE] = \n    {\n        half2(-0.9201498, -0.22287),\n        half2(-0.8605048, -0.299254),\n        half2(-0.935414, -0.327428),\n        half2(-0.885292, -0.144436),\n        half2(-0.9692278, -0.163568),\n        half2(-0.8505626, -0.21982),\n        half2(-0.804102, -0.267252),\n        half2(-0.8850916, -0.418868),\n        half2(-0.761426, -0.143982),\n        half2(-0.734088, -0.207592),\n        half2(-0.791622, -0.456888),\n        half2(-0.8161692, -0.3705),\n        half2(-0.8558564, -0.515092),\n        half2(-0.75746, -0.321792),\n        half2(-0.667992, -0.121056),\n        half2(-0.630718, -0.266118),\n        half2(-0.666464, -0.200634),\n        half2(-0.8556624, -0.07551003),\n        half2(-0.757414, -0.07336599),\n        half2(-0.796542, -0.559626),\n        half2(-0.714384, -0.386646),\n        half2(-0.768648, 0.01476395),\n        half2(-0.70181, -0.04250199),\n        half2(-0.854348, -0.01258802),\n        half2(-0.685494, 0.02367401),\n        half2(-0.74702, 0.09159994),\n        half2(-0.8366696, 0.110682),\n        half2(-0.68451, -0.568832),\n        half2(-0.73164, -0.624556),\n        half2(-0.735386, -0.520398),\n        half2(-0.831311, 0.19481),\n        half2(-0.8912344, 0.1471519),\n        half2(-0.9063584, 0.05636597),\n        half2(-0.760204, 0.16782),\n        half2(-0.542522, -0.203472),\n        half2(-0.589684, -0.381952),\n        half2(-0.613702, -0.1671),\n        half2(-0.571606, -0.298152),\n        half2(-0.674462, -0.32759),\n        half2(-0.661386, -0.652678),\n        half2(-0.70894, -0.696096),\n        half2(-0.62268, -0.578828),\n        half2(-0.467232, -0.336824),\n        half2(-0.714028, -0.454092),\n        half2(-0.645236, -0.507064),\n        half2(-0.517362, -0.53032),\n        half2(-0.57095, -0.645814),\n        half2(-0.573734, -0.489554),\n        half2(-0.9724408, 0.02568603),\n        half2(-0.9180296, -0.03604001),\n        half2(-0.958289, 0.13588),\n        half2(-0.582116, -0.030074),\n        half2(-0.692654, 0.1263781),\n        half2(-0.584858, 0.06003201),\n        half2(-0.644652, 0.07999599),\n        half2(-0.579248, -0.737116),\n        half2(-0.508156, -0.717582),\n        half2(-0.505584, -0.468338),\n        half2(-0.63386, -0.428028),\n        half2(-0.421308, -0.467364),\n        half2(-0.45103, -0.554224),\n        half2(-0.527104, -0.403584),\n        half2(-0.42737, -0.22306),\n        half2(-0.53541, -0.08209401),\n        half2(-0.485534, -0.258902),\n        half2(-0.470866, -0.143792),\n        half2(-0.515748, 0.04130995),\n        half2(-0.451366, -0.003494024),\n        half2(-0.461378, -0.066962),\n        half2(-0.60701, -0.09158802),\n        half2(-0.9245856, 0.246538),\n        half2(-0.61713, 0.180802),\n        half2(-0.563824, 0.133636),\n        half2(-0.310486, -0.263414),\n        half2(-0.374002, -0.1797),\n        half2(-0.395084, -0.281566),\n        half2(-0.540702, 0.19409),\n        half2(-0.702792, 0.2384959),\n        half2(-0.631386, 0.252888),\n        half2(-0.50028, 0.144184),\n        half2(-0.533226, 0.260294),\n        half2(-0.717886, -0.26959),\n        half2(-0.473436, 0.228022),\n        half2(-0.42668, 0.324762),\n        half2(-0.60027, 0.35883),\n        half2(-0.505636, 0.327734),\n        half2(-0.329704, -0.06660998),\n        half2(-0.376518, -0.112962),\n        half2(-0.294102, -0.139424),\n        half2(-0.422844, -0.636036),\n        half2(-0.346264, -0.60195),\n        half2(-0.490772, -0.616714),\n        half2(-0.332182, -0.521046),\n        half2(-0.256624, -0.08134401),\n        half2(-0.250896, -0.556948),\n        half2(-0.326562, -0.437568),\n        half2(-0.240504, -0.492004),\n        half2(-0.64136, -0.752552),\n        half2(-0.652838, 0.32083),\n        half2(-0.517262, 0.438768),\n        half2(-0.674754, 0.4138221),\n        half2(-0.71923, 0.36831),\n        half2(-0.59027, 0.421306),\n        half2(-0.8530308, 0.25828),\n        half2(-0.8135734, 0.317878),\n        half2(-0.759636, 0.278758),\n        half2(-0.211034, -0.136436),\n        half2(-0.276278, -0.01447397),\n        half2(-0.150618, -0.03248799),\n        half2(-0.222516, -0.240512),\n        half2(-0.314602, -0.19939),\n        half2(-0.563116, -0.8159846),\n        half2(-0.336062, -0.328088),\n        half2(-0.405648, -0.361738),\n        half2(-0.8986644, 0.3355401),\n        half2(-0.463916, -0.409452),\n        half2(-0.446522, 0.4208699),\n        half2(-0.310628, 0.339512),\n        half2(-0.385762, 0.392682),\n        half2(-0.412586, 0.2454619),\n        half2(-0.33412, 0.272872),\n        half2(-0.458754, -0.867821),\n        half2(-0.490806, -0.783102),\n        half2(-0.211294, -0.335882),\n        half2(-0.852224, 0.3777),\n        half2(-0.9838775, -0.06605601),\n        half2(-0.24356, -0.627638),\n        half2(-0.18011, -0.592642),\n        half2(-0.180642, -0.522528),\n        half2(-0.55607, -0.579652),\n        half2(-0.405346, -0.775044),\n        half2(-0.11855, -0.167966),\n        half2(-0.154036, -0.09522998),\n        half2(-0.342064, -0.699674),\n        half2(-0.272628, -0.70013),\n        half2(-0.357726, -0.8204688),\n        half2(-0.415178, -0.70029),\n        half2(-0.294026, -0.78183),\n        half2(-0.07088798, -0.07783002),\n        half2(-0.07380998, -0.281718),\n        half2(-0.05423403, -0.157044),\n        half2(-0.143154, -0.240464),\n        half2(-0.01349998, -0.210624),\n        half2(-0.321204, 0.207706),\n        half2(-0.244388, 0.31991),\n        half2(-0.370286, 0.153814),\n        half2(-0.454868, 0.09060204),\n        half2(-0.768342, 0.431664),\n        half2(-0.267114, -0.8933438),\n        half2(-0.229946, -0.771626),\n        half2(-0.202472, -0.707426),\n        half2(-0.211388, -0.8643098),\n        half2(-0.198264, 0.38131),\n        half2(-0.27134, 0.430096),\n        half2(-0.130264, -0.8424898),\n        half2(-0.135996, -0.745296),\n        half2(-0.298568, 0.535174),\n        half2(-0.334546, 0.450016),\n        half2(-0.233688, 0.509284),\n        half2(-0.180412, 0.44221),\n        half2(-0.120444, -0.632764),\n        half2(-0.351448, -0.003167987),\n        half2(-0.06715798, -0.696366),\n        half2(-0.02329803, -0.610646),\n        half2(-0.112616, -0.536338),\n        half2(-0.26148, 0.15624),\n        half2(-0.38878, 0.08266199),\n        half2(-0.30076, 0.1029119),\n        half2(-0.43657, 0.157644),\n        half2(-0.601806, 0.522552),\n        half2(-0.541708, 0.499788),\n        half2(-0.237052, -0.40947),\n        half2(-0.176204, -0.429896),\n        half2(-0.294956, -0.380112),\n        half2(-0.362076, -0.92842),\n        half2(-0.164492, -0.9556782),\n        half2(-0.11435, -0.33696),\n        half2(-0.211474, 0.24431),\n        half2(-0.163144, 0.285322),\n        half2(-0.684186, 0.4976979),\n        half2(-0.8199862, 0.485778),\n        half2(-0.760328, 0.52891),\n        half2(-0.06094199, -0.9267842),\n        half2(-0.05698001, -0.770906),\n        half2(-0.061234, -0.863679),\n        half2(-0.04783398, -0.9879191),\n        half2(-0.230666, 0.06458604),\n        half2(-0.07945198, -0.01420403),\n        half2(-0.09371001, 0.06743205),\n        half2(-0.158176, 0.04387796),\n        half2(-0.213246, -0.01217002),\n        half2(0.050704, -0.146266),\n        half2(-0.01661998, -0.04312801),\n        half2(0.001016021, -0.9438242),\n        half2(-0.04842001, -0.545376),\n        half2(-0.05697799, -0.48302),\n        half2(-0.108662, -0.429012),\n        half2(-0.467986, 0.57118),\n        half2(-0.548004, 0.564576),\n        half2(-0.42474, 0.4833781),\n        half2(-0.646846, 0.61087),\n        half2(-0.7318, 0.5997601),\n        half2(-0.163948, 0.16313),\n        half2(-0.03503799, -0.393308),\n        half2(-0.590376, 0.645046),\n        half2(-0.441582, 0.660248),\n        half2(-0.398312, 0.605168),\n        half2(-0.01240402, 0.02911997),\n        half2(-0.02350998, 0.12702),\n        half2(-0.07578802, 0.190534),\n        half2(0.01185405, -0.8300228),\n        half2(-0.001230001, -0.105818),\n        half2(0.06173801, 0.01206803),\n        half2(0.09921598, -0.07415801),\n        half2(0.08428597, -0.851013),\n        half2(0.07176399, -0.9781068),\n        half2(0.098876, -0.9214686),\n        half2(0.05050004, -0.767196),\n        half2(0.005470037, -0.684122),\n        half2(-0.363274, 0.539108),\n        half2(0.166608, -0.8037344),\n        half2(0.07178605, -0.667308),\n        half2(0.144348, -0.694232),\n        half2(-0.330414, 0.595612),\n        half2(-0.3544, 0.660198),\n        half2(-0.872762, 0.447858),\n        half2(-0.223916, 0.660122),\n        half2(-0.251884, 0.5812221),\n        half2(0.04538596, -0.415166),\n        half2(0.03422999, -0.501266),\n        half2(0.216496, -0.695394),\n        half2(0.19909, -0.605788),\n        half2(0.130834, -0.608458),\n        half2(0.234418, -0.755522),\n        half2(0.291218, -0.599274),\n        half2(0.297754, -0.74472),\n        half2(0.3335921, -0.65972),\n        half2(0.03672397, -0.583132),\n        half2(-0.010414, 0.252984),\n        half2(-0.07869399, 0.257808),\n        half2(0.30215, -0.8431478),\n        half2(0.3791521, -0.72016),\n        half2(0.3904901, -0.795258),\n        half2(0.09242594, -0.54858),\n        half2(0.109938, -0.472112),\n        half2(0.365038, -0.879176),\n        half2(0.458438, -0.788726),\n        half2(0.4735399, -0.8785866),\n        half2(0.443464, -0.694),\n        half2(0.546068, -0.79417),\n        half2(-0.175356, 0.54976),\n        half2(-0.292492, 0.733062),\n        half2(-0.127874, 0.717968),\n        half2(-0.203636, 0.74886),\n        half2(0.08473802, 0.128888),\n        half2(0.04651999, 0.223868),\n        half2(-0.627504, 0.69941),\n        half2(0.28304, -0.523336),\n        half2(0.3932019, -0.532062),\n        half2(0.386616, -0.59686),\n        half2(0.518986, -0.61073),\n        half2(0.536122, -0.720298),\n        half2(0.213954, -0.5191),\n        half2(0.2675281, -0.658588),\n        half2(-0.112646, 0.5126899),\n        half2(0.05360794, 0.295974),\n        half2(0.1257499, 0.264666),\n        half2(0.1593519, 0.21165),\n        half2(-0.51043, 0.66602),\n        half2(-0.07731402, 0.32783),\n        half2(0.001034021, 0.338634),\n        half2(-0.145036, 0.606104),\n        half2(-0.076814, 0.569872),\n        half2(-0.09723598, 0.44379),\n        half2(0.188614, 0.324384),\n        half2(0.234992, 0.255066),\n        half2(0.171452, 0.091856),\n        half2(0.24371, 0.133),\n        half2(0.125356, 0.3836679),\n        half2(0.09603798, -0.371602),\n        half2(0.003371954, -0.342468),\n        half2(0.14229, -0.416152),\n        half2(-0.286714, 0.64597),\n        half2(0.335946, 0.08452404),\n        half2(0.287936, 0.03582597),\n        half2(0.307024, 0.158214),\n        half2(0.121168, -0.143328),\n        half2(0.139468, -0.215092),\n        half2(0.03422999, -0.251846),\n        half2(-0.02272803, 0.400564),\n        half2(0.04618204, 0.428982),\n        half2(0.32736, 0.315708),\n        half2(0.3381619, 0.235924),\n        half2(0.261534, 0.333474),\n        half2(0.133536, 0.01976001),\n        half2(0.03028405, 0.08092403),\n        half2(0.326154, -0.455574),\n        half2(0.237762, -0.434876),\n        half2(0.191772, -0.174984),\n        half2(0.169304, -0.05324),\n        half2(0.218722, -0.102562),\n        half2(-0.412024, 0.773008),\n        half2(-0.49719, 0.73207),\n        half2(0.08303201, -0.294264),\n        half2(0.168342, -0.9303672),\n        half2(-0.689532, 0.6791641),\n        half2(0.2262501, -0.8703084),\n        half2(-0.530858, 0.797374),\n        half2(0.299046, 0.41266),\n        half2(0.228636, 0.44892),\n        half2(0.2761919, -0.9483468),\n        half2(-0.131616, 0.221554),\n        half2(-0.00298202, 0.47769),\n        half2(0.4392101, 0.06058598),\n        half2(0.44725, 0.126444),\n        half2(0.305398, -0.03423798),\n        half2(0.382746, 0.129148),\n        half2(0.377152, 0.02127802),\n        half2(0.22133, 0.03738201),\n        half2(0.236456, -0.04114401),\n        half2(0.5359859, 0.114616),\n        half2(0.437386, 0.201172),\n        half2(0.511994, 0.176156),\n        half2(0.509698, 0.03282797),\n        half2(0.429906, 0.3045239),\n        half2(0.5124, 0.29719),\n        half2(0.216962, -0.970028),\n        half2(0.197992, -0.3128),\n        half2(0.595786, 0.16646),\n        half2(0.548582, 0.236626),\n        half2(0.622654, 0.108608),\n        half2(0.59489, 0.036906),\n        half2(-0.244282, 0.800202),\n        half2(-0.368268, 0.728352),\n        half2(-0.35247, 0.79699),\n        half2(-0.153706, 0.838748),\n        half2(-0.007968009, 0.581422),\n        half2(0.10747, 0.47361),\n        half2(0.03462803, 0.5342081),\n        half2(0.1036381, 0.541122),\n        half2(0.3939019, -0.04312998),\n        half2(0.27156, -0.153948),\n        half2(0.3774559, -0.113384),\n        half2(0.100288, 0.607964),\n        half2(0.3480819, -0.390676),\n        half2(0.230486, -0.370876),\n        half2(-0.312444, 0.864266),\n        half2(-0.462524, 0.829812),\n        half2(-0.422188, 0.888016),\n        half2(0.430166, -0.479608),\n        half2(0.26842, -0.281008),\n        half2(0.303916, -0.339772),\n        half2(0.437812, -0.141666),\n        half2(0.504496, -0.04538399),\n        half2(0.165612, 0.496858),\n        half2(0.506646, -0.543712),\n        half2(-0.05008, 0.672394),\n        half2(0.02541196, 0.682722),\n        half2(0.171124, 0.56383),\n        half2(-0.3483, 0.927326),\n        half2(-0.252404, 0.952384),\n        half2(-0.221412, 0.89511),\n        half2(0.25933, 0.524606),\n        half2(0.230904, 0.5836281),\n        half2(0.212286, -0.248742),\n        half2(0.3507, 0.555078),\n        half2(0.35229, 0.476064),\n        half2(0.265376, 0.645682),\n        half2(-0.114292, 0.9402),\n        half2(-0.06626999, 0.872332),\n        half2(-0.07257199, 0.8062561),\n        half2(-0.178758, 0.958388),\n        half2(0.6116281, -0.707478),\n        half2(0.614316, -0.78804),\n        half2(0.376614, 0.639168),\n        half2(0.21768, 0.7476619),\n        half2(0.295512, 0.70201),\n        half2(0.193202, 0.6604559),\n        half2(0.589512, -0.450726),\n        half2(0.571386, -0.53326),\n        half2(0.523698, -0.46728),\n        half2(0.5919321, -0.622052),\n        half2(0.455608, -0.001984),\n        half2(0.669668, -0.654976),\n        half2(0.532144, -0.39384),\n        half2(0.429234, -0.397004),\n        half2(0.135736, -0.9850379),\n        half2(0.3307739, -0.180608),\n        half2(0.67255, 0.179316),\n        half2(0.629514, 0.24555),\n        half2(0.437106, -0.21069),\n        half2(0.003484011, 0.8227381),\n        half2(0.016698, 0.939054),\n        half2(0.633786, -0.03036797),\n        half2(0.66645, 0.05477798),\n        half2(-0.01531798, 0.754462),\n        half2(0.752876, 0.07338405),\n        half2(0.759442, 0.006559968),\n        half2(0.7237819, -0.04648399),\n        half2(-0.614492, 0.763148),\n        half2(0.386578, 0.748374),\n        half2(0.448494, 0.561312),\n        half2(0.4710799, 0.643508),\n        half2(0.468678, 0.713258),\n        half2(0.298858, 0.590348),\n        half2(0.3892, -0.276912),\n        half2(0.569672, -0.06406599),\n        half2(0.382326, 0.414042),\n        half2(-0.139272, 0.343856),\n        half2(0.59455, -0.355298),\n        half2(0.676762, -0.521828),\n        half2(0.698356, -0.450362),\n        half2(0.668244, -0.369604),\n        half2(0.518434, -0.134298),\n        half2(0.524574, -0.216296),\n        half2(0.43911, 0.469668),\n        half2(0.45047, 0.400512),\n        half2(0.85078, -0.04848599),\n        half2(0.820578, 0.105672),\n        half2(0.5245301, 0.55732),\n        half2(0.5708621, 0.634674),\n        half2(0.548702, 0.725116),\n        half2(0.208262, 0.389576),\n        half2(0.768062, -0.350102),\n        half2(0.6658421, -0.30199),\n        half2(0.647806, 0.7292221),\n        half2(0.6386679, 0.54922),\n        half2(0.626248, 0.664916),\n        half2(0.673718, 0.61326),\n        half2(0.6944259, 0.343796),\n        half2(0.719622, 0.276346),\n        half2(0.580112, 0.304034),\n        half2(0.3429019, 0.8038599),\n        half2(0.277624, 0.77072),\n        half2(0.557386, 0.41099),\n        half2(-0.05859399, 0.989776),\n        half2(0.10624, 0.953308),\n        half2(0.07485795, 0.858662),\n        half2(0.74632, 0.5952801),\n        half2(0.5869499, 0.489112),\n        half2(0.684582, 0.4374599),\n        half2(0.743016, 0.51248),\n        half2(0.6997139, -0.118888),\n        half2(0.6340261, -0.10181),\n        half2(0.7957439, -0.125826),\n        half2(0.186246, 0.880298),\n        half2(0.108664, 0.78416),\n        half2(0.657634, -0.186898),\n        half2(0.598642, -0.163714),\n        half2(0.923364, 0.03591204),\n        half2(0.955772, -0.08267403),\n        half2(0.871644, -0.150874),\n        half2(0.8404959, 0.02678204),\n        half2(0.07739794, 0.7184221),\n        half2(0.852258, -0.22803),\n        half2(0.7919101, -0.203192),\n        half2(0.747982, 0.209636),\n        half2(0.05236995, 0.9908479),\n        half2(0.206334, 0.9710521),\n        half2(0.722316, -0.197018),\n        half2(0.578024, -0.261164),\n        half2(0.256652, 0.90131),\n        half2(0.511034, 0.477772),\n        half2(0.617276, 0.3750499),\n        half2(0.543614, -0.315864),\n        half2(0.912778, -0.199326),\n        half2(0.758106, -0.265734),\n        half2(0.957918, -0.25561),\n        half2(0.860622, -0.294788),\n        half2(0.921806, -0.308392),\n        half2(0.6405981, -0.581798),\n        half2(0.732656, -0.605768),\n        half2(0.79361, -0.564378),\n        half2(0.755386, -0.479682),\n        half2(0.980396, 0.006135941),\n        half2(0.2132061, 0.813012),\n        half2(0.490056, 0.814008),\n        half2(0.55321, 0.80812),\n        half2(0.389986, 0.86865),\n        half2(0.462218, -0.307958),\n        half2(0.1505359, 0.71542),\n        half2(0.783438, 0.287814),\n        half2(0.759678, 0.390276),\n        half2(0.810156, 0.352222),\n        half2(0.806246, -0.423326),\n        half2(0.323728, 0.871244),\n        half2(0.421296, 0.814526),\n        half2(0.836796, 0.201496),\n        half2(0.889388, 0.3518161),\n        half2(0.86418, 0.259586),\n        half2(0.365852, 0.92744),\n        half2(0.852342, -0.47897),\n        half2(0.722872, 0.137748),\n        half2(0.279832, -0.21838),\n        half2(0.798272, 0.452448),\n        half2(0.9001679, 0.4275481),\n        half2(0.882284, -0.381238),\n        half2(0.853526, 0.506608),\n        half2(0.460592, 0.870962),\n        half2(0.947592, 0.3045419),\n        half2(0.807204, 0.550822),\n        half2(0.329008, -0.257532),\n        half2(0.699424, 0.6915441),\n        half2(0.9524159, 0.23209),\n        half2(0.385848, -0.340032),\n        half2(0.983722, -0.160246),\n        half2(0.8927079, 0.104544),\n        half2(0.938886, 0.163002),\n        half2(0.989176, 0.10458),\n        half2(-0.557664, 0.707182),\n        half2(0.703514, -0.70895),\n        half2(0.919008, -0.02679801)\n    };\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Shift.hlsli",
    "content": "#ifndef RESTIR_PT_SHIFT_H\n#define RESTIR_PT_SHIFT_H\n\n#include \"ReSTIR_PT_NEE.hlsli\"\n\nnamespace RPT_Util\n{\n    enum SHIFT_ERROR : uint16_t\n    {\n        SUCCESS = 0,\n        INVALID_PIXEL = 1,\n        NOT_FOUND = 2,\n        EMPTY = 4\n    };\n\n    struct Reconnection\n    {\n        static Reconnection Init()\n        {\n            Reconnection ret;\n            ret.k = Reconnection::EMPTY;\n            ret.lt_k = Light::TYPE::NONE;\n            ret.lt_k_plus_1 = Light::TYPE::NONE;\n            ret.partialJacobian = 0;\n            ret.x_k = FLT_MAX;\n            ret.seed_replay = 0;\n            ret.w_k_lightNormal_w_sky = 0;\n            ret.L = 0;\n            ret.lightPdf = 0;\n            ret.seed_nee = 0;\n            ret.dwdA = 0;\n\n            return ret;\n        }\n\n        bool Empty()\n        {\n            return this.k == Reconnection::EMPTY;\n        }\n\n        bool IsCase1()\n        {\n            return !this.IsCase2() && !this.IsCase3();\n        }\n\n        bool IsCase2()\n        {\n            return this.lt_k_plus_1 != Light::TYPE::NONE;\n        }\n\n        bool IsCase3()\n        {\n            return this.lt_k != Light::TYPE::NONE;\n        }\n\n        void Clear()\n        {\n            this.k = Reconnection::EMPTY;\n            this.lt_k = Light::TYPE::NONE;\n            this.lt_k_plus_1 = Light::TYPE::NONE;\n        }\n\n        // w_{k - 1} = \\hat {x_k - x_{k - 1}}\n        // t = || x_k - x_{k - 1} ||\n        void SetCase1(int16 k, float3 x_k, float t, float3 normal_k, uint hitID, \n            uint meshIdx, float3 w_k_min_1, BSDF::LOBE l_k_min_1, float pdf_w_k_min_1, \n            float3 w_k, BSDF::LOBE l_k, float pdf_w_k)\n        {\n            this.lobe_k_min_1 = l_k_min_1;\n\n            this.k = k;\n            this.x_k = x_k;\n            this.ID = hitID;\n            this.meshIdx = meshIdx;\n            this.lt_k = Light::TYPE::NONE;\n            this.lobe_k = l_k;\n            this.w_k_lightNormal_w_sky = w_k;\n\n            this.lt_k_plus_1 = Light::TYPE::NONE;\n\n            this.partialJacobian = pdf_w_k_min_1;\n            float cos_theta_k = abs(dot(-w_k_min_1, normal_k));\n            this.partialJacobian *= cos_theta_k / (t * t);\n            this.partialJacobian *= pdf_w_k;\n        }\n\n        // seed: RNG state for direct lighting at x_k\n        void SetCase2(int16 k, float3 x_k, float t, float3 normal_k, uint hitID, \n            uint meshIdx, float3 w_k_min_1, BSDF::LOBE l_k_min_1, float pdf_w_k_min_1, \n            float3 w_k, BSDF::LOBE l_k, float pdf_w_k, Light::TYPE t_k_plus_1, \n            float pdf_light, float3 le, uint seed, float dwdA)\n        {\n            this.lobe_k_min_1 = l_k_min_1;\n\n            this.k = k;\n            this.x_k = x_k;\n            this.ID = hitID;\n            this.meshIdx = meshIdx;\n            this.lt_k = Light::TYPE::NONE;\n            this.lobe_k = l_k;\n            this.w_k_lightNormal_w_sky = w_k;\n\n            this.lt_k_plus_1 = t_k_plus_1;\n            // [Emissives] Cache light pdf and dwdA to avoid recomputing them\n            this.lightPdf = pdf_light;\n            this.dwdA = dwdA;\n            this.seed_nee = seed;\n            this.L = half3(le);\n\n            this.partialJacobian = pdf_w_k_min_1;\n            float cos_theta_k = abs(dot(-w_k_min_1, normal_k));\n            this.partialJacobian *= cos_theta_k / (t * t);\n\n            // Not needed as it cancels out with the same term in offset path\n            if(this.lobe_k != BSDF::LOBE::ALL)\n                this.partialJacobian *= pdf_w_k;\n        }\n\n        // seed: RNG state for direct lighting at x_{k - 1}\n        void SetCase3(int16 k, float3 x_k, Light::TYPE t, BSDF::LOBE l_k_min_1, \n            uint lightID, float3 le, float3 lightNormal, float pdf_solidAngle, \n            float pdf_light, float dwdA, float3 w_sky, bool twoSided, uint seed)\n        {\n            this.lobe_k_min_1 = l_k_min_1;\n\n            this.k = k;\n            this.x_k = x_k;\n            this.ID = lightID;\n            this.lt_k = t;\n            this.seed_nee = seed;\n            // Jacobian simplifies to 1.0 when x_k was sampled using light sampling\n            this.partialJacobian = l_k_min_1 == BSDF::LOBE::ALL ? \n                1.0f :\n                pdf_solidAngle * dwdA;\n            // [Emissives] Cache light pdf and le to avoid recomputing them\n            this.lightPdf = twoSided ? pdf_light : -pdf_light;\n            this.L = half3(le);\n\n            this.lt_k_plus_1 = Light::TYPE::NONE;\n\n            if(t == Light::TYPE::EMISSIVE)\n                this.w_k_lightNormal_w_sky = lightNormal;\n            else if(t == Light::TYPE::SKY)\n                this.w_k_lightNormal_w_sky = w_sky;\n        }\n\n        static const uint16_t EMPTY = 0xf;\n\n        float3 x_k;\n        // Tri ID when x_k is not on a light source and light ID otherwise\n        uint ID;\n        uint meshIdx;\n        float partialJacobian;\n        // A union =\n        //  - w_k, when case = 1 \n        //  - w_sky, when case = 2 and lt_{k + 1} = sky or case = 3 and lt_k = sky\n        //  - w_light, when case = 2 and lt_{k + 1} = emissive\n        //  - light normal, when case = 3\n        float3 w_k_lightNormal_w_sky;\n        // Cache the light sampling pdf when case = 2 or case = 3\n        float lightPdf;\n        uint seed_replay;\n        uint seed_nee;\n        float dwdA;\n        half3 L;\n        uint16_t k;\n        BSDF::LOBE lobe_k_min_1;\n        BSDF::LOBE lobe_k;\n        Light::TYPE lt_k;\n        Light::TYPE lt_k_plus_1;\n        bool x_k_in_motion;\n    };\n\n    struct OffsetPath\n    {\n        static OffsetPath Init()\n        {\n            OffsetPath ret;\n            ret.target = 0;\n            ret.partialJacobian = 0;\n            ret.surfKMin1Tramsmissive = false;\n\n            return ret;\n        }\n\n        float3 target;\n        float partialJacobian;\n        bool surfKMin1Tramsmissive;\n    };\n\n    struct OffsetPathContext\n    {\n        static OffsetPathContext Init()\n        {\n            OffsetPathContext ret;\n            ret.throughput = 0;\n            ret.pos = 0;\n            ret.normal = 0;\n            ret.rd = RT::RayDifferentials::Init();\n            ret.surface = BSDF::ShadingData::Init();\n            ret.eta_curr = ETA_AIR;\n            ret.eta_next = DEFAULT_ETA_MAT;\n            ret.rngReplay.State = 0;\n            // ret.anyGlossyBounces = false;\n\n            return ret;\n        }\n        \n        static OffsetPathContext Load(uint2 DTid, uint srvAIdx, uint srvBIdx, uint srvCIdx, \n            uint srvDIdx, bool isCase3)\n        {\n            OffsetPathContext ctx = OffsetPathContext::Init();\n\n            Texture2D<float4> g_cbA = ResourceDescriptorHeap[srvAIdx];\n            Texture2D<uint4> g_cbB = ResourceDescriptorHeap[srvBIdx];\n            Texture2D<uint4> g_cbC = ResourceDescriptorHeap[srvCIdx];\n            Texture2D<uint> g_cbD = ResourceDescriptorHeap[srvDIdx];\n\n            float4 inA = 0;\n\n            // Texture filtering is not needed for case 3\n            if(!isCase3)\n            {\n                inA = g_cbA[DTid];\n                ctx.rd.uv_grads.xy = inA.w;\n                ctx.rd.uv_grads.zw = inA.w;\n            }\n            else\n                inA.xyz = g_cbA[DTid].xyz;\n\n            ctx.throughput = inA.xyz;\n            if(dot(ctx.throughput, ctx.throughput) == 0)\n                return ctx;\n\n            uint4 inB = g_cbB[DTid];\n            uint3 inC = g_cbC[DTid].xyz;\n\n            ctx.pos = asfloat(inB.xyz);\n            ctx.normal = Math::DecodeOct32(Math::UnpackUintToUint16(inB.w));\n            ctx.eta_curr = mad(Math::UNorm8ToFloat((inC.z >> 8) & 0xff), 1.5f, 1.0f);\n            ctx.eta_next = mad(Math::UNorm8ToFloat((inC.z >> 16) & 0xff), 1.5f, 1.0f);\n\n            float3 wo = Math::DecodeOct32(Math::UnpackUintToUint16(inC.x));\n            float roughness = Math::UNorm8ToFloat(inC.z & 0xff);\n            float3 baseColor = Math::UnpackRGB8(inC.y & 0xffffff);\n            uint flags = inC.y >> 24;\n            bool metallic = flags & 0x1;\n            // ctx.anyGlossyBounces = (flags & 0x2) == 0x2;\n            bool specTr = (flags & 0x4) == 0x4;\n            half trDepth = (flags & 0x8) == 0x8 ? 1.0h : 0.0h;\n            bool coated = (flags & 0x10) == 0x10;\n            float subsurface = Math::UNorm8ToFloat((inC.z >> 24) & 0xff);\n\n            // UNorm8 encoding above preserves ETA_AIR = 1, so the comparison\n            // below works\n            float eta_next = ctx.eta_curr == ETA_AIR ? ctx.eta_next : ETA_AIR;\n\n            float coat_weight = 0;\n            float3 coat_color = 0.0f;\n            float coat_roughness = 0;\n            float coat_ior = DEFAULT_ETA_COAT;\n\n            if(coated)\n            {\n                uint c_w = g_cbC[DTid].w;\n                uint d_w = g_cbD[DTid];\n\n                coat_weight = Math::UNorm8ToFloat((c_w >> 24) & 0xff);\n                coat_color = Math::UnpackRGB8(c_w & 0xffffff);\n                coat_roughness = Math::UNorm8ToFloat(d_w & 0xff);\n                coat_ior = mad(Math::UNorm8ToFloat((d_w >> 8) & 0xff), 1.5f, 1.0f);\n            }\n\n            ctx.surface = BSDF::ShadingData::Init(ctx.normal, wo, metallic, roughness, \n                baseColor, ctx.eta_curr, eta_next, specTr, trDepth, (half)subsurface,\n                coat_weight, coat_color, coat_roughness, coat_ior);\n\n            return ctx;\n        }\n\n        void Write(uint2 DTid, uint uavAIdx, uint uavBIdx, uint uavCIdx, uint uavDIdx,\n            bool isCase3)\n        {\n            // R16G16B16A16_FLOAT\n            RWTexture2D<float4> g_rbA = ResourceDescriptorHeap[uavAIdx];\n            // R32G32B32A32_UINT\n            RWTexture2D<uint4> g_rbB = ResourceDescriptorHeap[uavBIdx];\n            // R32G32B32A32_UINT\n            RWTexture2D<uint4> g_rbC = ResourceDescriptorHeap[uavCIdx];\n            // R16_UINT\n            RWTexture2D<uint> g_rbD = ResourceDescriptorHeap[uavDIdx];\n\n            // Texture filtering is not needed for case 3\n            if(!isCase3)\n            {\n                float ddx_uv = sqrt(dot(this.rd.uv_grads.xy, this.rd.uv_grads.xy));\n                float ddy_uv = sqrt(dot(this.rd.uv_grads.zw, this.rd.uv_grads.zw));\n                float grad_max = max(ddx_uv, ddy_uv);\n\n                g_rbA[DTid] = float4(this.throughput, grad_max);\n            }\n            else\n                g_rbA[DTid].xyz = this.throughput;\n\n            if(dot(this.throughput, this.throughput) == 0)\n                return;\n\n            uint16_t2 e1 = Math::EncodeOct32(this.normal);\n            uint normal_e = e1.x | (uint(e1.y) << 16);\n\n            // ShadingData\n            uint16_t2 e2 = Math::EncodeOct32(this.surface.wo);\n            uint wo = e2.x | (uint(e2.y) << 16);\n            // Note: needed so that BSDF evaluation at x_{k - 1} uses the right\n            // transmission tint\n            bool hasVolumetricInterior = surface.trDepth > 0;\n            uint flags = (uint)surface.metallic | \n                // ((uint)this.anyGlossyBounces << 1) | \n                ((uint)surface.specTr << 2) |\n                ((uint)hasVolumetricInterior << 3) |\n                ((uint)surface.Coated() << 4);\n            uint baseColor_Flags = Math::Float3ToRGB8(surface.baseColor_Fr0_TrCol);\n            baseColor_Flags = baseColor_Flags | (flags << 24);\n            uint roughness = Math::FloatToUNorm8(!surface.GlossSpecular() ? sqrt(surface.alpha) : 0);\n            uint eta_curr = Math::FloatToUNorm8((this.eta_curr - 1.0f) / 1.5f);\n            uint eta_next = Math::FloatToUNorm8((this.eta_next - 1.0f) / 1.5f);\n            uint subsurface = Math::FloatToUNorm8((float)surface.subsurface);\n            uint packed = roughness | (eta_curr << 8) | (eta_next << 16) | (subsurface << 24);\n\n            g_rbB[DTid] = uint4(asuint(this.pos), normal_e);\n\n            if(surface.Coated())\n            {\n                uint coat_weight = Math::FloatToUNorm8(surface.coat_weight);\n                uint coat_color = Math::Float3ToRGB8(surface.coat_color);\n                uint coat_roughness = Math::FloatToUNorm8(!surface.CoatSpecular() ? \n                    sqrt(surface.coat_alpha) : 0);\n                float coat_eta = surface.coat_eta >= 1.0f ? surface.coat_eta : \n                    1.0f / surface.coat_eta;\n                uint coat_eta_e = Math::FloatToUNorm8((coat_eta - 1.0f) / 1.5f);\n\n                g_rbC[DTid] = uint4(wo, baseColor_Flags, packed, coat_color | (coat_weight << 24));\n                g_rbD[DTid] = coat_roughness | (coat_eta_e << 8);\n            }\n            else\n                g_rbC[DTid].xyz = uint3(wo, baseColor_Flags, packed);\n        }\n\n        float3 throughput;\n        float3 pos;\n        float3 normal;\n        RT::RayDifferentials rd;\n        BSDF::ShadingData surface;\n        float eta_curr;\n        float eta_next;\n        RNG rngReplay;\n        // bool anyGlossyBounces;\n    };\n\n    bool CanReconnect(float alpha_lobe_k_min_1, float alpha_lobe_k, float3 x_k_min_1, float3 x_k, \n        BSDF::LOBE lobe_k_min_1, BSDF::LOBE lobe_k, float alpha_min)\n    {\n        if((alpha_lobe_k_min_1 < alpha_min) || (alpha_lobe_k < alpha_min))\n            return false;\n\n        if((lobe_k_min_1 == BSDF::LOBE::GLOSSY_T) && (lobe_k == BSDF::LOBE::GLOSSY_T))\n            return false;\n\n        // float3 delta = x_k - x_k_min_1;\n        // float distSq = dot(delta, delta);\n        // if(distSq < d_min)\n        //     return false;\n\n        return true;\n    }\n\n    template<bool InCurrFrame>\n    void Replay(int16 numBounces, BSDF::BSDFSample bsdfSample, float alpha_min, \n        bool regularization, ConstantBuffer<cbFrameConstants> g_frame, SamplerState samp,\n        ReSTIR_Util::Globals globals, inout OffsetPathContext ctx)\n    {\n        ctx.throughput = bsdfSample.bsdfOverPdf;\n        int bounce = 0;\n        ctx.eta_curr = dot(ctx.normal, bsdfSample.wi) < 0 ? ctx.eta_next : ETA_AIR;\n        bool inTranslucentMedium = ctx.eta_curr != ETA_AIR;\n        // Note: skip the first bounce for a milder impacet. May have to change in the future.\n        // ctx.anyGlossyBounces = bsdfSample.lobe != BSDF::LOBE::DIFFUSE_R;\n        // ctx.anyGlossyBounces = false;\n\n        float alpha_lobe_prev = BSDF::LobeAlpha(ctx.surface, bsdfSample.lobe);\n        bool tr_prev = ctx.surface.specTr;\n        BSDF::LOBE lobe_prev = bsdfSample.lobe;\n        float3 pos_prev = ctx.pos;\n\n        while(true)\n        {\n            RtRayQuery::Hit hitInfo = RtRayQuery::Hit::FindClosest<false, InCurrFrame>(ctx.pos, \n                ctx.normal, bsdfSample.wi, globals.bvh, globals.frameMeshData, globals.vertices, \n                globals.indices, ctx.surface.Transmissive());\n\n            // Not invertible -- base path would've stopped here\n            if(!hitInfo.hit)\n            {\n                ctx.throughput = 0;\n                return;\n            }\n\n            float3 newPos = mad(hitInfo.t, bsdfSample.wi, ctx.pos);\n            float3 dpdx;\n            float3 dpdy;\n            ctx.rd.dpdx_dpdy(newPos, hitInfo.normal, dpdx, dpdy);\n            ctx.rd.ComputeUVDifferentials(dpdx, dpdy, hitInfo.triDiffs.dpdu, hitInfo.triDiffs.dpdv);\n\n            if(!RtRayQuery::GetMaterialData(-bsdfSample.wi, globals.materials, g_frame, ctx.eta_curr, \n                ctx.rd.uv_grads, hitInfo, ctx.surface, ctx.eta_next, samp))\n            {\n                // Not invertible\n                ctx.throughput = 0;\n                return;\n            }\n\n            // Make sure these are updated before breaking\n            ctx.pos = mad(hitInfo.t, bsdfSample.wi, ctx.pos);\n            ctx.normal = hitInfo.normal;\n            bounce++;\n\n            // if(regularization && ctx.anyGlossyBounces)\n            //     ctx.surface.Regularize();\n\n            if(inTranslucentMedium && (ctx.surface.trDepth > 0))\n            {\n                float3 extCoeff = -log(ctx.surface.baseColor_Fr0_TrCol) / ctx.surface.trDepth;\n                ctx.throughput *= exp(-hitInfo.t * extCoeff);\n            }\n\n            // Remaining code can be skipped in last iteration\n            if(bounce >= numBounces)\n                break;\n\n            // Sample BSDF to generate new direction\n            bsdfSample = BSDF::SampleBSDF(ctx.normal, ctx.surface, ctx.rngReplay);\n\n            // Not invertible -- base path would've stopped here\n            if(dot(bsdfSample.bsdfOverPdf, bsdfSample.bsdfOverPdf) == 0)\n            {\n                ctx.throughput = 0;\n                return;\n            }\n\n            const float alpha_lobe = BSDF::LobeAlpha(ctx.surface, bsdfSample.lobe);\n\n            // Not invertible -- reconnection vertex must match\n            if(RPT_Util::CanReconnect(alpha_lobe_prev, alpha_lobe, pos_prev, ctx.pos, lobe_prev, \n                bsdfSample.lobe, alpha_min))\n            {\n                ctx.throughput = 0;\n                return;\n            }\n\n            const bool transmitted = dot(ctx.normal, bsdfSample.wi) < 0;\n            ctx.eta_curr = transmitted ? (ctx.eta_curr == ETA_AIR ? ctx.eta_next : ETA_AIR) : ctx.eta_curr;\n            ctx.throughput *= bsdfSample.bsdfOverPdf;\n            // ctx.anyGlossyBounces = ctx.anyGlossyBounces || (bsdfSample.lobe != BSDF::LOBE::DIFFUSE_R);\n            inTranslucentMedium = ctx.eta_curr != ETA_AIR;\n\n            pos_prev = ctx.pos;\n            alpha_lobe_prev = alpha_lobe;\n            tr_prev = ctx.surface.specTr;\n            lobe_prev = bsdfSample.lobe;\n\n            ctx.rd.UpdateRays(ctx.pos, ctx.normal, bsdfSample.wi, ctx.surface.wo, \n                hitInfo.triDiffs, dpdx, dpdy, transmitted, ctx.surface.eta);\n        }\n    }\n\n    template<bool InCurrFrame>\n    float StepPath(inout OffsetPathContext ctx, bool anyGlossyBounces, float alpha_min, \n        bool regularization, Reconnection rc, ConstantBuffer<cbFrameConstants> g_frame, \n        ReSTIR_Util::Globals globals)\n    {\n        // Not invertible\n        if(!BSDF::IsLobeValid(ctx.surface, rc.lobe_k_min_1))\n            return 0;\n\n        float alpha_lobe_k_min_1 = BSDF::LobeAlpha(ctx.surface, rc.lobe_k_min_1);\n\n        // Not invertible\n        if(!RPT_Util::CanReconnect(alpha_lobe_k_min_1, 1, ctx.pos, rc.x_k,\n            rc.lobe_k_min_1, rc.lobe_k, alpha_min))\n            return 0;\n\n        float3 w_k_min_1 = normalize(rc.x_k - ctx.pos);\n        int16 bounce = rc.k - (int16)2;\n\n        // Evaluate f / p at x_{k - 1}\n        BSDF::BSDFSamplerEval eval = BSDF::EvalBSDFSampler(ctx.normal, ctx.surface, w_k_min_1, \n            rc.lobe_k_min_1, ctx.rngReplay);\n\n        if(dot(eval.bsdfOverPdf, eval.bsdfOverPdf) == 0)\n            return 0;\n\n        RtRayQuery::Hit hitInfo = RtRayQuery::Hit::FindClosest<true, InCurrFrame>(ctx.pos, ctx.normal, \n            w_k_min_1, globals.bvh, globals.frameMeshData, globals.vertices, globals.indices, \n            ctx.surface.Transmissive());\n\n        // Not invertible\n        if(!hitInfo.hit || (hitInfo.ID != rc.ID))\n            return 0;\n\n        // Move to y_k = x_k\n        const float3 y_k = mad(hitInfo.t, w_k_min_1, ctx.pos);\n        bounce++;\n\n        // Update medium (from y_{k - 1} to x_k)\n        const bool transmitted = dot(ctx.normal, w_k_min_1) < 0;\n        ctx.eta_curr = transmitted ? (ctx.eta_curr == ETA_AIR ? ctx.eta_next : ETA_AIR) : ctx.eta_curr;\n        const bool inTranslucentMedium = ctx.eta_curr != ETA_AIR;\n\n        RtRayQuery::IsotropicSampler is;\n        if(!RtRayQuery::GetMaterialData(-w_k_min_1, globals.materials, g_frame, ctx.eta_curr, \n            ctx.rd.uv_grads, hitInfo, ctx.surface, ctx.eta_next, g_samLinearWrap, is))\n        {\n            // Not invertible\n            return 0;\n        }\n\n        // if(regularization && anyGlossyBounces)\n        //     surface.Regularize();\n\n        // Account for transmittance from y_{k - 1} to x_k\n        if(inTranslucentMedium && (ctx.surface.trDepth > 0))\n        {\n            float3 extCoeff = -log(ctx.surface.baseColor_Fr0_TrCol) / ctx.surface.trDepth;\n            ctx.throughput *= exp(-hitInfo.t * extCoeff);\n        }\n\n        float partialJacobian = eval.pdf;\n        partialJacobian *= abs(dot(-w_k_min_1, hitInfo.normal));\n        partialJacobian /= (hitInfo.t * hitInfo.t);\n\n        ctx.pos = y_k;\n        ctx.normal = hitInfo.normal;\n        ctx.throughput *= eval.bsdfOverPdf;\n\n        return partialJacobian;\n    }\n\n    float4 EstimateDirect_y_k_min_1(OffsetPathContext ctx, Light::TYPE lt, float3 wd, BSDF::LOBE lobe, \n        ConstantBuffer<cbFrameConstants> g_frame, ReSTIR_Util::Globals globals, RNG rngNEE)\n    {\n#if SKY_SAMPLING_PREFER_PERFORMANCE == 1\n        const float2 u_wrs = rngNEE.Uniform2D();\n        const float2 u_d = rngNEE.Uniform2D();\n        const float2 u_c = rngNEE.Uniform2D();\n        const float2 u_g = rngNEE.Uniform2D();\n        const float u_wrs_b0 = rngNEE.Uniform();\n        const float u_wrs_b1 = rngNEE.Uniform();\n#else\n        const float u_wrs = rngNEE.Uniform();\n#endif\n\n        ReSTIR_Util::SkyIncidentRadiance leFunc = ReSTIR_Util::SkyIncidentRadiance::Init(\n            g_frame.EnvMapDescHeapOffset);\n        const bool specular = ctx.surface.GlossSpecular() && (ctx.surface.metallic || ctx.surface.specTr) && \n            (!ctx.surface.Coated() || ctx.surface.CoatSpecular());\n\n        // TODO assumes visibility doesn't change. Not necessarily true for temporal.\n        float3 target_z = 0;\n        float w_sum;\n\n        // Sun\n        {\n            float3 wi_sun = -g_frame.SunDir;\n            float pdf_b = 0;\n            float pdf_e = 0;\n            // Skip when Sun is below the horizon or it hits backside of non-transmissive surface\n            const bool visible = (wi_sun.y > 0) &&\n                ((dot(wi_sun, ctx.normal) > 0) || ctx.surface.Transmissive());\n\n            if(visible)\n            {\n                ctx.surface.SetWi(wi_sun, ctx.normal);\n                target_z = Light::Le_Sun(ctx.pos, g_frame) * BSDF::Unified(ctx.surface).f;\n                float ndotWi = dot(wi_sun, ctx.normal);\n\n#if SKY_SAMPLING_PREFER_PERFORMANCE == 1\n                pdf_b = (ndotWi < 0) && ctx.surface.ThinWalled() ? 0 : \n                    BSDF::BSDFSamplerPdf_NoDiffuse(ctx.normal, ctx.surface, wi_sun, leFunc);\n                pdf_e = !specular * abs(ndotWi) * ONE_OVER_PI;\n                pdf_e *= ctx.surface.ThinWalled() ? 0.5f : ndotWi > 0;\n#else\n                pdf_b = BSDF::BSDFSamplerPdf(ctx.normal, ctx.surface, wi_sun, \n                    leFunc, rngNEE);\n#endif\n            }\n\n            w_sum = RT::BalanceHeuristic3(1, pdf_e, pdf_b, Math::Luminance(target_z));\n        }\n\n#if SKY_SAMPLING_PREFER_PERFORMANCE == 1\n        if(!specular)\n        {\n            const bool isZ_e = lt == Light::TYPE::SKY && lobe == BSDF::LOBE::ALL;\n            float3 wi_e = isZ_e ? wd : BSDF::SampleDiffuse(ctx.normal, u_d);\n            float pdf_e = saturate(dot(ctx.normal, wi_e)) * ONE_OVER_PI;\n            if(ctx.surface.ThinWalled())\n            {\n                wi_e = u_wrs_b1 > 0.5 ? -wi_e : wi_e;\n                pdf_e *= 0.5f;\n            }\n            ctx.surface.SetWi(wi_e, ctx.normal);\n            float3 target = leFunc(wi_e) * BSDF::Unified(ctx.surface).f;\n            target_z = isZ_e ? target : target_z;\n\n            const float pdf_b = !ctx.surface.reflection && ctx.surface.ThinWalled() ? 0 :\n                BSDF::BSDFSamplerPdf_NoDiffuse(ctx.normal, ctx.surface, wi_e, leFunc);\n            w_sum += RT::BalanceHeuristic(pdf_e, pdf_b, Math::Luminance(target));\n        }\n#endif\n\n        const bool isZ_b = lt == Light::TYPE::SKY && lobe != BSDF::LOBE::ALL;\n        if(isZ_b)\n        {\n#if SKY_SAMPLING_PREFER_PERFORMANCE == 1\n            BSDF::BSDFSamplerEval eval = BSDF::EvalBSDFSampler_NoDiffuse(ctx.normal, ctx.surface, \n                wd, lobe, /*unused*/0, leFunc);\n            target_z = eval.f;\n            float ndotwi = dot(wd, ctx.normal);\n            float pdf_e = !specular * abs(ndotwi) * ONE_OVER_PI;\n            pdf_e *= ctx.surface.ThinWalled() ? 0.5f : ndotwi > 0;\n            w_sum += RT::BalanceHeuristic(eval.pdf, pdf_e, Math::Luminance(eval.f));\n#else\n            BSDF::BSDFSamplerEval eval = BSDF::EvalBSDFSampler(ctx.normal, ctx.surface, \n                wd, lobe, leFunc, rngNEE);\n            target_z = eval.f;\n            w_sum += Math::Luminance(eval.bsdfOverPdf);\n#endif\n        }\n        else\n        {\n#if SKY_SAMPLING_PREFER_PERFORMANCE == 1\n            BSDF::BSDFSample bsdfSample = BSDF::SampleBSDF_NoDiffuse(ctx.normal, ctx.surface, \n                u_c, u_g, u_wrs_b0, u_wrs_b1, leFunc);\n            float ndotwi = dot(bsdfSample.wi, ctx.normal);\n            float pdf_e = !specular * abs(ndotwi) * ONE_OVER_PI;\n            pdf_e *= ctx.surface.ThinWalled() ? 0.5f : ndotwi > 0;\n            w_sum += RT::BalanceHeuristic(bsdfSample.pdf, pdf_e, Math::Luminance(bsdfSample.f));\n#else\n            BSDF::BSDFSample bsdfSample = BSDF::SampleBSDF(ctx.normal, ctx.surface, \n                leFunc, rngNEE);\n            w_sum += Math::Luminance(bsdfSample.bsdfOverPdf);\n#endif\n        }\n\n        const float targetLum = Math::Luminance(target_z);\n        float3 ld = targetLum > 0 ? target_z * w_sum / targetLum : 0;\n        float pdf = w_sum > 0 ? targetLum / w_sum : 0;        \n\n        return float4(ld, pdf);\n    }\n\n    template<bool Emissive, bool InCurrFrame>\n    OffsetPath Shift2(uint2 DTid, float3 pos, float3 normal, float ior, \n        BSDF::ShadingData surface, RT::RayDifferentials rd, Math::TriDifferentials triDiffs, \n        RPT_Util::Reconnection rc, uint rbufferASrv, uint rbufferBSrv, uint rbufferCSrv, \n        uint rbufferDSrv, float alpha_min, bool regularization, ConstantBuffer<cbFrameConstants> g_frame, \n        ReSTIR_Util::Globals globals)\n    {\n        OffsetPathContext ctx = OffsetPathContext::Init();\n        ctx.pos = pos;\n        ctx.normal = normal;\n        ctx.surface = surface;\n        ctx.rngReplay = RNG::Init(rc.seed_replay);\n        ctx.rd = rd;\n        // Assumes camera is in the air\n        ctx.eta_curr = ETA_AIR;\n        ctx.eta_next = ior;\n        // ctx.anyGlossyBounces = false;\n        ctx.throughput = 1;\n\n        // Number of bounces to reach y_{k - 1}, where zero means case 1 or case 2\n        const int16 numBounces = rc.k - (int16)2;\n\n        // Initialize ray differentials given the primary hit triangle. This is only\n        // needed when replay is not used - replayed paths load path context (including ray \n        // differentials) from replay buffers.\n        if(numBounces == 0)\n        {\n            float3 dpdx;\n            float3 dpdy;\n            ctx.rd.dpdx_dpdy(ctx.pos, ctx.normal, dpdx, dpdy);\n            ctx.rd.ComputeUVDifferentials(dpdx, dpdy, triDiffs.dpdu, triDiffs.dpdv);\n\n            float eta = ior;  // = eta_i / eta_t = ior / ETA_AIR\n            float3 wi = normalize(rc.x_k - ctx.pos);\n            ctx.rd.UpdateRays(ctx.pos, ctx.normal, wi, ctx.surface.wo, \n                triDiffs, dpdx, dpdy, dot(wi, ctx.normal) < 0, eta);\n        }\n        else\n        {\n            ctx = OffsetPathContext::Load(DTid, rbufferASrv, rbufferBSrv, rbufferCSrv, \n                rbufferDSrv, rc.IsCase3());\n\n            if(dot(ctx.throughput, ctx.throughput) == 0)\n                return RPT_Util::OffsetPath::Init();\n\n            // Advance rng of path context to what it would be after replay\n            for(int bounce = 0; bounce < numBounces; bounce++)\n            {\n                ctx.rngReplay.Uniform4D();\n                ctx.rngReplay.Uniform4D();\n                ctx.rngReplay.Uniform();\n            }\n        }\n\n\n        OffsetPath ret = OffsetPath::Init();\n        ret.surfKMin1Tramsmissive = ctx.surface.specTr;\n        \n        if(!rc.IsCase3())\n        {\n            ret.partialJacobian = StepPath<InCurrFrame>(ctx, false, alpha_min, regularization, rc, \n                g_frame, globals);\n\n            if(ret.partialJacobian == 0)\n                return ret;\n\n            // Case 1\n            if(rc.IsCase1())\n            {\n                float3 w_k = rc.w_k_lightNormal_w_sky;\n                BSDF::BSDFSamplerEval eval = BSDF::EvalBSDFSampler(ctx.normal, ctx.surface, \n                    w_k, rc.lobe_k, ctx.rngReplay);\n\n                ctx.throughput *= eval.bsdfOverPdf;\n                ret.target = ctx.throughput * rc.L;\n                ret.partialJacobian *= eval.pdf;\n\n                return ret;\n            }\n        }\n        else\n        {\n            // Not invertible\n            if(!BSDF::IsLobeValid(ctx.surface, rc.lobe_k_min_1))\n                return ret;\n\n            float alpha_lobe_k_min_1 = BSDF::LobeAlpha(ctx.surface, rc.lobe_k_min_1);\n\n            // Not invertible\n            if(alpha_lobe_k_min_1 < alpha_min)\n                return ret;\n        }\n\n        RNG rngNEE = RNG::Init(rc.seed_nee);\n\n        if(Emissive)\n        {\n            if(rc.IsCase2())\n            {\n                float3 w_k = rc.w_k_lightNormal_w_sky;\n\n                // TODO For temporal, following assumes visibility hasn't change between frames\n                ReSTIR_Util::DirectLightingEstimate ls = EvalDirect_Emissive_Case2(ctx.pos, \n                    ctx.normal, ctx.surface, w_k, rc.L, rc.dwdA, rc.lightPdf, rc.lobe_k, \n                    ctx.rngReplay, rngNEE);\n\n                ret.target = ctx.throughput * ls.ld;\n                ret.partialJacobian *= ls.pdf_solidAngle;\n            }\n            else\n            {\n                float3 wi_k_min_1 = rc.x_k - ctx.pos;\n                float t = length(wi_k_min_1);\n                wi_k_min_1 /= t;\n\n                float3 lightNormal = rc.w_k_lightNormal_w_sky;\n                bool twoSided = rc.lightPdf > 0;\n\n                ReSTIR_Util::DirectLightingEstimate ls = EvalDirect_Emissive_Case3(ctx.pos, \n                    ctx.pos, ctx.surface, wi_k_min_1, t, rc.L, lightNormal, abs(rc.lightPdf), rc.ID, \n                    twoSided, rc.lobe_k_min_1, globals.bvh, ctx.rngReplay, rngNEE);\n\n                ret.target = ctx.throughput * ls.ld;\n                ret.partialJacobian = ls.pdf_solidAngle;\n            }\n        }\n        else\n        {\n            Light::TYPE lt = rc.IsCase2() ? rc.lt_k_plus_1 : rc.lt_k;\n            BSDF::LOBE lobe = rc.IsCase2() ? rc.lobe_k : rc.lobe_k_min_1;\n            \n            const float4 ldAndPdf = EstimateDirect_y_k_min_1(ctx, lt, rc.w_k_lightNormal_w_sky, lobe, \n                g_frame, globals, rngNEE);\n            const float3 target = ldAndPdf.xyz;\n            const float targetLum = Math::Luminance(target);\n            ret.target = ctx.throughput * target;\n\n            if(rc.IsCase2())\n                ret.partialJacobian *= ldAndPdf.w;\n            else\n            {\n                ret.partialJacobian = ldAndPdf.w;\n\n                if(dot(ret.target, ret.target) > 0)\n                {\n                    float3 wi = rc.lt_k == Light::TYPE::SUN ? -g_frame.SunDir : \n                        rc.w_k_lightNormal_w_sky;\n                    ret.target *= RtRayQuery::Visibility_Ray(ctx.pos, wi, ctx.normal, \n                        globals.bvh, ctx.surface.Transmissive());\n                }\n            }\n        }\n\n        return ret;\n    }\n\n    template<bool InCurrFrame>\n    OffsetPathContext Replay_kGt2(float3 pos, float3 normal, float ior, BSDF::ShadingData surface, \n        RT::RayDifferentials rd, Math::TriDifferentials triDiffs, Reconnection rc, \n        float alpha_min, bool regularization, SamplerState samp, \n        ConstantBuffer<cbFrameConstants> g_frame, ReSTIR_Util::Globals globals)\n    {\n        OffsetPathContext ctx = OffsetPathContext::Init();\n        ctx.pos = pos;\n        ctx.normal = normal;\n        ctx.surface = surface;\n        ctx.rngReplay = RNG::Init(rc.seed_replay);\n        ctx.rd = rd;\n        // Assumes camera is in the air\n        ctx.eta_curr = ETA_AIR;\n        ctx.eta_next = ior;\n        // ctx.anyGlossyBounces = false;\n        ctx.throughput = 1;\n\n        // Number of bounces to reach y_{k - 1}, where zero means case 1 or case 2\n        const int16 numBounces = rc.k - (int16)2;\n        BSDF::BSDFSample bsdfSample = BSDF::SampleBSDF(ctx.normal, ctx.surface, ctx.rngReplay);\n\n        if(dot(bsdfSample.bsdfOverPdf, bsdfSample.bsdfOverPdf) == 0)\n        {\n            ctx.throughput = 0;\n            return ctx;\n        }\n\n        // Initialize ray differentials given the primary hit triangle\n        float3 dpdx;\n        float3 dpdy;\n        ctx.rd.dpdx_dpdy(ctx.pos, ctx.normal, dpdx, dpdy);\n        ctx.rd.ComputeUVDifferentials(dpdx, dpdy, triDiffs.dpdu, triDiffs.dpdv);\n\n        ctx.rd.UpdateRays(ctx.pos, ctx.normal, bsdfSample.wi, ctx.surface.wo, \n            triDiffs, dpdx, dpdy, dot(bsdfSample.wi, ctx.normal) < 0, ctx.surface.eta);\n\n        RPT_Util::Replay<InCurrFrame>(numBounces, bsdfSample, alpha_min, regularization, g_frame, \n            samp, globals, ctx);\n\n        return ctx;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Util.hlsli",
    "content": "#ifndef RESTIR_PT_UTIL_H\n#define RESTIR_PT_UTIL_H\n\n#include \"../IndirectLighting_Common.h\"\n#include \"Reservoir.hlsli\"\n\nnamespace RPT_Util\n{\n    static const int SPATIAL_NEIGHBOR_OFFSET = 32;\n\n    bool PlaneHeuristic(float3 prevPos, float3 normal, float3 pos, float linearDepth, \n        float th = MAX_PLANE_DIST_REUSE)\n    {\n        float planeDist = abs(dot(normal, prevPos - pos));\n        bool onPlane = planeDist <= th * linearDepth;\n\n        return onPlane;\n    }\n\n    void EncodeSorted(uint2 DTid, uint2 mappedDTid, uint descHeapIdx, uint error)\n    {\n        // In [-31, +31]\n        int2 diff = (int2)DTid - (int2)mappedDTid;\n        uint2 diffU = (uint2)(diff + 31);\n        error = error > 0;\n        uint encoded = diffU.x | (diffU.y << 7) | (error << 15);\n\n        RWTexture2D<uint> g_threadMap = ResourceDescriptorHeap[descHeapIdx];\n        g_threadMap[mappedDTid] = encoded;\n    }\n\n    int2 DecodeSorted(uint2 DTid, uint descHeapIdx, out bool error)\n    {\n        Texture2D<uint> g_threadMap = ResourceDescriptorHeap[descHeapIdx];\n        uint encoded = g_threadMap[DTid];\n\n        error = (encoded & (1 << 15)) != 0;\n        uint2 decoded = uint2(encoded, (encoded >> 7)) & 0x3f;\n        int2 decodedI = (int2)decoded - 31;\n\n        return (int2)DTid + decodedI;\n    }\n\n    void SuppressOutlierReservoirs(inout RPT_Util::Reservoir r)\n    {\n        float waveSum = WaveActiveSum(r.w_sum);\n        float waveNonZeroCount = WaveActiveSum(r.w_sum != 0.0);\n        float waveAvgExclusive = (waveSum - r.w_sum) / max(waveNonZeroCount - 1, 1);\n        if(r.w_sum > 50 * waveAvgExclusive)\n        {\n            r.M = 0;\n            r.w_sum = 0;\n            r.W = 0;\n            r.rc.Clear();\n        }\n    }\n\n    void SuppressOutlierReservoirs(float waveAvgExclusive, inout RPT_Util::Reservoir r)\n    {\n        if(r.w_sum > 50 * waveAvgExclusive)\n        {\n            r.M = 0;\n            r.w_sum = 0;\n            r.W = 0;\n            r.rc.Clear();\n        }\n    }\n\n    void DebugColor(Reconnection rc, uint packed, inout float3 c)\n    {\n        const uint option = packed >> PACKED_INDEX::DEBUG_VIEW;\n        if(option == (int)RPT_DEBUG_VIEW::NONE)\n            return;\n\n        if(option == (int)RPT_DEBUG_VIEW::K)\n        {\n            if(rc.Empty())\n                c = float3(0, 0, 0);\n            else if(rc.k == 2)\n                c = float3(0.1, 0.25, 0.88);\n            else if(rc.k == 3)\n                c = float3(0.13, 0.55, 0.14);\n            else if(rc.k == 4)\n                c = float3(0.69, 0.45, 0.1);\n            else if(rc.k >= 5)\n                c = float3(0.88, 0.08, 0.1);\n        }\n        else if(option == (int)RPT_DEBUG_VIEW::CASE)\n        {\n            if(rc.Empty())\n                c = float3(0, 0, 0);\n            else if(rc.IsCase1())\n                c = float3(0.85, 0.096, 0.1);\n            else if(rc.IsCase2())\n                c = float3(0.13, 0.6, 0.14);\n            else if(rc.IsCase3())\n                c = float3(0.1, 0.27, 0.888);\n        }\n        else if(option == (int)RPT_DEBUG_VIEW::FOUND_CONNECTION)\n        {\n            c = !rc.Empty() ? float3(0.234, 0.12, 0.2134) : float3(0, 0, 0);\n        }\n        else if(option == (int)RPT_DEBUG_VIEW::CONNECTION_LOBE_K_MIN_1)\n        {\n            if(rc.Empty())\n                c = float3(0, 0, 0);\n            else\n            {\n                if(rc.lobe_k_min_1 == BSDF::LOBE::DIFFUSE_R)\n                    c = float3(0.384, 0.12, 0.2134);\n                else if(rc.lobe_k_min_1 == BSDF::LOBE::GLOSSY_R)\n                    c = float3(0.12, 0.4284, 0.2134);\n                else if(rc.lobe_k_min_1 == BSDF::LOBE::GLOSSY_T)\n                    c = float3(0.1134, 0.12, 0.634);\n                else if(rc.lobe_k_min_1 == BSDF::LOBE::DIFFUSE_T)\n                    c = float3(0.25f, 0.25f, 0.25f);\n                else\n                    c = float3(0.55f, 0.55f, 0.0f);\n            }\n        }\n        else if(option == (int)RPT_DEBUG_VIEW::CONNECTION_LOBE_K)\n        {\n            if(rc.Empty() || rc.IsCase3())\n                c = float3(0, 0, 0);\n            else\n            {\n                if(rc.lobe_k == BSDF::LOBE::DIFFUSE_R)\n                    c = float3(0.384, 0.12, 0.2134);\n                else if(rc.lobe_k == BSDF::LOBE::GLOSSY_R)\n                    c = float3(0.12, 0.284, 0.2134);\n                else if(rc.lobe_k == BSDF::LOBE::GLOSSY_T)\n                    c = float3(0.1134, 0.12, 0.634);\n                else if(rc.lobe_k == BSDF::LOBE::DIFFUSE_T)\n                    c = float3(0.25f, 0.25f, 0);\n                else\n                    c = float3(0.25f, 0.25f, 0.25f);\n            }\n        }\n    }\n\n    void WriteOutputColor(uint2 DTid, float3 li, uint packed, uint outDescHeapIdx, \n        ConstantBuffer<cbFrameConstants> g_frame,\n        bool filterToBlackWhenDebugViewEnabled = true)\n    {\n        const uint debugView = packed >> PACKED_INDEX::DEBUG_VIEW;\n        if((filterToBlackWhenDebugViewEnabled && (debugView != (uint)RPT_DEBUG_VIEW::NONE)))\n            li = 0;\n\n        RWTexture2D<float4> g_final = ResourceDescriptorHeap[outDescHeapIdx];\n        li = any(isnan(li)) ? 0 : li;\n\n        if(g_frame.Accumulate && g_frame.CameraStatic && g_frame.NumFramesCameraStatic > 1)\n        {\n            float3 prev = g_final[DTid].rgb;\n            g_final[DTid].rgb = prev + li;\n        }\n        else\n            g_final[DTid].rgb = li;\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_PathTrace_WPS.hlsl",
    "content": "#define NEE_EMISSIVE 1\n#define USE_PRESAMPLED_SETS\n#include \"../ReSTIR_PT_PathTrace.hlsl\""
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_PathTrace_WoPS.hlsl",
    "content": "#define NEE_EMISSIVE 1\n#include \"../ReSTIR_PT_PathTrace.hlsl\""
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Reconnect_CtS_E.hlsl",
    "content": "#define NEE_EMISSIVE 1\n#include \"../ReSTIR_PT_Reconnect_CtS.hlsl\""
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Reconnect_CtT_E.hlsl",
    "content": "#define NEE_EMISSIVE 1\n#include \"../ReSTIR_PT_Reconnect_CtT.hlsl\""
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Reconnect_StC_E.hlsl",
    "content": "#define NEE_EMISSIVE 1\n#include \"../ReSTIR_PT_Reconnect_StC.hlsl\""
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Reconnect_TtC_E.hlsl",
    "content": "#define NEE_EMISSIVE 1\n#include \"../ReSTIR_PT_Reconnect_TtC.hlsl\""
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Replay_CtS.hlsl",
    "content": "#define CURRENT_TO_SPATIAL\n#include \"../ReSTIR_PT_Replay.hlsl\"\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Replay_CtS_E.hlsl",
    "content": "#define NEE_EMISSIVE 1\n#define CURRENT_TO_SPATIAL\n#include \"../ReSTIR_PT_Replay.hlsl\"\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Replay_E.hlsl",
    "content": "#define NEE_EMISSIVE 1\n#include \"../ReSTIR_PT_Replay.hlsl\""
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Replay_StC.hlsl",
    "content": "#define SPATIAL_TO_CURRENT\n#include \"../ReSTIR_PT_Replay.hlsl\"\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Replay_StC_E.hlsl",
    "content": "#define NEE_EMISSIVE 1\n#define SPATIAL_TO_CURRENT\n#include \"../ReSTIR_PT_Replay.hlsl\"\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Replay_TtC.hlsl",
    "content": "#define TEMPORAL_TO_CURRENT\n#include \"../ReSTIR_PT_Replay.hlsl\"\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Replay_TtC_E.hlsl",
    "content": "#define NEE_EMISSIVE 1\n#define TEMPORAL_TO_CURRENT\n#include \"../ReSTIR_PT_Replay.hlsl\"\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Sort_CtS.hlsl",
    "content": "#define CURRENT_TO_SPATIAL\n#include \"../ReSTIR_PT_Sort.hlsl\"\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Sort_StC.hlsl",
    "content": "#define SPATIAL_TO_CURRENT\n#include \"../ReSTIR_PT_Sort.hlsl\"\n"
  },
  {
    "path": "Source/ZetaRenderPass/IndirectLighting/ReSTIR_PT/Variants/ReSTIR_PT_Sort_TtC.hlsl",
    "content": "#define TEMPORAL_TO_CURRENT\n#include \"../ReSTIR_PT_Sort.hlsl\"\n"
  },
  {
    "path": "Source/ZetaRenderPass/PreLighting/BuildLightVoxelGrid.hlsl",
    "content": "#include \"PreLighting_Common.h\"\n#include \"../Common/LightVoxelGrid.hlsli\"\n\n#define NUM_CANDIDATES 6\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbLVG> g_local : register(b0);\nConstantBuffer<cbFrameConstants> g_frame : register(b1);\nStructuredBuffer<RT::EmissiveTriangle> g_emissives : register(t0);\nStructuredBuffer<RT::EmissiveLumenAliasTableEntry> g_aliasTable : register(t1);\nRWStructuredBuffer<RT::VoxelSample> g_voxel : register(u0);\n\n//--------------------------------------------------------------------------------------\n// Helper functions\n//--------------------------------------------------------------------------------------\n\nfloat3 AdjustLightPos(float3 pos, float3 c, float3 extents, out bool inside)\n{\n    float3 d = abs(pos - c);\n    inside = d.x <= extents.x && d.y <= extents.y && d.z <= extents.z;\n    \n    if(!inside)\n        return pos;\n\n    uint maxIdx = d.x >= d.y ? (d.x >= d.z ? 0 : 2) : (d.y >= d.z ? 1 : 2);\n    float3 posSnapped = pos;\n    posSnapped[maxIdx] = extents[maxIdx];\n\n    return posSnapped;\n}\n\nbool IsBackfacing(float3 lightPos, float3 lightNormal, float3 corners[8])\n{\n    [unroll]\n    for(int i = 0; i < 8; i++)\n    {\n        if(dot(corners[i] - lightPos, lightNormal) <= 0)\n            return true;\n    }\n\n    return false;\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\nstatic const int MinWaveSize = 16;\nstatic const int MaxNumWaves = NUM_SAMPLES_PER_VOXEL / MinWaveSize;\ngroupshared float g_waveSum[MaxNumWaves];\ngroupshared uint16_t g_waveNumLights[MaxNumWaves];\n\n[numthreads(NUM_SAMPLES_PER_VOXEL, 1, 1)]\nvoid main(uint3 Gid : SV_GroupID, uint Gidx : SV_GroupIndex)\n{\n    const uint3 gridDim = uint3(g_local.GridDim_x, g_local.GridDim_y, g_local.GridDim_z);   \n    const uint gridStart = LVG::FlattenVoxelIndex(Gid, gridDim);\n\n    // if (gridStart * NUM_SAMPLES_PER_VOXEL + Gidx >= g_local.NumTotalSamples)\n    //     return;\n\n    const float3 extents = float3(g_local.Extents_x, g_local.Extents_y, g_local.Extents_z);\n    RNG rng = RNG::Init(gridStart * NUM_SAMPLES_PER_VOXEL + Gidx, g_frame.FrameNum);\n    const float3 voxelCenter = LVG::VoxelCenter(Gid, gridDim, extents, g_frame.CurrViewInv, g_local.Offset_y);\n\n    RT::VoxelSample r;\n    r.pos = FLT_MAX;\n    r.normal = 0;\n    r.le = 0;\n    r.pdf = 0;\n    r.twoSided = false;\n    r.ID = UINT32_MAX;\n\n    float w_sum = 0;\n    float target_z = 0;\n\n    float3 corners[8];\n    corners[0] = float3(-1, -1, -1);\n    corners[1] = float3(-1, -1, 1);\n    corners[2] = float3(-1, 1, -1);\n    corners[3] = float3(-1, 1, 1);\n    corners[4] = float3(1, -1, -1);\n    corners[5] = float3(1, -1, 1);\n    corners[6] = float3(1, 1, -1);\n    corners[7] = float3(1, 1, 1);\n    \n    [unroll]\n    for(int i = 0; i < 8; i++)\n        corners[i] = voxelCenter + corners[i] * extents;\n\n    uint16_t numLights = 0;\n\n    for(int i = 0; i < NUM_CANDIDATES; i++)\n    {\n        Light::AliasTableSample entry = Light::AliasTableSample::get(g_aliasTable, \n            g_frame.NumEmissiveTriangles, rng);\n        RT::EmissiveTriangle tri = g_emissives[entry.idx];\n        Light::EmissiveTriSample lightSample = Light::EmissiveTriSample::get(voxelCenter, tri, \n            rng, false);\n\n        const float3 le = Light::Le_EmissiveTriangle(tri, lightSample.bary, g_frame.EmissiveMapsDescHeapOffset);\n        \n        // \"Snap\" lights inside the voxel to its boundary planes.\n        bool inside;\n        const float3 lightPos = AdjustLightPos(lightSample.pos, voxelCenter, extents, inside);\n\n        // Cull backfacing lights, but only if they're not inside the voxel.\n        if(!inside && !tri.IsDoubleSided())\n        {\n            if(IsBackfacing(lightSample.pos, lightSample.normal, corners))\n                continue;\n        }\n\n        const float t = length(lightPos - voxelCenter);\n\n        const float target = Math::Luminance(le) / max(t * t, 1e-6);\n        const float lightPdf = entry.pdf * lightSample.pdf;\n        float w = target / max(lightPdf, 1e-6);\n        w_sum += w;\n\n        if(rng.Uniform() < w / max(w_sum, 1e-6))\n        {\n            r.pos = lightSample.pos;\n            r.normal = Math::EncodeOct32(lightSample.normal);\n            r.le = half3(le);\n            r.twoSided = tri.IsDoubleSided();\n            r.ID = tri.ID;\n            target_z = target;\n        }\n\n        numLights++;\n    }\n\n    const uint numLanesInWave = WaveGetLaneCount();\n    const uint wave = Gidx / numLanesInWave;\n    const uint numWavesInGroup = NUM_SAMPLES_PER_VOXEL / numLanesInWave;\n    float w_sum_group = WaveActiveSum(w_sum);\n    uint16_t numLightsGroup = WaveActiveSum(numLights);\n    \n    if (WaveIsFirstLane())\n    {\n        g_waveSum[wave] = w_sum_group;\n        g_waveNumLights[wave] = numLightsGroup;\n    }\n    \n    GroupMemoryBarrierWithGroupSync();\n\n    const uint GidxModWaveLen = Gidx - numLanesInWave * wave;\n    w_sum_group = GidxModWaveLen < numWavesInGroup ? g_waveSum[GidxModWaveLen] : 0.0f;\n    numLightsGroup = GidxModWaveLen < numWavesInGroup ? g_waveNumLights[GidxModWaveLen] : (uint16_t)0;\n    // Assuming min wave size of 16, there are at most NUM_SAMPLES_PER_VOXEL / 16 values to \n    // add together, so one WaveActiveSum would be enough as long as NUM_SAMPLES_PER_VOXEL <= 256.\n    w_sum_group = WaveActiveSum(w_sum_group);\n    numLightsGroup = WaveActiveSum(numLightsGroup);\n\n    w_sum_group /= numLightsGroup;\n    r.pdf = target_z / max(w_sum_group, 1e-6);\n\n    g_voxel[gridStart * NUM_SAMPLES_PER_VOXEL + Gidx] = r;\n}"
  },
  {
    "path": "Source/ZetaRenderPass/PreLighting/CMakeLists.txt",
    "content": "set(RP_PRE_LIGHTING_DIR ${ZETA_RENDER_PASS_DIR}/PreLighting)\nset(RP_PRE_LIGHTING_SRC\n    ${RP_PRE_LIGHTING_DIR}/BuildLightVoxelGrid.hlsl\n    ${RP_PRE_LIGHTING_DIR}/EstimateTriEmissivePower.hlsl\n\t${RP_PRE_LIGHTING_DIR}/PreLighting.cpp\n    ${RP_PRE_LIGHTING_DIR}/PreLighting.h\n    ${RP_PRE_LIGHTING_DIR}/PreLighting_Common.h\n    ${RP_PRE_LIGHTING_DIR}/PresampleEmissives.hlsl)\nset(RP_PRE_LIGHTING_SRC ${RP_PRE_LIGHTING_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaRenderPass/PreLighting/EstimateTriEmissivePower.hlsl",
    "content": "#include \"PreLighting_Common.h\"\n#include \"../Common/GBuffers.hlsli\"\n#include \"../Common/LightSource.hlsli\"\n\n#define NUM_SAMPLES_PER_LANE (ESTIMATE_TRI_POWER_NUM_SAMPLES_PER_TRI / ESTIMATE_TRI_POWER_WAVE_LEN)\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b1);\nStructuredBuffer<RT::EmissiveTriangle> g_emissvies : register(t0);\nStructuredBuffer<float2> g_halton : register(t2);\nRWStructuredBuffer<float> g_power : register(u0);\n\n//--------------------------------------------------------------------------------------\n// Helper functions\n//--------------------------------------------------------------------------------------\n\nfloat TriangleArea(float3 vtx0, float3 vtx1, float3 vtx2)\n{\n    return 0.5f * length(cross(vtx1 - vtx0, vtx2 - vtx0));\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[WaveSize(ESTIMATE_TRI_POWER_WAVE_LEN)]\n[numthreads(ESTIMATE_TRI_POWER_GROUP_DIM_X, 1, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint Gidx : SV_GroupIndex)\n{\n    const uint wave = Gidx / ESTIMATE_TRI_POWER_WAVE_LEN;\n    const uint triIdx = Gid.x * ESTIMATE_TRI_POWER_NUM_TRIS_PER_GROUP + wave;\n\n    if (triIdx >= g_frame.NumEmissiveTriangles)\n        return;\n\n    const uint laneIdx = WaveGetLaneIndex();\n    const RT::EmissiveTriangle tri = g_emissvies[triIdx];\n    uint emissiveTex = tri.GetTex();\n\n    float3 power = 0.0f;\n    const bool hasTexture = emissiveTex != Material::INVALID_ID;\n\n    if(hasTexture)\n    {\n        // no need for NonUniformResourceIndex, constant across the wave\n        EMISSIVE_MAP g_emissiveMap = ResourceDescriptorHeap[g_frame.EmissiveMapsDescHeapOffset + emissiveTex];\n        const uint base = laneIdx * NUM_SAMPLES_PER_LANE;\n\n        [unroll]\n        for(int i = 0; i < (int)NUM_SAMPLES_PER_LANE; i++)\n        {\n            float2 u = g_halton[base + i];\n            float2 bary = Sampling::UniformSampleTriangle(u);\n\n            float2 texUV = (1.0f - bary.x - bary.y) * tri.UV0 + bary.x * tri.UV1 + bary.y * tri.UV2;\n            float3 le = g_emissiveMap.SampleLevel(g_samLinearWrap, texUV, 0).rgb;\n            \n            power += le;\n        }\n    }\n\n    power = hasTexture ? WaveActiveSum(power) : ESTIMATE_TRI_POWER_NUM_SAMPLES_PER_TRI;\n\n    const float3 emissiveFactor = tri.GetFactor();\n    const float emissiveStrength = (float)tri.GetStrength();\n    power = power * emissiveFactor * emissiveStrength;\n\n    const float3 vtx1 = Light::DecodeEmissiveTriV1(tri);\n    const float3 vtx2 = Light::DecodeEmissiveTriV2(tri);\n    const float surfaceArea = TriangleArea(tri.Vtx0, vtx1, vtx2);\n    const float pdf = surfaceArea > 0 ? 1.0f / surfaceArea : 0;\n    float mcEstimate = pdf > 0 ? Math::Luminance(power) * PI / (pdf * ESTIMATE_TRI_POWER_NUM_SAMPLES_PER_TRI) : 0;\n\n    if (laneIdx == 0)\n        g_power[triIdx] = mcEstimate;\n}"
  },
  {
    "path": "Source/ZetaRenderPass/PreLighting/PreLighting.cpp",
    "content": "#include \"PreLighting.h\"\n#include <Core/CommandList.h>\n#include <Support/Param.h>\n#include <Math/Sampling.h>\n#include <Scene/SceneCore.h>\n#include <Core/RenderGraph.h>\n#include <Core/SharedShaderResources.h>\n#include <Math/Sampling.h>\n#include <Support/Task.h>\n#include <App/Timer.h>\n#include <App/Log.h>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::App;\nusing namespace ZetaRay::Math;\n\nnamespace\n{\n    // Ref: https://www.keithschwarz.com/darts-dice-coins/\n    void BuildAliasTable(MutableSpan<float> probs, MutableSpan<RT::EmissiveLumenAliasTableEntry> table)\n    {\n        const int64_t N = probs.size();\n        const float oneDivN = 1.0f / N;\n        AliasTable_Normalize(probs);\n\n        for (int64_t i = 0; i < N; i++)\n        {\n            table[i].CachedP_Orig = probs[i] * oneDivN;\n#ifndef NDEBUG\n            table[i].Alias = UINT32_MAX;\n#endif\n        }\n\n        struct TempAllocator\n        {\n            void* AllocateAligned(size_t size, size_t alignment)\n            {\n                m_offset += size;\n                Assert(m_offset <= m_sizeInBytes, \"bug\");\n\n                return m_memPtr;\n            }\n\n            ZetaInline void FreeAligned(void* mem, size_t size, size_t alignment)\n            {}\n\n            void* m_memPtr;\n            size_t m_sizeInBytes;\n            size_t m_offset = 0;\n        };\n\n        const size_t sizeInBytes = N * sizeof(uint32_t);\n        const size_t totalSizeInBytes = 2 * sizeInBytes;\n        App::OneTimeFrameAllocatorWithFallback allocator;\n        void* mem = allocator.AllocateAligned(totalSizeInBytes);\n\n        TempAllocator tempAllocator1{\n            .m_memPtr = mem,\n            .m_sizeInBytes = sizeInBytes };\n        TempAllocator tempAllocator2{\n            .m_memPtr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(mem) + sizeInBytes),\n            .m_sizeInBytes = sizeInBytes };\n\n        // maintain an index buffer since original ordering of elements must be preserved\n        SmallVector<uint32_t, TempAllocator> larger(tempAllocator1);\n        larger.reserve(N);\n\n        SmallVector<uint32_t, TempAllocator> smaller(tempAllocator2);\n        smaller.reserve(N);\n\n        for (int64_t i = 0; i < N; i++)\n        {\n            if (probs[i] < 1.0f)\n                smaller.push_back((uint32_t)i);\n            else\n                larger.push_back((uint32_t)i);\n        }\n\n#ifndef NDEBUG\n        int64_t numInsertions = 0;\n#endif\n\n        // in each iteration, pick two probabilities such that one is smaller than 1.0 and the other larger \n        // than 1.0. Use the latter to bring up the former to 1.0.\n        while (!smaller.empty() && !larger.empty())\n        {\n            const uint32_t smallerIdx = smaller.back();\n            smaller.pop_back();\n            const float smallerProb = probs[smallerIdx];\n\n            const uint32_t largerIdx = larger.back();\n            float largerProb = probs[largerIdx];\n            Assert(largerProb >= 1.0f, \"should be >= 1.0\");\n\n            RT::EmissiveLumenAliasTableEntry& e = table[smallerIdx];\n            Assert(e.Alias == uint32_t(-1), \"Every element must be inserted exactly one time.\");\n            e.Alias = largerIdx;\n            e.P_Curr = smallerProb;\n\n            // = largerProb - (1.0f - smallerProb);\n            largerProb = (smallerProb + largerProb) - 1.0f;\n            probs[largerIdx] = largerProb;\n\n            if (largerProb < 1.0f)\n            {\n                larger.pop_back();\n                smaller.push_back(largerIdx);\n            }\n\n#ifndef NDEBUG\n            numInsertions++;\n#endif\n        }\n\n        while (!larger.empty())\n        {\n            size_t idx = larger.back();\n            larger.pop_back();\n            //Assert(fabsf(1.0f - probs[idx]) <= 0.1f, \"This should be ~1.0.\");\n\n            // alias should point to itself\n            table[idx].Alias = (uint32_t)idx;\n            table[idx].P_Curr = 1.0f;\n\n#ifndef NDEBUG\n            numInsertions++;\n#endif\n        }\n\n        while (!smaller.empty())\n        {\n            size_t idx = smaller.back();\n            smaller.pop_back();\n            //Assert(fabsf(1.0f - probs[idx]) <= 0.1f, \"This should be ~1.0.\");\n\n            // alias should point to itself\n            table[idx].Alias = (uint32_t)idx;\n            table[idx].P_Curr = 1.0f;\n\n#ifndef NDEBUG\n            numInsertions++;\n#endif\n        }\n\n        Assert(numInsertions == N, \"Some elements were not inserted.\");\n\n        for (int64_t i = 0; i < N; i++)\n            table[i].CachedP_Alias = table[table[i].Alias].CachedP_Orig;\n\n        allocator.FreeAligned(mem, sizeInBytes);\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// PreLighting\n//--------------------------------------------------------------------------------------\n\nPreLighting::PreLighting()\n    : RenderPassBase(NUM_CBV, NUM_SRV, NUM_UAV, NUM_GLOBS, NUM_CONSTS)\n{\n    // root constants\n    m_rootSig.InitAsConstants(0, NUM_CONSTS, 0);\n\n    // frame constants\n    m_rootSig.InitAsCBV(1, 1, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::FRAME_CONSTANTS_BUFFER);\n\n    // emissive triangles\n    m_rootSig.InitAsBufferSRV(2, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::EMISSIVE_TRIANGLE_BUFFER,\n        true);\n\n    // alias table\n    m_rootSig.InitAsBufferSRV(3, 1, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::EMISSIVE_TRIANGLE_ALIAS_TABLE,\n        true);\n\n    // halton\n    m_rootSig.InitAsBufferSRV(4, 2, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        nullptr,\n        true);\n\n    // tri power/sample sets\n    m_rootSig.InitAsBufferUAV(5, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_VOLATILE,\n        nullptr,\n        true);\n}\n\nvoid PreLighting::InitPSOs()\n{\n    constexpr D3D12_ROOT_SIGNATURE_FLAGS flags =\n        D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;\n\n    auto samplers = App::GetRenderer().GetStaticSamplers();\n    RenderPassBase::InitRenderPass(\"PreLighting\", flags, samplers);\n\n    TaskSet ts;\n\n    for (int i = 0; i < (int)SHADER::COUNT; i++)\n    {\n        StackStr(buff, n, \"PreLighting_shader_%d\", i);\n\n        ts.EmplaceTask(buff, [i, this]()\n            {\n                m_psoLib.CompileComputePSO_MT(i, m_rootSigObj.Get(), COMPILED_CS[i]);\n            });\n    }\n\n    ts.Sort();\n    ts.Finalize();\n    App::Submit(ZetaMove(ts));\n}\n\nvoid PreLighting::Init()\n{\n    InitPSOs();\n\n    float2 samples[ESTIMATE_TRI_POWER_NUM_SAMPLES_PER_TRI];\n\n    for (int i = 0; i < ESTIMATE_TRI_POWER_NUM_SAMPLES_PER_TRI; i++)\n    {\n        samples[i].x = Halton(i + 1, 2);\n        samples[i].y = Halton(i + 1, 3);\n    }\n\n    const size_t sizeInBytes = ESTIMATE_TRI_POWER_NUM_SAMPLES_PER_TRI * sizeof(float2);\n    m_halton = GpuMemory::GetDefaultHeapBufferAndInit(\"Halton\",\n        (uint32)sizeInBytes,\n        false,\n        MemoryRegion{ .Data = samples, .SizeInBytes = sizeInBytes });\n}\n\nvoid PreLighting::Update()\n{\n    m_estimatePowerThisFrame = false;\n    m_doPresamplingThisFrame = false;\n    m_currNumTris = (uint32_t)App::GetScene().NumEmissiveTriangles();\n    m_useLVG = m_useLVG && (m_currNumTris >= m_minNumLightsForPresampling);\n\n    if (m_currNumTris == 0)\n        return;\n\n    const bool isLVGAllocated = m_lvg.IsInitialized();\n    if ((m_useLVG && !isLVGAllocated) || (!m_useLVG && isLVGAllocated))\n        ToggleLVG();\n\n    if (App::GetScene().AreEmissiveMaterialsStale())\n    {\n        m_estimatePowerThisFrame = true;\n        const size_t currPowerBuffLen = m_triPower.IsInitialized() ? \n            m_triPower.Desc().Width / sizeof(float) : 0;\n\n        if (currPowerBuffLen < m_currNumTris)\n        {\n            const uint32_t sizeInBytes = m_currNumTris * sizeof(float);\n\n            // GPU buffer containing power estimates per triangle\n            m_triPower = GpuMemory::GetDefaultHeapBuffer(\"TriPower\",\n                sizeInBytes,\n                D3D12_RESOURCE_STATE_COMMON,\n                true);\n\n            // Readback buffer to read results on CPU\n            m_readback = GpuMemory::GetReadbackHeapBuffer(sizeInBytes);\n        }\n\n        return;\n    }\n\n    // Skip light presampling when number of emissives is low\n    Assert(m_minNumLightsForPresampling != UINT32_MAX, \n        \"Light presampling is enabled, but presampling params haven't been set.\");\n    if (m_currNumTris < m_minNumLightsForPresampling)\n        return;\n\n    if (App::GetScene().EmissiveLighting())\n    {\n        m_doPresamplingThisFrame = true;\n\n        if (!m_sampleSets.IsInitialized())\n        {\n            Assert(m_numSampleSets > 0 && m_sampleSetSize > 0, \"Rresampling params haven't been set.\");\n            const uint32_t sizeInBytes = m_numSampleSets * m_sampleSetSize * \n                sizeof(RT::PresampledEmissiveTriangle);\n\n            m_sampleSets = GpuMemory::GetDefaultHeapBuffer(\"EmissiveSampleSets\",\n                sizeInBytes,\n                D3D12_RESOURCE_STATE_COMMON,\n                true);\n\n            auto& r = App::GetRenderer().GetSharedShaderResources();\n            r.InsertOrAssignDefaultHeapBuffer(GlobalResource::PRESAMPLED_EMISSIVE_SETS, \n                m_sampleSets);\n        }\n    }\n}\n\nvoid PreLighting::Render(CommandList& cmdList)\n{\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT ||\n        cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE, \"Invalid downcast\");\n    ComputeCmdList& computeCmdList = static_cast<ComputeCmdList&>(cmdList);\n\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n    const uint32_t w = renderer.GetRenderWidth();\n    const uint32_t h = renderer.GetRenderHeight();\n\n    computeCmdList.SetRootSignature(m_rootSig, m_rootSigObj.Get());\n\n    if (m_estimatePowerThisFrame)\n    {\n        Assert(m_readback.IsInitialized(), \"no readback buffer.\");\n        Assert(!m_readback.IsMapped(), \"readback buffer can't be mapped while in use by the GPU.\");\n        Assert(m_triPower.IsInitialized(), \"Tri emissive power buffer hasn't been initialized.\");\n\n        const uint32_t dispatchDimX = CeilUnsignedIntDiv(m_currNumTris, ESTIMATE_TRI_POWER_NUM_TRIS_PER_GROUP);\n        Assert(dispatchDimX <= D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION, \"#blocks exceeded maximum allowed.\");\n\n        computeCmdList.PIXBeginEvent(\"EstimateTriPower\");\n        const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"EstimateTriPower\");\n\n        computeCmdList.ResourceBarrier(m_triPower.Resource(),\n            D3D12_RESOURCE_STATE_COPY_SOURCE,\n            D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n\n        m_rootSig.SetRootSRV(4, m_halton.GpuVA());\n        m_rootSig.SetRootUAV(5, m_triPower.GpuVA());\n\n        m_rootSig.End(computeCmdList);\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::ESTIMATE_TRIANGLE_POWER));\n        computeCmdList.Dispatch(dispatchDimX, 1, 1);\n\n        // copy results to readback buffer, so alias table can be computed on the cpu\n        computeCmdList.ResourceBarrier(m_triPower.Resource(),\n            D3D12_RESOURCE_STATE_UNORDERED_ACCESS,\n            D3D12_RESOURCE_STATE_COPY_SOURCE);\n\n        computeCmdList.CopyBufferRegion(m_readback.Resource(),\n            0,\n            m_triPower.Resource(),\n            0,\n            m_currNumTris * sizeof(float));\n\n        gpuTimer.EndQuery(computeCmdList, queryIdx);\n        computeCmdList.PIXEndEvent();\n    }\n\n    if (m_doPresamplingThisFrame)\n    {\n        const uint32_t numSamples = m_numSampleSets * m_sampleSetSize;\n        const uint32_t dispatchDimX = CeilUnsignedIntDiv(numSamples, PRESAMPLE_EMISSIVE_GROUP_DIM_X);\n        Assert(dispatchDimX <= D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION, \"#blocks exceeded maximum allowed.\");\n\n        computeCmdList.PIXBeginEvent(\"PresampleEmissives\");\n        const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"PresampleEmissives\");\n\n        // \"buffers MAY be initially accessed in an ExecuteCommandLists scope without a Barrier...Additionally, a buffer \n        // or texture using a queue-specific common layout can use D3D12_BARRIER_ACCESS_UNORDERED_ACCESS without a barrier.\"\n        // Ref: https://microsoft.github.io/DirectX-Specs/d3d/D3D12EnhancedBarriers.html\n#if 0\n        D3D12_BUFFER_BARRIER barrier = Direct3DUtil::BufferBarrier(m_sampleSets.Resource(),\n            D3D12_BARRIER_SYNC_NONE,\n            D3D12_BARRIER_SYNC_COMPUTE_SHADING,\n            D3D12_BARRIER_ACCESS_NO_ACCESS,\n            D3D12_BARRIER_ACCESS_UNORDERED_ACCESS);\n\n        computeCmdList.ResourceBarrier(barrier);\n#endif\n\n        cbPresampling cb;\n        cb.NumTotalSamples = numSamples;\n\n        m_rootSig.SetRootConstants(0, sizeof(cb) / sizeof(DWORD), &cb);\n        m_rootSig.SetRootUAV(5, m_sampleSets.GpuVA());\n        m_rootSig.End(computeCmdList);\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::PRESAMPLING));\n        computeCmdList.Dispatch(dispatchDimX, 1, 1);\n\n        gpuTimer.EndQuery(computeCmdList, queryIdx);\n        cmdList.PIXEndEvent();\n    }\n\n    if (m_buildLVGThisFrame && m_lvg.IsInitialized())\n    {\n        computeCmdList.PIXBeginEvent(\"LightVoxelGrid\");\n        const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"LightVoxelGrid\");\n\n        cbLVG cb;\n        cb.GridDim_x = m_voxelGridDim.x;\n        cb.GridDim_y = m_voxelGridDim.y;\n        cb.GridDim_z = m_voxelGridDim.z;\n        cb.Extents_x = m_voxelExtents.x;\n        cb.Extents_y = m_voxelExtents.y;\n        cb.Extents_z = m_voxelExtents.z;\n        cb.NumTotalSamples = NUM_SAMPLES_PER_VOXEL * m_voxelGridDim.x * m_voxelGridDim.y * m_voxelGridDim.z;\n\n        m_rootSig.SetRootConstants(0, sizeof(cb) / sizeof(DWORD), &cb);\n        m_rootSig.SetRootUAV(5, m_lvg.GpuVA());\n        m_rootSig.End(computeCmdList);\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::BUILD_LIGHT_VOXEL_GRID));\n        computeCmdList.Dispatch(m_voxelGridDim.x, m_voxelGridDim.y, m_voxelGridDim.z);\n\n        gpuTimer.EndQuery(computeCmdList, queryIdx);\n        cmdList.PIXEndEvent();\n    }\n}\n\nvoid PreLighting::ToggleLVG()\n{\n    if (m_useLVG)\n    {\n        Assert(!m_lvg.IsInitialized(), \"Redundant call.\");\n        const size_t sizeInBytes = NUM_SAMPLES_PER_VOXEL * m_voxelGridDim.x * m_voxelGridDim.y * m_voxelGridDim.z *\n            sizeof(RT::VoxelSample);\n\n        m_lvg = GpuMemory::GetDefaultHeapBuffer(\"LVG\",\n            (uint32_t)sizeInBytes,\n            D3D12_RESOURCE_STATE_COMMON,\n            true);\n\n        auto& r = App::GetRenderer().GetSharedShaderResources();\n        r.InsertOrAssignDefaultHeapBuffer(GlobalResource::LIGHT_VOXEL_GRID, m_lvg);\n\n\n\n        App::AddShaderReloadHandler(\"BuildLightVoxelGrid\", fastdelegate::MakeDelegate(this, &PreLighting::ReloadBuildLVG));\n    }\n    else\n    {\n        Assert(m_lvg.IsInitialized(), \"Redundant call.\");\n\n        auto& r = App::GetRenderer().GetSharedShaderResources();\n        r.RemoveDefaultHeapBuffer(GlobalResource::LIGHT_VOXEL_GRID, m_lvg);\n\n        App::RemoveParam(\"Renderer\", \"Light Voxel Grid\", \"Extents\");\n        App::RemoveParam(\"Renderer\", \"Light Voxel Grid\", \"Y Offset\");\n\n        App::RemoveShaderReloadHandler(\"BuildLightVoxelGrid\");\n        m_lvg.Reset();\n    }\n}\n\nvoid PreLighting::ReleaseTriPowerBufferAndReadback()\n{\n    m_triPower.Reset();\n    m_readback.Reset();\n    m_buildLVGThisFrame = m_useLVG;\n}\n\nvoid PreLighting::ReloadBuildLVG()\n{\n    const int i = (int)SHADER::BUILD_LIGHT_VOXEL_GRID;\n    m_psoLib.Reload(i, m_rootSigObj.Get(), \"PreLighting\\\\BuildLightVoxelGrid.hlsl\");\n}\n\n//--------------------------------------------------------------------------------------\n// EmissiveTriangleAliasTable\n//--------------------------------------------------------------------------------------\n\nvoid EmissiveTriangleAliasTable::Update(ReadbackHeapBuffer* readback)\n{\n    Assert(readback, \"Readback buffer was NULL.\");\n    m_readback = readback;\n\n    const size_t currBuffLen = m_aliasTable.IsInitialized() ? \n        m_aliasTable.Desc().Width / sizeof(float) : 0;\n    m_currNumTris = (uint32_t)App::GetScene().NumEmissiveTriangles();\n    Assert(m_currNumTris, \"redundant call.\");\n\n    if (currBuffLen < m_currNumTris)\n    {\n        m_aliasTable = GpuMemory::GetDefaultHeapBuffer(\"AliasTable\",\n            m_currNumTris * sizeof(RT::EmissiveLumenAliasTableEntry),\n            D3D12_RESOURCE_STATE_COMMON,\n            false);\n\n        auto& r = App::GetRenderer().GetSharedShaderResources();\n        r.InsertOrAssignDefaultHeapBuffer(\n            GlobalResource::EMISSIVE_TRIANGLE_ALIAS_TABLE, m_aliasTable);\n    }\n}\n\nvoid EmissiveTriangleAliasTable::SetEmissiveTriPassHandle(RenderNodeHandle& emissiveTriHandle)\n{\n    Assert(emissiveTriHandle.IsValid(), \"invalid handle.\");\n    m_emissiveTriHandle = emissiveTriHandle.Val;\n}\n\nvoid EmissiveTriangleAliasTable::Render(CommandList& cmdList)\n{\n    Assert(m_readback, \"Readback buffer hasn't been set.\");\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT ||\n        cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE, \"Invalid downcast\");\n    ComputeCmdList& computeCmdList = static_cast<ComputeCmdList&>(cmdList);\n\n    auto& renderer = App::GetRenderer();\n\n    m_fence = m_fence == UINT64_MAX ?\n        App::GetScene().GetRenderGraph()->GetCompletionFence(RenderNodeHandle(m_emissiveTriHandle)) :\n        m_fence;\n    Assert(m_fence != UINT64_MAX, \"Invalid fence value.\");\n\n    // For 1st frame, wait until GPU finishes copying data to readback buffer. For subsequent\n    // frames, check the fence and defer to next frame if not ready.\n    if(App::GetTimer().GetTotalFrameCount() <= 1)\n        renderer.WaitForDirectQueueFenceCPU(m_fence);\n    else if (!renderer.IsDirectQueueFenceComplete(m_fence))\n    {\n        LOG_UI_INFO(\"Alias table - fence hasn't passed, returning...\");\n        return;\n    }\n\n    // Try to use frame allocator first, if it fails (allocation size exceeded per-frame max),\n    // use malloc instead\n    SmallVector<RT::EmissiveLumenAliasTableEntry, App::OneTimeFrameAllocatorWithFallback> table;\n    table.resize(m_currNumTris);\n\n    App::DeltaTimer timer;\n    timer.Start();\n\n    {\n        // Safe to map, related fence has passed\n        m_readback->Map();\n\n        float* data = reinterpret_cast<float*>(m_readback->MappedMemory());\n        BuildAliasTable(MutableSpan(data, m_currNumTris), table);\n\n        // Unmapping happens automatically when readback buffer is released\n        //m_readback->Unmap();\n    }\n\n    timer.End();\n    LOG_UI_INFO(\"Alias table - computation took %u [us].\", (uint32_t)timer.DeltaMicro());\n\n    auto& gpuTimer = renderer.GetGpuTimer();\n    const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"UploadAliasTable\");\n    computeCmdList.PIXBeginEvent(\"UploadAliasTable\");\n\n    // Schedule a copy\n    const uint32_t sizeInBytes = sizeof(RT::EmissiveLumenAliasTableEntry) * m_currNumTris;\n    m_aliasTableUpload = GpuMemory::GetUploadHeapBuffer(sizeInBytes);\n    m_aliasTableUpload.Copy(0, sizeInBytes, table.data());\n    computeCmdList.CopyBufferRegion(m_aliasTable.Resource(),\n        0,\n        m_aliasTableUpload.Resource(),\n        m_aliasTableUpload.Offset(),\n        sizeInBytes);\n\n    computeCmdList.ResourceBarrier(m_aliasTable.Resource(),\n        D3D12_RESOURCE_STATE_COPY_DEST,\n        D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n\n    gpuTimer.EndQuery(computeCmdList, queryIdx);\n    cmdList.PIXEndEvent();\n\n    // Even though at this point this command list hasn't been submitted yet (only recorded),\n    // it's safe to release the buffers here -- this is because resource deallocation\n    // and signalling the related fence happens at the end of frame when all command \n    // lists have been submitted\n    m_releaseDlg();\n    m_fence = UINT64_MAX;\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/PreLighting/PreLighting.h",
    "content": "#pragma once\n\n#include \"../RenderPass.h\"\n#include <Core/GpuMemory.h>\n#include \"PreLighting_Common.h\"\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n    struct RenderNodeHandle;\n}\n\nnamespace ZetaRay::Support\n{\n    struct ParamVariant;\n}\n\nnamespace ZetaRay::RenderPass\n{\n    enum class PRE_LIGHTING_SHADER\n    {\n        ESTIMATE_TRIANGLE_POWER,\n        PRESAMPLING,\n        BUILD_LIGHT_VOXEL_GRID,\n        COUNT\n    };\n\n    struct PreLighting final : public RenderPassBase<(int)PRE_LIGHTING_SHADER::COUNT>\n    {\n        PreLighting();\n        ~PreLighting() = default;\n\n        void InitPSOs();\n        void Init();\n        void OnWindowResized() {};\n        void SetLightPresamplingParams(uint32_t minToEnale, uint32_t numSampleSets, uint32_t sampleSetSize)\n        { \n            m_minNumLightsForPresampling = minToEnale;\n            m_numSampleSets = numSampleSets;\n            m_sampleSetSize = sampleSetSize;\n        }\n        void SetLightVoxelGridParams(bool enabled, const Math::uint3& gridDim, const Math::float3& extents, float offset_y)\n        {\n            m_useLVG = enabled;\n            m_voxelGridDim = gridDim;\n            m_voxelExtents = extents;\n            m_yOffset = offset_y;\n        }\n        const Core::GpuMemory::Buffer& GetTriEmissivePowerBuffer() { return m_triPower; }\n        const Core::GpuMemory::Buffer& GePresampledSets() { return m_sampleSets; }\n        const Core::GpuMemory::Buffer& GetLightVoxelGrid() { return m_lvg; }\n        Core::GpuMemory::ReadbackHeapBuffer& GetLumenReadbackBuffer() { return m_readback; }\n        // Releasing the power buffer and its readback buffer should happen after the alias table \n        // has been calculated. Delegate that to code that does that calculation.\n        auto GetReleaseBuffersDlg() { return fastdelegate::MakeDelegate(this, &PreLighting::ReleaseTriPowerBufferAndReadback); };\n\n        void Update();\n        void Render(Core::CommandList& cmdList);\n\n    private:\n        static constexpr int NUM_CBV = 1;\n        static constexpr int NUM_SRV = 3;\n        static constexpr int NUM_UAV = 1;\n        static constexpr int NUM_GLOBS = 3;\n        static constexpr int NUM_CONSTS = (int)Math::Max(sizeof(cbPresampling) / sizeof(DWORD), \n            Math::Max(sizeof(cbLVG) / sizeof(DWORD), sizeof(cbCurvature) / sizeof(DWORD)));\n        using SHADER = PRE_LIGHTING_SHADER;\n\n        inline static constexpr const char* COMPILED_CS[(int)SHADER::COUNT] = {\n            \"EstimateTriEmissivePower_cs.cso\",\n            \"PresampleEmissives_cs.cso\",\n            \"BuildLightVoxelGrid_cs.cso\"\n        };\n\n        void ToggleLVG();\n        void ReleaseTriPowerBufferAndReadback();\n        void ReloadBuildLVG();\n\n        Core::GpuMemory::Buffer m_halton;\n        Core::GpuMemory::Buffer m_triPower;\n        Core::GpuMemory::ReadbackHeapBuffer m_readback;\n        Core::GpuMemory::Buffer m_sampleSets;\n        Core::GpuMemory::Buffer m_lvg;\n        uint32_t m_currNumTris = 0;\n        uint32_t m_minNumLightsForPresampling = UINT32_MAX;\n        uint32_t m_numSampleSets = 0;\n        uint32_t m_sampleSetSize = 0;\n        Math::uint3 m_voxelGridDim;\n        Math::float3 m_voxelExtents;\n        float m_yOffset = 0.0;\n        bool m_estimatePowerThisFrame;\n        bool m_doPresamplingThisFrame;\n        bool m_buildLVGThisFrame = false;\n        bool m_useLVG = false;\n    };\n\n    struct EmissiveTriangleAliasTable\n    {\n        enum class SHADER_OUT_RES\n        {\n            ALIAS_TABLE,\n            COUNT\n        };\n\n        EmissiveTriangleAliasTable() = default;\n        ~EmissiveTriangleAliasTable() = default;\n\n        ZetaInline Core::GpuMemory::Buffer& GetOutput(SHADER_OUT_RES i)\n        {\n            Assert((int)i < (int)SHADER_OUT_RES::COUNT, \"out-of-bound access.\");\n            return m_aliasTable;\n        }\n        ZetaInline void SetReleaseBuffersDlg(fastdelegate::FastDelegate0<> dlg) { m_releaseDlg = dlg; }\n        ZetaInline bool HasPendingRender() { return m_fence != UINT64_MAX; }\n\n        void Update(Core::GpuMemory::ReadbackHeapBuffer* readback);\n        void SetEmissiveTriPassHandle(Core::RenderNodeHandle& emissiveTriHandle);\n        void Render(Core::CommandList& cmdList);\n\n    private:\n        Core::GpuMemory::Buffer m_aliasTable;\n        Core::GpuMemory::UploadHeapBuffer m_aliasTableUpload;\n        Core::GpuMemory::ReadbackHeapBuffer* m_readback = nullptr;\n        fastdelegate::FastDelegate0<> m_releaseDlg;\n        uint32_t m_currNumTris = 0;\n        int m_emissiveTriHandle = -1;\n        uint64_t m_fence = UINT64_MAX;\n    };\n}"
  },
  {
    "path": "Source/ZetaRenderPass/PreLighting/PreLighting_Common.h",
    "content": "#ifndef PRE_LIGHTING_COMMON_H\n#define PRE_LIGHTING_COMMON_H\n\n#include \"../../ZetaCore/Core/HLSLCompat.h\"\n#include \"../../ZetaCore/RayTracing/RtCommon.h\"\n\n#define ESTIMATE_TRI_POWER_GROUP_DIM_X 256u\n#define ESTIMATE_TRI_POWER_NUM_SAMPLES_PER_TRI 64\n#define ESTIMATE_TRI_POWER_WAVE_LEN 32\n#define ESTIMATE_TRI_POWER_NUM_TRIS_PER_GROUP (ESTIMATE_TRI_POWER_GROUP_DIM_X / ESTIMATE_TRI_POWER_WAVE_LEN)\n\n#define PRESAMPLE_EMISSIVE_GROUP_DIM_X 64u\n\n#define NUM_SAMPLES_PER_VOXEL 64\n\nstruct cbPresampling\n{\n    uint32_t NumTotalSamples;\n};\n\nstruct cbCurvature\n{\n    uint32_t OutputUAVDescHeapIdx;\n};\n\nstruct cbLVG\n{\n    float Extents_x;\n    float Extents_y;\n    float Extents_z;\n    float Offset_y;\n    uint32_t GridDim_x;\n    uint32_t GridDim_y;\n    uint32_t GridDim_z;\n    uint32_t NumTotalSamples;\n};\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/PreLighting/PresampleEmissives.hlsl",
    "content": "#include \"PreLighting_Common.h\"\n#include \"../Common/FrameConstants.h\"\n#include \"../Common/LightSource.hlsli\"\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbPresampling> g_local : register(b0);\nConstantBuffer<cbFrameConstants> g_frame : register(b1);\nStructuredBuffer<RT::EmissiveTriangle> g_emissives : register(t0);\nStructuredBuffer<RT::EmissiveLumenAliasTableEntry> g_aliasTable : register(t1);\nRWStructuredBuffer<RT::PresampledEmissiveTriangle> g_sampleSets : register(u0);\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(PRESAMPLE_EMISSIVE_GROUP_DIM_X, 1, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint Gidx : SV_GroupIndex)\n{\n    if (DTid.x >= g_local.NumTotalSamples)\n        return;\n\n    RNG rng = RNG::Init(DTid.x, g_frame.FrameNum);\n\n    Light::AliasTableSample entry = Light::AliasTableSample::get(g_aliasTable, \n        g_frame.NumEmissiveTriangles, rng);\n    RT::EmissiveTriangle tri = g_emissives[entry.idx];\n    Light::EmissiveTriSample lightSample = Light::EmissiveTriSample::get(/*unused*/ 0, tri, rng, false);\n\n    float3 le = Light::Le_EmissiveTriangle(tri, lightSample.bary, g_frame.EmissiveMapsDescHeapOffset);\n\n    RT::PresampledEmissiveTriangle s;\n    s.pos = lightSample.pos;\n    s.normal = Math::EncodeOct32(lightSample.normal);\n    s.le = half3(le);\n    s.bary = Math::EncodeAsUNorm2(lightSample.bary);;\n    s.twoSided = tri.IsDoubleSided();\n    s.idx = entry.idx;\n    s.ID = tri.ID;\n    s.pdf = entry.pdf * lightSample.pdf;\n\n    g_sampleSets[DTid.x] = s;\n}"
  },
  {
    "path": "Source/ZetaRenderPass/RenderPass.h",
    "content": "#pragma once\n\n#include <Core/PipelineStateLibrary.h>\n#include <Core/RootSignature.h>\n#include <Core/RendererCore.h>\n\nnamespace ZetaRay::RenderPass\n{\n    template<int nShaders>\n    struct RenderPassBase\n    {\n    public:\n        // Note: allocation may be conflated with initialization -- here, the memory for \n        // all render passes is allocated at startup and released upon shutdown. So even\n        // after reset, the actual memory for the render pass object is not freed, only that\n        // of resources and device objects included in the object.\n        ZetaInline bool IsInitialized() const { return m_rootSigObj != nullptr; }\n        void Reset(bool waitForGPU)\n        {\n            if (!IsInitialized())\n                return;\n\n            if (waitForGPU)\n            {\n                ComPtr<ID3D12Fence> m_fence;\n                CheckHR(App::GetRenderer().GetDevice()->CreateFence(0, D3D12_FENCE_FLAG_NONE,\n                    IID_PPV_ARGS(m_fence.GetAddressOf())));\n\n                App::GetRenderer().SignalDirectQueue(m_fence.Get(), 1);\n\n                if (m_fence->GetCompletedValue() < 1)\n                {\n                    HANDLE handle = CreateEventA(nullptr, false, false, nullptr);\n                    CheckWin32(handle);\n                    CheckHR(m_fence->SetEventOnCompletion(1, handle));\n\n                    WaitForSingleObject(handle, INFINITE);\n                    CloseHandle(handle);\n                }\n            }\n\n            m_psoLib.Reset();\n            uint32_t reftCount = m_rootSigObj.Reset();\n            Assert(reftCount == 0, \"unexpected ref count.\");\n        }\n\n    protected:\n        RenderPassBase(int nRootCBV, int nRootSRV, int nRootUAV, \n            int nRootGlobs, int nRootConsts)\n            : m_rootSig(nRootCBV, nRootSRV, nRootUAV, nRootGlobs, nRootConsts),\n            m_psoLib(m_psoCache)\n        {}\n        ~RenderPassBase()\n        {\n            // \n            //if (IsInitialized())\n            //{\n            //    uint32_t reftCount = m_rootSigObj.Reset();\n            //    Assert(reftCount == 0, \"unexpected ref count.\");\n            //}\n        }\n\n        RenderPassBase(RenderPassBase&&) = delete;\n        RenderPassBase& operator=(RenderPassBase&&) = delete;\n\n        void InitRenderPass(const char* name,\n            D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE,\n            Util::Span<D3D12_STATIC_SAMPLER_DESC> samplers = Util::Span<D3D12_STATIC_SAMPLER_DESC>(nullptr, 0))\n        {\n            Assert(!m_rootSigObj, \"Attempting to double-init.\");\n            m_rootSig.Finalize(name, m_rootSigObj, samplers, flags);\n            m_psoLib.Init(name);\n        }\n\n        Core::PipelineStateLibrary m_psoLib;\n        Core::RootSignature m_rootSig;\n        ComPtr<ID3D12RootSignature> m_rootSigObj;\n\n        ID3D12PipelineState* m_psoCache[nShaders] = { 0 };\n    };\n}"
  },
  {
    "path": "Source/ZetaRenderPass/Sky/CMakeLists.txt",
    "content": "set(RP_SKY_DIR ${ZETA_RENDER_PASS_DIR}/Sky)\nset(RP_SKY_SRC\n    ${RP_SKY_DIR}/Sky.cpp\n    ${RP_SKY_DIR}/Sky.h\n    ${RP_SKY_DIR}/Inscattering.hlsl\n    ${RP_SKY_DIR}/SkyViewLUT.hlsl\n    ${RP_SKY_DIR}/Sky_Common.h)\n\nset(RP_SKY_SRC ${RP_SKY_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaRenderPass/Sky/Inscattering.hlsl",
    "content": "#include \"../Common/StaticTextureSamplers.hlsli\"\n#include \"../Common/FrameConstants.h\"\n#include \"../Common/Volumetric.hlsli\"\n#include \"../Common/RT.hlsli\"\n#include \"Sky_Common.h\"\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbSky> g_local : register(b0, space0);\nConstantBuffer<cbFrameConstants> g_frame : register(b1, space0);\nRaytracingAccelerationStructure g_bvh : register(t0, space0);\n\n//--------------------------------------------------------------------------------------\n// Globals\n//--------------------------------------------------------------------------------------\n\n// assumes wave size of at least 32\n#define WAVE_SIZE 32 \n#define LOG_WAVE_SIZE 5\n\ngroupshared float3 g_waveTr[WAVE_SIZE];\ngroupshared float3 g_waveLs[WAVE_SIZE];\n\nstatic const float Halton[8] = { 0.5f, 0.25f, 0.75f, 0.125f, 0.625f, 0.375f, 0.875f, 0.0625f };\n\n//--------------------------------------------------------------------------------------\n// Helper Functions\n//--------------------------------------------------------------------------------------\n\nfloat VoxelLinearDepth(uint voxelZ)\n{\n//    float z = g_local.VoxelGridNearZ + ((float) voxelZ / NUM_SLICES) * (g_local.VoxelGridDepth - 0.03f);\n//    z *= exp(-(NUM_SLICES - voxelZ - 1) / NUM_SLICES);\n\n    float z = g_local.VoxelGridNearZ + pow((float)voxelZ / float(INSCATTERING_THREAD_GROUP_SIZE_X), \n        g_local.DepthMappingExp) *\n        (g_local.VoxelGridFarZ - g_local.VoxelGridNearZ);\n\n    return z;\n}\n\nfloat Visibility(float3 pos, float3 wi)\n{\n    RayQuery<RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH |\n        RAY_FLAG_SKIP_CLOSEST_HIT_SHADER |\n        RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES |\n        RAY_FLAG_CULL_NON_OPAQUE> rayQuery;\n\n    RayDesc ray;\n    ray.Origin = pos;\n    ray.TMin = 0.0f;\n    ray.TMax = FLT_MAX;\n    ray.Direction = wi;\n    \n    rayQuery.TraceRayInline(g_bvh, RAY_FLAG_NONE, RT_AS_SUBGROUP::ALL, ray);\n    rayQuery.Proceed();\n\n    if (rayQuery.CommittedStatus() == COMMITTED_TRIANGLE_HIT)\n        return 0.0f;\n    \n    return 1.0f;\n}\n\nvoid ComputeVoxelData(in float3 pos, in float3 sigma_t_rayleigh, in float sigma_t_mie, \n    in float3 sigma_t_ozone, out float3 LoTranmittance, out float3 density)\n{\n    pos.y += g_frame.PlanetRadius;\n    const float altitude = Volume::Altitude(pos, g_frame.PlanetRadius);\n    density = Volume::AtmosphereDensity(altitude);\n\n    const float posToAtmosphereDist = Volume::IntersectRayAtmosphere(\n        g_frame.PlanetRadius + g_frame.AtmosphereAltitude, pos, -g_frame.SunDir);\n    LoTranmittance = Volume::EstimateTransmittance(g_frame.PlanetRadius, pos, \n        -g_frame.SunDir, posToAtmosphereDist, sigma_t_rayleigh, sigma_t_mie, \n        sigma_t_ozone, 8);\n\n    pos.y -= g_frame.PlanetRadius;\n    const float isSunVisibleFromPos = Visibility(pos, -g_frame.SunDir);\n    LoTranmittance *= isSunVisibleFromPos;\n}\n\nvoid Integrate(float3 rayDir, float ds, float3 sigma_s_rayleigh, float sigma_s_mie, \n    float sigma_t_mie, float3 sigma_t_ozone, float3 LoTranmittance, float3 density, \n    inout float3 waveStartToPosTr, out float3 Ls)\n{\n    const float3 sliceDensity = density * ds;\n    const float3 opticalThickness = WavePrefixSum(sliceDensity) + sliceDensity;\n\n    // transmittance from beginning of this wave to position of this lane\n    waveStartToPosTr = exp(-(sigma_s_rayleigh * opticalThickness.x +\n            sigma_t_mie * opticalThickness.y +\n            sigma_t_ozone * opticalThickness.z));\n\n    const float3 common = waveStartToPosTr * LoTranmittance * ds;    \n    const float3 sliceLsRayleigh = common * density.x;\n    const float3 sliceLsMie = common * density.y;\n\n    const float3 LsRayleigh = WavePrefixSum(sliceLsRayleigh) + sliceLsRayleigh;\n    const float3 LsMie = WavePrefixSum(sliceLsMie) + sliceLsMie;\n\n    // following are constant when sun is the light source\n    const float cosTheta = dot(g_frame.SunDir, -rayDir);\n    const float phaseRayleigh = Volume::RayleighPhaseFunction(cosTheta);\n    const float phaseMie = Volume::SchlickPhaseFunction(cosTheta, g_frame.g);\n\n    Ls = LsRayleigh * sigma_s_rayleigh * phaseRayleigh + LsMie * sigma_s_mie * phaseMie;\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[WaveSize(WAVE_SIZE)]\n[numthreads(INSCATTERING_THREAD_GROUP_SIZE_X, INSCATTERING_THREAD_GROUP_SIZE_Y, INSCATTERING_THREAD_GROUP_SIZE_Z)]\nvoid main(uint Gidx : SV_GroupIndex, uint3 Gid : SV_GroupID)\n{\n    const uint3 voxelID = uint3(Gid.xy, Gidx);\n    const float2 posUV = (Gid.xy + 0.5f) / float2(g_local.NumVoxelsX, g_local.NumVoxelsY);\n\n    const float3 viewBasisX = g_frame.CurrView[0].xyz;\n    const float3 viewBasisY = g_frame.CurrView[1].xyz;\n    const float3 viewBasisZ = g_frame.CurrView[2].xyz;\n\n    float2 posNDC = mad(posUV, 2.0, -1.0f);\n    posNDC.y = -posNDC.y;\n    posNDC.x *= g_frame.AspectRatio;\n    posNDC *= g_frame.TanHalfFOV;\n    const float3 dirV = float3(posNDC, 1.0f);\n    const float3 dirW = mad(dirV.x, viewBasisX, mad(dirV.y, viewBasisY, dirV.z * viewBasisZ));\n\n    const float3 rayDirVS = normalize(dirV);\n    const float3 rayDirWS = normalize(dirW);\n\n    // exponentially distributed slices along the frustum-aligned voxel grid depth\n    // \n    // |--------|------------|------------------|-------------------------|\n    // |  Voxel |   Voxel    |      Voxel       |          Voxel          | ...\n    //    \n    // ----> z\n    //\n\n    // slice-depth for this voxel\n    const float currSliceStartLinearDepth = VoxelLinearDepth(voxelID.z);\n    const float nextSliceStarLineartDepth = VoxelLinearDepth(voxelID.z + 1);    \n    const float ds = ((nextSliceStarLineartDepth - currSliceStartLinearDepth) / rayDirVS.z);\n\n    // sample position\n    const float sliceStartT = currSliceStartLinearDepth / rayDirVS.z;\n    const float offset = Halton[g_frame.FrameNum & 7];\n    float3 voxelPos = g_frame.CameraPos + rayDirWS * (sliceStartT + offset * ds);\n\n    const float3 sigma_s_rayleigh = g_frame.RayleighSigmaSColor * g_frame.RayleighSigmaSScale;\n    const float sigma_t_mie = g_frame.MieSigmaA + g_frame.MieSigmaS;\n    const float3 sigma_t_ozone = g_frame.OzoneSigmaAColor * g_frame.OzoneSigmaAScale;\n\n    //\n    // compute voxel data\n    //\n\n    float3 density;\n    float3 LoTransmittance;\n    ComputeVoxelData(voxelPos, sigma_s_rayleigh, sigma_t_mie, sigma_t_ozone, \n        LoTransmittance, density);\n\n    //\n    // integrate across wave\n    //\n\n    float3 tr;\n    float3 Ls;\n    Integrate(rayDirWS, ds, sigma_s_rayleigh, g_frame.MieSigmaS, sigma_t_mie, \n        sigma_t_ozone, LoTransmittance, density, tr, Ls);\n\n    // wave size is always a power of 2\n    const uint waveIdx = voxelID.z >> LOG_WAVE_SIZE;\n\n    if ((Gidx & (WAVE_SIZE - 1)) == WAVE_SIZE - 1)\n    {\n        g_waveTr[waveIdx] = WaveReadLaneAt(tr, WaveGetLaneCount() - 1);\n        g_waveLs[waveIdx] = WaveReadLaneAt(Ls, WaveGetLaneCount() - 1);\n    }\n\n    GroupMemoryBarrierWithGroupSync();\n\n    float3 totalTr = 1.0f;\n    float3 prevLs = 0.0f;\n\n    // Account for inscattering and transmittance from earlier waves.\n    // Transmittance from wave start to each voxel is already accounted for.\n    for (uint wave = 0; wave < waveIdx; wave++)\n    {\n        prevLs += g_waveLs[wave] * totalTr;\n        totalTr *= g_waveTr[wave];        // transmittance is multiplicative along a given ray\n    }\n\n    Ls = Ls * totalTr + prevLs;\n\n    RWTexture3D<half4> g_voxelGrid = ResourceDescriptorHeap[g_local.VoxelGridDescHeapIdx];    \n\n    // R11G11B10 doesn't have a sign bit\n    Ls = max(Ls, 0.0f);\n    g_voxelGrid[voxelID].xyz = half3(Ls * g_frame.SunIlluminance);\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/Sky/Sky.cpp",
    "content": "#include \"Sky.h\"\n#include <Core/CommandList.h>\n#include <Scene/SceneCore.h>\n#include <Support/Param.h>\n\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Scene;\n\n//--------------------------------------------------------------------------------------\n// Sky\n//--------------------------------------------------------------------------------------\n\nSky::Sky()\n    : RenderPassBase(NUM_CBV, NUM_SRV, NUM_UAV, NUM_GLOBS, NUM_CONSTS)\n{\n    // root constants\n    m_rootSig.InitAsConstants(0, NUM_CONSTS, 0);\n\n    // frame constants\n    m_rootSig.InitAsCBV(1, 1, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::FRAME_CONSTANTS_BUFFER);\n\n    // BVH\n    m_rootSig.InitAsBufferSRV(2, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC,\n        GlobalResource::RT_SCENE_BVH_CURR);\n}\n\nvoid Sky::Init(int lutWidth, int lutHeight, bool doInscattering)\n{\n    Assert(lutHeight > 0 && lutWidth > 0, \"invalid texture dimensions\");\n    m_localCB.LutWidth = lutWidth;\n    m_localCB.LutHeight = lutHeight;\n\n    constexpr D3D12_ROOT_SIGNATURE_FLAGS flags =\n        D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;\n\n    auto& renderer = App::GetRenderer();\n    auto samplers = renderer.GetStaticSamplers();\n    RenderPassBase::InitRenderPass(\"Sky\", flags, samplers);\n\n    m_psoLib.CompileComputePSO((int)SHADER::SKY_LUT, m_rootSigObj.Get(),\n        COMPILED_CS[(int)SHADER::SKY_LUT]);\n\n    m_descTable = renderer.GetGpuDescriptorHeap().Allocate((int)DESC_TABLE::COUNT);\n\n    m_localCB.DepthMappingExp = DefaultParamVals::DEPTH_MAP_EXP;\n    m_localCB.VoxelGridNearZ = DefaultParamVals::VOXEL_GRID_NEAR_Z;\n    m_localCB.VoxelGridFarZ = DefaultParamVals::VOXEL_GRID_FAR_Z;\n    m_localCB.NumVoxelsX = DefaultParamVals::NUM_VOXELS_X;\n    m_localCB.NumVoxelsY = DefaultParamVals::NUM_VOXELS_Y;\n\n    CreateSkyviewLUT();\n    App::AddShaderReloadHandler(\"SkyViewLUT\", fastdelegate::MakeDelegate(this, &Sky::ReloadSkyLUTShader));\n\n    SetInscatteringEnablement(doInscattering);\n}\n\nvoid Sky::SetInscatteringEnablement(bool b)\n{\n    if (b == m_doInscattering)\n        return;\n\n    m_doInscattering = b;\n\n    if (b)\n    {\n        Assert(!m_voxelGrid.IsInitialized(), \"This should be NULL\");\n\n        CreateVoxelGrid();\n\n        ParamVariant depthExp;\n        depthExp.InitFloat(\"Renderer\", \"Inscattering\", \"DepthMapExp\", \n            fastdelegate::MakeDelegate(this, &Sky::DepthMapExpCallback),\n            DefaultParamVals::DEPTH_MAP_EXP, 1.0f, 5.0f, 0.2f);\n        App::AddParam(depthExp);\n\n        ParamVariant voxelGridNearZ;\n        voxelGridNearZ.InitFloat(\"Renderer\", \"Inscattering\", \"VoxelGridNearZ\", \n            fastdelegate::MakeDelegate(this, &Sky::VoxelGridNearZCallback),\n            DefaultParamVals::VOXEL_GRID_NEAR_Z, 0.0f, 1.0f, 1e-2f);\n        App::AddParam(voxelGridNearZ);\n\n        ParamVariant voxelGridFarZ;\n        voxelGridFarZ.InitFloat(\"Renderer\", \"Inscattering\", \"VoxelGridFarZ\", \n            fastdelegate::MakeDelegate(this, &Sky::VoxelGridFarZCallback),\n            DefaultParamVals::VOXEL_GRID_FAR_Z, 10.0f, 200.0f, 1.0f);\n        App::AddParam(voxelGridFarZ);\n\n        //App::AddShaderReloadHandler(\"Inscattering\", fastdelegate::MakeDelegate(this, &Sky::ReloadInscatteringShader));\n\n        if (!m_psoLib.GetPSO((int)SHADER::INSCATTERING))\n        {\n            m_psoLib.CompileComputePSO((int)SHADER::INSCATTERING, m_rootSigObj.Get(),\n                COMPILED_CS[(int)SHADER::INSCATTERING]);\n        }\n    }\n    else\n    {\n        m_voxelGrid.Reset();\n\n        App::RemoveParam(\"Renderer\", \"Inscattering\", \"DepthMapExp\");\n        App::RemoveParam(\"Renderer\", \"Inscattering\", \"VoxelGridNearZ\");\n        App::RemoveParam(\"Renderer\", \"Inscattering\", \"VoxelGridFarZ\");\n\n        //App::RemoveShaderReloadHandler(\"Inscattering\");\n    }\n}\n\nvoid Sky::Render(CommandList& cmdList)\n{\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT ||\n        cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE, \"Invalid downcast\");\n    ComputeCmdList& computeCmdList = static_cast<ComputeCmdList&>(cmdList);\n\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n\n    computeCmdList.SetRootSignature(m_rootSig, m_rootSigObj.Get());\n    m_rootSig.SetRootConstants(0, sizeof(m_localCB) / sizeof(DWORD), &m_localCB);\n    m_rootSig.End(computeCmdList);\n\n    //\n    // Sky LUT\n    //\n    {\n        computeCmdList.PIXBeginEvent(\"SkyViewLUT\");\n        const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"SkyViewLUT\");\n\n        const uint32_t dispatchDimX = CeilUnsignedIntDiv(m_localCB.LutWidth, SKY_VIEW_LUT_THREAD_GROUP_SIZE_X);\n        const uint32_t dispatchDimY = CeilUnsignedIntDiv(m_localCB.LutHeight, SKY_VIEW_LUT_THREAD_GROUP_SIZE_Y);\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::SKY_LUT));\n        computeCmdList.Dispatch(dispatchDimX, dispatchDimY, 1);\n\n        gpuTimer.EndQuery(computeCmdList, queryIdx);\n        computeCmdList.PIXEndEvent();\n    }\n\n    //\n    // Inscattering\n    //\n    if(m_doInscattering)\n    {\n        computeCmdList.PIXBeginEvent(\"InscatteringVoxelGrid\");\n        const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"InscatteringVoxelGrid\");\n\n        computeCmdList.SetPipelineState(m_psoLib.GetPSO((int)SHADER::INSCATTERING));\n        computeCmdList.Dispatch(m_localCB.NumVoxelsX, m_localCB.NumVoxelsY, 1);\n\n        gpuTimer.EndQuery(computeCmdList, queryIdx);\n        computeCmdList.PIXEndEvent();\n    }\n}\n\nvoid Sky::CreateSkyviewLUT()\n{\n    auto& renderer = App::GetRenderer();\n    auto* device = renderer.GetDevice();\n\n    m_lut = GpuMemory::GetTexture2D(\"SkyLUT\",\n        m_localCB.LutWidth, m_localCB.LutHeight,\n        ResourceFormats::SKY_VIEW_LUT,\n        D3D12_RESOURCE_STATE_COMMON,\n        TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n    D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc{};\n    uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;\n    uavDesc.Format = ResourceFormats::SKY_VIEW_LUT;\n    uavDesc.Texture2D.MipSlice = 0;\n    uavDesc.Texture2D.PlaneSlice = 0;\n\n    device->CreateUnorderedAccessView(m_lut.Resource(), nullptr, &uavDesc, \n        m_descTable.CPUHandle((int)DESC_TABLE::SKY_LUT_UAV));\n    m_localCB.LutDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE::SKY_LUT_UAV);\n}\n\nvoid Sky::CreateVoxelGrid()\n{\n    auto* device = App::GetRenderer().GetDevice();\n\n    m_voxelGrid = GpuMemory::GetTexture3D(\"InscatteringVoxelGrid\",\n        m_localCB.NumVoxelsX, m_localCB.NumVoxelsY, INSCATTERING_THREAD_GROUP_SIZE_X,\n        ResourceFormats::INSCATTERING_VOXEL_GRID,\n        D3D12_RESOURCE_STATE_COMMON,\n        TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n    D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc{};\n    uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;\n    uavDesc.Format = ResourceFormats::INSCATTERING_VOXEL_GRID;\n    uavDesc.Texture3D.MipSlice = 0;\n    uavDesc.Texture3D.WSize = INSCATTERING_THREAD_GROUP_SIZE_X;\n    uavDesc.Texture3D.FirstWSlice = 0;\n\n    device->CreateUnorderedAccessView(m_voxelGrid.Resource(), nullptr, &uavDesc, \n        m_descTable.CPUHandle((int)DESC_TABLE::VOXEL_GRID_UAV));\n    m_localCB.VoxelGridDescHeapIdx = m_descTable.GPUDescriptorHeapIndex((int)DESC_TABLE::VOXEL_GRID_UAV);    \n}\n\nvoid Sky::DepthMapExpCallback(const ParamVariant& p)\n{\n    m_localCB.DepthMappingExp = p.GetFloat().m_value;\n}\n\nvoid Sky::VoxelGridNearZCallback(const ParamVariant& p)\n{\n    m_localCB.VoxelGridNearZ = p.GetFloat().m_value;\n}\n\nvoid Sky::VoxelGridFarZCallback(const ParamVariant& p)\n{\n    m_localCB.VoxelGridFarZ = p.GetFloat().m_value;\n}\n\nvoid Sky::ReloadInscatteringShader()\n{\n    m_psoLib.Reload((int)SHADER::INSCATTERING, m_rootSigObj.Get(), \"Sky\\\\Inscattering.hlsl\");\n}\n\nvoid Sky::ReloadSkyLUTShader()\n{\n    m_psoLib.Reload((int)SHADER::SKY_LUT, m_rootSigObj.Get(), \"Sky\\\\SkyViewLUT.hlsl\");\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/Sky/Sky.h",
    "content": "#pragma once\n\n#include \"../RenderPass.h\"\n#include <Core/GpuMemory.h>\n#include \"Sky_Common.h\"\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n}\n\nnamespace ZetaRay::Support\n{\n    struct ParamVariant;\n}\n\nnamespace ZetaRay::RenderPass\n{\n    enum class SKY_SHADER\n    {\n        SKY_LUT,\n        INSCATTERING,\n        COUNT\n    };\n\n    struct Sky final : public RenderPassBase<(int)SKY_SHADER::COUNT>\n    {\n        enum class SHADER_OUT_RES\n        {\n            SKY_VIEW_LUT,\n            INSCATTERING,\n            COUNT\n        };\n\n        Sky();\n        ~Sky() = default;\n\n        void Init(int lutWidth, int lutHeight, bool doInscattering);\n        bool IsInscatteringEnabled() { return m_doInscattering; }\n        void SetInscatteringEnablement(bool b);\n        Math::uint3 GetVoxelGridDim() const\n        { \n            return Math::uint3(m_localCB.NumVoxelsX, m_localCB.NumVoxelsY,\n                INSCATTERING_THREAD_GROUP_SIZE_X);\n        }\n        Math::float2 GetVoxelGridDepth() const \n        { \n            return Math::float2(m_localCB.VoxelGridNearZ, m_localCB.VoxelGridFarZ); \n        }\n        float GetVoxelGridMappingExp() const { return m_localCB.DepthMappingExp; }\n        const Core::GpuMemory::Texture& GetOutput(SHADER_OUT_RES i) const\n        {\n            Assert((int)i < (int)SHADER_OUT_RES::COUNT, \"out-of-bound access.\");\n\n            if (i == SHADER_OUT_RES::SKY_VIEW_LUT)\n                return m_lut;\n            else\n                return m_voxelGrid;\n        }\n        void Render(Core::CommandList& cmdList);\n\n    private:\n        static constexpr int NUM_CBV = 1;\n        static constexpr int NUM_SRV = 1;\n        static constexpr int NUM_UAV = 0;\n        static constexpr int NUM_GLOBS = 1;\n        static constexpr int NUM_CONSTS = sizeof(cbSky) / sizeof(DWORD);\n        using SHADER = SKY_SHADER;\n\n        struct ResourceFormats\n        {\n            static constexpr DXGI_FORMAT INSCATTERING_VOXEL_GRID = DXGI_FORMAT_R11G11B10_FLOAT;\n            static constexpr DXGI_FORMAT SKY_VIEW_LUT = DXGI_FORMAT_R11G11B10_FLOAT;\n        };\n\n        struct DefaultParamVals\n        {\n            static constexpr int NUM_VOXELS_X = 192;\n            static constexpr int NUM_VOXELS_Y = int(NUM_VOXELS_X / 1.77f);\n            static constexpr float DEPTH_MAP_EXP = 2.0f;\n            static constexpr float VOXEL_GRID_NEAR_Z = 0.5f;\n            static constexpr float VOXEL_GRID_FAR_Z = 30.0f;\n        };\n\n        enum class DESC_TABLE\n        {\n            SKY_LUT_UAV,\n            VOXEL_GRID_UAV,\n            COUNT\n        };\n\n        inline static constexpr const char* COMPILED_CS[(int)SHADER::COUNT] = {\n            \"SkyViewLUT_cs.cso\", \"Inscattering_cs.cso\" };\n\n        void CreateSkyviewLUT();\n        void CreateVoxelGrid();\n\n        // parameter callbacks\n        void DepthMapExpCallback(const Support::ParamVariant& p);\n        void VoxelGridNearZCallback(const Support::ParamVariant& p);\n        void VoxelGridFarZCallback(const Support::ParamVariant& p);\n\n        // shader reload\n        void ReloadInscatteringShader();\n        void ReloadSkyLUTShader();\n\n        Core::GpuMemory::Texture m_lut;\n        Core::GpuMemory::Texture m_voxelGrid;\n        Core::DescriptorTable m_descTable;\n        cbSky m_localCB;\n        bool m_doInscattering = false;\n    };\n}"
  },
  {
    "path": "Source/ZetaRenderPass/Sky/SkyViewLUT.hlsl",
    "content": "#include \"../Common/StaticTextureSamplers.hlsli\"\n#include \"../Common/FrameConstants.h\"\n#include \"../Common/Volumetric.hlsli\"\n#include \"Sky_Common.h\"\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbSky> g_local : register(b0, space0);\nConstantBuffer<cbFrameConstants> g_frame : register(b1, space0);\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n#define NON_LINEAR_LATITUDE 1\n\n[numthreads(SKY_VIEW_LUT_THREAD_GROUP_SIZE_X, SKY_VIEW_LUT_THREAD_GROUP_SIZE_Y, 1)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID)\n{\n    const uint2 textureDim = uint2(g_local.LutWidth, g_local.LutHeight);\n    if (DTid.x >= g_local.LutWidth || DTid.y >= g_local.LutHeight)\n        return;\n\n    float phi = ((float) DTid.x / (float) g_local.LutWidth);\n    phi *= TWO_PI;\n\n    float v = ((float) DTid.y / (float) g_local.LutHeight);\n\n#if NON_LINEAR_LATITUDE == 1\n    // Since horizon (theta ~ PI / 2) contains higher frequencies, low sampling rates used \n    // for LUT generation (128 for latitude) lead to overblurring. To compensate, apply \n    // a non-linear transformation that maps more texels to be around the horizon. The invsese \n    // mapping has to be applied when this LUT is sampled.\n    // Ref: S. Hillaire, \"A Scalable and Production Ready Sky and Atmosphere Rendering Technique,\" Computer Graphics Forum, 2020.\n    float s = v >= 0.5f ? 1.0f : -1.0f;\n    float a = v - 0.5f;\n    float theta = a * a * TWO_PI * s + PI_OVER_2;\n#else\n    float theta = v * PI;\n#endif\n\n    float3 w = Math::SphericalToCartesian(1, theta, phi);\n    \n    const float3 sigma_s_rayleigh = g_frame.RayleighSigmaSColor * g_frame.RayleighSigmaSScale;\n    const float sigma_t_mie = g_frame.MieSigmaA + g_frame.MieSigmaS;\n    const float3 sigma_t_ozone = g_frame.OzoneSigmaAColor * g_frame.OzoneSigmaAScale;\n\n    // Place the camera slightly above the ground to avoid artifacts\n    float3 rayOrigin = float3(0.0f, g_frame.PlanetRadius + 0.2f, 0.0f);\n\n    // In-scattered lighting\n    float3 Ls = Volume::EstimateLs(g_frame.PlanetRadius, rayOrigin, w, g_frame.SunDir, \n        g_frame.AtmosphereAltitude, g_frame.g, sigma_s_rayleigh, g_frame.MieSigmaS, \n        sigma_t_mie, sigma_t_ozone, 32);\n    Ls *= g_frame.SunIlluminance;\n\n    RWTexture2D<float4> g_out = ResourceDescriptorHeap[g_local.LutDescHeapIdx];\n\n    // R11G11B10 doesn't have a sign bit\n    g_out[DTid.xy].xyz = max(0.0f, Ls);\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/Sky/Sky_Common.h",
    "content": "#ifndef SKY_H\n#define SKY_H\n\n#include \"../../ZetaCore/Core/HLSLCompat.h\"\n\n#define SKY_VIEW_LUT_THREAD_GROUP_SIZE_X 8u\n#define SKY_VIEW_LUT_THREAD_GROUP_SIZE_Y 8u\n\n#define INSCATTERING_THREAD_GROUP_SIZE_X 128u\n#define INSCATTERING_THREAD_GROUP_SIZE_Y 1\n#define INSCATTERING_THREAD_GROUP_SIZE_Z 1\n\nstruct cbSky\n{\n    uint32_t LutWidth;\n    uint32_t LutHeight;\n\n    uint32_t NumVoxelsX;\n    uint32_t NumVoxelsY;\n\n    float DepthMappingExp;\n    float VoxelGridNearZ;\n    float VoxelGridFarZ;\n\n    // \n    // Resources\n    //\n\n    // RWTexture3D<half4>\n    // RWTexture2D<float4>\n    uint32_t LutDescHeapIdx;\n    uint32_t VoxelGridDescHeapIdx;\n};\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderPass/TAA/CMakeLists.txt",
    "content": "set(RP_TAA_DIR ${ZETA_RENDER_PASS_DIR}/TAA)\nset(RP_TAA_SRC\n    \"${RP_TAA_DIR}/TAA.cpp\"\n    \"${RP_TAA_DIR}/TAA.h\"\n    \"${RP_TAA_DIR}/TAA_Common.h\"\n    \"${RP_TAA_DIR}/TAA.hlsl\")\nset(RP_TAA_SRC ${RP_TAA_SRC} PARENT_SCOPE)\n"
  },
  {
    "path": "Source/ZetaRenderPass/TAA/TAA.cpp",
    "content": "#include \"TAA.h\"\n#include <Core/CommandList.h>\n#include <Scene/SceneRenderer.h>\n#include <Support/Param.h>\n#include \"../Assets/Font/IconsFontAwesome6.h\"\n\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Support;\n\n//--------------------------------------------------------------------------------------\n// TAA\n//--------------------------------------------------------------------------------------\n\nTAA::TAA()\n    : RenderPassBase(NUM_CBV, NUM_SRV, NUM_UAV, NUM_GLOBS, NUM_CONSTS)\n{\n    // frame constants\n    m_rootSig.InitAsCBV(0, 0, 0,\n        D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE,\n        GlobalResource::FRAME_CONSTANTS_BUFFER);\n\n    // root constants\n    m_rootSig.InitAsConstants(1, sizeof(cbTAA) / sizeof(DWORD), 1);\n}\n\nTAA::~TAA()\n{\n    Reset();\n}\n\nvoid TAA::Init()\n{\n    constexpr D3D12_ROOT_SIGNATURE_FLAGS flags =\n        D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS |\n        D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;\n\n    auto samplers = App::GetRenderer().GetStaticSamplers();\n    RenderPassBase::InitRenderPass(\"TAA\", flags, samplers);\n\n    m_psoLib.CompileComputePSO(0, m_rootSigObj.Get(), COMPILED_CS[0]);\n\n    m_descTable = App::GetRenderer().GetGpuDescriptorHeap().Allocate((int)DESC_TABLE::COUNT);\n    CreateResources();\n\n    m_localCB.BlendWeight = DefaultParamVals::BlendWeight;\n\n    ParamVariant blendWeight;\n    blendWeight.InitFloat(ICON_FA_FILM \" Renderer\", \"TAA\", \"BlendWeight\", fastdelegate::MakeDelegate(this, &TAA::BlendWeightCallback),\n        DefaultParamVals::BlendWeight, 0.0f, 1.0f, 0.1f);\n    App::AddParam(blendWeight);\n\n    m_isTemporalTexValid = false;\n    //App::AddShaderReloadHandler(\"TAA\", fastdelegate::MakeDelegate(this, &TAA::ReloadShader));\n}\n\nvoid TAA::Reset()\n{\n    if (IsInitialized())\n    {\n        App::RemoveParam(\"Renderer\", \"TAA\", \"BlendWeight\");\n        // App::RemoveShaderReloadHandler(\"TAA\");\n\n        m_antiAliased[0].Reset();\n        m_antiAliased[1].Reset();\n        m_descTable.Reset();\n\n        RenderPassBase::Reset(true);\n    }\n}\n\nvoid TAA::OnWindowResized()\n{\n    CreateResources();\n    m_isTemporalTexValid = false;\n}\n\nvoid TAA::Render(CommandList& cmdList)\n{\n    Assert(cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT ||\n        cmdList.GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE, \"Invalid downcast\");\n    ComputeCmdList& computeCmdList = static_cast<ComputeCmdList&>(cmdList);\n\n    auto& renderer = App::GetRenderer();\n    auto& gpuTimer = renderer.GetGpuTimer();\n    const int outIdx = renderer.GlobalIdxForDoubleBufferedResources();\n    const uint32_t w = renderer.GetRenderWidth();\n    const uint32_t h = renderer.GetRenderWidth();\n\n    Assert(m_inputDesc[(int)SHADER_IN_DESC::SIGNAL] > 0, \"Input SRV hasn't been set.\");\n    m_localCB.InputDescHeapIdx = m_inputDesc[(int)SHADER_IN_DESC::SIGNAL];\n    m_localCB.PrevOutputDescHeapIdx = m_descTable.GPUDescriptorHeapIndex() + (outIdx == 0 ? \n        (int)DESC_TABLE::TEX_A_SRV : (int)DESC_TABLE::TEX_B_SRV);\n    m_localCB.CurrOutputDescHeapIdx = m_descTable.GPUDescriptorHeapIndex() + (outIdx == 0 ? \n        (int)DESC_TABLE::TEX_B_UAV : (int)DESC_TABLE::TEX_A_UAV);\n    m_localCB.TemporalIsValid = m_isTemporalTexValid;\n\n    computeCmdList.PIXBeginEvent(\"TAA\");\n    const uint32_t queryIdx = gpuTimer.BeginQuery(computeCmdList, \"TAA\");\n\n    computeCmdList.SetRootSignature(m_rootSig, m_rootSigObj.Get());\n\n    m_rootSig.SetRootConstants(0, sizeof(cbTAA) / sizeof(DWORD), &m_localCB);\n    m_rootSig.End(computeCmdList);\n\n    computeCmdList.SetPipelineState(m_psoLib.GetPSO(0));\n    computeCmdList.Dispatch(CeilUnsignedIntDiv(w, TAA_THREAD_GROUP_SIZE_X), \n        CeilUnsignedIntDiv(h, TAA_THREAD_GROUP_SIZE_Y), 1);\n\n    computeCmdList.PIXEndEvent();\n    gpuTimer.EndQuery(computeCmdList, queryIdx);\n\n    m_isTemporalTexValid = true;\n}\n\nvoid TAA::CreateResources()\n{\n    auto& renderer = App::GetRenderer();\n\n    m_antiAliased[0] = GpuMemory::GetTexture2D(\"TAA_A\",\n        renderer.GetRenderWidth(), renderer.GetRenderHeight(),\n        DXGI_FORMAT_R16G16B16A16_FLOAT,\n        D3D12_RESOURCE_STATE_COMMON,\n        TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n    m_antiAliased[1] = GpuMemory::GetTexture2D(\"TAA_B\",\n        renderer.GetRenderWidth(), renderer.GetRenderHeight(),\n        DXGI_FORMAT_R16G16B16A16_FLOAT,\n        D3D12_RESOURCE_STATE_COMMON,\n        TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS);\n\n    // SRVs\n    Direct3DUtil::CreateTexture2DSRV(m_antiAliased[0], m_descTable.CPUHandle((int)DESC_TABLE::TEX_A_SRV));\n    Direct3DUtil::CreateTexture2DSRV(m_antiAliased[1], m_descTable.CPUHandle((int)DESC_TABLE::TEX_B_SRV));\n\n    // UAVs\n    Direct3DUtil::CreateTexture2DUAV(m_antiAliased[0], m_descTable.CPUHandle((int)DESC_TABLE::TEX_A_UAV));\n    Direct3DUtil::CreateTexture2DUAV(m_antiAliased[1], m_descTable.CPUHandle((int)DESC_TABLE::TEX_B_UAV));\n}\n\nvoid TAA::BlendWeightCallback(const ParamVariant& p)\n{\n    m_localCB.BlendWeight = p.GetFloat().m_value;\n}\n\nvoid TAA::ReloadShader()\n{\n    m_psoLib.Reload(0, m_rootSigObj.Get(), \"TAA\\\\TAA.hlsl\");\n}\n"
  },
  {
    "path": "Source/ZetaRenderPass/TAA/TAA.h",
    "content": "#pragma once\n\n#include \"../RenderPass.h\"\n#include <Core/GpuMemory.h>\n#include \"TAA_Common.h\"\n\nnamespace ZetaRay::Core\n{\n    class CommandList;\n}\n\nnamespace ZetaRay::Support\n{\n    struct ParamVariant;\n}\n\nnamespace ZetaRay::RenderPass\n{\n    struct TAA final : public RenderPassBase<1>\n    {\n        enum class SHADER_IN_DESC\n        {\n            SIGNAL,\n            COUNT\n        };\n\n        enum class SHADER_OUT_RES\n        {\n            OUTPUT_A,\n            OUTPUT_B,\n            COUNT\n        };\n\n        TAA();\n        ~TAA();\n\n        void Init();\n        void Reset();\n        void OnWindowResized();\n        void SetDescriptor(SHADER_IN_DESC i, uint32_t heapIdx)\n        {\n            Assert((int)i < (int)SHADER_IN_DESC::COUNT, \"out-of-bound access.\");\n            m_inputDesc[(int)i] = heapIdx;\n        }\n        Core::GpuMemory::Texture& GetOutput(SHADER_OUT_RES i)\n        {\n            Assert((int)i < (int)SHADER_OUT_RES::COUNT, \"out-of-bound access.\");\n            return m_antiAliased[(int)i];\n        }\n        void Render(Core::CommandList& cmdList);\n\n    private:\n        static constexpr int NUM_CBV = 1;\n        static constexpr int NUM_SRV = 0;\n        static constexpr int NUM_UAV = 0;\n        static constexpr int NUM_GLOBS = 1;\n        static constexpr int NUM_CONSTS = sizeof(cbTAA) / sizeof(DWORD);\n\n        enum class DESC_TABLE\n        {\n            TEX_A_SRV,\n            TEX_A_UAV,\n            TEX_B_SRV,\n            TEX_B_UAV,\n            COUNT\n        };\n\n        inline static constexpr const char* COMPILED_CS[] = { \"TAA_cs.cso\" };\n\n        struct DefaultParamVals\n        {\n            static constexpr float BlendWeight = 0.1f;\n        };\n\n        void CreateResources();\n        void BlendWeightCallback(const Support::ParamVariant& p);\n        void ReloadShader();\n\n        // ping-pong between input & output\n        Core::GpuMemory::Texture m_antiAliased[2];\n        uint32_t m_inputDesc[(int)SHADER_IN_DESC::COUNT];\n        cbTAA m_localCB;\n        Core::DescriptorTable m_descTable;\n        bool m_isTemporalTexValid;\n    };\n}"
  },
  {
    "path": "Source/ZetaRenderPass/TAA/TAA.hlsl",
    "content": "// Refs:\n// 1. L. Yang, S. Liu, and M. Salvi, \"A Survey of Temporal Antialiasing Techniques,\" Computer Graphics Forum, 2020.\n// 2. https://github.com/TheRealMJP/MSAAFilter\n// 3. https://alextardif.com/TAA.html\n// 4. https://www.elopezr.com/temporal-aa-and-the-quest-for-the-holy-trail/\n\n#include \"TAA_Common.h\"\n#include \"../Common/Math.hlsli\"\n#include \"../Common/Common.hlsli\"\n#include \"../Common/GBuffers.hlsli\"\n#include \"../Common/StaticTextureSamplers.hlsli\"\n#include \"../Common/FrameConstants.h\"\n\n#define DEPTH_DILATION 1\n#define CATMULL_ROM_FILTERING 1\n\n//--------------------------------------------------------------------------------------\n// Root Signature\n//--------------------------------------------------------------------------------------\n\nConstantBuffer<cbFrameConstants> g_frame : register(b0);\nConstantBuffer<cbTAA> g_local : register(b1);\n\n//--------------------------------------------------------------------------------------\n// Helper functions\n//--------------------------------------------------------------------------------------\n\n// Ref: M. Pharr, W. Jakob, and G. Humphreys, Physically Based Rendering, Morgan Kaufmann, 2016.\nfloat Mitchell1D(in float x, in float B, in float C)\n{\n    x = abs(2.0f * x);\n    const float oneDivSix = 1.0f / 6.0f;\n\n    if (x > 1)\n    {\n        return ((-B - 6.0f * C) * x * x * x + (6.0f * B + 30.0f * C) * x * x +\n                (-12.0f * B - 48.0f * C) * x + (8.0f * B + 24.0f * C)) * oneDivSix;\n    }\n    else\n    {\n        return ((12.0f - 9.0f * B - 6.0f * C) * x * x * x +\n                (-18.0f + 12.0f * B + 6.0f * C) * x * x +\n                (6.0f - 2.0f * B)) * oneDivSix;\n    }\n}\n\n// Ref: https://github.com/playdeadgames/temporal\nfloat3 ClipAABB(float3 aabbMin, float3 aabbMax, float3 histSample)\n{\n    float3 center = 0.5f * (aabbMax + aabbMin);\n    float3 extents = 0.5f * (aabbMax - aabbMin);\n\n    float3 rayToCenter = histSample - center;\n    float3 rayToCenterUnit = rayToCenter.xyz / extents;\n    rayToCenterUnit = abs(rayToCenterUnit);\n    float rayToCenterUnitMax = max(rayToCenterUnit.x, max(rayToCenterUnit.y, rayToCenterUnit.z));\n\n    if (rayToCenterUnitMax > 1.0)\n        return center + rayToCenter / rayToCenterUnitMax;\n    else\n        return histSample; // point inside aabb\n}\n\n//--------------------------------------------------------------------------------------\n// Main\n//--------------------------------------------------------------------------------------\n\n[numthreads(TAA_THREAD_GROUP_SIZE_X, TAA_THREAD_GROUP_SIZE_Y, TAA_THREAD_GROUP_SIZE_Z)]\nvoid main(uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID)\n{\n    if(DTid.x >= g_frame.RenderWidth || DTid.y >= g_frame.RenderHeight)\n        return;\n\n    GBUFFER_DEPTH g_depth = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + GBUFFER_OFFSET::DEPTH];\n    const float depth = g_depth[DTid.xy];\n\n    RWTexture2D<float4> g_antiAliased = ResourceDescriptorHeap[g_local.CurrOutputDescHeapIdx];\n    Texture2D<float4> g_currSignal = ResourceDescriptorHeap[g_local.InputDescHeapIdx];\n    const float3 currColor = g_currSignal[DTid.xy].rgb;\n\n    if (!g_local.TemporalIsValid || depth == FLT_MAX)\n    {\n        g_antiAliased[DTid.xy].rgb = currColor;\n        return;\n    }\n\n    float weightSum = Mitchell1D(0, 0.33f, 0.33f) * Mitchell1D(0, 0.33f, 0.33f);\n    float3 reconstructed = currColor * weightSum;\n    float3 firstMoment = currColor;\n    float3 secondMoment = currColor * currColor;\n\n#if DEPTH_DILATION    \n    float closestDepth = depth;\n    int2 closestDepthAddress = 0.0.xx;\n#endif\n\n    // compute neighborhood's AABB\n    int numNeighbors = 1;\n\n    [unroll]\n    for (int i = -1; i < 2; i++)\n    {\n        for (int j = -1; j < 2; j++)\n        {\n            if(i == 0 && j == 0)\n                continue;\n\n            int2 neighborAddrr = DTid.xy + int2(i, j);\n            if (any(neighborAddrr < 0) || any(neighborAddrr >= int2(g_frame.RenderWidth, g_frame.RenderHeight)))\n                continue;\n\n            float3 neighborColor = max(g_currSignal[neighborAddrr].rgb, 0.0.xxx);\n            \n            float weight = Mitchell1D(i, 0.33f, 0.33f) * Mitchell1D(j, 0.33f, 0.33f);\n            weight *= 1.0 / (1.0 + Math::Luminance(neighborColor));\n\n            reconstructed += neighborColor * weight;\n            weightSum += weight;\n\n            firstMoment += neighborColor;\n            secondMoment += neighborColor * neighborColor;\n            \n            // motion vector signal might be aliased -- prefilter it by selecting the motion vector\n            // of the neighborhood pixel that is closest to the camera.\n#if DEPTH_DILATION\n            float neighborDepth = g_depth[neighborAddrr];\n            if (neighborDepth < closestDepth)\n            {\n                closestDepth = neighborDepth;\n                closestDepthAddress = int2(i, j);\n            }\n#endif\n            \n            numNeighbors += 1;\n        }\n    }\n\n    reconstructed /= max(weightSum, 1e-5);\n    \n    // sample history using motion vector\n    GBUFFER_MOTION_VECTOR g_motionVector = ResourceDescriptorHeap[g_frame.CurrGBufferDescHeapOffset + GBUFFER_OFFSET::MOTION_VECTOR];\n\n#if DEPTH_DILATION\n    const float2 motionVec = g_motionVector[DTid.xy + closestDepthAddress];\n#else\n    const float2 motionVec = g_motionVector[DTid.xy];\n#endif\n\n    // motion vector is relative to texture space\n    const float2 renderDim = float2(g_frame.RenderWidth, g_frame.RenderHeight);\n    const float2 currUV = (DTid.xy + 0.5f) / renderDim;\n    const float2 prevUV = currUV - motionVec;\n    \n    // no history sample was available\n    if (any(prevUV < 0.0f.xx) || any(prevUV > 1.0f.xx))\n    {\n        g_antiAliased[DTid.xy].rgb = reconstructed;\n        return;\n    }\n\n    Texture2D<float4> g_prevColor = ResourceDescriptorHeap[g_local.PrevOutputDescHeapIdx];\n    \n#if CATMULL_ROM_FILTERING\n    float3 history = Common::SampleTextureCatmullRom(g_prevColor, g_samLinearClamp, prevUV, renderDim);\n#else\n    float3 history = g_prevColor.SampleLevel(g_samLinearClamp, prevUV, 0).xyz;\n#endif\n\n    // clip history sample towards neighborhood AABB's center\n    const float3 mean = firstMoment / numNeighbors;\n    float3 std = abs(secondMoment - (firstMoment * firstMoment) / numNeighbors);\n    // apply Bessel's correction to get an unbiased sample variance\n    std /= (numNeighbors - 1.0f);\n    std = sqrt(std);\n\n    // form a confidene interval for the distribution of color around the current pixel\n    const float3 clippedHistory = ClipAABB(mean - std, mean + std, history);\n\n    // inverse-luminance filtering\n    const float currWeight = saturate(g_local.BlendWeight * rcp(1.0f + Math::Luminance(reconstructed)));\n    const float histWeight = saturate((1.0f - g_local.BlendWeight) * rcp(1.0f + Math::Luminance(clippedHistory)));\n    float3 result = (currWeight * reconstructed + histWeight * clippedHistory) / (currWeight + histWeight);\n\n    // TODO on rare occasions, result can be NaN. figure out what's causing it\n    // temporary solution in the meantime -- NaN propagation is avoided at least\n    result = any(isnan(result)) ? reconstructed : result;\n\n    g_antiAliased[DTid.xy].rgb = result;\n}"
  },
  {
    "path": "Source/ZetaRenderPass/TAA/TAA_Common.h",
    "content": "#ifndef TAA_H\n#define TAA_H\n\n#define TAA_THREAD_GROUP_SIZE_X 8u\n#define TAA_THREAD_GROUP_SIZE_Y 8u\n#define TAA_THREAD_GROUP_SIZE_Z 1\n\nstruct cbTAA\n{\n    float BlendWeight;\n    uint32_t InputDescHeapIdx;\n    uint32_t PrevOutputDescHeapIdx;\n    uint32_t CurrOutputDescHeapIdx;\n    uint32_t TemporalIsValid;\n};\n\n#endif"
  },
  {
    "path": "Source/ZetaRenderer/CMakeLists.txt",
    "content": "add_subdirectory(Default)\n\n# build ZetaRenderer as a static library\nadd_library(ZetaRenderer STATIC ${DEFAULT_RENDERER_SRC})\ntarget_link_libraries(ZetaRenderer PUBLIC ZetaCore PRIVATE ZetaRenderPass)\ntarget_include_directories(ZetaRenderer AFTER PUBLIC \"${ZETA_CORE_DIR}\" \n    PRIVATE \"${EXTERNAL_DIR}\" \"${ZETA_RENDER_PASS_DIR}\")\nset_target_properties(ZetaRenderer PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\n\nsource_group(TREE \"${ZETA_RENDERER_DIR}\" FILES ${DEFAULT_RENDERER_SRC})"
  },
  {
    "path": "Source/ZetaRenderer/Default/CMakeLists.txt",
    "content": "set(DEFAULT_RENDERER_DIR \"${ZETA_RENDERER_DIR}/Default\")\nset(DEFAULT_RENDERER_SRC\n    \"${DEFAULT_RENDERER_DIR}/GBuffer.cpp\"\n    \"${DEFAULT_RENDERER_DIR}/PostProcessor.cpp\"\n    \"${DEFAULT_RENDERER_DIR}/PathTracer.cpp\"\n    \"${DEFAULT_RENDERER_DIR}/DefaultRenderer.cpp\"\n    \"${DEFAULT_RENDERER_DIR}/DefaultRenderer.h\"\n    \"${DEFAULT_RENDERER_DIR}/DefaultRendererImpl.h\")\n\nset(DEFAULT_RENDERER_SRC ${DEFAULT_RENDERER_SRC} PARENT_SCOPE)"
  },
  {
    "path": "Source/ZetaRenderer/Default/DefaultRenderer.cpp",
    "content": "#include \"DefaultRenderer.h\"\n#include \"DefaultRendererImpl.h\"\n#include <App/Timer.h>\n#include <Core/SharedShaderResources.h>\n#include <Support/Task.h>\n#include <Support/Param.h>\n#include <Math/MatrixFuncs.h>\n#include <Scene/Camera.h>\n#include \"../Assets/Font/IconsFontAwesome6.h\"\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::DefaultRenderer;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::App;\nusing namespace ZetaRay::RenderPass;\n\nnamespace\n{\n    Data* g_data = nullptr;\n}\n\n//--------------------------------------------------------------------------------------\n// DefaultRenderer::Common\n//--------------------------------------------------------------------------------------\n\nvoid Common::UpdateFrameConstants(cbFrameConstants& frameConsts, Buffer& frameConstsBuff,\n    const GBufferData& gbuffData, const PathTracerData& rtData)\n{\n    auto& renderer = App::GetRenderer();\n    const int currIdx = renderer.GlobalIdxForDoubleBufferedResources();\n\n    frameConsts.FrameNum = (uint32_t)App::GetTimer().GetTotalFrameCount();\n    frameConsts.dt = (float)App::GetTimer().GetElapsedTime();\n    frameConsts.RenderWidth = renderer.GetRenderWidth();\n    frameConsts.RenderHeight = renderer.GetRenderHeight();\n    frameConsts.DisplayWidth = renderer.GetDisplayWidth();\n    frameConsts.DisplayHeight = renderer.GetDisplayHeight();\n    frameConsts.CameraRayUVGradsScale = App::GetUpscalingFactor() != 1.0f ?\n        powf(2.0f, -(float)frameConsts.RenderWidth / frameConsts.DisplayWidth) :\n        1.0f;\n    frameConsts.MipBias = App::GetUpscalingFactor() != 1.0f ?\n        log2f((float)frameConsts.RenderWidth / frameConsts.DisplayWidth) - 1.0f :\n        0.0f;\n\n    frameConsts.BaseColorMapsDescHeapOffset = App::GetScene().GetBaseColMapsDescHeapOffset();\n    frameConsts.NormalMapsDescHeapOffset = App::GetScene().GetNormalMapsDescHeapOffset();\n    frameConsts.MetallicRoughnessMapsDescHeapOffset = App::GetScene().GetMetallicRougnessMapsDescHeapOffset();\n    frameConsts.EmissiveMapsDescHeapOffset = App::GetScene().GetEmissiveMapsDescHeapOffset();\n\n    // Note: assumes BVH has been built\n    //frameConsts.WorldRadius = App::GetScene().GetWorldAABB().Extents.length();\n\n    // camera\n    const Camera& cam = App::GetCamera();\n    v_float4x4 vCurrV = load4x4(const_cast<float4x4a&>(cam.GetCurrView()));\n    v_float4x4 vP = load4x4(const_cast<float4x4a&>(cam.GetProj()));\n    v_float4x4 vVP = mul(vCurrV, vP);\n    float3 prevCameraPos = frameConsts.CameraPos;\n\n    frameConsts.CameraPos = cam.GetPos();\n    frameConsts.CameraNear = cam.GetNearZ();\n    frameConsts.AspectRatio = cam.GetAspectRatio();\n    frameConsts.PixelSpreadAngle = cam.GetPixelSpreadAngle();\n    frameConsts.TanHalfFOV = cam.GetTanHalfFOV();\n    frameConsts.FocusDepth = cam.GetFocusDepth();\n    frameConsts.LensRadius = cam.GetLensRadius();;\n    frameConsts.PrevView = frameConsts.CurrView;\n    frameConsts.CurrView = float3x4(cam.GetCurrView());\n    frameConsts.PrevViewInv = frameConsts.CurrViewInv;\n    frameConsts.CurrViewInv = float3x4(cam.GetViewInv());\n    frameConsts.PrevCameraJitter = frameConsts.CurrCameraJitter;\n    frameConsts.CurrCameraJitter = cam.GetCurrJitter();\n    frameConsts.PrevViewProj = frameConsts.CurrViewProj;\n    frameConsts.CurrViewProj = store(vVP);\n\n    // Frame g-buffer SRV descriptor table\n    frameConsts.CurrGBufferDescHeapOffset = gbuffData.SrvDescTable[currIdx].GPUDescriptorHeapIndex();\n    frameConsts.PrevGBufferDescHeapOffset = gbuffData.SrvDescTable[1 - currIdx].GPUDescriptorHeapIndex();\n\n    // Sky-view LUT SRV\n    frameConsts.EnvMapDescHeapOffset = rtData.ConstDescTable.GPUDescriptorHeapIndex(\n        (int)PathTracerData::DESC_TABLE_CONST::ENV_MAP_SRV);\n\n    float3 prevViewDir = float3(frameConsts.PrevViewInv.m[0].z, frameConsts.PrevViewInv.m[1].z, \n        frameConsts.PrevViewInv.m[2].z);\n    float3 currViewDir = float3(frameConsts.CurrViewInv.m[0].z, frameConsts.CurrViewInv.m[1].z, \n        frameConsts.CurrViewInv.m[2].z);\n    float3 delta_pos = prevCameraPos - frameConsts.CameraPos;\n    bool cameraStatic = (delta_pos.dot(delta_pos) < 3e-6f) &&\n        (prevViewDir.dot(currViewDir) >= 0.9999995);\n    cameraStatic = cameraStatic && !g_data->m_sunMoved && !g_data->m_sceneChanged;\n    frameConsts.NumFramesCameraStatic = cameraStatic && frameConsts.Accumulate ? \n        frameConsts.NumFramesCameraStatic + 1 : 0;\n    frameConsts.CameraStatic = cameraStatic;\n    frameConsts.SunMoved = g_data->m_sunMoved;\n    g_data->m_sunMoved = false;\n    g_data->m_sceneChanged = false;\n\n    frameConsts.NumEmissiveTriangles = (uint32_t)App::GetScene().NumEmissiveTriangles();\n    frameConsts.OneDivNumEmissiveTriangles = 1.0f / frameConsts.NumEmissiveTriangles;\n\n    if (!frameConstsBuff.IsInitialized())\n    {\n        constexpr size_t sizeInBytes = AlignUp(sizeof(cbFrameConstants), \n            (size_t)D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);\n\n        frameConstsBuff = GpuMemory::GetDefaultHeapBufferAndInit(GlobalResource::FRAME_CONSTANTS_BUFFER,\n            (uint32_t)sizeInBytes,\n            false,\n            MemoryRegion{.Data = &frameConsts, .SizeInBytes = sizeof(cbFrameConstants) });\n\n        renderer.GetSharedShaderResources().InsertOrAssignDefaultHeapBuffer(GlobalResource::FRAME_CONSTANTS_BUFFER,\n            frameConstsBuff);\n    }\n    else\n    {\n        GpuMemory::UploadToDefaultHeapBuffer(frameConstsBuff, (uint32_t)sizeof(cbFrameConstants), \n            MemoryRegion{ .Data = &frameConsts, .SizeInBytes = sizeof(cbFrameConstants) });\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// DefaultRenderer\n//--------------------------------------------------------------------------------------\n\nnamespace ZetaRay::DefaultRenderer\n{\n    void SetInscatteringEnablement(const ParamVariant& p)\n    {\n        g_data->m_settings.Inscattering = p.GetBool();\n    }\n\n    void SetAA(const ParamVariant& p)\n    {\n        const int e = p.GetEnum().m_curr;\n        Assert(e < (int)AA::COUNT, \"Invalid enum value.\");\n        const AA u = (AA)e;\n\n        if (u == g_data->m_settings.AntiAliasing)\n            return;\n\n        float newUpscaleFactor;\n        g_data->PendingAA = u;\n\n        switch (u)\n        {\n        case AA::FSR2:\n            if (!g_data->m_postProcessorData.Fsr2Pass.IsInitialized())\n                g_data->m_postProcessorData.Fsr2Pass.Init();\n\n            newUpscaleFactor = 1.5f;\n            break;\n        case AA::NONE:\n        case AA::TAA:\n        default:\n            newUpscaleFactor = 1.0f;\n            break;\n        }\n\n        App::SetUpscaleFactor(newUpscaleFactor);\n\n        g_data->m_sceneChanged = true;\n    }\n\n    void SetSunDir(const ParamVariant& p)\n    {\n        float pitch = p.GetUnitDir().m_pitch;\n        float yaw = p.GetUnitDir().m_yaw;\n        g_data->m_frameConstants.SunDir = -Math::SphericalToCartesian(pitch, yaw);\n        g_data->m_sunMoved = true;\n    }\n\n    void SetSunLux(const ParamVariant& p)\n    {\n        g_data->m_frameConstants.SunIlluminance = p.GetFloat().m_value;\n        g_data->m_sunMoved = true;\n    }\n\n    void SetSunAngularDiameter(const ParamVariant& p)\n    {\n        auto r = DegreesToRadians(0.5f * p.GetFloat().m_value);\n        g_data->m_frameConstants.SunCosAngularRadius = cosf(r);\n        g_data->m_sunMoved = true;\n    }\n\n    void SetRayleighSigmaSColor(const ParamVariant& p)\n    {\n        g_data->m_frameConstants.RayleighSigmaSColor = p.GetFloat3().m_value;\n        g_data->m_sceneChanged = true;\n    }\n\n    void SetRayleighSigmaSScale(const ParamVariant& p)\n    {\n        g_data->m_frameConstants.RayleighSigmaSScale = p.GetFloat().m_value;\n        g_data->m_sceneChanged = true;\n    }\n\n    void SetMieSigmaS(const ParamVariant& p)\n    {\n        g_data->m_frameConstants.MieSigmaS = p.GetFloat().m_value;\n        g_data->m_sceneChanged = true;\n    }\n\n    void SetMieSigmaA(const ParamVariant& p)\n    {\n        g_data->m_frameConstants.MieSigmaA = p.GetFloat().m_value;\n        g_data->m_sceneChanged = true;\n    }\n\n    void SetOzoneSigmaAColor(const ParamVariant& p)\n    {\n        g_data->m_frameConstants.OzoneSigmaAColor = p.GetColor().m_value;\n        g_data->m_sceneChanged = true;\n    }\n\n    void SetOzoneSigmaAScale(const ParamVariant& p)\n    {\n        g_data->m_frameConstants.OzoneSigmaAScale = p.GetFloat().m_value;\n        g_data->m_sceneChanged = true;\n    }\n\n    void SetgForPhaseHG(const ParamVariant& p)\n    {\n        g_data->m_frameConstants.g = p.GetFloat().m_value;\n        g_data->m_sceneChanged = true;\n    }\n\n    void SetAccumulation(const ParamVariant& p)\n    {\n        g_data->m_frameConstants.Accumulate = p.GetBool();\n    }\n\n    void SetIndirect(const ParamVariant& p)\n    {\n        const int e = p.GetEnum().m_curr;\n        Assert(e < (int)IndirectLighting::INTEGRATOR::COUNT, \"Invalid enum value.\");\n        g_data->m_settings.Indirect = (IndirectLighting::INTEGRATOR)e;\n        g_data->m_pathTracerData.IndirecLightingPass.SetMethod(g_data->m_settings.Indirect);\n\n        g_data->m_sceneChanged = true;\n    }\n\n    void SetLensType(const Support::ParamVariant& p)\n    {\n        g_data->m_frameConstants.DoF = p.GetEnum().m_curr;\n        g_data->m_sceneChanged = true;\n    }\n}\n\nnamespace ZetaRay::DefaultRenderer\n{\n    void Init()\n    {\n        Assert(g_data->PendingAA == g_data->m_settings.AntiAliasing, \"These must match.\");\n        memset(&g_data->m_frameConstants, 0, sizeof(cbFrameConstants));\n\n        g_data->m_renderGraph.Reset();\n\n        const Camera& cam = App::GetCamera();\n        v_float4x4 vCurrV = load4x4(const_cast<float4x4a&>(cam.GetCurrView()));\n\n        // For 1st frame\n        v_float4x4 vP = load4x4(const_cast<float4x4a&>(cam.GetProj()));\n        v_float4x4 vVP = mul(vCurrV, vP);\n        g_data->m_frameConstants.PrevViewInv = float3x4(cam.GetViewInv());\n        g_data->m_frameConstants.PrevView = float3x4(cam.GetCurrView());\n        g_data->m_frameConstants.CurrViewProj = store(vVP);\n\n        //g_data->m_frameConstants.SunDir = float3(0.223f, -0.96f, -0.167f);\n        g_data->m_frameConstants.SunDir = float3(0.6565358f, -0.0560669f, 0.752208233f);\n        //g_data->m_frameConstants.SunDir = float3(0.0f, 1.0f, 0.0f);\n        g_data->m_frameConstants.SunDir.normalize();\n        g_data->m_frameConstants.SunIlluminance = 20.0f;\n        constexpr float angularRadius = DegreesToRadians(0.5f * Defaults::SUN_ANGULAR_DIAMETER);\n        g_data->m_frameConstants.SunCosAngularRadius = cosf(angularRadius);\n        g_data->m_frameConstants.SunSinAngularRadius = sqrtf(1.0f - g_data->m_frameConstants.SunCosAngularRadius * \n            g_data->m_frameConstants.SunCosAngularRadius);\n        g_data->m_frameConstants.AtmosphereAltitude = Defaults::ATMOSPHERE_ALTITUDE;\n        g_data->m_frameConstants.PlanetRadius = Defaults::PLANET_RADIUS;\n        g_data->m_frameConstants.g = Defaults::g;\n        g_data->m_frameConstants.NumFramesCameraStatic = 0;\n        g_data->m_frameConstants.Accumulate = true;\n        g_data->m_frameConstants.DoF = 0;\n\n        auto normalizeAndStore = [](float3 v, float3& cbVal, float& cbScale)\n        {\n            float scale = v.length();\n            cbScale = scale;\n\n            if (scale >= FLT_EPSILON)\n            {\n                float scaleRcp = 1.0f / scale;\n                cbVal = v * scaleRcp;\n            }\n        };\n\n        normalizeAndStore(Defaults::SIGMA_S_RAYLEIGH, g_data->m_frameConstants.RayleighSigmaSColor, \n            g_data->m_frameConstants.RayleighSigmaSScale);\n        normalizeAndStore(float3(Defaults::SIGMA_A_OZONE), g_data->m_frameConstants.OzoneSigmaAColor, \n            g_data->m_frameConstants.OzoneSigmaAScale);\n\n        g_data->m_frameConstants.MieSigmaA = Defaults::SIGMA_A_MIE;\n        g_data->m_frameConstants.MieSigmaS = Defaults::SIGMA_S_MIE;\n\n        TaskSet ts;\n        ts.EmplaceTask(\"GBuffer_Init\", []()\n            {\n                GBuffer::Init(g_data->m_settings, g_data->m_gbuffData);\n            });\n        ts.EmplaceTask(\"PathTracer_Init\", []()\n            {\n                PathTracer::Init(g_data->m_settings, g_data->m_pathTracerData);\n            });\n        ts.EmplaceTask(\"PostProcessor_Init\", []()\n            {\n                PostProcessor::Init(g_data->m_settings, g_data->m_postProcessorData);\n            });\n\n        ts.Sort();\n        ts.Finalize();\n        App::Submit(ZetaMove(ts));\n\n        // Render settings\n        {\n            //ParamVariant enableInscattering;\n            //enableInscattering.InitBool(ICON_FA_FILM \" Renderer\", \"Compositing\", \"Inscattering\",\n            //    fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetInscatteringEnablement),\n            //    g_data->m_settings.Inscattering);\n            //App::AddParam(enableInscattering);\n\n            ParamVariant p;\n            p.InitEnum(ICON_FA_FILM \" Renderer\", \"Anti-Aliasing\", \"Method\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetAA),\n                AAOptions, ZetaArrayLen(AAOptions), (int)g_data->m_settings.AntiAliasing);\n            App::AddParam(p);\n\n            ParamVariant p1;\n            p1.InitBool(ICON_FA_FILM \" Renderer\", \"Compositing\", \"Accumulate\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetAccumulation),\n                g_data->m_frameConstants.Accumulate);\n            App::AddParam(p1);\n\n            ParamVariant p2;\n            p2.InitEnum(ICON_FA_FILM \" Renderer\", \"Indirect Lighting\", \"Integrator\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetIndirect),\n                IndirectOptions, ZetaArrayLen(IndirectOptions), (int)g_data->m_settings.Indirect);\n            App::AddParam(p2);\n\n            ParamVariant p3;\n            p3.InitEnum(ICON_FA_LANDMARK \" Scene\", \"Camera\", \"Type\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetLensType),\n                LensTypes, ZetaArrayLen(LensTypes), 0, \"Lens\");\n            App::AddParam(p3);\n\n            const auto& scene = App::GetScene();\n            g_data->m_settings.LightPresampling = scene.EmissiveLighting() && \n                (scene.NumEmissiveTriangles() >= Defaults::MIN_NUM_LIGHTS_PRESAMPLING);\n            g_data->m_settings.UseLVG = g_data->m_settings.UseLVG && g_data->m_settings.LightPresampling;\n        }\n\n        // Sun\n        {\n            ParamVariant p0;\n            p0.InitUnitDir(ICON_FA_LANDMARK \" Scene\", \"Sun\", \"(-)Dir\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetSunDir),\n                -g_data->m_frameConstants.SunDir);\n            App::AddParam(p0);\n\n            ParamVariant p1;\n            p1.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Sun\", \"Illuminance\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetSunLux),\n                g_data->m_frameConstants.SunIlluminance, 1.0f, 100.0f, 1.0f);\n            App::AddParam(p1);\n\n            ParamVariant p2;\n            p2.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Sun\", \"Angular Diameter (degrees)\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetSunAngularDiameter),\n                Defaults::SUN_ANGULAR_DIAMETER, 0.1f, 10.0f, 1e-2f);\n            App::AddParam(p2);\n        }\n\n        // Atmosphere\n        {\n            ParamVariant p0;\n            p0.InitColor(ICON_FA_LANDMARK \" Scene\", \"Atmosphere\", \"Rayleigh scattering color\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetRayleighSigmaSColor),\n                g_data->m_frameConstants.RayleighSigmaSColor);\n            App::AddParam(p0);\n\n            ParamVariant p1;\n            p1.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Atmosphere\", \"Rayleigh scattering scale\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetRayleighSigmaSScale),\n                g_data->m_frameConstants.RayleighSigmaSScale, 0.0f, 10.0f, 1e-3f);\n            App::AddParam(p1);\n\n            ParamVariant p2;\n            p2.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Atmosphere\", \"Mie scattering coeff.\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetMieSigmaS),\n                Defaults::SIGMA_S_MIE, 1e-6f, 1e-1f, 1e-3f);\n            App::AddParam(p2);\n\n            ParamVariant p3;\n            p3.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Atmosphere\", \"Mie absorption coeff.\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetMieSigmaA),\n                Defaults::SIGMA_A_MIE, 1e-6f, 10.0f, 1e-3f);\n            App::AddParam(p3);\n\n            ParamVariant p4;\n            p4.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Atmosphere\", \"Ozone absorption scale\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetOzoneSigmaAScale),\n                g_data->m_frameConstants.OzoneSigmaAScale, 0.0f, 10.0f, 1e-4f);\n            App::AddParam(p4);\n\n            ParamVariant p5;\n            p5.InitColor(ICON_FA_LANDMARK \" Scene\", \"Atmosphere\", \"Ozone absorption color\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetOzoneSigmaAColor),\n                g_data->m_frameConstants.OzoneSigmaAColor);\n            App::AddParam(p5);\n\n            ParamVariant p6;\n            p6.InitFloat(ICON_FA_LANDMARK \" Scene\", \"Atmosphere\", \"g (HG Phase Function)\",\n                fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetgForPhaseHG),\n                Defaults::g, -0.99f, 0.99f, 0.2f);\n            App::AddParam(p6);\n        }\n    }\n\n    void Update(TaskSet& ts)\n    {\n        g_data->m_settings.AntiAliasing = g_data->PendingAA;\n        const auto frame = App::GetTimer().GetTotalFrameCount();\n        const auto& scene = App::GetScene();\n\n        g_data->m_settings.LightPresampling = scene.EmissiveLighting() && \n            App::GetScene().NumEmissiveTriangles() >= Defaults::MIN_NUM_LIGHTS_PRESAMPLING;\n\n        if (frame <= 1)\n        {\n            if (scene.EmissiveLighting())\n            {\n                //g_data->m_settings.UseLVG = g_data->m_settings.UseLVG && g_data->m_settings.LightPresampling;\n\n                // Move the sun below the horizon when there are emissives\n                g_data->m_frameConstants.SunDir = float3(0.0f, 1.0f, 0.0f);\n\n                // HACK UI params can't be modified from outside - remove then readd\n                App::RemoveParam(ICON_FA_LANDMARK \" Scene\", \"Sun\", \"(-)Dir\");\n\n                ParamVariant p0;\n                p0.InitUnitDir(ICON_FA_LANDMARK \" Scene\", \"Sun\", \"(-)Dir\",\n                    fastdelegate::FastDelegate1<const ParamVariant&>(&DefaultRenderer::SetSunDir),\n                    -g_data->m_frameConstants.SunDir);\n                App::AddParam(p0);\n            }\n        }\n\n        if (g_data->m_settings.LightPresampling)\n        {\n            // Notes:\n            // 1. Light presampling is off by default. So the following calls are only needed when it's been enabled.\n            // 2. Render graph ensures alias table and presampled sets are already computed when GPU \n            //    accesses them in the following render passes.\n            g_data->m_pathTracerData.PreLightingPass.SetLightPresamplingParams(\n                Defaults::MIN_NUM_LIGHTS_PRESAMPLING,\n                Defaults::NUM_SAMPLE_SETS, Defaults::SAMPLE_SET_SIZE);\n            g_data->m_pathTracerData.IndirecLightingPass.SetLightPresamplingParams(true,\n                Defaults::NUM_SAMPLE_SETS, Defaults::SAMPLE_SET_SIZE);\n        }\n        else\n        {\n            g_data->m_pathTracerData.PreLightingPass.SetLightPresamplingParams(\n                Defaults::MIN_NUM_LIGHTS_PRESAMPLING, 0, 0);\n            g_data->m_pathTracerData.IndirecLightingPass.SetLightPresamplingParams(false,\n                0, 0);\n        }\n\n        auto h0 = ts.EmplaceTask(\"SceneRenderer::UpdatePasses\", []()\n            {\n                GBuffer::Update(g_data->m_gbuffData);\n                PathTracer::Update(g_data->m_settings, g_data->m_renderGraph, g_data->m_pathTracerData);\n                PostProcessor::Update(g_data->m_settings, g_data->m_postProcessorData, g_data->m_gbuffData,\n                    g_data->m_pathTracerData);\n                Common::UpdateFrameConstants(g_data->m_frameConstants, g_data->m_frameConstantsBuff, g_data->m_gbuffData, \n                    g_data->m_pathTracerData);\n            });\n\n        auto h3 = ts.EmplaceTask(\"SceneRenderer::RenderGraph\", []()\n            {\n                g_data->m_renderGraph.BeginFrame();\n\n                GBuffer::Register(g_data->m_gbuffData, g_data->m_pathTracerData, g_data->m_renderGraph);\n                PathTracer::Register(g_data->m_settings, g_data->m_pathTracerData, g_data->m_renderGraph);\n                PostProcessor::Register(g_data->m_settings, g_data->m_postProcessorData, g_data->m_gbuffData,\n                    g_data->m_renderGraph);\n\n                g_data->m_renderGraph.MoveToPostRegister();\n\n                GBuffer::AddAdjacencies(g_data->m_gbuffData, g_data->m_pathTracerData, g_data->m_renderGraph);\n                PathTracer::AddAdjacencies(g_data->m_settings, g_data->m_pathTracerData, g_data->m_gbuffData,\n                    g_data->m_renderGraph);\n                PostProcessor::AddAdjacencies(g_data->m_settings, g_data->m_postProcessorData, g_data->m_gbuffData,\n                    g_data->m_pathTracerData, g_data->m_renderGraph);\n            });\n\n        // Render graph should go last\n        ts.AddOutgoingEdge(h0, h3);\n    }\n\n    void Render(TaskSet& ts)\n    {\n        g_data->m_renderGraph.Build(ts);\n    }\n\n    void Shutdown()\n    {\n        g_data->m_renderGraph.Shutdown();\n\n        // At this point, GPU has been flushed, so extra synchronization is not needed\n        delete g_data;\n    }\n\n    void OnWindowSizeChanged()\n    {\n        // Following order is important\n        GBuffer::OnWindowSizeChanged(g_data->m_settings, g_data->m_gbuffData);\n        PathTracer::OnWindowSizeChanged(g_data->m_settings, g_data->m_pathTracerData);\n        PostProcessor::OnWindowSizeChanged(g_data->m_settings, g_data->m_postProcessorData, g_data->m_pathTracerData);\n\n        g_data->m_renderGraph.Reset();\n        g_data->m_sceneChanged = true;\n    }\n\n    Core::RenderGraph* GetRenderGraph()\n    {\n        return &g_data->m_renderGraph;\n    }\n\n    void DebugDrawRenderGraph()\n    {\n        g_data->m_renderGraph.DebugDrawGraph();\n    }\n\n    bool IsRTASBuilt()\n    {\n        return g_data->m_pathTracerData.RtAS.GetTLAS().IsInitialized();\n    }\n\n    void SceneModified()\n    {\n        g_data->m_sceneChanged = true;\n    }\n\n    void Pick(uint16 screenPosX, uint16 screenPosY)\n    {\n        if (!g_data->m_pathTracerData.RtAS.IsReady())\n            return;\n\n        g_data->m_gbuffData.GBufferPass.PickPixel(screenPosX, screenPosY);\n    }\n\n    void ClearPick()\n    {\n        g_data->m_postProcessorData.DisplayPass.ClearPick();\n    }\n\n    void CaptureScreen()\n    {\n        g_data->m_postProcessorData.DisplayPass.CaptureScreen();\n    }\n\n    void ToggleEmissives()\n    {\n        if(g_data->m_pathTracerData.SkyDI_Pass.IsInitialized())\n            g_data->m_pathTracerData.SkyDI_Pass.ResetTemporal();\n        if(g_data->m_pathTracerData.DirecLightingPass.IsInitialized())\n            g_data->m_pathTracerData.DirecLightingPass.ResetTemporal();\n\n        g_data->m_pathTracerData.IndirecLightingPass.ResetTemporal();\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// DefaultRenderer\n//--------------------------------------------------------------------------------------\n\nScene::Renderer::Interface DefaultRenderer::InitAndGetInterface()\n{\n    Assert(!g_data, \"g_data has already been initialized.\");\n    g_data = new (std::nothrow) Data;\n\n    Scene::Renderer::Interface rndIntrf;\n\n    rndIntrf.Init = &DefaultRenderer::Init;\n    rndIntrf.Update = &DefaultRenderer::Update;\n    rndIntrf.Render = &DefaultRenderer::Render;\n    rndIntrf.Shutdown = &DefaultRenderer::Shutdown;\n    rndIntrf.OnWindowSizeChanged = &DefaultRenderer::OnWindowSizeChanged;\n    rndIntrf.GetRenderGraph = &DefaultRenderer::GetRenderGraph;\n    rndIntrf.DebugDrawRenderGraph = &DefaultRenderer::DebugDrawRenderGraph;\n    rndIntrf.IsRTASBuilt = &DefaultRenderer::IsRTASBuilt;\n    rndIntrf.SceneModified = &DefaultRenderer::SceneModified;\n    rndIntrf.Pick = &DefaultRenderer::Pick;\n    rndIntrf.ClearPick = &DefaultRenderer::ClearPick;\n    rndIntrf.CaptureScreen = &DefaultRenderer::CaptureScreen;\n    rndIntrf.ToggleEmissives = &DefaultRenderer::ToggleEmissives;\n\n    return rndIntrf;\n}"
  },
  {
    "path": "Source/ZetaRenderer/Default/DefaultRenderer.h",
    "content": "#pragma once\n\n#include <Scene/SceneRenderer.h>\n\nnamespace ZetaRay::DefaultRenderer\n{\n    Scene::Renderer::Interface InitAndGetInterface();\n}\n"
  },
  {
    "path": "Source/ZetaRenderer/Default/DefaultRendererImpl.h",
    "content": "#pragma once\n\n#include <Scene/SceneCore.h>\n#include <Core/RenderGraph.h>\n#include <Common/FrameConstants.h>\n#include <GBuffer/GBufferRT.h>\n#include <Compositing/Compositing.h>\n#include <TAA/TAA.h>\n#include <AutoExposure/AutoExposure.h>\n#include <Display/Display.h>\n#include <GUI/GuiPass.h>\n#include <Sky/Sky.h>\n#include <RayTracing/RtAccelerationStructure.h>\n#include <FSR2/FSR2.h>\n#include <DirectLighting/Emissive/DirectLighting.h>\n#include <DirectLighting/Sky/SkyDI.h>\n#include <PreLighting/PreLighting.h>\n#include <IndirectLighting/IndirectLighting.h>\n\n//--------------------------------------------------------------------------------------\n// DefaultRenderer\n//--------------------------------------------------------------------------------------\n\nnamespace ZetaRay::DefaultRenderer\n{\n    struct Defaults\n    {\n        // Ref: S. Hillaire, \"A Scalable and Production Ready Sky and Atmosphere Rendering Technique,\" Computer Graphics Forum, 2020.\n        inline static constexpr Math::float3 SIGMA_S_RAYLEIGH = Math::float3(5.802f, 13.558f, 33.1f) * 1e-3f;    // 1 / km\n        inline static constexpr float SIGMA_S_MIE = 3.996f * 1e-3f;        // Mie scattering is not wavelength dependent\n        inline static constexpr float SIGMA_A_MIE = 4.4f * 1e-3f;\n        inline static constexpr Math::float3 SIGMA_A_OZONE = Math::float3(0.65f, 1.881f, 0.085f) * 1e-3f;\n        static constexpr float g = 0.8f;\n        static constexpr float ATMOSPHERE_ALTITUDE = 100.0f;       // km\n        static constexpr float PLANET_RADIUS = 6360.0f;            // km\n        static constexpr float SUN_ANGULAR_DIAMETER = 0.526f;      // degrees\n        static constexpr int NUM_SAMPLE_SETS = 128;\n        static constexpr int SAMPLE_SET_SIZE = 512;\n        static constexpr float EMISSIVE_SET_MEM_BUDGET_MB = 0.5;\n        static constexpr int MIN_NUM_LIGHTS_PRESAMPLING = int((EMISSIVE_SET_MEM_BUDGET_MB * 1024 * 1024) /\n            sizeof(RT::PresampledEmissiveTriangle));\n        static constexpr Math::uint3 VOXEL_GRID_DIM = Math::uint3(32, 8, 40);\n        static constexpr Math::float3 VOXEL_EXTENTS = Math::float3(0.6f, 0.45f, 0.6f);\n    };\n\n    enum class AA\n    {\n        NONE,\n        TAA,\n        FSR2,\n        COUNT\n    };\n\n    inline static const char* AAOptions[] = { \"None\", \"TAA\", \"AMD FSR 2.2 (Quality)\" };\n    static_assert((int)AA::COUNT == ZetaArrayLen(AAOptions), \"enum <-> string mismatch.\");\n\n    inline static const char* IndirectOptions[] = { \"Path Tracing\", \"ReSTIR GI\", \"ReSTIR PT\" };\n    static_assert((int)RenderPass::IndirectLighting::INTEGRATOR::COUNT == ZetaArrayLen(IndirectOptions), \"enum <-> string mismatch.\");\n\n    inline static const char* LensTypes[] = { \"Pinhole\", \"Thin Lens\" };\n\n    static constexpr auto DEFAULT_AA = AA::NONE;\n\n    struct alignas(64) RenderSettings\n    {\n        bool Inscattering = false;\n        AA AntiAliasing = DEFAULT_AA;\n        RenderPass::IndirectLighting::INTEGRATOR Indirect = RenderPass::IndirectLighting::INTEGRATOR::ReSTIR_PT;\n\n        // Presampled sets\n        bool LightPresampling = false;\n\n        // LVG\n        bool UseLVG = false;\n        Math::uint3 VoxelGridDim = Defaults::VOXEL_GRID_DIM;\n        Math::float3 VoxelExtents = Defaults::VOXEL_EXTENTS;\n        float VoxelGridyOffset = 0.1f;\n    };\n\n    struct alignas(64) GBufferData\n    {\n        enum GBUFFER\n        {\n            BASE_COLOR,\n            NORMAL,\n            METALLIC_ROUGHNESS,\n            MOTION_VECTOR,\n            EMISSIVE_COLOR,\n            IOR,\n            COAT,\n            DEPTH,\n            TRI_DIFF_GEO_A,\n            TRI_DIFF_GEO_B,\n            COUNT\n        };\n\n        inline static const DXGI_FORMAT GBUFFER_FORMAT[GBUFFER::COUNT] =\n        {\n            DXGI_FORMAT_R8G8B8A8_UNORM,\n            DXGI_FORMAT_R16G16_UNORM,\n            DXGI_FORMAT_R8G8_UNORM,\n            DXGI_FORMAT_R16G16_SNORM,\n            DXGI_FORMAT_UNKNOWN,\n            DXGI_FORMAT_R8_UNORM,\n            DXGI_FORMAT_R16G16B16A16_UINT,\n            DXGI_FORMAT_R32_FLOAT,\n            DXGI_FORMAT_R32G32B32A32_UINT,\n            DXGI_FORMAT_R32G32_UINT\n        };\n\n        // Previous frame's g-buffers are required for denoising and ReSTIR\n        Core::GpuMemory::Texture BaseColor[2];\n        Core::GpuMemory::Texture Normal[2];\n        Core::GpuMemory::Texture MetallicRoughness[2];\n        Core::GpuMemory::Texture MotionVec;\n        Core::GpuMemory::Texture EmissiveColor;\n        Core::GpuMemory::Texture IORBuffer[2];\n        Core::GpuMemory::Texture CoatBuffer[2];\n        Core::GpuMemory::Texture Depth[2];\n        Core::GpuMemory::Texture TriDiffGeo_A[2];\n        Core::GpuMemory::Texture TriDiffGeo_B[2];\n        Core::GpuMemory::ResourceHeap ResHeap;\n\n        Core::DescriptorTable SrvDescTable[2];\n        Core::DescriptorTable UavDescTable[2];\n\n        RenderPass::GBufferRT GBufferPass;\n        Core::RenderNodeHandle GBufferPassHandle;\n    };\n\n    struct alignas(64) PostProcessData\n    {\n        // Render Passes\n        RenderPass::Compositing CompositingPass;\n        Core::RenderNodeHandle CompositingHandle;\n\n        RenderPass::TAA TaaPass;\n        Core::RenderNodeHandle TaaHandle;\n        RenderPass::FSR2Pass Fsr2Pass;\n        Core::RenderNodeHandle Fsr2Handle;\n\n        RenderPass::AutoExposure AutoExposurePass;\n        Core::RenderNodeHandle AutoExposureHandle;\n\n        RenderPass::DisplayPass DisplayPass;\n        Core::RenderNodeHandle DisplayHandle;\n\n        RenderPass::GuiPass GuiPass;\n        Core::RenderNodeHandle GuiHandle;\n\n        // Descriptors\n        enum class DESC_TABLE_CONST\n        {\n            HDR_LIGHT_ACCUM_SRV,\n            EXPOSURE_SRV,\n            COUNT\n        };\n\n        Core::DescriptorTable WindowSizeConstSRVs;\n        Core::DescriptorTable TaaOrFsr2OutSRV;\n    };\n\n    struct alignas(64) PathTracerData\n    {\n        static constexpr int SKY_LUT_WIDTH = 256;\n        static constexpr int SKY_LUT_HEIGHT = 128;\n\n        // Scene BVH\n        RT::TLAS RtAS;\n\n        // Render Passes\n        Core::RenderNodeHandle RtASBuildHandle;\n\n        RenderPass::SkyDI SkyDI_Pass;\n        Core::RenderNodeHandle SkyDI_Handle;\n\n        RenderPass::Sky SkyPass;\n        Core::RenderNodeHandle SkyHandle;\n\n        RenderPass::PreLighting PreLightingPass;\n        Core::RenderNodeHandle PreLightingPassHandle;\n\n        RenderPass::EmissiveTriangleAliasTable EmissiveAliasTable;\n        Core::RenderNodeHandle EmissiveAliasTableHandle;\n\n        RenderPass::DirectLighting DirecLightingPass;\n        Core::RenderNodeHandle DirecLightingHandle;\n\n        RenderPass::IndirectLighting IndirecLightingPass;\n        Core::RenderNodeHandle IndirecLightingHandle;\n\n        // Reflectance look up texture\n        Core::GpuMemory::Texture m_rhoLUT;\n\n        // Descrtiptors\n        enum class DESC_TABLE_WND_SIZE_CONST\n        {\n            SKY_DI,\n            EMISSIVE_DI,\n            INDIRECT,\n            COUNT\n        };\n\n        enum class DESC_TABLE_CONST\n        {\n            ENV_MAP_SRV,\n            INSCATTERING_SRV,\n            COUNT\n        };\n\n        Core::DescriptorTable ConstDescTable;\n        Core::DescriptorTable WndConstDescTable;\n    };\n\n    struct PrivateData\n    {\n        Core::RenderGraph m_renderGraph;\n        Core::GpuMemory::Buffer m_frameConstantsBuff;\n\n        cbFrameConstants m_frameConstants;\n        RenderSettings m_settings;\n\n        GBufferData m_gbuffData;\n        PostProcessData m_postProcessorData;\n        PathTracerData m_pathTracerData;\n\n        AA PendingAA = DEFAULT_AA;\n        bool m_sunMoved = false;\n        bool m_sceneChanged = false;\n    };\n}\n\nusing Data = ZetaRay::DefaultRenderer::PrivateData;\n\n//--------------------------------------------------------------------------------------\n// Common\n//--------------------------------------------------------------------------------------\n\nnamespace ZetaRay::DefaultRenderer::Common\n{\n    void UpdateFrameConstants(cbFrameConstants& frameConsts, Core::GpuMemory::Buffer& frameConstsBuff,\n        const GBufferData& gbuffData, const PathTracerData& rtData);\n}\n\n//--------------------------------------------------------------------------------------\n// GBuffer\n//--------------------------------------------------------------------------------------\n\nnamespace ZetaRay::DefaultRenderer::GBuffer\n{\n    void Init(const RenderSettings& settings, GBufferData& data);\n    void CreateGBuffers(GBufferData& data);\n    void OnWindowSizeChanged(const RenderSettings& settings, GBufferData& data);\n\n    void Update(GBufferData& gbuffData);\n    void Register(GBufferData& data, const PathTracerData& rayTracerData, Core::RenderGraph& renderGraph);\n    void AddAdjacencies(GBufferData& data, const PathTracerData& pathTracerData,\n        Core::RenderGraph& renderGraph);\n}\n\n//--------------------------------------------------------------------------------------\n// PathTracer\n//--------------------------------------------------------------------------------------\n\nnamespace ZetaRay::DefaultRenderer::PathTracer\n{\n    void Init(const RenderSettings& settings, PathTracerData& data);\n    void OnWindowSizeChanged(const RenderSettings& settings, PathTracerData& data);\n\n    void Update(const RenderSettings& settings, Core::RenderGraph& renderGraph, PathTracerData& data);\n    void Register(const RenderSettings& settings, PathTracerData& data, Core::RenderGraph& renderGraph);\n    void AddAdjacencies(const RenderSettings& settings, PathTracerData& rtData, const GBufferData& gbuffData,\n        Core::RenderGraph& renderGraph);\n}\n\n//--------------------------------------------------------------------------------------\n// PostProcessor\n//--------------------------------------------------------------------------------------\n\nnamespace ZetaRay::DefaultRenderer::PostProcessor\n{\n    void Init(const RenderSettings& settings, PostProcessData& data);\n    void OnWindowSizeChanged(const RenderSettings& settings, PostProcessData& data,\n        const PathTracerData& pathTracerData);\n\n    void UpdateWndDependentDescriptors(const RenderSettings& settings, PostProcessData& data);\n    void UpdateFrameDescriptors(const RenderSettings& settings, PostProcessData& data);\n    void UpdatePasses(const RenderSettings& settings, PostProcessData& data);\n    void Update(const RenderSettings& settings, PostProcessData& data, const GBufferData& gbufferData,\n        const PathTracerData& pathTracerData);\n    void Register(const RenderSettings& settings, PostProcessData& data, GBufferData& gbufferData,\n        Core::RenderGraph& renderGraph);\n    void AddAdjacencies(const RenderSettings& settings, PostProcessData& data, \n        const GBufferData& gbufferData,const PathTracerData& pathTracerData,\n        Core::RenderGraph& renderGraph);\n}"
  },
  {
    "path": "Source/ZetaRenderer/Default/GBuffer.cpp",
    "content": "#include \"DefaultRendererImpl.h\"\n\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Model;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Scene;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::DefaultRenderer;\n\n//--------------------------------------------------------------------------------------\n// GBuffer\n//--------------------------------------------------------------------------------------\n\nvoid GBuffer::Init(const RenderSettings& settings, GBufferData& data)\n{\n    for (int i = 0; i < 2; i++)\n    {\n        data.SrvDescTable[i] = App::GetRenderer().GetGpuDescriptorHeap().Allocate(\n            GBufferData::COUNT);\n        data.UavDescTable[i] = App::GetRenderer().GetGpuDescriptorHeap().Allocate(\n            GBufferData::COUNT);\n    }\n\n    CreateGBuffers(data);\n\n    data.GBufferPass.Init();\n}\n\nvoid GBuffer::CreateGBuffers(GBufferData& data)\n{\n    auto& renderer = App::GetRenderer();\n    const int width = renderer.GetRenderWidth();\n    const int height = renderer.GetRenderHeight();\n\n    const auto texFlags = TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS;\n    const auto texFlagsDepth = TEXTURE_FLAGS::ALLOW_UNORDERED_ACCESS;\n    const D3D12_RESOURCE_STATES depthInitState = D3D12_RESOURCE_STATE_COMMON;\n\n    const auto emissiveColFormat = App::GetRenderer().IsRGBESupported() ?\n        DXGI_FORMAT_R9G9B9E5_SHAREDEXP :\n        DXGI_FORMAT_R11G11B10_FLOAT;\n\n    // Except emissive and motion vector, everything is double-buffered\n    constexpr int N = 2 * (GBufferData::COUNT - 2) + 2;\n    PlacedResourceList<N> list;\n\n    // Base color\n    for (int i = 0; i < 2; i++)\n        list.PushTex2D(GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::BASE_COLOR], width, height, texFlags);\n    // Normal\n    for (int i = 0; i < 2; i++)\n        list.PushTex2D(GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::NORMAL], width, height, texFlags);\n    // Metallic-roughness\n    for (int i = 0; i < 2; i++)\n        list.PushTex2D(GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::METALLIC_ROUGHNESS], width, height, texFlags);\n    // Motion vector\n    list.PushTex2D(GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::MOTION_VECTOR], width, height, texFlags);\n    // Emissive color\n    list.PushTex2D(emissiveColFormat, width, height, texFlags);\n    // IOR\n    for (int i = 0; i < 2; i++)\n        list.PushTex2D(GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::IOR], width, height, texFlags);\n    // Coat\n    for (int i = 0; i < 2; i++)\n        list.PushTex2D(GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::COAT], width, height, texFlags);\n    // Triangle differential geometry - A\n    for (int i = 0; i < 2; i++)\n        list.PushTex2D(GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::TRI_DIFF_GEO_A], width, height, texFlags);\n    // Triangle differential geometry - B\n    for (int i = 0; i < 2; i++)\n        list.PushTex2D(GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::TRI_DIFF_GEO_B], width, height, texFlags);\n    // Depth\n    for (int i = 0; i < 2; i++)\n        list.PushTex2D(GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::DEPTH], width, height, texFlags);\n\n    list.End();\n\n    data.ResHeap = GpuMemory::GetResourceHeap(list.TotalSizeInBytes());\n    auto allocs = list.AllocInfos();\n    int currRes = 0;\n\n    // Base color\n    {\n        for (int i = 0; i < 2; i++)\n        {\n            StackStr(name, n, \"GBuffer_BaseColor_%d\", i);\n\n            data.BaseColor[i] = ZetaMove(GpuMemory::GetPlacedTexture2D(name,\n                width, height,\n                GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::BASE_COLOR],\n                data.ResHeap.Heap(),\n                allocs[currRes++].Offset,\n                D3D12_RESOURCE_STATE_COMMON,\n                texFlags));\n\n            // UAV\n            Direct3DUtil::CreateTexture2DUAV(data.BaseColor[i], data.UavDescTable[i].CPUHandle(\n                GBufferData::GBUFFER::BASE_COLOR));\n            // SRV\n            Direct3DUtil::CreateTexture2DSRV(data.BaseColor[i], data.SrvDescTable[i].CPUHandle(\n                GBufferData::GBUFFER::BASE_COLOR));\n        }\n    }\n\n    // Normal\n    {\n        for (int i = 0; i < 2; i++)\n        {\n            StackStr(name, n, \"GBuffer_Normal_%d\", i);\n\n            data.Normal[i] = ZetaMove(GpuMemory::GetPlacedTexture2D(name,\n                width, height,\n                GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::NORMAL],\n                data.ResHeap.Heap(),\n                allocs[currRes++].Offset,\n                D3D12_RESOURCE_STATE_COMMON,\n                texFlags));\n\n            // UAV\n            Direct3DUtil::CreateTexture2DUAV(data.Normal[i], data.UavDescTable[i].CPUHandle(\n                GBufferData::GBUFFER::NORMAL));\n            // SRV\n            Direct3DUtil::CreateTexture2DSRV(data.Normal[i], data.SrvDescTable[i].CPUHandle(\n                GBufferData::GBUFFER::NORMAL));\n        }\n    }\n\n    // Metallic-roughness\n    {\n        for (int i = 0; i < 2; i++)\n        {\n            StackStr(name, n, \"GBuffer_MR_%d\", i);\n\n            data.MetallicRoughness[i] = ZetaMove(GpuMemory::GetPlacedTexture2D(name,\n                width, height,\n                GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::METALLIC_ROUGHNESS],\n                data.ResHeap.Heap(),\n                allocs[currRes++].Offset,\n                D3D12_RESOURCE_STATE_COMMON,\n                texFlags));\n\n            // UAV\n            Direct3DUtil::CreateTexture2DUAV(data.MetallicRoughness[i], data.UavDescTable[i].CPUHandle(\n                GBufferData::GBUFFER::METALLIC_ROUGHNESS));\n            // SRV\n            Direct3DUtil::CreateTexture2DSRV(data.MetallicRoughness[i], data.SrvDescTable[i].CPUHandle(\n                GBufferData::GBUFFER::METALLIC_ROUGHNESS));\n        }\n    }\n\n    // Motion vector\n    {\n        data.MotionVec = ZetaMove(GpuMemory::GetPlacedTexture2D(\"GBuffer_MV\",\n            width, height,\n            GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::MOTION_VECTOR],\n            data.ResHeap.Heap(),\n            allocs[currRes++].Offset,\n            D3D12_RESOURCE_STATE_COMMON,\n            texFlags));\n\n        //UAV\n        Direct3DUtil::CreateTexture2DUAV(data.MotionVec, data.UavDescTable[0].CPUHandle(\n            GBufferData::GBUFFER::MOTION_VECTOR));\n        Direct3DUtil::CreateTexture2DUAV(data.MotionVec, data.UavDescTable[1].CPUHandle(\n            GBufferData::GBUFFER::MOTION_VECTOR));\n        // SRV\n        Direct3DUtil::CreateTexture2DSRV(data.MotionVec, data.SrvDescTable[0].CPUHandle(\n            GBufferData::GBUFFER::MOTION_VECTOR));\n        Direct3DUtil::CreateTexture2DSRV(data.MotionVec, data.SrvDescTable[1].CPUHandle(\n            GBufferData::GBUFFER::MOTION_VECTOR));\n    }\n\n    // Emissive color\n    {\n        data.EmissiveColor = ZetaMove(GpuMemory::GetPlacedTexture2D(\"GBuffer_Emissive\",\n            width, height,\n            emissiveColFormat,\n            data.ResHeap.Heap(),\n            allocs[currRes++].Offset,\n            D3D12_RESOURCE_STATE_COMMON,\n            texFlags));\n\n        //UAV\n        Direct3DUtil::CreateTexture2DUAV(data.EmissiveColor, data.UavDescTable[0].CPUHandle(\n            GBufferData::GBUFFER::EMISSIVE_COLOR));\n        Direct3DUtil::CreateTexture2DUAV(data.EmissiveColor, data.UavDescTable[1].CPUHandle(\n            GBufferData::GBUFFER::EMISSIVE_COLOR));\n        // SRV\n        Direct3DUtil::CreateTexture2DSRV(data.EmissiveColor, data.SrvDescTable[0].CPUHandle(\n            GBufferData::GBUFFER::EMISSIVE_COLOR));\n        Direct3DUtil::CreateTexture2DSRV(data.EmissiveColor, data.SrvDescTable[1].CPUHandle(\n            GBufferData::GBUFFER::EMISSIVE_COLOR));\n    }\n\n    // IOR\n    {\n        for (int i = 0; i < 2; i++)\n        {\n            StackStr(name, n, \"GBuffer_IOR_%d\", i);\n\n            data.IORBuffer[i] = ZetaMove(GpuMemory::GetPlacedTexture2D(name,\n                width, height,\n                GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::IOR],\n                data.ResHeap.Heap(),\n                allocs[currRes++].Offset,\n                D3D12_RESOURCE_STATE_COMMON,\n                texFlags));\n\n            // UAV\n            Direct3DUtil::CreateTexture2DUAV(data.IORBuffer[i], data.UavDescTable[i].CPUHandle(\n                GBufferData::GBUFFER::IOR));\n            // SRV\n            Direct3DUtil::CreateTexture2DSRV(data.IORBuffer[i], data.SrvDescTable[i].CPUHandle(\n                GBufferData::GBUFFER::IOR));\n        }\n    }\n\n    // Coat\n    {\n        for (int i = 0; i < 2; i++)\n        {\n            StackStr(name, n, \"GBuffer_Coat_%d\", i);\n\n            data.CoatBuffer[i] = ZetaMove(GpuMemory::GetPlacedTexture2D(name,\n                width, height,\n                GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::COAT],\n                data.ResHeap.Heap(),\n                allocs[currRes++].Offset,\n                D3D12_RESOURCE_STATE_COMMON,\n                texFlags));\n\n            // UAV\n            Direct3DUtil::CreateTexture2DUAV(data.CoatBuffer[i], data.UavDescTable[i].CPUHandle(\n                GBufferData::GBUFFER::COAT));\n            // SRV\n            Direct3DUtil::CreateTexture2DSRV(data.CoatBuffer[i], data.SrvDescTable[i].CPUHandle(\n                GBufferData::GBUFFER::COAT));\n        }\n    }\n\n    // Triangle differential geometry\n    {\n        for (int i = 0; i < 2; i++)\n        {\n            StackStr(nameA, nA, \"TriDiffGeoA_%d\", i);\n\n            data.TriDiffGeo_A[i] = ZetaMove(GpuMemory::GetPlacedTexture2D(nameA,\n                width, height,\n                GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::TRI_DIFF_GEO_A],\n                data.ResHeap.Heap(),\n                allocs[currRes++].Offset,\n                D3D12_RESOURCE_STATE_COMMON,\n                texFlags));\n\n            // UAV\n            Direct3DUtil::CreateTexture2DUAV(data.TriDiffGeo_A[i],\n                data.UavDescTable[i].CPUHandle(GBufferData::GBUFFER::TRI_DIFF_GEO_A));\n            // SRV\n            Direct3DUtil::CreateTexture2DSRV(data.TriDiffGeo_A[i],\n                data.SrvDescTable[i].CPUHandle(GBufferData::GBUFFER::TRI_DIFF_GEO_A));\n        }\n\n        for (int i = 0; i < 2; i++)\n        {\n            StackStr(nameA, nA, \"TriDiffGeoB_%d\", i);\n\n            data.TriDiffGeo_B[i] = ZetaMove(GpuMemory::GetPlacedTexture2D(nameA,\n                width, height,\n                GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::TRI_DIFF_GEO_B],\n                data.ResHeap.Heap(),\n                allocs[currRes++].Offset,\n                D3D12_RESOURCE_STATE_COMMON,\n                texFlags));\n\n            // UAV\n            Direct3DUtil::CreateTexture2DUAV(data.TriDiffGeo_B[i],\n                data.UavDescTable[i].CPUHandle(GBufferData::GBUFFER::TRI_DIFF_GEO_B));\n            // SRV\n            Direct3DUtil::CreateTexture2DSRV(data.TriDiffGeo_B[i],\n                data.SrvDescTable[i].CPUHandle(GBufferData::GBUFFER::TRI_DIFF_GEO_B));\n        }\n    }\n\n    // Depth\n    {\n        for (int i = 0; i < 2; i++)\n        {\n            StackStr(name, n, \"Depth_%d\", i);\n\n            data.Depth[i] = ZetaMove(GpuMemory::GetPlacedTexture2D(name,\n                width, height,\n                GBufferData::GBUFFER_FORMAT[GBufferData::GBUFFER::DEPTH],\n                data.ResHeap.Heap(),\n                allocs[currRes++].Offset,\n                depthInitState,\n                texFlagsDepth));\n\n            // UAV\n            Direct3DUtil::CreateTexture2DUAV(data.Depth[i], data.UavDescTable[i].CPUHandle(\n                GBufferData::GBUFFER::DEPTH));\n            // SRV\n            Direct3DUtil::CreateTexture2DSRV(data.Depth[i], data.SrvDescTable[i].CPUHandle(\n                GBufferData::GBUFFER::DEPTH),\n                DXGI_FORMAT_R32_FLOAT);\n        }\n    }\n}\n\nvoid GBuffer::OnWindowSizeChanged(const RenderSettings& settings, GBufferData& data)\n{\n    GBuffer::CreateGBuffers(data);\n}\n\nvoid GBuffer::Update(GBufferData& gbufferData)\n{\n    const int outIdx = App::GetRenderer().GlobalIdxForDoubleBufferedResources();\n\n    gbufferData.GBufferPass.SetGBufferUavDescTableGpuHeapIdx(\n        gbufferData.UavDescTable[outIdx].GPUDescriptorHeapIndex(GBufferData::GBUFFER::BASE_COLOR));\n}\n\nvoid GBuffer::Register(GBufferData& data, const PathTracerData& pathTracerData, RenderGraph& renderGraph)\n{\n    const bool tlasReady = pathTracerData.RtAS.IsReady();\n    if (!tlasReady)\n        return;\n\n    // GBuffer\n    fastdelegate::FastDelegate1<CommandList&> dlg = fastdelegate::MakeDelegate(&data.GBufferPass, &GBufferRT::Render);\n    data.GBufferPassHandle = renderGraph.RegisterRenderPass(\"GBuffer\", RENDER_NODE_TYPE::COMPUTE, dlg);\n\n    const D3D12_RESOURCE_STATES initDepthState = D3D12_RESOURCE_STATE_COMMON;\n\n    // Register current and previous frame's g-buffers\n    for (int i = 0; i < 2; i++)\n    {\n        renderGraph.RegisterResource(data.Normal[i].Resource(), data.Normal[i].ID());\n        renderGraph.RegisterResource(data.Depth[i].Resource(), data.Depth[i].ID(), initDepthState);\n        renderGraph.RegisterResource(data.MetallicRoughness[i].Resource(), data.MetallicRoughness[i].ID());\n        renderGraph.RegisterResource(data.BaseColor[i].Resource(), data.BaseColor[i].ID());\n        renderGraph.RegisterResource(data.IORBuffer[i].Resource(), data.IORBuffer[i].ID());\n        renderGraph.RegisterResource(data.CoatBuffer[i].Resource(), data.CoatBuffer[i].ID());\n        renderGraph.RegisterResource(data.TriDiffGeo_A[i].Resource(), data.TriDiffGeo_A[i].ID());\n        renderGraph.RegisterResource(data.TriDiffGeo_B[i].Resource(), data.TriDiffGeo_B[i].ID());\n    }\n\n    renderGraph.RegisterResource(data.MotionVec.Resource(), data.MotionVec.ID());\n    renderGraph.RegisterResource(data.EmissiveColor.Resource(), data.EmissiveColor.ID());\n}\n\nvoid GBuffer::AddAdjacencies(GBufferData& data, const PathTracerData& pathTracerData,\n    RenderGraph& renderGraph)\n{\n    const int outIdx = App::GetRenderer().GlobalIdxForDoubleBufferedResources();\n\n    const bool tlasReady = pathTracerData.RtAS.IsReady();\n    if (!tlasReady)\n        return;\n\n    const D3D12_RESOURCE_STATES gbufferOutState = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;\n    const D3D12_RESOURCE_STATES depthBuffOutState = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;\n\n    renderGraph.AddInput(data.GBufferPassHandle,\n        pathTracerData.RtAS.GetTLAS().ID(),\n        D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE);\n\n    renderGraph.AddOutput(data.GBufferPassHandle, data.BaseColor[outIdx].ID(), gbufferOutState);\n    renderGraph.AddOutput(data.GBufferPassHandle, data.Normal[outIdx].ID(), gbufferOutState);\n    renderGraph.AddOutput(data.GBufferPassHandle, data.MetallicRoughness[outIdx].ID(), gbufferOutState);\n    renderGraph.AddOutput(data.GBufferPassHandle, data.MotionVec.ID(), gbufferOutState);\n    renderGraph.AddOutput(data.GBufferPassHandle, data.EmissiveColor.ID(), gbufferOutState);\n    renderGraph.AddOutput(data.GBufferPassHandle, data.IORBuffer[outIdx].ID(), gbufferOutState);\n    renderGraph.AddOutput(data.GBufferPassHandle, data.CoatBuffer[outIdx].ID(), gbufferOutState);\n    renderGraph.AddOutput(data.GBufferPassHandle, data.Depth[outIdx].ID(), depthBuffOutState);\n}\n"
  },
  {
    "path": "Source/ZetaRenderer/Default/PathTracer.cpp",
    "content": "#include \"DefaultRendererImpl.h\"\n#include <App/Timer.h>\n\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::DefaultRenderer;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::RT;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\nusing namespace ZetaRay::Core::Direct3DUtil;\nusing namespace ZetaRay::Scene;\n\n//--------------------------------------------------------------------------------------\n// PathTracer\n//--------------------------------------------------------------------------------------\n\nvoid PathTracer::Init(const RenderSettings& settings, PathTracerData& data)\n{\n    // Allocate descriptor tables\n    data.WndConstDescTable = App::GetRenderer().GetGpuDescriptorHeap().Allocate(\n        (int)PathTracerData::DESC_TABLE_WND_SIZE_CONST::COUNT);\n    data.ConstDescTable = App::GetRenderer().GetGpuDescriptorHeap().Allocate(\n        (int)PathTracerData::DESC_TABLE_CONST::COUNT);\n\n    // Inscattering + sku-view lut\n    data.SkyPass.Init(PathTracerData::SKY_LUT_WIDTH, PathTracerData::SKY_LUT_HEIGHT, \n        settings.Inscattering);\n\n    Direct3DUtil::CreateTexture2DSRV(data.SkyPass.GetOutput(Sky::SHADER_OUT_RES::SKY_VIEW_LUT),\n        data.ConstDescTable.CPUHandle((int)PathTracerData::DESC_TABLE_CONST::ENV_MAP_SRV));\n\n    if (settings.Inscattering)\n    {\n        Direct3DUtil::CreateTexture3DSRV(data.SkyPass.GetOutput(Sky::SHADER_OUT_RES::INSCATTERING),\n            data.ConstDescTable.CPUHandle((int)PathTracerData::DESC_TABLE_CONST::INSCATTERING_SRV));\n    }\n\n    data.PreLightingPass.Init();\n\n    {\n        data.IndirecLightingPass.Init(settings.Indirect);\n\n        const Texture& indirectFinal = data.IndirecLightingPass.GetOutput(\n            IndirectLighting::SHADER_OUT_RES::FINAL);\n        Direct3DUtil::CreateTexture2DSRV(indirectFinal, data.WndConstDescTable.CPUHandle(\n            (int)PathTracerData::DESC_TABLE_WND_SIZE_CONST::INDIRECT));\n    }\n\n    App::Filesystem::Path p(App::GetAssetDir());\n    p.Append(\"LUT\\\\rho.dds\");\n    auto err = GpuMemory::GetTexture3DFromDisk(p.Get(), data.m_rhoLUT);\n    Check(err == LOAD_DDS_RESULT::SUCCESS, \"Error loading DDS texture from path %s: %d\",\n        p.Get(), err);\n\n    const DescriptorTable& table = App::GetRenderer().ReservedDescTable();\n    Direct3DUtil::CreateTexture3DSRV(data.m_rhoLUT, table.CPUHandle(0));\n}\n\nvoid PathTracer::OnWindowSizeChanged(const RenderSettings& settings, PathTracerData& data)\n{\n    // GPU is flushed after resize, safe to reuse descriptors\n\n    data.PreLightingPass.OnWindowResized();\n\n    if (data.DirecLightingPass.IsInitialized())\n    {\n        data.DirecLightingPass.OnWindowResized();\n\n        const Texture& t = data.DirecLightingPass.GetOutput(\n            DirectLighting::SHADER_OUT_RES::FINAL);\n        CreateTexture2DSRV(t, data.WndConstDescTable.CPUHandle(\n            (int)PathTracerData::DESC_TABLE_WND_SIZE_CONST::EMISSIVE_DI));\n    }\n\n    if (data.SkyDI_Pass.IsInitialized())\n    {\n        data.SkyDI_Pass.OnWindowResized();\n\n        const Texture& t = data.SkyDI_Pass.GetOutput(SkyDI::SHADER_OUT_RES::DENOISED);\n        CreateTexture2DSRV(t, data.WndConstDescTable.CPUHandle(\n            (int)PathTracerData::DESC_TABLE_WND_SIZE_CONST::SKY_DI));\n    }\n\n    {\n        data.IndirecLightingPass.OnWindowResized();\n\n        const Texture& indirectFinal = data.IndirecLightingPass.GetOutput(\n            IndirectLighting::SHADER_OUT_RES::FINAL);\n        CreateTexture2DSRV(indirectFinal, data.WndConstDescTable.CPUHandle(\n            (int)PathTracerData::DESC_TABLE_WND_SIZE_CONST::INDIRECT));\n    }\n}\n\nvoid PathTracer::Update(const RenderSettings& settings, Core::RenderGraph& renderGraph, \n    PathTracerData& data)\n{\n    const auto numEmissives = App::GetScene().NumEmissiveInstances();\n    const auto emissiveLighting = App::GetScene().EmissiveLighting();\n\n    if (settings.Inscattering && !data.SkyPass.IsInscatteringEnabled())\n    {\n        data.SkyPass.SetInscatteringEnablement(true);\n\n        CreateTexture3DSRV(data.SkyPass.GetOutput(Sky::SHADER_OUT_RES::INSCATTERING),\n            data.ConstDescTable.CPUHandle(\n                (int)PathTracerData::DESC_TABLE_CONST::INSCATTERING_SRV));\n    }\n    else if (!settings.Inscattering && data.SkyPass.IsInscatteringEnabled())\n        data.SkyPass.SetInscatteringEnablement(false);\n\n    if (!emissiveLighting && !data.SkyDI_Pass.IsInitialized())\n    {\n        data.SkyDI_Pass.Init();\n\n        const Texture& skyDIOutTex = data.SkyDI_Pass.GetOutput(SkyDI::SHADER_OUT_RES::DENOISED);\n        CreateTexture2DSRV(skyDIOutTex, data.WndConstDescTable.CPUHandle(\n            (int)PathTracerData::DESC_TABLE_WND_SIZE_CONST::SKY_DI));\n    }\n\n    data.RtAS.Update();\n\n    data.PreLightingPass.Update();\n\n    // Recompute alias table only if there are stale emissives\n    if (numEmissives > 0)\n    {\n        if (emissiveLighting && !data.DirecLightingPass.IsInitialized())\n        {\n            data.DirecLightingPass.Init();\n\n            const Texture& t = data.DirecLightingPass.GetOutput(DirectLighting::SHADER_OUT_RES::FINAL);\n            CreateTexture2DSRV(t, data.WndConstDescTable.CPUHandle(\n                (int)PathTracerData::DESC_TABLE_WND_SIZE_CONST::EMISSIVE_DI));\n\n            data.DirecLightingPass.SetLightPresamplingParams(settings.LightPresampling,\n                Defaults::NUM_SAMPLE_SETS, Defaults::SAMPLE_SET_SIZE);\n        }\n\n        if (App::GetScene().AreEmissiveMaterialsStale())\n        {\n            auto& readback = data.PreLightingPass.GetLumenReadbackBuffer();\n            data.EmissiveAliasTable.Update(&readback);\n            data.EmissiveAliasTable.SetReleaseBuffersDlg(data.PreLightingPass.GetReleaseBuffersDlg());\n        }\n    }\n}\n\nvoid PathTracer::Register(const RenderSettings& settings, PathTracerData& data, \n    RenderGraph& renderGraph)\n{\n    // Rt AS rebuild/update\n    {\n        fastdelegate::FastDelegate1<CommandList&> dlg1 = fastdelegate::MakeDelegate(\n            &data.RtAS, &TLAS::Render);\n        data.RtASBuildHandle = renderGraph.RegisterRenderPass(\"RT_AS_Build\", \n            RENDER_NODE_TYPE::COMPUTE, dlg1);\n    }\n\n    const bool tlasReady = data.RtAS.IsReady();\n    const bool numEmissives = App::GetScene().NumEmissiveInstances();\n    const bool emissiveLighting = App::GetScene().EmissiveLighting();\n    const auto frame = App::GetTimer().GetTotalFrameCount();\n\n    // Sky-view lut + inscattering\n    if (tlasReady)\n    {\n        fastdelegate::FastDelegate1<CommandList&> dlg = fastdelegate::MakeDelegate(\n            &data.SkyPass, &Sky::Render);\n        data.SkyHandle = renderGraph.RegisterRenderPass(\"Sky\", RENDER_NODE_TYPE::COMPUTE, \n            dlg);\n\n        auto& skyviewLUT = const_cast<Texture&>(data.SkyPass.GetOutput(\n            Sky::SHADER_OUT_RES::SKY_VIEW_LUT));\n        renderGraph.RegisterResource(skyviewLUT.Resource(), skyviewLUT.ID(), \n            D3D12_RESOURCE_STATE_COMMON, false);\n\n        if (settings.Inscattering)\n        {\n            auto& voxelGrid = const_cast<Texture&>(data.SkyPass.GetOutput(\n                Sky::SHADER_OUT_RES::INSCATTERING));\n            renderGraph.RegisterResource(voxelGrid.Resource(), voxelGrid.ID(), \n                D3D12_RESOURCE_STATE_COMMON, false);\n        }\n    }\n\n    if (tlasReady)\n    {\n        auto& tlas = const_cast<Buffer&>(data.RtAS.GetTLAS());\n        renderGraph.RegisterResource(tlas.Resource(), tlas.ID(), \n            D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE,\n            false);\n    }\n\n    if (numEmissives)\n    {\n        // Pre lighting\n        fastdelegate::FastDelegate1<CommandList&> dlg1 = fastdelegate::MakeDelegate(&data.PreLightingPass,\n            &PreLighting::Render);\n        data.PreLightingPassHandle = renderGraph.RegisterRenderPass(\"PreLighting\", \n            RENDER_NODE_TYPE::COMPUTE, dlg1);\n\n        // Read back emissive lumen buffer and compute alias table on CPU\n        if (App::GetScene().AreEmissiveMaterialsStale())\n        {\n            auto& triPowerBuffer = data.PreLightingPass.GetTriEmissivePowerBuffer();\n            renderGraph.RegisterResource(const_cast<Buffer&>(triPowerBuffer).Resource(),\n                triPowerBuffer.ID(), D3D12_RESOURCE_STATE_COPY_SOURCE, false);\n\n            fastdelegate::FastDelegate1<CommandList&> dlg2 = fastdelegate::MakeDelegate(&data.EmissiveAliasTable,\n                &EmissiveTriangleAliasTable::Render);\n            data.EmissiveAliasTableHandle = renderGraph.RegisterRenderPass(\"EmissiveAliasTable\", \n                RENDER_NODE_TYPE::COMPUTE, dlg2);\n\n            auto& aliasTable = data.EmissiveAliasTable.GetOutput(\n                EmissiveTriangleAliasTable::SHADER_OUT_RES::ALIAS_TABLE);\n            renderGraph.RegisterResource(aliasTable.Resource(), aliasTable.ID(), \n                D3D12_RESOURCE_STATE_COMMON, false);\n\n            data.EmissiveAliasTable.SetEmissiveTriPassHandle(data.PreLightingPassHandle);\n        }\n        // Since alias table is computed on CPU, instead of waiting for GPU to finish\n        // computation and causing a hitch, defer computation to next frame(s) at\n        // the expense of some lag\n        else if (data.EmissiveAliasTable.HasPendingRender())\n        {\n            fastdelegate::FastDelegate1<CommandList&> dlg2 = fastdelegate::MakeDelegate(&data.EmissiveAliasTable,\n                &EmissiveTriangleAliasTable::Render);\n            data.EmissiveAliasTableHandle = renderGraph.RegisterRenderPass(\"EmissiveAliasTable\",\n                RENDER_NODE_TYPE::COMPUTE, dlg2);\n\n            // Refer to notes in lines 413-415\n            if (settings.LightPresampling)\n            {\n                auto& aliasTable = data.EmissiveAliasTable.GetOutput(\n                    EmissiveTriangleAliasTable::SHADER_OUT_RES::ALIAS_TABLE);\n                renderGraph.RegisterResource(aliasTable.Resource(), aliasTable.ID(),\n                    D3D12_RESOURCE_STATE_COMMON, false);\n            }\n        }\n\n        if (tlasReady)\n        {\n            // At frame 1 (app startup is counted as \"frame\" 0, so program\n            // loop starts from frame 1):\n            // 1. Power of each emissive triangle is estimated (1)\n            // 2. Results of step 1 are read back on CPU and alias table is built (1)\n            // 3. Alias table is uploaded to GPU\n            // 4. If light presampling is enabled, presampled sets are built each frame \n            //    using the alias table starting from next frame (2 - one frame of delay)\n            // \n            // In conclusion, when light presampling is enabled, shaders that depend on it \n            // shouldn't execute in frame 1.\n            const bool presampledSetsBuiltOnce = frame > 1;\n\n            if (!settings.LightPresampling || presampledSetsBuiltOnce)\n            {\n                // Pre lighting\n                if (settings.LightPresampling && presampledSetsBuiltOnce && emissiveLighting)\n                {\n                    auto& presampled = data.PreLightingPass.GePresampledSets();\n                    renderGraph.RegisterResource(const_cast<Buffer&>(presampled).Resource(), \n                        presampled.ID(), D3D12_RESOURCE_STATE_COMMON);\n\n                    if (settings.UseLVG)\n                    {\n                        auto& lvg = data.PreLightingPass.GetLightVoxelGrid();\n                        renderGraph.RegisterResource(const_cast<Buffer&>(lvg).Resource(), lvg.ID(),\n                            D3D12_RESOURCE_STATE_COMMON);\n                    }\n                }\n\n                // Direct lighting\n                if (emissiveLighting)\n                {\n                    fastdelegate::FastDelegate1<CommandList&> dlg3 = fastdelegate::MakeDelegate(&data.DirecLightingPass,\n                        &DirectLighting::Render);\n                    data.DirecLightingHandle = renderGraph.RegisterRenderPass(\"DirectLighting\", \n                        RENDER_NODE_TYPE::COMPUTE, dlg3);\n\n                    Texture& td = const_cast<Texture&>(data.DirecLightingPass.GetOutput(\n                        DirectLighting::SHADER_OUT_RES::FINAL));\n                    renderGraph.RegisterResource(td.Resource(), td.ID());\n                }\n\n                // Indirect lighting\n                fastdelegate::FastDelegate1<CommandList&> dlg2 = fastdelegate::MakeDelegate(\n                    &data.IndirecLightingPass, &IndirectLighting::Render);\n                data.IndirecLightingHandle = renderGraph.RegisterRenderPass(\"Indirect\", \n                    RENDER_NODE_TYPE::COMPUTE, dlg2);\n\n                Texture& ti = const_cast<Texture&>(data.IndirecLightingPass.GetOutput(\n                    IndirectLighting::SHADER_OUT_RES::FINAL));\n                renderGraph.RegisterResource(ti.Resource(), ti.ID());\n            }\n        }\n    }\n    // Indirect lighting\n    else if (tlasReady)\n    {\n        fastdelegate::FastDelegate1<CommandList&> dlg2 = fastdelegate::MakeDelegate(\n            &data.IndirecLightingPass, &IndirectLighting::Render);\n        data.IndirecLightingHandle = renderGraph.RegisterRenderPass(\"Indirect\", \n            RENDER_NODE_TYPE::COMPUTE, dlg2);\n\n        Texture& t = const_cast<Texture&>(data.IndirecLightingPass.GetOutput(\n            IndirectLighting::SHADER_OUT_RES::FINAL));\n        renderGraph.RegisterResource(t.Resource(), t.ID());\n    }\n\n    // Sky DI\n    if (!emissiveLighting && tlasReady)\n    {\n        fastdelegate::FastDelegate1<CommandList&> dlg2 = fastdelegate::MakeDelegate(\n            &data.SkyDI_Pass, &SkyDI::Render);\n        data.SkyDI_Handle = renderGraph.RegisterRenderPass(\"SkyDI\", RENDER_NODE_TYPE::COMPUTE, \n            dlg2);\n\n        Texture& t = const_cast<Texture&>(data.SkyDI_Pass.GetOutput(\n            SkyDI::SHADER_OUT_RES::DENOISED));\n        renderGraph.RegisterResource(t.Resource(), t.ID());\n    }\n}\n\nvoid PathTracer::AddAdjacencies(const RenderSettings& settings, PathTracerData& data, \n    const GBufferData& gbuffData, RenderGraph& renderGraph)\n{\n    const int outIdx = App::GetRenderer().GlobalIdxForDoubleBufferedResources();\n    const bool tlasReady = data.RtAS.IsReady();\n    const auto tlasID = tlasReady ? data.RtAS.GetTLAS().ID() : Buffer::INVALID_ID;\n    const auto numEmissives = App::GetScene().NumEmissiveInstances();\n    const auto emissiveLighting = App::GetScene().EmissiveLighting();\n    const auto frame = App::GetTimer().GetTotalFrameCount();\n\n    // Rt AS\n    if (tlasReady)\n    {\n        renderGraph.AddOutput(data.RtASBuildHandle,\n            tlasID,\n            D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE);\n    }\n\n    // Inscattering + sky-view lut\n    if (tlasReady)\n    {\n        renderGraph.AddOutput(data.SkyHandle,\n            data.SkyPass.GetOutput(Sky::SHADER_OUT_RES::SKY_VIEW_LUT).ID(),\n            D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n\n        if (settings.Inscattering)\n        {\n            // Rt AS\n            renderGraph.AddInput(data.SkyHandle,\n                tlasID,\n                D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE);\n\n            renderGraph.AddOutput(data.SkyHandle,\n                data.SkyPass.GetOutput(Sky::SHADER_OUT_RES::INSCATTERING).ID(),\n                D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n        }\n    }\n\n    SmallVector<RenderNodeHandle, Support::SystemAllocator, 3> handles;\n    handles.reserve(3);\n    handles.push_back(data.IndirecLightingHandle);\n    \n    // When light presampling is enabled, sample sets are available starting frame frame 2\n    const bool presampledSetsBuiltOnce = frame > 1;\n    if (emissiveLighting && (!settings.LightPresampling || presampledSetsBuiltOnce))\n        handles.push_back(data.DirecLightingHandle);\n\n    if(!emissiveLighting)\n        handles.push_back(data.SkyDI_Handle);\n\n    if (numEmissives)\n    {\n        // Pre lighting\n        if (App::GetScene().AreEmissiveMaterialsStale())\n        {\n            const auto& triPowerBuffer = data.PreLightingPass.GetTriEmissivePowerBuffer();\n\n            renderGraph.AddOutput(data.PreLightingPassHandle,\n                triPowerBuffer.ID(),\n                D3D12_RESOURCE_STATE_COPY_SOURCE);\n\n            renderGraph.AddInput(data.EmissiveAliasTableHandle,\n                triPowerBuffer.ID(),\n                D3D12_RESOURCE_STATE_COPY_SOURCE);\n\n            renderGraph.AddOutput(data.EmissiveAliasTableHandle,\n                data.EmissiveAliasTable.GetOutput(EmissiveTriangleAliasTable::SHADER_OUT_RES::ALIAS_TABLE).ID(),\n                D3D12_RESOURCE_STATE_COPY_DEST);\n        }\n        // Tri lumen buffer was recomputed last frame, but the results weren't ready yet. Now\n        // in this frame, alias table pass has no dependencies, but prelighting should run\n        // after it so the new alias table is used as early as possible for presampling.\n        else if (settings.LightPresampling && data.EmissiveAliasTable.HasPendingRender())\n        {\n            const uint32_t aliasTable = data.EmissiveAliasTable.GetOutput(\n                EmissiveTriangleAliasTable::SHADER_OUT_RES::ALIAS_TABLE).ID();\n\n            renderGraph.AddOutput(data.EmissiveAliasTableHandle,\n                aliasTable,\n                D3D12_RESOURCE_STATE_COPY_DEST);\n\n            renderGraph.AddInput(data.PreLightingPassHandle,\n                aliasTable,\n                D3D12_RESOURCE_STATE_COPY_DEST);\n        }\n\n        // Direct + indirect lighting\n        if (tlasReady && emissiveLighting)\n        {\n            // Lighting passes should run after alias table when it's recomputed\n            if (!settings.LightPresampling && \n                (App::GetScene().AreEmissiveMaterialsStale() || data.EmissiveAliasTable.HasPendingRender()))\n            {\n                const uint32_t aliasTable = data.EmissiveAliasTable.GetOutput(\n                    EmissiveTriangleAliasTable::SHADER_OUT_RES::ALIAS_TABLE).ID();\n\n                renderGraph.AddInput(data.DirecLightingHandle,\n                    aliasTable,\n                    D3D12_RESOURCE_STATE_COPY_DEST);\n\n                renderGraph.AddInput(data.IndirecLightingHandle,\n                    aliasTable,\n                    D3D12_RESOURCE_STATE_COPY_DEST);\n\n                renderGraph.AddOutput(data.DirecLightingHandle,\n                    data.DirecLightingPass.GetOutput(DirectLighting::SHADER_OUT_RES::FINAL).ID(),\n                    D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n            }\n            // Lighting passes should run after light presampling pass\n            else if(settings.LightPresampling && presampledSetsBuiltOnce)\n            {\n                const uint32_t presampled = data.PreLightingPass.GePresampledSets().ID();\n\n                renderGraph.AddOutput(data.PreLightingPassHandle,\n                    presampled,\n                    D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n\n                if (settings.UseLVG)\n                {\n                    renderGraph.AddOutput(data.PreLightingPassHandle,\n                        data.PreLightingPass.GetLightVoxelGrid().ID(),\n                        D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n\n                    renderGraph.AddInput(data.IndirecLightingHandle,\n                        data.PreLightingPass.GetLightVoxelGrid().ID(),\n                        D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n                }\n\n                renderGraph.AddInput(data.DirecLightingHandle,\n                    presampled,\n                    D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n\n                renderGraph.AddInput(data.IndirecLightingHandle,\n                    presampled,\n                    D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n\n                renderGraph.AddOutput(data.DirecLightingHandle,\n                    data.DirecLightingPass.GetOutput(DirectLighting::SHADER_OUT_RES::FINAL).ID(),\n                    D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n            }\n        }\n    }\n\n    // Direct + indirect lighting depend on current and previous g-buffers\n    if (tlasReady)\n    {\n        for (int i = 0; i < handles.size(); i++)\n        {\n            // Rt AS\n            renderGraph.AddInput(handles[i],\n                tlasID,\n                D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE);\n\n            // Previous g-buffers\n            renderGraph.AddInput(handles[i],\n                gbuffData.Depth[1 - outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.BaseColor[1 - outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.Normal[1 - outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.MetallicRoughness[1 - outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.IORBuffer[1 - outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.CoatBuffer[1 - outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.TriDiffGeo_A[1 - outIdx].ID(),\n                D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.TriDiffGeo_B[1 - outIdx].ID(),\n                D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n\n            // Current g-buffers\n            renderGraph.AddInput(handles[i],\n                gbuffData.Normal[outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.MetallicRoughness[outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.Depth[outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.MotionVec.ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.BaseColor[outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.IORBuffer[outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.CoatBuffer[outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.TriDiffGeo_A[outIdx].ID(),\n                D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(handles[i],\n                gbuffData.TriDiffGeo_B[outIdx].ID(),\n                D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n        }\n\n        // Outputs\n        renderGraph.AddOutput(data.IndirecLightingHandle,\n            data.IndirecLightingPass.GetOutput(IndirectLighting::SHADER_OUT_RES::FINAL).ID(),\n            D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n    }\n\n    // Sky DI\n    if (!emissiveLighting && tlasReady)\n    {\n        // Denoised output\n        renderGraph.AddOutput(data.SkyDI_Handle,\n            data.SkyDI_Pass.GetOutput(SkyDI::SHADER_OUT_RES::DENOISED).ID(),\n            D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n    }\n}\n"
  },
  {
    "path": "Source/ZetaRenderer/Default/PostProcessor.cpp",
    "content": "#include \"DefaultRendererImpl.h\"\n\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::RenderPass;\nusing namespace ZetaRay::DefaultRenderer;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Core::GpuMemory;\n\n//--------------------------------------------------------------------------------------\n// PostProcessor\n//--------------------------------------------------------------------------------------\n\nvoid PostProcessor::Init(const RenderSettings& settings, PostProcessData& data)\n{\n    data.AutoExposurePass.Init();\n    data.DisplayPass.Init();\n    data.GuiPass.Init();\n    data.CompositingPass.Init();\n\n    UpdateWndDependentDescriptors(settings, data);\n}\n\nvoid PostProcessor::UpdateWndDependentDescriptors(const RenderSettings& settings, \n    PostProcessData& data)\n{\n    data.WindowSizeConstSRVs = App::GetRenderer().GetGpuDescriptorHeap().Allocate(\n        (int)PostProcessData::DESC_TABLE_CONST::COUNT);\n\n    Direct3DUtil::CreateTexture2DSRV(data.AutoExposurePass.GetOutput(\n        AutoExposure::SHADER_OUT_RES::EXPOSURE),\n        data.WindowSizeConstSRVs.CPUHandle((int)PostProcessData::DESC_TABLE_CONST::EXPOSURE_SRV));\n\n    const Texture& lightAccum = data.CompositingPass.GetOutput(\n        Compositing::SHADER_OUT_RES::COMPOSITED);\n    Direct3DUtil::CreateTexture2DSRV(lightAccum,\n        data.WindowSizeConstSRVs.CPUHandle(\n            (int)PostProcessData::DESC_TABLE_CONST::HDR_LIGHT_ACCUM_SRV));\n}\n\nvoid PostProcessor::UpdateFrameDescriptors(const RenderSettings& settings, PostProcessData& data)\n{\n    if (settings.AntiAliasing == AA::TAA)\n    {\n        const int outIdx = App::GetRenderer().GlobalIdxForDoubleBufferedResources();\n\n        data.TaaOrFsr2OutSRV = App::GetRenderer().GetGpuDescriptorHeap().Allocate(1);\n\n        // Due to ping-ponging, TAA's output texture changes every frame\n        const TAA::SHADER_OUT_RES taaOutIdx = outIdx == 0 ? TAA::SHADER_OUT_RES::OUTPUT_B : \n            TAA::SHADER_OUT_RES::OUTPUT_A;\n        Texture& taaOut = data.TaaPass.GetOutput(taaOutIdx);\n        Direct3DUtil::CreateTexture2DSRV(taaOut, data.TaaOrFsr2OutSRV.CPUHandle(0));\n    }\n}\n\nvoid PostProcessor::UpdatePasses(const RenderSettings& settings, PostProcessData& data)\n{\n    if (settings.AntiAliasing != AA::FSR2 && data.Fsr2Pass.IsInitialized())\n        data.Fsr2Pass.Reset();\n\n    if (settings.AntiAliasing != AA::TAA && data.TaaPass.IsInitialized())\n        data.TaaPass.Reset();\n\n    if (settings.AntiAliasing == AA::TAA && !data.TaaPass.IsInitialized())\n        data.TaaPass.Init();\n    else if (settings.AntiAliasing == AA::FSR2 && !data.Fsr2Pass.IsInitialized())\n    {\n        data.Fsr2Pass.Activate();\n\n        data.TaaOrFsr2OutSRV = App::GetRenderer().GetGpuDescriptorHeap().Allocate(1);\n\n        const Texture& upscaled = data.Fsr2Pass.GetOutput(FSR2Pass::SHADER_OUT_RES::UPSCALED);\n        Direct3DUtil::CreateTexture2DSRV(upscaled, data.TaaOrFsr2OutSRV.CPUHandle(0));\n    }\n}\n\nvoid PostProcessor::OnWindowSizeChanged(const RenderSettings& settings, PostProcessData& data,\n    const PathTracerData& rtData)\n{\n    data.CompositingPass.OnWindowResized();\n    data.GuiPass.OnWindowResized();\n\n    if (settings.AntiAliasing == AA::TAA)\n        data.TaaPass.OnWindowResized();\n    else if (settings.AntiAliasing == AA::FSR2)\n        data.Fsr2Pass.OnWindowResized();\n\n    UpdateWndDependentDescriptors(settings, data);\n}\n\nvoid PostProcessor::Update(const RenderSettings& settings, PostProcessData& data, \n    const GBufferData& gbuffData, const PathTracerData& rtData)\n{\n    UpdatePasses(settings, data);\n    UpdateFrameDescriptors(settings, data);\n\n    const int outIdx = App::GetRenderer().GlobalIdxForDoubleBufferedResources();\n    const auto compositedSrv = PostProcessData::DESC_TABLE_CONST::HDR_LIGHT_ACCUM_SRV;\n\n    if (rtData.RtAS.IsReady())\n    {\n        // Emissive DI\n        if (App::GetScene().EmissiveLighting())\n        {\n            data.CompositingPass.SetGpuDescriptor(Compositing::SHADER_IN_GPU_DESC::EMISSIVE_DI,\n                rtData.WndConstDescTable.GPUDescriptorHeapIndex(\n                    (int)PathTracerData::DESC_TABLE_WND_SIZE_CONST::EMISSIVE_DI));\n        }\n        // Sky DI\n        else\n        {\n            data.CompositingPass.SetGpuDescriptor(Compositing::SHADER_IN_GPU_DESC::SKY_DI,\n                rtData.WndConstDescTable.GPUDescriptorHeapIndex(\n                    (int)PathTracerData::DESC_TABLE_WND_SIZE_CONST::SKY_DI));\n        }\n\n        // Indirect lighting\n        data.CompositingPass.SetGpuDescriptor(Compositing::SHADER_IN_GPU_DESC::INDIRECT,\n            rtData.WndConstDescTable.GPUDescriptorHeapIndex(\n                (int)PathTracerData::DESC_TABLE_WND_SIZE_CONST::INDIRECT));\n\n        if (settings.Inscattering)\n        {\n            data.CompositingPass.SetInscatteringEnablement(true);\n\n            const float p = rtData.SkyPass.GetVoxelGridMappingExp();\n            float2 depths = rtData.SkyPass.GetVoxelGridDepth();\n\n            data.CompositingPass.SetVoxelGridMappingExp(p);\n            data.CompositingPass.SetVoxelGridDepth(depths.x, depths.y);\n            data.CompositingPass.SetGpuDescriptor(Compositing::SHADER_IN_GPU_DESC::INSCATTERING,\n                rtData.ConstDescTable.GPUDescriptorHeapIndex((int)PathTracerData::DESC_TABLE_CONST::INSCATTERING_SRV));\n        }\n        else\n            data.CompositingPass.SetInscatteringEnablement(false);\n    }\n\n    // Display\n    auto backBuffRTV = App::GetRenderer().GetCurrBackBufferRTV();\n    data.DisplayPass.SetCpuDescriptor(DisplayPass::SHADER_IN_CPU_DESC::RTV, backBuffRTV);\n\n    const Texture& exposureTex = data.AutoExposurePass.GetOutput(\n        AutoExposure::SHADER_OUT_RES::EXPOSURE);\n    data.DisplayPass.SetGpuDescriptor(DisplayPass::SHADER_IN_GPU_DESC::EXPOSURE,\n        data.WindowSizeConstSRVs.GPUDescriptorHeapIndex(\n            (int)PostProcessData::DESC_TABLE_CONST::EXPOSURE_SRV));\n\n    data.GuiPass.SetCPUDescriptor(GuiPass::SHADER_IN_CPU_DESC::RTV, backBuffRTV);\n\n    // Auto Exposure\n    data.AutoExposurePass.SetDescriptor(AutoExposure::SHADER_IN_DESC::COMPOSITED,\n        data.WindowSizeConstSRVs.GPUDescriptorHeapIndex((int)compositedSrv));\n\n    // TAA\n    if (settings.AntiAliasing == AA::TAA)\n    {\n        data.TaaPass.SetDescriptor(TAA::SHADER_IN_DESC::SIGNAL,\n            data.WindowSizeConstSRVs.GPUDescriptorHeapIndex((int)compositedSrv));\n\n        // Display\n        data.DisplayPass.SetGpuDescriptor(DisplayPass::SHADER_IN_GPU_DESC::COMPOSITED, \n            data.TaaOrFsr2OutSRV.GPUDescriptorHeapIndex(0));\n    }\n    // FSR2\n    else if (settings.AntiAliasing == AA::FSR2)\n    {\n        Texture& composited = const_cast<Texture&>(data.CompositingPass.GetOutput(\n            Compositing::SHADER_OUT_RES::COMPOSITED));\n\n        data.Fsr2Pass.SetInput(FSR2Pass::SHADER_IN_RES::DEPTH, \n            const_cast<Texture&>(gbuffData.Depth[outIdx]).Resource());\n        data.Fsr2Pass.SetInput(FSR2Pass::SHADER_IN_RES::MOTION_VECTOR, \n            const_cast<Texture&>(gbuffData.MotionVec).Resource());\n        data.Fsr2Pass.SetInput(FSR2Pass::SHADER_IN_RES::COLOR, composited.Resource());\n        data.Fsr2Pass.SetInput(FSR2Pass::SHADER_IN_RES::EXPOSURE, \n            const_cast<Texture&>(exposureTex).Resource());\n\n        // Display\n        data.DisplayPass.SetGpuDescriptor(DisplayPass::SHADER_IN_GPU_DESC::COMPOSITED, \n            data.TaaOrFsr2OutSRV.GPUDescriptorHeapIndex(0));\n    }\n    else\n    {\n        // Display\n        data.DisplayPass.SetGpuDescriptor(DisplayPass::SHADER_IN_GPU_DESC::COMPOSITED,\n            data.WindowSizeConstSRVs.GPUDescriptorHeapIndex((int)compositedSrv));\n    }\n}\n\nvoid PostProcessor::Register(const RenderSettings& settings, PostProcessData& data, \n    GBufferData& gbufferData, RenderGraph& renderGraph)\n{\n    // Compositing\n    {\n        Texture& lightAccum = const_cast<Texture&>(data.CompositingPass.GetOutput(\n            Compositing::SHADER_OUT_RES::COMPOSITED));\n        renderGraph.RegisterResource(lightAccum.Resource(), lightAccum.ID());\n\n        fastdelegate::FastDelegate1<CommandList&> dlg = fastdelegate::MakeDelegate(&data.CompositingPass,\n            &Compositing::Render);\n        data.CompositingHandle = renderGraph.RegisterRenderPass(\"Compositing\", \n            RENDER_NODE_TYPE::COMPUTE, dlg);\n    }\n\n    // TAA\n    if (settings.AntiAliasing == AA::TAA)\n    {\n        fastdelegate::FastDelegate1<CommandList&> dlg = fastdelegate::MakeDelegate(&data.TaaPass,\n            &TAA::Render);\n\n        data.TaaHandle = renderGraph.RegisterRenderPass(\"TAA\", RENDER_NODE_TYPE::COMPUTE, dlg);\n\n        Texture& taaA = data.TaaPass.GetOutput(TAA::SHADER_OUT_RES::OUTPUT_A);\n        renderGraph.RegisterResource(taaA.Resource(), taaA.ID());\n\n        Texture& taaB = data.TaaPass.GetOutput(TAA::SHADER_OUT_RES::OUTPUT_B);\n        renderGraph.RegisterResource(taaB.Resource(), taaB.ID());\n    }\n    // FSR2\n    else if (settings.AntiAliasing == AA::FSR2)\n    {\n        fastdelegate::FastDelegate1<CommandList&> dlg = fastdelegate::MakeDelegate(&data.Fsr2Pass,\n            &FSR2Pass::Render);\n\n        data.Fsr2Handle = renderGraph.RegisterRenderPass(\"FSR2\", RENDER_NODE_TYPE::COMPUTE, dlg);\n\n        const Texture& upscaled = data.Fsr2Pass.GetOutput(FSR2Pass::SHADER_OUT_RES::UPSCALED);\n        renderGraph.RegisterResource(const_cast<Texture&>(upscaled).Resource(), upscaled.ID());\n    }\n\n    // Auto Exposure\n    {\n        fastdelegate::FastDelegate1<CommandList&> dlg = fastdelegate::MakeDelegate(\n            &data.AutoExposurePass, &AutoExposure::Render);\n\n        data.AutoExposureHandle = renderGraph.RegisterRenderPass(\"AutoExposure\", \n            RENDER_NODE_TYPE::COMPUTE, dlg);\n\n        Texture& exposureTex = data.AutoExposurePass.GetOutput(AutoExposure::SHADER_OUT_RES::EXPOSURE);\n        renderGraph.RegisterResource(exposureTex.Resource(), exposureTex.ID(), \n            D3D12_RESOURCE_STATE_COMMON, false);\n    }\n\n    // Display\n    {\n        fastdelegate::FastDelegate1<CommandList&> dlg = fastdelegate::MakeDelegate(&data.DisplayPass, \n            &DisplayPass::Render);\n        data.DisplayHandle = renderGraph.RegisterRenderPass(\"DisplayPass\", RENDER_NODE_TYPE::RENDER, dlg);\n\n        // When there's a pending pick in this frame, DisplayPass::Render() will call the delegate\n        // below to clear it later in the same frame\n        if (gbufferData.GBufferPass.HasPendingPick())\n        {\n            auto pickDlg = fastdelegate::MakeDelegate(&gbufferData.GBufferPass, &GBufferRT::ClearPick);\n            auto& readback = gbufferData.GBufferPass.GetPickReadbackBuffer();\n\n            data.DisplayPass.SetPickData(gbufferData.GBufferPassHandle, &readback, pickDlg);\n        }\n    }\n\n    // ImGui\n    {\n        fastdelegate::FastDelegate1<CommandList&> dlg = fastdelegate::MakeDelegate(&data.GuiPass, \n            &GuiPass::Render);\n        data.GuiHandle = renderGraph.RegisterRenderPass(\"GuiPass\", RENDER_NODE_TYPE::RENDER, dlg);\n    }\n\n    // Register backbuffer\n    const Texture& backbuff = App::GetRenderer().GetCurrentBackBuffer();\n    renderGraph.RegisterResource(const_cast<Texture&>(backbuff).Resource(), backbuff.ID());\n\n    // Dummy resource\n    renderGraph.RegisterResource(nullptr, RenderGraph::DUMMY_RES::RES_1);\n}\n\nvoid PostProcessor::AddAdjacencies(const RenderSettings& settings, PostProcessData& data, \n    const GBufferData& gbuffData, const PathTracerData& rtData, RenderGraph& renderGraph)\n{\n    const Texture& composited = data.CompositingPass.GetOutput(\n        Compositing::SHADER_OUT_RES::COMPOSITED);\n    const Texture& exposureTex = data.AutoExposurePass.GetOutput(\n        AutoExposure::SHADER_OUT_RES::EXPOSURE);\n    const bool tlasReady = rtData.RtAS.IsReady();\n    const int outIdx = App::GetRenderer().GlobalIdxForDoubleBufferedResources();\n\n    // Compositing\n    if (tlasReady)\n    {\n        // G-buffers\n        renderGraph.AddInput(data.CompositingHandle,\n            gbuffData.BaseColor[outIdx].ID(),\n            D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n        renderGraph.AddInput(data.CompositingHandle,\n            gbuffData.Normal[outIdx].ID(),\n            D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n        renderGraph.AddInput(data.CompositingHandle,\n            gbuffData.Depth[outIdx].ID(),\n            D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n        renderGraph.AddInput(data.CompositingHandle,\n            gbuffData.MetallicRoughness[outIdx].ID(),\n            D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n        renderGraph.AddInput(data.CompositingHandle,\n            gbuffData.IORBuffer[outIdx].ID(),\n            D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n        renderGraph.AddInput(data.CompositingHandle,\n            gbuffData.CoatBuffer[outIdx].ID(),\n            D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n        if (tlasReady)\n        {\n            // Emissive DI\n            if (App::GetScene().EmissiveLighting())\n            {\n                renderGraph.AddInput(data.CompositingHandle,\n                    rtData.DirecLightingPass.GetOutput(DirectLighting::SHADER_OUT_RES::FINAL).ID(),\n                    D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n            }\n            // Sky DI\n            else\n            {\n                renderGraph.AddInput(data.CompositingHandle,\n                    rtData.SkyDI_Pass.GetOutput(SkyDI::SHADER_OUT_RES::DENOISED).ID(),\n                    D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n            }\n\n            // Indirect lighting\n            renderGraph.AddInput(data.CompositingHandle,\n                rtData.IndirecLightingPass.GetOutput(IndirectLighting::SHADER_OUT_RES::FINAL).ID(),\n                D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n\n            // Inscattering\n            if (settings.Inscattering)\n            {\n                renderGraph.AddInput(data.CompositingHandle,\n                    rtData.SkyPass.GetOutput(Sky::SHADER_OUT_RES::INSCATTERING).ID(),\n                    D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);\n            }\n        }\n    }\n\n    renderGraph.AddOutput(data.CompositingHandle,\n        data.CompositingPass.GetOutput(Compositing::SHADER_OUT_RES::COMPOSITED).ID(),\n        D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n\n    // TAA\n    if (tlasReady)\n    {\n        if (settings.AntiAliasing == AA::TAA)\n        {\n            const TAA::SHADER_OUT_RES taaCurrOutIdx = outIdx == 0 ? TAA::SHADER_OUT_RES::OUTPUT_B : \n                TAA::SHADER_OUT_RES::OUTPUT_A;\n            const TAA::SHADER_OUT_RES taaPrevOutIdx = outIdx == 0 ? TAA::SHADER_OUT_RES::OUTPUT_A : \n                TAA::SHADER_OUT_RES::OUTPUT_B;\n            Texture& taaCurrOut = data.TaaPass.GetOutput(taaCurrOutIdx);\n            Texture& taaPrevOut = data.TaaPass.GetOutput(taaPrevOutIdx);\n\n            renderGraph.AddInput(data.TaaHandle,\n                gbuffData.Depth[outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(data.TaaHandle,\n                composited.ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(data.TaaHandle,\n                taaPrevOut.ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddOutput(data.TaaHandle,\n                taaCurrOut.ID(),\n                D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n\n            // Display\n            renderGraph.AddInput(data.DisplayHandle,\n                taaCurrOut.ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n        }\n        // FSR2\n        else if (settings.AntiAliasing == AA::FSR2)\n        {\n            renderGraph.AddInput(data.Fsr2Handle,\n                gbuffData.Depth[outIdx].ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(data.Fsr2Handle,\n                composited.ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(data.Fsr2Handle,\n                gbuffData.MotionVec.ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            renderGraph.AddInput(data.Fsr2Handle,\n                exposureTex.ID(),\n                D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n            const Texture& upscaled = data.Fsr2Pass.GetOutput(FSR2Pass::SHADER_OUT_RES::UPSCALED);\n            Assert(upscaled.IsInitialized(), \"Upscaled output hasn't been initialized.\");\n\n            renderGraph.AddOutput(data.Fsr2Handle,\n                upscaled.ID(),\n                D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n\n            // Display\n            renderGraph.AddInput(data.DisplayHandle,\n                upscaled.ID(),\n                D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);\n        }\n    }\n\n    // Auto Exposure\n    {\n        renderGraph.AddInput(data.AutoExposureHandle,\n            composited.ID(),\n            D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n        renderGraph.AddOutput(data.AutoExposureHandle,\n            exposureTex.ID(),\n            D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n    }\n\n    // Display\n    if (tlasReady)\n    {\n        renderGraph.AddInput(data.DisplayHandle,\n            gbuffData.Depth[outIdx].ID(),\n            D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n        renderGraph.AddInput(data.DisplayHandle,\n            gbuffData.BaseColor[outIdx].ID(),\n            D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);\n\n        renderGraph.AddInput(data.DisplayHandle,\n            gbuffData.Normal[outIdx].ID(),\n            D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);\n\n        renderGraph.AddInput(data.DisplayHandle,\n            gbuffData.MetallicRoughness[outIdx].ID(),\n            D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);\n\n        renderGraph.AddInput(data.DisplayHandle,\n            gbuffData.CoatBuffer[outIdx].ID(),\n            D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);\n\n        renderGraph.AddInput(data.DisplayHandle,\n            gbuffData.EmissiveColor.ID(),\n            D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);\n    }\n\n    renderGraph.AddInput(data.DisplayHandle,\n        exposureTex.ID(),\n        D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);\n\n    // Backbuffer\n    renderGraph.AddOutput(data.DisplayHandle,\n        App::GetRenderer().GetCurrentBackBuffer().ID(),\n        D3D12_RESOURCE_STATE_RENDER_TARGET);\n\n    // For GUI Pass\n    renderGraph.AddOutput(data.DisplayHandle,\n        RenderGraph::DUMMY_RES::RES_1,\n        D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n\n    // Due to blending, ImGui should go last\n    renderGraph.AddInput(data.GuiHandle,\n        RenderGraph::DUMMY_RES::RES_1,\n        D3D12_RESOURCE_STATE_UNORDERED_ACCESS);\n\n    renderGraph.AddOutput(data.GuiHandle,\n        App::GetRenderer().GetCurrentBackBuffer().ID(),\n        D3D12_RESOURCE_STATE_RENDER_TARGET);\n}\n"
  },
  {
    "path": "Tests/CMakeLists.txt",
    "content": "include(\"${CMAKE_INCLUDE_DIR}/SetupDoctest.cmake\")\n\nSetupDoctest()\n\nset(TEST_DIR ${CMAKE_SOURCE_DIR}/Tests)\nset(TEST_SRC \n    \"${TEST_DIR}/TestContainer.cpp\"\n    \"${TEST_DIR}/TestMath.cpp\"\n    \"${TEST_DIR}/TestAliasTable.cpp\"\n    \"${TEST_DIR}/TestOffsetAllocator.cpp\"\n    \"${TEST_DIR}/TestOptional.cpp\"\n    \"${TEST_DIR}/main.cpp\")\n\nadd_executable(Tests ${TEST_SRC})\ntarget_link_libraries(Tests ZetaCore)\ntarget_include_directories(Tests BEFORE PRIVATE ${ZETA_CORE_DIR})\n# doctest requires exception handling\ntarget_compile_options(Tests PRIVATE /EHsc)\nset_target_properties(Tests PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})\nset_target_properties(Tests PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\n"
  },
  {
    "path": "Tests/TestAliasTable.cpp",
    "content": "#include <Math/Sampling.h>\n#include <Utility/SmallVector.h>\n#include <Utility/RNG.h>\n#include <App/App.h>\n#include <doctest/doctest.h>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Math;\n\nTEST_SUITE(\"AliasTable\")\n{\n    TEST_CASE(\"Normalize\")\n    {\n        float vals[] = { 1.0f, 22.0f, 4.0f, 8.0f, 3.5f, 10.0f };\n        SmallVector<float, Support::SystemAllocator, 6> weights;\n        weights.append_range(vals, vals + sizeof(vals) / sizeof(float));\n\n        AliasTable_Normalize(weights);\n\n        float sum = 0.0f;\n        for (auto e : weights)\n            sum += e;\n\n        INFO(\"Set of values don't form a probability distribution function as they don't integrate to 1.\");\n        CHECK(fabsf(sum - weights.size()) < 1e-7f);\n    }\n\n    TEST_CASE(\"ReturnedPdfMatchesOriginal\")\n    {\n        int unused;\n        RNG rng(reinterpret_cast<uintptr_t>(&unused));\n        INFO(\"RNG seed: \", reinterpret_cast<uintptr_t>(&unused));\n\n        const uint32_t n = 1 + rng.UniformUintBounded(999);\n        SmallVector<float> vals;\n        vals.resize(n);\n\n        for (uint32_t i = 0; i < n; i++)\n        {\n            float f = rng.Uniform() * 100.0f;\n            vals[i] = f;\n        }\n\n        SmallVector<float> valsNormalized = vals;\n        const float sum = Math::KahanSum(vals);\n\n        for (uint32_t i = 0; i < n; i++)\n            valsNormalized[i] /= sum;\n\n        SmallVector<AliasTableEntry> table;\n        table.resize(n);\n        AliasTable_Build(vals, table);\n\n        for (int i = 0; i < 100; i++)\n        {\n            float pdf;\n            uint32_t idx = SampleAliasTable(table, rng, pdf);\n\n            INFO(\"Out-of-bound index\");\n            CHECK(idx < n);\n\n            INFO(\"Density mismatch, got \", pdf, \", expected \", valsNormalized[idx]);\n            CHECK(fabsf(pdf - valsNormalized[idx]) < 1e-7f);\n        }\n    }\n\n    TEST_CASE(\"Density\")\n    {\n        int unused;\n        RNG rng(reinterpret_cast<uintptr_t>(&unused));\n        INFO(\"RNG seed: \", reinterpret_cast<uintptr_t>(&unused));\n\n        // generate some weights\n        const int n = 50;\n        SmallVector<float> vals;\n        vals.resize(n);\n\n        for (int i = 0; i < n; i++)\n            vals[i] = (float)rng.UniformUintBounded(1000);\n\n        // normalize\n        SmallVector<float> valsNormalized = vals;\n        const float sum = Math::KahanSum(vals);\n\n        for (int i = 0; i < n; i++)\n            valsNormalized[i] /= sum;\n\n        SmallVector<AliasTableEntry> table;\n        table.resize(n);\n        AliasTable_Build(vals, table);\n\n        const int sampleSize = 100;\n        SmallVector<size_t> count;\n        count.resize(n, 0);\n\n        // generate some observations\n        for (int i = 0; i < sampleSize; i++)\n        {\n            float pdf;\n            uint32_t idx = SampleAliasTable(table, rng, pdf);\n\n            count[idx]++;\n        }\n\n        // Chi-squared goodness-of-fit test\n        double chiSquared = 0.0;\n        for (size_t i = 0; i < n; ++i) \n        {\n            double expected = valsNormalized[i] * sampleSize;\n            double diff = count[i] - expected;\n            chiSquared += expected == 0 ? 0 : (diff * diff) / expected;\n        }\n\n        // corresponding to alpha = 0.05 and dof = sampleSize - 1 = 99\n        const double criticalValue = 124.34211340400407;\n\n        INFO(\"Test statistic: \", chiSquared, \", critical value: \", criticalValue);\n        CHECK(chiSquared <= criticalValue);\n    }\n};"
  },
  {
    "path": "Tests/TestContainer.cpp",
    "content": "#include <Utility/SmallVector.h>\n#include <Utility/HashTable.h>\n#include <App/App.h>\n#include <Support/MemoryArena.h>\n#include <doctest/doctest.h>\n\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::App;\n\nTEST_SUITE(\"SmallVector\")\n{\n    TEST_CASE(\"Basic\")\n    {\n        MemoryArena ma(32);\n        ArenaAllocator aa(ma);\n\n        SmallVector<int, ArenaAllocator, 3> vec1(aa);\n        CHECK(vec1.has_inline_storage() == true);\n\n        for (int i = 0; i < 3; i++)\n        {\n            vec1.push_back(i);\n            CHECK(vec1.has_inline_storage() == true);\n            CHECK(vec1[i] == i);\n        }\n\n        vec1.push_back(4);\n        CHECK(vec1.has_inline_storage() == false);\n\n        SmallVector<int, SystemAllocator, 5> vec2(12);\n        CHECK(vec2.size() == 5);\n        for(int i = 0; i < 5; i++)\n            CHECK(vec2[i] == 12);\n\n        SmallVector<int, SystemAllocator, 15> vec3;\n        CHECK(vec3.has_inline_storage());\n\n        vec3.reserve(3);\n        CHECK(vec3.has_inline_storage());\n\n        vec3.resize(10);\n        CHECK(vec3.capacity() == 15);\n        vec3.resize(20);\n        CHECK(!vec3.has_inline_storage());\n        CHECK(vec3.capacity() == 20);\n        vec3.resize(3);\n        CHECK(vec3.capacity() == 20);\n    }\n\n    TEST_CASE(\"Move constructor-HeapHeap\")\n    {\n        MemoryArena ma(8);\n        ArenaAllocator aa(ma);\n\n        SmallVector<int, ArenaAllocator> vec1(aa);\n        SmallVector<int, ArenaAllocator> vec2(aa);\n\n        for (int i = 0; i < 4; i++)\n            vec1.push_back(i);\n\n        vec2 = ZetaMove(vec1);\n        CHECK(vec2.has_inline_storage() == false);\n        CHECK(vec1.begin() == nullptr);\n        CHECK(vec1.end() == nullptr);\n        CHECK(vec1.capacity() == 0);\n\n        CHECK(vec1.size() == 0);\n        CHECK(vec2.size() == 4);\n\n        for (int i = 0; i < 4; i++)\n            CHECK(vec2[i] == i);\n    }\n\n    TEST_CASE(\"Move constructor-HeapInline\")\n    {\n        MemoryArena ma(16);\n        ArenaAllocator aa(ma);\n\n        SmallVector<int, ArenaAllocator> vec1(aa);\n        SmallVector<int, ArenaAllocator, 10> vec2(aa);\n        vec2.push_back(10);\n        vec2.push_back(11);\n\n        for (int i = 0; i < 4; i++)\n            vec1.push_back(i);\n\n        vec2 = ZetaMove(vec1);\n        CHECK(vec2.has_inline_storage() == true);\n\n        CHECK(vec1.size() == 0);\n        CHECK(vec2.size() == 4);\n\n        for (int i = 0; i < 4; i++)\n            CHECK(vec2[i] == i);\n    }\n\n    TEST_CASE(\"Move constructor-InlineInline\")\n    {\n        MemoryArena ma(8);\n        ArenaAllocator aa(ma);\n\n        SmallVector<int, ArenaAllocator, 5> vec1(aa);\n        SmallVector<int, ArenaAllocator, 10> vec2(aa);\n\n        for (int i = 0; i < 5; i++)\n            vec1.push_back(i);\n\n        CHECK(vec1.has_inline_storage() == true);\n        vec2 = ZetaMove(vec1);\n        CHECK(vec2.has_inline_storage() == true);\n\n        CHECK(vec1.size() == 0);\n        CHECK(vec2.size() == 5);\n\n        for (int i = 0; i < 5; i++)\n        {\n            CHECK(vec2[i] == i);\n        }\n    }\n\n    TEST_CASE(\"Copy assignment\")\n    {\n        MemoryArena ma(128);\n        ArenaAllocator aa(ma);\n\n        SmallVector<int, ArenaAllocator> vec1(aa);\n        SmallVector<int, ArenaAllocator> vec2(aa);\n\n        for (int i = 0; i < 4; i++)\n            vec1.push_back(i);\n\n        vec2 = vec1;\n        CHECK(vec2.has_inline_storage() == false);\n\n        CHECK(vec1.size() == 4);\n        CHECK(vec2.size() == 4);\n\n        for (int i = 0; i < 4; i++)\n        {\n            CHECK(vec1[i] == i);\n            CHECK(vec2[i] == i);\n        }\n    }\n\n    TEST_CASE(\"Default constructor\")\n    {\n        struct A\n        {\n            A()\n                : m_a(3)\n            {}\n            int m_a;\n        };\n\n        SmallVector<A, SystemAllocator, 5> vec;\n        vec.resize(3);\n\n        for (auto& a : vec)\n            CHECK(a.m_a == 3);\n    }\n\n    TEST_CASE(\"Swap\")\n    {\n        MemoryArena ma(128);\n        ArenaAllocator aa(ma);\n\n        SmallVector<int, ArenaAllocator> vec1(aa);\n        SmallVector<int, ArenaAllocator, 10> vec2(aa);\n\n        for (int i = 0; i < 10; i++)\n            vec2.push_back(i);\n\n        vec1.swap(vec2);\n        CHECK(vec1.size() == 10);\n        CHECK(vec2.size() == 0);\n\n        for (int i = 0; i < 10; i++)\n            CHECK(vec1[i] == i);\n    }\n};\n\nTEST_SUITE(\"HashTable\")\n{\n    TEST_CASE(\"Basic\")\n    {\n        HashTable<int> table(6);\n\n        CHECK(table.empty());\n        CHECK(table.size() == 0);\n        CHECK(table.load_factor() == 0.0f);\n        CHECK(!table.find(1));\n        CHECK(table.bucket_count() == 8);\n\n        CHECK(table.try_emplace(0, 100));\n        CHECK(!table.empty());\n        CHECK(table.try_emplace(1, 101));\n        CHECK(table.try_emplace(2, 102));\n        CHECK(table.try_emplace(3, 103));\n\n        // One more insertion should trigger relocation\n        const auto oldSize = table.size();\n        const auto oldLoad = table.load_factor();\n        CHECK(!table.try_emplace(3, 103));\n        // Since try_emplace() failed, relocation shouldn't have happened\n        const auto newSize = table.size();\n        const auto newLoad = table.load_factor();\n        CHECK(oldSize == newSize);\n        CHECK(oldLoad == newLoad);\n\n        auto entry = table.find(2);\n        CHECK(entry);\n        CHECK(*entry.value() == 102);\n\n        table.insert_or_assign(0, 200);\n        CHECK(newSize == table.size());\n        // Check if insert_or_assign() replaced the old value\n        auto* entry2 = table.find(0).value();\n        CHECK(*entry2 == 200);\n    }\n\n    TEST_CASE(\"Relocation\")\n    {\n        HashTable<int> table(6);\n        CHECK(table.bucket_count() == 8);\n\n        table.try_emplace(0, 100);\n        table[1] = 101;\n        table[2] = 102;\n        table[3] = 103;\n        table[4] = 104;\n        table[5] = 105;\n        table[6] = 106;\n\n        const auto oldLoad = table.load_factor();\n        CHECK(table.size() == 7);\n\n        // Should trigger relocation\n        table[7] = 107;\n        const auto newLoad = table.load_factor();\n        CHECK(newLoad < oldLoad);\n        CHECK(table.size() == 8);\n\n        for (int i = 0; i < 8; i++)\n        {\n            auto* entry = table.find(i).value();\n            CHECK(*entry == 100 + i);\n        }\n    }\n\n    TEST_CASE(\"Clear\")\n    {\n        int destructorCounter = 0;\n\n        struct Temp\n        {\n            Temp() = default;\n            Temp(float unused, int* p)\n                : val(unused),\n                ptr(p)\n            {}\n            ~Temp()\n            {\n                if(ptr)\n                    (*ptr)++;\n            }\n\n            float val;\n            int* ptr = nullptr;\n        };\n\n        {\n            HashTable<Temp> table(8);\n\n            table.try_emplace(0, 1.0f, &destructorCounter);\n            table.try_emplace(1, 2.0f, &destructorCounter);\n            CHECK(table.size() == 2);\n\n            const auto oldBucketCount = table.bucket_count();\n            table.clear();\n            CHECK(destructorCounter == 2);\n            // Repeated clear() calls shouldn't double-destruct\n            table.clear();\n            CHECK(destructorCounter == 2);\n            CHECK(table.size() == 0);\n            CHECK(table.bucket_count() == oldBucketCount);\n        }\n\n        {\n            HashTable<Temp> table(8);\n\n            table.try_emplace(0, 1.0f, &destructorCounter);\n            table.try_emplace(1, 2.0f, &destructorCounter);\n            table.try_emplace(2, 3.0f, &destructorCounter);\n        }\n\n        CHECK(destructorCounter == 5);\n    }\n\n    TEST_CASE(\"Erase\")\n    {\n        HashTable<int> table(6);\n        CHECK(table.bucket_count() == 8);\n\n        // Following keys map to same bucket\n        table[3] = 103;\n        table[3 + 8] = 104;\n        table[3 + 8 * 2] = 105;\n        CHECK(table.size() == 3);\n\n        auto numErased = table.erase(3 + 8);\n        CHECK(numErased == 1);\n        auto entry = table.find(3 + 8);\n        CHECK(!entry);\n\n        // Erase with key that doesn't exist\n        numErased = table.erase(10);\n        CHECK(numErased == 0);\n        numErased = table.erase(10);\n        CHECK(numErased == 0);\n\n        CHECK(table.size() == 2);\n\n        // Probing with tombstones in between\n        auto entry2 = table.find(3 + 8 * 2);\n        CHECK(entry2);\n        CHECK(*entry2.value() == 105);\n\n        // Should reuse the removed entry\n        auto oldLoad = table.load_factor();\n        table[3 + 8 * 3] = 106;\n        auto newLoad = table.load_factor();\n        CHECK(oldLoad == newLoad);\n\n        // Delete all the entries\n        numErased = table.erase(3);\n        CHECK(numErased == 1);\n        numErased = table.erase(3 + 8 * 2);\n        CHECK(numErased == 1);\n        numErased = table.erase(3 + 8 * 3);\n        CHECK(numErased == 1);\n        CHECK(table.size() == 0);\n        CHECK(table.empty());\n\n        table[0] = 100;\n        table[1] = 101;\n        table[2] = 102;\n        table[3] = 103;\n        CHECK(table.size() == 4);\n\n        table.erase(0);\n        table.erase(1);\n        CHECK(table.size() == 2);\n\n        // Insert new entries to force resize\n        oldLoad = table.load_factor();\n        table[6] = 106;\n        table[7] = 107;\n        newLoad = table.load_factor();\n        CHECK(newLoad < oldLoad);\n        // Tombstones shouldn't be carried over to new table\n        CHECK(table.load_factor() == 4.0f / table.bucket_count());\n    }\n\n    TEST_CASE(\"Iteration\")\n    {\n        HashTable<int> table(4);\n        int i = 0;\n\n        for (auto it = table.begin_it(); it < table.end_it(); it = table.next_it(it))\n            i++;\n\n        CHECK(i == 0);\n\n        table.try_emplace(1, 5);\n        table.try_emplace(2, 6);\n        table.try_emplace(3, 7);\n        i = 0;\n\n        for (auto it = table.begin_it(); it < table.end_it(); it = table.next_it(it))\n        {\n            CHECK(it->Val == it->Key + 4);\n            i++;\n        }\n\n        CHECK(i == 3);\n\n        // Iteration should ignore tombstone entries\n        CHECK(table.erase(2) == 1);\n        i = 0;\n\n        for (auto it = table.begin_it(); it < table.end_it(); it = table.next_it(it))\n            i++;\n\n        CHECK(i == 2);\n    }\n};"
  },
  {
    "path": "Tests/TestMath.cpp",
    "content": "#include <Math/CollisionFuncs.h>\n#include <Math/Quaternion.h>\n#include <Math/MatrixFuncs.h>\n#include <Utility/RNG.h>\n#include <Math/Sampling.h>\n#include <doctest/doctest.h>\n#include <DirectXMath.h>\n#include <DirectXCollision.h>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Math;\n\nTEST_CASE(\"3x3 Determinant\")\n{\n    float4x3 M(float3(1, 0, 0),\n        float3(0, -1.19209290e-07f, 0.999999940f),\n        float3(0, -0.999999940f, -1.19209290e-07f),\n        float3(0, 0, 1));\n\n    v_float4x4 vM = load4x3(M);\n    auto det = det3x3(vM);\n    auto d = store(det);\n\n    CHECK(fabsf(d.x - 1.0f) < 1e-6);\n}\n\nTEST_CASE(\"SRT Decomposition\")\n{\n    float3 scaleFactor = float3(1.5f, 2.0f, 1.0f);\n    float3 translation = float3(-2.0f, 0.34f, -5.7f);\n    float theta = 0.610865238f;\n\n    v_float4x4 vS = scale(scaleFactor.x, scaleFactor.y, scaleFactor.z);\n    v_float4x4 vR = rotateZ(theta);\n    v_float4x4 vT = translate(translation);\n    v_float4x4 vSRT = mul(vS, vR);\n    vSRT = mul(vSRT, vT);\n\n    float4a s;\n    float4a r;\n    float4a t;\n    decomposeSRT(vSRT, s, r, t);\n\n    CHECK(fabsf(s.x - 1.5f) < 1e-6f);\n    CHECK(fabsf(s.y - 2.0f) < 1e-6f);\n    CHECK(fabsf(s.z - 1.0f) < 1e-6f);\n\n    float3 axis2;\n    float theta2;\n    quaternionToAxisAngle(r, axis2, theta2);\n\n    CHECK(fabsf(axis2.x - 0) < 1e-6f);\n    CHECK(fabsf(axis2.y - 0) < 1e-6f);\n    CHECK(fabsf(axis2.z - 1) < 1e-6f);\n    CHECK(fabsf(theta2 - theta) < 1e-6f);\n\n    CHECK(fabsf(t.x - translation.x) < 1e-6f);\n    CHECK(fabsf(t.y - translation.y) < 1e-6f);\n    CHECK(fabsf(t.z - translation.z) < 1e-6f);\n}\n\nTEST_CASE(\"TRS Decomposition\")\n{\n    float3 scaleFactor = float3(1.5f, 2.0f, 1.0f);\n    float3 translation = float3(-2.0f, 0.34f, -5.7f);\n    float theta = 0.610865238f;\n\n    v_float4x4 vS = scale(scaleFactor.x, scaleFactor.y, scaleFactor.z);\n    v_float4x4 vR = rotateZ(theta);\n    vR = transpose(vR);\n    v_float4x4 vT = translate(translation);\n    vT = transpose(vT);\n    v_float4x4 vTRS = mul(vT, vR);\n    vTRS = mul(vTRS, vS);\n\n    float3 s;\n    float4 r;\n    float3 t;\n    decomposeTRS(vTRS, s, r, t);\n\n    CHECK(fabsf(s.x - 1.5f) < 1e-6f);\n    CHECK(fabsf(s.y - 2.0f) < 1e-6f);\n    CHECK(fabsf(s.z - 1.0f) < 1e-6f);\n\n    float3 axis2;\n    float theta2;\n    quaternionToAxisAngle(float4a(r), axis2, theta2);\n\n    CHECK(fabsf(axis2.x - 0) < 1e-6f);\n    CHECK(fabsf(axis2.y - 0) < 1e-6f);\n    CHECK(fabsf(axis2.z - 1) < 1e-6f);\n    CHECK(fabsf(theta2 - theta) < 1e-6f);\n\n    CHECK(fabsf(t.x - translation.x) < 1e-6f);\n    CHECK(fabsf(t.y - translation.y) < 1e-6f);\n    CHECK(fabsf(t.z - translation.z) < 1e-6f);\n}\n\nTEST_CASE(\"AABBvsAABB\")\n{\n    int unused;\n    RNG rng(reinterpret_cast<uintptr_t>(&unused));\n\n    for (int i = 0; i < 10000; i++)\n    {\n        float cx = rng.Uniform() * 1000.0f - rng.Uniform() * 1000.0f;\n        float cy = rng.Uniform() * 1000.0f - rng.Uniform() * 1000.0f;\n        float cz = rng.Uniform() * 1000.0f - rng.Uniform() * 1000.0f;\n\n        float ex = 0.1f + rng.Uniform() * 1000.0f;\n        float ey = 0.1f + rng.Uniform() * 1000.0f;\n        float ez = 0.1f + rng.Uniform() * 1000.0f;\n\n        DirectX::XMFLOAT3 xc1 = DirectX::XMFLOAT3(cx, cy, cz);\n        DirectX::XMFLOAT3 xe1 = DirectX::XMFLOAT3(ex, ey, ez);\n        DirectX::BoundingBox xb1(xc1, xe1);\n        float3 c1 = float3(cx, cy, cz);\n        float3 e1 = float3(ex, ey, ez);\n        v_AABB b1(c1, e1);\n\n        cx = rng.Uniform() * 1000.0f - rng.Uniform() * 1000.0f;\n        cy = rng.Uniform() * 1000.0f - rng.Uniform() * 1000.0f;\n        cz = rng.Uniform() * 1000.0f - rng.Uniform() * 1000.0f;\n\n        ex = 0.1f + rng.Uniform() * 1000.0f;\n        ey = 0.1f + rng.Uniform() * 1000.0f;\n        ez = 0.1f + rng.Uniform() * 1000.0f;\n\n        DirectX::XMFLOAT3 xc2 = DirectX::XMFLOAT3(cx, cy, cz);\n        DirectX::XMFLOAT3 xe2 = DirectX::XMFLOAT3(ex, ey, ez);\n        DirectX::BoundingBox xb2(xc2, xe2);\n        float3 c2 = float3(cx, cy, cz);\n        float3 e2 = float3(ex, ey, ez);\n        v_AABB b2(c2, e2);\n\n        auto xr = xb1.Contains(xb2);\n        auto r = intersectAABBvsAABB(b1, b2);\n\n        INFO(\"Center1(\", c1.x, \", \", c1.y, \", \", c1.z, \")\", \"Extents1(\", e1.x, \", \", e1.y, \", \", e1.z, \")\");\n        INFO(\"Center2(\", c2.x, \", \", c2.y, \", \", c2.z, \")\", \"Extents2(\", e2.x, \", \", e2.y, \", \", e2.z, \")\");\n        INFO(\"DirectXMath:BoundingBox: \", xr, \"ZetaRay: \", (int)r);\n        CHECK(xr == (int)r);\n    }\n}\n\nTEST_CASE(\"AABBvsFrustum\")\n{\n    float r = 1920.0f / 1080.0f;\n    float n = 1.0f;\n    float f = 1000.0f;\n    DirectX::XMMATRIX P = DirectX::XMMatrixPerspectiveFovLH(DirectX::XM_PIDIV4, r, n, f);\n    DirectX::BoundingFrustum frustum;\n    DirectX::BoundingFrustum::CreateFromMatrix(frustum, P);\n    ViewFrustum q(DirectX::XM_PIDIV4, r, n, f);\n    v_ViewFrustum vf(q);\n\n    RNG rng(reinterpret_cast<uintptr_t>(&vf));\n    INFO(\"Seed: \", reinterpret_cast<uintptr_t>(&vf));\n\n    for (int i = 0; i < 10000; i++)\n    {\n        float cx = -1000.0f + rng.Uniform() * 1000.0f;\n        float cy = -1000.0f + rng.Uniform() * 1000.0f;\n        float cz = -1000.0f + rng.Uniform() * 1000.0f;\n\n        float ex = 0.1f + rng.Uniform() * 1000.0f;\n        float ey = 0.1f + rng.Uniform() * 1000.0f;\n        float ez = 0.1f + rng.Uniform() * 1000.0f;\n\n        DirectX::XMFLOAT3 xc1 = DirectX::XMFLOAT3(cx, cy, cz);\n        DirectX::XMFLOAT3 xe1 = DirectX::XMFLOAT3(ex, ey, ez);\n        DirectX::BoundingBox xb1(xc1, xe1);\n\n        float3 c1 = float3(cx, cy, cz);\n        float3 e1 = float3(ex, ey, ez);\n        v_AABB b1(c1, e1);\n\n        auto ct = frustum.Contains(xb1);\n        bool xr = (ct == DirectX::INTERSECTS) || (ct == DirectX::CONTAINS);\n\n        auto res = instersectFrustumVsAABB(vf, b1);\n        bool zr = (res == COLLISION_TYPE::CONTAINS) || (res == COLLISION_TYPE::INTERSECTS);\n\n        INFO(\"Center:(\", c1.x, \", \", c1.y, \", \", c1.z, \")\", \"Extents:(\", e1.x, \", \", e1.y, \", \", e1.z, \")\");\n        INFO(\"DirectXMath result: \", xr, \"ZetaRay result: \", zr);\n        CHECK(zr == xr);\n    }\n}\n\nTEST_CASE(\"QuaternionSlerp\")\n{\n    // Note: setting theta=3.14159f causes test results to be different due to the difference\n    // in computation of cos(theta) using CRT's cosf() in rotationQuat() & XMScalarSinCos() in DirectXMath. \n    // See commented lines below\n\n    const int numTests = 10000;\n    RNG rng(reinterpret_cast<uintptr_t>(&numTests));\n    INFO(\"Seed: \", reinterpret_cast<uintptr_t>(&numTests));\n\n    for (int i = 0; i < numTests; i++)\n    {\n        float3 axis1(rng.UniformUintBounded(100) - 50.0f, rng.UniformUintBounded(100) - 50.0f, rng.UniformUintBounded(100) - 50.0f);\n        axis1.normalize();\n        float theta1 = rng.Uniform() * TWO_PI;\n\n        float3 axis2(rng.UniformUintBounded(100) - 50.0f, rng.UniformUintBounded(100) - 50.0f, rng.UniformUintBounded(100) - 50.0f);\n        axis2.normalize();\n        float theta2 = rng.Uniform() * TWO_PI;\n\n        float t = rng.Uniform();\n\n        __m128 vQ1 = rotationQuaternion(axis1, theta1);\n        __m128 vQ2 = rotationQuaternion(axis2, theta2);\n        __m128 vQ3 = slerp(vQ1, vQ2, t);\n        auto q = store(vQ3);\n\n        auto xaxis1 = DirectX::XMVectorSet(axis1.x, axis1.y, axis1.z, 0.0f);\n        //auto Q0 = DirectX::XMQuaternionRotationNormal(xaxis1, theta1);\n        auto Q0 = vQ1;\n        auto xaxis2 = DirectX::XMVectorSet(axis2.x, axis2.y, axis2.z, 0.0f);\n        //auto Q1 = DirectX::XMQuaternionRotationNormal(xaxis2, theta2);\n        auto Q1 = vQ2;\n        auto xq3 = DirectX::XMQuaternionSlerp(Q0, Q1, t);\n        DirectX::XMFLOAT4 ff;\n        DirectX::XMStoreFloat4(&ff, xq3);\n\n        constexpr float EPS = 1e-2f;\n\n        auto q1 = store(vQ1);\n        auto q2 = store(vQ2);\n        auto q3 = store(vQ3);\n\n        DirectX::XMFLOAT4 xQ0;\n        DirectX::XMStoreFloat4(&xQ0, Q0);\n        DirectX::XMFLOAT4 xQ1;\n        DirectX::XMStoreFloat4(&xQ1, Q1);\n\n        INFO(\"axis1:(\", axis1.x, \", \", axis1.y, \", \", axis1.z, \")\");\n        INFO(\"theta1:\", theta1);\n        INFO(\"axis2:(\", axis2.x, \", \", axis2.y, \", \", axis2.z, \")\");\n        INFO(\"theta2:\", theta2);\n        INFO(\"zq1:(\", q1.x, \", \", q1.y, \", \", q1.z, \", \", q1.w);\n        INFO(\"zq2:(\", q2.x, \", \", q2.y, \", \", q2.z, \", \", q2.w);\n        INFO(\"xq1:(\", xQ0.x, \", \", xQ0.y, \", \", xQ0.z, \", \", xQ0.w);\n        INFO(\"xq2:(\", xQ1.x, \", \", xQ1.y, \", \", xQ1.z, \", \", xQ1.w);\n        INFO(\"t:\", t);\n        INFO(\"ZetaRay:(\", q3.x, \", \", q3.y, \", \", q3.z, \", \", q3.w);\n        INFO(\"DirectXMath:(\", ff.x, \", \", ff.y, \", \", ff.z, \", \", ff.w);\n\n        bool isEqual = fabsf(q.x - ff.x) <= EPS &&\n            fabsf(q.y - ff.y) <= EPS &&\n            fabsf(q.z - ff.z) <= EPS &&\n            fabsf(q.w - ff.w) <= EPS;\n\n        CHECK(isEqual == true);\n    }\n}\n\nTEST_CASE(\"RayVsAABB\")\n{\n    int unused;\n    RNG rng(reinterpret_cast<uintptr_t>(&unused));\n    INFO(\"Seed: \", reinterpret_cast<uintptr_t>(&unused));\n\n    auto getc = [&rng]() {return rng.Uniform() * 100.0f - rng.Uniform() * 100.0f; };\n    auto gete = [&rng]() {return 1.0f + rng.Uniform() * 1000.0f; };\n    auto geto = [&rng]() {return rng.Uniform() * 50.0f - rng.Uniform() * 50.0f; };\n    auto getd = [&rng]()\n        {\n            float f = rng.Uniform();\n            bool z = f > 0.1f;\n            float3 res(0.01f + rng.Uniform(), 0.01f + rng.Uniform(), 0.01f + rng.Uniform());\n\n            if (z)\n            {\n                uint32_t c = rng.UniformUint() % 3;\n\n                if (c == 0)\n                    res.x = 0.0f;\n                else if (c == 1)\n                    res.y = 0.0f;\n                else\n                    res.z = 0.0f;\n            }\n\n            return res;\n        };\n\n    const int N = 100'000;\n\n    for (int i = 0; i < N; i++)\n    {\n        float3 Center(getc(), getc(), getc());\n        float3 Extents(gete(), gete(), gete());\n        float3 Origin(geto(), geto(), geto());\n        float3 Dir = getd();\n        Dir.normalize();\n\n        DirectX::BoundingBox xb1(DirectX::XMFLOAT3(Center.x, Center.y, Center.z), DirectX::XMFLOAT3(Extents.x, Extents.y, Extents.z));\n        v_AABB b1(Center, Extents);\n\n        float t;\n        auto resDx = xb1.Intersects(DirectX::XMVectorSet(Origin.x, Origin.y, Origin.z, 1.0f),\n            DirectX::XMVectorSet(Dir.x, Dir.y, Dir.z, 0.0f), t);\n\n        v_Ray vRay(Origin, Dir);\n        auto resZeta = intersectRayVsAABB(vRay, b1, t);\n\n        INFO(\"Center:(\", Center.x, \", \", Center.y, \", \", Center.z, \")\", \", Extents:(\", Extents.x, \", \", Extents.y, \", \", Extents.z, \")\");\n        INFO(\"Origin:(\", Origin.x, \", \", Origin.y, \", \", Origin.z, \")\", \", Dir:(\", Dir.x, \", \", Dir.y, \", \", Dir.z, \")\");\n        INFO(\"DirecXMath: \", resDx, \", ZetaRay: \", resZeta);\n\n        CHECK(resDx == resZeta);\n    }\n}\n\nTEST_CASE(\"MergingAABBs\")\n{\n    v_AABB vBox1;\n    vBox1.vCenter = _mm_setr_ps(-100.0f, -50.0f, -85.0f, 0.0f);\n    vBox1.vExtents = _mm_setr_ps(10.0f, 5.0f, 14.0f, 0.0f);\n\n    v_AABB vBox2 = v_AABB::Init();\n    v_AABB vMergedBox = unionAABB(vBox1, vBox2);\n    AABB box = store(vMergedBox);\n    AABB box2 = store(vBox1);\n\n    INFO(\"Merging any AABB with a default-initialized AABB should result in the former.\");\n    bool centerEq = fabsf(box.Center.x - box2.Center.x) < 1e-6 &&\n        fabsf(box.Center.y - box2.Center.y) < 1e-6 &&\n        fabsf(box.Center.z - box2.Center.z) < 1e-6;\n    bool extEq = fabsf(box.Extents.x - box2.Extents.x) < 1e-6 &&\n        fabsf(box.Extents.y - box2.Extents.y) < 1e-6 &&\n        fabsf(box.Extents.z - box2.Extents.z) < 1e-6;\n\n    CHECK(centerEq == true);\n    CHECK(extEq == true);\n}\n\nTEST_CASE(\"LookAt\")\n{\n    float4a camPos(-10.0f, 5.0f, -3.0f, 1.0f);\n    float4a focus(0.0f, 0.0f, 0.0f, 1.0f);\n    float4a up(0.0f, 1.0f, 0.0f, 0.0f);\n\n    auto viewMat = lookAtLH(camPos, focus, up);\n    auto resZ = store(viewMat);\n\n    DirectX::XMVECTOR eye = DirectX::XMVectorSet(camPos.x, camPos.y, camPos.z, camPos.w);\n    DirectX::XMVECTOR f = DirectX::XMVectorSet(focus.x, focus.y, focus.z, focus.w);\n    DirectX::XMVECTOR u = DirectX::XMVectorSet(up.x, up.y, up.z, up.w);\n\n    auto viewX = DirectX::XMMatrixLookAtLH(eye, f, u);\n\n    DirectX::XMFLOAT4X4 res;\n    DirectX::XMStoreFloat4x4(&res, viewX);\n\n    for (int i = 0; i < 4; i++)\n    {\n        for (int j = 0; j < 4; j++)\n        {\n            CHECK(res.m[i][j] - reinterpret_cast<float*>(&resZ.m[i])[j] <= FLT_EPSILON);\n        }\n    }\n}\n\nTEST_CASE(\"PerspectiveMat\")\n{\n    int w = 991;\n    int h = 561;\n    float r = (float)w / h;\n    float nearZ = 0.1f;\n    float farZ = 1000.0f;\n    float fov = Math::DegreesToRadians(85.0f);\n\n    v_float4x4 vP = perspective(r, fov, nearZ, farZ);\n    auto resZ = store(vP);\n\n    auto projX = DirectX::XMMatrixPerspectiveFovLH(fov, r, nearZ, farZ);\n\n    DirectX::XMFLOAT4X4 res;\n    DirectX::XMStoreFloat4x4(&res, projX);\n\n    for (int i = 0; i < 4; i++)\n    {\n        for (int j = 0; j < 4; j++)\n        {\n            CHECK(res.m[i][j] - reinterpret_cast<float*>(&resZ.m[i])[j] <= FLT_EPSILON);\n        }\n    }\n}\n\nTEST_CASE(\"RotationMatFromQuaternion\")\n{\n    __m128 vQs[4];\n\n    vQs[0] = _mm_setr_ps(-0.5614617466926575f,\n        -0.4267434775829315f,\n        0.3989279866218567f,\n        0.586094856262207f);\n\n    vQs[1] = _mm_setr_ps(-0.703005313873291f,\n        -0.1396184116601944f,\n        0.13859958946704865f,\n        0.6834328770637512f);\n\n    vQs[2] = _mm_setr_ps(-0.6417776942253113f,\n        -0.3504522740840912f,\n        0.3484876751899719f,\n        0.5863965749740601f);\n\n    vQs[3] = _mm_setr_ps(-0.7071068286895752f,\n        0.0f,\n        0.0f,\n        0.7071067094802856f);\n\n    for (int i = 0; i < 4; i++)\n    {\n        v_float4x4 vR = rotationMatFromQuat(vQs[i]);\n        auto resZ = store(vR);\n\n        auto quatX = DirectX::XMMatrixRotationQuaternion(vQs[i]);\n\n        DirectX::XMFLOAT4X4 res;\n        DirectX::XMStoreFloat4x4(&res, quatX);\n\n        for (int k = 0; k < 4; k++)\n        {\n            for (int j = 0; j < 4; j++)\n            {\n                CHECK(res.m[k][j] - reinterpret_cast<float*>(&resZ.m[k])[j] <= FLT_EPSILON);\n            }\n        }\n\n        /*\n        DirectX::XMVECTOR axis;\n        float angle;\n        DirectX::XMQuaternionToAxisAngle(&axis, &angle, vQs[i]);\n\n        auto qq = quatToAxisAngle(vQs[i]);\n\n        for (int i = 0; i < 4; i++)\n        {\n            for (int j = 0; j < 4; j++)\n            {\n                CHECK(res.m[i][j] - reinterpret_cast<float*>(&resZ.m[i])[j] <= FLT_EPSILON);\n            }\n        }\n        */\n    }\n}\n\nTEST_CASE(\"QuaternionFromRotationMat\")\n{\n    float4a axis(1, 2, 3, 0);\n    __m128 vAxis = _mm_load_ps(reinterpret_cast<float*>(&axis));\n    vAxis = normalize(vAxis);\n\n    v_float4x4 vR = rotate(vAxis, PI / 6);\n    float4 result = quaternionFromRotationMat1(vR);\n\n    CHECK(fabsf(result.x - 0.0691723f) <= FLT_EPSILON);\n    CHECK(fabsf(result.y - 0.1383446f) <= FLT_EPSILON);\n    CHECK(fabsf(result.z - 0.2075168f) <= FLT_EPSILON);\n    CHECK(fabsf(result.w - 0.9659258f) <= FLT_EPSILON);\n}\n\n/*\nTEST_CASE(\"PlaneTransformation\")\n{\n    auto r0 = float4(-0.979171753f, 0.0f, 0.2030335f, 0.0f);\n    auto r1 = float4(-0.034616f, 0.98535f, -0.16694f, 0.0f);\n    auto r2 = float4(-0.20f, -0.17049f, -0.96483f, 0.0f);\n    auto r3 = float4(-1.98634f, 8.5402f, 0.14189f, 1.0f);\n\n    float4x4a(r0, r1, r2, r3);\n\n\n\n    DirectX::XMPlaneTransform()\n}\n*/\n\nTEST_CASE(\"Octahedral Encoding\")\n{\n    int unused;\n    RNG rng(reinterpret_cast<uintptr_t>(&unused));\n    INFO(\"RNG seed: \", reinterpret_cast<uintptr_t>(&unused));\n\n    constexpr int N = 1000;\n\n    for (int i = 0; i < N; i++)\n    {\n        float2 u = float2(rng.Uniform(), rng.Uniform());\n        float3 n = UniformSampleSphere(u);\n\n        __m128 vN = loadFloat3(n);\n        __m128 e = encode_octahedral(vN);\n        __m128 d = decode_octahedral(e);\n        float3 decoded = storeFloat3(d);\n\n        float3 diff = decoded - n;\n        float l2 = diff.dot(diff);\n        float mse = sqrtf(l2) / 3.0f;\n\n        CHECK(mse <= 1e-6f);\n    }\n}"
  },
  {
    "path": "Tests/TestOffsetAllocator.cpp",
    "content": "#include <Support/OffsetAllocator.h>\n#include <doctest/doctest.h>\n\nusing namespace ZetaRay::Support;\n\n// Ref: https://github.com/sebbbi/OffsetAllocator/blob/main/offsetAllocatorTests.cpp\nTEST_SUITE(\"OffsetAllocator\")\n{\n    TEST_CASE(\"MaxNumAllocs\")\n    {\n        OffsetAllocator allocator(128, 2);\n\n        auto a = allocator.Allocate(31);\n        CHECK(!a.IsEmpty());\n\n        auto b = allocator.Allocate(23);\n        CHECK(!b.IsEmpty());\n\n        auto c = allocator.Allocate(19);\n        CHECK(c.IsEmpty());\n    }\n\n    TEST_CASE(\"Alignment\")\n    {\n        OffsetAllocator allocator(1024, 16);\n\n        auto a = allocator.Allocate(7);\n        CHECK(a.Offset == 0);\n\n        auto b = allocator.Allocate(10);\n        CHECK(b.Offset == 7);\n        auto c = allocator.Allocate(12);\n        CHECK(c.Offset == 17);\n\n        allocator.Free(b);\n\n        auto d = allocator.Allocate(1, 256);\n        // shouldn't reuse \"B\" even though the size fits\n        CHECK(d.Offset != 7);\n        CHECK((d.Offset & 255) == 0);\n\n        // should reuse \"B\"\n        auto e = allocator.Allocate(1);\n        CHECK(e.Offset == 7);\n    }\n\n    TEST_CASE(\"FreeStorage\")\n    {\n        OffsetAllocator allocator(1024, 16);\n\n        auto a = allocator.Allocate(88);\n        auto b = allocator.Allocate(91);\n\n        allocator.Free(a);\n        CHECK(allocator.FreeStorage() == 1024 - 91);\n\n        auto c = allocator.Allocate(85);\n        CHECK(allocator.FreeStorage() == 1024 - 91 - 85);\n    }\n\n    TEST_CASE(\"Free\")\n    {\n        OffsetAllocator allocator(1024, 16);\n\n        // Free merges neighbor empty nodes. Next allocation should also have offset = 0\n        auto a = allocator.Allocate(137);\n        CHECK(a.Offset == 0);\n        allocator.Free(a);\n\n        auto b = allocator.Allocate(137);\n        CHECK(b.Offset == 0);\n        allocator.Free(b);\n\n        // End: Validate that allocator has no fragmentation left. Should be 100% clean.\n        auto validateAll = allocator.Allocate(1024);\n        CHECK(validateAll.Offset == 0);\n        allocator.Free(validateAll);\n    }\n\n    TEST_CASE(\"Merge\")\n    {\n        OffsetAllocator allocator(1024, 16);\n\n        // Free merges neighbor empty nodes. Next allocation should also have offset = 0\n        auto a = allocator.Allocate(1);\n        REQUIRE(a.Offset == 0);\n\n        auto b = allocator.Allocate(123);\n        REQUIRE(b.Offset == 1);\n\n        auto c = allocator.Allocate(12);\n        REQUIRE(c.Offset == 124);\n\n        auto d = allocator.Allocate(29);\n        REQUIRE(d.Offset == 136);\n\n        allocator.Free(a);\n        allocator.Free(c);\n        allocator.Free(b);\n        allocator.Free(d);\n\n        // End: Validate that allocator has no fragmentation left. Should be 100% clean.\n        auto validateAll = allocator.Allocate(1024);\n        CHECK(validateAll.Offset == 0);\n        allocator.Free(validateAll);\n    }\n\n    TEST_CASE(\"Reuse (trivial)\")\n    {\n        OffsetAllocator allocator(1024, 16);\n\n        // Allocator should reuse node freed by A since the allocation C fits in the same bin\n        auto a = allocator.Allocate(128);\n        CHECK(a.Offset == 0);\n\n        auto b = allocator.Allocate(345);\n        CHECK(b.Offset == 128);\n\n        allocator.Free(a);\n\n        auto c = allocator.Allocate(128);\n        CHECK(c.Offset == 0);\n\n        allocator.Free(c);\n        allocator.Free(b);\n\n        // End: Validate that allocator has no fragmentation left. Should be 100% clean.\n        auto validateAll = allocator.Allocate(1024);\n        CHECK(validateAll.Offset == 0);\n        allocator.Free(validateAll);\n    }\n\n    TEST_CASE(\"Reuse (complex)\")\n    {\n        OffsetAllocator allocator(1024, 16);\n\n        // Allocator should not reuse node freed by A since the allocation C doesn't fit in the same bin\n        // However node D and E fit there and should reuse node from A\n        auto a = allocator.Allocate(128);\n        CHECK(a.Offset == 0);\n\n        auto b = allocator.Allocate(345);\n        CHECK(b.Offset == 128);\n\n        allocator.Free(a);\n\n        auto c = allocator.Allocate(234);\n        CHECK(c.Offset == 128 + 345);\n\n        // should reuse \"A\" (smallest free node such that node.size >= request), which is\n        // then broken up to 45 and (128 - 45) blocks\n        auto d = allocator.Allocate(45);\n        CHECK(d.Offset == 0);\n\n        auto e = allocator.Allocate(51);\n        CHECK(e.Offset == 45);\n\n        auto report = allocator.GetStorageReport();\n        CHECK(report.TotalFreeSpace == 1024 - 345 - 234 - 45 - 51);\n        CHECK(report.LargestFreeRegion != report.TotalFreeSpace);\n\n        allocator.Free(c);\n        allocator.Free(d);\n        allocator.Free(b);\n        allocator.Free(e);\n\n        // End: Validate that allocator has no fragmentation left. Should be 100% clean.\n        auto validateAll = allocator.Allocate(1024);\n        CHECK(validateAll.Offset == 0);\n        allocator.Free(validateAll);\n    }\n\n    TEST_CASE(\"Fragmentation\")\n    {\n        OffsetAllocator allocator(256 * 1024, 1024);\n\n        // Allocate 256 x 1kb. Should fit. Then free four random slots and reallocate four slots.\n        // Plus free four contiguous slots an allocate 4x larger slot. All must be zero fragmentation!\n        OffsetAllocator::Allocation allocations[256];\n\n        for (int i = 0; i < 256; i++)\n        {\n            allocations[i] = allocator.Allocate(1024);\n            CHECK(allocations[i].Offset == i * 1024);\n        }\n\n        auto report = allocator.GetStorageReport();\n        CHECK(report.TotalFreeSpace == 0);\n        CHECK(report.LargestFreeRegion == 0);\n\n        // Free four random slots\n        allocator.Free(allocations[243]);\n        allocator.Free(allocations[5]);\n        allocator.Free(allocations[123]);\n        allocator.Free(allocations[95]);\n\n        // Free four contiguous slots (allocator must merge)\n        allocator.Free(allocations[151]);\n        allocator.Free(allocations[152]);\n        allocator.Free(allocations[153]);\n        allocator.Free(allocations[154]);\n\n        allocations[243] = allocator.Allocate(1024);\n        allocations[5] = allocator.Allocate(1024);\n        allocations[123] = allocator.Allocate(1024);\n        allocations[95] = allocator.Allocate(1024);\n        allocations[151] = allocator.Allocate(1024 * 4); // 4x larger\n        CHECK(!allocations[243].IsEmpty());\n        CHECK(!allocations[5].IsEmpty());\n        CHECK(!allocations[123].IsEmpty());\n        CHECK(!allocations[95].IsEmpty());\n        CHECK(!allocations[151].IsEmpty());\n\n        for (int i = 0; i < 256; i++)\n        {\n            if (i < 152 || i > 154)\n                allocator.Free(allocations[i]);\n        }\n\n        auto report2 = allocator.GetStorageReport();\n        CHECK(report2.TotalFreeSpace == 1024 * 256);\n        CHECK(report2.LargestFreeRegion == 1024 * 256);\n\n        // End: Validate that allocator has no fragmentation left. Should be 100% clean.\n        auto validateAll = allocator.Allocate(256 * 1024);\n        CHECK(validateAll.Offset == 0);\n        allocator.Free(validateAll);\n    }\n};"
  },
  {
    "path": "Tests/TestOptional.cpp",
    "content": "#include <Utility/Optional.h>\n#include <App/App.h>\n#include <doctest/doctest.h>\n\n#include <optional>\n\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::App;\n\nstruct NonTrivial\n{\n    NonTrivial()\n        : val(0)\n    {}\n    NonTrivial(int v)\n        : val(v)\n    {}\n    ~NonTrivial()\n    {\n        val = -1;\n    }\n    NonTrivial(const NonTrivial& other)\n        : val(other.val)\n    {}\n    NonTrivial& operator=(NonTrivial&& other)\n    {\n        val = other.val;\n        other.val = -1;\n\n        return *this;\n    }\n\n    int val;\n};\n\nTEST_SUITE(\"Optional\")\n{\n    TEST_CASE(\"Basic\")\n    {\n        Optional<NonTrivial> a;\n        CHECK(!a);\n\n        a = 5;\n        CHECK(a);\n        CHECK(a.value().val == 5);\n\n        Optional<NonTrivial> b = NonTrivial();\n        CHECK(b.value().val == 0);\n    }\n\n    TEST_CASE(\"Copy constructor/assignment\")\n    {\n        Optional<NonTrivial> a(13);\n        Optional<NonTrivial> b(27);\n\n        a = b;\n        CHECK(a.value().val == 27);\n        CHECK(b.value().val == 27);\n\n        Optional<NonTrivial> c(a);\n        CHECK(c.value().val == 27);\n    }\n\n    TEST_CASE(\"Move constructor/assignment\")\n    {\n        Optional<NonTrivial> a(13);\n        Optional<NonTrivial> b(27);\n\n        a = ZetaMove(b);\n        CHECK(a.value().val == 27);\n        CHECK(!b);\n\n        Optional<NonTrivial> c(ZetaMove(a));\n        CHECK(c.value().val == 27);\n        CHECK(!a);\n\n        Optional<NonTrivial> o2;\n\n        {\n            NonTrivial a1(54);\n            o2 = ZetaMove(a1);\n        }\n\n        CHECK(o2.value().val == 54);\n    }\n\n    TEST_CASE(\"Reset\")\n    {\n        Optional<NonTrivial> o1(NonTrivial(13));\n        CHECK(o1.value().val == 13);\n\n        o1.reset();\n        CHECK(!o1);\n    }\n\n    TEST_CASE(\"Null pointer\")\n    {\n        int a = 45;\n\n        Optional<int*> o1(&a);\n        CHECK(o1);\n\n        o1 = nullptr;\n        CHECK(!o1);\n\n        Optional<int*> o2(nullptr);\n        CHECK(!o2);\n\n        Optional<int*> o3(&a);\n        CHECK(o3);\n        o3 = ZetaMove(o2);\n        CHECK(!o3);\n    }\n};"
  },
  {
    "path": "Tests/main.cpp",
    "content": "#include <App/ZetaRay.h>\n\n#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN\n#include <doctest/doctest.h>"
  },
  {
    "path": "Tools/BCnCompressglTF/BCnCompressglTF.cpp",
    "content": "#include <App/Path.h>\n#include <App/Common.h>\n#include <Support/MemoryArena.h>\n#include <algorithm>\n#include <Utility/Utility.h>\n#include \"TexConv/texconv.h\"\n\n#define STB_IMAGE_IMPLEMENTATION\n#include <stb/stb_image.h>\n\n#define CGLTF_IMPLEMENTATION\n#define CGLTF_WRITE_IMPLEMENTATION\n#include <cgltf/cgltf_write.h>\n\n#include <wrl/client.h>\nusing Microsoft::WRL::ComPtr;\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::App;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Math;\n\nnamespace\n{\n    using ArenaPath = Filesystem::FilePath<ArenaAllocator, 256>;\n    using ArenaPathNoInline = Filesystem::FilePath<ArenaAllocator, 0>;\n\n    static constexpr int DEFAULT_MAX_TEX_RES = 4096;\n    static constexpr const char* COMPRESSED_DIR_NAME = \"compressed\";\n\n    namespace TEX_CONV_ARGV_NO_OVERWRITE_SRGB\n    {\n        static const char* CMD = \" -w %d -h %d -m 0 -ft dds -f %s -srgb -nologo -o %s %s\";\n        constexpr int NUM_ARGS = 16;\n    };\n\n    namespace TEX_CONV_ARGV_OVERWRITE_SRGB\n    {\n        static const char* CMD = \" -w %d -h %d -m 0 -ft dds -f %s -srgb -nologo -y -o %s %s\";\n        constexpr int NUM_ARGS = 17;\n    }\n\n    namespace TEX_CONV_ARGV_NO_OVERWRITE\n    {\n        static const char* CMD = \" -w %d -h %d -m 0 -ft dds -f %s -nologo -o %s %s\";\n        constexpr int NUM_ARGS = 15;\n    }\n\n    namespace TEX_CONV_ARGV_OVERWRITE\n    {\n        static const char* CMD = \" -w %d -h %d -m 0 -ft dds -f %s -nologo -y -o %s %s\";\n        constexpr int NUM_ARGS = 16;\n    }\n\n    namespace TEX_CONV_ARGV_NO_OVERWRITE_SWIZZLE\n    {\n        static const char* CMD = \" -w %d -h %d -m 0 -ft dds -f %s -nologo -swizzle bg -o %s %s\";\n        constexpr int NUM_ARGS = 17;\n    }\n\n    namespace TEX_CONV_ARGV_OVERWRITE_SWIZZLE\n    {\n        static const char* CMD = \" -w %d -h %d -m 0 -ft dds -f %s -nologo -swizzle bg -y -o %s %s\";\n        constexpr int NUM_ARGS = 18;\n    }\n\n    static constexpr int MAX_NUM_ARGS = Max(\n        Max(TEX_CONV_ARGV_NO_OVERWRITE_SRGB::NUM_ARGS, TEX_CONV_ARGV_OVERWRITE_SRGB::NUM_ARGS),\n        Max(Max(TEX_CONV_ARGV_NO_OVERWRITE::NUM_ARGS, TEX_CONV_ARGV_OVERWRITE::NUM_ARGS),\n            Max(TEX_CONV_ARGV_NO_OVERWRITE_SWIZZLE::NUM_ARGS, TEX_CONV_ARGV_OVERWRITE_SWIZZLE::NUM_ARGS)));\n\n    enum TEXTURE_TYPE\n    {\n        BASE_COLOR,\n        NORMAL_MAP,\n        METALNESS_ROUGHNESS,\n        EMISSIVE\n    };\n\n    const char* GetTexFormat(TEXTURE_TYPE t)\n    {\n        switch (t)\n        {\n        case BASE_COLOR:\n            return \"BC7_UNORM_SRGB\";\n        case NORMAL_MAP:\n            return \"BC5_UNORM\";\n        case METALNESS_ROUGHNESS:\n            return \"BC5_UNORM\";\n        case EMISSIVE:\n            return \"BC7_UNORM_SRGB\";\n        default:\n            Check(false, \"unreachable case.\");\n            return \"\";\n        }\n    }\n\n    ZetaInline void DecodeURI_Inplace(ArenaPathNoInline& str, MemoryArena& arena)\n    {\n        auto hexToDecimal = [](unsigned char c)\n            {\n                if (c >= 48 && c <= 57)\n                    return c - 48;\n                if (c >= 65 && c <= 70)\n                    return c - 65 + 10;\n                if (c >= 97 && c <= 102)\n                    return c - 97 + 10;\n\n                return -1;\n            };\n\n        const int N = (int)str.Length();\n        const unsigned char* beg = reinterpret_cast<const unsigned char*>(str.Get());\n        bool needsConversion = false;\n\n        for (int i = 0; i < N; i++)\n        {\n            if (beg[i] == '%')\n            {\n                needsConversion = true;\n                break;\n            }\n        }\n\n        if (!needsConversion)\n            return;\n\n        ArenaPath converted(arena);\n        converted.Resize(str.Length());\n        int curr = 0;\n        unsigned char* out = reinterpret_cast<unsigned char*>(converted.Get());\n\n        while (curr < N)\n        {\n            unsigned char c = *(beg + curr);\n\n            if (c == '%')\n            {\n                int d1 = hexToDecimal(*(beg + curr + 1));\n                Check(d1 != -1, \"Unrecognized percent-encoding.\");\n                int d2 = hexToDecimal(*(beg + curr + 2));\n                Check(d2 != -1, \"Unrecognized percent-encoding.\");\n\n                unsigned char newC = (unsigned char)((d1 << 4) + d2);\n                *(out++) = newC;\n                curr += 3;\n\n                continue;\n            }\n\n            *(out++) = c;\n            curr++;\n        }\n\n        str.Reset(converted.GetView());\n    }\n\n    ZetaInline bool IsASCII(const ArenaPathNoInline& path)\n    {\n        auto view = path.GetView();\n\n        for (size_t i = 0; i < path.Length(); i++)\n        {\n            if (view[i] < 0)\n                return false;\n        }\n\n        return true;\n    }\n\n    void DecodeImageURIs(const ArenaPath& gltfPath, cgltf_data& model, MemoryArena& arena, \n        bool validate)\n    {\n        for (size_t i = 0; i < model.images_count; i++)\n        {\n            const cgltf_image& image = model.images[i];\n            Check(image.uri, \"Image has no URI.\");\n\n            ArenaPathNoInline imgPath(image.uri, arena);\n            if (validate)\n                Check(IsASCII(imgPath), \"Paths with non-ASCII characters are not supported.\");\n\n            DecodeURI_Inplace(imgPath, arena);\n\n            // Modify to decoded path\n            Assert(!imgPath.HasInlineStorage(), \"Bug\");\n            model.images[i].uri = imgPath.Get();\n        }\n    }\n\n    void CreateDevice(ID3D11Device** pDevice)\n    {\n        Assert(pDevice, \"invalid arg.\");\n        *pDevice = nullptr;\n\n        const D3D_FEATURE_LEVEL featureLevels[] =\n        {\n            D3D_FEATURE_LEVEL_11_0,\n        };\n\n        ComPtr<IDXGIFactory1> dxgiFactory;\n        HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(dxgiFactory.GetAddressOf()));\n        Check(SUCCEEDED(hr), \"CreateDXGIFactory1() failed with code: %d\", hr);\n\n        ComPtr<IDXGIAdapter> pAdapter;\n        if (FAILED(dxgiFactory->EnumAdapters(0, pAdapter.GetAddressOf())))\n            Check(false, \"ERROR: Invalid GPU adapter index 0!\\n\");\n\n        hr = D3D11CreateDevice(pAdapter.Get(), D3D_DRIVER_TYPE_UNKNOWN,\n            nullptr, 0, featureLevels, 1,\n            D3D11_SDK_VERSION, pDevice, nullptr, nullptr);\n\n        Check(SUCCEEDED(hr), \"D3D11CreateDevice() failed with code: %d\", hr);\n\n        ComPtr<IDXGIDevice> dxgiDevice;\n        hr = (*pDevice)->QueryInterface(IID_PPV_ARGS(dxgiDevice.GetAddressOf()));\n        if (SUCCEEDED(hr))\n        {\n            hr = dxgiDevice->GetAdapter(pAdapter.ReleaseAndGetAddressOf());\n            if (SUCCEEDED(hr))\n            {\n                DXGI_ADAPTER_DESC desc;\n                hr = pAdapter->GetDesc(&desc);\n                if (SUCCEEDED(hr))\n                    wprintf(L\"\\n[Using DirectCompute on \\\"%ls\\\"]\\n\", desc.Description);\n            }\n        }\n    }\n\n    bool ConvertTextures(TEXTURE_TYPE texType, const ArenaPath& glTFPath, \n        const ArenaPath& compressedDir, const char* compressedDirName,\n        cgltf_data& model, Span<int> textureMaps, MemoryArena& arena, ID3D11Device* device, \n        bool srgb, bool forceOverwrite, int maxRes, Span<int> toSkip)\n    {\n        const char* formatStr = srgb ?\n            (forceOverwrite ? TEX_CONV_ARGV_OVERWRITE_SRGB::CMD : TEX_CONV_ARGV_NO_OVERWRITE_SRGB::CMD) :\n            (texType == METALNESS_ROUGHNESS ?\n                (forceOverwrite ? TEX_CONV_ARGV_OVERWRITE_SWIZZLE::CMD : TEX_CONV_ARGV_NO_OVERWRITE_SWIZZLE::CMD) :\n                (forceOverwrite ? TEX_CONV_ARGV_OVERWRITE::CMD : TEX_CONV_ARGV_NO_OVERWRITE::CMD));\n\n        const int numArgs = srgb ?\n            (forceOverwrite ? TEX_CONV_ARGV_OVERWRITE_SRGB::NUM_ARGS : TEX_CONV_ARGV_NO_OVERWRITE_SRGB::NUM_ARGS) :\n            (texType == METALNESS_ROUGHNESS ?\n                (forceOverwrite ? TEX_CONV_ARGV_OVERWRITE_SWIZZLE::NUM_ARGS : TEX_CONV_ARGV_NO_OVERWRITE_SWIZZLE::NUM_ARGS) :\n                (forceOverwrite ? TEX_CONV_ARGV_OVERWRITE::NUM_ARGS : TEX_CONV_ARGV_NO_OVERWRITE::NUM_ARGS));\n\n        const char* texFormat = GetTexFormat(texType);\n\n        for (auto tex : textureMaps)\n        {\n            auto idx = BinarySearch(toSkip, tex);\n            if (idx != -1)\n                continue;\n\n            ArenaPath uriPath(model.images[tex].uri, arena);\n\n            // URI paths are relative to gltf file\n            SmallVector<char, ArenaAllocator, 256> filename(arena);\n\n            // resize for worst case\n            filename.resize(uriPath.Length() + 5);\n\n            // extract image file name\n            size_t fnLen;\n            uriPath.Stem(filename, &fnLen);\n\n            // change extension to dds\n            filename[fnLen] = '.';\n            filename[fnLen + 1] = 'd';\n            filename[fnLen + 2] = 'd';\n            filename[fnLen + 3] = 's';\n            filename[fnLen + 4] = '\\0';\n\n            ArenaPath ddsPath(compressedDir.GetView(), arena);\n            ddsPath.Append(filename.data());\n\n            if (forceOverwrite || !Filesystem::Exists(ddsPath.Get()))\n            {\n                Filesystem::Path imgPath(glTFPath.GetView());\n                imgPath.Directory();\n                imgPath.Append(model.images[tex].uri);\n\n                // DirectXTex expects backslashes\n                imgPath.ConvertToBackslashes();\n\n                int x;\n                int y;\n                int comp;\n                Check(stbi_info(imgPath.Get(), &x, &y, &comp), \"stbi_info() for path %s failed: %s\",\n                    imgPath.Get(), stbi_failure_reason());\n\n                int w = Min(x, maxRes);\n                int h = Min(y, maxRes);\n\n                // Direct3D requires BC image to be multiple of 4 in width & height\n                w = (int)AlignUp(w, 4);\n                h = (int)AlignUp(h, 4);\n\n                // Returns length without the null terminatir\n                const int len = stbsp_snprintf(nullptr, 0, formatStr, w, h, texFormat,\n                    compressedDir.GetView().data(), imgPath.Get());\n                // Now allocate a buffer large enough for the whole string plus\n                // null terminator\n                char* buffer = reinterpret_cast<char*>(arena.AllocateAligned(len + 1, 1));\n                stbsp_snprintf(buffer, len + 1, formatStr, w, h, texFormat,\n                    compressedDir.GetView().data(), imgPath.Get());\n\n                int wideStrLen = Common::CharToWideStrLen(buffer);\n                wchar_t* wideBuffer = reinterpret_cast<wchar_t*>(arena.AllocateAligned(wideStrLen));\n                Common::CharToWideStr(buffer, MutableSpan(wideBuffer, wideStrLen));\n\n                wchar_t* ptr = wideBuffer;\n                wchar_t* args[MAX_NUM_ARGS];\n                int currArg = 0;\n\n                while (ptr != wideBuffer + wideStrLen)\n                {\n                    args[currArg] = ptr;\n\n                    // spaces are valid for last argument (file path)\n                    while ((currArg == numArgs - 1 || *ptr != ' ') && *ptr != '\\0')\n                        ptr++;\n\n                    *ptr++ = '\\0';\n                    currArg++;\n                }\n\n                auto success = TexConv(numArgs, args, device);\n\n                if (success != 0)\n                {\n                    printf(\"TexConv for path %s failed. Exiting...\\n\", model.images[tex].uri);\n                    return false;\n                }\n            }\n            else\n                printf(\"Compressed texture already exists in the path %s. Skipping...\\n\", ddsPath.Get());\n\n            // Modify URI to dds path. URI paths are relative to gltf file.\n            ArenaPathNoInline ddsPathRelglTF(compressedDirName, arena);\n            ddsPathRelglTF.Append(filename.data());\n            ddsPathRelglTF.ConvertToForwardSlashes();\n\n            model.images[tex].uri = ddsPathRelglTF.Get();\n        }\n\n        return true;\n    }\n\n    void WriteModifiedglTF(cgltf_data& model, const ArenaPath& gltfPath, MemoryArena& arena)\n    {\n        SmallVector<char, ArenaAllocator, 256> filename(arena);\n        filename.resize(gltfPath.Length());\n\n        size_t fnLen;\n        gltfPath.Stem(filename, &fnLen);\n        filename.resize(fnLen + 11);\n\n        filename[fnLen] = '_';\n        filename[fnLen + 1] = 'z';\n        filename[fnLen + 2] = 'e';\n        filename[fnLen + 3] = 't';\n        filename[fnLen + 4] = 'a';\n        filename[fnLen + 5] = '.';\n        filename[fnLen + 6] = 'g';\n        filename[fnLen + 7] = 'l';\n        filename[fnLen + 8] = 't';\n        filename[fnLen + 9] = 'f';\n        filename[fnLen + 10] = '\\0';\n\n        Filesystem::Path convertedPath(gltfPath.GetView());\n        convertedPath.Directory().Append(StrView(filename.data(), filename.size()));\n\n        cgltf_options options = {};\n        if (cgltf_write_file(&options, convertedPath.Get(), &model) != cgltf_result_success)\n        {\n            printf(\"Error writing modified glTF to path %s\\n\", convertedPath.Get());\n            return;\n        }\n\n        printf(\"glTF scene file with modified image URIs has been written to %s...\\n\", convertedPath.Get());\n    }\n\n    ZetaInline void ReportUsageError()\n    {\n        printf(\"Usage: BCnCompressglTF <path-to-glTF> [options]\\n\\nOptions:\\n%5s%30s\\n%5s%30s\\n%18s%23s\\n\", \"-y\", \"Force overwrite\", \"-sv\", \"Skip validation\", \"-mr <resolution>\", \"Max output resolution\");\n    }\n}\n\nint main(int argc, char* argv[])\n{\n    if (argc < 2 || argc > 5)\n    {\n        ReportUsageError();\n        return 0;\n    }\n\n    MemoryArena arena(64 * 1024);\n    ArenaPath gltfPath(argv[1], arena);\n    if (!Filesystem::Exists(gltfPath.Get()))\n    {\n        printf(\"No such file found in the path %s\\nExiting...\\n\", gltfPath.Get());\n        return 0;\n    }\n\n    bool forceOverwrite = false;\n    bool validate = true;\n    int maxRes = -1;\n\n    for (int i = 2; i < argc; i++)\n    {\n        if (strcmp(argv[i], \"-y\") == 0)\n            forceOverwrite = true;\n        else if (strcmp(argv[i], \"-sv\") == 0)\n            validate = false;\n        else if (strcmp(argv[i], \"-mr\") == 0)\n        {\n            if (i == argc - 1)\n            {\n                ReportUsageError();\n                return 0;\n            }\n            maxRes = atoi(argv[i + 1]);\n            if (maxRes == 0)\n            {\n                ReportUsageError();\n                return 0;\n            }\n\n            maxRes = Min(maxRes, DEFAULT_MAX_TEX_RES);\n            i++;\n        }\n    }\n\n    maxRes = maxRes == -1 ? DEFAULT_MAX_TEX_RES : maxRes;\n    printf(\"Compressing textures for %s...\\nMaximum output resolution set to %dx%d...\\n\",\n        argv[1], maxRes, maxRes);\n\n    cgltf_options options{};\n    cgltf_data* model = nullptr;\n    if (cgltf_parse_file(&options, gltfPath.Get(), &model) != cgltf_result_success)\n    {\n        printf(\"Error parsing glTF from path %s\\n\", gltfPath.Get());\n        return 0;\n    }\n\n    if (model->images_count == 0)\n    {\n        printf(\"No images found. Exiting...\");\n        return 0;\n    }\n\n    DecodeImageURIs(gltfPath, *model, arena, validate);\n\n    const size_t numMats = model->materials_count;\n\n    SmallVector<int, ArenaAllocator> normalMaps(arena);\n    normalMaps.reserve(numMats);\n\n    // extract normal map texture indices\n    for (size_t i = 0; i < numMats; i++)\n    {\n        if (cgltf_texture* tex = model->materials[i].normal_texture.texture; tex)\n        {\n            int imgIdx = (int)(tex->image - model->images);\n            Assert(imgIdx < model->images_count, \"Invalid image index.\");\n            normalMaps.push_back(imgIdx);\n        }\n    }\n\n    SmallVector<int, Support::ArenaAllocator> baseColorMaps(arena);\n    baseColorMaps.reserve(numMats);\n\n    SmallVector<int, Support::ArenaAllocator> metalnessRoughnessMaps(arena);\n    metalnessRoughnessMaps.reserve(numMats);\n\n    SmallVector<int, Support::ArenaAllocator> emissiveMaps(arena);\n    emissiveMaps.reserve(numMats);\n\n    // extract pbr texture indices\n    for (size_t i = 0; i < numMats; i++)\n    {\n        if (model->materials[i].has_pbr_metallic_roughness)\n        {\n            cgltf_pbr_metallic_roughness& pbr = model->materials[i].pbr_metallic_roughness;\n\n            if (cgltf_texture* tex = pbr.base_color_texture.texture; tex)\n            {\n                int imgIdx = (int)(tex->image - model->images);\n                Assert(imgIdx < model->images_count, \"Invalid image index.\");\n                baseColorMaps.push_back(imgIdx);\n            }\n\n            if (cgltf_texture* tex = pbr.metallic_roughness_texture.texture; tex)\n            {\n                int imgIdx = (int)(tex->image - model->images);\n                Assert(imgIdx < model->images_count, \"Invalid image index.\");\n                metalnessRoughnessMaps.push_back(imgIdx);\n            }\n        }\n    }\n\n    // extract emissive map texture indices\n    for (size_t i = 0; i < numMats; i++)\n    {\n        if (cgltf_texture* tex = model->materials[i].emissive_texture.texture; tex)\n        {\n            int imgIdx = (int)(tex->image - model->images);\n            Assert(imgIdx < model->images_count, \"Invalid image index.\");\n            emissiveMaps.push_back(imgIdx);\n        }\n    }\n\n    SmallVector<int, Support::ArenaAllocator> skip(arena);\n\n    if (validate)\n    {\n        bool isValid = true;\n        SmallVector<int, Support::ArenaAllocator> intersections(arena);\n        intersections.resize(model->textures_count, -1);\n\n        std::sort(baseColorMaps.begin(), baseColorMaps.end());\n        std::sort(normalMaps.begin(), normalMaps.end());\n        std::sort(metalnessRoughnessMaps.begin(), metalnessRoughnessMaps.end());\n        std::sort(emissiveMaps.begin(), emissiveMaps.end());\n\n        auto checkIntersections = [model, &intersections, &isValid](Span<int> vec1,\n            Span<int> vec2, const char* n1, const char* n2)\n            {\n                std::set_intersection(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), intersections.begin());\n\n                for (int& i : intersections)\n                {\n                    if (i == -1)\n                        break;\n\n                    printf(\"WARNING: Following texture is used both as a(n) %s map and a(n) %s map:\\n%s\\n\",\n                        n1, n2, model->images[i].uri);\n\n                    i = -1;\n                    isValid = false;\n                }\n            };\n\n        checkIntersections(baseColorMaps, normalMaps, \"base-color\", \"normal\");\n        checkIntersections(baseColorMaps, metalnessRoughnessMaps, \"base-color\", \"metalness-roughness\");\n        checkIntersections(baseColorMaps, emissiveMaps, \"base-color\", \"emissive\");\n        checkIntersections(normalMaps, metalnessRoughnessMaps, \"normal\", \"metalness-roughness\");\n        checkIntersections(normalMaps, emissiveMaps, \"normal\", \"emissive\");\n        checkIntersections(metalnessRoughnessMaps, emissiveMaps, \"metalness-roughness\", \"normal\");\n\n        if (!isValid)\n        {\n            printf(\"glTF validation failed. Exiting...\\n\");\n            return 0;\n        }\n\n        const size_t allTexIndices = baseColorMaps.size() + normalMaps.size() +\n            metalnessRoughnessMaps.size() + emissiveMaps.size();\n        SmallVector<int, Support::ArenaAllocator> temp(arena);\n        temp.resize(allTexIndices);\n        skip.resize(allTexIndices);\n\n        // Input and output can't overlap\n        auto endIt = std::merge(baseColorMaps.begin(), baseColorMaps.end(), \n            normalMaps.begin(), normalMaps.end(),\n            temp.begin());\n        temp.resize(endIt - temp.begin());\n\n        endIt = std::merge(temp.begin(), temp.end(),\n            metalnessRoughnessMaps.begin(), metalnessRoughnessMaps.end(),\n            skip.begin());\n        skip.resize(endIt - skip.begin());\n\n        temp.resize(skip.size() + emissiveMaps.size());\n        endIt = std::merge(skip.begin(), skip.end(),\n            emissiveMaps.begin(), emissiveMaps.end(),\n            temp.begin());\n        temp.resize(endIt - temp.begin());\n\n        SmallVector<int, Support::ArenaAllocator> all(model->images_count, arena);\n        for (size_t i = 0; i < model->images_count; i++)\n            all[i] = (int)i;\n\n        skip.resize(model->images_count);\n        endIt = std::set_difference(all.begin(), all.end(), \n            temp.begin(), temp.end(),\n            skip.begin());\n        skip.resize(endIt - skip.begin());\n\n        for (auto i : skip)\n            printf(\"Image with URI %s is not referenced by any materials and will be skipped...\\n\", model->images[i].uri);\n    }\n\n    printf(\"Stats:\\n\\\n        #images: %llu \\n\\\n        #textures: %llu\\n\\\n        #base-color textures: %llu\\n\\\n        #normal-map textures: %llu\\n\\\n        #metalness-roughness textures: %llu\\n\\\n        #emissive textures: %llu\\n\", model->images_count, model->textures_count, baseColorMaps.size(),\n        normalMaps.size(), metalnessRoughnessMaps.size(), emissiveMaps.size());\n\n    ComPtr<ID3D11Device> device;\n    CreateDevice(device.GetAddressOf());\n\n    // Initialize COM (needed for WIC)\n    auto hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);\n    Check(hr == S_OK, \"CoInitializeEx() failed with code %x.\", hr);\n\n    ArenaPath compressedDir(gltfPath.Get(), arena);\n    compressedDir.Directory().Append(COMPRESSED_DIR_NAME);\n    Filesystem::CreateDirectoryIfNotExists(compressedDir.Get());\n\n    if (!ConvertTextures(TEXTURE_TYPE::BASE_COLOR, gltfPath, compressedDir, COMPRESSED_DIR_NAME,\n        *model, baseColorMaps, arena, device.Get(), true, forceOverwrite, maxRes, skip))\n    {\n        return 0;\n    }\n    if (!ConvertTextures(TEXTURE_TYPE::NORMAL_MAP, gltfPath, compressedDir, COMPRESSED_DIR_NAME,\n        *model, normalMaps, arena, device.Get(), false, forceOverwrite, maxRes, skip))\n    {\n        return 0;\n    }\n    if (!ConvertTextures(TEXTURE_TYPE::METALNESS_ROUGHNESS, gltfPath, compressedDir, COMPRESSED_DIR_NAME,\n        *model, metalnessRoughnessMaps, arena, device.Get(), false, forceOverwrite, maxRes, skip))\n    {\n        return 0;\n    }\n    if (!ConvertTextures(TEXTURE_TYPE::EMISSIVE, gltfPath, compressedDir, COMPRESSED_DIR_NAME,\n        *model, emissiveMaps, arena, device.Get(), true, forceOverwrite, maxRes, skip))\n    {\n        return 0;\n    }\n\n    WriteModifiedglTF(*model, gltfPath, arena);\n\n    return 0;\n}"
  },
  {
    "path": "Tools/BCnCompressglTF/CMakeLists.txt",
    "content": "set(COMPILED_SHADER_DIR DirectXTex/Shaders/Compiled)\n\nset(SOURCES\n    DirectXTex/DirectXTex.h\n    DirectXTex/DirectXTex.inl\n    DirectXTex/BC.h\n    DirectXTex/DDS.h\n    DirectXTex/DirectXTexP.h\n    DirectXTex/filters.h\n    DirectXTex/scoped.h\n    DirectXTex/BC.cpp\n    DirectXTex/BC4BC5.cpp\n    DirectXTex/BC6HBC7.cpp\n    DirectXTex/DirectXTexCompress.cpp\n    DirectXTex/DirectXTexConvert.cpp\n    DirectXTex/DirectXTexDDS.cpp\n    DirectXTex/DirectXTexImage.cpp\n    DirectXTex/DirectXTexMipmaps.cpp\n    DirectXTex/DirectXTexMisc.cpp\n    DirectXTex/DirectXTexResize.cpp\n    DirectXTex/DirectXTexUtil.cpp\n    DirectXTex/DirectXTexFlipRotate.cpp\n    DirectXTex/DirectXTexWIC.cpp\n    DirectXTex/BCDirectCompute.h\n    DirectXTex/BCDirectCompute.cpp\n    DirectXTex/DirectXTexCompressGPU.cpp\n    DirectXTex/DirectXTexD3D11.cpp\n    ${COMPILED_SHADER_DIR}/BC6HEncode_EncodeBlockCS.inc\n    ${COMPILED_SHADER_DIR}/BC7Encode_EncodeBlockCS.inc   \n    Texconv/texconv.cpp\n    Texconv/texconv.h\n    BCnCompressglTF.cpp)\n\n# BCnCompressglTF executable\nadd_executable(BCnCompressglTF ${SOURCES})\ntarget_include_directories(BCnCompressglTF BEFORE PRIVATE \"${ZETA_CORE_DIR}\" \"${COMPILED_SHADER_DIR}\" \"${EXTERNAL_DIR}\")\ntarget_link_libraries(BCnCompressglTF ZetaCore ole32.lib shell32.lib version.lib d3d11.lib dxgi.lib)\nset_target_properties(BCnCompressglTF PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\n\ntarget_compile_options(BCnCompressglTF PRIVATE /fp:precise \"$<$<NOT:$<CONFIG:DEBUG>>:/guard:cf>\")\ntarget_link_options(BCnCompressglTF PRIVATE /DYNAMICBASE /NXCOMPAT)\n\nif (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.24)\n    target_compile_options(BCnCompressglTF PRIVATE /ZH:SHA_256)\nendif()\n\nif (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.27)\n    target_link_options(BCnCompressglTF PRIVATE /CETCOMPAT)\nendif()\n\nset(WarningsEXE \"/wd4061\" \"/wd4062\" \"/wd4365\" \"/wd4514\" \"/wd4625\" \"/wd4626\" \"/wd4627\" \"/wd4668\" \"/wd4710\" \"/wd4751\" \"/wd4820\" \"/wd5026\" \"/wd5027\" \"/wd5039\" \"/wd5045\" \"/wd5219\")\ntarget_compile_options(BCnCompressglTF PRIVATE ${WarningsEXE})\n\nsource_group(TREE \"${CMAKE_CURRENT_SOURCE_DIR}\" PREFIX \"BCnCompressglTF\" FILES ${SOURCES})\n\nset_target_properties(BCnCompressglTF PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})\nset_target_properties(BCnCompressglTF PROPERTIES FOLDER \"Tools\")"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/BC.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// BC.cpp\n//\n// Block-compression (BC) functionality for BC1, BC2, BC3 (orginal DXTn formats)\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\n// Experiemental encoding variants, not enabled by default\n//#define COLOR_WEIGHTS\n//#define COLOR_AVG_0WEIGHTS\n\n#include \"BC.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::PackedVector;\n\nnamespace\n{\n    //-------------------------------------------------------------------------------------\n    // Constants\n    //-------------------------------------------------------------------------------------\n\n    // Perceptual weightings for the importance of each channel.\n    const HDRColorA g_Luminance(0.2125f / 0.7154f, 1.0f, 0.0721f / 0.7154f, 1.0f);\n    const HDRColorA g_LuminanceInv(0.7154f / 0.2125f, 1.0f, 0.7154f / 0.0721f, 1.0f);\n\n    //-------------------------------------------------------------------------------------\n    // Decode/Encode RGB 5/6/5 colors\n    //-------------------------------------------------------------------------------------\n    inline void Decode565(_Out_ HDRColorA *pColor, _In_ const uint16_t w565) noexcept\n    {\n        pColor->r = static_cast<float>((w565 >> 11) & 31) * (1.0f / 31.0f);\n        pColor->g = static_cast<float>((w565 >> 5) & 63) * (1.0f / 63.0f);\n        pColor->b = static_cast<float>((w565 >> 0) & 31) * (1.0f / 31.0f);\n        pColor->a = 1.0f;\n    }\n\n    inline uint16_t Encode565(_In_ const HDRColorA *pColor) noexcept\n    {\n        HDRColorA Color;\n\n        Color.r = (pColor->r < 0.0f) ? 0.0f : (pColor->r > 1.0f) ? 1.0f : pColor->r;\n        Color.g = (pColor->g < 0.0f) ? 0.0f : (pColor->g > 1.0f) ? 1.0f : pColor->g;\n        Color.b = (pColor->b < 0.0f) ? 0.0f : (pColor->b > 1.0f) ? 1.0f : pColor->b;\n        Color.a = pColor->a;\n\n        uint16_t w;\n\n        w = static_cast<uint16_t>(\n            (static_cast<int32_t>(Color.r * 31.0f + 0.5f) << 11)\n            | (static_cast<int32_t>(Color.g * 63.0f + 0.5f) << 5)\n            | (static_cast<int32_t>(Color.b * 31.0f + 0.5f) << 0));\n\n        return w;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    void OptimizeRGB(\n        _Out_ HDRColorA *pX,\n        _Out_ HDRColorA *pY,\n        _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA *pPoints,\n        uint32_t cSteps,\n        uint32_t flags) noexcept\n    {\n        constexpr float fEpsilon = (0.25f / 64.0f) * (0.25f / 64.0f);\n        static const float pC3[] = { 2.0f / 2.0f, 1.0f / 2.0f, 0.0f / 2.0f };\n        static const float pD3[] = { 0.0f / 2.0f, 1.0f / 2.0f, 2.0f / 2.0f };\n        static const float pC4[] = { 3.0f / 3.0f, 2.0f / 3.0f, 1.0f / 3.0f, 0.0f / 3.0f };\n        static const float pD4[] = { 0.0f / 3.0f, 1.0f / 3.0f, 2.0f / 3.0f, 3.0f / 3.0f };\n\n        const float *pC = (3 == cSteps) ? pC3 : pC4;\n        const float *pD = (3 == cSteps) ? pD3 : pD4;\n\n        // Find Min and Max points, as starting point\n        HDRColorA X = (flags & BC_FLAGS_UNIFORM) ? HDRColorA(1.f, 1.f, 1.f, 1.f) : g_Luminance;\n        HDRColorA Y = HDRColorA(0.0f, 0.0f, 0.0f, 1.0f);\n\n        for (size_t iPoint = 0; iPoint < NUM_PIXELS_PER_BLOCK; iPoint++)\n        {\n        #ifdef COLOR_WEIGHTS\n            if (pPoints[iPoint].a > 0.0f)\n            #endif // COLOR_WEIGHTS\n            {\n                if (pPoints[iPoint].r < X.r)\n                    X.r = pPoints[iPoint].r;\n\n                if (pPoints[iPoint].g < X.g)\n                    X.g = pPoints[iPoint].g;\n\n                if (pPoints[iPoint].b < X.b)\n                    X.b = pPoints[iPoint].b;\n\n                if (pPoints[iPoint].r > Y.r)\n                    Y.r = pPoints[iPoint].r;\n\n                if (pPoints[iPoint].g > Y.g)\n                    Y.g = pPoints[iPoint].g;\n\n                if (pPoints[iPoint].b > Y.b)\n                    Y.b = pPoints[iPoint].b;\n            }\n        }\n\n        // Diagonal axis\n        const HDRColorA AB(Y.r - X.r, Y.g - X.g, Y.b - X.b, 0.0f);\n\n        const float fAB = AB.r * AB.r + AB.g * AB.g + AB.b * AB.b;\n\n        // Single color block.. no need to root-find\n        if (fAB < FLT_MIN)\n        {\n            pX->r = X.r; pX->g = X.g; pX->b = X.b; pX->a = 1.0f;\n            pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; pY->a = 1.0f;\n            return;\n        }\n\n        // Try all four axis directions, to determine which diagonal best fits data\n        const float fABInv = 1.0f / fAB;\n\n        HDRColorA Dir(AB.r * fABInv, AB.g * fABInv, AB.b * fABInv, 0.0f);\n\n        const HDRColorA Mid(\n            (X.r + Y.r) * 0.5f,\n            (X.g + Y.g) * 0.5f,\n            (X.b + Y.b) * 0.5f,\n            0.0f);\n\n        float fDir[4] = {};\n\n        for (size_t iPoint = 0; iPoint < NUM_PIXELS_PER_BLOCK; iPoint++)\n        {\n            HDRColorA Pt;\n            Pt.r = (pPoints[iPoint].r - Mid.r) * Dir.r;\n            Pt.g = (pPoints[iPoint].g - Mid.g) * Dir.g;\n            Pt.b = (pPoints[iPoint].b - Mid.b) * Dir.b;\n            Pt.a = 0.0f;\n\n            float f;\n\n        #ifdef COLOR_WEIGHTS\n            f = Pt.r + Pt.g + Pt.b;\n            fDir[0] += pPoints[iPoint].a * f * f;\n\n            f = Pt.r + Pt.g - Pt.b;\n            fDir[1] += pPoints[iPoint].a * f * f;\n\n            f = Pt.r - Pt.g + Pt.b;\n            fDir[2] += pPoints[iPoint].a * f * f;\n\n            f = Pt.r - Pt.g - Pt.b;\n            fDir[3] += pPoints[iPoint].a * f * f;\n        #else\n            f = Pt.r + Pt.g + Pt.b;\n            fDir[0] += f * f;\n\n            f = Pt.r + Pt.g - Pt.b;\n            fDir[1] += f * f;\n\n            f = Pt.r - Pt.g + Pt.b;\n            fDir[2] += f * f;\n\n            f = Pt.r - Pt.g - Pt.b;\n            fDir[3] += f * f;\n        #endif // COLOR_WEIGHTS\n        }\n\n        float fDirMax = fDir[0];\n        size_t  iDirMax = 0;\n\n        for (size_t iDir = 1; iDir < 4; iDir++)\n        {\n            if (fDir[iDir] > fDirMax)\n            {\n                fDirMax = fDir[iDir];\n                iDirMax = iDir;\n            }\n        }\n\n        if (iDirMax & 2)\n        {\n            const float f = X.g; X.g = Y.g; Y.g = f;\n        }\n\n        if (iDirMax & 1)\n        {\n            const float f = X.b; X.b = Y.b; Y.b = f;\n        }\n\n\n        // Two color block.. no need to root-find\n        if (fAB < 1.0f / 4096.0f)\n        {\n            pX->r = X.r; pX->g = X.g; pX->b = X.b; pX->a = 1.0f;\n            pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; pY->a = 1.0f;\n            return;\n        }\n\n        // Use Newton's Method to find local minima of sum-of-squares error.\n        auto const fSteps = static_cast<float>(cSteps - 1);\n\n        for (size_t iIteration = 0; iIteration < 8; iIteration++)\n        {\n            // Calculate new steps\n            HDRColorA pSteps[4];\n\n            for (size_t iStep = 0; iStep < cSteps; iStep++)\n            {\n                pSteps[iStep].r = X.r * pC[iStep] + Y.r * pD[iStep];\n                pSteps[iStep].g = X.g * pC[iStep] + Y.g * pD[iStep];\n                pSteps[iStep].b = X.b * pC[iStep] + Y.b * pD[iStep];\n                pSteps[iStep].a = 1.0f;\n            }\n\n\n            // Calculate color direction\n            Dir.r = Y.r - X.r;\n            Dir.g = Y.g - X.g;\n            Dir.b = Y.b - X.b;\n\n            const float fLen = (Dir.r * Dir.r + Dir.g * Dir.g + Dir.b * Dir.b);\n\n            if (fLen < (1.0f / 4096.0f))\n                break;\n\n            const float fScale = fSteps / fLen;\n\n            Dir.r *= fScale;\n            Dir.g *= fScale;\n            Dir.b *= fScale;\n\n\n            // Evaluate function, and derivatives\n            float d2X = 0.f;\n            float d2Y = 0.f;\n            HDRColorA dX = {};\n            HDRColorA dY = {};\n\n            for (size_t iPoint = 0; iPoint < NUM_PIXELS_PER_BLOCK; iPoint++)\n            {\n                const float fDot = (pPoints[iPoint].r - X.r) * Dir.r +\n                    (pPoints[iPoint].g - X.g) * Dir.g +\n                    (pPoints[iPoint].b - X.b) * Dir.b;\n\n\n                uint32_t iStep;\n                if (fDot <= 0.0f)\n                    iStep = 0;\n                else if (fDot >= fSteps)\n                    iStep = cSteps - 1;\n                else\n                    iStep = uint32_t(fDot + 0.5f);\n\n\n                HDRColorA Diff;\n                Diff.r = pSteps[iStep].r - pPoints[iPoint].r;\n                Diff.g = pSteps[iStep].g - pPoints[iPoint].g;\n                Diff.b = pSteps[iStep].b - pPoints[iPoint].b;\n                Diff.a = 0.0f;\n\n            #ifdef COLOR_WEIGHTS\n                const float fC = pC[iStep] * pPoints[iPoint].a * (1.0f / 8.0f);\n                const float fD = pD[iStep] * pPoints[iPoint].a * (1.0f / 8.0f);\n            #else\n                const float fC = pC[iStep] * (1.0f / 8.0f);\n                const float fD = pD[iStep] * (1.0f / 8.0f);\n            #endif // COLOR_WEIGHTS\n\n                d2X += fC * pC[iStep];\n                dX.r += fC * Diff.r;\n                dX.g += fC * Diff.g;\n                dX.b += fC * Diff.b;\n\n                d2Y += fD * pD[iStep];\n                dY.r += fD * Diff.r;\n                dY.g += fD * Diff.g;\n                dY.b += fD * Diff.b;\n            }\n\n            // Move endpoints\n            if (d2X > 0.0f)\n            {\n                const float f = -1.0f / d2X;\n\n                X.r += dX.r * f;\n                X.g += dX.g * f;\n                X.b += dX.b * f;\n            }\n\n            if (d2Y > 0.0f)\n            {\n                const float f = -1.0f / d2Y;\n\n                Y.r += dY.r * f;\n                Y.g += dY.g * f;\n                Y.b += dY.b * f;\n            }\n\n            if ((dX.r * dX.r < fEpsilon) && (dX.g * dX.g < fEpsilon) && (dX.b * dX.b < fEpsilon) &&\n                (dY.r * dY.r < fEpsilon) && (dY.g * dY.g < fEpsilon) && (dY.b * dY.b < fEpsilon))\n            {\n                break;\n            }\n        }\n\n        pX->r = X.r; pX->g = X.g; pX->b = X.b; pX->a = 1.0f;\n        pY->r = Y.r; pY->g = Y.g; pY->b = Y.b; pY->a = 1.0f;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    inline void DecodeBC1(\n        _Out_writes_(NUM_PIXELS_PER_BLOCK) XMVECTOR *pColor,\n        _In_ const D3DX_BC1 *pBC,\n        bool isbc1) noexcept\n    {\n        assert(pColor && pBC);\n        static_assert(sizeof(D3DX_BC1) == 8, \"D3DX_BC1 should be 8 bytes\");\n\n        static XMVECTORF32 s_Scale = { { { 1.f / 31.f, 1.f / 63.f, 1.f / 31.f, 1.f } } };\n\n        XMVECTOR clr0 = XMLoadU565(reinterpret_cast<const XMU565*>(&pBC->rgb[0]));\n        XMVECTOR clr1 = XMLoadU565(reinterpret_cast<const XMU565*>(&pBC->rgb[1]));\n\n        clr0 = XMVectorMultiply(clr0, s_Scale);\n        clr1 = XMVectorMultiply(clr1, s_Scale);\n\n        clr0 = XMVectorSwizzle<2, 1, 0, 3>(clr0);\n        clr1 = XMVectorSwizzle<2, 1, 0, 3>(clr1);\n\n        clr0 = XMVectorSelect(g_XMIdentityR3, clr0, g_XMSelect1110);\n        clr1 = XMVectorSelect(g_XMIdentityR3, clr1, g_XMSelect1110);\n\n        XMVECTOR clr2, clr3;\n        if (isbc1 && (pBC->rgb[0] <= pBC->rgb[1]))\n        {\n            clr2 = XMVectorLerp(clr0, clr1, 0.5f);\n            clr3 = XMVectorZero();  // Alpha of 0\n        }\n        else\n        {\n            clr2 = XMVectorLerp(clr0, clr1, 1.f / 3.f);\n            clr3 = XMVectorLerp(clr0, clr1, 2.f / 3.f);\n        }\n\n        uint32_t dw = pBC->bitmap;\n\n        for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i, dw >>= 2)\n        {\n            switch (dw & 3)\n            {\n            case 0: pColor[i] = clr0; break;\n            case 1: pColor[i] = clr1; break;\n            case 2: pColor[i] = clr2; break;\n\n            case 3:\n            default: pColor[i] = clr3; break;\n            }\n        }\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    void EncodeBC1(\n        _Out_ D3DX_BC1 *pBC,\n        _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA *pColor,\n        bool bColorKey,\n        float threshold,\n        uint32_t flags) noexcept\n    {\n        assert(pBC && pColor);\n        static_assert(sizeof(D3DX_BC1) == 8, \"D3DX_BC1 should be 8 bytes\");\n\n        // Determine if we need to colorkey this block\n        uint32_t uSteps;\n\n        if (bColorKey)\n        {\n            size_t uColorKey = 0;\n\n            for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n            {\n                if (pColor[i].a < threshold)\n                    uColorKey++;\n            }\n\n            if (NUM_PIXELS_PER_BLOCK == uColorKey)\n            {\n                pBC->rgb[0] = 0x0000;\n                pBC->rgb[1] = 0xffff;\n                pBC->bitmap = 0xffffffff;\n                return;\n            }\n\n            uSteps = (uColorKey > 0) ? 3u : 4u;\n        }\n        else\n        {\n            uSteps = 4u;\n        }\n\n        // Quantize block to R56B5, using Floyd Stienberg error diffusion.  This\n        // increases the chance that colors will map directly to the quantized\n        // axis endpoints.\n        HDRColorA Color[NUM_PIXELS_PER_BLOCK];\n        HDRColorA Error[NUM_PIXELS_PER_BLOCK];\n\n        if (flags & BC_FLAGS_DITHER_RGB)\n            memset(Error, 0x00, NUM_PIXELS_PER_BLOCK * sizeof(HDRColorA));\n\n        size_t i;\n        for (i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n        {\n            HDRColorA Clr;\n            Clr.r = pColor[i].r;\n            Clr.g = pColor[i].g;\n            Clr.b = pColor[i].b;\n            Clr.a = 1.0f;\n\n            if (flags & BC_FLAGS_DITHER_RGB)\n            {\n                Clr.r += Error[i].r;\n                Clr.g += Error[i].g;\n                Clr.b += Error[i].b;\n            }\n\n            Color[i].r = static_cast<float>(static_cast<int32_t>(Clr.r * 31.0f + 0.5f)) * (1.0f / 31.0f);\n            Color[i].g = static_cast<float>(static_cast<int32_t>(Clr.g * 63.0f + 0.5f)) * (1.0f / 63.0f);\n            Color[i].b = static_cast<float>(static_cast<int32_t>(Clr.b * 31.0f + 0.5f)) * (1.0f / 31.0f);\n\n        #ifdef COLOR_WEIGHTS\n            Color[i].a = pColor[i].a;\n        #else\n            Color[i].a = 1.0f;\n        #endif // COLOR_WEIGHTS\n\n            if (flags & BC_FLAGS_DITHER_RGB)\n            {\n                HDRColorA Diff;\n                Diff.r = Color[i].a * (Clr.r - Color[i].r);\n                Diff.g = Color[i].a * (Clr.g - Color[i].g);\n                Diff.b = Color[i].a * (Clr.b - Color[i].b);\n                Diff.a = 0.0f;\n\n                if (3 != (i & 3))\n                {\n                    assert(i < 15);\n                    _Analysis_assume_(i < 15);\n                    Error[i + 1].r += Diff.r * (7.0f / 16.0f);\n                    Error[i + 1].g += Diff.g * (7.0f / 16.0f);\n                    Error[i + 1].b += Diff.b * (7.0f / 16.0f);\n                }\n\n                if (i < 12)\n                {\n                    if (i & 3)\n                    {\n                        Error[i + 3].r += Diff.r * (3.0f / 16.0f);\n                        Error[i + 3].g += Diff.g * (3.0f / 16.0f);\n                        Error[i + 3].b += Diff.b * (3.0f / 16.0f);\n                    }\n\n                    Error[i + 4].r += Diff.r * (5.0f / 16.0f);\n                    Error[i + 4].g += Diff.g * (5.0f / 16.0f);\n                    Error[i + 4].b += Diff.b * (5.0f / 16.0f);\n\n                    if (3 != (i & 3))\n                    {\n                        assert(i < 11);\n                        _Analysis_assume_(i < 11);\n                        Error[i + 5].r += Diff.r * (1.0f / 16.0f);\n                        Error[i + 5].g += Diff.g * (1.0f / 16.0f);\n                        Error[i + 5].b += Diff.b * (1.0f / 16.0f);\n                    }\n                }\n            }\n\n            if (!(flags & BC_FLAGS_UNIFORM))\n            {\n                Color[i].r *= g_Luminance.r;\n                Color[i].g *= g_Luminance.g;\n                Color[i].b *= g_Luminance.b;\n            }\n        }\n\n        // Perform 6D root finding function to find two endpoints of color axis.\n        // Then quantize and sort the endpoints depending on mode.\n        HDRColorA ColorA, ColorB, ColorC, ColorD;\n\n        OptimizeRGB(&ColorA, &ColorB, Color, uSteps, flags);\n\n        if (flags & BC_FLAGS_UNIFORM)\n        {\n            ColorC = ColorA;\n            ColorD = ColorB;\n        }\n        else\n        {\n            ColorC.r = ColorA.r * g_LuminanceInv.r;\n            ColorC.g = ColorA.g * g_LuminanceInv.g;\n            ColorC.b = ColorA.b * g_LuminanceInv.b;\n            ColorC.a = ColorA.a;\n\n            ColorD.r = ColorB.r * g_LuminanceInv.r;\n            ColorD.g = ColorB.g * g_LuminanceInv.g;\n            ColorD.b = ColorB.b * g_LuminanceInv.b;\n            ColorD.a = ColorB.a;\n        }\n\n        const uint16_t wColorA = Encode565(&ColorC);\n        const uint16_t wColorB = Encode565(&ColorD);\n\n        if ((uSteps == 4) && (wColorA == wColorB))\n        {\n            pBC->rgb[0] = wColorA;\n            pBC->rgb[1] = wColorB;\n            pBC->bitmap = 0x00000000;\n            return;\n        }\n\n        Decode565(&ColorC, wColorA);\n        Decode565(&ColorD, wColorB);\n\n        if (flags & BC_FLAGS_UNIFORM)\n        {\n            ColorA = ColorC;\n            ColorB = ColorD;\n        }\n        else\n        {\n            ColorA.r = ColorC.r * g_Luminance.r;\n            ColorA.g = ColorC.g * g_Luminance.g;\n            ColorA.b = ColorC.b * g_Luminance.b;\n\n            ColorB.r = ColorD.r * g_Luminance.r;\n            ColorB.g = ColorD.g * g_Luminance.g;\n            ColorB.b = ColorD.b * g_Luminance.b;\n        }\n\n        // Calculate color steps\n        HDRColorA Step[4];\n\n        if ((3 == uSteps) == (wColorA <= wColorB))\n        {\n            pBC->rgb[0] = wColorA;\n            pBC->rgb[1] = wColorB;\n\n            Step[0] = ColorA;\n            Step[1] = ColorB;\n        }\n        else\n        {\n            pBC->rgb[0] = wColorB;\n            pBC->rgb[1] = wColorA;\n\n            Step[0] = ColorB;\n            Step[1] = ColorA;\n        }\n\n        static const size_t pSteps3[] = { 0, 2, 1 };\n        static const size_t pSteps4[] = { 0, 2, 3, 1 };\n        const size_t *pSteps;\n\n        if (3 == uSteps)\n        {\n            pSteps = pSteps3;\n\n            HDRColorALerp(&Step[2], &Step[0], &Step[1], 0.5f);\n        }\n        else\n        {\n            pSteps = pSteps4;\n\n            HDRColorALerp(&Step[2], &Step[0], &Step[1], 1.0f / 3.0f);\n            HDRColorALerp(&Step[3], &Step[0], &Step[1], 2.0f / 3.0f);\n        }\n\n        // Calculate color direction\n        HDRColorA Dir;\n        Dir.r = Step[1].r - Step[0].r;\n        Dir.g = Step[1].g - Step[0].g;\n        Dir.b = Step[1].b - Step[0].b;\n        Dir.a = 0.0f;\n\n        const auto fSteps = static_cast<float>(uSteps - 1);\n        const float fScale = (wColorA != wColorB) ? (fSteps / (Dir.r * Dir.r + Dir.g * Dir.g + Dir.b * Dir.b)) : 0.0f;\n\n        Dir.r *= fScale;\n        Dir.g *= fScale;\n        Dir.b *= fScale;\n\n        // Encode colors\n        uint32_t dw = 0;\n        if (flags & BC_FLAGS_DITHER_RGB)\n            memset(Error, 0x00, NUM_PIXELS_PER_BLOCK * sizeof(HDRColorA));\n\n        for (i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n        {\n            if ((3 == uSteps) && (pColor[i].a < threshold))\n            {\n                dw = (3u << 30) | (dw >> 2);\n            }\n            else\n            {\n                HDRColorA Clr;\n                if (flags & BC_FLAGS_UNIFORM)\n                {\n                    Clr.r = pColor[i].r;\n                    Clr.g = pColor[i].g;\n                    Clr.b = pColor[i].b;\n                }\n                else\n                {\n                    Clr.r = pColor[i].r * g_Luminance.r;\n                    Clr.g = pColor[i].g * g_Luminance.g;\n                    Clr.b = pColor[i].b * g_Luminance.b;\n                }\n                Clr.a = 1.0f;\n\n                if (flags & BC_FLAGS_DITHER_RGB)\n                {\n                    Clr.r += Error[i].r;\n                    Clr.g += Error[i].g;\n                    Clr.b += Error[i].b;\n                }\n\n                const float fDot = (Clr.r - Step[0].r) * Dir.r + (Clr.g - Step[0].g) * Dir.g + (Clr.b - Step[0].b) * Dir.b;\n\n                uint32_t iStep;\n                if (fDot <= 0.0f)\n                    iStep = 0;\n                else if (fDot >= fSteps)\n                    iStep = 1;\n                else\n                    iStep = uint32_t(pSteps[uint32_t(fDot + 0.5f)]);\n\n                dw = (iStep << 30) | (dw >> 2);\n\n                if (flags & BC_FLAGS_DITHER_RGB)\n                {\n                    HDRColorA Diff;\n                    Diff.r = Color[i].a * (Clr.r - Step[iStep].r);\n                    Diff.g = Color[i].a * (Clr.g - Step[iStep].g);\n                    Diff.b = Color[i].a * (Clr.b - Step[iStep].b);\n                    Diff.a = 0.0f;\n\n                    if (3 != (i & 3))\n                    {\n                        Error[i + 1].r += Diff.r * (7.0f / 16.0f);\n                        Error[i + 1].g += Diff.g * (7.0f / 16.0f);\n                        Error[i + 1].b += Diff.b * (7.0f / 16.0f);\n                    }\n\n                    if (i < 12)\n                    {\n                        if (i & 3)\n                        {\n                            Error[i + 3].r += Diff.r * (3.0f / 16.0f);\n                            Error[i + 3].g += Diff.g * (3.0f / 16.0f);\n                            Error[i + 3].b += Diff.b * (3.0f / 16.0f);\n                        }\n\n                        Error[i + 4].r += Diff.r * (5.0f / 16.0f);\n                        Error[i + 4].g += Diff.g * (5.0f / 16.0f);\n                        Error[i + 4].b += Diff.b * (5.0f / 16.0f);\n\n                        if (3 != (i & 3))\n                        {\n                            Error[i + 5].r += Diff.r * (1.0f / 16.0f);\n                            Error[i + 5].g += Diff.g * (1.0f / 16.0f);\n                            Error[i + 5].b += Diff.b * (1.0f / 16.0f);\n                        }\n                    }\n                }\n            }\n        }\n\n        pBC->bitmap = dw;\n    }\n\n    //-------------------------------------------------------------------------------------\n#ifdef COLOR_WEIGHTS\n    void EncodeSolidBC1(_Out_ D3DX_BC1 *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA *pColor)\n    {\n    #ifdef COLOR_AVG_0WEIGHTS\n        // Compute avg color\n        HDRColorA Color;\n        Color.r = pColor[0].r;\n        Color.g = pColor[0].g;\n        Color.b = pColor[0].b;\n\n        for (size_t i = 1; i < NUM_PIXELS_PER_BLOCK; ++i)\n        {\n            Color.r += pColor[i].r;\n            Color.g += pColor[i].g;\n            Color.b += pColor[i].b;\n        }\n\n        Color.r *= 1.0f / 16.0f;\n        Color.g *= 1.0f / 16.0f;\n        Color.b *= 1.0f / 16.0f;\n\n        const uint16_t wColor = Encode565(&Color);\n    #else\n        const uint16_t wColor = 0x0000;\n    #endif // COLOR_AVG_0WEIGHTS\n\n        // Encode solid block\n        pBC->rgb[0] = wColor;\n        pBC->rgb[1] = wColor;\n        pBC->bitmap = 0x00000000;\n    }\n#endif // COLOR_WEIGHTS\n}\n\n\n//=====================================================================================\n// Entry points\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n// BC1 Compression\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nvoid DirectX::D3DXDecodeBC1(XMVECTOR *pColor, const uint8_t *pBC) noexcept\n{\n    auto pBC1 = reinterpret_cast<const D3DX_BC1 *>(pBC);\n    DecodeBC1(pColor, pBC1, true);\n}\n\n_Use_decl_annotations_\nvoid DirectX::D3DXEncodeBC1(uint8_t *pBC, const XMVECTOR *pColor, float threshold, uint32_t flags) noexcept\n{\n    assert(pBC && pColor);\n\n    HDRColorA Color[NUM_PIXELS_PER_BLOCK];\n\n    if (flags & BC_FLAGS_DITHER_A)\n    {\n        float fError[NUM_PIXELS_PER_BLOCK] = {};\n\n        for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n        {\n            HDRColorA clr;\n            XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&clr), pColor[i]);\n\n            const float fAlph = clr.a + fError[i];\n\n            Color[i].r = clr.r;\n            Color[i].g = clr.g;\n            Color[i].b = clr.b;\n            Color[i].a = static_cast<float>(static_cast<int32_t>(clr.a + fError[i] + 0.5f));\n\n            const float fDiff = fAlph - Color[i].a;\n\n            if (3 != (i & 3))\n            {\n                assert(i < 15);\n                _Analysis_assume_(i < 15);\n                fError[i + 1] += fDiff * (7.0f / 16.0f);\n            }\n\n            if (i < 12)\n            {\n                if (i & 3)\n                    fError[i + 3] += fDiff * (3.0f / 16.0f);\n\n                fError[i + 4] += fDiff * (5.0f / 16.0f);\n\n                if (3 != (i & 3))\n                {\n                    assert(i < 11);\n                    _Analysis_assume_(i < 11);\n                    fError[i + 5] += fDiff * (1.0f / 16.0f);\n                }\n            }\n        }\n    }\n    else\n    {\n        for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n        {\n            XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&Color[i]), pColor[i]);\n        }\n    }\n\n    auto pBC1 = reinterpret_cast<D3DX_BC1 *>(pBC);\n    EncodeBC1(pBC1, Color, true, threshold, flags);\n}\n\n\n//-------------------------------------------------------------------------------------\n// BC2 Compression\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nvoid DirectX::D3DXDecodeBC2(XMVECTOR *pColor, const uint8_t *pBC) noexcept\n{\n    assert(pColor && pBC);\n    static_assert(sizeof(D3DX_BC2) == 16, \"D3DX_BC2 should be 16 bytes\");\n\n    auto pBC2 = reinterpret_cast<const D3DX_BC2 *>(pBC);\n\n    // RGB part\n    DecodeBC1(pColor, &pBC2->bc1, false);\n\n    // 4-bit alpha part\n    uint32_t dw = pBC2->bitmap[0];\n\n    for (size_t i = 0; i < 8; ++i, dw >>= 4)\n    {\n    #pragma prefast(suppress:22103, \"writing blocks in two halves confuses tool\")\n        pColor[i] = XMVectorSetW(pColor[i], static_cast<float>(dw & 0xf) * (1.0f / 15.0f));\n    }\n\n    dw = pBC2->bitmap[1];\n\n    for (size_t i = 8; i < NUM_PIXELS_PER_BLOCK; ++i, dw >>= 4)\n        pColor[i] = XMVectorSetW(pColor[i], static_cast<float>(dw & 0xf) * (1.0f / 15.0f));\n}\n\n_Use_decl_annotations_\nvoid DirectX::D3DXEncodeBC2(uint8_t *pBC, const XMVECTOR *pColor, uint32_t flags) noexcept\n{\n    assert(pBC && pColor);\n    static_assert(sizeof(D3DX_BC2) == 16, \"D3DX_BC2 should be 16 bytes\");\n\n    HDRColorA Color[NUM_PIXELS_PER_BLOCK];\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n        XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&Color[i]), pColor[i]);\n    }\n\n    auto pBC2 = reinterpret_cast<D3DX_BC2 *>(pBC);\n\n    // 4-bit alpha part.  Dithered using Floyd Stienberg error diffusion.\n    pBC2->bitmap[0] = 0;\n    pBC2->bitmap[1] = 0;\n\n    float fError[NUM_PIXELS_PER_BLOCK] = {};\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n        float fAlph = Color[i].a;\n        if (flags & BC_FLAGS_DITHER_A)\n            fAlph += fError[i];\n\n        const auto u = static_cast<uint32_t>(fAlph * 15.0f + 0.5f);\n\n        pBC2->bitmap[i >> 3] >>= 4;\n        pBC2->bitmap[i >> 3] |= (u << 28);\n\n        if (flags & BC_FLAGS_DITHER_A)\n        {\n            const float fDiff = fAlph - float(u) * (1.0f / 15.0f);\n\n            if (3 != (i & 3))\n            {\n                assert(i < 15);\n                _Analysis_assume_(i < 15);\n                fError[i + 1] += fDiff * (7.0f / 16.0f);\n            }\n\n            if (i < 12)\n            {\n                if (i & 3)\n                    fError[i + 3] += fDiff * (3.0f / 16.0f);\n\n                fError[i + 4] += fDiff * (5.0f / 16.0f);\n\n                if (3 != (i & 3))\n                {\n                    assert(i < 11);\n                    _Analysis_assume_(i < 11);\n                    fError[i + 5] += fDiff * (1.0f / 16.0f);\n                }\n            }\n        }\n    }\n\n    // RGB part\n#ifdef COLOR_WEIGHTS\n    if (!pBC2->bitmap[0] && !pBC2->bitmap[1])\n    {\n        EncodeSolidBC1(pBC2->dxt1, Color);\n        return;\n    }\n#endif // COLOR_WEIGHTS\n\n    EncodeBC1(&pBC2->bc1, Color, false, 0.f, flags);\n}\n\n\n//-------------------------------------------------------------------------------------\n// BC3 Compression\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nvoid DirectX::D3DXDecodeBC3(XMVECTOR *pColor, const uint8_t *pBC) noexcept\n{\n    assert(pColor && pBC);\n    static_assert(sizeof(D3DX_BC3) == 16, \"D3DX_BC3 should be 16 bytes\");\n\n    auto pBC3 = reinterpret_cast<const D3DX_BC3 *>(pBC);\n\n    // RGB part\n    DecodeBC1(pColor, &pBC3->bc1, false);\n\n    // Adaptive 3-bit alpha part\n    float fAlpha[8];\n\n    fAlpha[0] = static_cast<float>(pBC3->alpha[0]) * (1.0f / 255.0f);\n    fAlpha[1] = static_cast<float>(pBC3->alpha[1]) * (1.0f / 255.0f);\n\n    if (pBC3->alpha[0] > pBC3->alpha[1])\n    {\n        for (size_t i = 1; i < 7; ++i)\n            fAlpha[i + 1] = (fAlpha[0] * float(7u - i) + fAlpha[1] * float(i)) * (1.0f / 7.0f);\n    }\n    else\n    {\n        for (size_t i = 1; i < 5; ++i)\n            fAlpha[i + 1] = (fAlpha[0] * float(5u - i) + fAlpha[1] * float(i)) * (1.0f / 5.0f);\n\n        fAlpha[6] = 0.0f;\n        fAlpha[7] = 1.0f;\n    }\n\n    uint32_t dw = uint32_t(pBC3->bitmap[0]) | uint32_t(pBC3->bitmap[1] << 8) | uint32_t(pBC3->bitmap[2] << 16);\n\n    for (size_t i = 0; i < 8; ++i, dw >>= 3)\n        pColor[i] = XMVectorSetW(pColor[i], fAlpha[dw & 0x7]);\n\n    dw = uint32_t(pBC3->bitmap[3]) | uint32_t(pBC3->bitmap[4] << 8) | uint32_t(pBC3->bitmap[5] << 16);\n\n    for (size_t i = 8; i < NUM_PIXELS_PER_BLOCK; ++i, dw >>= 3)\n        pColor[i] = XMVectorSetW(pColor[i], fAlpha[dw & 0x7]);\n}\n\n_Use_decl_annotations_\nvoid DirectX::D3DXEncodeBC3(uint8_t *pBC, const XMVECTOR *pColor, uint32_t flags) noexcept\n{\n    assert(pBC && pColor);\n    static_assert(sizeof(D3DX_BC3) == 16, \"D3DX_BC3 should be 16 bytes\");\n\n    HDRColorA Color[NUM_PIXELS_PER_BLOCK];\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n        XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(&Color[i]), pColor[i]);\n    }\n\n    auto pBC3 = reinterpret_cast<D3DX_BC3 *>(pBC);\n\n    // Quantize block to A8, using Floyd Stienberg error diffusion.  This\n    // increases the chance that colors will map directly to the quantized\n    // axis endpoints.\n    float fAlpha[NUM_PIXELS_PER_BLOCK] = {};\n    float fError[NUM_PIXELS_PER_BLOCK] = {};\n\n    float fMinAlpha = Color[0].a;\n    float fMaxAlpha = Color[0].a;\n\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n        float fAlph = Color[i].a;\n        if (flags & BC_FLAGS_DITHER_A)\n            fAlph += fError[i];\n\n        fAlpha[i] = static_cast<float>(static_cast<int32_t>(fAlph * 255.0f + 0.5f)) * (1.0f / 255.0f);\n\n        if (fAlpha[i] < fMinAlpha)\n            fMinAlpha = fAlpha[i];\n        else if (fAlpha[i] > fMaxAlpha)\n            fMaxAlpha = fAlpha[i];\n\n        if (flags & BC_FLAGS_DITHER_A)\n        {\n            const float fDiff = fAlph - fAlpha[i];\n\n            if (3 != (i & 3))\n            {\n                assert(i < 15);\n                _Analysis_assume_(i < 15);\n                fError[i + 1] += fDiff * (7.0f / 16.0f);\n            }\n\n            if (i < 12)\n            {\n                if (i & 3)\n                    fError[i + 3] += fDiff * (3.0f / 16.0f);\n\n                fError[i + 4] += fDiff * (5.0f / 16.0f);\n\n                if (3 != (i & 3))\n                {\n                    assert(i < 11);\n                    _Analysis_assume_(i < 11);\n                    fError[i + 5] += fDiff * (1.0f / 16.0f);\n                }\n            }\n        }\n    }\n\n#ifdef COLOR_WEIGHTS\n    if (0.0f == fMaxAlpha)\n    {\n        EncodeSolidBC1(&pBC3->dxt1, Color);\n        pBC3->alpha[0] = 0x00;\n        pBC3->alpha[1] = 0x00;\n        memset(pBC3->bitmap, 0x00, 6);\n    }\n#endif\n\n    // RGB part\n    EncodeBC1(&pBC3->bc1, Color, false, 0.f, flags);\n\n    // Alpha part\n    if (1.0f == fMinAlpha)\n    {\n        pBC3->alpha[0] = 0xff;\n        pBC3->alpha[1] = 0xff;\n        memset(pBC3->bitmap, 0x00, 6);\n        return;\n    }\n\n    // Optimize and Quantize Min and Max values\n    const uint32_t uSteps = ((0.0f == fMinAlpha) || (1.0f == fMaxAlpha)) ? 6u : 8u;\n\n    float fAlphaA, fAlphaB;\n    OptimizeAlpha<false>(&fAlphaA, &fAlphaB, fAlpha, uSteps);\n\n    auto const bAlphaA = static_cast<uint8_t>(static_cast<int32_t>(fAlphaA * 255.0f + 0.5f));\n    auto const bAlphaB = static_cast<uint8_t>(static_cast<int32_t>(fAlphaB * 255.0f + 0.5f));\n\n    fAlphaA = static_cast<float>(bAlphaA) * (1.0f / 255.0f);\n    fAlphaB = static_cast<float>(bAlphaB) * (1.0f / 255.0f);\n\n    // Setup block\n    if ((8 == uSteps) && (bAlphaA == bAlphaB))\n    {\n        pBC3->alpha[0] = bAlphaA;\n        pBC3->alpha[1] = bAlphaB;\n        memset(pBC3->bitmap, 0x00, 6);\n        return;\n    }\n\n    static const size_t pSteps6[] = { 0, 2, 3, 4, 5, 1 };\n    static const size_t pSteps8[] = { 0, 2, 3, 4, 5, 6, 7, 1 };\n\n    const size_t *pSteps;\n    float fStep[8] = {};\n\n    if (6 == uSteps)\n    {\n        pBC3->alpha[0] = bAlphaA;\n        pBC3->alpha[1] = bAlphaB;\n\n        fStep[0] = fAlphaA;\n        fStep[1] = fAlphaB;\n\n        for (size_t i = 1; i < 5; ++i)\n            fStep[i + 1] = (fStep[0] * float(5u - i) + fStep[1] * float(i)) * (1.0f / 5.0f);\n\n        fStep[6] = 0.0f;\n        fStep[7] = 1.0f;\n\n        pSteps = pSteps6;\n    }\n    else\n    {\n        pBC3->alpha[0] = bAlphaB;\n        pBC3->alpha[1] = bAlphaA;\n\n        fStep[0] = fAlphaB;\n        fStep[1] = fAlphaA;\n\n        for (size_t i = 1; i < 7; ++i)\n            fStep[i + 1] = (fStep[0] * float(7u - i) + fStep[1] * float(i)) * (1.0f / 7.0f);\n\n        pSteps = pSteps8;\n    }\n\n    // Encode alpha bitmap\n    auto const fSteps = static_cast<float>(uSteps - 1);\n    const float fScale = (fStep[0] != fStep[1]) ? (fSteps / (fStep[1] - fStep[0])) : 0.0f;\n\n    if (flags & BC_FLAGS_DITHER_A)\n        memset(fError, 0x00, NUM_PIXELS_PER_BLOCK * sizeof(float));\n\n    for (size_t iSet = 0; iSet < 2; iSet++)\n    {\n        uint32_t dw = 0;\n\n        const size_t iMin = iSet * 8;\n        const size_t iLim = iMin + 8;\n\n        for (size_t i = iMin; i < iLim; ++i)\n        {\n            float fAlph = Color[i].a;\n            if (flags & BC_FLAGS_DITHER_A)\n                fAlph += fError[i];\n            const float fDot = (fAlph - fStep[0]) * fScale;\n\n            uint32_t iStep;\n            if (fDot <= 0.0f)\n                iStep = ((6 == uSteps) && (fAlph <= fStep[0] * 0.5f)) ? 6u : 0u;\n            else if (fDot >= fSteps)\n                iStep = ((6 == uSteps) && (fAlph >= (fStep[1] + 1.0f) * 0.5f)) ? 7u : 1u;\n            else\n                iStep = uint32_t(pSteps[uint32_t(fDot + 0.5f)]);\n\n            dw = (iStep << 21) | (dw >> 3);\n\n            if (flags & BC_FLAGS_DITHER_A)\n            {\n                const float fDiff = (fAlph - fStep[iStep]);\n\n                if (3 != (i & 3))\n                    fError[i + 1] += fDiff * (7.0f / 16.0f);\n\n                if (i < 12)\n                {\n                    if (i & 3)\n                        fError[i + 3] += fDiff * (3.0f / 16.0f);\n\n                    fError[i + 4] += fDiff * (5.0f / 16.0f);\n\n                    if (3 != (i & 3))\n                        fError[i + 5] += fDiff * (1.0f / 16.0f);\n                }\n            }\n        }\n\n        pBC3->bitmap[0 + iSet * 3] = reinterpret_cast<uint8_t *>(&dw)[0];\n        pBC3->bitmap[1 + iSet * 3] = reinterpret_cast<uint8_t *>(&dw)[1];\n        pBC3->bitmap[2 + iSet * 3] = reinterpret_cast<uint8_t *>(&dw)[2];\n    }\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/BC.h",
    "content": "//-------------------------------------------------------------------------------------\n// BC.h\n//\n// Block-compression (BC) functionality\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <DirectXMath.h>\n#include <DirectXPackedVector.h>\n\nnamespace DirectX\n{\n//-------------------------------------------------------------------------------------\n// Macros\n//-------------------------------------------------------------------------------------\n\n// Because these are used in SAL annotations, they need to remain macros rather than const values\n#define NUM_PIXELS_PER_BLOCK 16\n\n//-------------------------------------------------------------------------------------\n// Constants\n//-------------------------------------------------------------------------------------\n\n    enum BC_FLAGS : uint32_t\n    {\n        BC_FLAGS_NONE = 0x0,\n\n        BC_FLAGS_DITHER_RGB = 0x10000,\n        // Enables dithering for RGB colors for BC1-3\n\n        BC_FLAGS_DITHER_A = 0x20000,\n        // Enables dithering for Alpha channel for BC1-3\n\n        BC_FLAGS_UNIFORM = 0x40000,\n        // By default, uses perceptual weighting for BC1-3; this flag makes it a uniform weighting\n\n        BC_FLAGS_USE_3SUBSETS = 0x80000,\n        // By default, BC7 skips mode 0 & 2; this flag adds those modes back\n\n        BC_FLAGS_FORCE_BC7_MODE6 = 0x100000,\n        // BC7 should only use mode 6; skip other modes\n    };\n\n    //-------------------------------------------------------------------------------------\n    // Structures\n    //-------------------------------------------------------------------------------------\n    class LDRColorA;\n\n    class HDRColorA\n    {\n    public:\n        float r, g, b, a;\n\n    public:\n        HDRColorA() = default;\n        HDRColorA(float _r, float _g, float _b, float _a) noexcept : r(_r), g(_g), b(_b), a(_a) {}\n        HDRColorA(const HDRColorA& c) noexcept : r(c.r), g(c.g), b(c.b), a(c.a) {}\n        HDRColorA& operator=(const HDRColorA& c) noexcept\n        {\n            r = c.r;\n            g = c.g;\n            b = c.b;\n            a = c.a;\n\n            return *this;\n        }\n\n        // binary operators\n        HDRColorA operator + (const HDRColorA& c) const noexcept\n        {\n            return HDRColorA(r + c.r, g + c.g, b + c.b, a + c.a);\n        }\n\n        HDRColorA operator - (const HDRColorA& c) const noexcept\n        {\n            return HDRColorA(r - c.r, g - c.g, b - c.b, a - c.a);\n        }\n\n        HDRColorA operator * (float f) const noexcept\n        {\n            return HDRColorA(r * f, g * f, b * f, a * f);\n        }\n\n        HDRColorA operator / (float f) const noexcept\n        {\n            const float fInv = 1.0f / f;\n            return HDRColorA(r * fInv, g * fInv, b * fInv, a * fInv);\n        }\n\n        float operator * (const HDRColorA& c) const noexcept\n        {\n            return r * c.r + g * c.g + b * c.b + a * c.a;\n        }\n\n        // assignment operators\n        HDRColorA& operator += (const HDRColorA& c) noexcept\n        {\n            r += c.r;\n            g += c.g;\n            b += c.b;\n            a += c.a;\n            return *this;\n        }\n\n        HDRColorA& operator -= (const HDRColorA& c) noexcept\n        {\n            r -= c.r;\n            g -= c.g;\n            b -= c.b;\n            a -= c.a;\n            return *this;\n        }\n\n        HDRColorA& operator *= (float f) noexcept\n        {\n            r *= f;\n            g *= f;\n            b *= f;\n            a *= f;\n            return *this;\n        }\n\n        HDRColorA& operator /= (float f) noexcept\n        {\n            const float fInv = 1.0f / f;\n            r *= fInv;\n            g *= fInv;\n            b *= fInv;\n            a *= fInv;\n            return *this;\n        }\n\n        HDRColorA& Clamp(_In_ float fMin, _In_ float fMax) noexcept\n        {\n            r = std::min<float>(fMax, std::max<float>(fMin, r));\n            g = std::min<float>(fMax, std::max<float>(fMin, g));\n            b = std::min<float>(fMax, std::max<float>(fMin, b));\n            a = std::min<float>(fMax, std::max<float>(fMin, a));\n            return *this;\n        }\n\n        HDRColorA(const LDRColorA& c) noexcept;\n        HDRColorA& operator = (const LDRColorA& c) noexcept;\n        LDRColorA ToLDRColorA() const noexcept;\n    };\n\n    inline HDRColorA* HDRColorALerp(_Out_ HDRColorA *pOut, _In_ const HDRColorA *pC1, _In_ const HDRColorA *pC2, _In_ float s) noexcept\n    {\n        pOut->r = pC1->r + s * (pC2->r - pC1->r);\n        pOut->g = pC1->g + s * (pC2->g - pC1->g);\n        pOut->b = pC1->b + s * (pC2->b - pC1->b);\n        pOut->a = pC1->a + s * (pC2->a - pC1->a);\n        return pOut;\n    }\n\n#pragma pack(push,1)\n// BC1/DXT1 compression (4 bits per texel)\n    struct D3DX_BC1\n    {\n        uint16_t    rgb[2]; // 565 colors\n        uint32_t    bitmap; // 2bpp rgb bitmap\n    };\n\n    // BC2/DXT2/3 compression (8 bits per texel)\n    struct D3DX_BC2\n    {\n        uint32_t    bitmap[2];  // 4bpp alpha bitmap\n        D3DX_BC1    bc1;        // BC1 rgb data\n    };\n\n    // BC3/DXT4/5 compression (8 bits per texel)\n    struct D3DX_BC3\n    {\n        uint8_t     alpha[2];   // alpha values\n        uint8_t     bitmap[6];  // 3bpp alpha bitmap\n        D3DX_BC1    bc1;        // BC1 rgb data\n    };\n#pragma pack(pop)\n\n//-------------------------------------------------------------------------------------\n// Templates\n//-------------------------------------------------------------------------------------\n#pragma warning(push)\n#pragma warning(disable : 4127)\n    template <bool bRange> void OptimizeAlpha(float *pX, float *pY, const float *pPoints, uint32_t cSteps) noexcept\n    {\n        static const float pC6[] = { 5.0f / 5.0f, 4.0f / 5.0f, 3.0f / 5.0f, 2.0f / 5.0f, 1.0f / 5.0f, 0.0f / 5.0f };\n        static const float pD6[] = { 0.0f / 5.0f, 1.0f / 5.0f, 2.0f / 5.0f, 3.0f / 5.0f, 4.0f / 5.0f, 5.0f / 5.0f };\n        static const float pC8[] = { 7.0f / 7.0f, 6.0f / 7.0f, 5.0f / 7.0f, 4.0f / 7.0f, 3.0f / 7.0f, 2.0f / 7.0f, 1.0f / 7.0f, 0.0f / 7.0f };\n        static const float pD8[] = { 0.0f / 7.0f, 1.0f / 7.0f, 2.0f / 7.0f, 3.0f / 7.0f, 4.0f / 7.0f, 5.0f / 7.0f, 6.0f / 7.0f, 7.0f / 7.0f };\n\n        const float *pC = (6 == cSteps) ? pC6 : pC8;\n        const float *pD = (6 == cSteps) ? pD6 : pD8;\n\n        constexpr float MAX_VALUE = 1.0f;\n        constexpr float MIN_VALUE = (bRange) ? -1.0f : 0.0f;\n\n        // Find Min and Max points, as starting point\n        float fX = MAX_VALUE;\n        float fY = MIN_VALUE;\n\n        if (8 == cSteps)\n        {\n            for (size_t iPoint = 0; iPoint < NUM_PIXELS_PER_BLOCK; iPoint++)\n            {\n                if (pPoints[iPoint] < fX)\n                    fX = pPoints[iPoint];\n\n                if (pPoints[iPoint] > fY)\n                    fY = pPoints[iPoint];\n            }\n        }\n        else\n        {\n            for (size_t iPoint = 0; iPoint < NUM_PIXELS_PER_BLOCK; iPoint++)\n            {\n                if (pPoints[iPoint] < fX && pPoints[iPoint] > MIN_VALUE)\n                    fX = pPoints[iPoint];\n\n                if (pPoints[iPoint] > fY && pPoints[iPoint] < MAX_VALUE)\n                    fY = pPoints[iPoint];\n            }\n\n            if (fX == fY)\n            {\n                fY = MAX_VALUE;\n            }\n        }\n\n        // Use Newton's Method to find local minima of sum-of-squares error.\n        auto const fSteps = static_cast<float>(cSteps - 1);\n\n        for (size_t iIteration = 0; iIteration < 8; iIteration++)\n        {\n            if ((fY - fX) < (1.0f / 256.0f))\n                break;\n\n            float const fScale = fSteps / (fY - fX);\n\n            // Calculate new steps\n            float pSteps[8];\n\n            for (size_t iStep = 0; iStep < cSteps; iStep++)\n                pSteps[iStep] = pC[iStep] * fX + pD[iStep] * fY;\n\n            if (6 == cSteps)\n            {\n                pSteps[6] = MIN_VALUE;\n                pSteps[7] = MAX_VALUE;\n            }\n\n            // Evaluate function, and derivatives\n            float dX = 0.0f;\n            float dY = 0.0f;\n            float d2X = 0.0f;\n            float d2Y = 0.0f;\n\n            for (size_t iPoint = 0; iPoint < NUM_PIXELS_PER_BLOCK; iPoint++)\n            {\n                const float fDot = (pPoints[iPoint] - fX) * fScale;\n\n                uint32_t iStep;\n                if (fDot <= 0.0f)\n                {\n                    // D3DX10 / D3DX11 didn't take into account the proper minimum value for the bRange (BC4S/BC5S) case\n                    iStep = ((6 == cSteps) && (pPoints[iPoint] <= (fX + MIN_VALUE) * 0.5f)) ? 6u : 0u;\n                }\n                else if (fDot >= fSteps)\n                {\n                    iStep = ((6 == cSteps) && (pPoints[iPoint] >= (fY + MAX_VALUE) * 0.5f)) ? 7u : (cSteps - 1);\n                }\n                else\n                {\n                    iStep = uint32_t(fDot + 0.5f);\n                }\n\n                if (iStep < cSteps)\n                {\n                    // D3DX had this computation backwards (pPoints[iPoint] - pSteps[iStep])\n                    // this fix improves RMS of the alpha component\n                    const float fDiff = pSteps[iStep] - pPoints[iPoint];\n\n                    dX += pC[iStep] * fDiff;\n                    d2X += pC[iStep] * pC[iStep];\n\n                    dY += pD[iStep] * fDiff;\n                    d2Y += pD[iStep] * pD[iStep];\n                }\n            }\n\n            // Move endpoints\n            if (d2X > 0.0f)\n                fX -= dX / d2X;\n\n            if (d2Y > 0.0f)\n                fY -= dY / d2Y;\n\n            if (fX > fY)\n            {\n                const float f = fX; fX = fY; fY = f;\n            }\n\n            if ((dX * dX < (1.0f / 64.0f)) && (dY * dY < (1.0f / 64.0f)))\n                break;\n        }\n\n        *pX = (fX < MIN_VALUE) ? MIN_VALUE : (fX > MAX_VALUE) ? MAX_VALUE : fX;\n        *pY = (fY < MIN_VALUE) ? MIN_VALUE : (fY > MAX_VALUE) ? MAX_VALUE : fY;\n    }\n#pragma warning(pop)\n\n//-------------------------------------------------------------------------------------\n// Functions\n//-------------------------------------------------------------------------------------\n\n    typedef void (*BC_DECODE)(XMVECTOR *pColor, const uint8_t *pBC);\n    typedef void (*BC_ENCODE)(uint8_t *pDXT, const XMVECTOR *pColor, uint32_t flags);\n\n    void D3DXDecodeBC1(_Out_writes_(NUM_PIXELS_PER_BLOCK) XMVECTOR *pColor, _In_reads_(8) const uint8_t *pBC) noexcept;\n    void D3DXDecodeBC2(_Out_writes_(NUM_PIXELS_PER_BLOCK) XMVECTOR *pColor, _In_reads_(16) const uint8_t *pBC) noexcept;\n    void D3DXDecodeBC3(_Out_writes_(NUM_PIXELS_PER_BLOCK) XMVECTOR *pColor, _In_reads_(16) const uint8_t *pBC) noexcept;\n    void D3DXDecodeBC4U(_Out_writes_(NUM_PIXELS_PER_BLOCK) XMVECTOR *pColor, _In_reads_(8) const uint8_t *pBC) noexcept;\n    void D3DXDecodeBC4S(_Out_writes_(NUM_PIXELS_PER_BLOCK) XMVECTOR *pColor, _In_reads_(8) const uint8_t *pBC) noexcept;\n    void D3DXDecodeBC5U(_Out_writes_(NUM_PIXELS_PER_BLOCK) XMVECTOR *pColor, _In_reads_(16) const uint8_t *pBC) noexcept;\n    void D3DXDecodeBC5S(_Out_writes_(NUM_PIXELS_PER_BLOCK) XMVECTOR *pColor, _In_reads_(16) const uint8_t *pBC) noexcept;\n    void D3DXDecodeBC6HU(_Out_writes_(NUM_PIXELS_PER_BLOCK) XMVECTOR *pColor, _In_reads_(16) const uint8_t *pBC) noexcept;\n    void D3DXDecodeBC6HS(_Out_writes_(NUM_PIXELS_PER_BLOCK) XMVECTOR *pColor, _In_reads_(16) const uint8_t *pBC) noexcept;\n    void D3DXDecodeBC7(_Out_writes_(NUM_PIXELS_PER_BLOCK) XMVECTOR *pColor, _In_reads_(16) const uint8_t *pBC) noexcept;\n\n    void D3DXEncodeBC1(_Out_writes_(8) uint8_t *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const XMVECTOR *pColor, _In_ float threshold, _In_ uint32_t flags) noexcept;\n        // BC1 requires one additional parameter, so it doesn't match signature of BC_ENCODE above\n\n    void D3DXEncodeBC2(_Out_writes_(16) uint8_t *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const XMVECTOR *pColor, _In_ uint32_t flags) noexcept;\n    void D3DXEncodeBC3(_Out_writes_(16) uint8_t *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const XMVECTOR *pColor, _In_ uint32_t flags) noexcept;\n    void D3DXEncodeBC4U(_Out_writes_(8) uint8_t *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const XMVECTOR *pColor, _In_ uint32_t flags) noexcept;\n    void D3DXEncodeBC4S(_Out_writes_(8) uint8_t *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const XMVECTOR *pColor, _In_ uint32_t flags) noexcept;\n    void D3DXEncodeBC5U(_Out_writes_(16) uint8_t *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const XMVECTOR *pColor, _In_ uint32_t flags) noexcept;\n    void D3DXEncodeBC5S(_Out_writes_(16) uint8_t *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const XMVECTOR *pColor, _In_ uint32_t flags) noexcept;\n    void D3DXEncodeBC6HU(_Out_writes_(16) uint8_t *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const XMVECTOR *pColor, _In_ uint32_t flags) noexcept;\n    void D3DXEncodeBC6HS(_Out_writes_(16) uint8_t *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const XMVECTOR *pColor, _In_ uint32_t flags) noexcept;\n    void D3DXEncodeBC7(_Out_writes_(16) uint8_t *pBC, _In_reads_(NUM_PIXELS_PER_BLOCK) const XMVECTOR *pColor, _In_ uint32_t flags) noexcept;\n\n} // namespace\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/BC4BC5.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// BC4BC5.cpp\n//\n// Block-compression (BC) functionality for BC4 and BC5 (DirectX 10 texture compression)\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\n#include \"BC.h\"\n\nusing namespace DirectX;\n\n//------------------------------------------------------------------------------------\n// Constants\n//------------------------------------------------------------------------------------\n\n// Because these are used in SAL annotations, they need to remain macros rather than const values\n#define BLOCK_LEN 4\n// length of each block in texel\n\n#define BLOCK_SIZE (BLOCK_LEN * BLOCK_LEN)\n// total texels in a 4x4 block.\n\nnamespace\n{\n    //------------------------------------------------------------------------------------\n    // Structures\n    //-------------------------------------------------------------------------------------\n\n#pragma warning(push)\n#pragma warning(disable : 4201)\n\n    // BC4U/BC5U\n    struct BC4_UNORM\n    {\n        float R(size_t uOffset) const noexcept\n        {\n            const size_t uIndex = GetIndex(uOffset);\n            return DecodeFromIndex(uIndex);\n        }\n\n        float DecodeFromIndex(size_t uIndex) const noexcept\n        {\n            if (uIndex == 0)\n                return float(red_0) / 255.0f;\n            if (uIndex == 1)\n                return float(red_1) / 255.0f;\n            const float fred_0 = float(red_0) / 255.0f;\n            const float fred_1 = float(red_1) / 255.0f;\n            if (red_0 > red_1)\n            {\n                uIndex -= 1;\n                return (fred_0 * float(7u - uIndex) + fred_1 * float(uIndex)) / 7.0f;\n            }\n            else\n            {\n                if (uIndex == 6)\n                    return 0.0f;\n                if (uIndex == 7)\n                    return 1.0f;\n                uIndex -= 1;\n                return (fred_0 * float(5u - uIndex) + fred_1 * float(uIndex)) / 5.0f;\n            }\n        }\n\n        size_t GetIndex(size_t uOffset) const noexcept\n        {\n            return static_cast<size_t>((data >> (3 * uOffset + 16)) & 0x07);\n        }\n\n        void SetIndex(size_t uOffset, size_t uIndex) noexcept\n        {\n            data &= ~(uint64_t(0x07) << (3 * uOffset + 16));\n            data |= (uint64_t(uIndex) << (3 * uOffset + 16));\n        }\n\n        union\n        {\n            struct\n            {\n                uint8_t red_0;\n                uint8_t red_1;\n                uint8_t indices[6];\n            };\n            uint64_t data;\n        };\n    };\n\n    // BC4S/BC5S\n    struct BC4_SNORM\n    {\n        float R(size_t uOffset) const noexcept\n        {\n            const size_t uIndex = GetIndex(uOffset);\n            return DecodeFromIndex(uIndex);\n        }\n\n        float DecodeFromIndex(size_t uIndex) const noexcept\n        {\n            const int8_t sred_0 = (red_0 == -128) ? -127 : red_0;\n            const int8_t sred_1 = (red_1 == -128) ? -127 : red_1;\n\n            if (uIndex == 0)\n                return float(sred_0) / 127.0f;\n            if (uIndex == 1)\n                return float(sred_1) / 127.0f;\n            const float fred_0 = float(sred_0) / 127.0f;\n            const float fred_1 = float(sred_1) / 127.0f;\n            if (red_0 > red_1)\n            {\n                uIndex -= 1;\n                return (fred_0 * float(7u - uIndex) + fred_1 * float(uIndex)) / 7.0f;\n            }\n            else\n            {\n                if (uIndex == 6)\n                    return -1.0f;\n                if (uIndex == 7)\n                    return 1.0f;\n                uIndex -= 1;\n                return (fred_0 * float(5u - uIndex) + fred_1 * float(uIndex)) / 5.0f;\n            }\n        }\n\n        size_t GetIndex(size_t uOffset) const noexcept\n        {\n            return static_cast<size_t>((data >> (3 * uOffset + 16)) & 0x07);\n        }\n\n        void SetIndex(size_t uOffset, size_t uIndex) noexcept\n        {\n            data &= ~(uint64_t(0x07) << (3 * uOffset + 16));\n            data |= (uint64_t(uIndex) << (3 * uOffset + 16));\n        }\n\n        union\n        {\n            struct\n            {\n                int8_t red_0;\n                int8_t red_1;\n                uint8_t indices[6];\n            };\n            uint64_t data;\n        };\n    };\n\n#pragma warning(pop)\n\n    //-------------------------------------------------------------------------------------\n    // Convert a floating point value to an 8-bit SNORM\n    //-------------------------------------------------------------------------------------\n    void inline FloatToSNorm(_In_ float fVal, _Out_ int8_t *piSNorm) noexcept\n    {\n        constexpr uint32_t dwMostNeg = (1 << (8 * sizeof(int8_t) - 1));\n\n        if (isnan(fVal))\n            fVal = 0;\n        else\n            if (fVal > 1)\n                fVal = 1;    // Clamp to 1\n            else\n                if (fVal < -1)\n                    fVal = -1;    // Clamp to -1\n\n        fVal = fVal * static_cast<int8_t>(dwMostNeg - 1);\n\n        if (fVal >= 0)\n            fVal += .5f;\n        else\n            fVal -= .5f;\n\n        *piSNorm = static_cast<int8_t>(fVal);\n    }\n\n\n    //------------------------------------------------------------------------------\n    void FindEndPointsBC4U(\n        _In_reads_(BLOCK_SIZE) const float theTexelsU[],\n        _Out_ uint8_t &endpointU_0,\n        _Out_ uint8_t &endpointU_1) noexcept\n    {\n        // The boundary of codec for signed/unsigned format\n        constexpr float MIN_NORM = 0.f;\n        constexpr float MAX_NORM = 1.f;\n\n        // Find max/min of input texels\n        float fBlockMax = theTexelsU[0];\n        float fBlockMin = theTexelsU[0];\n        for (size_t i = 0; i < BLOCK_SIZE; ++i)\n        {\n            if (theTexelsU[i] < fBlockMin)\n            {\n                fBlockMin = theTexelsU[i];\n            }\n            else if (theTexelsU[i] > fBlockMax)\n            {\n                fBlockMax = theTexelsU[i];\n            }\n        }\n\n        //  If there are boundary values in input texels, should use 4 interpolated color values to guarantee\n        //  the exact code of the boundary values.\n        const bool bUsing4BlockCodec = (MIN_NORM == fBlockMin || MAX_NORM == fBlockMax);\n\n        // Using Optimize\n        float fStart, fEnd;\n\n        if (!bUsing4BlockCodec)\n        {\n            // 6 interpolated color values\n            OptimizeAlpha<false>(&fStart, &fEnd, theTexelsU, 8);\n\n            auto iStart = static_cast<uint8_t>(fStart * 255.0f);\n            auto iEnd = static_cast<uint8_t>(fEnd * 255.0f);\n\n            endpointU_0 = iEnd;\n            endpointU_1 = iStart;\n        }\n        else\n        {\n            // 4 interpolated color values\n            OptimizeAlpha<false>(&fStart, &fEnd, theTexelsU, 6);\n\n            auto iStart = static_cast<uint8_t>(fStart * 255.0f);\n            auto iEnd = static_cast<uint8_t>(fEnd * 255.0f);\n\n            endpointU_1 = iEnd;\n            endpointU_0 = iStart;\n        }\n    }\n\n    void FindEndPointsBC4S(\n        _In_reads_(BLOCK_SIZE) const float theTexelsU[],\n        _Out_ int8_t &endpointU_0,\n        _Out_ int8_t &endpointU_1) noexcept\n    {\n        //  The boundary of codec for signed/unsigned format\n        constexpr float MIN_NORM = -1.f;\n        constexpr float MAX_NORM = 1.f;\n\n        // Find max/min of input texels\n        float fBlockMax = theTexelsU[0];\n        float fBlockMin = theTexelsU[0];\n        for (size_t i = 0; i < BLOCK_SIZE; ++i)\n        {\n            if (theTexelsU[i] < fBlockMin)\n            {\n                fBlockMin = theTexelsU[i];\n            }\n            else if (theTexelsU[i] > fBlockMax)\n            {\n                fBlockMax = theTexelsU[i];\n            }\n        }\n\n        //  If there are boundary values in input texels, should use 4 interpolated color values to guarantee\n        //  the exact code of the boundary values.\n        const bool bUsing4BlockCodec = (MIN_NORM == fBlockMin || MAX_NORM == fBlockMax);\n\n        // Using Optimize\n        float fStart, fEnd;\n\n        if (!bUsing4BlockCodec)\n        {\n            // 6 interpolated color values\n            OptimizeAlpha<true>(&fStart, &fEnd, theTexelsU, 8);\n\n            int8_t iStart, iEnd;\n            FloatToSNorm(fStart, &iStart);\n            FloatToSNorm(fEnd, &iEnd);\n\n            endpointU_0 = iEnd;\n            endpointU_1 = iStart;\n        }\n        else\n        {\n            // 4 interpolated color values\n            OptimizeAlpha<true>(&fStart, &fEnd, theTexelsU, 6);\n\n            int8_t iStart, iEnd;\n            FloatToSNorm(fStart, &iStart);\n            FloatToSNorm(fEnd, &iEnd);\n\n            endpointU_1 = iEnd;\n            endpointU_0 = iStart;\n        }\n    }\n\n\n    //------------------------------------------------------------------------------\n    inline void FindEndPointsBC5U(\n        _In_reads_(BLOCK_SIZE) const float theTexelsU[],\n        _In_reads_(BLOCK_SIZE) const float theTexelsV[],\n        _Out_ uint8_t &endpointU_0,\n        _Out_ uint8_t &endpointU_1,\n        _Out_ uint8_t &endpointV_0,\n        _Out_ uint8_t &endpointV_1) noexcept\n    {\n        //Encoding the U and V channel by BC4 codec separately.\n        FindEndPointsBC4U(theTexelsU, endpointU_0, endpointU_1);\n        FindEndPointsBC4U(theTexelsV, endpointV_0, endpointV_1);\n    }\n\n    inline void FindEndPointsBC5S(\n        _In_reads_(BLOCK_SIZE) const float theTexelsU[],\n        _In_reads_(BLOCK_SIZE) const float theTexelsV[],\n        _Out_ int8_t &endpointU_0,\n        _Out_ int8_t &endpointU_1,\n        _Out_ int8_t &endpointV_0,\n        _Out_ int8_t &endpointV_1) noexcept\n    {\n        //Encoding the U and V channel by BC4 codec separately.\n        FindEndPointsBC4S(theTexelsU, endpointU_0, endpointU_1);\n        FindEndPointsBC4S(theTexelsV, endpointV_0, endpointV_1);\n    }\n\n\n    //------------------------------------------------------------------------------\n    void FindClosestUNORM(\n        _Inout_ BC4_UNORM* pBC,\n        _In_reads_(NUM_PIXELS_PER_BLOCK) const float theTexelsU[]) noexcept\n    {\n        float rGradient[8];\n        for (size_t i = 0; i < 8; ++i)\n        {\n            rGradient[i] = pBC->DecodeFromIndex(i);\n        }\n\n        for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n        {\n            size_t uBestIndex = 0;\n            float fBestDelta = 100000;\n            for (size_t uIndex = 0; uIndex < 8; uIndex++)\n            {\n                const float fCurrentDelta = fabsf(rGradient[uIndex] - theTexelsU[i]);\n                if (fCurrentDelta < fBestDelta)\n                {\n                    uBestIndex = uIndex;\n                    fBestDelta = fCurrentDelta;\n                }\n            }\n            pBC->SetIndex(i, uBestIndex);\n        }\n    }\n\n    void FindClosestSNORM(\n        _Inout_ BC4_SNORM* pBC,\n        _In_reads_(NUM_PIXELS_PER_BLOCK) const float theTexelsU[]) noexcept\n    {\n        float rGradient[8];\n        for (size_t i = 0; i < 8; ++i)\n        {\n            rGradient[i] = pBC->DecodeFromIndex(i);\n        }\n\n        for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n        {\n            size_t uBestIndex = 0;\n            float fBestDelta = 100000;\n            for (size_t uIndex = 0; uIndex < 8; uIndex++)\n            {\n                const float fCurrentDelta = fabsf(rGradient[uIndex] - theTexelsU[i]);\n                if (fCurrentDelta < fBestDelta)\n                {\n                    uBestIndex = uIndex;\n                    fBestDelta = fCurrentDelta;\n                }\n            }\n            pBC->SetIndex(i, uBestIndex);\n        }\n    }\n}\n\n\n//=====================================================================================\n// Entry points\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n// BC4 Compression\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nvoid DirectX::D3DXDecodeBC4U(XMVECTOR *pColor, const uint8_t *pBC) noexcept\n{\n    assert(pColor && pBC);\n    static_assert(sizeof(BC4_UNORM) == 8, \"BC4_UNORM should be 8 bytes\");\n\n    auto pBC4 = reinterpret_cast<const BC4_UNORM*>(pBC);\n\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n    #pragma prefast(suppress:22103, \"writing blocks in two halves confuses tool\")\n        pColor[i] = XMVectorSet(pBC4->R(i), 0, 0, 1.0f);\n    }\n}\n\n_Use_decl_annotations_\nvoid DirectX::D3DXDecodeBC4S(XMVECTOR *pColor, const uint8_t *pBC) noexcept\n{\n    assert(pColor && pBC);\n    static_assert(sizeof(BC4_SNORM) == 8, \"BC4_SNORM should be 8 bytes\");\n\n    auto pBC4 = reinterpret_cast<const BC4_SNORM*>(pBC);\n\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n    #pragma prefast(suppress:22103, \"writing blocks in two halves confuses tool\")\n        pColor[i] = XMVectorSet(pBC4->R(i), 0, 0, 1.0f);\n    }\n}\n\n_Use_decl_annotations_\nvoid DirectX::D3DXEncodeBC4U(uint8_t *pBC, const XMVECTOR *pColor, uint32_t flags) noexcept\n{\n    UNREFERENCED_PARAMETER(flags);\n\n    assert(pBC && pColor);\n    static_assert(sizeof(BC4_UNORM) == 8, \"BC4_UNORM should be 8 bytes\");\n\n    memset(pBC, 0, sizeof(BC4_UNORM));\n    auto pBC4 = reinterpret_cast<BC4_UNORM*>(pBC);\n    float theTexelsU[NUM_PIXELS_PER_BLOCK];\n\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n        theTexelsU[i] = XMVectorGetX(pColor[i]);\n    }\n\n    FindEndPointsBC4U(theTexelsU, pBC4->red_0, pBC4->red_1);\n    FindClosestUNORM(pBC4, theTexelsU);\n}\n\n_Use_decl_annotations_\nvoid DirectX::D3DXEncodeBC4S(uint8_t *pBC, const XMVECTOR *pColor, uint32_t flags) noexcept\n{\n    UNREFERENCED_PARAMETER(flags);\n\n    assert(pBC && pColor);\n    static_assert(sizeof(BC4_SNORM) == 8, \"BC4_SNORM should be 8 bytes\");\n\n    memset(pBC, 0, sizeof(BC4_UNORM));\n    auto pBC4 = reinterpret_cast<BC4_SNORM*>(pBC);\n    float theTexelsU[NUM_PIXELS_PER_BLOCK];\n\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n        theTexelsU[i] = XMVectorGetX(pColor[i]);\n    }\n\n    FindEndPointsBC4S(theTexelsU, pBC4->red_0, pBC4->red_1);\n    FindClosestSNORM(pBC4, theTexelsU);\n}\n\n\n//-------------------------------------------------------------------------------------\n// BC5 Compression\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nvoid DirectX::D3DXDecodeBC5U(XMVECTOR *pColor, const uint8_t *pBC) noexcept\n{\n    assert(pColor && pBC);\n    static_assert(sizeof(BC4_UNORM) == 8, \"BC4_UNORM should be 8 bytes\");\n\n    auto pBCR = reinterpret_cast<const BC4_UNORM*>(pBC);\n    auto pBCG = reinterpret_cast<const BC4_UNORM*>(pBC + sizeof(BC4_UNORM));\n\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n    #pragma prefast(suppress:22103, \"writing blocks in two halves confuses tool\")\n        pColor[i] = XMVectorSet(pBCR->R(i), pBCG->R(i), 0, 1.0f);\n    }\n}\n\n_Use_decl_annotations_\nvoid DirectX::D3DXDecodeBC5S(XMVECTOR *pColor, const uint8_t *pBC) noexcept\n{\n    assert(pColor && pBC);\n    static_assert(sizeof(BC4_SNORM) == 8, \"BC4_SNORM should be 8 bytes\");\n\n    auto pBCR = reinterpret_cast<const BC4_SNORM*>(pBC);\n    auto pBCG = reinterpret_cast<const BC4_SNORM*>(pBC + sizeof(BC4_SNORM));\n\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n    #pragma prefast(suppress:22103, \"writing blocks in two halves confuses tool\")\n        pColor[i] = XMVectorSet(pBCR->R(i), pBCG->R(i), 0, 1.0f);\n    }\n}\n\n_Use_decl_annotations_\nvoid DirectX::D3DXEncodeBC5U(uint8_t *pBC, const XMVECTOR *pColor, uint32_t flags) noexcept\n{\n    UNREFERENCED_PARAMETER(flags);\n\n    assert(pBC && pColor);\n    static_assert(sizeof(BC4_UNORM) == 8, \"BC4_UNORM should be 8 bytes\");\n\n    memset(pBC, 0, sizeof(BC4_UNORM) * 2);\n    auto pBCR = reinterpret_cast<BC4_UNORM*>(pBC);\n    auto pBCG = reinterpret_cast<BC4_UNORM*>(pBC + sizeof(BC4_UNORM));\n    float theTexelsU[NUM_PIXELS_PER_BLOCK];\n    float theTexelsV[NUM_PIXELS_PER_BLOCK];\n\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n        XMFLOAT4A clr;\n        XMStoreFloat4A(&clr, pColor[i]);\n        theTexelsU[i] = clr.x;\n        theTexelsV[i] = clr.y;\n    }\n\n    FindEndPointsBC5U(\n        theTexelsU,\n        theTexelsV,\n        pBCR->red_0,\n        pBCR->red_1,\n        pBCG->red_0,\n        pBCG->red_1);\n\n    FindClosestUNORM(pBCR, theTexelsU);\n    FindClosestUNORM(pBCG, theTexelsV);\n}\n\n_Use_decl_annotations_\nvoid DirectX::D3DXEncodeBC5S(uint8_t *pBC, const XMVECTOR *pColor, uint32_t flags) noexcept\n{\n    UNREFERENCED_PARAMETER(flags);\n\n    assert(pBC && pColor);\n    static_assert(sizeof(BC4_SNORM) == 8, \"BC4_SNORM should be 8 bytes\");\n\n    memset(pBC, 0, sizeof(BC4_UNORM) * 2);\n    auto pBCR = reinterpret_cast<BC4_SNORM*>(pBC);\n    auto pBCG = reinterpret_cast<BC4_SNORM*>(pBC + sizeof(BC4_SNORM));\n    float theTexelsU[NUM_PIXELS_PER_BLOCK];\n    float theTexelsV[NUM_PIXELS_PER_BLOCK];\n\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n        XMFLOAT4A clr;\n        XMStoreFloat4A(&clr, pColor[i]);\n        theTexelsU[i] = clr.x;\n        theTexelsV[i] = clr.y;\n    }\n\n    FindEndPointsBC5S(\n        theTexelsU,\n        theTexelsV,\n        pBCR->red_0,\n        pBCR->red_1,\n        pBCG->red_0,\n        pBCG->red_1);\n\n    FindClosestSNORM(pBCR, theTexelsU);\n    FindClosestSNORM(pBCG, theTexelsV);\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/BC6HBC7.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// BC6HBC7.cpp\n//\n// Block-compression (BC) functionality for BC6H and BC7 (DirectX 11 texture compression)\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\n#include \"BC.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::PackedVector;\n\n//-------------------------------------------------------------------------------------\n// Macros\n//-------------------------------------------------------------------------------------\n\n#define SIGN_EXTEND(x,nb) ((((x)&(1<<((nb)-1)))?((~0)^((1<<(nb))-1)):0)|(x))\n\n// Because these are used in SAL annotations, they need to remain macros rather than const values\n#define BC6H_MAX_REGIONS 2\n#define BC6H_MAX_INDICES 16\n#define BC7_MAX_REGIONS 3\n#define BC7_MAX_INDICES 16\n\nnamespace\n{\n    //-------------------------------------------------------------------------------------\n    // Constants\n    //-------------------------------------------------------------------------------------\n\n    constexpr uint16_t F16S_MASK = 0x8000;   // f16 sign mask\n    constexpr uint16_t F16EM_MASK = 0x7fff;   // f16 exp & mantissa mask\n    constexpr uint16_t F16MAX = 0x7bff;   // MAXFLT bit pattern for XMHALF\n\n    constexpr size_t BC6H_NUM_CHANNELS = 3;\n    constexpr size_t BC6H_MAX_SHAPES = 32;\n\n    constexpr size_t BC7_NUM_CHANNELS = 4;\n    constexpr size_t BC7_MAX_SHAPES = 64;\n\n    constexpr int32_t BC67_WEIGHT_MAX = 64;\n    constexpr uint32_t BC67_WEIGHT_SHIFT = 6;\n    constexpr int32_t BC67_WEIGHT_ROUND = 32;\n\n    constexpr float fEpsilon = (0.25f / 64.0f) * (0.25f / 64.0f);\n    constexpr float pC3[] = { 2.0f / 2.0f, 1.0f / 2.0f, 0.0f / 2.0f };\n    constexpr float pD3[] = { 0.0f / 2.0f, 1.0f / 2.0f, 2.0f / 2.0f };\n    constexpr float pC4[] = { 3.0f / 3.0f, 2.0f / 3.0f, 1.0f / 3.0f, 0.0f / 3.0f };\n    constexpr float pD4[] = { 0.0f / 3.0f, 1.0f / 3.0f, 2.0f / 3.0f, 3.0f / 3.0f };\n\n    // Partition, Shape, Pixel (index into 4x4 block)\n    const uint8_t g_aPartitionTable[3][64][16] =\n    {\n        {   // 1 Region case has no subsets (all 0)\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }\n        },\n\n        {   // BC6H/BC7 Partition Set for 2 Subsets\n            { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 }, // Shape 0\n            { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }, // Shape 1\n            { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 }, // Shape 2\n            { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 3\n            { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 }, // Shape 4\n            { 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 5\n            { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 6\n            { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 7\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 }, // Shape 8\n            { 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 9\n            { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 10\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 }, // Shape 11\n            { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 12\n            { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 13\n            { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 14\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 }, // Shape 15\n            { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1 }, // Shape 16\n            { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, // Shape 17\n            { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0 }, // Shape 18\n            { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, // Shape 19\n            { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, // Shape 20\n            { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 }, // Shape 21\n            { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 }, // Shape 22\n            { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1 }, // Shape 23\n            { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, // Shape 24\n            { 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 }, // Shape 25\n            { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 }, // Shape 26\n            { 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0 }, // Shape 27\n            { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 }, // Shape 28\n            { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, // Shape 29\n            { 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0 }, // Shape 30\n            { 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 }, // Shape 31\n\n                                                                // BC7 Partition Set for 2 Subsets (second-half)\n            { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 }, // Shape 32\n            { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 }, // Shape 33\n            { 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0 }, // Shape 34\n            { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0 }, // Shape 35\n            { 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0 }, // Shape 36\n            { 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0 }, // Shape 37\n            { 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1 }, // Shape 38\n            { 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 }, // Shape 39\n            { 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0 }, // Shape 40\n            { 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 }, // Shape 41\n            { 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 }, // Shape 42\n            { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 }, // Shape 43\n            { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }, // Shape 44\n            { 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1 }, // Shape 45\n            { 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 }, // Shape 46\n            { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 }, // Shape 47\n            { 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // Shape 48\n            { 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, // Shape 49\n            { 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0 }, // Shape 50\n            { 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 }, // Shape 51\n            { 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 }, // Shape 52\n            { 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1 }, // Shape 53\n            { 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0 }, // Shape 54\n            { 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0 }, // Shape 55\n            { 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 }, // Shape 56\n            { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1 }, // Shape 57\n            { 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 }, // Shape 58\n            { 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 }, // Shape 59\n            { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 }, // Shape 60\n            { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, // Shape 61\n            { 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 }, // Shape 62\n            { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1 }  // Shape 63\n        },\n\n        {   // BC7 Partition Set for 3 Subsets\n            { 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 1, 2, 2, 2, 2 }, // Shape 0\n            { 0, 0, 0, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1 }, // Shape 1\n            { 0, 0, 0, 0, 2, 0, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1 }, // Shape 2\n            { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 3\n            { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2 }, // Shape 4\n            { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 2, 2 }, // Shape 5\n            { 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 6\n            { 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1 }, // Shape 7\n            { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2 }, // Shape 8\n            { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 }, // Shape 9\n            { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 10\n            { 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2 }, // Shape 11\n            { 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2 }, // Shape 12\n            { 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2 }, // Shape 13\n            { 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2 }, // Shape 14\n            { 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0 }, // Shape 15\n            { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2 }, // Shape 16\n            { 0, 1, 1, 1, 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0 }, // Shape 17\n            { 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2 }, // Shape 18\n            { 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1 }, // Shape 19\n            { 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2 }, // Shape 20\n            { 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 2, 1 }, // Shape 21\n            { 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2 }, // Shape 22\n            { 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 1, 0, 2, 2, 1, 0 }, // Shape 23\n            { 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0 }, // Shape 24\n            { 0, 0, 1, 2, 0, 0, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2 }, // Shape 25\n            { 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1, 0, 1, 1, 0 }, // Shape 26\n            { 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1 }, // Shape 27\n            { 0, 0, 2, 2, 1, 1, 0, 2, 1, 1, 0, 2, 0, 0, 2, 2 }, // Shape 28\n            { 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 0, 2, 2, 2, 2, 2 }, // Shape 29\n            { 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1 }, // Shape 30\n            { 0, 0, 0, 0, 2, 0, 0, 0, 2, 2, 1, 1, 2, 2, 2, 1 }, // Shape 31\n            { 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 2, 2, 2 }, // Shape 32\n            { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 2, 0, 0, 1, 1 }, // Shape 33\n            { 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 2, 2, 0, 2, 2, 2 }, // Shape 34\n            { 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0 }, // Shape 35\n            { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0 }, // Shape 36\n            { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0 }, // Shape 37\n            { 0, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 0, 1, 2, 0 }, // Shape 38\n            { 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1 }, // Shape 39\n            { 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1 }, // Shape 40\n            { 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 41\n            { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1 }, // Shape 42\n            { 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2, 1, 1, 2, 2 }, // Shape 43\n            { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1 }, // Shape 44\n            { 0, 2, 2, 0, 1, 2, 2, 1, 0, 2, 2, 0, 1, 2, 2, 1 }, // Shape 45\n            { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 1 }, // Shape 46\n            { 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1 }, // Shape 47\n            { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2 }, // Shape 48\n            { 0, 2, 2, 2, 0, 1, 1, 1, 0, 2, 2, 2, 0, 1, 1, 1 }, // Shape 49\n            { 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2 }, // Shape 50\n            { 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2 }, // Shape 51\n            { 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2 }, // Shape 52\n            { 0, 0, 0, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2 }, // Shape 53\n            { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2 }, // Shape 54\n            { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2 }, // Shape 55\n            { 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 56\n            { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2 }, // Shape 57\n            { 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2 }, // Shape 58\n            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2 }, // Shape 59\n            { 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1 }, // Shape 60\n            { 0, 2, 2, 2, 1, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2 }, // Shape 61\n            { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 62\n            { 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 2, 2, 2, 0 }  // Shape 63\n        }\n    };\n\n    // Partition, Shape, Fixup\n    const uint8_t g_aFixUp[3][64][3] =\n    {\n        {   // No fix-ups for 1st subset for BC6H or BC7\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },\n            { 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 },{ 0, 0, 0 }\n        },\n\n        {   // BC6H/BC7 Partition Set Fixups for 2 Subsets\n            { 0,15, 0 },{ 0,15, 0 },{ 0,15, 0 },{ 0,15, 0 },\n            { 0,15, 0 },{ 0,15, 0 },{ 0,15, 0 },{ 0,15, 0 },\n            { 0,15, 0 },{ 0,15, 0 },{ 0,15, 0 },{ 0,15, 0 },\n            { 0,15, 0 },{ 0,15, 0 },{ 0,15, 0 },{ 0,15, 0 },\n            { 0,15, 0 },{ 0, 2, 0 },{ 0, 8, 0 },{ 0, 2, 0 },\n            { 0, 2, 0 },{ 0, 8, 0 },{ 0, 8, 0 },{ 0,15, 0 },\n            { 0, 2, 0 },{ 0, 8, 0 },{ 0, 2, 0 },{ 0, 2, 0 },\n            { 0, 8, 0 },{ 0, 8, 0 },{ 0, 2, 0 },{ 0, 2, 0 },\n\n            // BC7 Partition Set Fixups for 2 Subsets (second-half)\n            { 0,15, 0 },{ 0,15, 0 },{ 0, 6, 0 },{ 0, 8, 0 },\n            { 0, 2, 0 },{ 0, 8, 0 },{ 0,15, 0 },{ 0,15, 0 },\n            { 0, 2, 0 },{ 0, 8, 0 },{ 0, 2, 0 },{ 0, 2, 0 },\n            { 0, 2, 0 },{ 0,15, 0 },{ 0,15, 0 },{ 0, 6, 0 },\n            { 0, 6, 0 },{ 0, 2, 0 },{ 0, 6, 0 },{ 0, 8, 0 },\n            { 0,15, 0 },{ 0,15, 0 },{ 0, 2, 0 },{ 0, 2, 0 },\n            { 0,15, 0 },{ 0,15, 0 },{ 0,15, 0 },{ 0,15, 0 },\n            { 0,15, 0 },{ 0, 2, 0 },{ 0, 2, 0 },{ 0,15, 0 }\n        },\n\n        {   // BC7 Partition Set Fixups for 3 Subsets\n            { 0, 3,15 },{ 0, 3, 8 },{ 0,15, 8 },{ 0,15, 3 },\n            { 0, 8,15 },{ 0, 3,15 },{ 0,15, 3 },{ 0,15, 8 },\n            { 0, 8,15 },{ 0, 8,15 },{ 0, 6,15 },{ 0, 6,15 },\n            { 0, 6,15 },{ 0, 5,15 },{ 0, 3,15 },{ 0, 3, 8 },\n            { 0, 3,15 },{ 0, 3, 8 },{ 0, 8,15 },{ 0,15, 3 },\n            { 0, 3,15 },{ 0, 3, 8 },{ 0, 6,15 },{ 0,10, 8 },\n            { 0, 5, 3 },{ 0, 8,15 },{ 0, 8, 6 },{ 0, 6,10 },\n            { 0, 8,15 },{ 0, 5,15 },{ 0,15,10 },{ 0,15, 8 },\n            { 0, 8,15 },{ 0,15, 3 },{ 0, 3,15 },{ 0, 5,10 },\n            { 0, 6,10 },{ 0,10, 8 },{ 0, 8, 9 },{ 0,15,10 },\n            { 0,15, 6 },{ 0, 3,15 },{ 0,15, 8 },{ 0, 5,15 },\n            { 0,15, 3 },{ 0,15, 6 },{ 0,15, 6 },{ 0,15, 8 },\n            { 0, 3,15 },{ 0,15, 3 },{ 0, 5,15 },{ 0, 5,15 },\n            { 0, 5,15 },{ 0, 8,15 },{ 0, 5,15 },{ 0,10,15 },\n            { 0, 5,15 },{ 0,10,15 },{ 0, 8,15 },{ 0,13,15 },\n            { 0,15, 3 },{ 0,12,15 },{ 0, 3,15 },{ 0, 3, 8 }\n        }\n    };\n\n    const int g_aWeights2[] = { 0, 21, 43, 64 };\n    const int g_aWeights3[] = { 0, 9, 18, 27, 37, 46, 55, 64 };\n    const int g_aWeights4[] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };\n}\n\nnamespace DirectX\n{\n    class LDRColorA\n    {\n    public:\n        uint8_t r, g, b, a;\n\n        LDRColorA() = default;\n        LDRColorA(uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a) noexcept : r(_r), g(_g), b(_b), a(_a) {}\n\n        const uint8_t& operator [] (_In_range_(0, 3) size_t uElement) const noexcept\n        {\n            switch (uElement)\n            {\n            case 0: return r;\n            case 1: return g;\n            case 2: return b;\n            case 3: return a;\n            default: assert(false); return r;\n            }\n        }\n\n        uint8_t& operator [] (_In_range_(0, 3) size_t uElement) noexcept\n        {\n            switch (uElement)\n            {\n            case 0: return r;\n            case 1: return g;\n            case 2: return b;\n            case 3: return a;\n            default: assert(false); return r;\n            }\n        }\n\n        LDRColorA operator = (_In_ const HDRColorA& c) noexcept\n        {\n            LDRColorA ret;\n            HDRColorA tmp(c);\n            tmp = tmp.Clamp(0.0f, 1.0f) * 255.0f;\n            ret.r = uint8_t(tmp.r + 0.001f);\n            ret.g = uint8_t(tmp.g + 0.001f);\n            ret.b = uint8_t(tmp.b + 0.001f);\n            ret.a = uint8_t(tmp.a + 0.001f);\n            return ret;\n        }\n\n        static void InterpolateRGB(_In_ const LDRColorA& c0, _In_ const LDRColorA& c1, _In_ size_t wc, _In_ _In_range_(2, 4) size_t wcprec, _Out_ LDRColorA& out) noexcept\n        {\n            const int* aWeights = nullptr;\n            switch (wcprec)\n            {\n            case 2: aWeights = g_aWeights2; assert(wc < 4); _Analysis_assume_(wc < 4); break;\n            case 3: aWeights = g_aWeights3; assert(wc < 8); _Analysis_assume_(wc < 8); break;\n            case 4: aWeights = g_aWeights4; assert(wc < 16); _Analysis_assume_(wc < 16); break;\n            default: assert(false); out.r = out.g = out.b = 0; return;\n            }\n            out.r = uint8_t((uint32_t(c0.r) * uint32_t(BC67_WEIGHT_MAX - aWeights[wc]) + uint32_t(c1.r) * uint32_t(aWeights[wc]) + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT);\n            out.g = uint8_t((uint32_t(c0.g) * uint32_t(BC67_WEIGHT_MAX - aWeights[wc]) + uint32_t(c1.g) * uint32_t(aWeights[wc]) + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT);\n            out.b = uint8_t((uint32_t(c0.b) * uint32_t(BC67_WEIGHT_MAX - aWeights[wc]) + uint32_t(c1.b) * uint32_t(aWeights[wc]) + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT);\n        }\n\n        static void InterpolateA(_In_ const LDRColorA& c0, _In_ const LDRColorA& c1, _In_ size_t wa, _In_range_(2, 4) _In_ size_t waprec, _Out_ LDRColorA& out) noexcept\n        {\n            const int* aWeights = nullptr;\n            switch (waprec)\n            {\n            case 2: aWeights = g_aWeights2; assert(wa < 4); _Analysis_assume_(wa < 4); break;\n            case 3: aWeights = g_aWeights3; assert(wa < 8); _Analysis_assume_(wa < 8); break;\n            case 4: aWeights = g_aWeights4; assert(wa < 16); _Analysis_assume_(wa < 16); break;\n            default: assert(false); out.a = 0; return;\n            }\n            out.a = uint8_t((uint32_t(c0.a) * uint32_t(BC67_WEIGHT_MAX - aWeights[wa]) + uint32_t(c1.a) * uint32_t(aWeights[wa]) + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT);\n        }\n\n        static void Interpolate(_In_ const LDRColorA& c0, _In_ const LDRColorA& c1, _In_ size_t wc, _In_ size_t wa, _In_ _In_range_(2, 4) size_t wcprec, _In_ _In_range_(2, 4) size_t waprec, _Out_ LDRColorA& out) noexcept\n        {\n            InterpolateRGB(c0, c1, wc, wcprec, out);\n            InterpolateA(c0, c1, wa, waprec, out);\n        }\n    };\n\n    static_assert(sizeof(LDRColorA) == 4, \"Unexpected packing\");\n\n    struct LDREndPntPair\n    {\n        LDRColorA A;\n        LDRColorA B;\n    };\n\n    inline HDRColorA::HDRColorA(const LDRColorA& c) noexcept\n    {\n        r = float(c.r) * (1.0f / 255.0f);\n        g = float(c.g) * (1.0f / 255.0f);\n        b = float(c.b) * (1.0f / 255.0f);\n        a = float(c.a) * (1.0f / 255.0f);\n    }\n\n    inline HDRColorA& HDRColorA::operator = (const LDRColorA& c) noexcept\n    {\n        r = static_cast<float>(c.r);\n        g = static_cast<float>(c.g);\n        b = static_cast<float>(c.b);\n        a = static_cast<float>(c.a);\n        return *this;\n    }\n\n    inline LDRColorA HDRColorA::ToLDRColorA() const noexcept\n    {\n        return LDRColorA(static_cast<uint8_t>(r + 0.01f), static_cast<uint8_t>(g + 0.01f), static_cast<uint8_t>(b + 0.01f), static_cast<uint8_t>(a + 0.01f));\n    }\n}\n\nnamespace\n{\n    class INTColor\n    {\n    public:\n        int r, g, b;\n        int pad;\n\n    public:\n        INTColor() = default;\n        INTColor(int nr, int ng, int nb) noexcept : r(nr), g(ng), b(nb), pad(0) {}\n        INTColor(const INTColor& c) noexcept : r(c.r), g(c.g), b(c.b), pad(0) {}\n        INTColor& operator=(const INTColor& c) noexcept\n        {\n            r = c.r;\n            g = c.g;\n            b = c.b;\n            pad = 0;\n\n            return *this;\n        }\n\n        INTColor& operator += (_In_ const INTColor& c) noexcept\n        {\n            r += c.r;\n            g += c.g;\n            b += c.b;\n            return *this;\n        }\n\n        INTColor& operator -= (_In_ const INTColor& c) noexcept\n        {\n            r -= c.r;\n            g -= c.g;\n            b -= c.b;\n            return *this;\n        }\n\n        INTColor& operator &= (_In_ const INTColor& c) noexcept\n        {\n            r &= c.r;\n            g &= c.g;\n            b &= c.b;\n            return *this;\n        }\n\n        int& operator [] (_In_ uint8_t i) noexcept\n        {\n            assert(i < sizeof(INTColor) / sizeof(int));\n            _Analysis_assume_(i < sizeof(INTColor) / sizeof(int));\n            return reinterpret_cast<int*>(this)[i];\n        }\n\n        void Set(_In_ const HDRColorA& c, _In_ bool bSigned) noexcept\n        {\n            PackedVector::XMHALF4 aF16;\n\n            const XMVECTOR v = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(&c));\n            XMStoreHalf4(&aF16, v);\n\n            r = F16ToINT(aF16.x, bSigned);\n            g = F16ToINT(aF16.y, bSigned);\n            b = F16ToINT(aF16.z, bSigned);\n        }\n\n        INTColor& Clamp(_In_ int iMin, _In_ int iMax) noexcept\n        {\n            r = std::min<int>(iMax, std::max<int>(iMin, r));\n            g = std::min<int>(iMax, std::max<int>(iMin, g));\n            b = std::min<int>(iMax, std::max<int>(iMin, b));\n            return *this;\n        }\n\n        INTColor& SignExtend(_In_ const LDRColorA& Prec) noexcept\n        {\n            r = SIGN_EXTEND(r, int(Prec.r));\n            g = SIGN_EXTEND(g, int(Prec.g));\n            b = SIGN_EXTEND(b, int(Prec.b));\n            return *this;\n        }\n\n        void ToF16(_Out_writes_(3) PackedVector::HALF aF16[3], _In_ bool bSigned) const noexcept\n        {\n            aF16[0] = INT2F16(r, bSigned);\n            aF16[1] = INT2F16(g, bSigned);\n            aF16[2] = INT2F16(b, bSigned);\n        }\n\n    private:\n        static int F16ToINT(_In_ const PackedVector::HALF& f, _In_ bool bSigned) noexcept\n        {\n            uint16_t input = *reinterpret_cast<const uint16_t*>(&f);\n            int out, s;\n            if (bSigned)\n            {\n                s = input & F16S_MASK;\n                input &= F16EM_MASK;\n                if (input > F16MAX) out = F16MAX;\n                else out = input;\n                out = s ? -out : out;\n            }\n            else\n            {\n                if (input & F16S_MASK) out = 0;\n                else out = input;\n            }\n            return out;\n        }\n\n        static PackedVector::HALF INT2F16(_In_ int input, _In_ bool bSigned) noexcept\n        {\n            PackedVector::HALF h;\n            uint16_t out;\n            if (bSigned)\n            {\n                int s = 0;\n                if (input < 0)\n                {\n                    s = F16S_MASK;\n                    input = -input;\n                }\n                out = uint16_t(s | input);\n            }\n            else\n            {\n                assert(input >= 0 && input <= F16MAX);\n                out = static_cast<uint16_t>(input);\n            }\n\n            *reinterpret_cast<uint16_t*>(&h) = out;\n            return h;\n        }\n    };\n\n    static_assert(sizeof(INTColor) == 16, \"Unexpected packing\");\n\n    struct INTEndPntPair\n    {\n        INTColor A;\n        INTColor B;\n    };\n\n    template< size_t SizeInBytes >\n    class CBits\n    {\n    public:\n        uint8_t GetBit(_Inout_ size_t& uStartBit) const noexcept\n        {\n            assert(uStartBit < 128);\n            _Analysis_assume_(uStartBit < 128);\n            const size_t uIndex = uStartBit >> 3;\n            auto const ret = static_cast<uint8_t>((m_uBits[uIndex] >> (uStartBit - (uIndex << 3))) & 0x01);\n            uStartBit++;\n            return ret;\n        }\n\n        uint8_t GetBits(_Inout_ size_t& uStartBit, _In_ size_t uNumBits) const noexcept\n        {\n            if (uNumBits == 0) return 0;\n            assert(uStartBit + uNumBits <= 128 && uNumBits <= 8);\n            _Analysis_assume_(uStartBit + uNumBits <= 128 && uNumBits <= 8);\n            uint8_t ret;\n            const size_t uIndex = uStartBit >> 3;\n            const size_t uBase = uStartBit - (uIndex << 3);\n            if (uBase + uNumBits > 8)\n            {\n                const size_t uFirstIndexBits = 8 - uBase;\n                const size_t uNextIndexBits = uNumBits - uFirstIndexBits;\n                ret = static_cast<uint8_t>((unsigned(m_uBits[uIndex]) >> uBase) | ((unsigned(m_uBits[uIndex + 1]) & ((1u << uNextIndexBits) - 1)) << uFirstIndexBits));\n            }\n            else\n            {\n                ret = static_cast<uint8_t>((m_uBits[uIndex] >> uBase) & ((1 << uNumBits) - 1));\n            }\n            assert(ret < (1 << uNumBits));\n            uStartBit += uNumBits;\n            return ret;\n        }\n\n        void SetBit(_Inout_ size_t& uStartBit, _In_ uint8_t uValue) noexcept\n        {\n            assert(uStartBit < 128 && uValue < 2);\n            _Analysis_assume_(uStartBit < 128 && uValue < 2);\n            size_t uIndex = uStartBit >> 3;\n            const size_t uBase = uStartBit - (uIndex << 3);\n            m_uBits[uIndex] &= ~(1 << uBase);\n            m_uBits[uIndex] |= uValue << uBase;\n            uStartBit++;\n        }\n\n        void SetBits(_Inout_ size_t& uStartBit, _In_ size_t uNumBits, _In_ uint8_t uValue) noexcept\n        {\n            if (uNumBits == 0)\n                return;\n            assert(uStartBit + uNumBits <= 128 && uNumBits <= 8);\n            _Analysis_assume_(uStartBit + uNumBits <= 128 && uNumBits <= 8);\n            assert(uValue < (1 << uNumBits));\n            size_t uIndex = uStartBit >> 3;\n            const size_t uBase = uStartBit - (uIndex << 3);\n            if (uBase + uNumBits > 8)\n            {\n                const size_t uFirstIndexBits = 8 - uBase;\n                const size_t uNextIndexBits = uNumBits - uFirstIndexBits;\n                m_uBits[uIndex] &= ~(((1 << uFirstIndexBits) - 1) << uBase);\n                m_uBits[uIndex] |= uValue << uBase;\n                m_uBits[uIndex + 1] &= ~((1 << uNextIndexBits) - 1);\n                m_uBits[uIndex + 1] |= uValue >> uFirstIndexBits;\n            }\n            else\n            {\n                m_uBits[uIndex] &= ~(((1 << uNumBits) - 1) << uBase);\n                m_uBits[uIndex] |= uValue << uBase;\n            }\n            uStartBit += uNumBits;\n        }\n\n    private:\n        uint8_t m_uBits[SizeInBytes];\n    };\n\n    // BC6H compression (16 bits per texel)\n    class D3DX_BC6H : private CBits< 16 >\n    {\n    public:\n        void Decode(_In_ bool bSigned, _Out_writes_(NUM_PIXELS_PER_BLOCK) HDRColorA* pOut) const noexcept;\n        void Encode(_In_ bool bSigned, _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA* const pIn) noexcept;\n\n    private:\n    #pragma warning(push)\n    #pragma warning(disable : 4480)\n        enum EField : uint8_t\n        {\n            NA, // N/A\n            M,  // Mode\n            D,  // Shape\n            RW,\n            RX,\n            RY,\n            RZ,\n            GW,\n            GX,\n            GY,\n            GZ,\n            BW,\n            BX,\n            BY,\n            BZ,\n        };\n    #pragma warning(pop)\n\n        struct ModeDescriptor\n        {\n            EField m_eField;\n            uint8_t   m_uBit;\n        };\n\n        struct ModeInfo\n        {\n            uint8_t uMode;\n            uint8_t uPartitions;\n            bool bTransformed;\n            uint8_t uIndexPrec;\n            LDRColorA RGBAPrec[BC6H_MAX_REGIONS][2];\n        };\n\n    #pragma warning(push)\n    #pragma warning(disable : 4512)\n        struct EncodeParams\n        {\n            float fBestErr;\n            const bool bSigned;\n            uint8_t uMode;\n            uint8_t uShape;\n            const HDRColorA* const aHDRPixels;\n            INTEndPntPair aUnqEndPts[BC6H_MAX_SHAPES][BC6H_MAX_REGIONS];\n            INTColor aIPixels[NUM_PIXELS_PER_BLOCK];\n\n            EncodeParams(const HDRColorA* const aOriginal, bool bSignedFormat) noexcept :\n                fBestErr(FLT_MAX), bSigned(bSignedFormat), uMode(0), uShape(0), aHDRPixels(aOriginal), aUnqEndPts{}, aIPixels{}\n            {\n                for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n                {\n                    aIPixels[i].Set(aOriginal[i], bSigned);\n                }\n            }\n        };\n    #pragma warning(pop)\n\n        static int Quantize(_In_ int iValue, _In_ int prec, _In_ bool bSigned) noexcept;\n        static int Unquantize(_In_ int comp, _In_ uint8_t uBitsPerComp, _In_ bool bSigned) noexcept;\n        static int FinishUnquantize(_In_ int comp, _In_ bool bSigned) noexcept;\n\n        static bool EndPointsFit(_In_ const EncodeParams* pEP, _In_reads_(BC6H_MAX_REGIONS) const INTEndPntPair aEndPts[]) noexcept;\n\n        void GeneratePaletteQuantized(_In_ const EncodeParams* pEP, _In_ const INTEndPntPair& endPts,\n            _Out_writes_(BC6H_MAX_INDICES) INTColor aPalette[]) const noexcept;\n        float MapColorsQuantized(_In_ const EncodeParams* pEP, _In_reads_(np) const INTColor aColors[], _In_ size_t np, _In_ const INTEndPntPair &endPts) const noexcept;\n        float PerturbOne(_In_ const EncodeParams* pEP, _In_reads_(np) const INTColor aColors[], _In_ size_t np, _In_ uint8_t ch,\n            _In_ const INTEndPntPair& oldEndPts, _Out_ INTEndPntPair& newEndPts, _In_ float fOldErr, _In_ int do_b) const noexcept;\n        void OptimizeOne(_In_ const EncodeParams* pEP, _In_reads_(np) const INTColor aColors[], _In_ size_t np, _In_ float aOrgErr,\n            _In_ const INTEndPntPair &aOrgEndPts, _Out_ INTEndPntPair &aOptEndPts) const noexcept;\n        void OptimizeEndPoints(_In_ const EncodeParams* pEP, _In_reads_(BC6H_MAX_REGIONS) const float aOrgErr[],\n            _In_reads_(BC6H_MAX_REGIONS) const INTEndPntPair aOrgEndPts[],\n            _Out_writes_all_(BC6H_MAX_REGIONS) INTEndPntPair aOptEndPts[]) const noexcept;\n        static void SwapIndices(_In_ const EncodeParams* pEP, _Inout_updates_all_(BC6H_MAX_REGIONS) INTEndPntPair aEndPts[],\n            _In_reads_(NUM_PIXELS_PER_BLOCK) size_t aIndices[]) noexcept;\n        void AssignIndices(_In_ const EncodeParams* pEP, _In_reads_(BC6H_MAX_REGIONS) const INTEndPntPair aEndPts[],\n            _Out_writes_(NUM_PIXELS_PER_BLOCK) size_t aIndices[],\n            _Out_writes_(BC6H_MAX_REGIONS) float aTotErr[]) const noexcept;\n        void QuantizeEndPts(_In_ const EncodeParams* pEP, _Out_writes_(BC6H_MAX_REGIONS) INTEndPntPair* qQntEndPts) const noexcept;\n        void EmitBlock(_In_ const EncodeParams* pEP, _In_reads_(BC6H_MAX_REGIONS) const INTEndPntPair aEndPts[],\n            _In_reads_(NUM_PIXELS_PER_BLOCK) const size_t aIndices[]) noexcept;\n        void Refine(_Inout_ EncodeParams* pEP) noexcept;\n\n        static void GeneratePaletteUnquantized(_In_ const EncodeParams* pEP, _In_ size_t uRegion, _Out_writes_(BC6H_MAX_INDICES) INTColor aPalette[]) noexcept;\n        float MapColors(_In_ const EncodeParams* pEP, _In_ size_t uRegion, _In_ size_t np, _In_reads_(np) const size_t* auIndex) const noexcept;\n        float RoughMSE(_Inout_ EncodeParams* pEP) const noexcept;\n\n    private:\n        static const ModeDescriptor ms_aDesc[][82];\n        static const ModeInfo ms_aInfo[];\n        static const int ms_aModeToInfo[];\n    };\n\n    // BC67 compression (16b bits per texel)\n    class D3DX_BC7 : private CBits< 16 >\n    {\n    public:\n        void Decode(_Out_writes_(NUM_PIXELS_PER_BLOCK) HDRColorA* pOut) const noexcept;\n        void Encode(uint32_t flags, _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA* const pIn) noexcept;\n\n    private:\n        struct ModeInfo\n        {\n            uint8_t uPartitions;\n            uint8_t uPartitionBits;\n            uint8_t uPBits;\n            uint8_t uRotationBits;\n            uint8_t uIndexModeBits;\n            uint8_t uIndexPrec;\n            uint8_t uIndexPrec2;\n            LDRColorA RGBAPrec;\n            LDRColorA RGBAPrecWithP;\n        };\n\n    #pragma warning(push)\n    #pragma warning(disable : 4512)\n        struct EncodeParams\n        {\n            uint8_t uMode;\n            LDREndPntPair aEndPts[BC7_MAX_SHAPES][BC7_MAX_REGIONS];\n            LDRColorA aLDRPixels[NUM_PIXELS_PER_BLOCK];\n            const HDRColorA* const aHDRPixels;\n\n            EncodeParams(const HDRColorA* const aOriginal) noexcept : uMode(0), aEndPts{}, aLDRPixels{}, aHDRPixels(aOriginal) {}\n        };\n    #pragma warning(pop)\n\n        static uint8_t Quantize(_In_ uint8_t comp, _In_ uint8_t uPrec) noexcept\n        {\n            assert(0 < uPrec && uPrec <= 8);\n            const uint8_t rnd = std::min<uint8_t>(255u, static_cast<uint8_t>(unsigned(comp) + (1u << (7 - uPrec))));\n            return uint8_t(rnd >> (8u - uPrec));\n        }\n\n        static LDRColorA Quantize(_In_ const LDRColorA& c, _In_ const LDRColorA& RGBAPrec) noexcept\n        {\n            LDRColorA q;\n            q.r = Quantize(c.r, RGBAPrec.r);\n            q.g = Quantize(c.g, RGBAPrec.g);\n            q.b = Quantize(c.b, RGBAPrec.b);\n            if (RGBAPrec.a)\n                q.a = Quantize(c.a, RGBAPrec.a);\n            else\n                q.a = 255;\n            return q;\n        }\n\n        static uint8_t Unquantize(_In_ uint8_t comp, _In_ size_t uPrec) noexcept\n        {\n            assert(0 < uPrec && uPrec <= 8);\n            comp = static_cast<uint8_t>(unsigned(comp) << (8 - uPrec));\n            return uint8_t(comp | (comp >> uPrec));\n        }\n\n        static LDRColorA Unquantize(_In_ const LDRColorA& c, _In_ const LDRColorA& RGBAPrec) noexcept\n        {\n            LDRColorA q;\n            q.r = Unquantize(c.r, RGBAPrec.r);\n            q.g = Unquantize(c.g, RGBAPrec.g);\n            q.b = Unquantize(c.b, RGBAPrec.b);\n            q.a = RGBAPrec.a > 0 ? Unquantize(c.a, RGBAPrec.a) : 255u;\n            return q;\n        }\n\n        void GeneratePaletteQuantized(_In_ const EncodeParams* pEP, _In_ size_t uIndexMode, _In_ const LDREndPntPair& endpts,\n            _Out_writes_(BC7_MAX_INDICES) LDRColorA aPalette[]) const noexcept;\n        float PerturbOne(_In_ const EncodeParams* pEP, _In_reads_(np) const LDRColorA colors[], _In_ size_t np, _In_ size_t uIndexMode,\n            _In_ size_t ch, _In_ const LDREndPntPair &old_endpts,\n            _Out_ LDREndPntPair &new_endpts, _In_ float old_err, _In_ uint8_t do_b) const noexcept;\n        void Exhaustive(_In_ const EncodeParams* pEP, _In_reads_(np) const LDRColorA aColors[], _In_ size_t np, _In_ size_t uIndexMode,\n            _In_ size_t ch, _Inout_ float& fOrgErr, _Inout_ LDREndPntPair& optEndPt) const noexcept;\n        void OptimizeOne(_In_ const EncodeParams* pEP, _In_reads_(np) const LDRColorA colors[], _In_ size_t np, _In_ size_t uIndexMode,\n            _In_ float orig_err, _In_ const LDREndPntPair &orig_endpts, _Out_ LDREndPntPair &opt_endpts) const noexcept;\n        void OptimizeEndPoints(_In_ const EncodeParams* pEP, _In_ size_t uShape, _In_ size_t uIndexMode,\n            _In_reads_(BC7_MAX_REGIONS) const float orig_err[],\n            _In_reads_(BC7_MAX_REGIONS) const LDREndPntPair orig_endpts[],\n            _Out_writes_(BC7_MAX_REGIONS) LDREndPntPair opt_endpts[]) const noexcept;\n        void AssignIndices(_In_ const EncodeParams* pEP, _In_ size_t uShape, _In_ size_t uIndexMode,\n            _In_reads_(BC7_MAX_REGIONS) LDREndPntPair endpts[],\n            _Out_writes_(NUM_PIXELS_PER_BLOCK) size_t aIndices[], _Out_writes_(NUM_PIXELS_PER_BLOCK) size_t aIndices2[],\n            _Out_writes_(BC7_MAX_REGIONS) float afTotErr[]) const noexcept;\n        void EmitBlock(_In_ const EncodeParams* pEP, _In_ size_t uShape, _In_ size_t uRotation, _In_ size_t uIndexMode,\n            _In_reads_(BC7_MAX_REGIONS) const LDREndPntPair aEndPts[],\n            _In_reads_(NUM_PIXELS_PER_BLOCK) const size_t aIndex[],\n            _In_reads_(NUM_PIXELS_PER_BLOCK) const size_t aIndex2[]) noexcept;\n        void FixEndpointPBits(_In_ const EncodeParams* pEP, _In_reads_(BC7_MAX_REGIONS) const LDREndPntPair *pOrigEndpoints, _Out_writes_(BC7_MAX_REGIONS) LDREndPntPair *pFixedEndpoints) noexcept;\n        float Refine(_In_ const EncodeParams* pEP, _In_ size_t uShape, _In_ size_t uRotation, _In_ size_t uIndexMode) noexcept;\n\n        float MapColors(_In_ const EncodeParams* pEP, _In_reads_(np) const LDRColorA aColors[], _In_ size_t np, _In_ size_t uIndexMode,\n            _In_ const LDREndPntPair& endPts, _In_ float fMinErr) const noexcept;\n        static float RoughMSE(_Inout_ EncodeParams* pEP, _In_ size_t uShape, _In_ size_t uIndexMode) noexcept;\n\n    private:\n        static const ModeInfo ms_aInfo[];\n    };\n}\n\n// BC6H Compression\nconst D3DX_BC6H::ModeDescriptor D3DX_BC6H::ms_aDesc[14][82] =\n{\n    {   // Mode 1 (0x00) - 10 5 5 5\n        { M, 0}, { M, 1}, {GY, 4}, {BY, 4}, {BZ, 4}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {RW, 6}, {RW, 7}, {RW, 8}, {RW, 9}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GW, 6}, {GW, 7}, {GW, 8}, {GW, 9}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {BW, 6}, {BW, 7}, {BW, 8}, {BW, 9}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RX, 4},\n        {GZ, 4}, {GY, 0}, {GY, 1}, {GY, 2}, {GY, 3}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GX, 4},\n        {BZ, 0}, {GZ, 0}, {GZ, 1}, {GZ, 2}, {GZ, 3}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BX, 4},\n        {BZ, 1}, {BY, 0}, {BY, 1}, {BY, 2}, {BY, 3}, {RY, 0}, {RY, 1}, {RY, 2}, {RY, 3}, {RY, 4},\n        {BZ, 2}, {RZ, 0}, {RZ, 1}, {RZ, 2}, {RZ, 3}, {RZ, 4}, {BZ, 3}, { D, 0}, { D, 1}, { D, 2},\n        { D, 3}, { D, 4},\n    },\n\n    {   // Mode 2 (0x01) - 7 6 6 6\n        { M, 0}, { M, 1}, {GY, 5}, {GZ, 4}, {GZ, 5}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {RW, 6}, {BZ, 0}, {BZ, 1}, {BY, 4}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GW, 6}, {BY, 5}, {BZ, 2}, {GY, 4}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {BW, 6}, {BZ, 3}, {BZ, 5}, {BZ, 4}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RX, 4},\n        {RX, 5}, {GY, 0}, {GY, 1}, {GY, 2}, {GY, 3}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GX, 4},\n        {GX, 5}, {GZ, 0}, {GZ, 1}, {GZ, 2}, {GZ, 3}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BX, 4},\n        {BX, 5}, {BY, 0}, {BY, 1}, {BY, 2}, {BY, 3}, {RY, 0}, {RY, 1}, {RY, 2}, {RY, 3}, {RY, 4},\n        {RY, 5}, {RZ, 0}, {RZ, 1}, {RZ, 2}, {RZ, 3}, {RZ, 4}, {RZ, 5}, { D, 0}, { D, 1}, { D, 2},\n        { D, 3}, { D, 4},\n    },\n\n    {   // Mode 3 (0x02) - 11 5 4 4\n        { M, 0}, { M, 1}, { M, 2}, { M, 3}, { M, 4}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {RW, 6}, {RW, 7}, {RW, 8}, {RW, 9}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GW, 6}, {GW, 7}, {GW, 8}, {GW, 9}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {BW, 6}, {BW, 7}, {BW, 8}, {BW, 9}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RX, 4},\n        {RW,10}, {GY, 0}, {GY, 1}, {GY, 2}, {GY, 3}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GW,10},\n        {BZ, 0}, {GZ, 0}, {GZ, 1}, {GZ, 2}, {GZ, 3}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BW,10},\n        {BZ, 1}, {BY, 0}, {BY, 1}, {BY, 2}, {BY, 3}, {RY, 0}, {RY, 1}, {RY, 2}, {RY, 3}, {RY, 4},\n        {BZ, 2}, {RZ, 0}, {RZ, 1}, {RZ, 2}, {RZ, 3}, {RZ, 4}, {BZ, 3}, { D, 0}, { D, 1}, { D, 2},\n        { D, 3}, { D, 4},\n    },\n\n    {   // Mode 4 (0x06) - 11 4 5 4\n        { M, 0}, { M, 1}, { M, 2}, { M, 3}, { M, 4}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {RW, 6}, {RW, 7}, {RW, 8}, {RW, 9}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GW, 6}, {GW, 7}, {GW, 8}, {GW, 9}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {BW, 6}, {BW, 7}, {BW, 8}, {BW, 9}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RW,10},\n        {GZ, 4}, {GY, 0}, {GY, 1}, {GY, 2}, {GY, 3}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GX, 4},\n        {GW,10}, {GZ, 0}, {GZ, 1}, {GZ, 2}, {GZ, 3}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BW,10},\n        {BZ, 1}, {BY, 0}, {BY, 1}, {BY, 2}, {BY, 3}, {RY, 0}, {RY, 1}, {RY, 2}, {RY, 3}, {BZ, 0},\n        {BZ, 2}, {RZ, 0}, {RZ, 1}, {RZ, 2}, {RZ, 3}, {GY, 4}, {BZ, 3}, { D, 0}, { D, 1}, { D, 2},\n        { D, 3}, { D, 4},\n    },\n\n    {   // Mode 5 (0x0a) - 11 4 4 5\n        { M, 0}, { M, 1}, { M, 2}, { M, 3}, { M, 4}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {RW, 6}, {RW, 7}, {RW, 8}, {RW, 9}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GW, 6}, {GW, 7}, {GW, 8}, {GW, 9}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {BW, 6}, {BW, 7}, {BW, 8}, {BW, 9}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RW,10},\n        {BY, 4}, {GY, 0}, {GY, 1}, {GY, 2}, {GY, 3}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GW,10},\n        {BZ, 0}, {GZ, 0}, {GZ, 1}, {GZ, 2}, {GZ, 3}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BX, 4},\n        {BW,10}, {BY, 0}, {BY, 1}, {BY, 2}, {BY, 3}, {RY, 0}, {RY, 1}, {RY, 2}, {RY, 3}, {BZ, 1},\n        {BZ, 2}, {RZ, 0}, {RZ, 1}, {RZ, 2}, {RZ, 3}, {BZ, 4}, {BZ, 3}, { D, 0}, { D, 1}, { D, 2},\n        { D, 3}, { D, 4},\n    },\n\n    {   // Mode 6 (0x0e) - 9 5 5 5\n        { M, 0}, { M, 1}, { M, 2}, { M, 3}, { M, 4}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {RW, 6}, {RW, 7}, {RW, 8}, {BY, 4}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GW, 6}, {GW, 7}, {GW, 8}, {GY, 4}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {BW, 6}, {BW, 7}, {BW, 8}, {BZ, 4}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RX, 4},\n        {GZ, 4}, {GY, 0}, {GY, 1}, {GY, 2}, {GY, 3}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GX, 4},\n        {BZ, 0}, {GZ, 0}, {GZ, 1}, {GZ, 2}, {GZ, 3}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BX, 4},\n        {BZ, 1}, {BY, 0}, {BY, 1}, {BY, 2}, {BY, 3}, {RY, 0}, {RY, 1}, {RY, 2}, {RY, 3}, {RY, 4},\n        {BZ, 2}, {RZ, 0}, {RZ, 1}, {RZ, 2}, {RZ, 3}, {RZ, 4}, {BZ, 3}, { D, 0}, { D, 1}, { D, 2},\n        { D, 3}, { D, 4},\n    },\n\n    {   // Mode 7 (0x12) - 8 6 5 5\n        { M, 0}, { M, 1}, { M, 2}, { M, 3}, { M, 4}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {RW, 6}, {RW, 7}, {GZ, 4}, {BY, 4}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GW, 6}, {GW, 7}, {BZ, 2}, {GY, 4}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {BW, 6}, {BW, 7}, {BZ, 3}, {BZ, 4}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RX, 4},\n        {RX, 5}, {GY, 0}, {GY, 1}, {GY, 2}, {GY, 3}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GX, 4},\n        {BZ, 0}, {GZ, 0}, {GZ, 1}, {GZ, 2}, {GZ, 3}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BX, 4},\n        {BZ, 1}, {BY, 0}, {BY, 1}, {BY, 2}, {BY, 3}, {RY, 0}, {RY, 1}, {RY, 2}, {RY, 3}, {RY, 4},\n        {RY, 5}, {RZ, 0}, {RZ, 1}, {RZ, 2}, {RZ, 3}, {RZ, 4}, {RZ, 5}, { D, 0}, { D, 1}, { D, 2},\n        { D, 3}, { D, 4},\n    },\n\n    {   // Mode 8 (0x16) - 8 5 6 5\n        { M, 0}, { M, 1}, { M, 2}, { M, 3}, { M, 4}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {RW, 6}, {RW, 7}, {BZ, 0}, {BY, 4}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GW, 6}, {GW, 7}, {GY, 5}, {GY, 4}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {BW, 6}, {BW, 7}, {GZ, 5}, {BZ, 4}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RX, 4},\n        {GZ, 4}, {GY, 0}, {GY, 1}, {GY, 2}, {GY, 3}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GX, 4},\n        {GX, 5}, {GZ, 0}, {GZ, 1}, {GZ, 2}, {GZ, 3}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BX, 4},\n        {BZ, 1}, {BY, 0}, {BY, 1}, {BY, 2}, {BY, 3}, {RY, 0}, {RY, 1}, {RY, 2}, {RY, 3}, {RY, 4},\n        {BZ, 2}, {RZ, 0}, {RZ, 1}, {RZ, 2}, {RZ, 3}, {RZ, 4}, {BZ, 3}, { D, 0}, { D, 1}, { D, 2},\n        { D, 3}, { D, 4},\n    },\n\n    {   // Mode 9 (0x1a) - 8 5 5 6\n        { M, 0}, { M, 1}, { M, 2}, { M, 3}, { M, 4}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {RW, 6}, {RW, 7}, {BZ, 1}, {BY, 4}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GW, 6}, {GW, 7}, {BY, 5}, {GY, 4}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {BW, 6}, {BW, 7}, {BZ, 5}, {BZ, 4}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RX, 4},\n        {GZ, 4}, {GY, 0}, {GY, 1}, {GY, 2}, {GY, 3}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GX, 4},\n        {BZ, 0}, {GZ, 0}, {GZ, 1}, {GZ, 2}, {GZ, 3}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BX, 4},\n        {BX, 5}, {BY, 0}, {BY, 1}, {BY, 2}, {BY, 3}, {RY, 0}, {RY, 1}, {RY, 2}, {RY, 3}, {RY, 4},\n        {BZ, 2}, {RZ, 0}, {RZ, 1}, {RZ, 2}, {RZ, 3}, {RZ, 4}, {BZ, 3}, { D, 0}, { D, 1}, { D, 2},\n        { D, 3}, { D, 4},\n    },\n\n    {   // Mode 10 (0x1e) - 6 6 6 6\n        { M, 0}, { M, 1}, { M, 2}, { M, 3}, { M, 4}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {GZ, 4}, {BZ, 0}, {BZ, 1}, {BY, 4}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GY, 5}, {BY, 5}, {BZ, 2}, {GY, 4}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {GZ, 5}, {BZ, 3}, {BZ, 5}, {BZ, 4}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RX, 4},\n        {RX, 5}, {GY, 0}, {GY, 1}, {GY, 2}, {GY, 3}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GX, 4},\n        {GX, 5}, {GZ, 0}, {GZ, 1}, {GZ, 2}, {GZ, 3}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BX, 4},\n        {BX, 5}, {BY, 0}, {BY, 1}, {BY, 2}, {BY, 3}, {RY, 0}, {RY, 1}, {RY, 2}, {RY, 3}, {RY, 4},\n        {RY, 5}, {RZ, 0}, {RZ, 1}, {RZ, 2}, {RZ, 3}, {RZ, 4}, {RZ, 5}, { D, 0}, { D, 1}, { D, 2},\n        { D, 3}, { D, 4},\n    },\n\n    {   // Mode 11 (0x03) - 10 10\n        { M, 0}, { M, 1}, { M, 2}, { M, 3}, { M, 4}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {RW, 6}, {RW, 7}, {RW, 8}, {RW, 9}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GW, 6}, {GW, 7}, {GW, 8}, {GW, 9}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {BW, 6}, {BW, 7}, {BW, 8}, {BW, 9}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RX, 4},\n        {RX, 5}, {RX, 6}, {RX, 7}, {RX, 8}, {RX, 9}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GX, 4},\n        {GX, 5}, {GX, 6}, {GX, 7}, {GX, 8}, {GX, 9}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BX, 4},\n        {BX, 5}, {BX, 6}, {BX, 7}, {BX, 8}, {BX, 9}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0},\n        {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0},\n        {NA, 0}, {NA, 0},\n    },\n\n    {   // Mode 12 (0x07) - 11 9\n        { M, 0}, { M, 1}, { M, 2}, { M, 3}, { M, 4}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {RW, 6}, {RW, 7}, {RW, 8}, {RW, 9}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GW, 6}, {GW, 7}, {GW, 8}, {GW, 9}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {BW, 6}, {BW, 7}, {BW, 8}, {BW, 9}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RX, 4},\n        {RX, 5}, {RX, 6}, {RX, 7}, {RX, 8}, {RW,10}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GX, 4},\n        {GX, 5}, {GX, 6}, {GX, 7}, {GX, 8}, {GW,10}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BX, 4},\n        {BX, 5}, {BX, 6}, {BX, 7}, {BX, 8}, {BW,10}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0},\n        {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0},\n        {NA, 0}, {NA, 0},\n    },\n\n    {   // Mode 13 (0x0b) - 12 8\n        { M, 0}, { M, 1}, { M, 2}, { M, 3}, { M, 4}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {RW, 6}, {RW, 7}, {RW, 8}, {RW, 9}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GW, 6}, {GW, 7}, {GW, 8}, {GW, 9}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {BW, 6}, {BW, 7}, {BW, 8}, {BW, 9}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RX, 4},\n        {RX, 5}, {RX, 6}, {RX, 7}, {RW,11}, {RW,10}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GX, 4},\n        {GX, 5}, {GX, 6}, {GX, 7}, {GW,11}, {GW,10}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BX, 4},\n        {BX, 5}, {BX, 6}, {BX, 7}, {BW,11}, {BW,10}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0},\n        {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0},\n        {NA, 0}, {NA, 0},\n    },\n\n    {   // Mode 14 (0x0f) - 16 4\n        { M, 0}, { M, 1}, { M, 2}, { M, 3}, { M, 4}, {RW, 0}, {RW, 1}, {RW, 2}, {RW, 3}, {RW, 4},\n        {RW, 5}, {RW, 6}, {RW, 7}, {RW, 8}, {RW, 9}, {GW, 0}, {GW, 1}, {GW, 2}, {GW, 3}, {GW, 4},\n        {GW, 5}, {GW, 6}, {GW, 7}, {GW, 8}, {GW, 9}, {BW, 0}, {BW, 1}, {BW, 2}, {BW, 3}, {BW, 4},\n        {BW, 5}, {BW, 6}, {BW, 7}, {BW, 8}, {BW, 9}, {RX, 0}, {RX, 1}, {RX, 2}, {RX, 3}, {RW,15},\n        {RW,14}, {RW,13}, {RW,12}, {RW,11}, {RW,10}, {GX, 0}, {GX, 1}, {GX, 2}, {GX, 3}, {GW,15},\n        {GW,14}, {GW,13}, {GW,12}, {GW,11}, {GW,10}, {BX, 0}, {BX, 1}, {BX, 2}, {BX, 3}, {BW,15},\n        {BW,14}, {BW,13}, {BW,12}, {BW,11}, {BW,10}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0},\n        {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0}, {NA, 0},\n        {NA, 0}, {NA, 0},\n    },\n};\n\n// Mode, Partitions, Transformed, IndexPrec, RGBAPrec\nconst D3DX_BC6H::ModeInfo D3DX_BC6H::ms_aInfo[] =\n{\n    {0x00, 1, true,  3, { { LDRColorA(10,10,10,0), LDRColorA(5, 5, 5,0) }, { LDRColorA(5,5,5,0), LDRColorA(5,5,5,0) } } }, // Mode 1\n    {0x01, 1, true,  3, { { LDRColorA(7, 7, 7,0), LDRColorA(6, 6, 6,0) }, { LDRColorA(6,6,6,0), LDRColorA(6,6,6,0) } } }, // Mode 2\n    {0x02, 1, true,  3, { { LDRColorA(11,11,11,0), LDRColorA(5, 4, 4,0) }, { LDRColorA(5,4,4,0), LDRColorA(5,4,4,0) } } }, // Mode 3\n    {0x06, 1, true,  3, { { LDRColorA(11,11,11,0), LDRColorA(4, 5, 4,0) }, { LDRColorA(4,5,4,0), LDRColorA(4,5,4,0) } } }, // Mode 4\n    {0x0a, 1, true,  3, { { LDRColorA(11,11,11,0), LDRColorA(4, 4, 5,0) }, { LDRColorA(4,4,5,0), LDRColorA(4,4,5,0) } } }, // Mode 5\n    {0x0e, 1, true,  3, { { LDRColorA(9, 9, 9,0), LDRColorA(5, 5, 5,0) }, { LDRColorA(5,5,5,0), LDRColorA(5,5,5,0) } } }, // Mode 6\n    {0x12, 1, true,  3, { { LDRColorA(8, 8, 8,0), LDRColorA(6, 5, 5,0) }, { LDRColorA(6,5,5,0), LDRColorA(6,5,5,0) } } }, // Mode 7\n    {0x16, 1, true,  3, { { LDRColorA(8, 8, 8,0), LDRColorA(5, 6, 5,0) }, { LDRColorA(5,6,5,0), LDRColorA(5,6,5,0) } } }, // Mode 8\n    {0x1a, 1, true,  3, { { LDRColorA(8, 8, 8,0), LDRColorA(5, 5, 6,0) }, { LDRColorA(5,5,6,0), LDRColorA(5,5,6,0) } } }, // Mode 9\n    {0x1e, 1, false, 3, { { LDRColorA(6, 6, 6,0), LDRColorA(6, 6, 6,0) }, { LDRColorA(6,6,6,0), LDRColorA(6,6,6,0) } } }, // Mode 10\n    {0x03, 0, false, 4, { { LDRColorA(10,10,10,0), LDRColorA(10,10,10,0) }, { LDRColorA(0,0,0,0), LDRColorA(0,0,0,0) } } }, // Mode 11\n    {0x07, 0, true,  4, { { LDRColorA(11,11,11,0), LDRColorA(9, 9, 9,0) }, { LDRColorA(0,0,0,0), LDRColorA(0,0,0,0) } } }, // Mode 12\n    {0x0b, 0, true,  4, { { LDRColorA(12,12,12,0), LDRColorA(8, 8, 8,0) }, { LDRColorA(0,0,0,0), LDRColorA(0,0,0,0) } } }, // Mode 13\n    {0x0f, 0, true,  4, { { LDRColorA(16,16,16,0), LDRColorA(4, 4, 4,0) }, { LDRColorA(0,0,0,0), LDRColorA(0,0,0,0) } } }, // Mode 14\n};\n\nconst int D3DX_BC6H::ms_aModeToInfo[] =\n{\n     0, // Mode 1   - 0x00\n     1, // Mode 2   - 0x01\n     2, // Mode 3   - 0x02\n    10, // Mode 11  - 0x03\n    -1, // Invalid  - 0x04\n    -1, // Invalid  - 0x05\n     3, // Mode 4   - 0x06\n    11, // Mode 12  - 0x07\n    -1, // Invalid  - 0x08\n    -1, // Invalid  - 0x09\n     4, // Mode 5   - 0x0a\n    12, // Mode 13  - 0x0b\n    -1, // Invalid  - 0x0c\n    -1, // Invalid  - 0x0d\n     5, // Mode 6   - 0x0e\n    13, // Mode 14  - 0x0f\n    -1, // Invalid  - 0x10\n    -1, // Invalid  - 0x11\n     6, // Mode 7   - 0x12\n    -1, // Reserved - 0x13\n    -1, // Invalid  - 0x14\n    -1, // Invalid  - 0x15\n     7, // Mode 8   - 0x16\n    -1, // Reserved - 0x17\n    -1, // Invalid  - 0x18\n    -1, // Invalid  - 0x19\n     8, // Mode 9   - 0x1a\n    -1, // Reserved - 0x1b\n    -1, // Invalid  - 0x1c\n    -1, // Invalid  - 0x1d\n     9, // Mode 10  - 0x1e\n    -1, // Resreved - 0x1f\n};\n\n// BC7 compression: uPartitions, uPartitionBits, uPBits, uRotationBits, uIndexModeBits, uIndexPrec, uIndexPrec2, RGBAPrec, RGBAPrecWithP\nconst D3DX_BC7::ModeInfo D3DX_BC7::ms_aInfo[] =\n{\n    {2, 4, 6, 0, 0, 3, 0, LDRColorA(4,4,4,0), LDRColorA(5,5,5,0)},\n        // Mode 0: Color only, 3 Subsets, RGBP 4441 (unique P-bit), 3-bit indecies, 16 partitions\n    {1, 6, 2, 0, 0, 3, 0, LDRColorA(6,6,6,0), LDRColorA(7,7,7,0)},\n        // Mode 1: Color only, 2 Subsets, RGBP 6661 (shared P-bit), 3-bit indecies, 64 partitions\n    {2, 6, 0, 0, 0, 2, 0, LDRColorA(5,5,5,0), LDRColorA(5,5,5,0)},\n        // Mode 2: Color only, 3 Subsets, RGB 555, 2-bit indecies, 64 partitions\n    {1, 6, 4, 0, 0, 2, 0, LDRColorA(7,7,7,0), LDRColorA(8,8,8,0)},\n        // Mode 3: Color only, 2 Subsets, RGBP 7771 (unique P-bit), 2-bits indecies, 64 partitions\n    {0, 0, 0, 2, 1, 2, 3, LDRColorA(5,5,5,6), LDRColorA(5,5,5,6)},\n        // Mode 4: Color w/ Separate Alpha, 1 Subset, RGB 555, A6, 16x2/16x3-bit indices, 2-bit rotation, 1-bit index selector\n    {0, 0, 0, 2, 0, 2, 2, LDRColorA(7,7,7,8), LDRColorA(7,7,7,8)},\n        // Mode 5: Color w/ Separate Alpha, 1 Subset, RGB 777, A8, 16x2/16x2-bit indices, 2-bit rotation\n    {0, 0, 2, 0, 0, 4, 0, LDRColorA(7,7,7,7), LDRColorA(8,8,8,8)},\n        // Mode 6: Color+Alpha, 1 Subset, RGBAP 77771 (unique P-bit), 16x4-bit indecies\n    {1, 6, 4, 0, 0, 2, 0, LDRColorA(5,5,5,5), LDRColorA(6,6,6,6)}\n        // Mode 7: Color+Alpha, 2 Subsets, RGBAP 55551 (unique P-bit), 2-bit indices, 64 partitions\n};\n\n\nnamespace\n{\n    //-------------------------------------------------------------------------------------\n    // Helper functions\n    //-------------------------------------------------------------------------------------\n    inline bool IsFixUpOffset(_In_range_(0, 2) size_t uPartitions, _In_range_(0, 63) size_t uShape, _In_range_(0, 15) size_t uOffset) noexcept\n    {\n        assert(uPartitions < 3 && uShape < 64 && uOffset < 16);\n        _Analysis_assume_(uPartitions < 3 && uShape < 64 && uOffset < 16);\n        for (size_t p = 0; p <= uPartitions; p++)\n        {\n            if (uOffset == g_aFixUp[uPartitions][uShape][p])\n            {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    inline void TransformForward(_Inout_updates_all_(BC6H_MAX_REGIONS) INTEndPntPair aEndPts[]) noexcept\n    {\n        aEndPts[0].B -= aEndPts[0].A;\n        aEndPts[1].A -= aEndPts[0].A;\n        aEndPts[1].B -= aEndPts[0].A;\n    }\n\n    inline void TransformInverse(_Inout_updates_all_(BC6H_MAX_REGIONS) INTEndPntPair aEndPts[], _In_ const LDRColorA& Prec, _In_ bool bSigned) noexcept\n    {\n        const INTColor WrapMask((1 << Prec.r) - 1, (1 << Prec.g) - 1, (1 << Prec.b) - 1);\n        aEndPts[0].B += aEndPts[0].A; aEndPts[0].B &= WrapMask;\n        aEndPts[1].A += aEndPts[0].A; aEndPts[1].A &= WrapMask;\n        aEndPts[1].B += aEndPts[0].A; aEndPts[1].B &= WrapMask;\n        if (bSigned)\n        {\n            aEndPts[0].B.SignExtend(Prec);\n            aEndPts[1].A.SignExtend(Prec);\n            aEndPts[1].B.SignExtend(Prec);\n        }\n    }\n\n    inline float Norm(_In_ const INTColor& a, _In_ const INTColor& b) noexcept\n    {\n        const float dr = float(a.r) - float(b.r);\n        const float dg = float(a.g) - float(b.g);\n        const float db = float(a.b) - float(b.b);\n        return dr * dr + dg * dg + db * db;\n    }\n\n    // return # of bits needed to store n. handle signed or unsigned cases properly\n    inline int NBits(_In_ int n, _In_ bool bIsSigned) noexcept\n    {\n        int nb;\n        if (n == 0)\n        {\n            return 0;\t// no bits needed for 0, signed or not\n        }\n        else if (n > 0)\n        {\n            for (nb = 0; n; ++nb, n >>= 1);\n            return nb + (bIsSigned ? 1 : 0);\n        }\n        else\n        {\n            assert(bIsSigned);\n            for (nb = 0; n < -1; ++nb, n >>= 1);\n            return nb + 1;\n        }\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    float OptimizeRGB(\n        _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA* const pPoints,\n        _Out_ HDRColorA* pX,\n        _Out_ HDRColorA* pY,\n        _In_range_(3, 4) uint32_t cSteps,\n        size_t cPixels,\n        _In_reads_(cPixels) const size_t* pIndex) noexcept\n    {\n        constexpr float fError = FLT_MAX;\n        const float *pC = (3 == cSteps) ? pC3 : pC4;\n        const float *pD = (3 == cSteps) ? pD3 : pD4;\n\n        // Find Min and Max points, as starting point\n        HDRColorA X(FLT_MAX, FLT_MAX, FLT_MAX, 0.0f);\n        HDRColorA Y(-FLT_MAX, -FLT_MAX, -FLT_MAX, 0.0f);\n\n        for (size_t iPoint = 0; iPoint < cPixels; iPoint++)\n        {\n            if (pPoints[pIndex[iPoint]].r < X.r) X.r = pPoints[pIndex[iPoint]].r;\n            if (pPoints[pIndex[iPoint]].g < X.g) X.g = pPoints[pIndex[iPoint]].g;\n            if (pPoints[pIndex[iPoint]].b < X.b) X.b = pPoints[pIndex[iPoint]].b;\n            if (pPoints[pIndex[iPoint]].r > Y.r) Y.r = pPoints[pIndex[iPoint]].r;\n            if (pPoints[pIndex[iPoint]].g > Y.g) Y.g = pPoints[pIndex[iPoint]].g;\n            if (pPoints[pIndex[iPoint]].b > Y.b) Y.b = pPoints[pIndex[iPoint]].b;\n        }\n\n        // Diagonal axis\n        HDRColorA AB;\n        AB.r = Y.r - X.r;\n        AB.g = Y.g - X.g;\n        AB.b = Y.b - X.b;\n\n        const float fAB = AB.r * AB.r + AB.g * AB.g + AB.b * AB.b;\n\n        // Single color block.. no need to root-find\n        if (fAB < FLT_MIN)\n        {\n            pX->r = X.r; pX->g = X.g; pX->b = X.b;\n            pY->r = Y.r; pY->g = Y.g; pY->b = Y.b;\n            return 0.0f;\n        }\n\n        // Try all four axis directions, to determine which diagonal best fits data\n        const float fABInv = 1.0f / fAB;\n\n        HDRColorA Dir;\n        Dir.r = AB.r * fABInv;\n        Dir.g = AB.g * fABInv;\n        Dir.b = AB.b * fABInv;\n\n        HDRColorA Mid;\n        Mid.r = (X.r + Y.r) * 0.5f;\n        Mid.g = (X.g + Y.g) * 0.5f;\n        Mid.b = (X.b + Y.b) * 0.5f;\n\n        float fDir[4];\n        fDir[0] = fDir[1] = fDir[2] = fDir[3] = 0.0f;\n\n        for (size_t iPoint = 0; iPoint < cPixels; iPoint++)\n        {\n            HDRColorA Pt;\n            Pt.r = (pPoints[pIndex[iPoint]].r - Mid.r) * Dir.r;\n            Pt.g = (pPoints[pIndex[iPoint]].g - Mid.g) * Dir.g;\n            Pt.b = (pPoints[pIndex[iPoint]].b - Mid.b) * Dir.b;\n\n            float f;\n            f = Pt.r + Pt.g + Pt.b; fDir[0] += f * f;\n            f = Pt.r + Pt.g - Pt.b; fDir[1] += f * f;\n            f = Pt.r - Pt.g + Pt.b; fDir[2] += f * f;\n            f = Pt.r - Pt.g - Pt.b; fDir[3] += f * f;\n        }\n\n        float fDirMax = fDir[0];\n        size_t  iDirMax = 0;\n\n        for (size_t iDir = 1; iDir < 4; iDir++)\n        {\n            if (fDir[iDir] > fDirMax)\n            {\n                fDirMax = fDir[iDir];\n                iDirMax = iDir;\n            }\n        }\n\n        if (iDirMax & 2) std::swap(X.g, Y.g);\n        if (iDirMax & 1) std::swap(X.b, Y.b);\n\n        // Two color block.. no need to root-find\n        if (fAB < 1.0f / 4096.0f)\n        {\n            pX->r = X.r; pX->g = X.g; pX->b = X.b;\n            pY->r = Y.r; pY->g = Y.g; pY->b = Y.b;\n            return 0.0f;\n        }\n\n        // Use Newton's Method to find local minima of sum-of-squares error.\n        auto const fSteps = static_cast<float>(cSteps - 1);\n\n        for (size_t iIteration = 0; iIteration < 8; iIteration++)\n        {\n            // Calculate new steps\n            HDRColorA pSteps[4] = {};\n\n            for (size_t iStep = 0; iStep < cSteps; iStep++)\n            {\n                pSteps[iStep].r = X.r * pC[iStep] + Y.r * pD[iStep];\n                pSteps[iStep].g = X.g * pC[iStep] + Y.g * pD[iStep];\n                pSteps[iStep].b = X.b * pC[iStep] + Y.b * pD[iStep];\n            }\n\n            // Calculate color direction\n            Dir.r = Y.r - X.r;\n            Dir.g = Y.g - X.g;\n            Dir.b = Y.b - X.b;\n\n            const float fLen = (Dir.r * Dir.r + Dir.g * Dir.g + Dir.b * Dir.b);\n\n            if (fLen < (1.0f / 4096.0f))\n                break;\n\n            const float fScale = fSteps / fLen;\n\n            Dir.r *= fScale;\n            Dir.g *= fScale;\n            Dir.b *= fScale;\n\n            // Evaluate function, and derivatives\n            float d2X = 0.0f, d2Y = 0.0f;\n            HDRColorA dX(0.0f, 0.0f, 0.0f, 0.0f), dY(0.0f, 0.0f, 0.0f, 0.0f);\n\n            for (size_t iPoint = 0; iPoint < cPixels; iPoint++)\n            {\n                const float fDot = (pPoints[pIndex[iPoint]].r - X.r) * Dir.r +\n                    (pPoints[pIndex[iPoint]].g - X.g) * Dir.g +\n                    (pPoints[pIndex[iPoint]].b - X.b) * Dir.b;\n\n                uint32_t iStep;\n                if (fDot <= 0.0f)\n                    iStep = 0;\n                else if (fDot >= fSteps)\n                    iStep = cSteps - 1;\n                else\n                    iStep = uint32_t(fDot + 0.5f);\n\n                HDRColorA Diff;\n                Diff.r = pSteps[iStep].r - pPoints[pIndex[iPoint]].r;\n                Diff.g = pSteps[iStep].g - pPoints[pIndex[iPoint]].g;\n                Diff.b = pSteps[iStep].b - pPoints[pIndex[iPoint]].b;\n\n                const float fC = pC[iStep] * (1.0f / 8.0f);\n                const float fD = pD[iStep] * (1.0f / 8.0f);\n\n                d2X += fC * pC[iStep];\n                dX.r += fC * Diff.r;\n                dX.g += fC * Diff.g;\n                dX.b += fC * Diff.b;\n\n                d2Y += fD * pD[iStep];\n                dY.r += fD * Diff.r;\n                dY.g += fD * Diff.g;\n                dY.b += fD * Diff.b;\n            }\n\n            // Move endpoints\n            if (d2X > 0.0f)\n            {\n                const float f = -1.0f / d2X;\n\n                X.r += dX.r * f;\n                X.g += dX.g * f;\n                X.b += dX.b * f;\n            }\n\n            if (d2Y > 0.0f)\n            {\n                const float f = -1.0f / d2Y;\n\n                Y.r += dY.r * f;\n                Y.g += dY.g * f;\n                Y.b += dY.b * f;\n            }\n\n            if ((dX.r * dX.r < fEpsilon) && (dX.g * dX.g < fEpsilon) && (dX.b * dX.b < fEpsilon) &&\n                (dY.r * dY.r < fEpsilon) && (dY.g * dY.g < fEpsilon) && (dY.b * dY.b < fEpsilon))\n            {\n                break;\n            }\n        }\n\n        pX->r = X.r; pX->g = X.g; pX->b = X.b;\n        pY->r = Y.r; pY->g = Y.g; pY->b = Y.b;\n        return fError;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    float OptimizeRGBA(\n        _In_reads_(NUM_PIXELS_PER_BLOCK) const HDRColorA* const pPoints,\n        _Out_ HDRColorA* pX,\n        _Out_ HDRColorA* pY,\n        _In_range_(3, 4) uint32_t cSteps,\n        size_t cPixels,\n        _In_reads_(cPixels) const size_t* pIndex) noexcept\n    {\n        constexpr float fError = FLT_MAX;\n        const float *pC = (3 == cSteps) ? pC3 : pC4;\n        const float *pD = (3 == cSteps) ? pD3 : pD4;\n\n        // Find Min and Max points, as starting point\n        HDRColorA X(1.0f, 1.0f, 1.0f, 1.0f);\n        HDRColorA Y(0.0f, 0.0f, 0.0f, 0.0f);\n\n        for (size_t iPoint = 0; iPoint < cPixels; iPoint++)\n        {\n            if (pPoints[pIndex[iPoint]].r < X.r) X.r = pPoints[pIndex[iPoint]].r;\n            if (pPoints[pIndex[iPoint]].g < X.g) X.g = pPoints[pIndex[iPoint]].g;\n            if (pPoints[pIndex[iPoint]].b < X.b) X.b = pPoints[pIndex[iPoint]].b;\n            if (pPoints[pIndex[iPoint]].a < X.a) X.a = pPoints[pIndex[iPoint]].a;\n            if (pPoints[pIndex[iPoint]].r > Y.r) Y.r = pPoints[pIndex[iPoint]].r;\n            if (pPoints[pIndex[iPoint]].g > Y.g) Y.g = pPoints[pIndex[iPoint]].g;\n            if (pPoints[pIndex[iPoint]].b > Y.b) Y.b = pPoints[pIndex[iPoint]].b;\n            if (pPoints[pIndex[iPoint]].a > Y.a) Y.a = pPoints[pIndex[iPoint]].a;\n        }\n\n        // Diagonal axis\n        const HDRColorA AB = Y - X;\n        const float fAB = AB * AB;\n\n        // Single color block.. no need to root-find\n        if (fAB < FLT_MIN)\n        {\n            *pX = X;\n            *pY = Y;\n            return 0.0f;\n        }\n\n        // Try all four axis directions, to determine which diagonal best fits data\n        const float fABInv = 1.0f / fAB;\n        HDRColorA Dir = AB * fABInv;\n        const HDRColorA Mid = (X + Y) * 0.5f;\n\n        float fDir[8];\n        fDir[0] = fDir[1] = fDir[2] = fDir[3] = fDir[4] = fDir[5] = fDir[6] = fDir[7] = 0.0f;\n\n        for (size_t iPoint = 0; iPoint < cPixels; iPoint++)\n        {\n            HDRColorA Pt;\n            Pt.r = (pPoints[pIndex[iPoint]].r - Mid.r) * Dir.r;\n            Pt.g = (pPoints[pIndex[iPoint]].g - Mid.g) * Dir.g;\n            Pt.b = (pPoints[pIndex[iPoint]].b - Mid.b) * Dir.b;\n            Pt.a = (pPoints[pIndex[iPoint]].a - Mid.a) * Dir.a;\n\n            float f;\n            f = Pt.r + Pt.g + Pt.b + Pt.a; fDir[0] += f * f;\n            f = Pt.r + Pt.g + Pt.b - Pt.a; fDir[1] += f * f;\n            f = Pt.r + Pt.g - Pt.b + Pt.a; fDir[2] += f * f;\n            f = Pt.r + Pt.g - Pt.b - Pt.a; fDir[3] += f * f;\n            f = Pt.r - Pt.g + Pt.b + Pt.a; fDir[4] += f * f;\n            f = Pt.r - Pt.g + Pt.b - Pt.a; fDir[5] += f * f;\n            f = Pt.r - Pt.g - Pt.b + Pt.a; fDir[6] += f * f;\n            f = Pt.r - Pt.g - Pt.b - Pt.a; fDir[7] += f * f;\n        }\n\n        float fDirMax = fDir[0];\n        size_t  iDirMax = 0;\n\n        for (size_t iDir = 1; iDir < 8; iDir++)\n        {\n            if (fDir[iDir] > fDirMax)\n            {\n                fDirMax = fDir[iDir];\n                iDirMax = iDir;\n            }\n        }\n\n        if (iDirMax & 4) std::swap(X.g, Y.g);\n        if (iDirMax & 2) std::swap(X.b, Y.b);\n        if (iDirMax & 1) std::swap(X.a, Y.a);\n\n        // Two color block.. no need to root-find\n        if (fAB < 1.0f / 4096.0f)\n        {\n            *pX = X;\n            *pY = Y;\n            return 0.0f;\n        }\n\n        // Use Newton's Method to find local minima of sum-of-squares error.\n        const auto fSteps = static_cast<float>(cSteps - 1u);\n\n        for (size_t iIteration = 0; iIteration < 8 && fError > 0.0f; iIteration++)\n        {\n            // Calculate new steps\n            HDRColorA pSteps[BC7_MAX_INDICES];\n\n            LDRColorA lX, lY;\n            lX = (X * 255.0f).ToLDRColorA();\n            lY = (Y * 255.0f).ToLDRColorA();\n\n            for (size_t iStep = 0; iStep < cSteps; iStep++)\n            {\n                pSteps[iStep] = X * pC[iStep] + Y * pD[iStep];\n                //LDRColorA::Interpolate(lX, lY, i, i, wcprec, waprec, aSteps[i]);\n            }\n\n            // Calculate color direction\n            Dir = Y - X;\n            const float fLen = Dir * Dir;\n            if (fLen < (1.0f / 4096.0f))\n                break;\n\n            const float fScale = fSteps / fLen;\n            Dir *= fScale;\n\n            // Evaluate function, and derivatives\n            float d2X = 0.0f, d2Y = 0.0f;\n            HDRColorA dX(0.0f, 0.0f, 0.0f, 0.0f), dY(0.0f, 0.0f, 0.0f, 0.0f);\n\n            for (size_t iPoint = 0; iPoint < cPixels; ++iPoint)\n            {\n                const float fDot = (pPoints[pIndex[iPoint]] - X) * Dir;\n\n                uint32_t iStep;\n                if (fDot <= 0.0f)\n                    iStep = 0;\n                else if (fDot >= fSteps)\n                    iStep = cSteps - 1;\n                else\n                    iStep = uint32_t(fDot + 0.5f);\n\n                const HDRColorA Diff = pSteps[iStep] - pPoints[pIndex[iPoint]];\n                const float fC = pC[iStep] * (1.0f / 8.0f);\n                const float fD = pD[iStep] * (1.0f / 8.0f);\n\n                d2X += fC * pC[iStep];\n                dX += Diff * fC;\n\n                d2Y += fD * pD[iStep];\n                dY += Diff * fD;\n            }\n\n            // Move endpoints\n            if (d2X > 0.0f)\n            {\n                const float f = -1.0f / d2X;\n                X += dX * f;\n            }\n\n            if (d2Y > 0.0f)\n            {\n                const float f = -1.0f / d2Y;\n                Y += dY * f;\n            }\n\n            if ((dX * dX < fEpsilon) && (dY * dY < fEpsilon))\n                break;\n        }\n\n        *pX = X;\n        *pY = Y;\n        return fError;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    float ComputeError(\n        _Inout_ const LDRColorA& pixel,\n        _In_reads_(1 << uIndexPrec) const LDRColorA aPalette[],\n        uint8_t uIndexPrec,\n        uint8_t uIndexPrec2,\n        _Out_opt_ size_t* pBestIndex = nullptr,\n        _Out_opt_ size_t* pBestIndex2 = nullptr) noexcept\n    {\n        const size_t uNumIndices = size_t(1) << uIndexPrec;\n        const size_t uNumIndices2 = size_t(1) << uIndexPrec2;\n        float fTotalErr = 0;\n        float fBestErr = FLT_MAX;\n\n        if (pBestIndex)\n            *pBestIndex = 0;\n        if (pBestIndex2)\n            *pBestIndex2 = 0;\n\n        const XMVECTOR vpixel = XMLoadUByte4(reinterpret_cast<const XMUBYTE4*>(&pixel));\n\n        if (uIndexPrec2 == 0)\n        {\n            for (size_t i = 0; i < uNumIndices && fBestErr > 0; i++)\n            {\n                XMVECTOR tpixel = XMLoadUByte4(reinterpret_cast<const XMUBYTE4*>(&aPalette[i]));\n                // Compute ErrorMetric\n                tpixel = XMVectorSubtract(vpixel, tpixel);\n                const float fErr = XMVectorGetX(XMVector4Dot(tpixel, tpixel));\n                if (fErr > fBestErr)\t// error increased, so we're done searching\n                    break;\n                if (fErr < fBestErr)\n                {\n                    fBestErr = fErr;\n                    if (pBestIndex)\n                        *pBestIndex = i;\n                }\n            }\n            fTotalErr += fBestErr;\n        }\n        else\n        {\n            for (size_t i = 0; i < uNumIndices && fBestErr > 0; i++)\n            {\n                XMVECTOR tpixel = XMLoadUByte4(reinterpret_cast<const XMUBYTE4*>(&aPalette[i]));\n                // Compute ErrorMetricRGB\n                tpixel = XMVectorSubtract(vpixel, tpixel);\n                const float fErr = XMVectorGetX(XMVector3Dot(tpixel, tpixel));\n                if (fErr > fBestErr)\t// error increased, so we're done searching\n                    break;\n                if (fErr < fBestErr)\n                {\n                    fBestErr = fErr;\n                    if (pBestIndex)\n                        *pBestIndex = i;\n                }\n            }\n            fTotalErr += fBestErr;\n            fBestErr = FLT_MAX;\n            for (size_t i = 0; i < uNumIndices2 && fBestErr > 0; i++)\n            {\n                // Compute ErrorMetricAlpha\n                const float ea = float(pixel.a) - float(aPalette[i].a);\n                const float fErr = ea*ea;\n                if (fErr > fBestErr)\t// error increased, so we're done searching\n                    break;\n                if (fErr < fBestErr)\n                {\n                    fBestErr = fErr;\n                    if (pBestIndex2)\n                        *pBestIndex2 = i;\n                }\n            }\n            fTotalErr += fBestErr;\n        }\n\n        return fTotalErr;\n    }\n\n\n    void FillWithErrorColors(_Out_writes_(NUM_PIXELS_PER_BLOCK) HDRColorA* pOut) noexcept\n    {\n        for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n        {\n        #ifdef _DEBUG\n            // Use Magenta in debug as a highly-visible error color\n            pOut[i] = HDRColorA(1.0f, 0.0f, 1.0f, 1.0f);\n        #else\n            // In production use, default to black\n            pOut[i] = HDRColorA(0.0f, 0.0f, 0.0f, 1.0f);\n        #endif\n        }\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// BC6H Compression\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nvoid D3DX_BC6H::Decode(bool bSigned, HDRColorA* pOut) const noexcept\n{\n    assert(pOut);\n\n    size_t uStartBit = 0;\n    uint8_t uMode = GetBits(uStartBit, 2u);\n    if (uMode != 0x00 && uMode != 0x01)\n    {\n        uMode = static_cast<uint8_t>((unsigned(GetBits(uStartBit, 3)) << 2) | uMode);\n    }\n\n    assert(uMode < 32);\n    _Analysis_assume_(uMode < 32);\n\n    if (ms_aModeToInfo[uMode] >= 0)\n    {\n        assert(static_cast<unsigned int>(ms_aModeToInfo[uMode]) < std::size(ms_aInfo));\n        _Analysis_assume_(ms_aModeToInfo[uMode] < std::size(ms_aInfo));\n        const ModeDescriptor* desc = ms_aDesc[ms_aModeToInfo[uMode]];\n\n        assert(static_cast<unsigned int>(ms_aModeToInfo[uMode]) < std::size(ms_aDesc));\n        _Analysis_assume_(ms_aModeToInfo[uMode] < std::size(ms_aDesc));\n        const ModeInfo& info = ms_aInfo[ms_aModeToInfo[uMode]];\n\n        INTEndPntPair aEndPts[BC6H_MAX_REGIONS] = {};\n        uint32_t uShape = 0;\n\n        // Read header\n        const size_t uHeaderBits = info.uPartitions > 0 ? 82u : 65u;\n        while (uStartBit < uHeaderBits)\n        {\n            const size_t uCurBit = uStartBit;\n            if (GetBit(uStartBit))\n            {\n                switch (desc[uCurBit].m_eField)\n                {\n                case D:  uShape |= 1 << uint32_t(desc[uCurBit].m_uBit); break;\n                case RW: aEndPts[0].A.r |= 1 << uint32_t(desc[uCurBit].m_uBit); break;\n                case RX: aEndPts[0].B.r |= 1 << uint32_t(desc[uCurBit].m_uBit); break;\n                case RY: aEndPts[1].A.r |= 1 << uint32_t(desc[uCurBit].m_uBit); break;\n                case RZ: aEndPts[1].B.r |= 1 << uint32_t(desc[uCurBit].m_uBit); break;\n                case GW: aEndPts[0].A.g |= 1 << uint32_t(desc[uCurBit].m_uBit); break;\n                case GX: aEndPts[0].B.g |= 1 << uint32_t(desc[uCurBit].m_uBit); break;\n                case GY: aEndPts[1].A.g |= 1 << uint32_t(desc[uCurBit].m_uBit); break;\n                case GZ: aEndPts[1].B.g |= 1 << uint32_t(desc[uCurBit].m_uBit); break;\n                case BW: aEndPts[0].A.b |= 1 << uint32_t(desc[uCurBit].m_uBit); break;\n                case BX: aEndPts[0].B.b |= 1 << uint32_t(desc[uCurBit].m_uBit); break;\n                case BY: aEndPts[1].A.b |= 1 << uint32_t(desc[uCurBit].m_uBit); break;\n                case BZ: aEndPts[1].B.b |= 1 << uint32_t(desc[uCurBit].m_uBit); break;\n                default:\n                    {\n                    #ifdef _DEBUG\n                        OutputDebugStringA(\"BC6H: Invalid header bits encountered during decoding\\n\");\n                    #endif\n                        FillWithErrorColors(pOut);\n                        return;\n                    }\n                }\n            }\n        }\n\n        assert(uShape < 64);\n        _Analysis_assume_(uShape < 64);\n\n        // Sign extend necessary end points\n        if (bSigned)\n        {\n            aEndPts[0].A.SignExtend(info.RGBAPrec[0][0]);\n        }\n        if (bSigned || info.bTransformed)\n        {\n            assert(info.uPartitions < BC6H_MAX_REGIONS);\n            _Analysis_assume_(info.uPartitions < BC6H_MAX_REGIONS);\n            for (size_t p = 0; p <= info.uPartitions; ++p)\n            {\n                if (p != 0)\n                {\n                    aEndPts[p].A.SignExtend(info.RGBAPrec[p][0]);\n                }\n                aEndPts[p].B.SignExtend(info.RGBAPrec[p][1]);\n            }\n        }\n\n        // Inverse transform the end points\n        if (info.bTransformed)\n        {\n            TransformInverse(aEndPts, info.RGBAPrec[0][0], bSigned);\n        }\n\n        // Read indices\n        for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n        {\n            const size_t uNumBits = IsFixUpOffset(info.uPartitions, uShape, i) ? info.uIndexPrec - 1u : info.uIndexPrec;\n            if (uStartBit + uNumBits > 128)\n            {\n            #ifdef _DEBUG\n                OutputDebugStringA(\"BC6H: Invalid block encountered during decoding\\n\");\n            #endif\n                FillWithErrorColors(pOut);\n                return;\n            }\n            const uint8_t uIndex = GetBits(uStartBit, uNumBits);\n\n            if (uIndex >= ((info.uPartitions > 0) ? 8 : 16))\n            {\n            #ifdef _DEBUG\n                OutputDebugStringA(\"BC6H: Invalid index encountered during decoding\\n\");\n            #endif\n                FillWithErrorColors(pOut);\n                return;\n            }\n\n            const size_t uRegion = g_aPartitionTable[info.uPartitions][uShape][i];\n            assert(uRegion < BC6H_MAX_REGIONS);\n            _Analysis_assume_(uRegion < BC6H_MAX_REGIONS);\n\n            // Unquantize endpoints and interpolate\n            const int r1 = Unquantize(aEndPts[uRegion].A.r, info.RGBAPrec[0][0].r, bSigned);\n            const int g1 = Unquantize(aEndPts[uRegion].A.g, info.RGBAPrec[0][0].g, bSigned);\n            const int b1 = Unquantize(aEndPts[uRegion].A.b, info.RGBAPrec[0][0].b, bSigned);\n            const int r2 = Unquantize(aEndPts[uRegion].B.r, info.RGBAPrec[0][0].r, bSigned);\n            const int g2 = Unquantize(aEndPts[uRegion].B.g, info.RGBAPrec[0][0].g, bSigned);\n            const int b2 = Unquantize(aEndPts[uRegion].B.b, info.RGBAPrec[0][0].b, bSigned);\n            const int* aWeights = info.uPartitions > 0 ? g_aWeights3 : g_aWeights4;\n            INTColor fc;\n            fc.r = FinishUnquantize((r1 * (BC67_WEIGHT_MAX - aWeights[uIndex]) + r2 * aWeights[uIndex] + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT, bSigned);\n            fc.g = FinishUnquantize((g1 * (BC67_WEIGHT_MAX - aWeights[uIndex]) + g2 * aWeights[uIndex] + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT, bSigned);\n            fc.b = FinishUnquantize((b1 * (BC67_WEIGHT_MAX - aWeights[uIndex]) + b2 * aWeights[uIndex] + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT, bSigned);\n\n            HALF rgb[3];\n            fc.ToF16(rgb, bSigned);\n\n            pOut[i].r = XMConvertHalfToFloat(rgb[0]);\n            pOut[i].g = XMConvertHalfToFloat(rgb[1]);\n            pOut[i].b = XMConvertHalfToFloat(rgb[2]);\n            pOut[i].a = 1.0f;\n        }\n    }\n    else\n    {\n    #ifdef _DEBUG\n        const char* warnstr = \"BC6H: Invalid mode encountered during decoding\\n\";\n        switch (uMode)\n        {\n        case 0x13:  warnstr = \"BC6H: Reserved mode 10011 encountered during decoding\\n\"; break;\n        case 0x17:  warnstr = \"BC6H: Reserved mode 10111 encountered during decoding\\n\"; break;\n        case 0x1B:  warnstr = \"BC6H: Reserved mode 11011 encountered during decoding\\n\"; break;\n        case 0x1F:  warnstr = \"BC6H: Reserved mode 11111 encountered during decoding\\n\"; break;\n        }\n        OutputDebugStringA(warnstr);\n    #endif\n        // Per the BC6H format spec, we must return opaque black\n        for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n        {\n            pOut[i] = HDRColorA(0.0f, 0.0f, 0.0f, 1.0f);\n        }\n    }\n}\n\n\n_Use_decl_annotations_\nvoid D3DX_BC6H::Encode(bool bSigned, const HDRColorA* const pIn) noexcept\n{\n    assert(pIn);\n\n    EncodeParams EP(pIn, bSigned);\n\n    for (EP.uMode = 0; EP.uMode < std::size(ms_aInfo) && EP.fBestErr > 0; ++EP.uMode)\n    {\n        const uint8_t uShapes = ms_aInfo[EP.uMode].uPartitions ? 32u : 1u;\n        // Number of rough cases to look at. reasonable values of this are 1, uShapes/4, and uShapes\n        // uShapes/4 gets nearly all the cases; you can increase that a bit (say by 3 or 4) if you really want to squeeze the last bit out\n        const size_t uItems = std::max<size_t>(1u, size_t(uShapes >> 2));\n        float afRoughMSE[BC6H_MAX_SHAPES];\n        uint8_t auShape[BC6H_MAX_SHAPES];\n\n        // pick the best uItems shapes and refine these.\n        for (EP.uShape = 0; EP.uShape < uShapes; ++EP.uShape)\n        {\n            size_t uShape = EP.uShape;\n            afRoughMSE[uShape] = RoughMSE(&EP);\n            auShape[uShape] = static_cast<uint8_t>(uShape);\n        }\n\n        // Bubble up the first uItems items\n        for (size_t i = 0; i < uItems; i++)\n        {\n            for (size_t j = i + 1; j < uShapes; j++)\n            {\n                if (afRoughMSE[i] > afRoughMSE[j])\n                {\n                    std::swap(afRoughMSE[i], afRoughMSE[j]);\n                    std::swap(auShape[i], auShape[j]);\n                }\n            }\n        }\n\n        for (size_t i = 0; i < uItems && EP.fBestErr > 0; i++)\n        {\n            EP.uShape = auShape[i];\n            Refine(&EP);\n        }\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nint D3DX_BC6H::Quantize(int iValue, int prec, bool bSigned) noexcept\n{\n    assert(prec > 1);\t// didn't bother to make it work for 1\n    int q, s = 0;\n    if (bSigned)\n    {\n        assert(iValue >= -F16MAX && iValue <= F16MAX);\n        if (iValue < 0)\n        {\n            s = 1;\n            iValue = -iValue;\n        }\n        q = (prec >= 16) ? iValue : (iValue << (prec - 1)) / (F16MAX + 1);\n        if (s)\n            q = -q;\n        assert(q > -(1 << (prec - 1)) && q < (1 << (prec - 1)));\n    }\n    else\n    {\n        assert(iValue >= 0 && iValue <= F16MAX);\n        q = (prec >= 15) ? iValue : (iValue << prec) / (F16MAX + 1);\n        assert(q >= 0 && q < (1 << prec));\n    }\n\n    return q;\n}\n\n\n_Use_decl_annotations_\nint D3DX_BC6H::Unquantize(int comp, uint8_t uBitsPerComp, bool bSigned) noexcept\n{\n    int unq = 0, s = 0;\n    if (bSigned)\n    {\n        if (uBitsPerComp >= 16)\n        {\n            unq = comp;\n        }\n        else\n        {\n            if (comp < 0)\n            {\n                s = 1;\n                comp = -comp;\n            }\n\n            if (comp == 0) unq = 0;\n            else if (comp >= ((1 << (uBitsPerComp - 1)) - 1)) unq = 0x7FFF;\n            else unq = ((comp << 15) + 0x4000) >> (uBitsPerComp - 1);\n\n            if (s) unq = -unq;\n        }\n    }\n    else\n    {\n        if (uBitsPerComp >= 15) unq = comp;\n        else if (comp == 0) unq = 0;\n        else if (comp == ((1 << uBitsPerComp) - 1)) unq = 0xFFFF;\n        else unq = ((comp << 16) + 0x8000) >> uBitsPerComp;\n    }\n\n    return unq;\n}\n\n\n_Use_decl_annotations_\nint D3DX_BC6H::FinishUnquantize(int comp, bool bSigned) noexcept\n{\n    if (bSigned)\n    {\n        return (comp < 0) ? -(((-comp) * 31) >> 5) : (comp * 31) >> 5;  // scale the magnitude by 31/32\n    }\n    else\n    {\n        return (comp * 31) >> 6;                                        // scale the magnitude by 31/64\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nbool D3DX_BC6H::EndPointsFit(const EncodeParams* pEP, const INTEndPntPair aEndPts[]) noexcept\n{\n    assert(pEP);\n    const bool bTransformed = ms_aInfo[pEP->uMode].bTransformed;\n    const bool bIsSigned = pEP->bSigned;\n    const LDRColorA& Prec0 = ms_aInfo[pEP->uMode].RGBAPrec[0][0];\n    const LDRColorA& Prec1 = ms_aInfo[pEP->uMode].RGBAPrec[0][1];\n    const LDRColorA& Prec2 = ms_aInfo[pEP->uMode].RGBAPrec[1][0];\n    const LDRColorA& Prec3 = ms_aInfo[pEP->uMode].RGBAPrec[1][1];\n\n    INTColor aBits[4];\n    aBits[0].r = NBits(aEndPts[0].A.r, bIsSigned);\n    aBits[0].g = NBits(aEndPts[0].A.g, bIsSigned);\n    aBits[0].b = NBits(aEndPts[0].A.b, bIsSigned);\n    aBits[1].r = NBits(aEndPts[0].B.r, bTransformed || bIsSigned);\n    aBits[1].g = NBits(aEndPts[0].B.g, bTransformed || bIsSigned);\n    aBits[1].b = NBits(aEndPts[0].B.b, bTransformed || bIsSigned);\n    if (aBits[0].r > Prec0.r || aBits[1].r > Prec1.r ||\n        aBits[0].g > Prec0.g || aBits[1].g > Prec1.g ||\n        aBits[0].b > Prec0.b || aBits[1].b > Prec1.b)\n        return false;\n\n    if (ms_aInfo[pEP->uMode].uPartitions)\n    {\n        aBits[2].r = NBits(aEndPts[1].A.r, bTransformed || bIsSigned);\n        aBits[2].g = NBits(aEndPts[1].A.g, bTransformed || bIsSigned);\n        aBits[2].b = NBits(aEndPts[1].A.b, bTransformed || bIsSigned);\n        aBits[3].r = NBits(aEndPts[1].B.r, bTransformed || bIsSigned);\n        aBits[3].g = NBits(aEndPts[1].B.g, bTransformed || bIsSigned);\n        aBits[3].b = NBits(aEndPts[1].B.b, bTransformed || bIsSigned);\n\n        if (aBits[2].r > Prec2.r || aBits[3].r > Prec3.r ||\n            aBits[2].g > Prec2.g || aBits[3].g > Prec3.g ||\n            aBits[2].b > Prec2.b || aBits[3].b > Prec3.b)\n            return false;\n    }\n\n    return true;\n}\n\n\n_Use_decl_annotations_\nvoid D3DX_BC6H::GeneratePaletteQuantized(const EncodeParams* pEP, const INTEndPntPair& endPts, INTColor aPalette[]) const noexcept\n{\n    assert(pEP);\n    const size_t uIndexPrec = ms_aInfo[pEP->uMode].uIndexPrec;\n    const size_t uNumIndices = size_t(1) << uIndexPrec;\n    assert(uNumIndices > 0);\n    _Analysis_assume_(uNumIndices > 0);\n    const LDRColorA& Prec = ms_aInfo[pEP->uMode].RGBAPrec[0][0];\n\n    // scale endpoints\n    INTEndPntPair unqEndPts;\n    unqEndPts.A.r = Unquantize(endPts.A.r, Prec.r, pEP->bSigned);\n    unqEndPts.A.g = Unquantize(endPts.A.g, Prec.g, pEP->bSigned);\n    unqEndPts.A.b = Unquantize(endPts.A.b, Prec.b, pEP->bSigned);\n    unqEndPts.B.r = Unquantize(endPts.B.r, Prec.r, pEP->bSigned);\n    unqEndPts.B.g = Unquantize(endPts.B.g, Prec.g, pEP->bSigned);\n    unqEndPts.B.b = Unquantize(endPts.B.b, Prec.b, pEP->bSigned);\n\n    // interpolate\n    const int* aWeights = nullptr;\n    switch (uIndexPrec)\n    {\n    case 3: aWeights = g_aWeights3; assert(uNumIndices <= 8); _Analysis_assume_(uNumIndices <= 8); break;\n    case 4: aWeights = g_aWeights4; assert(uNumIndices <= 16); _Analysis_assume_(uNumIndices <= 16); break;\n    default:\n        assert(false);\n        for (size_t i = 0; i < uNumIndices; ++i)\n        {\n        #pragma prefast(suppress:22102 22103, \"writing blocks in two halves confuses tool\")\n            aPalette[i] = INTColor(0, 0, 0);\n        }\n        return;\n    }\n\n    for (size_t i = 0; i < uNumIndices; ++i)\n    {\n        aPalette[i].r = FinishUnquantize(\n            (unqEndPts.A.r * (BC67_WEIGHT_MAX - aWeights[i]) + unqEndPts.B.r * aWeights[i] + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT,\n            pEP->bSigned);\n        aPalette[i].g = FinishUnquantize(\n            (unqEndPts.A.g * (BC67_WEIGHT_MAX - aWeights[i]) + unqEndPts.B.g * aWeights[i] + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT,\n            pEP->bSigned);\n        aPalette[i].b = FinishUnquantize(\n            (unqEndPts.A.b * (BC67_WEIGHT_MAX - aWeights[i]) + unqEndPts.B.b * aWeights[i] + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT,\n            pEP->bSigned);\n    }\n}\n\n\n// given a collection of colors and quantized endpoints, generate a palette, choose best entries, and return a single toterr\n_Use_decl_annotations_\nfloat D3DX_BC6H::MapColorsQuantized(const EncodeParams* pEP, const INTColor aColors[], size_t np, const INTEndPntPair &endPts) const noexcept\n{\n    assert(pEP);\n\n    const uint8_t uIndexPrec = ms_aInfo[pEP->uMode].uIndexPrec;\n    auto const uNumIndices = static_cast<const uint8_t>(1u << uIndexPrec);\n    INTColor aPalette[BC6H_MAX_INDICES];\n    GeneratePaletteQuantized(pEP, endPts, aPalette);\n\n    float fTotErr = 0;\n    for (size_t i = 0; i < np; ++i)\n    {\n        const XMVECTOR vcolors = XMLoadSInt4(reinterpret_cast<const XMINT4*>(&aColors[i]));\n\n        // Compute ErrorMetricRGB\n        XMVECTOR tpal = XMLoadSInt4(reinterpret_cast<const XMINT4*>(&aPalette[0]));\n        tpal = XMVectorSubtract(vcolors, tpal);\n        float fBestErr = XMVectorGetX(XMVector3Dot(tpal, tpal));\n\n        for (int j = 1; j < uNumIndices && fBestErr > 0; ++j)\n        {\n            // Compute ErrorMetricRGB\n            tpal = XMLoadSInt4(reinterpret_cast<const XMINT4*>(&aPalette[j]));\n            tpal = XMVectorSubtract(vcolors, tpal);\n            const float fErr = XMVectorGetX(XMVector3Dot(tpal, tpal));\n            if (fErr > fBestErr) break;     // error increased, so we're done searching\n            if (fErr < fBestErr) fBestErr = fErr;\n        }\n        fTotErr += fBestErr;\n    }\n    return fTotErr;\n}\n\n\n_Use_decl_annotations_\nfloat D3DX_BC6H::PerturbOne(const EncodeParams* pEP, const INTColor aColors[], size_t np, uint8_t ch,\n    const INTEndPntPair& oldEndPts, INTEndPntPair& newEndPts, float fOldErr, int do_b) const noexcept\n{\n    assert(pEP);\n    uint8_t uPrec;\n    switch (ch)\n    {\n    case 0: uPrec = ms_aInfo[pEP->uMode].RGBAPrec[0][0].r; break;\n    case 1: uPrec = ms_aInfo[pEP->uMode].RGBAPrec[0][0].g; break;\n    case 2: uPrec = ms_aInfo[pEP->uMode].RGBAPrec[0][0].b; break;\n    default: assert(false); newEndPts = oldEndPts; return FLT_MAX;\n    }\n    INTEndPntPair tmpEndPts;\n    float fMinErr = fOldErr;\n    int beststep = 0;\n\n    // copy real endpoints so we can perturb them\n    tmpEndPts = newEndPts = oldEndPts;\n\n    // do a logarithmic search for the best error for this endpoint (which)\n    for (int step = 1 << (uPrec - 1); step; step >>= 1)\n    {\n        bool bImproved = false;\n        for (int sign = -1; sign <= 1; sign += 2)\n        {\n            if (do_b == 0)\n            {\n                tmpEndPts.A[ch] = newEndPts.A[ch] + sign * step;\n                if (tmpEndPts.A[ch] < 0 || tmpEndPts.A[ch] >= (1 << uPrec))\n                    continue;\n            }\n            else\n            {\n                tmpEndPts.B[ch] = newEndPts.B[ch] + sign * step;\n                if (tmpEndPts.B[ch] < 0 || tmpEndPts.B[ch] >= (1 << uPrec))\n                    continue;\n            }\n\n            const float fErr = MapColorsQuantized(pEP, aColors, np, tmpEndPts);\n\n            if (fErr < fMinErr)\n            {\n                bImproved = true;\n                fMinErr = fErr;\n                beststep = sign * step;\n            }\n        }\n        // if this was an improvement, move the endpoint and continue search from there\n        if (bImproved)\n        {\n            if (do_b == 0)\n                newEndPts.A[ch] += beststep;\n            else\n                newEndPts.B[ch] += beststep;\n        }\n    }\n    return fMinErr;\n}\n\n\n_Use_decl_annotations_\nvoid D3DX_BC6H::OptimizeOne(const EncodeParams* pEP, const INTColor aColors[], size_t np, float aOrgErr,\n    const INTEndPntPair &aOrgEndPts, INTEndPntPair &aOptEndPts) const noexcept\n{\n    assert(pEP);\n    float aOptErr = aOrgErr;\n    aOptEndPts.A = aOrgEndPts.A;\n    aOptEndPts.B = aOrgEndPts.B;\n\n    INTEndPntPair new_a, new_b;\n    INTEndPntPair newEndPts;\n    int do_b;\n\n    // now optimize each channel separately\n    for (uint8_t ch = 0; ch < BC6H_NUM_CHANNELS; ++ch)\n    {\n        // figure out which endpoint when perturbed gives the most improvement and start there\n        // if we just alternate, we can easily end up in a local minima\n        const float fErr0 = PerturbOne(pEP, aColors, np, ch, aOptEndPts, new_a, aOptErr, 0);\t// perturb endpt A\n        const float fErr1 = PerturbOne(pEP, aColors, np, ch, aOptEndPts, new_b, aOptErr, 1);\t// perturb endpt B\n\n        if (fErr0 < fErr1)\n        {\n            if (fErr0 >= aOptErr) continue;\n            aOptEndPts.A[ch] = new_a.A[ch];\n            aOptErr = fErr0;\n            do_b = 1;\t\t// do B next\n        }\n        else\n        {\n            if (fErr1 >= aOptErr) continue;\n            aOptEndPts.B[ch] = new_b.B[ch];\n            aOptErr = fErr1;\n            do_b = 0;\t\t// do A next\n        }\n\n        // now alternate endpoints and keep trying until there is no improvement\n        for (;;)\n        {\n            const float fErr = PerturbOne(pEP, aColors, np, ch, aOptEndPts, newEndPts, aOptErr, do_b);\n            if (fErr >= aOptErr)\n                break;\n            if (do_b == 0)\n                aOptEndPts.A[ch] = newEndPts.A[ch];\n            else\n                aOptEndPts.B[ch] = newEndPts.B[ch];\n            aOptErr = fErr;\n            do_b = 1 - do_b;\t// now move the other endpoint\n        }\n    }\n}\n\n\n_Use_decl_annotations_\nvoid D3DX_BC6H::OptimizeEndPoints(const EncodeParams* pEP, const float aOrgErr[], const INTEndPntPair aOrgEndPts[], INTEndPntPair aOptEndPts[]) const noexcept\n{\n    assert(pEP);\n    const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions;\n    assert(uPartitions < BC6H_MAX_REGIONS);\n    _Analysis_assume_(uPartitions < BC6H_MAX_REGIONS);\n    INTColor aPixels[NUM_PIXELS_PER_BLOCK];\n\n    for (size_t p = 0; p <= uPartitions; ++p)\n    {\n        // collect the pixels in the region\n        size_t np = 0;\n        for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n        {\n            if (g_aPartitionTable[p][pEP->uShape][i] == p)\n            {\n                aPixels[np++] = pEP->aIPixels[i];\n            }\n        }\n\n        OptimizeOne(pEP, aPixels, np, aOrgErr[p], aOrgEndPts[p], aOptEndPts[p]);\n    }\n}\n\n\n// Swap endpoints as needed to ensure that the indices at fix up have a 0 high-order bit\n_Use_decl_annotations_\nvoid D3DX_BC6H::SwapIndices(const EncodeParams* pEP, INTEndPntPair aEndPts[], size_t aIndices[]) noexcept\n{\n    assert(pEP);\n    const size_t uPartitions = ms_aInfo[pEP->uMode].uPartitions;\n    const size_t uNumIndices = size_t(1) << ms_aInfo[pEP->uMode].uIndexPrec;\n    const size_t uHighIndexBit = uNumIndices >> 1;\n\n    assert(uPartitions < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES);\n    _Analysis_assume_(uPartitions < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES);\n\n    for (size_t p = 0; p <= uPartitions; ++p)\n    {\n        const size_t i = g_aFixUp[uPartitions][pEP->uShape][p];\n        assert(g_aPartitionTable[uPartitions][pEP->uShape][i] == p);\n        if (aIndices[i] & uHighIndexBit)\n        {\n            // high bit is set, swap the aEndPts and indices for this region\n            std::swap(aEndPts[p].A, aEndPts[p].B);\n\n            for (size_t j = 0; j < NUM_PIXELS_PER_BLOCK; ++j)\n                if (g_aPartitionTable[uPartitions][pEP->uShape][j] == p)\n                    aIndices[j] = uNumIndices - 1 - aIndices[j];\n        }\n    }\n}\n\n\n// assign indices given a tile, shape, and quantized endpoints, return toterr for each region\n_Use_decl_annotations_\nvoid D3DX_BC6H::AssignIndices(const EncodeParams* pEP, const INTEndPntPair aEndPts[], size_t aIndices[], float aTotErr[]) const noexcept\n{\n    assert(pEP);\n    const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions;\n    auto const uNumIndices = static_cast<const uint8_t>(1u << ms_aInfo[pEP->uMode].uIndexPrec);\n\n    assert(uPartitions < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES);\n    _Analysis_assume_(uPartitions < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES);\n\n    // build list of possibles\n    INTColor aPalette[BC6H_MAX_REGIONS][BC6H_MAX_INDICES];\n\n    for (size_t p = 0; p <= uPartitions; ++p)\n    {\n        GeneratePaletteQuantized(pEP, aEndPts[p], aPalette[p]);\n        aTotErr[p] = 0;\n    }\n\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n        const uint8_t uRegion = g_aPartitionTable[uPartitions][pEP->uShape][i];\n        assert(uRegion < BC6H_MAX_REGIONS);\n        _Analysis_assume_(uRegion < BC6H_MAX_REGIONS);\n        float fBestErr = Norm(pEP->aIPixels[i], aPalette[uRegion][0]);\n        aIndices[i] = 0;\n\n        for (uint8_t j = 1; j < uNumIndices && fBestErr > 0; ++j)\n        {\n            const float fErr = Norm(pEP->aIPixels[i], aPalette[uRegion][j]);\n            if (fErr > fBestErr) break;\t// error increased, so we're done searching\n            if (fErr < fBestErr)\n            {\n                fBestErr = fErr;\n                aIndices[i] = j;\n            }\n        }\n        aTotErr[uRegion] += fBestErr;\n    }\n}\n\n\n_Use_decl_annotations_\nvoid D3DX_BC6H::QuantizeEndPts(const EncodeParams* pEP, INTEndPntPair* aQntEndPts) const noexcept\n{\n    assert(pEP && aQntEndPts);\n    const INTEndPntPair* aUnqEndPts = pEP->aUnqEndPts[pEP->uShape];\n    const LDRColorA& Prec = ms_aInfo[pEP->uMode].RGBAPrec[0][0];\n    const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions;\n    assert(uPartitions < BC6H_MAX_REGIONS);\n    _Analysis_assume_(uPartitions < BC6H_MAX_REGIONS);\n\n    for (size_t p = 0; p <= uPartitions; ++p)\n    {\n        aQntEndPts[p].A.r = Quantize(aUnqEndPts[p].A.r, Prec.r, pEP->bSigned);\n        aQntEndPts[p].A.g = Quantize(aUnqEndPts[p].A.g, Prec.g, pEP->bSigned);\n        aQntEndPts[p].A.b = Quantize(aUnqEndPts[p].A.b, Prec.b, pEP->bSigned);\n        aQntEndPts[p].B.r = Quantize(aUnqEndPts[p].B.r, Prec.r, pEP->bSigned);\n        aQntEndPts[p].B.g = Quantize(aUnqEndPts[p].B.g, Prec.g, pEP->bSigned);\n        aQntEndPts[p].B.b = Quantize(aUnqEndPts[p].B.b, Prec.b, pEP->bSigned);\n    }\n}\n\n\n_Use_decl_annotations_\nvoid D3DX_BC6H::EmitBlock(const EncodeParams* pEP, const INTEndPntPair aEndPts[], const size_t aIndices[]) noexcept\n{\n    assert(pEP);\n    const uint8_t uRealMode = ms_aInfo[pEP->uMode].uMode;\n    const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions;\n    const uint8_t uIndexPrec = ms_aInfo[pEP->uMode].uIndexPrec;\n    const size_t uHeaderBits = uPartitions > 0 ? 82u : 65u;\n    const ModeDescriptor* desc = ms_aDesc[pEP->uMode];\n    size_t uStartBit = 0;\n\n    while (uStartBit < uHeaderBits)\n    {\n        switch (desc[uStartBit].m_eField)\n        {\n        case M:  SetBit(uStartBit, uint8_t(uRealMode >> desc[uStartBit].m_uBit) & 0x01u); break;\n        case D:  SetBit(uStartBit, uint8_t(pEP->uShape >> desc[uStartBit].m_uBit) & 0x01u); break;\n        case RW: SetBit(uStartBit, uint8_t(aEndPts[0].A.r >> desc[uStartBit].m_uBit) & 0x01u); break;\n        case RX: SetBit(uStartBit, uint8_t(aEndPts[0].B.r >> desc[uStartBit].m_uBit) & 0x01u); break;\n        case RY: SetBit(uStartBit, uint8_t(aEndPts[1].A.r >> desc[uStartBit].m_uBit) & 0x01u); break;\n        case RZ: SetBit(uStartBit, uint8_t(aEndPts[1].B.r >> desc[uStartBit].m_uBit) & 0x01u); break;\n        case GW: SetBit(uStartBit, uint8_t(aEndPts[0].A.g >> desc[uStartBit].m_uBit) & 0x01u); break;\n        case GX: SetBit(uStartBit, uint8_t(aEndPts[0].B.g >> desc[uStartBit].m_uBit) & 0x01u); break;\n        case GY: SetBit(uStartBit, uint8_t(aEndPts[1].A.g >> desc[uStartBit].m_uBit) & 0x01u); break;\n        case GZ: SetBit(uStartBit, uint8_t(aEndPts[1].B.g >> desc[uStartBit].m_uBit) & 0x01u); break;\n        case BW: SetBit(uStartBit, uint8_t(aEndPts[0].A.b >> desc[uStartBit].m_uBit) & 0x01u); break;\n        case BX: SetBit(uStartBit, uint8_t(aEndPts[0].B.b >> desc[uStartBit].m_uBit) & 0x01u); break;\n        case BY: SetBit(uStartBit, uint8_t(aEndPts[1].A.b >> desc[uStartBit].m_uBit) & 0x01u); break;\n        case BZ: SetBit(uStartBit, uint8_t(aEndPts[1].B.b >> desc[uStartBit].m_uBit) & 0x01u); break;\n        default: assert(false);\n        }\n    }\n\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n        if (IsFixUpOffset(ms_aInfo[pEP->uMode].uPartitions, pEP->uShape, i))\n            SetBits(uStartBit, uIndexPrec - 1u, static_cast<uint8_t>(aIndices[i]));\n        else\n            SetBits(uStartBit, uIndexPrec, static_cast<uint8_t>(aIndices[i]));\n    }\n    assert(uStartBit == 128);\n}\n\n\n_Use_decl_annotations_\nvoid D3DX_BC6H::Refine(EncodeParams* pEP) noexcept\n{\n    assert(pEP);\n    const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions;\n    assert(uPartitions < BC6H_MAX_REGIONS);\n    _Analysis_assume_(uPartitions < BC6H_MAX_REGIONS);\n\n    const bool bTransformed = ms_aInfo[pEP->uMode].bTransformed;\n    float aOrgErr[BC6H_MAX_REGIONS], aOptErr[BC6H_MAX_REGIONS];\n    INTEndPntPair aOrgEndPts[BC6H_MAX_REGIONS], aOptEndPts[BC6H_MAX_REGIONS];\n    size_t aOrgIdx[NUM_PIXELS_PER_BLOCK], aOptIdx[NUM_PIXELS_PER_BLOCK];\n\n    QuantizeEndPts(pEP, aOrgEndPts);\n    AssignIndices(pEP, aOrgEndPts, aOrgIdx, aOrgErr);\n    SwapIndices(pEP, aOrgEndPts, aOrgIdx);\n\n    if (bTransformed) TransformForward(aOrgEndPts);\n    if (EndPointsFit(pEP, aOrgEndPts))\n    {\n        if (bTransformed) TransformInverse(aOrgEndPts, ms_aInfo[pEP->uMode].RGBAPrec[0][0], pEP->bSigned);\n        OptimizeEndPoints(pEP, aOrgErr, aOrgEndPts, aOptEndPts);\n        AssignIndices(pEP, aOptEndPts, aOptIdx, aOptErr);\n        SwapIndices(pEP, aOptEndPts, aOptIdx);\n\n        float fOrgTotErr = 0.0f, fOptTotErr = 0.0f;\n        for (size_t p = 0; p <= uPartitions; ++p)\n        {\n            fOrgTotErr += aOrgErr[p];\n            fOptTotErr += aOptErr[p];\n        }\n\n        if (bTransformed) TransformForward(aOptEndPts);\n        if (EndPointsFit(pEP, aOptEndPts) && fOptTotErr < fOrgTotErr && fOptTotErr < pEP->fBestErr)\n        {\n            pEP->fBestErr = fOptTotErr;\n            EmitBlock(pEP, aOptEndPts, aOptIdx);\n        }\n        else if (fOrgTotErr < pEP->fBestErr)\n        {\n            // either it stopped fitting when we optimized it, or there was no improvement\n            // so go back to the unoptimized endpoints which we know will fit\n            if (bTransformed) TransformForward(aOrgEndPts);\n            pEP->fBestErr = fOrgTotErr;\n            EmitBlock(pEP, aOrgEndPts, aOrgIdx);\n        }\n    }\n}\n\n\n_Use_decl_annotations_\nvoid D3DX_BC6H::GeneratePaletteUnquantized(const EncodeParams* pEP, size_t uRegion, INTColor aPalette[]) noexcept\n{\n    assert(pEP);\n    assert(uRegion < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES);\n    _Analysis_assume_(uRegion < BC6H_MAX_REGIONS && pEP->uShape < BC6H_MAX_SHAPES);\n    const INTEndPntPair& endPts = pEP->aUnqEndPts[pEP->uShape][uRegion];\n    const uint8_t uIndexPrec = ms_aInfo[pEP->uMode].uIndexPrec;\n    auto const uNumIndices = static_cast<const uint8_t>(1u << uIndexPrec);\n    assert(uNumIndices > 0);\n    _Analysis_assume_(uNumIndices > 0);\n\n    const int* aWeights = nullptr;\n    switch (uIndexPrec)\n    {\n    case 3: aWeights = g_aWeights3; assert(uNumIndices <= 8); _Analysis_assume_(uNumIndices <= 8); break;\n    case 4: aWeights = g_aWeights4; assert(uNumIndices <= 16); _Analysis_assume_(uNumIndices <= 16); break;\n    default:\n        assert(false);\n        for (size_t i = 0; i < uNumIndices; ++i)\n        {\n        #pragma prefast(suppress:22102 22103, \"writing blocks in two halves confuses tool\")\n            aPalette[i] = INTColor(0, 0, 0);\n        }\n        return;\n    }\n\n    for (size_t i = 0; i < uNumIndices; ++i)\n    {\n        aPalette[i].r = (endPts.A.r * (BC67_WEIGHT_MAX - aWeights[i]) + endPts.B.r * aWeights[i] + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT;\n        aPalette[i].g = (endPts.A.g * (BC67_WEIGHT_MAX - aWeights[i]) + endPts.B.g * aWeights[i] + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT;\n        aPalette[i].b = (endPts.A.b * (BC67_WEIGHT_MAX - aWeights[i]) + endPts.B.b * aWeights[i] + BC67_WEIGHT_ROUND) >> BC67_WEIGHT_SHIFT;\n    }\n}\n\n\n_Use_decl_annotations_\nfloat D3DX_BC6H::MapColors(const EncodeParams* pEP, size_t uRegion, size_t np, const size_t* auIndex) const noexcept\n{\n    assert(pEP);\n    const uint8_t uIndexPrec = ms_aInfo[pEP->uMode].uIndexPrec;\n    auto const uNumIndices = static_cast<const uint8_t>(1u << uIndexPrec);\n    INTColor aPalette[BC6H_MAX_INDICES];\n    GeneratePaletteUnquantized(pEP, uRegion, aPalette);\n\n    float fTotalErr = 0.0f;\n    for (size_t i = 0; i < np; ++i)\n    {\n        float fBestErr = Norm(pEP->aIPixels[auIndex[i]], aPalette[0]);\n        for (uint8_t j = 1; j < uNumIndices && fBestErr > 0.0f; ++j)\n        {\n            const float fErr = Norm(pEP->aIPixels[auIndex[i]], aPalette[j]);\n            if (fErr > fBestErr) break;      // error increased, so we're done searching\n            if (fErr < fBestErr) fBestErr = fErr;\n        }\n        fTotalErr += fBestErr;\n    }\n\n    return fTotalErr;\n}\n\n_Use_decl_annotations_\nfloat D3DX_BC6H::RoughMSE(EncodeParams* pEP) const noexcept\n{\n    assert(pEP);\n    assert(pEP->uShape < BC6H_MAX_SHAPES);\n    _Analysis_assume_(pEP->uShape < BC6H_MAX_SHAPES);\n\n    INTEndPntPair* aEndPts = pEP->aUnqEndPts[pEP->uShape];\n\n    const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions;\n    assert(uPartitions < BC6H_MAX_REGIONS);\n    _Analysis_assume_(uPartitions < BC6H_MAX_REGIONS);\n\n    size_t auPixIdx[NUM_PIXELS_PER_BLOCK];\n\n    float fError = 0.0f;\n    for (size_t p = 0; p <= uPartitions; ++p)\n    {\n        size_t np = 0;\n        for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n        {\n            if (g_aPartitionTable[uPartitions][pEP->uShape][i] == p)\n            {\n                auPixIdx[np++] = i;\n            }\n        }\n\n        // handle simple cases\n        assert(np > 0);\n        if (np == 1)\n        {\n            aEndPts[p].A = pEP->aIPixels[auPixIdx[0]];\n            aEndPts[p].B = pEP->aIPixels[auPixIdx[0]];\n            continue;\n        }\n        else if (np == 2)\n        {\n            aEndPts[p].A = pEP->aIPixels[auPixIdx[0]];\n            aEndPts[p].B = pEP->aIPixels[auPixIdx[1]];\n            continue;\n        }\n\n        HDRColorA epA, epB;\n        OptimizeRGB(pEP->aHDRPixels, &epA, &epB, 4, np, auPixIdx);\n        aEndPts[p].A.Set(epA, pEP->bSigned);\n        aEndPts[p].B.Set(epB, pEP->bSigned);\n        if (pEP->bSigned)\n        {\n            aEndPts[p].A.Clamp(-F16MAX, F16MAX);\n            aEndPts[p].B.Clamp(-F16MAX, F16MAX);\n        }\n        else\n        {\n            aEndPts[p].A.Clamp(0, F16MAX);\n            aEndPts[p].B.Clamp(0, F16MAX);\n        }\n\n        fError += MapColors(pEP, p, np, auPixIdx);\n    }\n\n    return fError;\n}\n\n\n//-------------------------------------------------------------------------------------\n// BC7 Compression\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nvoid D3DX_BC7::Decode(HDRColorA* pOut) const noexcept\n{\n    assert(pOut);\n\n    size_t uFirst = 0;\n    while (uFirst < 128 && !GetBit(uFirst)) {}\n    const uint8_t uMode = uint8_t(uFirst - 1);\n\n    if (uMode < 8)\n    {\n        const uint8_t uPartitions = ms_aInfo[uMode].uPartitions;\n        assert(uPartitions < BC7_MAX_REGIONS);\n        _Analysis_assume_(uPartitions < BC7_MAX_REGIONS);\n\n        auto const uNumEndPts = static_cast<const uint8_t>((unsigned(uPartitions) + 1u) << 1);\n        const uint8_t uIndexPrec = ms_aInfo[uMode].uIndexPrec;\n        const uint8_t uIndexPrec2 = ms_aInfo[uMode].uIndexPrec2;\n        size_t i;\n        size_t uStartBit = size_t(uMode) + 1;\n        uint8_t P[6];\n        const uint8_t uShape = GetBits(uStartBit, ms_aInfo[uMode].uPartitionBits);\n        assert(uShape < BC7_MAX_SHAPES);\n        _Analysis_assume_(uShape < BC7_MAX_SHAPES);\n\n        const uint8_t uRotation = GetBits(uStartBit, ms_aInfo[uMode].uRotationBits);\n        assert(uRotation < 4);\n\n        const uint8_t uIndexMode = GetBits(uStartBit, ms_aInfo[uMode].uIndexModeBits);\n        assert(uIndexMode < 2);\n\n        LDRColorA c[BC7_MAX_REGIONS << 1];\n        const LDRColorA RGBAPrec = ms_aInfo[uMode].RGBAPrec;\n        const LDRColorA RGBAPrecWithP = ms_aInfo[uMode].RGBAPrecWithP;\n\n        assert(uNumEndPts <= (BC7_MAX_REGIONS << 1));\n\n        // Red channel\n        for (i = 0; i < uNumEndPts; i++)\n        {\n            if (uStartBit + RGBAPrec.r > 128)\n            {\n            #ifdef _DEBUG\n                OutputDebugStringA(\"BC7: Invalid block encountered during decoding\\n\");\n            #endif\n                FillWithErrorColors(pOut);\n                return;\n            }\n\n            c[i].r = GetBits(uStartBit, RGBAPrec.r);\n        }\n\n        // Green channel\n        for (i = 0; i < uNumEndPts; i++)\n        {\n            if (uStartBit + RGBAPrec.g > 128)\n            {\n            #ifdef _DEBUG\n                OutputDebugStringA(\"BC7: Invalid block encountered during decoding\\n\");\n            #endif\n                FillWithErrorColors(pOut);\n                return;\n            }\n\n            c[i].g = GetBits(uStartBit, RGBAPrec.g);\n        }\n\n        // Blue channel\n        for (i = 0; i < uNumEndPts; i++)\n        {\n            if (uStartBit + RGBAPrec.b > 128)\n            {\n            #ifdef _DEBUG\n                OutputDebugStringA(\"BC7: Invalid block encountered during decoding\\n\");\n            #endif\n                FillWithErrorColors(pOut);\n                return;\n            }\n\n            c[i].b = GetBits(uStartBit, RGBAPrec.b);\n        }\n\n        // Alpha channel\n        for (i = 0; i < uNumEndPts; i++)\n        {\n            if (uStartBit + RGBAPrec.a > 128)\n            {\n            #ifdef _DEBUG\n                OutputDebugStringA(\"BC7: Invalid block encountered during decoding\\n\");\n            #endif\n                FillWithErrorColors(pOut);\n                return;\n            }\n\n            c[i].a = RGBAPrec.a ? GetBits(uStartBit, RGBAPrec.a) : 255u;\n        }\n\n        // P-bits\n        assert(ms_aInfo[uMode].uPBits <= 6);\n        _Analysis_assume_(ms_aInfo[uMode].uPBits <= 6);\n        for (i = 0; i < ms_aInfo[uMode].uPBits; i++)\n        {\n            if (uStartBit > 127)\n            {\n            #ifdef _DEBUG\n                OutputDebugStringA(\"BC7: Invalid block encountered during decoding\\n\");\n            #endif\n                FillWithErrorColors(pOut);\n                return;\n            }\n\n            P[i] = GetBit(uStartBit);\n        }\n\n        if (ms_aInfo[uMode].uPBits)\n        {\n            for (i = 0; i < uNumEndPts; i++)\n            {\n                size_t pi = i * ms_aInfo[uMode].uPBits / uNumEndPts;\n                for (uint8_t ch = 0; ch < BC7_NUM_CHANNELS; ch++)\n                {\n                    if (RGBAPrec[ch] != RGBAPrecWithP[ch])\n                    {\n                        c[i][ch] = static_cast<uint8_t>((unsigned(c[i][ch]) << 1) | P[pi]);\n                    }\n                }\n            }\n        }\n\n        for (i = 0; i < uNumEndPts; i++)\n        {\n            c[i] = Unquantize(c[i], RGBAPrecWithP);\n        }\n\n        uint8_t w1[NUM_PIXELS_PER_BLOCK], w2[NUM_PIXELS_PER_BLOCK];\n\n        // read color indices\n        for (i = 0; i < NUM_PIXELS_PER_BLOCK; i++)\n        {\n            const size_t uNumBits = IsFixUpOffset(ms_aInfo[uMode].uPartitions, uShape, i) ? uIndexPrec - 1u : uIndexPrec;\n            if (uStartBit + uNumBits > 128)\n            {\n            #ifdef _DEBUG\n                OutputDebugStringA(\"BC7: Invalid block encountered during decoding\\n\");\n            #endif\n                FillWithErrorColors(pOut);\n                return;\n            }\n            w1[i] = GetBits(uStartBit, uNumBits);\n        }\n\n        // read alpha indices\n        if (uIndexPrec2)\n        {\n            for (i = 0; i < NUM_PIXELS_PER_BLOCK; i++)\n            {\n                const size_t uNumBits = i ? uIndexPrec2 : uIndexPrec2 - 1u;\n                if (uStartBit + uNumBits > 128)\n                {\n                #ifdef _DEBUG\n                    OutputDebugStringA(\"BC7: Invalid block encountered during decoding\\n\");\n                #endif\n                    FillWithErrorColors(pOut);\n                    return;\n                }\n                w2[i] = GetBits(uStartBit, uNumBits);\n            }\n        }\n\n        for (i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n        {\n            const uint8_t uRegion = g_aPartitionTable[uPartitions][uShape][i];\n            LDRColorA outPixel;\n            if (uIndexPrec2 == 0)\n            {\n                LDRColorA::Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w1[i], w1[i], uIndexPrec, uIndexPrec, outPixel);\n            }\n            else\n            {\n                if (uIndexMode == 0)\n                {\n                    LDRColorA::Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w1[i], w2[i], uIndexPrec, uIndexPrec2, outPixel);\n                }\n                else\n                {\n                    LDRColorA::Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w2[i], w1[i], uIndexPrec2, uIndexPrec, outPixel);\n                }\n            }\n\n            switch (uRotation)\n            {\n            case 1: std::swap(outPixel.r, outPixel.a); break;\n            case 2: std::swap(outPixel.g, outPixel.a); break;\n            case 3: std::swap(outPixel.b, outPixel.a); break;\n            }\n\n            pOut[i] = HDRColorA(outPixel);\n        }\n    }\n    else\n    {\n    #ifdef _DEBUG\n        OutputDebugStringA(\"BC7: Reserved mode 8 encountered during decoding\\n\");\n    #endif\n        // Per the BC7 format spec, we must return transparent black\n        memset(pOut, 0, sizeof(HDRColorA) * NUM_PIXELS_PER_BLOCK);\n    }\n}\n\n_Use_decl_annotations_\nvoid D3DX_BC7::Encode(uint32_t flags, const HDRColorA* const pIn) noexcept\n{\n    assert(pIn);\n\n    D3DX_BC7 final = *this;\n    EncodeParams EP(pIn);\n    float fMSEBest = FLT_MAX;\n    uint32_t alphaMask = 0xFF;\n\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n    {\n        EP.aLDRPixels[i].r = uint8_t(std::max<float>(0.0f, std::min<float>(255.0f, pIn[i].r * 255.0f + 0.01f)));\n        EP.aLDRPixels[i].g = uint8_t(std::max<float>(0.0f, std::min<float>(255.0f, pIn[i].g * 255.0f + 0.01f)));\n        EP.aLDRPixels[i].b = uint8_t(std::max<float>(0.0f, std::min<float>(255.0f, pIn[i].b * 255.0f + 0.01f)));\n        EP.aLDRPixels[i].a = uint8_t(std::max<float>(0.0f, std::min<float>(255.0f, pIn[i].a * 255.0f + 0.01f)));\n        alphaMask &= EP.aLDRPixels[i].a;\n    }\n\n    const bool bHasAlpha = (alphaMask != 0xFF);\n\n    for (EP.uMode = 0; EP.uMode < 8 && fMSEBest > 0; ++EP.uMode)\n    {\n        if (!(flags & BC_FLAGS_USE_3SUBSETS) && (EP.uMode == 0 || EP.uMode == 2))\n        {\n            // 3 subset modes tend to be used rarely and add significant compression time\n            continue;\n        }\n\n        if ((flags & TEX_COMPRESS_BC7_QUICK) && (EP.uMode != 6))\n        {\n            // Use only mode 6\n            continue;\n        }\n\n        if ((!bHasAlpha) && (EP.uMode == 7))\n        {\n            // There is no value in using mode 7 for completely opaque blocks (the other 2 subset modes handle this case for opaque blocks), so skip it for a small perf win.\n            continue;\n        }\n\n        const size_t uShapes = size_t(1) << ms_aInfo[EP.uMode].uPartitionBits;\n        assert(uShapes <= BC7_MAX_SHAPES);\n        _Analysis_assume_(uShapes <= BC7_MAX_SHAPES);\n\n        const size_t uNumRots = size_t(1) << ms_aInfo[EP.uMode].uRotationBits;\n        const size_t uNumIdxMode = size_t(1) << ms_aInfo[EP.uMode].uIndexModeBits;\n        // Number of rough cases to look at. reasonable values of this are 1, uShapes/4, and uShapes\n        // uShapes/4 gets nearly all the cases; you can increase that a bit (say by 3 or 4) if you really want to squeeze the last bit out\n        const size_t uItems = std::max<size_t>(1, uShapes >> 2);\n        float afRoughMSE[BC7_MAX_SHAPES];\n        size_t auShape[BC7_MAX_SHAPES];\n\n        for (size_t r = 0; r < uNumRots && fMSEBest > 0; ++r)\n        {\n            switch (r)\n            {\n            case 1: for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].r, EP.aLDRPixels[i].a); break;\n            case 2: for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].g, EP.aLDRPixels[i].a); break;\n            case 3: for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].b, EP.aLDRPixels[i].a); break;\n            }\n\n            for (size_t im = 0; im < uNumIdxMode && fMSEBest > 0; ++im)\n            {\n                // pick the best uItems shapes and refine these.\n                for (size_t s = 0; s < uShapes; s++)\n                {\n                    afRoughMSE[s] = RoughMSE(&EP, s, im);\n                    auShape[s] = s;\n                }\n\n                // Bubble up the first uItems items\n                for (size_t i = 0; i < uItems; i++)\n                {\n                    for (size_t j = i + 1; j < uShapes; j++)\n                    {\n                        if (afRoughMSE[i] > afRoughMSE[j])\n                        {\n                            std::swap(afRoughMSE[i], afRoughMSE[j]);\n                            std::swap(auShape[i], auShape[j]);\n                        }\n                    }\n                }\n\n                for (size_t i = 0; i < uItems && fMSEBest > 0; i++)\n                {\n                    const float fMSE = Refine(&EP, auShape[i], r, im);\n                    if (fMSE < fMSEBest)\n                    {\n                        final = *this;\n                        fMSEBest = fMSE;\n                    }\n                }\n            }\n\n            switch (r)\n            {\n            case 1: for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].r, EP.aLDRPixels[i].a); break;\n            case 2: for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].g, EP.aLDRPixels[i].a); break;\n            case 3: for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++) std::swap(EP.aLDRPixels[i].b, EP.aLDRPixels[i].a); break;\n            }\n        }\n    }\n\n    *this = final;\n}\n\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nvoid D3DX_BC7::GeneratePaletteQuantized(const EncodeParams* pEP, size_t uIndexMode, const LDREndPntPair& endPts, LDRColorA aPalette[]) const noexcept\n{\n    assert(pEP);\n    const size_t uIndexPrec = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec2 : ms_aInfo[pEP->uMode].uIndexPrec;\n    const size_t uIndexPrec2 = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec : ms_aInfo[pEP->uMode].uIndexPrec2;\n    const size_t uNumIndices = size_t(1) << uIndexPrec;\n    const size_t uNumIndices2 = size_t(1) << uIndexPrec2;\n    assert(uNumIndices > 0 && uNumIndices2 > 0);\n    _Analysis_assume_(uNumIndices > 0 && uNumIndices2 > 0);\n    assert((uNumIndices <= BC7_MAX_INDICES) && (uNumIndices2 <= BC7_MAX_INDICES));\n    _Analysis_assume_((uNumIndices <= BC7_MAX_INDICES) && (uNumIndices2 <= BC7_MAX_INDICES));\n\n    const LDRColorA a = Unquantize(endPts.A, ms_aInfo[pEP->uMode].RGBAPrecWithP);\n    const LDRColorA b = Unquantize(endPts.B, ms_aInfo[pEP->uMode].RGBAPrecWithP);\n    if (uIndexPrec2 == 0)\n    {\n        for (size_t i = 0; i < uNumIndices; i++)\n            LDRColorA::Interpolate(a, b, i, i, uIndexPrec, uIndexPrec, aPalette[i]);\n    }\n    else\n    {\n        for (size_t i = 0; i < uNumIndices; i++)\n            LDRColorA::InterpolateRGB(a, b, i, uIndexPrec, aPalette[i]);\n        for (size_t i = 0; i < uNumIndices2; i++)\n            LDRColorA::InterpolateA(a, b, i, uIndexPrec2, aPalette[i]);\n    }\n}\n\n_Use_decl_annotations_\nfloat D3DX_BC7::PerturbOne(const EncodeParams* pEP, const LDRColorA aColors[], size_t np, size_t uIndexMode, size_t ch,\n    const LDREndPntPair &oldEndPts, LDREndPntPair &newEndPts, float fOldErr, uint8_t do_b) const noexcept\n{\n    assert(pEP);\n    const int prec = ms_aInfo[pEP->uMode].RGBAPrecWithP[ch];\n    LDREndPntPair tmp_endPts = newEndPts = oldEndPts;\n    float fMinErr = fOldErr;\n    uint8_t* pnew_c = (do_b ? &newEndPts.B[ch] : &newEndPts.A[ch]);\n    uint8_t* ptmp_c = (do_b ? &tmp_endPts.B[ch] : &tmp_endPts.A[ch]);\n\n    // do a logarithmic search for the best error for this endpoint (which)\n    for (int step = 1 << (prec - 1); step; step >>= 1)\n    {\n        bool bImproved = false;\n        int beststep = 0;\n        for (int sign = -1; sign <= 1; sign += 2)\n        {\n            int tmp = int(*pnew_c) + sign * step;\n            if (tmp < 0 || tmp >= (1 << prec))\n                continue;\n            else\n                *ptmp_c = static_cast<uint8_t>(tmp);\n\n            const float fTotalErr = MapColors(pEP, aColors, np, uIndexMode, tmp_endPts, fMinErr);\n            if (fTotalErr < fMinErr)\n            {\n                bImproved = true;\n                fMinErr = fTotalErr;\n                beststep = sign * step;\n            }\n        }\n\n        // if this was an improvement, move the endpoint and continue search from there\n        if (bImproved)\n            *pnew_c = uint8_t(int(*pnew_c) + beststep);\n    }\n    return fMinErr;\n}\n\n// perturb the endpoints at least -3 to 3.\n// always ensure endpoint ordering is preserved (no need to overlap the scan)\n_Use_decl_annotations_\nvoid D3DX_BC7::Exhaustive(const EncodeParams* pEP, const LDRColorA aColors[], size_t np, size_t uIndexMode, size_t ch,\n    float& fOrgErr, LDREndPntPair& optEndPt) const noexcept\n{\n    assert(pEP);\n    const uint8_t uPrec = ms_aInfo[pEP->uMode].RGBAPrecWithP[ch];\n    LDREndPntPair tmpEndPt;\n    if (fOrgErr == 0)\n        return;\n\n    constexpr int delta = 5;\n\n    // ok figure out the range of A and B\n    tmpEndPt = optEndPt;\n    const int alow = std::max<int>(0, int(optEndPt.A[ch]) - delta);\n    const int ahigh = std::min<int>((1 << uPrec) - 1, int(optEndPt.A[ch]) + delta);\n    const int blow = std::max<int>(0, int(optEndPt.B[ch]) - delta);\n    const int bhigh = std::min<int>((1 << uPrec) - 1, int(optEndPt.B[ch]) + delta);\n    int amin = 0;\n    int bmin = 0;\n\n    float fBestErr = fOrgErr;\n    if (optEndPt.A[ch] <= optEndPt.B[ch])\n    {\n        // keep a <= b\n        for (int a = alow; a <= ahigh; ++a)\n        {\n            for (int b = std::max<int>(a, blow); b < bhigh; ++b)\n            {\n                tmpEndPt.A[ch] = static_cast<uint8_t>(a);\n                tmpEndPt.B[ch] = static_cast<uint8_t>(b);\n\n                const float fErr = MapColors(pEP, aColors, np, uIndexMode, tmpEndPt, fBestErr);\n                if (fErr < fBestErr)\n                {\n                    amin = a;\n                    bmin = b;\n                    fBestErr = fErr;\n                }\n            }\n        }\n    }\n    else\n    {\n        // keep b <= a\n        for (int b = blow; b < bhigh; ++b)\n        {\n            for (int a = std::max<int>(b, alow); a <= ahigh; ++a)\n            {\n                tmpEndPt.A[ch] = static_cast<uint8_t>(a);\n                tmpEndPt.B[ch] = static_cast<uint8_t>(b);\n\n                const float fErr = MapColors(pEP, aColors, np, uIndexMode, tmpEndPt, fBestErr);\n                if (fErr < fBestErr)\n                {\n                    amin = a;\n                    bmin = b;\n                    fBestErr = fErr;\n                }\n            }\n        }\n    }\n\n    if (fBestErr < fOrgErr)\n    {\n        optEndPt.A[ch] = static_cast<uint8_t>(amin);\n        optEndPt.B[ch] = static_cast<uint8_t>(bmin);\n        fOrgErr = fBestErr;\n    }\n}\n\n_Use_decl_annotations_\nvoid D3DX_BC7::OptimizeOne(const EncodeParams* pEP, const LDRColorA aColors[], size_t np, size_t uIndexMode,\n    float fOrgErr, const LDREndPntPair& org, LDREndPntPair& opt) const noexcept\n{\n    assert(pEP);\n\n    float fOptErr = fOrgErr;\n    opt = org;\n\n    LDREndPntPair new_a, new_b;\n    LDREndPntPair newEndPts;\n    uint8_t do_b;\n\n    // now optimize each channel separately\n    for (size_t ch = 0; ch < BC7_NUM_CHANNELS; ++ch)\n    {\n        if (ms_aInfo[pEP->uMode].RGBAPrecWithP[ch] == 0)\n            continue;\n\n        // figure out which endpoint when perturbed gives the most improvement and start there\n        // if we just alternate, we can easily end up in a local minima\n        const float fErr0 = PerturbOne(pEP, aColors, np, uIndexMode, ch, opt, new_a, fOptErr, 0);\t// perturb endpt A\n        const float fErr1 = PerturbOne(pEP, aColors, np, uIndexMode, ch, opt, new_b, fOptErr, 1);\t// perturb endpt B\n\n        uint8_t& copt_a = opt.A[ch];\n        uint8_t& copt_b = opt.B[ch];\n        uint8_t& cnew_a = new_a.A[ch];\n        uint8_t& cnew_b = new_a.B[ch];\n\n        if (fErr0 < fErr1)\n        {\n            if (fErr0 >= fOptErr)\n                continue;\n            copt_a = cnew_a;\n            fOptErr = fErr0;\n            do_b = 1;\t\t// do B next\n        }\n        else\n        {\n            if (fErr1 >= fOptErr)\n                continue;\n            copt_b = cnew_b;\n            fOptErr = fErr1;\n            do_b = 0;\t\t// do A next\n        }\n\n        // now alternate endpoints and keep trying until there is no improvement\n        for (; ; )\n        {\n            const float fErr = PerturbOne(pEP, aColors, np, uIndexMode, ch, opt, newEndPts, fOptErr, do_b);\n            if (fErr >= fOptErr)\n                break;\n            if (do_b == 0)\n                copt_a = cnew_a;\n            else\n                copt_b = cnew_b;\n            fOptErr = fErr;\n            do_b = 1u - do_b;\t// now move the other endpoint\n        }\n    }\n\n    // finally, do a small exhaustive search around what we think is the global minima to be sure\n    for (size_t ch = 0; ch < BC7_NUM_CHANNELS; ch++)\n        Exhaustive(pEP, aColors, np, uIndexMode, ch, fOptErr, opt);\n}\n\n_Use_decl_annotations_\nvoid D3DX_BC7::OptimizeEndPoints(const EncodeParams* pEP, size_t uShape, size_t uIndexMode, const float afOrgErr[],\n    const LDREndPntPair aOrgEndPts[], LDREndPntPair aOptEndPts[]) const noexcept\n{\n    assert(pEP);\n    const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions;\n    assert(uPartitions < BC7_MAX_REGIONS && uShape < BC7_MAX_SHAPES);\n    _Analysis_assume_(uPartitions < BC7_MAX_REGIONS && uShape < BC7_MAX_SHAPES);\n\n    LDRColorA aPixels[NUM_PIXELS_PER_BLOCK];\n\n    for (size_t p = 0; p <= uPartitions; ++p)\n    {\n        // collect the pixels in the region\n        size_t np = 0;\n        for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n            if (g_aPartitionTable[uPartitions][uShape][i] == p)\n                aPixels[np++] = pEP->aLDRPixels[i];\n\n        OptimizeOne(pEP, aPixels, np, uIndexMode, afOrgErr[p], aOrgEndPts[p], aOptEndPts[p]);\n    }\n}\n\n_Use_decl_annotations_\nvoid D3DX_BC7::AssignIndices(const EncodeParams* pEP, size_t uShape, size_t uIndexMode, LDREndPntPair endPts[], size_t aIndices[], size_t aIndices2[],\n    float afTotErr[]) const noexcept\n{\n    assert(pEP);\n    assert(uShape < BC7_MAX_SHAPES);\n    _Analysis_assume_(uShape < BC7_MAX_SHAPES);\n\n    const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions;\n    assert(uPartitions < BC7_MAX_REGIONS);\n    _Analysis_assume_(uPartitions < BC7_MAX_REGIONS);\n\n    const uint8_t uIndexPrec = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec2 : ms_aInfo[pEP->uMode].uIndexPrec;\n    const uint8_t uIndexPrec2 = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec : ms_aInfo[pEP->uMode].uIndexPrec2;\n    auto const uNumIndices = static_cast<const uint8_t>(1u << uIndexPrec);\n    auto const uNumIndices2 = static_cast<const uint8_t>(1u << uIndexPrec2);\n\n    assert((uNumIndices <= BC7_MAX_INDICES) && (uNumIndices2 <= BC7_MAX_INDICES));\n    _Analysis_assume_((uNumIndices <= BC7_MAX_INDICES) && (uNumIndices2 <= BC7_MAX_INDICES));\n\n    const uint8_t uHighestIndexBit = uint8_t(uNumIndices >> 1);\n    const uint8_t uHighestIndexBit2 = uint8_t(uNumIndices2 >> 1);\n    LDRColorA aPalette[BC7_MAX_REGIONS][BC7_MAX_INDICES];\n\n    // build list of possibles\n    for (size_t p = 0; p <= uPartitions; p++)\n    {\n        GeneratePaletteQuantized(pEP, uIndexMode, endPts[p], aPalette[p]);\n        afTotErr[p] = 0;\n    }\n\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++)\n    {\n        uint8_t uRegion = g_aPartitionTable[uPartitions][uShape][i];\n        assert(uRegion < BC7_MAX_REGIONS);\n        _Analysis_assume_(uRegion < BC7_MAX_REGIONS);\n        afTotErr[uRegion] += ComputeError(pEP->aLDRPixels[i], aPalette[uRegion], uIndexPrec, uIndexPrec2, &(aIndices[i]), &(aIndices2[i]));\n    }\n\n    // swap endpoints as needed to ensure that the indices at index_positions have a 0 high-order bit\n    if (uIndexPrec2 == 0)\n    {\n        for (size_t p = 0; p <= uPartitions; p++)\n        {\n            if (aIndices[g_aFixUp[uPartitions][uShape][p]] & uHighestIndexBit)\n            {\n                std::swap(endPts[p].A, endPts[p].B);\n                for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++)\n                    if (g_aPartitionTable[uPartitions][uShape][i] == p)\n                        aIndices[i] = uNumIndices - 1 - aIndices[i];\n            }\n            assert((aIndices[g_aFixUp[uPartitions][uShape][p]] & uHighestIndexBit) == 0);\n        }\n    }\n    else\n    {\n        for (size_t p = 0; p <= uPartitions; p++)\n        {\n            if (aIndices[g_aFixUp[uPartitions][uShape][p]] & uHighestIndexBit)\n            {\n                std::swap(endPts[p].A.r, endPts[p].B.r);\n                std::swap(endPts[p].A.g, endPts[p].B.g);\n                std::swap(endPts[p].A.b, endPts[p].B.b);\n                for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++)\n                    if (g_aPartitionTable[uPartitions][uShape][i] == p)\n                        aIndices[i] = uNumIndices - 1 - aIndices[i];\n            }\n            assert((aIndices[g_aFixUp[uPartitions][uShape][p]] & uHighestIndexBit) == 0);\n\n            if (aIndices2[0] & uHighestIndexBit2)\n            {\n                std::swap(endPts[p].A.a, endPts[p].B.a);\n                for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++)\n                    aIndices2[i] = uNumIndices2 - 1 - aIndices2[i];\n            }\n            assert((aIndices2[0] & uHighestIndexBit2) == 0);\n        }\n    }\n}\n\n_Use_decl_annotations_\nvoid D3DX_BC7::EmitBlock(const EncodeParams* pEP, size_t uShape, size_t uRotation, size_t uIndexMode, const LDREndPntPair aEndPts[], const size_t aIndex[], const size_t aIndex2[]) noexcept\n{\n    assert(pEP);\n    const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions;\n    assert(uPartitions < BC7_MAX_REGIONS);\n    _Analysis_assume_(uPartitions < BC7_MAX_REGIONS);\n\n    const size_t uPBits = ms_aInfo[pEP->uMode].uPBits;\n    const size_t uIndexPrec = ms_aInfo[pEP->uMode].uIndexPrec;\n    const size_t uIndexPrec2 = ms_aInfo[pEP->uMode].uIndexPrec2;\n    const LDRColorA RGBAPrec = ms_aInfo[pEP->uMode].RGBAPrec;\n    const LDRColorA RGBAPrecWithP = ms_aInfo[pEP->uMode].RGBAPrecWithP;\n    size_t i;\n    size_t uStartBit = 0;\n    SetBits(uStartBit, pEP->uMode, 0);\n    SetBits(uStartBit, 1, 1);\n    SetBits(uStartBit, ms_aInfo[pEP->uMode].uRotationBits, static_cast<uint8_t>(uRotation));\n    SetBits(uStartBit, ms_aInfo[pEP->uMode].uIndexModeBits, static_cast<uint8_t>(uIndexMode));\n    SetBits(uStartBit, ms_aInfo[pEP->uMode].uPartitionBits, static_cast<uint8_t>(uShape));\n\n    if (uPBits)\n    {\n        const size_t uNumEP = (size_t(uPartitions) + 1) << 1;\n        uint8_t aPVote[BC7_MAX_REGIONS << 1] = { 0,0,0,0,0,0 };\n        uint8_t aCount[BC7_MAX_REGIONS << 1] = { 0,0,0,0,0,0 };\n        for (uint8_t ch = 0; ch < BC7_NUM_CHANNELS; ch++)\n        {\n            uint8_t ep = 0;\n            for (i = 0; i <= uPartitions; i++)\n            {\n                if (RGBAPrec[ch] == RGBAPrecWithP[ch])\n                {\n                    SetBits(uStartBit, RGBAPrec[ch], aEndPts[i].A[ch]);\n                    SetBits(uStartBit, RGBAPrec[ch], aEndPts[i].B[ch]);\n                }\n                else\n                {\n                    SetBits(uStartBit, RGBAPrec[ch], uint8_t(aEndPts[i].A[ch] >> 1));\n                    SetBits(uStartBit, RGBAPrec[ch], uint8_t(aEndPts[i].B[ch] >> 1));\n                    size_t idx = ep++ * uPBits / uNumEP;\n                    assert(idx < (BC7_MAX_REGIONS << 1));\n                    _Analysis_assume_(idx < (BC7_MAX_REGIONS << 1));\n                    aPVote[idx] += aEndPts[i].A[ch] & 0x01;\n                    aCount[idx]++;\n                    idx = ep++ * uPBits / uNumEP;\n                    assert(idx < (BC7_MAX_REGIONS << 1));\n                    _Analysis_assume_(idx < (BC7_MAX_REGIONS << 1));\n                    aPVote[idx] += aEndPts[i].B[ch] & 0x01;\n                    aCount[idx]++;\n                }\n            }\n        }\n\n        for (i = 0; i < uPBits; i++)\n        {\n            SetBits(uStartBit, 1, (aPVote[i] >(aCount[i] >> 1)) ? 1u : 0u);\n        }\n    }\n    else\n    {\n        for (size_t ch = 0; ch < BC7_NUM_CHANNELS; ch++)\n        {\n            for (i = 0; i <= uPartitions; i++)\n            {\n                SetBits(uStartBit, RGBAPrec[ch], aEndPts[i].A[ch]);\n                SetBits(uStartBit, RGBAPrec[ch], aEndPts[i].B[ch]);\n            }\n        }\n    }\n\n    const size_t* aI1 = uIndexMode ? aIndex2 : aIndex;\n    const size_t* aI2 = uIndexMode ? aIndex : aIndex2;\n    for (i = 0; i < NUM_PIXELS_PER_BLOCK; i++)\n    {\n        if (IsFixUpOffset(ms_aInfo[pEP->uMode].uPartitions, uShape, i))\n            SetBits(uStartBit, uIndexPrec - 1, static_cast<uint8_t>(aI1[i]));\n        else\n            SetBits(uStartBit, uIndexPrec, static_cast<uint8_t>(aI1[i]));\n    }\n    if (uIndexPrec2)\n        for (i = 0; i < NUM_PIXELS_PER_BLOCK; i++)\n            SetBits(uStartBit, i ? uIndexPrec2 : uIndexPrec2 - 1, static_cast<uint8_t>(aI2[i]));\n\n    assert(uStartBit == 128);\n}\n\n_Use_decl_annotations_\nvoid D3DX_BC7::FixEndpointPBits(const EncodeParams* pEP, const LDREndPntPair *pOrigEndpoints, LDREndPntPair *pFixedEndpoints) noexcept\n{\n    assert(pEP);\n    const size_t uPartitions = ms_aInfo[pEP->uMode].uPartitions;\n    assert(uPartitions < BC7_MAX_REGIONS);\n    _Analysis_assume_(uPartitions < BC7_MAX_REGIONS);\n\n    pFixedEndpoints[0] = pOrigEndpoints[0];\n    pFixedEndpoints[1] = pOrigEndpoints[1];\n    pFixedEndpoints[2] = pOrigEndpoints[2];\n\n    const size_t uPBits = ms_aInfo[pEP->uMode].uPBits;\n\n    if (uPBits)\n    {\n        const size_t uNumEP = size_t(1 + uPartitions) << 1;\n        uint8_t aPVote[BC7_MAX_REGIONS << 1] = { 0,0,0,0,0,0 };\n        uint8_t aCount[BC7_MAX_REGIONS << 1] = { 0,0,0,0,0,0 };\n\n        const LDRColorA RGBAPrec = ms_aInfo[pEP->uMode].RGBAPrec;\n        const LDRColorA RGBAPrecWithP = ms_aInfo[pEP->uMode].RGBAPrecWithP;\n\n        for (uint8_t ch = 0; ch < BC7_NUM_CHANNELS; ch++)\n        {\n            uint8_t ep = 0;\n            for (size_t i = 0; i <= uPartitions; i++)\n            {\n                if (RGBAPrec[ch] == RGBAPrecWithP[ch])\n                {\n                    pFixedEndpoints[i].A[ch] = pOrigEndpoints[i].A[ch];\n                    pFixedEndpoints[i].B[ch] = pOrigEndpoints[i].B[ch];\n                }\n                else\n                {\n                    pFixedEndpoints[i].A[ch] = uint8_t(pOrigEndpoints[i].A[ch] >> 1);\n                    pFixedEndpoints[i].B[ch] = uint8_t(pOrigEndpoints[i].B[ch] >> 1);\n\n                    size_t idx = ep++ * uPBits / uNumEP;\n                    assert(idx < (BC7_MAX_REGIONS << 1));\n                    _Analysis_assume_(idx < (BC7_MAX_REGIONS << 1));\n                    aPVote[idx] += pOrigEndpoints[i].A[ch] & 0x01;\n                    aCount[idx]++;\n                    idx = ep++ * uPBits / uNumEP;\n                    assert(idx < (BC7_MAX_REGIONS << 1));\n                    _Analysis_assume_(idx < (BC7_MAX_REGIONS << 1));\n                    aPVote[idx] += pOrigEndpoints[i].B[ch] & 0x01;\n                    aCount[idx]++;\n                }\n            }\n        }\n\n        // Compute the actual pbits we'll use when we encode block. Note this is not\n        // rounding the component indices correctly in cases the pbits != a component's LSB.\n        int pbits[BC7_MAX_REGIONS << 1];\n        for (size_t i = 0; i < uPBits; i++)\n            pbits[i] = aPVote[i] >(aCount[i] >> 1) ? 1 : 0;\n\n        // Now calculate the actual endpoints with proper pbits, so error calculations are accurate.\n        if (pEP->uMode == 1)\n        {\n            // shared pbits\n            for (uint8_t ch = 0; ch < BC7_NUM_CHANNELS; ch++)\n            {\n                for (size_t i = 0; i <= uPartitions; i++)\n                {\n                    pFixedEndpoints[i].A[ch] = static_cast<uint8_t>((pFixedEndpoints[i].A[ch] << 1) | pbits[i]);\n                    pFixedEndpoints[i].B[ch] = static_cast<uint8_t>((pFixedEndpoints[i].B[ch] << 1) | pbits[i]);\n                }\n            }\n        }\n        else\n        {\n            for (uint8_t ch = 0; ch < BC7_NUM_CHANNELS; ch++)\n            {\n                for (size_t i = 0; i <= uPartitions; i++)\n                {\n                    pFixedEndpoints[i].A[ch] = static_cast<uint8_t>((pFixedEndpoints[i].A[ch] << 1) | pbits[i * 2 + 0]);\n                    pFixedEndpoints[i].B[ch] = static_cast<uint8_t>((pFixedEndpoints[i].B[ch] << 1) | pbits[i * 2 + 1]);\n                }\n            }\n        }\n    }\n}\n\n_Use_decl_annotations_\nfloat D3DX_BC7::Refine(const EncodeParams* pEP, size_t uShape, size_t uRotation, size_t uIndexMode) noexcept\n{\n    assert(pEP);\n    assert(uShape < BC7_MAX_SHAPES);\n    _Analysis_assume_(uShape < BC7_MAX_SHAPES);\n\n    const size_t uPartitions = ms_aInfo[pEP->uMode].uPartitions;\n    assert(uPartitions < BC7_MAX_REGIONS);\n    _Analysis_assume_(uPartitions < BC7_MAX_REGIONS);\n\n    LDREndPntPair aOrgEndPts[BC7_MAX_REGIONS];\n    LDREndPntPair aOptEndPts[BC7_MAX_REGIONS];\n    size_t aOrgIdx[NUM_PIXELS_PER_BLOCK];\n    size_t aOrgIdx2[NUM_PIXELS_PER_BLOCK];\n    size_t aOptIdx[NUM_PIXELS_PER_BLOCK];\n    size_t aOptIdx2[NUM_PIXELS_PER_BLOCK];\n    float aOrgErr[BC7_MAX_REGIONS];\n    float aOptErr[BC7_MAX_REGIONS];\n\n    const LDREndPntPair* aEndPts = &pEP->aEndPts[uShape][0];\n\n    for (size_t p = 0; p <= uPartitions; p++)\n    {\n        aOrgEndPts[p].A = Quantize(aEndPts[p].A, ms_aInfo[pEP->uMode].RGBAPrecWithP);\n        aOrgEndPts[p].B = Quantize(aEndPts[p].B, ms_aInfo[pEP->uMode].RGBAPrecWithP);\n    }\n\n    LDREndPntPair newEndPts1[BC7_MAX_REGIONS];\n    FixEndpointPBits(pEP, aOrgEndPts, newEndPts1);\n\n    AssignIndices(pEP, uShape, uIndexMode, newEndPts1, aOrgIdx, aOrgIdx2, aOrgErr);\n\n    OptimizeEndPoints(pEP, uShape, uIndexMode, aOrgErr, newEndPts1, aOptEndPts);\n\n    LDREndPntPair newEndPts2[BC7_MAX_REGIONS];\n    FixEndpointPBits(pEP, aOptEndPts, newEndPts2);\n\n    AssignIndices(pEP, uShape, uIndexMode, newEndPts2, aOptIdx, aOptIdx2, aOptErr);\n\n    float fOrgTotErr = 0, fOptTotErr = 0;\n    for (size_t p = 0; p <= uPartitions; p++)\n    {\n        fOrgTotErr += aOrgErr[p];\n        fOptTotErr += aOptErr[p];\n    }\n    if (fOptTotErr < fOrgTotErr)\n    {\n        EmitBlock(pEP, uShape, uRotation, uIndexMode, newEndPts2, aOptIdx, aOptIdx2);\n        return fOptTotErr;\n    }\n    else\n    {\n        EmitBlock(pEP, uShape, uRotation, uIndexMode, newEndPts1, aOrgIdx, aOrgIdx2);\n        return fOrgTotErr;\n    }\n}\n\n_Use_decl_annotations_\nfloat D3DX_BC7::MapColors(const EncodeParams* pEP, const LDRColorA aColors[], size_t np, size_t uIndexMode, const LDREndPntPair& endPts, float fMinErr) const noexcept\n{\n    assert(pEP);\n    const uint8_t uIndexPrec = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec2 : ms_aInfo[pEP->uMode].uIndexPrec;\n    const uint8_t uIndexPrec2 = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec : ms_aInfo[pEP->uMode].uIndexPrec2;\n    LDRColorA aPalette[BC7_MAX_INDICES];\n    float fTotalErr = 0;\n\n    GeneratePaletteQuantized(pEP, uIndexMode, endPts, aPalette);\n    for (size_t i = 0; i < np; ++i)\n    {\n        fTotalErr += ComputeError(aColors[i], aPalette, uIndexPrec, uIndexPrec2);\n        if (fTotalErr > fMinErr)   // check for early exit\n        {\n            fTotalErr = FLT_MAX;\n            break;\n        }\n    }\n\n    return fTotalErr;\n}\n\n_Use_decl_annotations_\nfloat D3DX_BC7::RoughMSE(EncodeParams* pEP, size_t uShape, size_t uIndexMode) noexcept\n{\n    assert(pEP);\n    assert(uShape < BC7_MAX_SHAPES);\n    _Analysis_assume_(uShape < BC7_MAX_SHAPES);\n    LDREndPntPair* aEndPts = pEP->aEndPts[uShape];\n\n    const uint8_t uPartitions = ms_aInfo[pEP->uMode].uPartitions;\n    assert(uPartitions < BC7_MAX_REGIONS);\n    _Analysis_assume_(uPartitions < BC7_MAX_REGIONS);\n\n    const uint8_t uIndexPrec = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec2 : ms_aInfo[pEP->uMode].uIndexPrec;\n    const uint8_t uIndexPrec2 = uIndexMode ? ms_aInfo[pEP->uMode].uIndexPrec : ms_aInfo[pEP->uMode].uIndexPrec2;\n    auto const uNumIndices = static_cast<const uint8_t>(1u << uIndexPrec);\n    auto const uNumIndices2 = static_cast<const uint8_t>(1u << uIndexPrec2);\n    size_t auPixIdx[NUM_PIXELS_PER_BLOCK];\n    LDRColorA aPalette[BC7_MAX_REGIONS][BC7_MAX_INDICES];\n\n    for (size_t p = 0; p <= uPartitions; p++)\n    {\n        size_t np = 0;\n        for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++)\n        {\n            if (g_aPartitionTable[uPartitions][uShape][i] == p)\n            {\n                auPixIdx[np++] = i;\n            }\n        }\n\n        // handle simple cases\n        assert(np > 0);\n        if (np == 1)\n        {\n            aEndPts[p].A = pEP->aLDRPixels[auPixIdx[0]];\n            aEndPts[p].B = pEP->aLDRPixels[auPixIdx[0]];\n            continue;\n        }\n        else if (np == 2)\n        {\n            aEndPts[p].A = pEP->aLDRPixels[auPixIdx[0]];\n            aEndPts[p].B = pEP->aLDRPixels[auPixIdx[1]];\n            continue;\n        }\n\n        if (uIndexPrec2 == 0)\n        {\n            HDRColorA epA, epB;\n            OptimizeRGBA(pEP->aHDRPixels, &epA, &epB, 4, np, auPixIdx);\n            epA.Clamp(0.0f, 1.0f);\n            epB.Clamp(0.0f, 1.0f);\n            epA *= 255.0f;\n            epB *= 255.0f;\n            aEndPts[p].A = epA.ToLDRColorA();\n            aEndPts[p].B = epB.ToLDRColorA();\n        }\n        else\n        {\n            uint8_t uMinAlpha = 255, uMaxAlpha = 0;\n            for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)\n            {\n                uMinAlpha = std::min<uint8_t>(uMinAlpha, pEP->aLDRPixels[auPixIdx[i]].a);\n                uMaxAlpha = std::max<uint8_t>(uMaxAlpha, pEP->aLDRPixels[auPixIdx[i]].a);\n            }\n\n            HDRColorA epA, epB;\n            OptimizeRGB(pEP->aHDRPixels, &epA, &epB, 4, np, auPixIdx);\n            epA.Clamp(0.0f, 1.0f);\n            epB.Clamp(0.0f, 1.0f);\n            epA *= 255.0f;\n            epB *= 255.0f;\n            aEndPts[p].A = epA.ToLDRColorA();\n            aEndPts[p].B = epB.ToLDRColorA();\n            aEndPts[p].A.a = uMinAlpha;\n            aEndPts[p].B.a = uMaxAlpha;\n        }\n    }\n\n    if (uIndexPrec2 == 0)\n    {\n        for (size_t p = 0; p <= uPartitions; p++)\n            for (size_t i = 0; i < uNumIndices; i++)\n                LDRColorA::Interpolate(aEndPts[p].A, aEndPts[p].B, i, i, uIndexPrec, uIndexPrec, aPalette[p][i]);\n    }\n    else\n    {\n        for (size_t p = 0; p <= uPartitions; p++)\n        {\n            for (size_t i = 0; i < uNumIndices; i++)\n                LDRColorA::InterpolateRGB(aEndPts[p].A, aEndPts[p].B, i, uIndexPrec, aPalette[p][i]);\n            for (size_t i = 0; i < uNumIndices2; i++)\n                LDRColorA::InterpolateA(aEndPts[p].A, aEndPts[p].B, i, uIndexPrec2, aPalette[p][i]);\n        }\n    }\n\n    float fTotalErr = 0;\n    for (size_t i = 0; i < NUM_PIXELS_PER_BLOCK; i++)\n    {\n        const uint8_t uRegion = g_aPartitionTable[uPartitions][uShape][i];\n        fTotalErr += ComputeError(pEP->aLDRPixels[i], aPalette[uRegion], uIndexPrec, uIndexPrec2);\n    }\n\n    return fTotalErr;\n}\n\n\n//=====================================================================================\n// Entry points\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n// BC6H Compression\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nvoid DirectX::D3DXDecodeBC6HU(XMVECTOR *pColor, const uint8_t *pBC) noexcept\n{\n    assert(pColor && pBC);\n    static_assert(sizeof(D3DX_BC6H) == 16, \"D3DX_BC6H should be 16 bytes\");\n    reinterpret_cast<const D3DX_BC6H*>(pBC)->Decode(false, reinterpret_cast<HDRColorA*>(pColor));\n}\n\n_Use_decl_annotations_\nvoid DirectX::D3DXDecodeBC6HS(XMVECTOR *pColor, const uint8_t *pBC) noexcept\n{\n    assert(pColor && pBC);\n    static_assert(sizeof(D3DX_BC6H) == 16, \"D3DX_BC6H should be 16 bytes\");\n    reinterpret_cast<const D3DX_BC6H*>(pBC)->Decode(true, reinterpret_cast<HDRColorA*>(pColor));\n}\n\n_Use_decl_annotations_\nvoid DirectX::D3DXEncodeBC6HU(uint8_t *pBC, const XMVECTOR *pColor, uint32_t flags) noexcept\n{\n    UNREFERENCED_PARAMETER(flags);\n    assert(pBC && pColor);\n    static_assert(sizeof(D3DX_BC6H) == 16, \"D3DX_BC6H should be 16 bytes\");\n    reinterpret_cast<D3DX_BC6H*>(pBC)->Encode(false, reinterpret_cast<const HDRColorA*>(pColor));\n}\n\n_Use_decl_annotations_\nvoid DirectX::D3DXEncodeBC6HS(uint8_t *pBC, const XMVECTOR *pColor, uint32_t flags) noexcept\n{\n    UNREFERENCED_PARAMETER(flags);\n    assert(pBC && pColor);\n    static_assert(sizeof(D3DX_BC6H) == 16, \"D3DX_BC6H should be 16 bytes\");\n    reinterpret_cast<D3DX_BC6H*>(pBC)->Encode(true, reinterpret_cast<const HDRColorA*>(pColor));\n}\n\n\n//-------------------------------------------------------------------------------------\n// BC7 Compression\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nvoid DirectX::D3DXDecodeBC7(XMVECTOR *pColor, const uint8_t *pBC) noexcept\n{\n    assert(pColor && pBC);\n    static_assert(sizeof(D3DX_BC7) == 16, \"D3DX_BC7 should be 16 bytes\");\n    reinterpret_cast<const D3DX_BC7*>(pBC)->Decode(reinterpret_cast<HDRColorA*>(pColor));\n}\n\n_Use_decl_annotations_\nvoid DirectX::D3DXEncodeBC7(uint8_t *pBC, const XMVECTOR *pColor, uint32_t flags) noexcept\n{\n    assert(pBC && pColor);\n    static_assert(sizeof(D3DX_BC7) == 16, \"D3DX_BC7 should be 16 bytes\");\n    reinterpret_cast<D3DX_BC7*>(pBC)->Encode(flags, reinterpret_cast<const HDRColorA*>(pColor));\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/BCDirectCompute.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// BCDirectCompute.cpp\n//\n// Direct3D 11 Compute Shader BC Compressor\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\n#include \"BCDirectCompute.h\"\n\n#if defined(_DEBUG) || defined(PROFILE)\n#pragma comment(lib,\"dxguid.lib\")\n#endif\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n#include \"BC7Encode_EncodeBlockCS.inc\"\n#include \"BC7Encode_TryMode02CS.inc\"\n#include \"BC7Encode_TryMode137CS.inc\"\n#include \"BC7Encode_TryMode456CS.inc\"\n#include \"BC6HEncode_EncodeBlockCS.inc\"\n#include \"BC6HEncode_TryModeG10CS.inc\"\n#include \"BC6HEncode_TryModeLE10CS.inc\"\n\n    struct BufferBC6HBC7\n    {\n        UINT color[4];\n    };\n\n    struct ConstantsBC6HBC7\n    {\n        UINT    tex_width;\n        UINT    num_block_x;\n        UINT    format;\n        UINT    mode_id;\n        UINT    start_block_id;\n        UINT    num_total_blocks;\n        float   alpha_weight;\n        UINT    reserved;\n    };\n\n    static_assert(sizeof(ConstantsBC6HBC7) == sizeof(UINT) * 8, \"Constant buffer size mismatch\");\n\n    inline void RunComputeShader(ID3D11DeviceContext* pContext,\n        ID3D11ComputeShader* shader,\n        ID3D11ShaderResourceView** pSRVs,\n        UINT srvCount,\n        ID3D11Buffer* pCB,\n        ID3D11UnorderedAccessView* pUAV,\n        UINT X)\n    {\n        // Force UAV to nullptr before setting SRV since we are swapping buffers\n        ID3D11UnorderedAccessView* nullUAV = nullptr;\n        pContext->CSSetUnorderedAccessViews(0, 1, &nullUAV, nullptr);\n\n        pContext->CSSetShader(shader, nullptr, 0);\n        pContext->CSSetShaderResources(0, srvCount, pSRVs);\n        pContext->CSSetUnorderedAccessViews(0, 1, &pUAV, nullptr);\n        pContext->CSSetConstantBuffers(0, 1, &pCB);\n        pContext->Dispatch(X, 1, 1);\n    }\n\n    inline void ResetContext(ID3D11DeviceContext* pContext)\n    {\n        ID3D11UnorderedAccessView* nullUAV = nullptr;\n        pContext->CSSetUnorderedAccessViews(0, 1, &nullUAV, nullptr);\n\n        ID3D11ShaderResourceView* nullSRV[3] = { nullptr, nullptr, nullptr };\n        pContext->CSSetShaderResources(0, 3, nullSRV);\n\n        ID3D11Buffer* nullBuffer[1] = { nullptr };\n        pContext->CSSetConstantBuffers(0, 1, nullBuffer);\n    }\n};\n\nGPUCompressBC::GPUCompressBC() noexcept :\n    m_bcformat(DXGI_FORMAT_UNKNOWN),\n    m_srcformat(DXGI_FORMAT_UNKNOWN),\n    m_alphaWeight(1.f),\n    m_bc7_mode02(false),\n    m_bc7_mode137(false),\n    m_width(0),\n    m_height(0)\n{\n}\n\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT GPUCompressBC::Initialize(ID3D11Device* pDevice)\n{\n    if (!pDevice)\n        return E_INVALIDARG;\n\n    // Check for DirectCompute support\n    const D3D_FEATURE_LEVEL fl = pDevice->GetFeatureLevel();\n\n    if (fl < D3D_FEATURE_LEVEL_10_0)\n    {\n        // DirectCompute not supported on Feature Level 9.x hardware\n        return HRESULT_E_NOT_SUPPORTED;\n    }\n\n    if (fl < D3D_FEATURE_LEVEL_11_0)\n    {\n        // DirectCompute support on Feature Level 10.x hardware is optional, and this function needs it\n        D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS hwopts;\n        HRESULT hr = pDevice->CheckFeatureSupport(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &hwopts, sizeof(hwopts));\n        if (FAILED(hr))\n        {\n            memset(&hwopts, 0, sizeof(hwopts));\n        }\n\n        if (!hwopts.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x)\n        {\n            return HRESULT_E_NOT_SUPPORTED;\n        }\n    }\n\n    // Save a device reference and obtain immediate context\n    m_device = pDevice;\n\n    pDevice->GetImmediateContext(m_context.ReleaseAndGetAddressOf());\n    assert(m_context);\n\n    //--- Create compute shader library: BC6H -----------------------------------------\n\n    // Modes 11-14\n    HRESULT hr = pDevice->CreateComputeShader(BC6HEncode_TryModeG10CS, sizeof(BC6HEncode_TryModeG10CS), nullptr, m_BC6H_tryModeG10CS.ReleaseAndGetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    // Modes 1-10\n    hr = pDevice->CreateComputeShader(BC6HEncode_TryModeLE10CS, sizeof(BC6HEncode_TryModeLE10CS), nullptr, m_BC6H_tryModeLE10CS.ReleaseAndGetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    // Encode\n    hr = pDevice->CreateComputeShader(BC6HEncode_EncodeBlockCS, sizeof(BC6HEncode_EncodeBlockCS), nullptr, m_BC6H_encodeBlockCS.ReleaseAndGetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    //--- Create compute shader library: BC7 ------------------------------------------\n\n    // Modes 4, 5, 6\n    hr = pDevice->CreateComputeShader(BC7Encode_TryMode456CS, sizeof(BC7Encode_TryMode456CS), nullptr, m_BC7_tryMode456CS.ReleaseAndGetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    // Modes 1, 3, 7\n    hr = pDevice->CreateComputeShader(BC7Encode_TryMode137CS, sizeof(BC7Encode_TryMode137CS), nullptr, m_BC7_tryMode137CS.ReleaseAndGetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    // Modes 0, 2\n    hr = pDevice->CreateComputeShader(BC7Encode_TryMode02CS, sizeof(BC7Encode_TryMode02CS), nullptr, m_BC7_tryMode02CS.ReleaseAndGetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    // Encode\n    hr = pDevice->CreateComputeShader(BC7Encode_EncodeBlockCS, sizeof(BC7Encode_EncodeBlockCS), nullptr, m_BC7_encodeBlockCS.ReleaseAndGetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\nHRESULT GPUCompressBC::Prepare(size_t width, size_t height, uint32_t flags, DXGI_FORMAT format, float alphaWeight)\n{\n    if (!width || !height || alphaWeight < 0.f)\n        return E_INVALIDARG;\n\n    if ((width > UINT32_MAX) || (height > UINT32_MAX))\n        return E_INVALIDARG;\n\n    m_width = width;\n    m_height = height;\n\n    m_alphaWeight = alphaWeight;\n\n    if (flags & TEX_COMPRESS_BC7_QUICK)\n    {\n        m_bc7_mode02 = false;\n        m_bc7_mode137 = false;\n    }\n    else\n    {\n        m_bc7_mode02 = (flags & TEX_COMPRESS_BC7_USE_3SUBSETS) != 0;\n        m_bc7_mode137 = true;\n    }\n\n    const size_t xblocks = std::max<size_t>(1, (width + 3) >> 2);\n    const size_t yblocks = std::max<size_t>(1, (height + 3) >> 2);\n    const size_t num_blocks = xblocks * yblocks;\n\n    switch (format)\n    {\n        // BC6H GPU compressor takes RGBAF32 as input\n    case DXGI_FORMAT_BC6H_TYPELESS:\n    case DXGI_FORMAT_BC6H_UF16:\n    case DXGI_FORMAT_BC6H_SF16:\n        m_srcformat = DXGI_FORMAT_R32G32B32A32_FLOAT;\n        break;\n\n        // BC7 GPU compressor takes RGBA32 as input\n    case DXGI_FORMAT_BC7_TYPELESS:\n    case DXGI_FORMAT_BC7_UNORM:\n        m_srcformat = DXGI_FORMAT_R8G8B8A8_UNORM;\n        break;\n\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n        m_srcformat = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;\n        break;\n\n    default:\n        m_bcformat = m_srcformat = DXGI_FORMAT_UNKNOWN;\n        return HRESULT_E_NOT_SUPPORTED;\n    }\n\n    m_bcformat = format;\n\n    auto pDevice = m_device.Get();\n    if (!pDevice)\n        return E_POINTER;\n\n    // Create structured buffers\n    const uint64_t sizeInBytes = uint64_t(num_blocks) * sizeof(BufferBC6HBC7);\n    if (sizeInBytes >= UINT32_MAX)\n        return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n    auto const bufferSize = static_cast<size_t>(sizeInBytes);\n\n    {\n        D3D11_BUFFER_DESC desc = {};\n        desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;\n        desc.Usage = D3D11_USAGE_DEFAULT;\n        desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;\n        desc.StructureByteStride = sizeof(BufferBC6HBC7);\n        desc.ByteWidth = static_cast<UINT>(bufferSize);\n\n        HRESULT hr = pDevice->CreateBuffer(&desc, nullptr, m_output.ReleaseAndGetAddressOf());\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n\n        hr = pDevice->CreateBuffer(&desc, nullptr, m_err1.ReleaseAndGetAddressOf());\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n\n        hr = pDevice->CreateBuffer(&desc, nullptr, m_err2.ReleaseAndGetAddressOf());\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n    }\n\n    // Create staging output buffer\n    {\n        D3D11_BUFFER_DESC desc = {};\n        desc.Usage = D3D11_USAGE_STAGING;\n        desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;\n        desc.ByteWidth = static_cast<UINT>(bufferSize);\n\n        HRESULT hr = pDevice->CreateBuffer(&desc, nullptr, m_outputCPU.ReleaseAndGetAddressOf());\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n    }\n\n    // Create constant buffer\n    {\n        D3D11_BUFFER_DESC desc = {};\n        desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;\n        desc.Usage = D3D11_USAGE_DYNAMIC;\n        desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;\n        desc.ByteWidth = sizeof(ConstantsBC6HBC7);\n\n        HRESULT hr = pDevice->CreateBuffer(&desc, nullptr, m_constBuffer.ReleaseAndGetAddressOf());\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n    }\n\n    // Create shader resource views\n    {\n        D3D11_SHADER_RESOURCE_VIEW_DESC desc = {};\n        desc.Buffer.NumElements = static_cast<UINT>(num_blocks);\n        desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;\n\n        HRESULT hr = pDevice->CreateShaderResourceView(m_err1.Get(), &desc, m_err1SRV.ReleaseAndGetAddressOf());\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n\n        hr = pDevice->CreateShaderResourceView(m_err2.Get(), &desc, m_err2SRV.ReleaseAndGetAddressOf());\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n    }\n\n    // Create unordered access views\n    {\n        D3D11_UNORDERED_ACCESS_VIEW_DESC desc = {};\n        desc.Buffer.NumElements = static_cast<UINT>(num_blocks);\n        desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;\n\n        HRESULT hr = pDevice->CreateUnorderedAccessView(m_output.Get(), &desc, m_outputUAV.ReleaseAndGetAddressOf());\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n\n        hr = pDevice->CreateUnorderedAccessView(m_err1.Get(), &desc, m_err1UAV.ReleaseAndGetAddressOf());\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n\n        hr = pDevice->CreateUnorderedAccessView(m_err2.Get(), &desc, m_err2UAV.ReleaseAndGetAddressOf());\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\nHRESULT GPUCompressBC::Compress(const Image& srcImage, const Image& destImage)\n{\n    if (!srcImage.pixels || !destImage.pixels)\n        return E_INVALIDARG;\n\n    if (srcImage.width != destImage.width\n        || srcImage.height != destImage.height\n        || srcImage.width != m_width\n        || srcImage.height != m_height\n        || srcImage.format != m_srcformat\n        || destImage.format != m_bcformat)\n    {\n        return E_UNEXPECTED;\n    }\n\n    //--- Create input texture --------------------------------------------------------\n    auto pDevice = m_device.Get();\n    if (!pDevice)\n        return E_POINTER;\n\n    // We need to avoid the hardware doing additional colorspace conversion\n    const DXGI_FORMAT inputFormat = (m_srcformat == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) ? DXGI_FORMAT_R8G8B8A8_UNORM : m_srcformat;\n\n    ComPtr<ID3D11Texture2D> sourceTex;\n    {\n        D3D11_TEXTURE2D_DESC desc = {};\n        desc.Width = static_cast<UINT>(srcImage.width);\n        desc.Height = static_cast<UINT>(srcImage.height);\n        desc.MipLevels = 1;\n        desc.ArraySize = 1;\n        desc.Format = inputFormat;\n        desc.SampleDesc.Count = 1;\n        desc.Usage = D3D11_USAGE_DEFAULT;\n        desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;\n\n        D3D11_SUBRESOURCE_DATA initData;\n        initData.pSysMem = srcImage.pixels;\n        initData.SysMemPitch = static_cast<DWORD>(srcImage.rowPitch);\n        initData.SysMemSlicePitch = static_cast<DWORD>(srcImage.slicePitch);\n\n        HRESULT hr = pDevice->CreateTexture2D(&desc, &initData, sourceTex.GetAddressOf());\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n    }\n\n    ComPtr<ID3D11ShaderResourceView> sourceSRV;\n    {\n        D3D11_SHADER_RESOURCE_VIEW_DESC desc = {};\n        desc.Texture2D.MipLevels = 1;\n        desc.Format = inputFormat;\n        desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;\n\n        HRESULT hr = pDevice->CreateShaderResourceView(sourceTex.Get(), &desc, sourceSRV.GetAddressOf());\n        if (FAILED(hr))\n        {\n            return hr;\n        }\n    }\n\n    //--- Compress using DirectCompute ------------------------------------------------\n    bool isbc7 = false;\n    switch (m_bcformat)\n    {\n    case DXGI_FORMAT_BC6H_TYPELESS:\n    case DXGI_FORMAT_BC6H_UF16:\n    case DXGI_FORMAT_BC6H_SF16:\n        break;\n\n    case DXGI_FORMAT_BC7_TYPELESS:\n    case DXGI_FORMAT_BC7_UNORM:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n        isbc7 = true;\n        break;\n\n    default:\n        return E_UNEXPECTED;\n    }\n\n    constexpr UINT MAX_BLOCK_BATCH = 64u;\n\n    auto pContext = m_context.Get();\n    if (!pContext)\n        return E_UNEXPECTED;\n\n    const size_t xblocks = std::max<size_t>(1, (m_width + 3) >> 2);\n    const size_t yblocks = std::max<size_t>(1, (m_height + 3) >> 2);\n\n    auto const num_total_blocks = static_cast<UINT>(xblocks * yblocks);\n    UINT num_blocks = num_total_blocks;\n    UINT start_block_id = 0;\n    while (num_blocks > 0)\n    {\n        const UINT n = std::min<UINT>(num_blocks, MAX_BLOCK_BATCH);\n        const UINT uThreadGroupCount = n;\n\n        {\n            D3D11_MAPPED_SUBRESOURCE mapped;\n            HRESULT hr = pContext->Map(m_constBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);\n            if (FAILED(hr))\n                return hr;\n\n            ConstantsBC6HBC7 param;\n            param.tex_width = static_cast<UINT>(srcImage.width);\n            param.num_block_x = static_cast<UINT>(xblocks);\n            param.format = static_cast<UINT>(m_bcformat);\n            param.mode_id = 0;\n            param.start_block_id = start_block_id;\n            param.num_total_blocks = num_total_blocks;\n            param.alpha_weight = m_alphaWeight;\n            memcpy(mapped.pData, &param, sizeof(param));\n\n            pContext->Unmap(m_constBuffer.Get(), 0);\n        }\n\n        if (isbc7)\n        {\n            //--- BC7 -----------------------------------------------------------------\n            ID3D11ShaderResourceView* pSRVs[] = { sourceSRV.Get(), nullptr };\n            RunComputeShader(pContext, m_BC7_tryMode456CS.Get(), pSRVs, 2, m_constBuffer.Get(),\n                m_err1UAV.Get(), std::max<UINT>((uThreadGroupCount + 3) / 4, 1));\n\n            if (m_bc7_mode137)\n            {\n                for (UINT i = 0; i < 3; ++i)\n                {\n                    static const UINT modes[] = { 1, 3, 7 };\n\n                    // Mode 1: err1 -> err2\n                    // Mode 3: err2 -> err1\n                    // Mode 7: err1 -> err2\n                    {\n                        D3D11_MAPPED_SUBRESOURCE mapped;\n                        HRESULT hr = pContext->Map(m_constBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);\n                        if (FAILED(hr))\n                        {\n                            ResetContext(pContext);\n                            return hr;\n                        }\n\n                        ConstantsBC6HBC7 param;\n                        param.tex_width = static_cast<UINT>(srcImage.width);\n                        param.num_block_x = static_cast<UINT>(xblocks);\n                        param.format = static_cast<UINT>(m_bcformat);\n                        param.mode_id = modes[i];\n                        param.start_block_id = start_block_id;\n                        param.num_total_blocks = num_total_blocks;\n                        param.alpha_weight = m_alphaWeight;\n                        memcpy(mapped.pData, &param, sizeof(param));\n                        pContext->Unmap(m_constBuffer.Get(), 0);\n                    }\n\n                    pSRVs[1] = (i & 1) ? m_err2SRV.Get() : m_err1SRV.Get();\n                    RunComputeShader(pContext, m_BC7_tryMode137CS.Get(), pSRVs, 2, m_constBuffer.Get(),\n                        (i & 1) ? m_err1UAV.Get() : m_err2UAV.Get(), uThreadGroupCount);\n                }\n            }\n\n            if (m_bc7_mode02)\n            {\n                // 3 subset modes tend to be used rarely and add significant compression time\n                for (UINT i = 0; i < 2; ++i)\n                {\n                    static const UINT modes[] = { 0, 2 };\n                    // Mode 0: err2 -> err1\n                    // Mode 2: err1 -> err2\n                    {\n                        D3D11_MAPPED_SUBRESOURCE mapped;\n                        HRESULT hr = pContext->Map(m_constBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);\n                        if (FAILED(hr))\n                        {\n                            ResetContext(pContext);\n                            return hr;\n                        }\n\n                        ConstantsBC6HBC7 param;\n                        param.tex_width = static_cast<UINT>(srcImage.width);\n                        param.num_block_x = static_cast<UINT>(xblocks);\n                        param.format = static_cast<UINT>(m_bcformat);\n                        param.mode_id = modes[i];\n                        param.start_block_id = start_block_id;\n                        param.num_total_blocks = num_total_blocks;\n                        param.alpha_weight = m_alphaWeight;\n                        memcpy(mapped.pData, &param, sizeof(param));\n                        pContext->Unmap(m_constBuffer.Get(), 0);\n                    }\n\n                    pSRVs[1] = (i & 1) ? m_err1SRV.Get() : m_err2SRV.Get();\n                    RunComputeShader(pContext, m_BC7_tryMode02CS.Get(), pSRVs, 2, m_constBuffer.Get(),\n                        (i & 1) ? m_err2UAV.Get() : m_err1UAV.Get(), uThreadGroupCount);\n                }\n            }\n\n            pSRVs[1] = (m_bc7_mode02 || m_bc7_mode137) ? m_err2SRV.Get() : m_err1SRV.Get();\n            RunComputeShader(pContext, m_BC7_encodeBlockCS.Get(), pSRVs, 2, m_constBuffer.Get(),\n                m_outputUAV.Get(), std::max<UINT>((uThreadGroupCount + 3) / 4, 1));\n        }\n        else\n        {\n            //--- BC6H ----------------------------------------------------------------\n            ID3D11ShaderResourceView* pSRVs[] = { sourceSRV.Get(), nullptr };\n            RunComputeShader(pContext, m_BC6H_tryModeG10CS.Get(), pSRVs, 2, m_constBuffer.Get(),\n                m_err1UAV.Get(), std::max<UINT>((uThreadGroupCount + 3) / 4, 1));\n\n            for (UINT i = 0; i < 10; ++i)\n            {\n                {\n                    D3D11_MAPPED_SUBRESOURCE mapped;\n                    HRESULT hr = pContext->Map(m_constBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);\n                    if (FAILED(hr))\n                    {\n                        ResetContext(pContext);\n                        return hr;\n                    }\n\n                    ConstantsBC6HBC7 param;\n                    param.tex_width = static_cast<UINT>(srcImage.width);\n                    param.num_block_x = static_cast<UINT>(xblocks);\n                    param.format = static_cast<UINT>(m_bcformat);\n                    param.mode_id = i;\n                    param.start_block_id = start_block_id;\n                    param.num_total_blocks = num_total_blocks;\n                    memcpy(mapped.pData, &param, sizeof(param));\n                    pContext->Unmap(m_constBuffer.Get(), 0);\n                }\n\n                pSRVs[1] = (i & 1) ? m_err2SRV.Get() : m_err1SRV.Get();\n                RunComputeShader(pContext, m_BC6H_tryModeLE10CS.Get(), pSRVs, 2, m_constBuffer.Get(),\n                    (i & 1) ? m_err1UAV.Get() : m_err2UAV.Get(), std::max<UINT>((uThreadGroupCount + 1) / 2, 1));\n            }\n\n            pSRVs[1] = m_err1SRV.Get();\n            RunComputeShader(pContext, m_BC6H_encodeBlockCS.Get(), pSRVs, 2, m_constBuffer.Get(),\n                m_outputUAV.Get(), std::max<UINT>((uThreadGroupCount + 1) / 2, 1));\n        }\n\n        start_block_id += n;\n        num_blocks -= n;\n    }\n\n    ResetContext(pContext);\n\n    //--- Copy output texture back to CPU ---------------------------------------------\n\n    pContext->CopyResource(m_outputCPU.Get(), m_output.Get());\n\n    D3D11_MAPPED_SUBRESOURCE mapped;\n    HRESULT hr = pContext->Map(m_outputCPU.Get(), 0, D3D11_MAP_READ, 0, &mapped);\n    if (SUCCEEDED(hr))\n    {\n        auto pSrc = static_cast<const uint8_t *>(mapped.pData);\n        uint8_t *pDest = destImage.pixels;\n\n        const size_t pitch = xblocks * sizeof(BufferBC6HBC7);\n\n        const size_t rows = std::max<size_t>(1, (destImage.height + 3) >> 2);\n\n        for (size_t h = 0; h < rows; ++h)\n        {\n            memcpy(pDest, pSrc, destImage.rowPitch);\n\n            pSrc += pitch;\n            pDest += destImage.rowPitch;\n        }\n\n        pContext->Unmap(m_outputCPU.Get(), 0);\n    }\n\n    return hr;\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/BCDirectCompute.h",
    "content": "//-------------------------------------------------------------------------------------\n// BCDirectCompute.h\n//\n// Direct3D 11 Compute Shader BC Compressor\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\nnamespace DirectX\n{\n\n    class GPUCompressBC\n    {\n    public:\n        GPUCompressBC() noexcept;\n\n        HRESULT Initialize(_In_ ID3D11Device* pDevice);\n\n        HRESULT Prepare(size_t width, size_t height, uint32_t flags, DXGI_FORMAT format, float alphaWeight);\n\n        HRESULT Compress(const Image& srcImage, const Image& destImage);\n\n        DXGI_FORMAT GetSourceFormat() const noexcept { return m_srcformat; }\n\n    private:\n        DXGI_FORMAT                                         m_bcformat;\n        DXGI_FORMAT                                         m_srcformat;\n        float                                               m_alphaWeight;\n        bool                                                m_bc7_mode02;\n        bool                                                m_bc7_mode137;\n        size_t                                              m_width;\n        size_t                                              m_height;\n\n        Microsoft::WRL::ComPtr<ID3D11Device>                m_device;\n        Microsoft::WRL::ComPtr<ID3D11DeviceContext>         m_context;\n\n        Microsoft::WRL::ComPtr<ID3D11Buffer>                m_err1;\n        Microsoft::WRL::ComPtr<ID3D11UnorderedAccessView>   m_err1UAV;\n        Microsoft::WRL::ComPtr<ID3D11ShaderResourceView>    m_err1SRV;\n\n        Microsoft::WRL::ComPtr<ID3D11Buffer>                m_err2;\n        Microsoft::WRL::ComPtr<ID3D11UnorderedAccessView>   m_err2UAV;\n        Microsoft::WRL::ComPtr<ID3D11ShaderResourceView>    m_err2SRV;\n\n        Microsoft::WRL::ComPtr<ID3D11Buffer>                m_output;\n        Microsoft::WRL::ComPtr<ID3D11Buffer>                m_outputCPU;\n        Microsoft::WRL::ComPtr<ID3D11UnorderedAccessView>   m_outputUAV;\n        Microsoft::WRL::ComPtr<ID3D11Buffer>                m_constBuffer;\n\n        // Compute shader library\n        Microsoft::WRL::ComPtr<ID3D11ComputeShader>         m_BC6H_tryModeG10CS;\n        Microsoft::WRL::ComPtr<ID3D11ComputeShader>         m_BC6H_tryModeLE10CS;\n        Microsoft::WRL::ComPtr<ID3D11ComputeShader>         m_BC6H_encodeBlockCS;\n\n        Microsoft::WRL::ComPtr<ID3D11ComputeShader>         m_BC7_tryMode456CS;\n        Microsoft::WRL::ComPtr<ID3D11ComputeShader>         m_BC7_tryMode137CS;\n        Microsoft::WRL::ComPtr<ID3D11ComputeShader>         m_BC7_tryMode02CS;\n        Microsoft::WRL::ComPtr<ID3D11ComputeShader>         m_BC7_encodeBlockCS;\n    };\n\n} // namespace\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DDS.h",
    "content": "//--------------------------------------------------------------------------------------\n// DDS.h\n//\n// This header defines constants and structures that are useful when parsing\n// DDS files.  DDS files were originally designed to use several structures\n// and constants that are native to DirectDraw and are defined in ddraw.h,\n// such as DDSURFACEDESC2 and DDSCAPS2.  This file defines similar\n// (compatible) constants and structures so that one can use DDS files\n// without needing to include ddraw.h.\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <cstdint>\n\nnamespace DirectX\n{\n\n#pragma pack(push,1)\n\n    constexpr uint32_t DDS_MAGIC = 0x20534444; // \"DDS \"\n\n    struct DDS_PIXELFORMAT\n    {\n        uint32_t    size;\n        uint32_t    flags;\n        uint32_t    fourCC;\n        uint32_t    RGBBitCount;\n        uint32_t    RBitMask;\n        uint32_t    GBitMask;\n        uint32_t    BBitMask;\n        uint32_t    ABitMask;\n    };\n\n#define DDS_FOURCC      0x00000004  // DDPF_FOURCC\n#define DDS_RGB         0x00000040  // DDPF_RGB\n#define DDS_RGBA        0x00000041  // DDPF_RGB | DDPF_ALPHAPIXELS\n#define DDS_LUMINANCE   0x00020000  // DDPF_LUMINANCE\n#define DDS_LUMINANCEA  0x00020001  // DDPF_LUMINANCE | DDPF_ALPHAPIXELS\n#define DDS_ALPHAPIXELS 0x00000001  // DDPF_ALPHAPIXELS\n#define DDS_ALPHA       0x00000002  // DDPF_ALPHA\n#define DDS_PAL8        0x00000020  // DDPF_PALETTEINDEXED8\n#define DDS_PAL8A       0x00000021  // DDPF_PALETTEINDEXED8 | DDPF_ALPHAPIXELS\n#define DDS_BUMPDUDV    0x00080000  // DDPF_BUMPDUDV\n// DDS_BUMPLUMINANCE 0x00040000\n\n#ifndef MAKEFOURCC\n#define MAKEFOURCC(ch0, ch1, ch2, ch3) \\\n                (static_cast<uint32_t>(static_cast<uint8_t>(ch0)) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch1)) << 8) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch2)) << 16) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch3)) << 24))\n#endif /* MAKEFOURCC */\n\n#ifndef DDSGLOBALCONST\n#if defined(__GNUC__) && !defined(__MINGW32__)\n#define DDSGLOBALCONST extern const __attribute__((weak))\n#else\n#define DDSGLOBALCONST extern const __declspec(selectany)\n#endif\n#endif /* DDSGLOBALCONST */\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT1 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','2'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT3 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_BC4_UNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','U'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_BC4_SNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_BC5_UNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','U'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_BC5_SNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','S'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_R8G8_B8G8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('R','G','B','G'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_G8R8_G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_YUY2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_UYVY =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('U','Y','V','Y'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8R8G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_X8R8G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB,  0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8B8G8R8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_X8B8G8R8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB,  0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_G16R16 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB,  0, 32, 0x0000ffff, 0xffff0000, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_R5G6B5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0xf800, 0x07e0, 0x001f, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A1R5G5B5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x8000 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_X1R5G5B5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x7c00, 0x03e0, 0x001f, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A4R4G4B4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x0f00, 0x00f0, 0x000f, 0xf000 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_X4R4G4B4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0f00, 0x00f0, 0x000f, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_R8G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8R3G3B2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_R3G3B2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A4L4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 8, 0x0f, 0, 0, 0xf0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_L8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 8, 0xff, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_L16 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 16, 0xffff, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8L8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 16, 0x00ff, 0, 0, 0xff00 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8L8_ALT =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 8, 0x00ff, 0, 0, 0xff00 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_L8_NVTT1 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 8, 0xff, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_L16_NVTT1 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0xffff, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8L8_NVTT1 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00ff, 0, 0, 0xff00 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_ALPHA, 0, 8, 0, 0, 0, 0xff };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_V8U8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_Q8W8V8U8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_V16U16 =\n    { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0, 0 };\n\n// D3DFMT_A2R10G10B10/D3DFMT_A2B10G10R10 should be written using DX10 extension to avoid D3DX 10:10:10:2 reversal issue\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A2R10G10B10 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 };\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A2B10G10R10 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 };\n\n// We do not support the following legacy Direct3D 9 formats:\n// DDSPF_A2W10V10U10 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 };\n// DDSPF_L6V5U5 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPLUMINANCE, 0, 16, 0x001f, 0x03e0, 0xfc00, 0 };\n// DDSPF_X8L8V8U8 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPLUMINANCE, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0 };\n\n// This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat)\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DX10 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 };\n\n#define DDS_HEADER_FLAGS_TEXTURE        0x00001007  // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT\n#define DDS_HEADER_FLAGS_MIPMAP         0x00020000  // DDSD_MIPMAPCOUNT\n#define DDS_HEADER_FLAGS_VOLUME         0x00800000  // DDSD_DEPTH\n#define DDS_HEADER_FLAGS_PITCH          0x00000008  // DDSD_PITCH\n#define DDS_HEADER_FLAGS_LINEARSIZE     0x00080000  // DDSD_LINEARSIZE\n\n#define DDS_HEIGHT 0x00000002 // DDSD_HEIGHT\n#define DDS_WIDTH  0x00000004 // DDSD_WIDTH\n\n#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE\n#define DDS_SURFACE_FLAGS_MIPMAP  0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP\n#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX\n\n#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX\n#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX\n#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY\n#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY\n#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ\n#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ\n\n#define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\\\n                               DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\\\n                               DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ )\n\n#define DDS_CUBEMAP 0x00000200 // DDSCAPS2_CUBEMAP\n\n#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME\n\n// Subset here matches D3D10_RESOURCE_DIMENSION and D3D11_RESOURCE_DIMENSION\n    enum DDS_RESOURCE_DIMENSION : uint32_t\n    {\n        DDS_DIMENSION_TEXTURE1D = 2,\n        DDS_DIMENSION_TEXTURE2D = 3,\n        DDS_DIMENSION_TEXTURE3D = 4,\n    };\n\n    // Subset here matches D3D10_RESOURCE_MISC_FLAG and D3D11_RESOURCE_MISC_FLAG\n    enum DDS_RESOURCE_MISC_FLAG : uint32_t\n    {\n        DDS_RESOURCE_MISC_TEXTURECUBE = 0x4L,\n    };\n\n    enum DDS_MISC_FLAGS2 : uint32_t\n    {\n        DDS_MISC_FLAGS2_ALPHA_MODE_MASK = 0x7L,\n    };\n\n#ifndef DDS_ALPHA_MODE_DEFINED\n#define DDS_ALPHA_MODE_DEFINED\n    enum DDS_ALPHA_MODE : uint32_t\n    {\n        DDS_ALPHA_MODE_UNKNOWN = 0,\n        DDS_ALPHA_MODE_STRAIGHT = 1,\n        DDS_ALPHA_MODE_PREMULTIPLIED = 2,\n        DDS_ALPHA_MODE_OPAQUE = 3,\n        DDS_ALPHA_MODE_CUSTOM = 4,\n    };\n#endif\n\n    struct DDS_HEADER\n    {\n        uint32_t        size;\n        uint32_t        flags;\n        uint32_t        height;\n        uint32_t        width;\n        uint32_t        pitchOrLinearSize;\n        uint32_t        depth; // only if DDS_HEADER_FLAGS_VOLUME is set in flags\n        uint32_t        mipMapCount;\n        uint32_t        reserved1[11];\n        DDS_PIXELFORMAT ddspf;\n        uint32_t        caps;\n        uint32_t        caps2;\n        uint32_t        caps3;\n        uint32_t        caps4;\n        uint32_t        reserved2;\n    };\n\n    struct DDS_HEADER_DXT10\n    {\n        DXGI_FORMAT     dxgiFormat;\n        uint32_t        resourceDimension;\n        uint32_t        miscFlag; // see D3D11_RESOURCE_MISC_FLAG\n        uint32_t        arraySize;\n        uint32_t        miscFlags2; // see DDS_MISC_FLAGS2\n    };\n\n#pragma pack(pop)\n\n    static_assert(sizeof(DDS_HEADER) == 124, \"DDS Header size mismatch\");\n    static_assert(sizeof(DDS_HEADER_DXT10) == 20, \"DDS DX10 Extended Header size mismatch\");\n\n} // namespace\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTex.h",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTex.h\n//\n// DirectX Texture Library\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <App/ZetaRay.h>\n#include <functional>\n\n#include <DirectXMath.h>\n\n#ifdef _WIN32\n#if defined(NTDDI_WIN10_FE) || defined(__MINGW32__)\n#include <ocidl.h>\n#else\n#include <OCIdl.h>\n#endif\n\nstruct IWICImagingFactory;\nstruct IWICMetadataQueryReader;\n#endif\n\n#define DIRECTX_TEX_VERSION 196\n\n#include <d3d11.h>\n#include <dxgi.h>\n#include <dxgiformat.h>\n\nnamespace DirectX\n{\n\n    //---------------------------------------------------------------------------------\n    // DXGI Format Utilities\n    constexpr bool __cdecl IsValid(_In_ DXGI_FORMAT fmt) noexcept;\n    bool __cdecl IsCompressed(_In_ DXGI_FORMAT fmt) noexcept;\n    bool __cdecl IsPacked(_In_ DXGI_FORMAT fmt) noexcept;\n    bool __cdecl IsVideo(_In_ DXGI_FORMAT fmt) noexcept;\n    bool __cdecl IsPlanar(_In_ DXGI_FORMAT fmt) noexcept;\n    bool __cdecl IsPalettized(_In_ DXGI_FORMAT fmt) noexcept;\n    bool __cdecl IsDepthStencil(_In_ DXGI_FORMAT fmt) noexcept;\n    bool __cdecl IsSRGB(_In_ DXGI_FORMAT fmt) noexcept;\n    bool __cdecl IsBGR(_In_ DXGI_FORMAT fmt) noexcept;\n    bool __cdecl IsTypeless(_In_ DXGI_FORMAT fmt, _In_ bool partialTypeless = true) noexcept;\n\n    bool __cdecl HasAlpha(_In_ DXGI_FORMAT fmt) noexcept;\n\n    size_t __cdecl BitsPerPixel(_In_ DXGI_FORMAT fmt) noexcept;\n\n    size_t __cdecl BitsPerColor(_In_ DXGI_FORMAT fmt) noexcept;\n\n    enum FORMAT_TYPE\n    {\n        FORMAT_TYPE_TYPELESS,\n        FORMAT_TYPE_FLOAT,\n        FORMAT_TYPE_UNORM,\n        FORMAT_TYPE_SNORM,\n        FORMAT_TYPE_UINT,\n        FORMAT_TYPE_SINT,\n    };\n\n    FORMAT_TYPE __cdecl FormatDataType(_In_ DXGI_FORMAT fmt) noexcept;\n\n    enum CP_FLAGS : unsigned long\n    {\n        CP_FLAGS_NONE = 0x0,\n        // Normal operation\n\n        CP_FLAGS_LEGACY_DWORD = 0x1,\n        // Assume pitch is DWORD aligned instead of BYTE aligned\n\n        CP_FLAGS_PARAGRAPH = 0x2,\n        // Assume pitch is 16-byte aligned instead of BYTE aligned\n\n        CP_FLAGS_YMM = 0x4,\n        // Assume pitch is 32-byte aligned instead of BYTE aligned\n\n        CP_FLAGS_ZMM = 0x8,\n        // Assume pitch is 64-byte aligned instead of BYTE aligned\n\n        CP_FLAGS_PAGE4K = 0x200,\n        // Assume pitch is 4096-byte aligned instead of BYTE aligned\n\n        CP_FLAGS_BAD_DXTN_TAILS = 0x1000,\n        // BC formats with malformed mipchain blocks smaller than 4x4\n\n        CP_FLAGS_24BPP = 0x10000,\n        // Override with a legacy 24 bits-per-pixel format size\n\n        CP_FLAGS_16BPP = 0x20000,\n        // Override with a legacy 16 bits-per-pixel format size\n\n        CP_FLAGS_8BPP = 0x40000,\n        // Override with a legacy 8 bits-per-pixel format size\n    };\n\n    HRESULT __cdecl ComputePitch(\n        _In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height,\n        _Out_ size_t& rowPitch, _Out_ size_t& slicePitch, _In_ CP_FLAGS flags = CP_FLAGS_NONE) noexcept;\n\n    size_t __cdecl ComputeScanlines(_In_ DXGI_FORMAT fmt, _In_ size_t height) noexcept;\n\n    DXGI_FORMAT __cdecl MakeSRGB(_In_ DXGI_FORMAT fmt) noexcept;\n    DXGI_FORMAT __cdecl MakeTypeless(_In_ DXGI_FORMAT fmt) noexcept;\n    DXGI_FORMAT __cdecl MakeTypelessUNORM(_In_ DXGI_FORMAT fmt) noexcept;\n    DXGI_FORMAT __cdecl MakeTypelessFLOAT(_In_ DXGI_FORMAT fmt) noexcept;\n\n    //---------------------------------------------------------------------------------\n    // Texture metadata\n    enum TEX_DIMENSION\n        // Subset here matches D3D10_RESOURCE_DIMENSION and D3D11_RESOURCE_DIMENSION\n    {\n        TEX_DIMENSION_TEXTURE1D = 2,\n        TEX_DIMENSION_TEXTURE2D = 3,\n        TEX_DIMENSION_TEXTURE3D = 4,\n    };\n\n    enum TEX_MISC_FLAG : unsigned long\n        // Subset here matches D3D10_RESOURCE_MISC_FLAG and D3D11_RESOURCE_MISC_FLAG\n    {\n        TEX_MISC_TEXTURECUBE = 0x4L,\n    };\n\n    enum TEX_MISC_FLAG2 : unsigned long\n    {\n        TEX_MISC2_ALPHA_MODE_MASK = 0x7L,\n    };\n\n    enum TEX_ALPHA_MODE\n        // Matches DDS_ALPHA_MODE, encoded in MISC_FLAGS2\n    {\n        TEX_ALPHA_MODE_UNKNOWN = 0,\n        TEX_ALPHA_MODE_STRAIGHT = 1,\n        TEX_ALPHA_MODE_PREMULTIPLIED = 2,\n        TEX_ALPHA_MODE_OPAQUE = 3,\n        TEX_ALPHA_MODE_CUSTOM = 4,\n    };\n\n    struct TexMetadata\n    {\n        size_t          width;\n        size_t          height;     // Should be 1 for 1D textures\n        size_t          depth;      // Should be 1 for 1D or 2D textures\n        size_t          arraySize;  // For cubemap, this is a multiple of 6\n        size_t          mipLevels;\n        uint32_t        miscFlags;\n        uint32_t        miscFlags2;\n        DXGI_FORMAT     format;\n        TEX_DIMENSION   dimension;\n\n        size_t __cdecl ComputeIndex(_In_ size_t mip, _In_ size_t item, _In_ size_t slice) const noexcept;\n            // Returns size_t(-1) to indicate an out-of-range error\n\n        bool __cdecl IsCubemap() const noexcept { return (miscFlags & TEX_MISC_TEXTURECUBE) != 0; }\n            // Helper for miscFlags\n\n        bool __cdecl IsPMAlpha() const noexcept { return ((miscFlags2 & TEX_MISC2_ALPHA_MODE_MASK) == TEX_ALPHA_MODE_PREMULTIPLIED) != 0; }\n        void __cdecl SetAlphaMode(TEX_ALPHA_MODE mode) noexcept { miscFlags2 = (miscFlags2 & ~static_cast<uint32_t>(TEX_MISC2_ALPHA_MODE_MASK)) | static_cast<uint32_t>(mode); }\n        TEX_ALPHA_MODE __cdecl GetAlphaMode() const noexcept { return static_cast<TEX_ALPHA_MODE>(miscFlags2 & TEX_MISC2_ALPHA_MODE_MASK); }\n            // Helpers for miscFlags2\n\n        bool __cdecl IsVolumemap() const noexcept { return (dimension == TEX_DIMENSION_TEXTURE3D); }\n            // Helper for dimension\n    };\n\n    enum DDS_FLAGS : unsigned long\n    {\n        DDS_FLAGS_NONE = 0x0,\n\n        DDS_FLAGS_LEGACY_DWORD = 0x1,\n        // Assume pitch is DWORD aligned instead of BYTE aligned (used by some legacy DDS files)\n\n        DDS_FLAGS_NO_LEGACY_EXPANSION = 0x2,\n        // Do not implicitly convert legacy formats that result in larger pixel sizes (24 bpp, 3:3:2, A8L8, A4L4, P8, A8P8)\n\n        DDS_FLAGS_NO_R10B10G10A2_FIXUP = 0x4,\n        // Do not use work-around for long-standing D3DX DDS file format issue which reversed the 10:10:10:2 color order masks\n\n        DDS_FLAGS_FORCE_RGB = 0x8,\n        // Convert DXGI 1.1 BGR formats to DXGI_FORMAT_R8G8B8A8_UNORM to avoid use of optional WDDM 1.1 formats\n\n        DDS_FLAGS_NO_16BPP = 0x10,\n        // Conversions avoid use of 565, 5551, and 4444 formats and instead expand to 8888 to avoid use of optional WDDM 1.2 formats\n\n        DDS_FLAGS_EXPAND_LUMINANCE = 0x20,\n        // When loading legacy luminance formats expand replicating the color channels rather than leaving them packed (L8, L16, A8L8)\n\n        DDS_FLAGS_BAD_DXTN_TAILS = 0x40,\n        // Some older DXTn DDS files incorrectly handle mipchain tails for blocks smaller than 4x4\n\n        DDS_FLAGS_FORCE_DX10_EXT = 0x10000,\n        // Always use the 'DX10' header extension for DDS writer (i.e. don't try to write DX9 compatible DDS files)\n\n        DDS_FLAGS_FORCE_DX10_EXT_MISC2 = 0x20000,\n        // DDS_FLAGS_FORCE_DX10_EXT including miscFlags2 information (result may not be compatible with D3DX10 or D3DX11)\n\n        DDS_FLAGS_FORCE_DX9_LEGACY = 0x40000,\n        // Force use of legacy header for DDS writer (will fail if unable to write as such)\n\n        DDS_FLAGS_ALLOW_LARGE_FILES = 0x1000000,\n        // Enables the loader to read large dimension .dds files (i.e. greater than known hardware requirements)\n    };\n\n    enum TGA_FLAGS : unsigned long\n    {\n        TGA_FLAGS_NONE = 0x0,\n\n        TGA_FLAGS_BGR = 0x1,\n        // 24bpp files are returned as BGRX; 32bpp files are returned as BGRA\n\n        TGA_FLAGS_ALLOW_ALL_ZERO_ALPHA = 0x2,\n        // If the loaded image has an all zero alpha channel, normally we assume it should be opaque. This flag leaves it alone.\n\n        TGA_FLAGS_IGNORE_SRGB = 0x10,\n        // Ignores sRGB TGA 2.0 metadata if present in the file\n\n        TGA_FLAGS_FORCE_SRGB = 0x20,\n        // Writes sRGB metadata into the file reguardless of format (TGA 2.0 only)\n\n        TGA_FLAGS_FORCE_LINEAR = 0x40,\n        // Writes linear gamma metadata into the file reguardless of format (TGA 2.0 only)\n\n        TGA_FLAGS_DEFAULT_SRGB = 0x80,\n        // If no colorspace is specified in TGA 2.0 metadata, assume sRGB\n    };\n\n    enum WIC_FLAGS : unsigned long\n    {\n        WIC_FLAGS_NONE = 0x0,\n\n        WIC_FLAGS_FORCE_RGB = 0x1,\n        // Loads DXGI 1.1 BGR formats as DXGI_FORMAT_R8G8B8A8_UNORM to avoid use of optional WDDM 1.1 formats\n\n        WIC_FLAGS_NO_X2_BIAS = 0x2,\n        // Loads DXGI 1.1 X2 10:10:10:2 format as DXGI_FORMAT_R10G10B10A2_UNORM\n\n        WIC_FLAGS_NO_16BPP = 0x4,\n        // Loads 565, 5551, and 4444 formats as 8888 to avoid use of optional WDDM 1.2 formats\n\n        WIC_FLAGS_ALLOW_MONO = 0x8,\n        // Loads 1-bit monochrome (black & white) as R1_UNORM rather than 8-bit grayscale\n\n        WIC_FLAGS_ALL_FRAMES = 0x10,\n        // Loads all images in a multi-frame file, converting/resizing to match the first frame as needed, defaults to 0th frame otherwise\n\n        WIC_FLAGS_IGNORE_SRGB = 0x20,\n        // Ignores sRGB metadata if present in the file\n\n        WIC_FLAGS_FORCE_SRGB = 0x40,\n        // Writes sRGB metadata into the file reguardless of format\n\n        WIC_FLAGS_FORCE_LINEAR = 0x80,\n        // Writes linear gamma metadata into the file reguardless of format\n\n        WIC_FLAGS_DEFAULT_SRGB = 0x100,\n        // If no colorspace is specified, assume sRGB\n\n        WIC_FLAGS_DITHER = 0x10000,\n        // Use ordered 4x4 dithering for any required conversions\n\n        WIC_FLAGS_DITHER_DIFFUSION = 0x20000,\n        // Use error-diffusion dithering for any required conversions\n\n        WIC_FLAGS_FILTER_POINT = 0x100000,\n        WIC_FLAGS_FILTER_LINEAR = 0x200000,\n        WIC_FLAGS_FILTER_CUBIC = 0x300000,\n        WIC_FLAGS_FILTER_FANT = 0x400000, // Combination of Linear and Box filter\n            // Filtering mode to use for any required image resizing (only needed when loading arrays of differently sized images; defaults to Fant)\n    };\n\n    HRESULT __cdecl GetMetadataFromDDSMemory(\n        _In_reads_bytes_(size) const void* pSource, _In_ size_t size,\n        _In_ DDS_FLAGS flags,\n        _Out_ TexMetadata& metadata) noexcept;\n    HRESULT __cdecl GetMetadataFromDDSFile(\n        _In_z_ const wchar_t* szFile,\n        _In_ DDS_FLAGS flags,\n        _Out_ TexMetadata& metadata) noexcept;\n\n    HRESULT __cdecl GetMetadataFromHDRMemory(\n        _In_reads_bytes_(size) const void* pSource, _In_ size_t size,\n        _Out_ TexMetadata& metadata) noexcept;\n    HRESULT __cdecl GetMetadataFromHDRFile(\n        _In_z_ const wchar_t* szFile,\n        _Out_ TexMetadata& metadata) noexcept;\n\n    HRESULT __cdecl GetMetadataFromTGAMemory(\n        _In_reads_bytes_(size) const void* pSource, _In_ size_t size,\n        _In_ TGA_FLAGS flags,\n        _Out_ TexMetadata& metadata) noexcept;\n    HRESULT __cdecl GetMetadataFromTGAFile(\n        _In_z_ const wchar_t* szFile,\n        _In_ TGA_FLAGS flags,\n        _Out_ TexMetadata& metadata) noexcept;\n\n#ifdef _WIN32\n    HRESULT __cdecl GetMetadataFromWICMemory(\n        _In_reads_bytes_(size) const void* pSource, _In_ size_t size,\n        _In_ WIC_FLAGS flags,\n        _Out_ TexMetadata& metadata,\n        _In_opt_ std::function<void __cdecl(IWICMetadataQueryReader*)> getMQR = nullptr);\n\n    HRESULT __cdecl GetMetadataFromWICFile(\n        _In_z_ const wchar_t* szFile,\n        _In_ WIC_FLAGS flags,\n        _Out_ TexMetadata& metadata,\n        _In_opt_ std::function<void __cdecl(IWICMetadataQueryReader*)> getMQR = nullptr);\n#endif\n\n    //---------------------------------------------------------------------------------\n    // Bitmap image container\n    struct Image\n    {\n        size_t      width;\n        size_t      height;\n        DXGI_FORMAT format;\n        size_t      rowPitch;\n        size_t      slicePitch;\n        uint8_t*    pixels;\n    };\n\n    class ScratchImage\n    {\n    public:\n        ScratchImage() noexcept\n            : m_nimages(0), m_size(0), m_metadata{}, m_image(nullptr), m_memory(nullptr) {}\n        ScratchImage(ScratchImage&& moveFrom) noexcept\n            : m_nimages(0), m_size(0), m_metadata{}, m_image(nullptr), m_memory(nullptr) { *this = std::move(moveFrom); }\n        ~ScratchImage() { Release(); }\n\n        ScratchImage& __cdecl operator= (ScratchImage&& moveFrom) noexcept;\n\n        ScratchImage(const ScratchImage&) = delete;\n        ScratchImage& operator=(const ScratchImage&) = delete;\n\n        HRESULT __cdecl Initialize(_In_ const TexMetadata& mdata, _In_ CP_FLAGS flags = CP_FLAGS_NONE) noexcept;\n\n        HRESULT __cdecl Initialize1D(_In_ DXGI_FORMAT fmt, _In_ size_t length, _In_ size_t arraySize, _In_ size_t mipLevels, _In_ CP_FLAGS flags = CP_FLAGS_NONE) noexcept;\n        HRESULT __cdecl Initialize2D(_In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _In_ size_t arraySize, _In_ size_t mipLevels, _In_ CP_FLAGS flags = CP_FLAGS_NONE) noexcept;\n        HRESULT __cdecl Initialize3D(_In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _In_ size_t depth, _In_ size_t mipLevels, _In_ CP_FLAGS flags = CP_FLAGS_NONE) noexcept;\n        HRESULT __cdecl InitializeCube(_In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _In_ size_t nCubes, _In_ size_t mipLevels, _In_ CP_FLAGS flags = CP_FLAGS_NONE) noexcept;\n\n        HRESULT __cdecl InitializeFromImage(_In_ const Image& srcImage, _In_ bool allow1D = false, _In_ CP_FLAGS flags = CP_FLAGS_NONE) noexcept;\n        HRESULT __cdecl InitializeArrayFromImages(_In_reads_(nImages) const Image* images, _In_ size_t nImages, _In_ bool allow1D = false, _In_ CP_FLAGS flags = CP_FLAGS_NONE) noexcept;\n        HRESULT __cdecl InitializeCubeFromImages(_In_reads_(nImages) const Image* images, _In_ size_t nImages, _In_ CP_FLAGS flags = CP_FLAGS_NONE) noexcept;\n        HRESULT __cdecl Initialize3DFromImages(_In_reads_(depth) const Image* images, _In_ size_t depth, _In_ CP_FLAGS flags = CP_FLAGS_NONE) noexcept;\n\n        void __cdecl Release() noexcept;\n\n        bool __cdecl OverrideFormat(_In_ DXGI_FORMAT f) noexcept;\n\n        const TexMetadata& __cdecl GetMetadata() const noexcept { return m_metadata; }\n        const Image* __cdecl GetImage(_In_ size_t mip, _In_ size_t item, _In_ size_t slice) const noexcept;\n\n        const Image* __cdecl GetImages() const noexcept { return m_image; }\n        size_t __cdecl GetImageCount() const noexcept { return m_nimages; }\n\n        uint8_t* __cdecl GetPixels() const noexcept { return m_memory; }\n        size_t __cdecl GetPixelsSize() const noexcept { return m_size; }\n\n        bool __cdecl IsAlphaAllOpaque() const noexcept;\n\n    private:\n        size_t      m_nimages;\n        size_t      m_size;\n        TexMetadata m_metadata;\n        Image*      m_image;\n        uint8_t*    m_memory;\n    };\n\n    //---------------------------------------------------------------------------------\n    // Memory blob (allocated buffer pointer is always 16-byte aligned)\n    class Blob\n    {\n    public:\n        Blob() noexcept : m_buffer(nullptr), m_size(0) {}\n        Blob(Blob&& moveFrom) noexcept : m_buffer(nullptr), m_size(0) { *this = std::move(moveFrom); }\n        ~Blob() { Release(); }\n\n        Blob& __cdecl operator= (Blob&& moveFrom) noexcept;\n\n        Blob(const Blob&) = delete;\n        Blob& operator=(const Blob&) = delete;\n\n        HRESULT __cdecl Initialize(_In_ size_t size) noexcept;\n\n        void __cdecl Release() noexcept;\n\n        void *__cdecl GetBufferPointer() const noexcept { return m_buffer; }\n        size_t __cdecl GetBufferSize() const noexcept { return m_size; }\n\n        HRESULT __cdecl Resize(size_t size) noexcept;\n            // Reallocate for a new size\n\n        HRESULT __cdecl Trim(size_t size) noexcept;\n            // Shorten size without reallocation\n\n    private:\n        void*   m_buffer;\n        size_t  m_size;\n    };\n\n    //---------------------------------------------------------------------------------\n    // Image I/O\n\n    // DDS operations\n    HRESULT __cdecl LoadFromDDSMemory(\n        _In_reads_bytes_(size) const void* pSource, _In_ size_t size,\n        _In_ DDS_FLAGS flags,\n        _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image) noexcept;\n    HRESULT __cdecl LoadFromDDSFile(\n        _In_z_ const wchar_t* szFile,\n        _In_ DDS_FLAGS flags,\n        _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image) noexcept;\n\n    HRESULT __cdecl SaveToDDSMemory(\n        _In_ const Image& image,\n        _In_ DDS_FLAGS flags,\n        _Out_ Blob& blob) noexcept;\n    HRESULT __cdecl SaveToDDSMemory(\n        _In_reads_(nimages) const Image* images, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ DDS_FLAGS flags,\n        _Out_ Blob& blob) noexcept;\n\n    HRESULT __cdecl SaveToDDSFile(_In_ const Image& image, _In_ DDS_FLAGS flags, _In_z_ const wchar_t* szFile) noexcept;\n    HRESULT __cdecl SaveToDDSFile(\n        _In_reads_(nimages) const Image* images, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ DDS_FLAGS flags, _In_z_ const wchar_t* szFile) noexcept;\n\n    // HDR operations\n    HRESULT __cdecl LoadFromHDRMemory(\n        _In_reads_bytes_(size) const void* pSource, _In_ size_t size,\n        _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image) noexcept;\n    HRESULT __cdecl LoadFromHDRFile(\n        _In_z_ const wchar_t* szFile,\n        _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image) noexcept;\n\n    HRESULT __cdecl SaveToHDRMemory(_In_ const Image& image, _Out_ Blob& blob) noexcept;\n    HRESULT __cdecl SaveToHDRFile(_In_ const Image& image, _In_z_ const wchar_t* szFile) noexcept;\n\n    // TGA operations\n    HRESULT __cdecl LoadFromTGAMemory(\n        _In_reads_bytes_(size) const void* pSource, _In_ size_t size,\n        _In_ TGA_FLAGS flags,\n        _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image) noexcept;\n    HRESULT __cdecl LoadFromTGAFile(\n        _In_z_ const wchar_t* szFile,\n        _In_ TGA_FLAGS flags,\n        _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image) noexcept;\n\n    HRESULT __cdecl SaveToTGAMemory(_In_ const Image& image,\n        _In_ TGA_FLAGS flags,\n        _Out_ Blob& blob, _In_opt_ const TexMetadata* metadata = nullptr) noexcept;\n    HRESULT __cdecl SaveToTGAFile(_In_ const Image& image,\n        _In_ TGA_FLAGS flags,\n        _In_z_ const wchar_t* szFile, _In_opt_ const TexMetadata* metadata = nullptr) noexcept;\n\n    // WIC operations\n#ifdef _WIN32\n    HRESULT __cdecl LoadFromWICMemory(\n        _In_reads_bytes_(size) const void* pSource, _In_ size_t size,\n        _In_ WIC_FLAGS flags,\n        _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image,\n        _In_opt_ std::function<void __cdecl(IWICMetadataQueryReader*)> getMQR = nullptr);\n    HRESULT __cdecl LoadFromWICFile(\n        _In_z_ const wchar_t* szFile, _In_ WIC_FLAGS flags,\n        _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image,\n        _In_opt_ std::function<void __cdecl(IWICMetadataQueryReader*)> getMQR = nullptr);\n\n    HRESULT __cdecl SaveToWICMemory(\n        _In_ const Image& image, _In_ WIC_FLAGS flags, _In_ REFGUID guidContainerFormat,\n        _Out_ Blob& blob, _In_opt_ const GUID* targetFormat = nullptr,\n        _In_opt_ std::function<void __cdecl(IPropertyBag2*)> setCustomProps = nullptr);\n    HRESULT __cdecl SaveToWICMemory(\n        _In_count_(nimages) const Image* images, _In_ size_t nimages,\n        _In_ WIC_FLAGS flags, _In_ REFGUID guidContainerFormat,\n        _Out_ Blob& blob, _In_opt_ const GUID* targetFormat = nullptr,\n        _In_opt_ std::function<void __cdecl(IPropertyBag2*)> setCustomProps = nullptr);\n\n    HRESULT __cdecl SaveToWICFile(\n        _In_ const Image& image, _In_ WIC_FLAGS flags, _In_ REFGUID guidContainerFormat,\n        _In_z_ const wchar_t* szFile, _In_opt_ const GUID* targetFormat = nullptr,\n        _In_opt_ std::function<void __cdecl(IPropertyBag2*)> setCustomProps = nullptr);\n    HRESULT __cdecl SaveToWICFile(\n        _In_count_(nimages) const Image* images, _In_ size_t nimages,\n        _In_ WIC_FLAGS flags, _In_ REFGUID guidContainerFormat,\n        _In_z_ const wchar_t* szFile, _In_opt_ const GUID* targetFormat = nullptr,\n        _In_opt_ std::function<void __cdecl(IPropertyBag2*)> setCustomProps = nullptr);\n#endif // WIN32\n\n    //---------------------------------------------------------------------------------\n    // Texture conversion, resizing, mipmap generation, and block compression\n\n    enum TEX_FR_FLAGS : unsigned long\n    {\n        TEX_FR_ROTATE0 = 0x0,\n        TEX_FR_ROTATE90 = 0x1,\n        TEX_FR_ROTATE180 = 0x2,\n        TEX_FR_ROTATE270 = 0x3,\n        TEX_FR_FLIP_HORIZONTAL = 0x08,\n        TEX_FR_FLIP_VERTICAL = 0x10,\n    };\n\n#ifdef _WIN32\n    HRESULT __cdecl FlipRotate(_In_ const Image& srcImage, _In_ TEX_FR_FLAGS flags, _Out_ ScratchImage& image) noexcept;\n    HRESULT __cdecl FlipRotate(\n        _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ TEX_FR_FLAGS flags, _Out_ ScratchImage& result) noexcept;\n        // Flip and/or rotate image\n#endif\n\n    enum TEX_FILTER_FLAGS : unsigned long\n    {\n        TEX_FILTER_DEFAULT = 0,\n\n        TEX_FILTER_WRAP_U = 0x1,\n        TEX_FILTER_WRAP_V = 0x2,\n        TEX_FILTER_WRAP_W = 0x4,\n        TEX_FILTER_WRAP = (TEX_FILTER_WRAP_U | TEX_FILTER_WRAP_V | TEX_FILTER_WRAP_W),\n        TEX_FILTER_MIRROR_U = 0x10,\n        TEX_FILTER_MIRROR_V = 0x20,\n        TEX_FILTER_MIRROR_W = 0x40,\n        TEX_FILTER_MIRROR = (TEX_FILTER_MIRROR_U | TEX_FILTER_MIRROR_V | TEX_FILTER_MIRROR_W),\n        // Wrap vs. Mirror vs. Clamp filtering options\n\n        TEX_FILTER_SEPARATE_ALPHA = 0x100,\n        // Resize color and alpha channel independently\n\n        TEX_FILTER_FLOAT_X2BIAS = 0x200,\n        // Enable *2 - 1 conversion cases for unorm<->float and positive-only float formats\n\n        TEX_FILTER_RGB_COPY_RED = 0x1000,\n        TEX_FILTER_RGB_COPY_GREEN = 0x2000,\n        TEX_FILTER_RGB_COPY_BLUE = 0x4000,\n        // When converting RGB to R, defaults to using grayscale. These flags indicate copying a specific channel instead\n        // When converting RGB to RG, defaults to copying RED | GREEN. These flags control which channels are selected instead.\n\n        TEX_FILTER_DITHER = 0x10000,\n        // Use ordered 4x4 dithering for any required conversions\n        TEX_FILTER_DITHER_DIFFUSION = 0x20000,\n        // Use error-diffusion dithering for any required conversions\n\n        TEX_FILTER_POINT = 0x100000,\n        TEX_FILTER_LINEAR = 0x200000,\n        TEX_FILTER_CUBIC = 0x300000,\n        TEX_FILTER_BOX = 0x400000,\n        TEX_FILTER_FANT = 0x400000, // Equiv to Box filtering for mipmap generation\n        TEX_FILTER_TRIANGLE = 0x500000,\n        // Filtering mode to use for any required image resizing\n\n        TEX_FILTER_SRGB_IN = 0x1000000,\n        TEX_FILTER_SRGB_OUT = 0x2000000,\n        TEX_FILTER_SRGB = (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT),\n        // sRGB <-> RGB for use in conversion operations\n        // if the input format type is IsSRGB(), then SRGB_IN is on by default\n        // if the output format type is IsSRGB(), then SRGB_OUT is on by default\n\n        TEX_FILTER_FORCE_NON_WIC = 0x10000000,\n        // Forces use of the non-WIC path when both are an option\n\n        TEX_FILTER_FORCE_WIC = 0x20000000,\n        // Forces use of the WIC path even when logic would have picked a non-WIC path when both are an option\n    };\n\n    constexpr unsigned long TEX_FILTER_DITHER_MASK = 0xF0000;\n    constexpr unsigned long TEX_FILTER_MODE_MASK = 0xF00000;\n    constexpr unsigned long TEX_FILTER_SRGB_MASK = 0xF000000;\n\n    HRESULT __cdecl Resize(\n        _In_ const Image& srcImage, _In_ size_t width, _In_ size_t height,\n        _In_ TEX_FILTER_FLAGS filter,\n        _Out_ ScratchImage& image) noexcept;\n    HRESULT __cdecl Resize(\n        _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ size_t width, _In_ size_t height, _In_ TEX_FILTER_FLAGS filter, _Out_ ScratchImage& result) noexcept;\n        // Resize the image to width x height. Defaults to Fant filtering.\n        // Note for a complex resize, the result will always have mipLevels == 1\n\n    constexpr float TEX_THRESHOLD_DEFAULT = 0.5f;\n        // Default value for alpha threshold used when converting to 1-bit alpha\n\n    HRESULT __cdecl Convert(\n        _In_ const Image& srcImage, _In_ DXGI_FORMAT format, _In_ TEX_FILTER_FLAGS filter, _In_ float threshold,\n        _Out_ ScratchImage& image) noexcept;\n    HRESULT __cdecl Convert(\n        _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ DXGI_FORMAT format, _In_ TEX_FILTER_FLAGS filter, _In_ float threshold, _Out_ ScratchImage& result) noexcept;\n        // Convert the image to a new format\n\n    HRESULT __cdecl ConvertToSinglePlane(_In_ const Image& srcImage, _Out_ ScratchImage& image) noexcept;\n    HRESULT __cdecl ConvertToSinglePlane(\n        _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _Out_ ScratchImage& image) noexcept;\n        // Converts the image from a planar format to an equivalent non-planar format\n\n    HRESULT __cdecl GenerateMipMaps(\n        _In_ const Image& baseImage, _In_ TEX_FILTER_FLAGS filter, _In_ size_t levels,\n        _Inout_ ScratchImage& mipChain, _In_ bool allow1D = false) noexcept;\n    HRESULT __cdecl GenerateMipMaps(\n        _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ TEX_FILTER_FLAGS filter, _In_ size_t levels, _Inout_ ScratchImage& mipChain);\n        // levels of '0' indicates a full mipchain, otherwise is generates that number of total levels (including the source base image)\n        // Defaults to Fant filtering which is equivalent to a box filter\n\n    HRESULT __cdecl GenerateMipMaps3D(\n        _In_reads_(depth) const Image* baseImages, _In_ size_t depth, _In_ TEX_FILTER_FLAGS filter, _In_ size_t levels,\n        _Out_ ScratchImage& mipChain) noexcept;\n    HRESULT __cdecl GenerateMipMaps3D(\n        _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ TEX_FILTER_FLAGS filter, _In_ size_t levels, _Out_ ScratchImage& mipChain);\n        // levels of '0' indicates a full mipchain, otherwise is generates that number of total levels (including the source base image)\n        // Defaults to Fant filtering which is equivalent to a box filter\n\n    HRESULT __cdecl ScaleMipMapsAlphaForCoverage(\n        _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata, _In_ size_t item,\n        _In_ float alphaReference, _Inout_ ScratchImage& mipChain) noexcept;\n\n\n    enum TEX_PMALPHA_FLAGS : unsigned long\n    {\n        TEX_PMALPHA_DEFAULT = 0,\n\n        TEX_PMALPHA_IGNORE_SRGB = 0x1,\n        // ignores sRGB colorspace conversions\n\n        TEX_PMALPHA_REVERSE = 0x2,\n        // converts from premultiplied alpha back to straight alpha\n\n        TEX_PMALPHA_SRGB_IN = 0x1000000,\n        TEX_PMALPHA_SRGB_OUT = 0x2000000,\n        TEX_PMALPHA_SRGB = (TEX_PMALPHA_SRGB_IN | TEX_PMALPHA_SRGB_OUT),\n        // if the input format type is IsSRGB(), then SRGB_IN is on by default\n        // if the output format type is IsSRGB(), then SRGB_OUT is on by default\n    };\n\n    HRESULT __cdecl PremultiplyAlpha(_In_ const Image& srcImage, _In_ TEX_PMALPHA_FLAGS flags, _Out_ ScratchImage& image) noexcept;\n    HRESULT __cdecl PremultiplyAlpha(\n        _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ TEX_PMALPHA_FLAGS flags, _Out_ ScratchImage& result) noexcept;\n        // Converts to/from a premultiplied alpha version of the texture\n\n    enum TEX_COMPRESS_FLAGS : unsigned long\n    {\n        TEX_COMPRESS_DEFAULT = 0,\n\n        TEX_COMPRESS_RGB_DITHER = 0x10000,\n        // Enables dithering RGB colors for BC1-3 compression\n\n        TEX_COMPRESS_A_DITHER = 0x20000,\n        // Enables dithering alpha for BC1-3 compression\n\n        TEX_COMPRESS_DITHER = 0x30000,\n        // Enables both RGB and alpha dithering for BC1-3 compression\n\n        TEX_COMPRESS_UNIFORM = 0x40000,\n        // Uniform color weighting for BC1-3 compression; by default uses perceptual weighting\n\n        TEX_COMPRESS_BC7_USE_3SUBSETS = 0x80000,\n        // Enables exhaustive search for BC7 compress for mode 0 and 2; by default skips trying these modes\n\n        TEX_COMPRESS_BC7_QUICK = 0x100000,\n        // Minimal modes (usually mode 6) for BC7 compression\n\n        TEX_COMPRESS_SRGB_IN = 0x1000000,\n        TEX_COMPRESS_SRGB_OUT = 0x2000000,\n        TEX_COMPRESS_SRGB = (TEX_COMPRESS_SRGB_IN | TEX_COMPRESS_SRGB_OUT),\n        // if the input format type is IsSRGB(), then SRGB_IN is on by default\n        // if the output format type is IsSRGB(), then SRGB_OUT is on by default\n\n        TEX_COMPRESS_PARALLEL = 0x10000000,\n        // Compress is free to use multithreading to improve performance (by default it does not use multithreading)\n    };\n\n    HRESULT __cdecl Compress(\n        _In_ const Image& srcImage, _In_ DXGI_FORMAT format, _In_ TEX_COMPRESS_FLAGS compress, _In_ float threshold,\n        _Out_ ScratchImage& cImage) noexcept;\n    HRESULT __cdecl Compress(\n        _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ DXGI_FORMAT format, _In_ TEX_COMPRESS_FLAGS compress, _In_ float threshold, _Out_ ScratchImage& cImages) noexcept;\n        // Note that threshold is only used by BC1. TEX_THRESHOLD_DEFAULT is a typical value to use\n\n#if defined(__d3d11_h__) || defined(__d3d11_x_h__)\n    HRESULT __cdecl Compress(\n        _In_ ID3D11Device* pDevice, _In_ const Image& srcImage, _In_ DXGI_FORMAT format, _In_ TEX_COMPRESS_FLAGS compress,\n        _In_ float alphaWeight, _Out_ ScratchImage& image) noexcept;\n    HRESULT __cdecl Compress(\n        _In_ ID3D11Device* pDevice, _In_ const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ DXGI_FORMAT format, _In_ TEX_COMPRESS_FLAGS compress, _In_ float alphaWeight, _Out_ ScratchImage& cImages) noexcept;\n        // DirectCompute-based compression (alphaWeight is only used by BC7. 1.0 is the typical value to use)\n#endif\n\n    HRESULT __cdecl Decompress(_In_ const Image& cImage, _In_ DXGI_FORMAT format, _Out_ ScratchImage& image) noexcept;\n    HRESULT __cdecl Decompress(\n        _In_reads_(nimages) const Image* cImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ DXGI_FORMAT format, _Out_ ScratchImage& images) noexcept;\n\n    //---------------------------------------------------------------------------------\n    // Normal map operations\n\n    enum CNMAP_FLAGS : unsigned long\n    {\n        CNMAP_DEFAULT = 0,\n\n        CNMAP_CHANNEL_RED = 0x1,\n        CNMAP_CHANNEL_GREEN = 0x2,\n        CNMAP_CHANNEL_BLUE = 0x3,\n        CNMAP_CHANNEL_ALPHA = 0x4,\n        CNMAP_CHANNEL_LUMINANCE = 0x5,\n        // Channel selection when evaluting color value for height\n        // Luminance is a combination of red, green, and blue\n\n        CNMAP_MIRROR_U = 0x1000,\n        CNMAP_MIRROR_V = 0x2000,\n        CNMAP_MIRROR = 0x3000,\n        // Use mirror semantics for scanline references (defaults to wrap)\n\n        CNMAP_INVERT_SIGN = 0x4000,\n        // Inverts normal sign\n\n        CNMAP_COMPUTE_OCCLUSION = 0x8000,\n        // Computes a crude occlusion term stored in the alpha channel\n    };\n\n    HRESULT __cdecl ComputeNormalMap(\n        _In_ const Image& srcImage, _In_ CNMAP_FLAGS flags, _In_ float amplitude,\n        _In_ DXGI_FORMAT format, _Out_ ScratchImage& normalMap) noexcept;\n    HRESULT __cdecl ComputeNormalMap(\n        _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ CNMAP_FLAGS flags, _In_ float amplitude, _In_ DXGI_FORMAT format, _Out_ ScratchImage& normalMaps) noexcept;\n\n    //---------------------------------------------------------------------------------\n    // Misc image operations\n\n    struct Rect\n    {\n        size_t x;\n        size_t y;\n        size_t w;\n        size_t h;\n\n        Rect() = default;\n        Rect(size_t _x, size_t _y, size_t _w, size_t _h) noexcept : x(_x), y(_y), w(_w), h(_h) {}\n    };\n\n    HRESULT __cdecl CopyRectangle(\n        _In_ const Image& srcImage, _In_ const Rect& srcRect, _In_ const Image& dstImage,\n        _In_ TEX_FILTER_FLAGS filter, _In_ size_t xOffset, _In_ size_t yOffset) noexcept;\n\n    enum CMSE_FLAGS : unsigned long\n    {\n        CMSE_DEFAULT = 0,\n\n        CMSE_IMAGE1_SRGB = 0x1,\n        CMSE_IMAGE2_SRGB = 0x2,\n        // Indicates that image needs gamma correction before comparision\n\n        CMSE_IGNORE_RED = 0x10,\n        CMSE_IGNORE_GREEN = 0x20,\n        CMSE_IGNORE_BLUE = 0x40,\n        CMSE_IGNORE_ALPHA = 0x80,\n        // Ignore the channel when computing MSE\n\n        CMSE_IMAGE1_X2_BIAS = 0x100,\n        CMSE_IMAGE2_X2_BIAS = 0x200,\n        // Indicates that image should be scaled and biased before comparison (i.e. UNORM -> SNORM)\n    };\n\n    HRESULT __cdecl ComputeMSE(_In_ const Image& image1, _In_ const Image& image2, _Out_ float& mse, _Out_writes_opt_(4) float* mseV, _In_ CMSE_FLAGS flags = CMSE_DEFAULT) noexcept;\n\n    HRESULT __cdecl EvaluateImage(\n        _In_ const Image& image,\n        _In_ std::function<void __cdecl(_In_reads_(width) const XMVECTOR* pixels, size_t width, size_t y)> pixelFunc);\n    HRESULT __cdecl EvaluateImage(\n        _In_reads_(nimages) const Image* images, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ std::function<void __cdecl(_In_reads_(width) const XMVECTOR* pixels, size_t width, size_t y)> pixelFunc);\n\n    HRESULT __cdecl TransformImage(\n        _In_ const Image& image,\n        _In_ std::function<void __cdecl(_Out_writes_(width) XMVECTOR* outPixels,\n            _In_reads_(width) const XMVECTOR* inPixels, size_t width, size_t y)> pixelFunc,\n        ScratchImage& result);\n    HRESULT __cdecl TransformImage(\n        _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n        _In_ std::function<void __cdecl(_Out_writes_(width) XMVECTOR* outPixels,\n            _In_reads_(width) const XMVECTOR* inPixels, size_t width, size_t y)> pixelFunc,\n        ScratchImage& result);\n\n    //---------------------------------------------------------------------------------\n    // WIC utility code\n#ifdef _WIN32\n    enum WICCodecs\n    {\n        WIC_CODEC_BMP = 1,          // Windows Bitmap (.bmp)\n        WIC_CODEC_JPEG,             // Joint Photographic Experts Group (.jpg, .jpeg)\n        WIC_CODEC_PNG,              // Portable Network Graphics (.png)\n        WIC_CODEC_TIFF,             // Tagged Image File Format  (.tif, .tiff)\n        WIC_CODEC_GIF,              // Graphics Interchange Format  (.gif)\n        WIC_CODEC_WMP,              // Windows Media Photo / HD Photo / JPEG XR (.hdp, .jxr, .wdp)\n        WIC_CODEC_ICO,              // Windows Icon (.ico)\n        WIC_CODEC_HEIF,             // High Efficiency Image File (.heif, .heic)\n    };\n\n    REFGUID __cdecl GetWICCodec(_In_ WICCodecs codec) noexcept;\n\n    IWICImagingFactory* __cdecl GetWICFactory(bool& iswic2) noexcept;\n    void __cdecl SetWICFactory(_In_opt_ IWICImagingFactory* pWIC) noexcept;\n#endif\n\n    //---------------------------------------------------------------------------------\n    // DDS helper functions\n    HRESULT __cdecl EncodeDDSHeader(\n        _In_ const TexMetadata& metadata, DDS_FLAGS flags,\n        _Out_writes_bytes_to_opt_(maxsize, required) void* pDestination, _In_ size_t maxsize,\n        _Out_ size_t& required) noexcept;\n\n    //---------------------------------------------------------------------------------\n    // Direct3D 11 functions\n#if defined(__d3d11_h__) || defined(__d3d11_x_h__)\n    bool __cdecl IsSupportedTexture(_In_ ID3D11Device* pDevice, _In_ const TexMetadata& metadata) noexcept;\n#endif\n\n#pragma warning(push)\n#pragma warning(disable : 4619 4616 4061)\n\n#include \"DirectXTex.inl\"\n\n#pragma warning(pop)\n\n} // namespace\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTex.inl",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTex.inl\n//\n// DirectX Texture Library\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n//=====================================================================================\n// Bitmask flags enumerator operators\n//=====================================================================================\nDEFINE_ENUM_FLAG_OPERATORS(CP_FLAGS);\nDEFINE_ENUM_FLAG_OPERATORS(DDS_FLAGS);\nDEFINE_ENUM_FLAG_OPERATORS(TGA_FLAGS);\nDEFINE_ENUM_FLAG_OPERATORS(WIC_FLAGS);\nDEFINE_ENUM_FLAG_OPERATORS(TEX_FR_FLAGS);\nDEFINE_ENUM_FLAG_OPERATORS(TEX_FILTER_FLAGS);\nDEFINE_ENUM_FLAG_OPERATORS(TEX_PMALPHA_FLAGS);\nDEFINE_ENUM_FLAG_OPERATORS(TEX_COMPRESS_FLAGS);\nDEFINE_ENUM_FLAG_OPERATORS(CNMAP_FLAGS);\nDEFINE_ENUM_FLAG_OPERATORS(CMSE_FLAGS);\n\n// WIC_FILTER modes match TEX_FILTER modes\nconstexpr WIC_FLAGS operator|(WIC_FLAGS a, TEX_FILTER_FLAGS b) { return static_cast<WIC_FLAGS>(static_cast<unsigned long>(a) | static_cast<unsigned long>(b & TEX_FILTER_MODE_MASK)); }\nconstexpr WIC_FLAGS operator|(TEX_FILTER_FLAGS a, WIC_FLAGS b) { return static_cast<WIC_FLAGS>(static_cast<unsigned long>(a & TEX_FILTER_MODE_MASK) | static_cast<unsigned long>(b)); }\n\n// TEX_PMALPHA_SRGB match TEX_FILTER_SRGB\nconstexpr TEX_PMALPHA_FLAGS operator|(TEX_PMALPHA_FLAGS a, TEX_FILTER_FLAGS b) { return static_cast<TEX_PMALPHA_FLAGS>(static_cast<unsigned long>(a) | static_cast<unsigned long>(b & TEX_FILTER_SRGB_MASK)); }\nconstexpr TEX_PMALPHA_FLAGS operator|(TEX_FILTER_FLAGS a, TEX_PMALPHA_FLAGS b) { return static_cast<TEX_PMALPHA_FLAGS>(static_cast<unsigned long>(a & TEX_FILTER_SRGB_MASK) | static_cast<unsigned long>(b)); }\n\n// TEX_COMPRESS_SRGB match TEX_FILTER_SRGB\nconstexpr TEX_COMPRESS_FLAGS operator|(TEX_COMPRESS_FLAGS a, TEX_FILTER_FLAGS b) { return static_cast<TEX_COMPRESS_FLAGS>(static_cast<unsigned long>(a) | static_cast<unsigned long>(b & TEX_FILTER_SRGB_MASK)); }\nconstexpr TEX_COMPRESS_FLAGS operator|(TEX_FILTER_FLAGS a, TEX_COMPRESS_FLAGS b) { return static_cast<TEX_COMPRESS_FLAGS>(static_cast<unsigned long>(a & TEX_FILTER_SRGB_MASK) | static_cast<unsigned long>(b)); }\n\n\n//=====================================================================================\n// DXGI Format Utilities\n//=====================================================================================\n\n_Use_decl_annotations_\nconstexpr bool __cdecl IsValid(DXGI_FORMAT fmt) noexcept\n{\n    return (static_cast<size_t>(fmt) >= 1 && static_cast<size_t>(fmt) <= 190);\n}\n\n_Use_decl_annotations_\ninline bool __cdecl IsCompressed(DXGI_FORMAT fmt) noexcept\n{\n    switch (fmt)\n    {\n    case DXGI_FORMAT_BC1_TYPELESS:\n    case DXGI_FORMAT_BC1_UNORM:\n    case DXGI_FORMAT_BC1_UNORM_SRGB:\n    case DXGI_FORMAT_BC2_TYPELESS:\n    case DXGI_FORMAT_BC2_UNORM:\n    case DXGI_FORMAT_BC2_UNORM_SRGB:\n    case DXGI_FORMAT_BC3_TYPELESS:\n    case DXGI_FORMAT_BC3_UNORM:\n    case DXGI_FORMAT_BC3_UNORM_SRGB:\n    case DXGI_FORMAT_BC4_TYPELESS:\n    case DXGI_FORMAT_BC4_UNORM:\n    case DXGI_FORMAT_BC4_SNORM:\n    case DXGI_FORMAT_BC5_TYPELESS:\n    case DXGI_FORMAT_BC5_UNORM:\n    case DXGI_FORMAT_BC5_SNORM:\n    case DXGI_FORMAT_BC6H_TYPELESS:\n    case DXGI_FORMAT_BC6H_UF16:\n    case DXGI_FORMAT_BC6H_SF16:\n    case DXGI_FORMAT_BC7_TYPELESS:\n    case DXGI_FORMAT_BC7_UNORM:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n        return true;\n\n    default:\n        return false;\n    }\n}\n\n_Use_decl_annotations_\ninline bool __cdecl IsPalettized(DXGI_FORMAT fmt) noexcept\n{\n    switch (fmt)\n    {\n    case DXGI_FORMAT_AI44:\n    case DXGI_FORMAT_IA44:\n    case DXGI_FORMAT_P8:\n    case DXGI_FORMAT_A8P8:\n        return true;\n\n    default:\n        return false;\n    }\n}\n\n_Use_decl_annotations_\ninline bool __cdecl IsSRGB(DXGI_FORMAT fmt) noexcept\n{\n    switch (fmt)\n    {\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n    case DXGI_FORMAT_BC1_UNORM_SRGB:\n    case DXGI_FORMAT_BC2_UNORM_SRGB:\n    case DXGI_FORMAT_BC3_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n        return true;\n\n    default:\n        return false;\n    }\n}\n\n_Use_decl_annotations_\ninline bool __cdecl IsBGR(DXGI_FORMAT fmt) noexcept\n{\n    switch (fmt)\n    {\n    case DXGI_FORMAT_B5G6R5_UNORM:\n    case DXGI_FORMAT_B5G5R5A1_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_UNORM:\n    case DXGI_FORMAT_B8G8R8X8_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_TYPELESS:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8X8_TYPELESS:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n    case DXGI_FORMAT_B4G4R4A4_UNORM:\n        return true;\n\n    default:\n        return false;\n    }\n}\n\n\n//=====================================================================================\n// Image I/O\n//=====================================================================================\n_Use_decl_annotations_\ninline HRESULT __cdecl SaveToDDSMemory(const Image& image, DDS_FLAGS flags, Blob& blob) noexcept\n{\n    TexMetadata mdata = {};\n    mdata.width = image.width;\n    mdata.height = image.height;\n    mdata.depth = 1;\n    mdata.arraySize = 1;\n    mdata.mipLevels = 1;\n    mdata.format = image.format;\n    mdata.dimension = TEX_DIMENSION_TEXTURE2D;\n\n    return SaveToDDSMemory(&image, 1, mdata, flags, blob);\n}\n\n_Use_decl_annotations_\ninline HRESULT __cdecl SaveToDDSFile(const Image& image, DDS_FLAGS flags, const wchar_t* szFile) noexcept\n{\n    TexMetadata mdata = {};\n    mdata.width = image.width;\n    mdata.height = image.height;\n    mdata.depth = 1;\n    mdata.arraySize = 1;\n    mdata.mipLevels = 1;\n    mdata.format = image.format;\n    mdata.dimension = TEX_DIMENSION_TEXTURE2D;\n\n    return SaveToDDSFile(&image, 1, mdata, flags, szFile);\n}\n\n\n//=====================================================================================\n// Compatability helpers\n//=====================================================================================\n_Use_decl_annotations_\ninline HRESULT __cdecl GetMetadataFromTGAMemory(const void* pSource, size_t size, TexMetadata& metadata) noexcept\n{\n    return GetMetadataFromTGAMemory(pSource, size, TGA_FLAGS_NONE, metadata);\n}\n\n_Use_decl_annotations_\ninline HRESULT __cdecl GetMetadataFromTGAFile(const wchar_t* szFile, TexMetadata& metadata) noexcept\n{\n    return GetMetadataFromTGAFile(szFile, TGA_FLAGS_NONE, metadata);\n}\n\n_Use_decl_annotations_\ninline HRESULT __cdecl LoadFromTGAMemory(const void* pSource, size_t size, TexMetadata* metadata, ScratchImage& image) noexcept\n{\n    return LoadFromTGAMemory(pSource, size, TGA_FLAGS_NONE, metadata, image);\n}\n\n_Use_decl_annotations_\ninline HRESULT __cdecl LoadFromTGAFile(const wchar_t* szFile, TexMetadata* metadata, ScratchImage& image) noexcept\n{\n    return LoadFromTGAFile(szFile, TGA_FLAGS_NONE, metadata, image);\n}\n\n_Use_decl_annotations_\ninline HRESULT __cdecl SaveToTGAMemory(const Image& image, Blob& blob, const TexMetadata* metadata) noexcept\n{\n    return SaveToTGAMemory(image, TGA_FLAGS_NONE, blob, metadata);\n}\n\n_Use_decl_annotations_\ninline HRESULT __cdecl SaveToTGAFile(const Image& image, const wchar_t* szFile, const TexMetadata* metadata) noexcept\n{\n    return SaveToTGAFile(image, TGA_FLAGS_NONE, szFile, metadata);\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTexCompress.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTexCompress.cpp\n//\n// DirectX Texture Library - Texture compression\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\n#ifdef _OPENMP\n#include <omp.h>\n#pragma warning(disable : 4616 6993)\n#endif\n\n#include \"BC.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::Internal;\n\nnamespace\n{\n    constexpr uint32_t GetBCFlags(_In_ TEX_COMPRESS_FLAGS compress) noexcept\n    {\n        static_assert(static_cast<int>(TEX_COMPRESS_RGB_DITHER) == static_cast<int>(BC_FLAGS_DITHER_RGB), \"TEX_COMPRESS_* flags should match BC_FLAGS_*\");\n        static_assert(static_cast<int>(TEX_COMPRESS_A_DITHER) == static_cast<int>(BC_FLAGS_DITHER_A), \"TEX_COMPRESS_* flags should match BC_FLAGS_*\");\n        static_assert(static_cast<int>(TEX_COMPRESS_DITHER) == static_cast<int>(BC_FLAGS_DITHER_RGB | BC_FLAGS_DITHER_A), \"TEX_COMPRESS_* flags should match BC_FLAGS_*\");\n        static_assert(static_cast<int>(TEX_COMPRESS_UNIFORM) == static_cast<int>(BC_FLAGS_UNIFORM), \"TEX_COMPRESS_* flags should match BC_FLAGS_*\");\n        static_assert(static_cast<int>(TEX_COMPRESS_BC7_USE_3SUBSETS) == static_cast<int>(BC_FLAGS_USE_3SUBSETS), \"TEX_COMPRESS_* flags should match BC_FLAGS_*\");\n        static_assert(static_cast<int>(TEX_COMPRESS_BC7_QUICK) == static_cast<int>(BC_FLAGS_FORCE_BC7_MODE6), \"TEX_COMPRESS_* flags should match BC_FLAGS_*\");\n        return (compress & (BC_FLAGS_DITHER_RGB | BC_FLAGS_DITHER_A | BC_FLAGS_UNIFORM | BC_FLAGS_USE_3SUBSETS | BC_FLAGS_FORCE_BC7_MODE6));\n    }\n\n    constexpr TEX_FILTER_FLAGS GetSRGBFlags(_In_ TEX_COMPRESS_FLAGS compress) noexcept\n    {\n        static_assert(TEX_FILTER_SRGB_IN == 0x1000000, \"TEX_FILTER_SRGB flag values don't match TEX_FILTER_SRGB_MASK\");\n        static_assert(static_cast<int>(TEX_COMPRESS_SRGB_IN) == static_cast<int>(TEX_FILTER_SRGB_IN), \"TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*\");\n        static_assert(static_cast<int>(TEX_COMPRESS_SRGB_OUT) == static_cast<int>(TEX_FILTER_SRGB_OUT), \"TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*\");\n        static_assert(static_cast<int>(TEX_COMPRESS_SRGB) == static_cast<int>(TEX_FILTER_SRGB), \"TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*\");\n        return static_cast<TEX_FILTER_FLAGS>(compress & TEX_FILTER_SRGB_MASK);\n    }\n\n    inline bool DetermineEncoderSettings(_In_ DXGI_FORMAT format, _Out_ BC_ENCODE& pfEncode, _Out_ size_t& blocksize, _Out_ TEX_FILTER_FLAGS& cflags) noexcept\n    {\n        switch (format)\n        {\n        case DXGI_FORMAT_BC1_UNORM:\n        case DXGI_FORMAT_BC1_UNORM_SRGB:    pfEncode = nullptr;         blocksize = 8;   cflags = TEX_FILTER_DEFAULT; break;\n        case DXGI_FORMAT_BC2_UNORM:\n        case DXGI_FORMAT_BC2_UNORM_SRGB:    pfEncode = D3DXEncodeBC2;   blocksize = 16;  cflags = TEX_FILTER_DEFAULT; break;\n        case DXGI_FORMAT_BC3_UNORM:\n        case DXGI_FORMAT_BC3_UNORM_SRGB:    pfEncode = D3DXEncodeBC3;   blocksize = 16;  cflags = TEX_FILTER_DEFAULT; break;\n        case DXGI_FORMAT_BC4_UNORM:         pfEncode = D3DXEncodeBC4U;  blocksize = 8;   cflags = TEX_FILTER_RGB_COPY_RED; break;\n        case DXGI_FORMAT_BC4_SNORM:         pfEncode = D3DXEncodeBC4S;  blocksize = 8;   cflags = TEX_FILTER_RGB_COPY_RED; break;\n        case DXGI_FORMAT_BC5_UNORM:         pfEncode = D3DXEncodeBC5U;  blocksize = 16;  cflags = TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN; break;\n        case DXGI_FORMAT_BC5_SNORM:         pfEncode = D3DXEncodeBC5S;  blocksize = 16;  cflags = TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN; break;\n        case DXGI_FORMAT_BC6H_UF16:         pfEncode = D3DXEncodeBC6HU; blocksize = 16;  cflags = TEX_FILTER_DEFAULT; break;\n        case DXGI_FORMAT_BC6H_SF16:         pfEncode = D3DXEncodeBC6HS; blocksize = 16;  cflags = TEX_FILTER_DEFAULT; break;\n        case DXGI_FORMAT_BC7_UNORM:\n        case DXGI_FORMAT_BC7_UNORM_SRGB:    pfEncode = D3DXEncodeBC7;   blocksize = 16;  cflags = TEX_FILTER_DEFAULT; break;\n        default:                            pfEncode = nullptr;         blocksize = 0;   cflags = TEX_FILTER_DEFAULT; return false;\n        }\n\n        return true;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    HRESULT CompressBC(\n        const Image& image,\n        const Image& result,\n        uint32_t bcflags,\n        TEX_FILTER_FLAGS srgb,\n        float threshold) noexcept\n    {\n        if (!image.pixels || !result.pixels)\n            return E_POINTER;\n\n        assert(image.width == result.width);\n        assert(image.height == result.height);\n\n        const DXGI_FORMAT format = image.format;\n        size_t sbpp = BitsPerPixel(format);\n        if (!sbpp)\n            return E_FAIL;\n\n        if (sbpp < 8)\n        {\n            // We don't support compressing from monochrome (DXGI_FORMAT_R1_UNORM)\n            return HRESULT_E_NOT_SUPPORTED;\n        }\n\n        // Round to bytes\n        sbpp = (sbpp + 7) / 8;\n\n        uint8_t *pDest = result.pixels;\n\n        // Determine BC format encoder\n        BC_ENCODE pfEncode;\n        size_t blocksize;\n        TEX_FILTER_FLAGS cflags;\n        if (!DetermineEncoderSettings(result.format, pfEncode, blocksize, cflags))\n            return HRESULT_E_NOT_SUPPORTED;\n\n        XM_ALIGNED_DATA(16) XMVECTOR temp[16];\n        const uint8_t *pSrc = image.pixels;\n        const uint8_t *pEnd = image.pixels + image.slicePitch;\n        const size_t rowPitch = image.rowPitch;\n        for (size_t h = 0; h < image.height; h += 4)\n        {\n            const uint8_t *sptr = pSrc;\n            uint8_t* dptr = pDest;\n            const size_t ph = std::min<size_t>(4, image.height - h);\n            size_t w = 0;\n            for (size_t count = 0; (count < result.rowPitch) && (w < image.width); count += blocksize, w += 4)\n            {\n                const size_t pw = std::min<size_t>(4, image.width - w);\n                assert(pw > 0 && ph > 0);\n\n                const ptrdiff_t bytesLeft = pEnd - sptr;\n                assert(bytesLeft > 0);\n                size_t bytesToRead = std::min<size_t>(rowPitch, static_cast<size_t>(bytesLeft));\n                if (!LoadScanline(&temp[0], pw, sptr, bytesToRead, format))\n                    return E_FAIL;\n\n                if (ph > 1)\n                {\n                    bytesToRead = std::min<size_t>(rowPitch, static_cast<size_t>(bytesLeft) - rowPitch);\n                    if (!LoadScanline(&temp[4], pw, sptr + rowPitch, bytesToRead, format))\n                        return E_FAIL;\n\n                    if (ph > 2)\n                    {\n                        bytesToRead = std::min<size_t>(rowPitch, static_cast<size_t>(bytesLeft) - rowPitch * 2);\n                        if (!LoadScanline(&temp[8], pw, sptr + rowPitch * 2, bytesToRead, format))\n                            return E_FAIL;\n\n                        if (ph > 3)\n                        {\n                            bytesToRead = std::min<size_t>(rowPitch, static_cast<size_t>(bytesLeft) - rowPitch * 3);\n                            if (!LoadScanline(&temp[12], pw, sptr + rowPitch * 3, bytesToRead, format))\n                                return E_FAIL;\n                        }\n                    }\n                }\n\n                if (pw != 4 || ph != 4)\n                {\n                    // Replicate pixels for partial block\n                    static const size_t uSrc[] = { 0, 0, 0, 1 };\n\n                    if (pw < 4)\n                    {\n                        for (size_t t = 0; t < ph && t < 4; ++t)\n                        {\n                            for (size_t s = pw; s < 4; ++s)\n                            {\n                            #pragma prefast(suppress: 26000, \"PREFAST false positive\")\n                                temp[(t << 2) | s] = temp[(t << 2) | uSrc[s]];\n                            }\n                        }\n                    }\n\n                    if (ph < 4)\n                    {\n                        for (size_t t = ph; t < 4; ++t)\n                        {\n                            for (size_t s = 0; s < 4; ++s)\n                            {\n                            #pragma prefast(suppress: 26000, \"PREFAST false positive\")\n                                temp[(t << 2) | s] = temp[(uSrc[t] << 2) | s];\n                            }\n                        }\n                    }\n                }\n\n                ConvertScanline(temp, 16, result.format, format, cflags | srgb);\n\n                if (pfEncode)\n                    pfEncode(dptr, temp, bcflags);\n                else\n                    D3DXEncodeBC1(dptr, temp, threshold, bcflags);\n\n                sptr += sbpp * 4;\n                dptr += blocksize;\n            }\n\n            pSrc += rowPitch * 4;\n            pDest += result.rowPitch;\n        }\n\n        return S_OK;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n#ifdef _OPENMP\n    HRESULT CompressBC_Parallel(\n        const Image& image,\n        const Image& result,\n        uint32_t bcflags,\n        TEX_FILTER_FLAGS srgb,\n        float threshold) noexcept\n    {\n        if (!image.pixels || !result.pixels)\n            return E_POINTER;\n\n        assert(image.width == result.width);\n        assert(image.height == result.height);\n\n        const DXGI_FORMAT format = image.format;\n        size_t sbpp = BitsPerPixel(format);\n        if (!sbpp)\n            return E_FAIL;\n\n        if (sbpp < 8)\n        {\n            // We don't support compressing from monochrome (DXGI_FORMAT_R1_UNORM)\n            return HRESULT_E_NOT_SUPPORTED;\n        }\n\n        // Round to bytes\n        sbpp = (sbpp + 7) / 8;\n\n        const uint8_t *pEnd = image.pixels + image.slicePitch;\n\n        // Determine BC format encoder\n        BC_ENCODE pfEncode;\n        size_t blocksize;\n        TEX_FILTER_FLAGS cflags;\n        if (!DetermineEncoderSettings(result.format, pfEncode, blocksize, cflags))\n            return HRESULT_E_NOT_SUPPORTED;\n\n        // Refactored version of loop to support parallel independance\n        const size_t nBlocks = std::max<size_t>(1, (image.width + 3) / 4) * std::max<size_t>(1, (image.height + 3) / 4);\n\n        bool fail = false;\n\n    #pragma omp parallel for\n        for (int nb = 0; nb < static_cast<int>(nBlocks); ++nb)\n        {\n            const int nbWidth = std::max<int>(1, int((image.width + 3) / 4));\n\n            int y = nb / nbWidth;\n            const int x = (nb - (y*nbWidth)) * 4;\n            y *= 4;\n\n            assert((x >= 0) && (x < int(image.width)));\n            assert((y >= 0) && (y < int(image.height)));\n\n            const size_t rowPitch = image.rowPitch;\n            const uint8_t *pSrc = image.pixels + (size_t(y)*rowPitch) + (size_t(x)*sbpp);\n\n            uint8_t *pDest = result.pixels + (size_t(nb)*blocksize);\n\n            const size_t ph = std::min<size_t>(4, image.height - size_t(y));\n            const size_t pw = std::min<size_t>(4, image.width - size_t(x));\n            assert(pw > 0 && ph > 0);\n\n            const ptrdiff_t bytesLeft = pEnd - pSrc;\n            assert(bytesLeft > 0);\n            size_t bytesToRead = std::min<size_t>(rowPitch, size_t(bytesLeft));\n\n            XM_ALIGNED_DATA(16) XMVECTOR temp[16];\n            if (!LoadScanline(&temp[0], pw, pSrc, bytesToRead, format))\n                fail = true;\n\n            if (ph > 1)\n            {\n                bytesToRead = std::min<size_t>(rowPitch, size_t(bytesLeft) - rowPitch);\n                if (!LoadScanline(&temp[4], pw, pSrc + rowPitch, bytesToRead, format))\n                    fail = true;\n\n                if (ph > 2)\n                {\n                    bytesToRead = std::min<size_t>(rowPitch, size_t(bytesLeft) - rowPitch * 2);\n                    if (!LoadScanline(&temp[8], pw, pSrc + rowPitch * 2, bytesToRead, format))\n                        fail = true;\n\n                    if (ph > 3)\n                    {\n                        bytesToRead = std::min<size_t>(rowPitch, size_t(bytesLeft) - rowPitch * 3);\n                        if (!LoadScanline(&temp[12], pw, pSrc + rowPitch * 3, bytesToRead, format))\n                            fail = true;\n                    }\n                }\n            }\n\n            if (pw != 4 || ph != 4)\n            {\n                // Replicate pixels for partial block\n                static const size_t uSrc[] = { 0, 0, 0, 1 };\n\n                if (pw < 4)\n                {\n                    for (size_t t = 0; t < ph && t < 4; ++t)\n                    {\n                        for (size_t s = pw; s < 4; ++s)\n                        {\n                            temp[(t << 2) | s] = temp[(t << 2) | uSrc[s]];\n                        }\n                    }\n                }\n\n                if (ph < 4)\n                {\n                    for (size_t t = ph; t < 4; ++t)\n                    {\n                        for (size_t s = 0; s < 4; ++s)\n                        {\n                            temp[(t << 2) | s] = temp[(uSrc[t] << 2) | s];\n                        }\n                    }\n                }\n            }\n\n            ConvertScanline(temp, 16, result.format, format, cflags | srgb);\n\n            if (pfEncode)\n                pfEncode(pDest, temp, bcflags);\n            else\n                D3DXEncodeBC1(pDest, temp, threshold, bcflags);\n        }\n\n        return (fail) ? E_FAIL : S_OK;\n    }\n#endif // _OPENMP\n\n\n    //-------------------------------------------------------------------------------------\n    DXGI_FORMAT DefaultDecompress(_In_ DXGI_FORMAT format) noexcept\n    {\n        switch (format)\n        {\n        case DXGI_FORMAT_BC1_TYPELESS:\n        case DXGI_FORMAT_BC1_UNORM:\n        case DXGI_FORMAT_BC2_TYPELESS:\n        case DXGI_FORMAT_BC2_UNORM:\n        case DXGI_FORMAT_BC3_TYPELESS:\n        case DXGI_FORMAT_BC3_UNORM:\n        case DXGI_FORMAT_BC7_TYPELESS:\n        case DXGI_FORMAT_BC7_UNORM:\n            return DXGI_FORMAT_R8G8B8A8_UNORM;\n\n        case DXGI_FORMAT_BC1_UNORM_SRGB:\n        case DXGI_FORMAT_BC2_UNORM_SRGB:\n        case DXGI_FORMAT_BC3_UNORM_SRGB:\n        case DXGI_FORMAT_BC7_UNORM_SRGB:\n            return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;\n\n        case DXGI_FORMAT_BC4_TYPELESS:\n        case DXGI_FORMAT_BC4_UNORM:\n            return DXGI_FORMAT_R8_UNORM;\n\n        case DXGI_FORMAT_BC4_SNORM:\n            return DXGI_FORMAT_R8_SNORM;\n\n        case DXGI_FORMAT_BC5_TYPELESS:\n        case DXGI_FORMAT_BC5_UNORM:\n            return DXGI_FORMAT_R8G8_UNORM;\n\n        case DXGI_FORMAT_BC5_SNORM:\n            return DXGI_FORMAT_R8G8_SNORM;\n\n        case DXGI_FORMAT_BC6H_TYPELESS:\n        case DXGI_FORMAT_BC6H_UF16:\n        case DXGI_FORMAT_BC6H_SF16:\n            // We could use DXGI_FORMAT_R32G32B32_FLOAT here since BC6H is always Alpha 1.0,\n            // but this format is more supported by viewers\n            return DXGI_FORMAT_R32G32B32A32_FLOAT;\n\n        default:\n            return DXGI_FORMAT_UNKNOWN;\n        }\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    HRESULT DecompressBC(_In_ const Image& cImage, _In_ const Image& result) noexcept\n    {\n        if (!cImage.pixels || !result.pixels)\n            return E_POINTER;\n\n        assert(cImage.width == result.width);\n        assert(cImage.height == result.height);\n\n        const DXGI_FORMAT format = result.format;\n        size_t dbpp = BitsPerPixel(format);\n        if (!dbpp)\n            return E_FAIL;\n\n        if (dbpp < 8)\n        {\n            // We don't support decompressing to monochrome (DXGI_FORMAT_R1_UNORM)\n            return HRESULT_E_NOT_SUPPORTED;\n        }\n\n        // Round to bytes\n        dbpp = (dbpp + 7) / 8;\n\n        uint8_t *pDest = result.pixels;\n        if (!pDest)\n            return E_POINTER;\n\n        // Promote \"typeless\" BC formats\n        DXGI_FORMAT cformat;\n        switch (cImage.format)\n        {\n        case DXGI_FORMAT_BC1_TYPELESS:  cformat = DXGI_FORMAT_BC1_UNORM; break;\n        case DXGI_FORMAT_BC2_TYPELESS:  cformat = DXGI_FORMAT_BC2_UNORM; break;\n        case DXGI_FORMAT_BC3_TYPELESS:  cformat = DXGI_FORMAT_BC3_UNORM; break;\n        case DXGI_FORMAT_BC4_TYPELESS:  cformat = DXGI_FORMAT_BC4_UNORM; break;\n        case DXGI_FORMAT_BC5_TYPELESS:  cformat = DXGI_FORMAT_BC5_UNORM; break;\n        case DXGI_FORMAT_BC6H_TYPELESS: cformat = DXGI_FORMAT_BC6H_UF16; break;\n        case DXGI_FORMAT_BC7_TYPELESS:  cformat = DXGI_FORMAT_BC7_UNORM; break;\n        default:                        cformat = cImage.format;         break;\n        }\n\n        // Determine BC format decoder\n        BC_DECODE pfDecode;\n        size_t sbpp;\n        switch (cformat)\n        {\n        case DXGI_FORMAT_BC1_UNORM:\n        case DXGI_FORMAT_BC1_UNORM_SRGB:    pfDecode = D3DXDecodeBC1;   sbpp = 8;   break;\n        case DXGI_FORMAT_BC2_UNORM:\n        case DXGI_FORMAT_BC2_UNORM_SRGB:    pfDecode = D3DXDecodeBC2;   sbpp = 16;  break;\n        case DXGI_FORMAT_BC3_UNORM:\n        case DXGI_FORMAT_BC3_UNORM_SRGB:    pfDecode = D3DXDecodeBC3;   sbpp = 16;  break;\n        case DXGI_FORMAT_BC4_UNORM:         pfDecode = D3DXDecodeBC4U;  sbpp = 8;   break;\n        case DXGI_FORMAT_BC4_SNORM:         pfDecode = D3DXDecodeBC4S;  sbpp = 8;   break;\n        case DXGI_FORMAT_BC5_UNORM:         pfDecode = D3DXDecodeBC5U;  sbpp = 16;  break;\n        case DXGI_FORMAT_BC5_SNORM:         pfDecode = D3DXDecodeBC5S;  sbpp = 16;  break;\n        case DXGI_FORMAT_BC6H_UF16:         pfDecode = D3DXDecodeBC6HU; sbpp = 16;  break;\n        case DXGI_FORMAT_BC6H_SF16:         pfDecode = D3DXDecodeBC6HS; sbpp = 16;  break;\n        case DXGI_FORMAT_BC7_UNORM:\n        case DXGI_FORMAT_BC7_UNORM_SRGB:    pfDecode = D3DXDecodeBC7;   sbpp = 16;  break;\n        default:\n            return HRESULT_E_NOT_SUPPORTED;\n        }\n\n        XM_ALIGNED_DATA(16) XMVECTOR temp[16];\n        const uint8_t *pSrc = cImage.pixels;\n        const size_t rowPitch = result.rowPitch;\n        for (size_t h = 0; h < cImage.height; h += 4)\n        {\n            const uint8_t *sptr = pSrc;\n            uint8_t* dptr = pDest;\n            const size_t ph = std::min<size_t>(4, cImage.height - h);\n            size_t w = 0;\n            for (size_t count = 0; (count < cImage.rowPitch) && (w < cImage.width); count += sbpp, w += 4)\n            {\n                pfDecode(temp, sptr);\n                ConvertScanline(temp, 16, format, cformat, TEX_FILTER_DEFAULT);\n\n                const size_t pw = std::min<size_t>(4, cImage.width - w);\n                assert(pw > 0 && ph > 0);\n\n                if (!StoreScanline(dptr, rowPitch, format, &temp[0], pw))\n                    return E_FAIL;\n\n                if (ph > 1)\n                {\n                    if (!StoreScanline(dptr + rowPitch, rowPitch, format, &temp[4], pw))\n                        return E_FAIL;\n\n                    if (ph > 2)\n                    {\n                        if (!StoreScanline(dptr + rowPitch * 2, rowPitch, format, &temp[8], pw))\n                            return E_FAIL;\n\n                        if (ph > 3)\n                        {\n                            if (!StoreScanline(dptr + rowPitch * 3, rowPitch, format, &temp[12], pw))\n                                return E_FAIL;\n                        }\n                    }\n                }\n\n                sptr += sbpp;\n                dptr += dbpp * 4;\n            }\n\n            pSrc += cImage.rowPitch;\n            pDest += rowPitch * 4;\n        }\n\n        return S_OK;\n    }\n}\n\n//-------------------------------------------------------------------------------------\nbool DirectX::Internal::IsAlphaAllOpaqueBC(_In_ const Image& cImage) noexcept\n{\n    if (!cImage.pixels)\n        return false;\n\n    // Promote \"typeless\" BC formats\n    DXGI_FORMAT cformat;\n    switch (cImage.format)\n    {\n    case DXGI_FORMAT_BC1_TYPELESS:  cformat = DXGI_FORMAT_BC1_UNORM; break;\n    case DXGI_FORMAT_BC2_TYPELESS:  cformat = DXGI_FORMAT_BC2_UNORM; break;\n    case DXGI_FORMAT_BC3_TYPELESS:  cformat = DXGI_FORMAT_BC3_UNORM; break;\n    case DXGI_FORMAT_BC7_TYPELESS:  cformat = DXGI_FORMAT_BC7_UNORM; break;\n    default:                        cformat = cImage.format;         break;\n    }\n\n    // Determine BC format decoder\n    BC_DECODE pfDecode;\n    size_t sbpp;\n    switch (cformat)\n    {\n    case DXGI_FORMAT_BC1_UNORM:\n    case DXGI_FORMAT_BC1_UNORM_SRGB:    pfDecode = D3DXDecodeBC1;   sbpp = 8;   break;\n    case DXGI_FORMAT_BC2_UNORM:\n    case DXGI_FORMAT_BC2_UNORM_SRGB:    pfDecode = D3DXDecodeBC2;   sbpp = 16;  break;\n    case DXGI_FORMAT_BC3_UNORM:\n    case DXGI_FORMAT_BC3_UNORM_SRGB:    pfDecode = D3DXDecodeBC3;   sbpp = 16;  break;\n    case DXGI_FORMAT_BC7_UNORM:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:    pfDecode = D3DXDecodeBC7;   sbpp = 16;  break;\n    default:\n        // BC4, BC5, and BC6 don't have alpha channels\n        return false;\n    }\n\n    // Scan blocks for non-opaque alpha\n    static const XMVECTORF32 threshold = { { { 0.99f, 0.99f, 0.99f, 0.99f } } };\n\n    XM_ALIGNED_DATA(16) XMVECTOR temp[16];\n    const uint8_t* pPixels = cImage.pixels;\n    for (size_t h = 0; h < cImage.height; h += 4)\n    {\n        const uint8_t* ptr = pPixels;\n        const size_t ph = std::min<size_t>(4, cImage.height - h);\n        size_t w = 0;\n        for (size_t count = 0; (count < cImage.rowPitch) && (w < cImage.width); count += sbpp, w += 4)\n        {\n            pfDecode(temp, ptr);\n\n            const size_t pw = std::min<size_t>(4, cImage.width - w);\n            assert(pw > 0 && ph > 0);\n\n            if (pw == 4 && ph == 4)\n            {\n                // Full blocks\n                for (size_t j = 0; j < 16; ++j)\n                {\n                    const XMVECTOR alpha = XMVectorSplatW(temp[j]);\n                    if (XMVector4Less(alpha, threshold))\n                        return false;\n                }\n            }\n            else\n            {\n                // Handle partial blocks\n                for (size_t y = 0; y < ph; ++y)\n                {\n                    for (size_t x = 0; x < pw; ++x)\n                    {\n                        const XMVECTOR alpha = XMVectorSplatW(temp[y * 4 + x]);\n                        if (XMVector4Less(alpha, threshold))\n                            return false;\n                    }\n                }\n            }\n\n            ptr += sbpp;\n        }\n\n        pPixels += cImage.rowPitch;\n    }\n\n    return true;\n}\n\n\n//=====================================================================================\n// Entry-points\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n// Compression\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::Compress(\n    const Image& srcImage,\n    DXGI_FORMAT format,\n    TEX_COMPRESS_FLAGS compress,\n    float threshold,\n    ScratchImage& image) noexcept\n{\n    if (IsCompressed(srcImage.format) || !IsCompressed(format))\n        return E_INVALIDARG;\n\n    if (IsTypeless(format)\n        || IsTypeless(srcImage.format) || IsPlanar(srcImage.format) || IsPalettized(srcImage.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    // Create compressed image\n    HRESULT hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1);\n    if (FAILED(hr))\n        return hr;\n\n    const Image *img = image.GetImage(0, 0, 0);\n    if (!img)\n    {\n        image.Release();\n        return E_POINTER;\n    }\n\n    // Compress single image\n    if (compress & TEX_COMPRESS_PARALLEL)\n    {\n    #ifndef _OPENMP\n        return E_NOTIMPL;\n    #else\n        hr = CompressBC_Parallel(srcImage, *img, GetBCFlags(compress), GetSRGBFlags(compress), threshold);\n    #endif // _OPENMP\n    }\n    else\n    {\n        hr = CompressBC(srcImage, *img, GetBCFlags(compress), GetSRGBFlags(compress), threshold);\n    }\n\n    if (FAILED(hr))\n        image.Release();\n\n    return hr;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::Compress(\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    DXGI_FORMAT format,\n    TEX_COMPRESS_FLAGS compress,\n    float threshold,\n    ScratchImage& cImages) noexcept\n{\n    if (!srcImages || !nimages)\n        return E_INVALIDARG;\n\n    if (IsCompressed(metadata.format) || !IsCompressed(format))\n        return E_INVALIDARG;\n\n    if (IsTypeless(format)\n        || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    cImages.Release();\n\n    TexMetadata mdata2 = metadata;\n    mdata2.format = format;\n    HRESULT hr = cImages.Initialize(mdata2);\n    if (FAILED(hr))\n        return hr;\n\n    if (nimages != cImages.GetImageCount())\n    {\n        cImages.Release();\n        return E_FAIL;\n    }\n\n    const Image* dest = cImages.GetImages();\n    if (!dest)\n    {\n        cImages.Release();\n        return E_POINTER;\n    }\n\n    for (size_t index = 0; index < nimages; ++index)\n    {\n        assert(dest[index].format == format);\n\n        const Image& src = srcImages[index];\n\n        if (src.width != dest[index].width || src.height != dest[index].height)\n        {\n            cImages.Release();\n            return E_FAIL;\n        }\n\n        if ((compress & TEX_COMPRESS_PARALLEL))\n        {\n        #ifndef _OPENMP\n            return E_NOTIMPL;\n        #else\n            if (compress & TEX_COMPRESS_PARALLEL)\n            {\n                hr = CompressBC_Parallel(src, dest[index], GetBCFlags(compress), GetSRGBFlags(compress), threshold);\n                if (FAILED(hr))\n                {\n                    cImages.Release();\n                    return  hr;\n                }\n            }\n        #endif // _OPENMP\n        }\n        else\n        {\n            hr = CompressBC(src, dest[index], GetBCFlags(compress), GetSRGBFlags(compress), threshold);\n            if (FAILED(hr))\n            {\n                cImages.Release();\n                return hr;\n            }\n        }\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Decompression\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::Decompress(\n    const Image& cImage,\n    DXGI_FORMAT format,\n    ScratchImage& image) noexcept\n{\n    if (!IsCompressed(cImage.format) || IsCompressed(format))\n        return E_INVALIDARG;\n\n    if (format == DXGI_FORMAT_UNKNOWN)\n    {\n        // Pick a default decompressed format based on BC input format\n        format = DefaultDecompress(cImage.format);\n        if (format == DXGI_FORMAT_UNKNOWN)\n        {\n            // Input is not a compressed format\n            return E_INVALIDARG;\n        }\n    }\n    else\n    {\n        if (!IsValid(format))\n            return E_INVALIDARG;\n\n        if (IsTypeless(format) || IsPlanar(format) || IsPalettized(format))\n            return HRESULT_E_NOT_SUPPORTED;\n    }\n\n    // Create decompressed image\n    HRESULT hr = image.Initialize2D(format, cImage.width, cImage.height, 1, 1);\n    if (FAILED(hr))\n        return hr;\n\n    const Image *img = image.GetImage(0, 0, 0);\n    if (!img)\n    {\n        image.Release();\n        return E_POINTER;\n    }\n\n    // Decompress single image\n    hr = DecompressBC(cImage, *img);\n    if (FAILED(hr))\n        image.Release();\n\n    return hr;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::Decompress(\n    const Image* cImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    DXGI_FORMAT format,\n    ScratchImage& images) noexcept\n{\n    if (!cImages || !nimages)\n        return E_INVALIDARG;\n\n    if (!IsCompressed(metadata.format) || IsCompressed(format))\n        return E_INVALIDARG;\n\n    if (format == DXGI_FORMAT_UNKNOWN)\n    {\n        // Pick a default decompressed format based on BC input format\n        format = DefaultDecompress(cImages[0].format);\n        if (format == DXGI_FORMAT_UNKNOWN)\n        {\n            // Input is not a compressed format\n            return E_FAIL;\n        }\n    }\n    else\n    {\n        if (!IsValid(format))\n            return E_INVALIDARG;\n\n        if (IsTypeless(format) || IsPlanar(format) || IsPalettized(format))\n            return HRESULT_E_NOT_SUPPORTED;\n    }\n\n    images.Release();\n\n    TexMetadata mdata2 = metadata;\n    mdata2.format = format;\n    HRESULT hr = images.Initialize(mdata2);\n    if (FAILED(hr))\n        return hr;\n\n    if (nimages != images.GetImageCount())\n    {\n        images.Release();\n        return E_FAIL;\n    }\n\n    const Image* dest = images.GetImages();\n    if (!dest)\n    {\n        images.Release();\n        return E_POINTER;\n    }\n\n    for (size_t index = 0; index < nimages; ++index)\n    {\n        assert(dest[index].format == format);\n\n        const Image& src = cImages[index];\n        if (!IsCompressed(src.format))\n        {\n            images.Release();\n            return E_FAIL;\n        }\n\n        if (src.width != dest[index].width || src.height != dest[index].height)\n        {\n            images.Release();\n            return E_FAIL;\n        }\n\n        hr = DecompressBC(src, dest[index]);\n        if (FAILED(hr))\n        {\n            images.Release();\n            return hr;\n        }\n    }\n\n    return S_OK;\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTexCompressGPU.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTexCompressGPU.cpp\n//\n// DirectX Texture Library - DirectCompute-based texture compression\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\n#include \"BCDirectCompute.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::Internal;\n\nnamespace\n{\n    constexpr TEX_FILTER_FLAGS GetSRGBFlags(_In_ TEX_COMPRESS_FLAGS compress) noexcept\n    {\n        static_assert(TEX_FILTER_SRGB_IN == 0x1000000, \"TEX_FILTER_SRGB flag values don't match TEX_FILTER_SRGB_MASK\");\n        static_assert(static_cast<int>(TEX_COMPRESS_SRGB_IN) == static_cast<int>(TEX_FILTER_SRGB_IN), \"TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*\");\n        static_assert(static_cast<int>(TEX_COMPRESS_SRGB_OUT) == static_cast<int>(TEX_FILTER_SRGB_OUT), \"TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*\");\n        static_assert(static_cast<int>(TEX_COMPRESS_SRGB) == static_cast<int>(TEX_FILTER_SRGB), \"TEX_COMPRESS_SRGB* should match TEX_FILTER_SRGB*\");\n        return static_cast<TEX_FILTER_FLAGS>(compress & TEX_FILTER_SRGB_MASK);\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    // Converts to R8G8B8A8_UNORM or R8G8B8A8_UNORM_SRGB doing any conversion logic needed\n    //-------------------------------------------------------------------------------------\n    HRESULT ConvertToRGBA32(\n        const Image& srcImage,\n        ScratchImage& image,\n        bool srgb,\n        TEX_FILTER_FLAGS filter) noexcept\n    {\n        if (!srcImage.pixels)\n            return E_POINTER;\n\n        const DXGI_FORMAT format = srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;\n\n        HRESULT hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1);\n        if (FAILED(hr))\n            return hr;\n\n        const Image *img = image.GetImage(0, 0, 0);\n        if (!img)\n        {\n            image.Release();\n            return E_POINTER;\n        }\n\n        uint8_t* pDest = img->pixels;\n        if (!pDest)\n        {\n            image.Release();\n            return E_POINTER;\n        }\n\n        auto scanline = make_AlignedArrayXMVECTOR(srcImage.width);\n        if (!scanline)\n        {\n            image.Release();\n            return E_OUTOFMEMORY;\n        }\n\n        const uint8_t *pSrc = srcImage.pixels;\n        for (size_t h = 0; h < srcImage.height; ++h)\n        {\n            if (!LoadScanline(scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format))\n            {\n                image.Release();\n                return E_FAIL;\n            }\n\n            ConvertScanline(scanline.get(), srcImage.width, format, srcImage.format, filter);\n\n            if (!StoreScanline(pDest, img->rowPitch, format, scanline.get(), srcImage.width))\n            {\n                image.Release();\n                return E_FAIL;\n            }\n\n            pSrc += srcImage.rowPitch;\n            pDest += img->rowPitch;\n        }\n\n        return S_OK;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    // Converts to DXGI_FORMAT_R32G32B32A32_FLOAT doing any conversion logic needed\n    //-------------------------------------------------------------------------------------\n    HRESULT ConvertToRGBAF32(\n        const Image& srcImage,\n        ScratchImage& image,\n        TEX_FILTER_FLAGS filter) noexcept\n    {\n        if (!srcImage.pixels)\n            return E_POINTER;\n\n        HRESULT hr = image.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1);\n        if (FAILED(hr))\n            return hr;\n\n        const Image *img = image.GetImage(0, 0, 0);\n        if (!img)\n        {\n            image.Release();\n            return E_POINTER;\n        }\n\n        uint8_t* pDest = img->pixels;\n        if (!pDest)\n        {\n            image.Release();\n            return E_POINTER;\n        }\n\n        const uint8_t *pSrc = srcImage.pixels;\n        for (size_t h = 0; h < srcImage.height; ++h)\n        {\n            if (!LoadScanline(reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format))\n            {\n                image.Release();\n                return E_FAIL;\n            }\n\n            ConvertScanline(reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.format, filter);\n\n            pSrc += srcImage.rowPitch;\n            pDest += img->rowPitch;\n        }\n\n        return S_OK;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    // Compress using GPU, converting to the proper input format for the shader if needed\n    //-------------------------------------------------------------------------------------\n    inline HRESULT GPUCompress(\n        _In_ GPUCompressBC* gpubc,\n        const Image& srcImage,\n        const Image& destImage,\n        TEX_COMPRESS_FLAGS compress)\n    {\n        if (!gpubc)\n            return E_POINTER;\n\n        assert(srcImage.pixels && destImage.pixels);\n\n        const DXGI_FORMAT format = gpubc->GetSourceFormat();\n\n        if (srcImage.format == format)\n        {\n            // Input is already in our required source format\n            return gpubc->Compress(srcImage, destImage);\n        }\n        else\n        {\n            // Convert format and then use as the source image\n            ScratchImage image;\n            HRESULT hr = E_UNEXPECTED;\n\n            auto const srgb = GetSRGBFlags(compress);\n\n            switch (format)\n            {\n            case DXGI_FORMAT_R8G8B8A8_UNORM:\n                hr = ConvertToRGBA32(srcImage, image, false, srgb);\n                break;\n\n            case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n                hr = ConvertToRGBA32(srcImage, image, true, srgb);\n                break;\n\n            case DXGI_FORMAT_R32G32B32A32_FLOAT:\n                hr = ConvertToRGBAF32(srcImage, image, srgb);\n                break;\n\n            default:\n                break;\n            }\n\n            if (FAILED(hr))\n                return hr;\n\n            const Image *img = image.GetImage(0, 0, 0);\n            if (!img)\n                return E_POINTER;\n\n            return gpubc->Compress(*img, destImage);\n        }\n    }\n};\n\n//=====================================================================================\n// Entry-points\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n// Compression\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::Compress(\n    ID3D11Device* pDevice,\n    const Image& srcImage,\n    DXGI_FORMAT format,\n    TEX_COMPRESS_FLAGS compress,\n    float alphaWeight,\n    ScratchImage& image) noexcept\n{\n    if (!pDevice || IsCompressed(srcImage.format) || !IsCompressed(format))\n        return E_INVALIDARG;\n\n    if (IsTypeless(format)\n        || IsTypeless(srcImage.format) || IsPlanar(srcImage.format) || IsPalettized(srcImage.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    // Setup GPU compressor\n    std::unique_ptr<GPUCompressBC> gpubc(new (std::nothrow) GPUCompressBC);\n    if (!gpubc)\n        return E_OUTOFMEMORY;\n\n    HRESULT hr = gpubc->Initialize(pDevice);\n    if (FAILED(hr))\n        return hr;\n\n    hr = gpubc->Prepare(srcImage.width, srcImage.height, compress, format, alphaWeight);\n    if (FAILED(hr))\n        return hr;\n\n    // Create workspace for result\n    hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1);\n    if (FAILED(hr))\n        return hr;\n\n    const Image *img = image.GetImage(0, 0, 0);\n    if (!img)\n    {\n        image.Release();\n        return E_POINTER;\n    }\n\n    hr = GPUCompress(gpubc.get(), srcImage, *img, compress);\n    if (FAILED(hr))\n        image.Release();\n\n    return hr;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::Compress(\n    ID3D11Device* pDevice,\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    DXGI_FORMAT format,\n    TEX_COMPRESS_FLAGS compress,\n    float alphaWeight,\n    ScratchImage& cImages) noexcept\n{\n    if (!pDevice || !srcImages || !nimages)\n        return E_INVALIDARG;\n\n    if (IsCompressed(metadata.format) || !IsCompressed(format))\n        return E_INVALIDARG;\n\n    if (IsTypeless(format)\n        || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    cImages.Release();\n\n    // Setup GPU compressor\n    std::unique_ptr<GPUCompressBC> gpubc(new (std::nothrow) GPUCompressBC);\n    if (!gpubc)\n        return E_OUTOFMEMORY;\n\n    HRESULT hr = gpubc->Initialize(pDevice);\n    if (FAILED(hr))\n        return hr;\n\n    // Create workspace for result\n    TexMetadata mdata2 = metadata;\n    mdata2.format = format;\n    hr = cImages.Initialize(mdata2);\n    if (FAILED(hr))\n        return hr;\n\n    if (nimages != cImages.GetImageCount())\n    {\n        cImages.Release();\n        return E_FAIL;\n    }\n\n    const Image* dest = cImages.GetImages();\n    if (!dest)\n    {\n        cImages.Release();\n        return E_POINTER;\n    }\n\n    // Process images (ordered by size)\n    switch (metadata.dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n    case TEX_DIMENSION_TEXTURE2D:\n        {\n            size_t w = metadata.width;\n            size_t h = metadata.height;\n\n            for (size_t level = 0; level < metadata.mipLevels; ++level)\n            {\n                hr = gpubc->Prepare(w, h, compress, format, alphaWeight);\n                if (FAILED(hr))\n                {\n                    cImages.Release();\n                    return hr;\n                }\n\n                for (size_t item = 0; item < metadata.arraySize; ++item)\n                {\n                    const size_t index = metadata.ComputeIndex(level, item, 0);\n                    if (index >= nimages)\n                    {\n                        cImages.Release();\n                        return E_FAIL;\n                    }\n\n                    assert(dest[index].format == format);\n\n                    const Image& src = srcImages[index];\n\n                    if (src.width != dest[index].width || src.height != dest[index].height)\n                    {\n                        cImages.Release();\n                        return E_FAIL;\n                    }\n\n                    hr = GPUCompress(gpubc.get(), src, dest[index], compress);\n                    if (FAILED(hr))\n                    {\n                        cImages.Release();\n                        return hr;\n                    }\n                }\n\n                if (h > 1)\n                    h >>= 1;\n\n                if (w > 1)\n                    w >>= 1;\n            }\n        }\n        break;\n\n    case TEX_DIMENSION_TEXTURE3D:\n        {\n            size_t w = metadata.width;\n            size_t h = metadata.height;\n            size_t d = metadata.depth;\n\n            for (size_t level = 0; level < metadata.mipLevels; ++level)\n            {\n                hr = gpubc->Prepare(w, h, compress, format, alphaWeight);\n                if (FAILED(hr))\n                {\n                    cImages.Release();\n                    return hr;\n                }\n\n                for (size_t slice = 0; slice < d; ++slice)\n                {\n                    const size_t index = metadata.ComputeIndex(level, 0, slice);\n                    if (index >= nimages)\n                    {\n                        cImages.Release();\n                        return E_FAIL;\n                    }\n\n                    assert(dest[index].format == format);\n\n                    const Image& src = srcImages[index];\n\n                    if (src.width != dest[index].width || src.height != dest[index].height)\n                    {\n                        cImages.Release();\n                        return E_FAIL;\n                    }\n\n                    hr = GPUCompress(gpubc.get(), src, dest[index], compress);\n                    if (FAILED(hr))\n                    {\n                        cImages.Release();\n                        return hr;\n                    }\n                }\n\n                if (h > 1)\n                    h >>= 1;\n\n                if (w > 1)\n                    w >>= 1;\n\n                if (d > 1)\n                    d >>= 1;\n            }\n        }\n        break;\n\n    default:\n        return HRESULT_E_NOT_SUPPORTED;\n    }\n\n    return S_OK;\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTexConvert.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTexConvert.cpp\n//\n// DirectX Texture Library - Image pixel format conversion\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::Internal;\nusing namespace DirectX::PackedVector;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    inline uint32_t FloatTo7e3(float Value) noexcept\n    {\n        uint32_t IValue = reinterpret_cast<uint32_t *>(&Value)[0];\n\n        if (IValue & 0x80000000U)\n        {\n            // Positive only\n            return 0;\n        }\n        else if (IValue > 0x41FF73FFU)\n        {\n            // The number is too large to be represented as a 7e3. Saturate.\n            return 0x3FFU;\n        }\n        else\n        {\n            if (IValue < 0x3E800000U)\n            {\n                // The number is too small to be represented as a normalized 7e3.\n                // Convert it to a denormalized value.\n                const uint32_t Shift = std::min<uint32_t>(125U - (IValue >> 23U), 24U);\n                IValue = (0x800000U | (IValue & 0x7FFFFFU)) >> Shift;\n            }\n            else\n            {\n                // Rebias the exponent to represent the value as a normalized 7e3.\n                IValue += 0xC2000000U;\n            }\n\n            return ((IValue + 0x7FFFU + ((IValue >> 16U) & 1U)) >> 16U) & 0x3FFU;\n        }\n    }\n\n    inline float FloatFrom7e3(uint32_t Value) noexcept\n    {\n        auto Mantissa = static_cast<uint32_t>(Value & 0x7F);\n\n        uint32_t Exponent = (Value & 0x380);\n        if (Exponent != 0)  // The value is normalized\n        {\n            Exponent = static_cast<uint32_t>((Value >> 7) & 0x7);\n        }\n        else if (Mantissa != 0)     // The value is denormalized\n        {\n            // Normalize the value in the resulting float\n            Exponent = 1;\n\n            do\n            {\n                Exponent--;\n                Mantissa <<= 1;\n            }\n            while ((Mantissa & 0x80) == 0);\n\n            Mantissa &= 0x7F;\n        }\n        else                        // The value is zero\n        {\n            Exponent = uint32_t(-124);\n        }\n\n        const uint32_t Result = ((Exponent + 124) << 23) | // Exponent\n            (Mantissa << 16);          // Mantissa\n\n        return reinterpret_cast<const float*>(&Result)[0];\n    }\n\n    inline uint32_t FloatTo6e4(float Value) noexcept\n    {\n        uint32_t IValue = reinterpret_cast<uint32_t *>(&Value)[0];\n\n        if (IValue & 0x80000000U)\n        {\n            // Positive only\n            return 0;\n        }\n        else if (IValue > 0x43FEFFFFU)\n        {\n            // The number is too large to be represented as a 6e4. Saturate.\n            return 0x3FFU;\n        }\n        else\n        {\n            if (IValue < 0x3C800000U)\n            {\n                // The number is too small to be represented as a normalized 6e4.\n                // Convert it to a denormalized value.\n                const uint32_t Shift = std::min<uint32_t>(121U - (IValue >> 23U), 24U);\n                IValue = (0x800000U | (IValue & 0x7FFFFFU)) >> Shift;\n            }\n            else\n            {\n                // Rebias the exponent to represent the value as a normalized 6e4.\n                IValue += 0xC4000000U;\n            }\n\n            return ((IValue + 0xFFFFU + ((IValue >> 17U) & 1U)) >> 17U) & 0x3FFU;\n        }\n    }\n\n    inline float FloatFrom6e4(uint32_t Value) noexcept\n    {\n        uint32_t Mantissa = static_cast<uint32_t>(Value & 0x3F);\n\n        uint32_t Exponent = (Value & 0x3C0);\n        if (Exponent != 0)  // The value is normalized\n        {\n            Exponent = static_cast<uint32_t>((Value >> 6) & 0xF);\n        }\n        else if (Mantissa != 0)     // The value is denormalized\n        {\n            // Normalize the value in the resulting float\n            Exponent = 1;\n\n            do\n            {\n                Exponent--;\n                Mantissa <<= 1;\n            }\n            while ((Mantissa & 0x40) == 0);\n\n            Mantissa &= 0x3F;\n        }\n        else                        // The value is zero\n        {\n            Exponent = uint32_t(-120);\n        }\n\n        const uint32_t Result = ((Exponent + 120) << 23) | // Exponent\n            (Mantissa << 17);          // Mantissa\n\n        return reinterpret_cast<const float*>(&Result)[0];\n    }\n\n#if DIRECTX_MATH_VERSION >= 310\n#define StoreFloat3SE XMStoreFloat3SE\n#else\n    inline void XM_CALLCONV StoreFloat3SE(_Out_ XMFLOAT3SE* pDestination, DirectX::FXMVECTOR V)\n    {\n        assert(pDestination);\n\n        DirectX::XMFLOAT3A tmp;\n        DirectX::XMStoreFloat3A(&tmp, V);\n\n        constexpr float maxf9 = float(0x1FF << 7);\n        constexpr float minf9 = float(1.f / (1 << 16));\n\n        float x = (tmp.x >= 0.f) ? ((tmp.x > maxf9) ? maxf9 : tmp.x) : 0.f;\n        float y = (tmp.y >= 0.f) ? ((tmp.y > maxf9) ? maxf9 : tmp.y) : 0.f;\n        float z = (tmp.z >= 0.f) ? ((tmp.z > maxf9) ? maxf9 : tmp.z) : 0.f;\n\n        const float max_xy = (x > y) ? x : y;\n        const float max_xyz = (max_xy > z) ? max_xy : z;\n\n        const float maxColor = (max_xyz > minf9) ? max_xyz : minf9;\n\n        union { float f; int32_t i; } fi;\n        fi.f = maxColor;\n        fi.i += 0x00004000; // round up leaving 9 bits in fraction (including assumed 1)\n\n        // Fix applied from DirectXMath 3.10\n        uint32_t exp = fi.i >> 23;\n        pDestination->e = exp - 0x6f;\n\n        fi.i = 0x83000000 - (exp << 23);\n        float ScaleR = fi.f;\n\n        pDestination->xm = static_cast<uint32_t>(lroundf(x * ScaleR));\n        pDestination->ym = static_cast<uint32_t>(lroundf(y * ScaleR));\n        pDestination->zm = static_cast<uint32_t>(lroundf(z * ScaleR));\n    }\n#endif\n\n    const XMVECTORF32 g_Grayscale = { { { 0.2125f, 0.7154f, 0.0721f, 0.0f } } };\n    const XMVECTORF32 g_HalfMin = { { { -65504.f, -65504.f, -65504.f, -65504.f } } };\n    const XMVECTORF32 g_HalfMax = { { { 65504.f, 65504.f, 65504.f, 65504.f } } };\n    const XMVECTORF32 g_8BitBias = { { { 0.5f / 255.f, 0.5f / 255.f, 0.5f / 255.f, 0.5f / 255.f } } };\n}\n\n//-------------------------------------------------------------------------------------\n// Copies an image row with optional clearing of alpha value to 1.0\n// (can be used in place as well) otherwise copies the image row unmodified.\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nvoid DirectX::Internal::CopyScanline(\n    void* pDestination,\n    size_t outSize,\n    const void* pSource,\n    size_t inSize,\n    DXGI_FORMAT format,\n    uint32_t tflags) noexcept\n{\n    assert(pDestination && outSize > 0);\n    assert(pSource && inSize > 0);\n    assert(IsValid(format) && !IsPalettized(format));\n\n    if (tflags & TEXP_SCANLINE_SETALPHA)\n    {\n        switch (static_cast<int>(format))\n        {\n            //-----------------------------------------------------------------------------\n        case DXGI_FORMAT_R32G32B32A32_TYPELESS:\n        case DXGI_FORMAT_R32G32B32A32_FLOAT:\n        case DXGI_FORMAT_R32G32B32A32_UINT:\n        case DXGI_FORMAT_R32G32B32A32_SINT:\n            if (inSize >= 16 && outSize >= 16)\n            {\n                uint32_t alpha;\n                if (format == DXGI_FORMAT_R32G32B32A32_FLOAT)\n                    alpha = 0x3f800000;\n                else if (format == DXGI_FORMAT_R32G32B32A32_SINT)\n                    alpha = 0x7fffffff;\n                else\n                    alpha = 0xffffffff;\n\n                if (pDestination == pSource)\n                {\n                    auto dPtr = static_cast<uint32_t*>(pDestination);\n                    for (size_t count = 0; count < (outSize - 15); count += 16)\n                    {\n                        dPtr += 3;\n                        *(dPtr++) = alpha;\n                    }\n                }\n                else\n                {\n                    const uint32_t * __restrict sPtr = static_cast<const uint32_t*>(pSource);\n                    uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n                    const size_t size = std::min<size_t>(outSize, inSize);\n                    for (size_t count = 0; count < (size - 15); count += 16)\n                    {\n                        *(dPtr++) = *(sPtr++);\n                        *(dPtr++) = *(sPtr++);\n                        *(dPtr++) = *(sPtr++);\n                        *(dPtr++) = alpha;\n                        ++sPtr;\n                    }\n                }\n            }\n            return;\n\n            //-----------------------------------------------------------------------------\n        case DXGI_FORMAT_R16G16B16A16_TYPELESS:\n        case DXGI_FORMAT_R16G16B16A16_FLOAT:\n        case DXGI_FORMAT_R16G16B16A16_UNORM:\n        case DXGI_FORMAT_R16G16B16A16_UINT:\n        case DXGI_FORMAT_R16G16B16A16_SNORM:\n        case DXGI_FORMAT_R16G16B16A16_SINT:\n        case DXGI_FORMAT_Y416:\n            if (inSize >= 8 && outSize >= 8)\n            {\n                uint16_t alpha;\n                if (format == DXGI_FORMAT_R16G16B16A16_FLOAT)\n                    alpha = 0x3c00;\n                else if (format == DXGI_FORMAT_R16G16B16A16_SNORM || format == DXGI_FORMAT_R16G16B16A16_SINT)\n                    alpha = 0x7fff;\n                else\n                    alpha = 0xffff;\n\n                if (pDestination == pSource)\n                {\n                    auto dPtr = static_cast<uint16_t*>(pDestination);\n                    for (size_t count = 0; count < (outSize - 7); count += 8)\n                    {\n                        dPtr += 3;\n                        *(dPtr++) = alpha;\n                    }\n                }\n                else\n                {\n                    const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);\n                    uint16_t * __restrict dPtr = static_cast<uint16_t*>(pDestination);\n                    const size_t size = std::min<size_t>(outSize, inSize);\n                    for (size_t count = 0; count < (size - 7); count += 8)\n                    {\n                        *(dPtr++) = *(sPtr++);\n                        *(dPtr++) = *(sPtr++);\n                        *(dPtr++) = *(sPtr++);\n                        *(dPtr++) = alpha;\n                        ++sPtr;\n                    }\n                }\n            }\n            return;\n\n            //-----------------------------------------------------------------------------\n        case DXGI_FORMAT_R10G10B10A2_TYPELESS:\n        case DXGI_FORMAT_R10G10B10A2_UNORM:\n        case DXGI_FORMAT_R10G10B10A2_UINT:\n        case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:\n        case DXGI_FORMAT_Y410:\n        case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT:\n        case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT:\n        case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:\n            if (inSize >= 4 && outSize >= 4)\n            {\n                if (pDestination == pSource)\n                {\n                    auto dPtr = static_cast<uint32_t*>(pDestination);\n                    for (size_t count = 0; count < (outSize - 3); count += 4)\n                    {\n                        *dPtr |= 0xC0000000;\n                        ++dPtr;\n                    }\n                }\n                else\n                {\n                    const uint32_t * __restrict sPtr = static_cast<const uint32_t*>(pSource);\n                    uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n                    const size_t size = std::min<size_t>(outSize, inSize);\n                    for (size_t count = 0; count < (size - 3); count += 4)\n                    {\n                        *(dPtr++) = *(sPtr++) | 0xC0000000;\n                    }\n                }\n            }\n            return;\n\n            //-----------------------------------------------------------------------------\n        case DXGI_FORMAT_R8G8B8A8_TYPELESS:\n        case DXGI_FORMAT_R8G8B8A8_UNORM:\n        case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n        case DXGI_FORMAT_R8G8B8A8_UINT:\n        case DXGI_FORMAT_R8G8B8A8_SNORM:\n        case DXGI_FORMAT_R8G8B8A8_SINT:\n        case DXGI_FORMAT_B8G8R8A8_UNORM:\n        case DXGI_FORMAT_B8G8R8A8_TYPELESS:\n        case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n        case DXGI_FORMAT_AYUV:\n            if (inSize >= 4 && outSize >= 4)\n            {\n                const uint32_t alpha = (format == DXGI_FORMAT_R8G8B8A8_SNORM || format == DXGI_FORMAT_R8G8B8A8_SINT) ? 0x7f000000 : 0xff000000;\n\n                if (pDestination == pSource)\n                {\n                    auto dPtr = static_cast<uint32_t*>(pDestination);\n                    for (size_t count = 0; count < (outSize - 3); count += 4)\n                    {\n                        uint32_t t = *dPtr & 0xFFFFFF;\n                        t |= alpha;\n                        *(dPtr++) = t;\n                    }\n                }\n                else\n                {\n                    const uint32_t * __restrict sPtr = static_cast<const uint32_t*>(pSource);\n                    uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n                    const size_t size = std::min<size_t>(outSize, inSize);\n                    for (size_t count = 0; count < (size - 3); count += 4)\n                    {\n                        uint32_t t = *(sPtr++) & 0xFFFFFF;\n                        t |= alpha;\n                        *(dPtr++) = t;\n                    }\n                }\n            }\n            return;\n\n            //-----------------------------------------------------------------------------\n        case DXGI_FORMAT_B5G5R5A1_UNORM:\n            if (inSize >= 2 && outSize >= 2)\n            {\n                if (pDestination == pSource)\n                {\n                    auto dPtr = static_cast<uint16_t*>(pDestination);\n                    for (size_t count = 0; count < (outSize - 1); count += 2)\n                    {\n                        *(dPtr++) |= 0x8000;\n                    }\n                }\n                else\n                {\n                    const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);\n                    uint16_t * __restrict dPtr = static_cast<uint16_t*>(pDestination);\n                    const size_t size = std::min<size_t>(outSize, inSize);\n                    for (size_t count = 0; count < (size - 1); count += 2)\n                    {\n                        *(dPtr++) = uint16_t(*(sPtr++) | 0x8000);\n                    }\n                }\n            }\n            return;\n\n            //-----------------------------------------------------------------------------\n        case DXGI_FORMAT_A8_UNORM:\n            memset(pDestination, 0xff, outSize);\n            return;\n\n            //-----------------------------------------------------------------------------\n        case DXGI_FORMAT_B4G4R4A4_UNORM:\n            if (inSize >= 2 && outSize >= 2)\n            {\n                if (pDestination == pSource)\n                {\n                    auto dPtr = static_cast<uint16_t*>(pDestination);\n                    for (size_t count = 0; count < (outSize - 1); count += 2)\n                    {\n                        *(dPtr++) |= 0xF000;\n                    }\n                }\n                else\n                {\n                    const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);\n                    uint16_t * __restrict dPtr = static_cast<uint16_t*>(pDestination);\n                    const size_t size = std::min<size_t>(outSize, inSize);\n                    for (size_t count = 0; count < (size - 1); count += 2)\n                    {\n                        *(dPtr++) = uint16_t(*(sPtr++) | 0xF000);\n                    }\n                }\n            }\n            return;\n        }\n    }\n\n    // Fall-through case is to just use memcpy (assuming this is not an in-place operation)\n    if (pDestination == pSource)\n        return;\n\n    const size_t size = std::min<size_t>(outSize, inSize);\n    memcpy(pDestination, pSource, size);\n}\n\n\n//-------------------------------------------------------------------------------------\n// Swizzles (RGB <-> BGR) an image row with optional clearing of alpha value to 1.0\n// (can be used in place as well) otherwise copies the image row unmodified.\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nvoid DirectX::Internal::SwizzleScanline(\n    void* pDestination,\n    size_t outSize,\n    const void* pSource,\n    size_t inSize,\n    DXGI_FORMAT format,\n    uint32_t tflags) noexcept\n{\n    assert(pDestination && outSize > 0);\n    assert(pSource && inSize > 0);\n    assert(IsValid(format) && !IsPlanar(format) && !IsPalettized(format));\n\n    switch (static_cast<int>(format))\n    {\n        //---------------------------------------------------------------------------------\n    case DXGI_FORMAT_R10G10B10A2_TYPELESS:\n    case DXGI_FORMAT_R10G10B10A2_UNORM:\n    case DXGI_FORMAT_R10G10B10A2_UINT:\n    case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:\n    case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:\n        if (inSize >= 4 && outSize >= 4)\n        {\n            if (tflags & TEXP_SCANLINE_LEGACY)\n            {\n                // Swap Red (R) and Blue (B) channel (used for D3DFMT_A2R10G10B10 legacy sources)\n                if (pDestination == pSource)\n                {\n                    auto dPtr = static_cast<uint32_t*>(pDestination);\n                    for (size_t count = 0; count < (outSize - 3); count += 4)\n                    {\n                        const uint32_t t = *dPtr;\n\n                        uint32_t t1 = (t & 0x3ff00000) >> 20;\n                        uint32_t t2 = (t & 0x000003ff) << 20;\n                        uint32_t t3 = (t & 0x000ffc00);\n                        uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xC0000000 : (t & 0xC0000000);\n\n                        *(dPtr++) = t1 | t2 | t3 | ta;\n                    }\n                }\n                else\n                {\n                    const uint32_t * __restrict sPtr = static_cast<const uint32_t*>(pSource);\n                    uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n                    const size_t size = std::min<size_t>(outSize, inSize);\n                    for (size_t count = 0; count < (size - 3); count += 4)\n                    {\n                        const uint32_t t = *(sPtr++);\n\n                        uint32_t t1 = (t & 0x3ff00000) >> 20;\n                        uint32_t t2 = (t & 0x000003ff) << 20;\n                        uint32_t t3 = (t & 0x000ffc00);\n                        uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xC0000000 : (t & 0xC0000000);\n\n                        *(dPtr++) = t1 | t2 | t3 | ta;\n                    }\n                }\n                return;\n            }\n        }\n        break;\n\n        //---------------------------------------------------------------------------------\n    case DXGI_FORMAT_R8G8B8A8_TYPELESS:\n    case DXGI_FORMAT_R8G8B8A8_UNORM:\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8A8_UNORM:\n    case DXGI_FORMAT_B8G8R8X8_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_TYPELESS:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8X8_TYPELESS:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n        if (inSize >= 4 && outSize >= 4)\n        {\n            // Swap Red (R) and Blue (B) channels (used to convert from DXGI 1.1 BGR formats to DXGI 1.0 RGB)\n            if (pDestination == pSource)\n            {\n                auto dPtr = static_cast<uint32_t*>(pDestination);\n                for (size_t count = 0; count < (outSize - 3); count += 4)\n                {\n                    const uint32_t t = *dPtr;\n\n                    uint32_t t1 = (t & 0x00ff0000) >> 16;\n                    uint32_t t2 = (t & 0x000000ff) << 16;\n                    uint32_t t3 = (t & 0x0000ff00);\n                    uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : (t & 0xFF000000);\n\n                    *(dPtr++) = t1 | t2 | t3 | ta;\n                }\n            }\n            else\n            {\n                const uint32_t * __restrict sPtr = static_cast<const uint32_t*>(pSource);\n                uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n                const size_t size = std::min<size_t>(outSize, inSize);\n                for (size_t count = 0; count < (size - 3); count += 4)\n                {\n                    const uint32_t t = *(sPtr++);\n\n                    uint32_t t1 = (t & 0x00ff0000) >> 16;\n                    uint32_t t2 = (t & 0x000000ff) << 16;\n                    uint32_t t3 = (t & 0x0000ff00);\n                    uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : (t & 0xFF000000);\n\n                    *(dPtr++) = t1 | t2 | t3 | ta;\n                }\n            }\n            return;\n        }\n        break;\n\n        //---------------------------------------------------------------------------------\n    case DXGI_FORMAT_YUY2:\n        if (inSize >= 4 && outSize >= 4)\n        {\n            if (tflags & TEXP_SCANLINE_LEGACY)\n            {\n                // Reorder YUV components (used to convert legacy UYVY -> YUY2)\n                if (pDestination == pSource)\n                {\n                    auto dPtr = static_cast<uint32_t*>(pDestination);\n                    for (size_t count = 0; count < (outSize - 3); count += 4)\n                    {\n                        const uint32_t t = *dPtr;\n\n                        uint32_t t1 = (t & 0x000000ff) << 8;\n                        uint32_t t2 = (t & 0x0000ff00) >> 8;\n                        uint32_t t3 = (t & 0x00ff0000) << 8;\n                        uint32_t t4 = (t & 0xff000000) >> 8;\n\n                        *(dPtr++) = t1 | t2 | t3 | t4;\n                    }\n                }\n                else\n                {\n                    const uint32_t * __restrict sPtr = static_cast<const uint32_t*>(pSource);\n                    uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n                    const size_t size = std::min<size_t>(outSize, inSize);\n                    for (size_t count = 0; count < (size - 3); count += 4)\n                    {\n                        const uint32_t t = *(sPtr++);\n\n                        uint32_t t1 = (t & 0x000000ff) << 8;\n                        uint32_t t2 = (t & 0x0000ff00) >> 8;\n                        uint32_t t3 = (t & 0x00ff0000) << 8;\n                        uint32_t t4 = (t & 0xff000000) >> 8;\n\n                        *(dPtr++) = t1 | t2 | t3 | t4;\n                    }\n                }\n                return;\n            }\n        }\n        break;\n    }\n\n    // Fall-through case is to just use memcpy (assuming this is not an in-place operation)\n    if (pDestination == pSource)\n        return;\n\n    const size_t size = std::min<size_t>(outSize, inSize);\n    memcpy(pDestination, pSource, size);\n}\n\n\n//-------------------------------------------------------------------------------------\n// Converts an image row with optional clearing of alpha value to 1.0\n// Returns true if supported, false if expansion case not supported\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nbool DirectX::Internal::ExpandScanline(\n    void* pDestination,\n    size_t outSize,\n    DXGI_FORMAT outFormat,\n    const void* pSource,\n    size_t inSize,\n    DXGI_FORMAT inFormat,\n    uint32_t tflags) noexcept\n{\n    assert(pDestination && outSize > 0);\n    assert(pSource && inSize > 0);\n    assert(IsValid(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat));\n    assert(IsValid(inFormat) && !IsPlanar(inFormat) && !IsPalettized(inFormat));\n\n    switch (inFormat)\n    {\n    case DXGI_FORMAT_B5G6R5_UNORM:\n        if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)\n            return false;\n\n        // DXGI_FORMAT_B5G6R5_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM\n        if (inSize >= 2 && outSize >= 4)\n        {\n            const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);\n            uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n\n            for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4)\n            {\n                const uint16_t t = *(sPtr++);\n\n                uint32_t t1 = uint32_t(((t & 0xf800) >> 8) | ((t & 0xe000) >> 13));\n                uint32_t t2 = uint32_t(((t & 0x07e0) << 5) | ((t & 0x0600) >> 5));\n                uint32_t t3 = uint32_t(((t & 0x001f) << 19) | ((t & 0x001c) << 14));\n\n                *(dPtr++) = t1 | t2 | t3 | 0xff000000;\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B5G5R5A1_UNORM:\n        if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)\n            return false;\n\n        // DXGI_FORMAT_B5G5R5A1_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM\n        if (inSize >= 2 && outSize >= 4)\n        {\n            const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);\n            uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n\n            for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4)\n            {\n                const uint16_t t = *(sPtr++);\n\n                uint32_t t1 = uint32_t(((t & 0x7c00) >> 7) | ((t & 0x7000) >> 12));\n                uint32_t t2 = uint32_t(((t & 0x03e0) << 6) | ((t & 0x0380) << 1));\n                uint32_t t3 = uint32_t(((t & 0x001f) << 19) | ((t & 0x001c) << 14));\n                uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : ((t & 0x8000) ? 0xff000000 : 0);\n\n                *(dPtr++) = t1 | t2 | t3 | ta;\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B4G4R4A4_UNORM:\n        if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)\n            return false;\n\n        // DXGI_FORMAT_B4G4R4A4_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM\n        if (inSize >= 2 && outSize >= 4)\n        {\n            const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);\n            uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n\n            for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4)\n            {\n                const uint16_t t = *(sPtr++);\n\n                uint32_t t1 = uint32_t(((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8));\n                uint32_t t2 = uint32_t(((t & 0x00f0) << 8) | ((t & 0x00f0) << 4));\n                uint32_t t3 = uint32_t(((t & 0x000f) << 20) | ((t & 0x000f) << 16));\n                uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : uint32_t(((t & 0xf000) << 16) | ((t & 0xf000) << 12));\n\n                *(dPtr++) = t1 | t2 | t3 | ta;\n            }\n            return true;\n        }\n        return false;\n\n    default:\n        return false;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// Loads an image row into standard RGBA XMVECTOR (aligned) array\n//-------------------------------------------------------------------------------------\n#define LOAD_SCANLINE( type, func )\\\n        if (size >= sizeof(type))\\\n        {\\\n            const type * __restrict sPtr = reinterpret_cast<const type*>(pSource);\\\n            for(size_t icount = 0; icount < (size - sizeof(type) + 1); icount += sizeof(type))\\\n            {\\\n                if (dPtr >= ePtr) break;\\\n                *(dPtr++) = func(sPtr++);\\\n            }\\\n            return true;\\\n        }\\\n        return false;\n\n#define LOAD_SCANLINE3( type, func, defvec )\\\n        if (size >= sizeof(type))\\\n        {\\\n            const type * __restrict sPtr = reinterpret_cast<const type*>(pSource);\\\n            for(size_t icount = 0; icount < (size - sizeof(type) + 1); icount += sizeof(type))\\\n            {\\\n                const XMVECTOR v = func(sPtr++);\\\n                if (dPtr >= ePtr) break;\\\n                *(dPtr++) = XMVectorSelect(defvec, v, g_XMSelect1110);\\\n            }\\\n            return true;\\\n        }\\\n        return false;\n\n#define LOAD_SCANLINE2( type, func, defvec )\\\n        if (size >= sizeof(type))\\\n        {\\\n            const type * __restrict sPtr = reinterpret_cast<const type*>(pSource);\\\n            for(size_t icount = 0; icount < (size - sizeof(type) + 1); icount += sizeof(type))\\\n            {\\\n                const XMVECTOR v = func(sPtr++);\\\n                if (dPtr >= ePtr) break;\\\n                *(dPtr++) = XMVectorSelect(defvec, v, g_XMSelect1100);\\\n            }\\\n            return true;\\\n        }\\\n        return false;\n\n#pragma warning(suppress: 6101)\n_Use_decl_annotations_ bool DirectX::Internal::LoadScanline(\n    XMVECTOR* pDestination,\n    size_t count,\n    const void* pSource,\n    size_t size,\n    DXGI_FORMAT format) noexcept\n{\n    assert(pDestination && count > 0 && ((reinterpret_cast<uintptr_t>(pDestination) & 0xF) == 0));\n    assert(pSource && size > 0);\n    assert(IsValid(format) && !IsTypeless(format, false) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format));\n\n    XMVECTOR* __restrict dPtr = pDestination;\n    if (!dPtr)\n        return false;\n\n    const XMVECTOR* ePtr = pDestination + count;\n\n    switch (static_cast<int>(format))\n    {\n    case DXGI_FORMAT_R32G32B32A32_FLOAT:\n        {\n            const size_t msize = (size > (sizeof(XMVECTOR)*count)) ? (sizeof(XMVECTOR)*count) : size;\n            memcpy(dPtr, pSource, msize);\n        }\n        return true;\n\n    case DXGI_FORMAT_R32G32B32A32_UINT:\n        LOAD_SCANLINE(XMUINT4, XMLoadUInt4)\n\n    case DXGI_FORMAT_R32G32B32A32_SINT:\n        LOAD_SCANLINE(XMINT4, XMLoadSInt4)\n\n    case DXGI_FORMAT_R32G32B32_FLOAT:\n        LOAD_SCANLINE3(XMFLOAT3, XMLoadFloat3, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R32G32B32_UINT:\n        LOAD_SCANLINE3(XMUINT3, XMLoadUInt3, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R32G32B32_SINT:\n        LOAD_SCANLINE3(XMINT3, XMLoadSInt3, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R16G16B16A16_FLOAT:\n        LOAD_SCANLINE(XMHALF4, XMLoadHalf4)\n\n    case DXGI_FORMAT_R16G16B16A16_UNORM:\n        LOAD_SCANLINE(XMUSHORTN4, XMLoadUShortN4)\n\n    case DXGI_FORMAT_R16G16B16A16_UINT:\n        LOAD_SCANLINE(XMUSHORT4, XMLoadUShort4)\n\n    case DXGI_FORMAT_R16G16B16A16_SNORM:\n        LOAD_SCANLINE(XMSHORTN4, XMLoadShortN4)\n\n    case DXGI_FORMAT_R16G16B16A16_SINT:\n        LOAD_SCANLINE(XMSHORT4, XMLoadShort4)\n\n    case DXGI_FORMAT_R32G32_FLOAT:\n        LOAD_SCANLINE2(XMFLOAT2, XMLoadFloat2, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R32G32_UINT:\n        LOAD_SCANLINE2(XMUINT2, XMLoadUInt2, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R32G32_SINT:\n        LOAD_SCANLINE2(XMINT2, XMLoadSInt2, g_XMIdentityR3)\n\n    case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:\n            {\n                constexpr size_t psize = sizeof(float) + sizeof(uint32_t);\n                if (size >= psize)\n                {\n                    auto sPtr = static_cast<const float*>(pSource);\n                    for (size_t icount = 0; icount < (size - psize + 1); icount += psize)\n                    {\n                        auto ps8 = reinterpret_cast<const uint8_t*>(&sPtr[1]);\n                        if (dPtr >= ePtr) break;\n                        *(dPtr++) = XMVectorSet(sPtr[0], static_cast<float>(*ps8), 0.f, 1.f);\n                        sPtr += 2;\n                    }\n                    return true;\n                }\n            }\n            return false;\n\n    case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:\n        {\n            constexpr size_t psize = sizeof(float) + sizeof(uint32_t);\n            if (size >= psize)\n            {\n                auto sPtr = static_cast<const float*>(pSource);\n                for (size_t icount = 0; icount < (size - psize + 1); icount += psize)\n                {\n                    if (dPtr >= ePtr) break;\n                    *(dPtr++) = XMVectorSet(sPtr[0], 0.f /* typeless component assumed zero */, 0.f, 1.f);\n                    sPtr += 2;\n                }\n                return true;\n            }\n        }\n        return false;\n\n    case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:\n        {\n            constexpr size_t psize = sizeof(float) + sizeof(uint32_t);\n            if (size >= psize)\n            {\n                auto sPtr = static_cast<const float*>(pSource);\n                for (size_t icount = 0; icount < (size - psize + 1); icount += psize)\n                {\n                    auto pg8 = reinterpret_cast<const uint8_t*>(&sPtr[1]);\n                    if (dPtr >= ePtr) break;\n                    *(dPtr++) = XMVectorSet(0.f /* typeless component assumed zero */, static_cast<float>(*pg8), 0.f, 1.f);\n                    sPtr += 2;\n                }\n                return true;\n            }\n        }\n        return false;\n\n    case DXGI_FORMAT_R10G10B10A2_UNORM:\n        LOAD_SCANLINE(XMUDECN4, XMLoadUDecN4)\n\n    case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:\n        LOAD_SCANLINE(XMUDECN4, XMLoadUDecN4_XR)\n\n    case DXGI_FORMAT_R10G10B10A2_UINT:\n        LOAD_SCANLINE(XMUDEC4, XMLoadUDec4)\n\n    case DXGI_FORMAT_R11G11B10_FLOAT:\n        LOAD_SCANLINE3(XMFLOAT3PK, XMLoadFloat3PK, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R8G8B8A8_UNORM:\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n        LOAD_SCANLINE(XMUBYTEN4, XMLoadUByteN4)\n\n    case DXGI_FORMAT_R8G8B8A8_UINT:\n        LOAD_SCANLINE(XMUBYTE4, XMLoadUByte4)\n\n    case DXGI_FORMAT_R8G8B8A8_SNORM:\n        LOAD_SCANLINE(XMBYTEN4, XMLoadByteN4)\n\n    case DXGI_FORMAT_R8G8B8A8_SINT:\n        LOAD_SCANLINE(XMBYTE4, XMLoadByte4)\n\n    case DXGI_FORMAT_R16G16_FLOAT:\n        LOAD_SCANLINE2(XMHALF2, XMLoadHalf2, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R16G16_UNORM:\n        LOAD_SCANLINE2(XMUSHORTN2, XMLoadUShortN2, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R16G16_UINT:\n        LOAD_SCANLINE2(XMUSHORT2, XMLoadUShort2, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R16G16_SNORM:\n        LOAD_SCANLINE2(XMSHORTN2, XMLoadShortN2, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R16G16_SINT:\n        LOAD_SCANLINE2(XMSHORT2, XMLoadShort2, g_XMIdentityR3)\n\n    case DXGI_FORMAT_D32_FLOAT:\n    case DXGI_FORMAT_R32_FLOAT:\n        if (size >= sizeof(float))\n        {\n            const float* __restrict sPtr = static_cast<const float*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(float) + 1); icount += sizeof(float))\n            {\n                const XMVECTOR v = XMLoadFloat(sPtr++);\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1000);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R32_UINT:\n        if (size >= sizeof(uint32_t))\n        {\n            const uint32_t* __restrict sPtr = static_cast<const uint32_t*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t))\n            {\n                XMVECTOR v = XMLoadInt(sPtr++);\n                v = XMConvertVectorUIntToFloat(v, 0);\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1000);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R32_SINT:\n        if (size >= sizeof(int32_t))\n        {\n            const int32_t * __restrict sPtr = static_cast<const int32_t*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(int32_t) + 1); icount += sizeof(int32_t))\n            {\n                XMVECTOR v = XMLoadInt(reinterpret_cast<const uint32_t*>(sPtr++));\n                v = XMConvertVectorIntToFloat(v, 0);\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1000);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_D24_UNORM_S8_UINT:\n        if (size >= sizeof(uint32_t))\n        {\n            auto sPtr = static_cast<const uint32_t*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t))\n            {\n                auto const d = static_cast<float>(*sPtr & 0xFFFFFF) / 16777215.f;\n                auto const s = static_cast<float>((*sPtr & 0xFF000000) >> 24);\n                ++sPtr;\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(d, s, 0.f, 1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:\n        if (size >= sizeof(uint32_t))\n        {\n            auto sPtr = static_cast<const uint32_t*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t))\n            {\n                auto const r = static_cast<float>(*sPtr & 0xFFFFFF) / 16777215.f;\n                ++sPtr;\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(r, 0.f /* typeless component assumed zero */, 0.f, 1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_X24_TYPELESS_G8_UINT:\n        if (size >= sizeof(uint32_t))\n        {\n            auto sPtr = static_cast<const uint32_t*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t))\n            {\n                auto const g = static_cast<float>((*sPtr & 0xFF000000) >> 24);\n                ++sPtr;\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(0.f /* typeless component assumed zero */, g, 0.f, 1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R8G8_UNORM:\n        LOAD_SCANLINE2(XMUBYTEN2, XMLoadUByteN2, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R8G8_UINT:\n        LOAD_SCANLINE2(XMUBYTE2, XMLoadUByte2, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R8G8_SNORM:\n        LOAD_SCANLINE2(XMBYTEN2, XMLoadByteN2, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R8G8_SINT:\n        LOAD_SCANLINE2(XMBYTE2, XMLoadByte2, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R16_FLOAT:\n        if (size >= sizeof(HALF))\n        {\n            const HALF * __restrict sPtr = static_cast<const HALF*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(HALF) + 1); icount += sizeof(HALF))\n            {\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(XMConvertHalfToFloat(*sPtr++), 0.f, 0.f, 1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_D16_UNORM:\n    case DXGI_FORMAT_R16_UNORM:\n        if (size >= sizeof(uint16_t))\n        {\n            const uint16_t* __restrict sPtr = static_cast<const uint16_t*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(uint16_t) + 1); icount += sizeof(uint16_t))\n            {\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++) / 65535.f, 0.f, 0.f, 1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R16_UINT:\n        if (size >= sizeof(uint16_t))\n        {\n            const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(uint16_t) + 1); icount += sizeof(uint16_t))\n            {\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++), 0.f, 0.f, 1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R16_SNORM:\n        if (size >= sizeof(int16_t))\n        {\n            const int16_t * __restrict sPtr = static_cast<const int16_t*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(int16_t) + 1); icount += sizeof(int16_t))\n            {\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++) / 32767.f, 0.f, 0.f, 1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R16_SINT:\n        if (size >= sizeof(int16_t))\n        {\n            const int16_t * __restrict sPtr = static_cast<const int16_t*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(int16_t) + 1); icount += sizeof(int16_t))\n            {\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++), 0.f, 0.f, 1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R8_UNORM:\n        if (size >= sizeof(uint8_t))\n        {\n            const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);\n            for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))\n            {\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++) / 255.f, 0.f, 0.f, 1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R8_UINT:\n        if (size >= sizeof(uint8_t))\n        {\n            const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);\n            for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))\n            {\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++), 0.f, 0.f, 1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R8_SNORM:\n        if (size >= sizeof(int8_t))\n        {\n            const int8_t * __restrict sPtr = static_cast<const int8_t*>(pSource);\n            for (size_t icount = 0; icount < size; icount += sizeof(int8_t))\n            {\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++) / 127.f, 0.f, 0.f, 1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R8_SINT:\n        if (size >= sizeof(int8_t))\n        {\n            const int8_t * __restrict sPtr = static_cast<const int8_t*>(pSource);\n            for (size_t icount = 0; icount < size; icount += sizeof(int8_t))\n            {\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(static_cast<float>(*sPtr++), 0.f, 0.f, 1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_A8_UNORM:\n        if (size >= sizeof(uint8_t))\n        {\n            const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);\n            for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))\n            {\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(0.f, 0.f, 0.f, static_cast<float>(*sPtr++) / 255.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R1_UNORM:\n        if (size >= sizeof(uint8_t))\n        {\n            const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);\n            for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))\n            {\n                for (size_t bcount = 8; bcount > 0; --bcount)\n                {\n                    if (dPtr >= ePtr) break;\n                    *(dPtr++) = XMVectorSet((((*sPtr >> (bcount - 1)) & 0x1) ? 1.f : 0.f), 0.f, 0.f, 1.f);\n                }\n\n                ++sPtr;\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:\n        LOAD_SCANLINE3(XMFLOAT3SE, XMLoadFloat3SE, g_XMIdentityR3)\n\n    case DXGI_FORMAT_R8G8_B8G8_UNORM:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            const XMUBYTEN4 * __restrict sPtr = static_cast<const XMUBYTEN4*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))\n            {\n                const XMVECTOR v = XMLoadUByteN4(sPtr++);\n                const XMVECTOR v1 = XMVectorSwizzle<0, 3, 2, 1>(v);\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1110);\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v1, g_XMSelect1110);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_G8R8_G8B8_UNORM:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            const XMUBYTEN4 * __restrict sPtr = static_cast<const XMUBYTEN4*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))\n            {\n                const XMVECTOR v = XMLoadUByteN4(sPtr++);\n                const XMVECTOR v0 = XMVectorSwizzle<1, 0, 3, 2>(v);\n                const XMVECTOR v1 = XMVectorSwizzle<1, 2, 3, 0>(v);\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v0, g_XMSelect1110);\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v1, g_XMSelect1110);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B5G6R5_UNORM:\n        if (size >= sizeof(XMU565))\n        {\n            static const XMVECTORF32 s_Scale = { { { 1.f / 31.f, 1.f / 63.f, 1.f / 31.f, 1.f } } };\n            const XMU565 * __restrict sPtr = static_cast<const XMU565*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMU565) + 1); icount += sizeof(XMU565))\n            {\n                XMVECTOR v = XMLoadU565(sPtr++);\n                v = XMVectorMultiply(v, s_Scale);\n                v = XMVectorSwizzle<2, 1, 0, 3>(v);\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1110);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B5G5R5A1_UNORM:\n        if (size >= sizeof(XMU555))\n        {\n            static const XMVECTORF32 s_Scale = { { { 1.f / 31.f, 1.f / 31.f, 1.f / 31.f, 1.f } } };\n            const XMU555 * __restrict sPtr = static_cast<const XMU555*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMU555) + 1); icount += sizeof(XMU555))\n            {\n                XMVECTOR v = XMLoadU555(sPtr++);\n                v = XMVectorMultiply(v, s_Scale);\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>(v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B8G8R8A8_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            const XMUBYTEN4 * __restrict sPtr = static_cast<const XMUBYTEN4*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))\n            {\n                const XMVECTOR v = XMLoadUByteN4(sPtr++);\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>(v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B8G8R8X8_UNORM:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            const XMUBYTEN4 * __restrict sPtr = static_cast<const XMUBYTEN4*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))\n            {\n                XMVECTOR v = XMLoadUByteN4(sPtr++);\n                v = XMVectorSwizzle<2, 1, 0, 3>(v);\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1110);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_AYUV:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            const XMUBYTEN4 * __restrict sPtr = static_cast<const XMUBYTEN4*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))\n            {\n                const int v = int(sPtr->x) - 128;\n                const int u = int(sPtr->y) - 128;\n                const int y = int(sPtr->z) - 16;\n                const unsigned int a = sPtr->w;\n                ++sPtr;\n\n                // http://msdn.microsoft.com/en-us/library/windows/desktop/dd206750.aspx\n\n                // Y'  = Y - 16\n                // Cb' = Cb - 128\n                // Cr' = Cr - 128\n\n                // R = 1.1644Y' + 1.5960Cr'\n                // G = 1.1644Y' - 0.3917Cb' - 0.8128Cr'\n                // B = 1.1644Y' + 2.0172Cb'\n\n                const int r = (298 * y + 409 * v + 128) >> 8;\n                const int g = (298 * y - 100 * u - 208 * v + 128) >> 8;\n                const int b = (298 * y + 516 * u + 128) >> 8;\n\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 255)) / 255.f,\n                    float(std::min<int>(std::max<int>(g, 0), 255)) / 255.f,\n                    float(std::min<int>(std::max<int>(b, 0), 255)) / 255.f,\n                    float(a) / 255.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_Y410:\n        if (size >= sizeof(XMUDECN4))\n        {\n            const XMUDECN4 * __restrict sPtr = static_cast<const XMUDECN4*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4))\n            {\n                const int64_t u = int(sPtr->x) - 512;\n                const int64_t y = int(sPtr->y) - 64;\n                const int64_t v = int(sPtr->z) - 512;\n                const unsigned int a = sPtr->w;\n                ++sPtr;\n\n                // http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx\n\n                // Y'  = Y - 64\n                // Cb' = Cb - 512\n                // Cr' = Cr - 512\n\n                // R = 1.1678Y' + 1.6007Cr'\n                // G = 1.1678Y' - 0.3929Cb' - 0.8152Cr'\n                // B = 1.1678Y' + 2.0232Cb'\n\n                auto const r = static_cast<int>((76533 * y + 104905 * v + 32768) >> 16);\n                auto const g = static_cast<int>((76533 * y - 25747 * u - 53425 * v + 32768) >> 16);\n                auto const b = static_cast<int>((76533 * y + 132590 * u + 32768) >> 16);\n\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 1023)) / 1023.f,\n                    float(std::min<int>(std::max<int>(g, 0), 1023)) / 1023.f,\n                    float(std::min<int>(std::max<int>(b, 0), 1023)) / 1023.f,\n                    float(a) / 3.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_Y416:\n        if (size >= sizeof(XMUSHORTN4))\n        {\n            const XMUSHORTN4 * __restrict sPtr = static_cast<const XMUSHORTN4*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4))\n            {\n                const int64_t u = int64_t(sPtr->x) - 32768;\n                const int64_t y = int64_t(sPtr->y) - 4096;\n                const int64_t v = int64_t(sPtr->z) - 32768;\n                auto const a = static_cast<int>(sPtr->w);\n                ++sPtr;\n\n                // http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx\n\n                // Y'  = Y - 4096\n                // Cb' = Cb - 32768\n                // Cr' = Cr - 32768\n\n                // R = 1.1689Y' + 1.6023Cr'\n                // G = 1.1689Y' - 0.3933Cb' - 0.8160Cr'\n                // B = 1.1689Y'+ 2.0251Cb'\n\n                auto const r = static_cast<int>((76607 * y + 105006 * v + 32768) >> 16);\n                auto const g = static_cast<int>((76607 * y - 25772 * u - 53477 * v + 32768) >> 16);\n                auto const b = static_cast<int>((76607 * y + 132718 * u + 32768) >> 16);\n\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 65535)) / 65535.f,\n                    float(std::min<int>(std::max<int>(g, 0), 65535)) / 65535.f,\n                    float(std::min<int>(std::max<int>(b, 0), 65535)) / 65535.f,\n                    float(std::min<int>(std::max<int>(a, 0), 65535)) / 65535.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_YUY2:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            const XMUBYTEN4 * __restrict sPtr = static_cast<const XMUBYTEN4*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))\n            {\n                const int y0 = int(sPtr->x) - 16;\n                const int u = int(sPtr->y) - 128;\n                const int y1 = int(sPtr->z) - 16;\n                const int v = int(sPtr->w) - 128;\n                ++sPtr;\n\n                // See AYUV\n                int r = (298 * y0 + 409 * v + 128) >> 8;\n                int g = (298 * y0 - 100 * u - 208 * v + 128) >> 8;\n                int b = (298 * y0 + 516 * u + 128) >> 8;\n\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 255)) / 255.f,\n                    float(std::min<int>(std::max<int>(g, 0), 255)) / 255.f,\n                    float(std::min<int>(std::max<int>(b, 0), 255)) / 255.f,\n                    1.f);\n\n                r = (298 * y1 + 409 * v + 128) >> 8;\n                g = (298 * y1 - 100 * u - 208 * v + 128) >> 8;\n                b = (298 * y1 + 516 * u + 128) >> 8;\n\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 255)) / 255.f,\n                    float(std::min<int>(std::max<int>(g, 0), 255)) / 255.f,\n                    float(std::min<int>(std::max<int>(b, 0), 255)) / 255.f,\n                    1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_Y210:\n        // Same as Y216 with least significant 6 bits set to zero\n        if (size >= sizeof(XMUSHORTN4))\n        {\n            const XMUSHORTN4 * __restrict sPtr = static_cast<const XMUSHORTN4*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4))\n            {\n                const int64_t y0 = int64_t(sPtr->x >> 6) - 64;\n                const int64_t u = int64_t(sPtr->y >> 6) - 512;\n                const int64_t y1 = int64_t(sPtr->z >> 6) - 64;\n                const int64_t v = int64_t(sPtr->w >> 6) - 512;\n                ++sPtr;\n\n                // See Y410\n                auto r = static_cast<int>((76533 * y0 + 104905 * v + 32768) >> 16);\n                auto g = static_cast<int>((76533 * y0 - 25747 * u - 53425 * v + 32768) >> 16);\n                auto b = static_cast<int>((76533 * y0 + 132590 * u + 32768) >> 16);\n\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 1023)) / 1023.f,\n                    float(std::min<int>(std::max<int>(g, 0), 1023)) / 1023.f,\n                    float(std::min<int>(std::max<int>(b, 0), 1023)) / 1023.f,\n                    1.f);\n\n                r = static_cast<int>((76533 * y1 + 104905 * v + 32768) >> 16);\n                g = static_cast<int>((76533 * y1 - 25747 * u - 53425 * v + 32768) >> 16);\n                b = static_cast<int>((76533 * y1 + 132590 * u + 32768) >> 16);\n\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 1023)) / 1023.f,\n                    float(std::min<int>(std::max<int>(g, 0), 1023)) / 1023.f,\n                    float(std::min<int>(std::max<int>(b, 0), 1023)) / 1023.f,\n                    1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_Y216:\n        if (size >= sizeof(XMUSHORTN4))\n        {\n            const XMUSHORTN4 * __restrict sPtr = static_cast<const XMUSHORTN4*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4))\n            {\n                const int64_t y0 = int64_t(sPtr->x) - 4096;\n                const int64_t u = int64_t(sPtr->y) - 32768;\n                const int64_t y1 = int64_t(sPtr->z) - 4096;\n                const int64_t v = int64_t(sPtr->w) - 32768;\n                ++sPtr;\n\n                // See Y416\n                auto r = static_cast<int>((76607 * y0 + 105006 * v + 32768) >> 16);\n                auto g = static_cast<int>((76607 * y0 - 25772 * u - 53477 * v + 32768) >> 16);\n                auto b = static_cast<int>((76607 * y0 + 132718 * u + 32768) >> 16);\n\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 65535)) / 65535.f,\n                    float(std::min<int>(std::max<int>(g, 0), 65535)) / 65535.f,\n                    float(std::min<int>(std::max<int>(b, 0), 65535)) / 65535.f,\n                    1.f);\n\n                r = static_cast<int>((76607 * y1 + 105006 * v + 32768) >> 16);\n                g = static_cast<int>((76607 * y1 - 25772 * u - 53477 * v + 32768) >> 16);\n                b = static_cast<int>((76607 * y1 + 132718 * u + 32768) >> 16);\n\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSet(float(std::min<int>(std::max<int>(r, 0), 65535)) / 65535.f,\n                    float(std::min<int>(std::max<int>(g, 0), 65535)) / 65535.f,\n                    float(std::min<int>(std::max<int>(b, 0), 65535)) / 65535.f,\n                    1.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B4G4R4A4_UNORM:\n        if (size >= sizeof(XMUNIBBLE4))\n        {\n            static const XMVECTORF32 s_Scale = { { { 1.f / 15.f, 1.f / 15.f, 1.f / 15.f, 1.f / 15.f } } };\n            const XMUNIBBLE4 * __restrict sPtr = static_cast<const XMUNIBBLE4*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMUNIBBLE4) + 1); icount += sizeof(XMUNIBBLE4))\n            {\n                XMVECTOR v = XMLoadUNibble4(sPtr++);\n                v = XMVectorMultiply(v, s_Scale);\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>(v);\n            }\n            return true;\n        }\n        return false;\n\n    case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT:\n        // Xbox One specific 7e3 format\n        if (size >= sizeof(XMUDECN4))\n        {\n            const XMUDECN4 * __restrict sPtr = static_cast<const XMUDECN4*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4))\n            {\n                if (dPtr >= ePtr) break;\n\n                XMVECTORF32 vResult = { { {\n                    FloatFrom7e3(sPtr->x),\n                    FloatFrom7e3(sPtr->y),\n                    FloatFrom7e3(sPtr->z),\n                    static_cast<float>(sPtr->v >> 30) / 3.0f\n                } } };\n\n                ++sPtr;\n\n                *(dPtr++) = vResult.v;\n            }\n            return true;\n        }\n        return false;\n\n    case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT:\n        // Xbox One specific 6e4 format\n        if (size >= sizeof(XMUDECN4))\n        {\n            const XMUDECN4 * __restrict sPtr = static_cast<const XMUDECN4*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4))\n            {\n                if (dPtr >= ePtr) break;\n\n                XMVECTORF32 vResult = { { {\n                    FloatFrom6e4(sPtr->x),\n                    FloatFrom6e4(sPtr->y),\n                    FloatFrom6e4(sPtr->z),\n                    static_cast<float>(sPtr->v >> 30) / 3.0f\n                } } };\n\n                ++sPtr;\n\n                *(dPtr++) = vResult.v;\n            }\n            return true;\n        }\n        return false;\n\n    case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:\n        // Xbox One specific format\n        LOAD_SCANLINE(XMXDECN4, XMLoadXDecN4)\n\n    case XBOX_DXGI_FORMAT_R4G4_UNORM:\n        // Xbox One specific format\n        if (size >= sizeof(uint8_t))\n        {\n            static const XMVECTORF32 s_Scale = { { { 1.f / 15.f, 1.f / 15.f, 0.f, 0.f } } };\n            const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);\n            for (size_t icount = 0; icount < (size - sizeof(uint8_t) + 1); icount += sizeof(uint8_t))\n            {\n                XMUNIBBLE4 nibble;\n                nibble.v = static_cast<uint16_t>(*sPtr++);\n                XMVECTOR v = XMLoadUNibble4(&nibble);\n                v = XMVectorMultiply(v, s_Scale);\n                if (dPtr >= ePtr) break;\n                *(dPtr++) = XMVectorSelect(g_XMIdentityR3, v, g_XMSelect1100);\n            }\n            return true;\n        }\n        return false;\n\n        // We don't support the planar or palettized formats\n\n    default:\n        return false;\n    }\n}\n\n#undef LOAD_SCANLINE\n#undef LOAD_SCANLINE3\n#undef LOAD_SCANLINE2\n\n\n//-------------------------------------------------------------------------------------\n// Stores an image row from standard RGBA XMVECTOR (aligned) array\n//-------------------------------------------------------------------------------------\n#define STORE_SCANLINE( type, func )\\\n        if (size >= sizeof(type))\\\n        {\\\n            type * __restrict dPtr = reinterpret_cast<type*>(pDestination);\\\n            for(size_t icount = 0; icount < (size - sizeof(type) + 1); icount += sizeof(type))\\\n            {\\\n                if (sPtr >= ePtr) break;\\\n                func(dPtr++, *sPtr++);\\\n            }\\\n            return true; \\\n        }\\\n        return false;\n\n_Use_decl_annotations_\nbool DirectX::Internal::StoreScanline(\n    void* pDestination,\n    size_t size,\n    DXGI_FORMAT format,\n    const XMVECTOR* pSource,\n    size_t count,\n    float threshold) noexcept\n{\n    assert(pDestination != nullptr);\n    assert(IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format));\n\n    if (!size || !count)\n        return false;\n\n    const XMVECTOR* __restrict sPtr = pSource;\n    if (!sPtr)\n        return false;\n\n    assert((reinterpret_cast<uintptr_t>(pSource) & 0xF) == 0);\n\n    const XMVECTOR* ePtr = sPtr + count;\n\n#ifdef _PREFAST_\n    *reinterpret_cast<uint8_t*>(pDestination) = 0;\n#endif\n\n    switch (static_cast<int>(format))\n    {\n    case DXGI_FORMAT_R32G32B32A32_FLOAT:\n        STORE_SCANLINE(XMFLOAT4, XMStoreFloat4)\n\n    case DXGI_FORMAT_R32G32B32A32_UINT:\n        STORE_SCANLINE(XMUINT4, XMStoreUInt4)\n\n    case DXGI_FORMAT_R32G32B32A32_SINT:\n        STORE_SCANLINE(XMINT4, XMStoreSInt4)\n\n    case DXGI_FORMAT_R32G32B32_FLOAT:\n        STORE_SCANLINE(XMFLOAT3, XMStoreFloat3)\n\n    case DXGI_FORMAT_R32G32B32_UINT:\n        STORE_SCANLINE(XMUINT3, XMStoreUInt3)\n\n    case DXGI_FORMAT_R32G32B32_SINT:\n        STORE_SCANLINE(XMINT3, XMStoreSInt3)\n\n    case DXGI_FORMAT_R16G16B16A16_FLOAT:\n        if (size >= sizeof(XMHALF4))\n        {\n            XMHALF4* __restrict dPtr = static_cast<XMHALF4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMHALF4) + 1); icount += sizeof(XMHALF4))\n            {\n                if (sPtr >= ePtr) break;\n                XMVECTOR v = *sPtr++;\n                v = XMVectorClamp(v, g_HalfMin, g_HalfMax);\n                XMStoreHalf4(dPtr++, v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R16G16B16A16_UNORM:\n        STORE_SCANLINE(XMUSHORTN4, XMStoreUShortN4)\n\n    case DXGI_FORMAT_R16G16B16A16_UINT:\n        STORE_SCANLINE(XMUSHORT4, XMStoreUShort4)\n\n    case DXGI_FORMAT_R16G16B16A16_SNORM:\n        STORE_SCANLINE(XMSHORTN4, XMStoreShortN4)\n\n    case DXGI_FORMAT_R16G16B16A16_SINT:\n        STORE_SCANLINE(XMSHORT4, XMStoreShort4)\n\n    case DXGI_FORMAT_R32G32_FLOAT:\n        STORE_SCANLINE(XMFLOAT2, XMStoreFloat2)\n\n    case DXGI_FORMAT_R32G32_UINT:\n        STORE_SCANLINE(XMUINT2, XMStoreUInt2)\n\n    case DXGI_FORMAT_R32G32_SINT:\n        STORE_SCANLINE(XMINT2, XMStoreSInt2)\n\n    case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:\n            {\n                constexpr size_t psize = sizeof(float) + sizeof(uint32_t);\n                if (size >= psize)\n                {\n                    auto dPtr = static_cast<float*>(pDestination);\n                    for (size_t icount = 0; icount < (size - psize + 1); icount += psize)\n                    {\n                        if (sPtr >= ePtr) break;\n                        XMFLOAT4 f;\n                        XMStoreFloat4(&f, *sPtr++);\n                        dPtr[0] = f.x;\n                        auto ps8 = reinterpret_cast<uint8_t*>(&dPtr[1]);\n                        ps8[0] = static_cast<uint8_t>(std::min<float>(255.f, std::max<float>(0.f, f.y)));\n                        ps8[1] = ps8[2] = ps8[3] = 0;\n                        dPtr += 2;\n                    }\n                    return true;\n                }\n            }\n            return false;\n\n    case DXGI_FORMAT_R10G10B10A2_UNORM:\n        STORE_SCANLINE(XMUDECN4, XMStoreUDecN4)\n\n    case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:\n        STORE_SCANLINE(XMUDECN4, XMStoreUDecN4_XR)\n\n    case DXGI_FORMAT_R10G10B10A2_UINT:\n        STORE_SCANLINE(XMUDEC4, XMStoreUDec4)\n\n    case DXGI_FORMAT_R11G11B10_FLOAT:\n        STORE_SCANLINE(XMFLOAT3PK, XMStoreFloat3PK)\n\n    case DXGI_FORMAT_R8G8B8A8_UNORM:\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))\n            {\n                if (sPtr >= ePtr) break;\n                const XMVECTOR v = XMVectorAdd(*sPtr++, g_8BitBias);\n                XMStoreUByteN4(dPtr++, v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R8G8B8A8_UINT:\n        STORE_SCANLINE(XMUBYTE4, XMStoreUByte4)\n\n    case DXGI_FORMAT_R8G8B8A8_SNORM:\n        STORE_SCANLINE(XMBYTEN4, XMStoreByteN4)\n\n    case DXGI_FORMAT_R8G8B8A8_SINT:\n        STORE_SCANLINE(XMBYTE4, XMStoreByte4)\n\n    case DXGI_FORMAT_R16G16_FLOAT:\n        if (size >= sizeof(XMHALF2))\n        {\n            XMHALF2* __restrict dPtr = static_cast<XMHALF2*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMHALF2) + 1); icount += sizeof(XMHALF2))\n            {\n                if (sPtr >= ePtr) break;\n                XMVECTOR v = *sPtr++;\n                v = XMVectorClamp(v, g_HalfMin, g_HalfMax);\n                XMStoreHalf2(dPtr++, v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R16G16_UNORM:\n        STORE_SCANLINE(XMUSHORTN2, XMStoreUShortN2)\n\n    case DXGI_FORMAT_R16G16_UINT:\n        STORE_SCANLINE(XMUSHORT2, XMStoreUShort2)\n\n    case DXGI_FORMAT_R16G16_SNORM:\n        STORE_SCANLINE(XMSHORTN2, XMStoreShortN2)\n\n    case DXGI_FORMAT_R16G16_SINT:\n        STORE_SCANLINE(XMSHORT2, XMStoreShort2)\n\n    case DXGI_FORMAT_D32_FLOAT:\n    case DXGI_FORMAT_R32_FLOAT:\n        if (size >= sizeof(float))\n        {\n            float * __restrict dPtr = static_cast<float*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(float) + 1); icount += sizeof(float))\n            {\n                if (sPtr >= ePtr) break;\n                XMStoreFloat(dPtr++, *(sPtr++));\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R32_UINT:\n        if (size >= sizeof(uint32_t))\n        {\n            uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t))\n            {\n                if (sPtr >= ePtr) break;\n                const XMVECTOR v = XMConvertVectorFloatToUInt(*(sPtr++), 0);\n                XMStoreInt(dPtr++, v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R32_SINT:\n        if (size >= sizeof(int32_t))\n        {\n            uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(int32_t) + 1); icount += sizeof(int32_t))\n            {\n                if (sPtr >= ePtr) break;\n                const XMVECTOR v = XMConvertVectorFloatToInt(*(sPtr++), 0);\n                XMStoreInt(dPtr++, v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_D24_UNORM_S8_UINT:\n        if (size >= sizeof(uint32_t))\n        {\n            static const XMVECTORF32 clamp = { { { 1.f, 255.f, 0.f, 0.f } } };\n            const XMVECTOR zero = XMVectorZero();\n            auto dPtr = static_cast<uint32_t*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(uint32_t) + 1); icount += sizeof(uint32_t))\n            {\n                if (sPtr >= ePtr) break;\n                XMFLOAT4 f;\n                XMStoreFloat4(&f, XMVectorClamp(*sPtr++, zero, clamp));\n                *dPtr++ = (static_cast<uint32_t>(f.x * 16777215.f) & 0xFFFFFF)\n                    | ((static_cast<uint32_t>(f.y) & 0xFF) << 24);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R8G8_UNORM:\n        STORE_SCANLINE(XMUBYTEN2, XMStoreUByteN2)\n\n    case DXGI_FORMAT_R8G8_UINT:\n        STORE_SCANLINE(XMUBYTE2, XMStoreUByte2)\n\n    case DXGI_FORMAT_R8G8_SNORM:\n        STORE_SCANLINE(XMBYTEN2, XMStoreByteN2)\n\n    case DXGI_FORMAT_R8G8_SINT:\n        STORE_SCANLINE(XMBYTE2, XMStoreByte2)\n\n    case DXGI_FORMAT_R16_FLOAT:\n        if (size >= sizeof(HALF))\n        {\n            HALF * __restrict dPtr = static_cast<HALF*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(HALF) + 1); icount += sizeof(HALF))\n            {\n                if (sPtr >= ePtr) break;\n                float v = XMVectorGetX(*sPtr++);\n                v = std::max<float>(std::min<float>(v, 65504.f), -65504.f);\n                *(dPtr++) = XMConvertFloatToHalf(v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_D16_UNORM:\n    case DXGI_FORMAT_R16_UNORM:\n        if (size >= sizeof(uint16_t))\n        {\n            uint16_t * __restrict dPtr = static_cast<uint16_t*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(uint16_t) + 1); icount += sizeof(uint16_t))\n            {\n                if (sPtr >= ePtr) break;\n                float v = XMVectorGetX(*sPtr++);\n                v = std::max<float>(std::min<float>(v, 1.f), 0.f);\n                *(dPtr++) = static_cast<uint16_t>(v*65535.f + 0.5f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R16_UINT:\n        if (size >= sizeof(uint16_t))\n        {\n            uint16_t * __restrict dPtr = static_cast<uint16_t*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(uint16_t) + 1); icount += sizeof(uint16_t))\n            {\n                if (sPtr >= ePtr) break;\n                float v = XMVectorGetX(*sPtr++);\n                v = std::max<float>(std::min<float>(v, 65535.f), 0.f);\n                *(dPtr++) = static_cast<uint16_t>(v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R16_SNORM:\n        if (size >= sizeof(int16_t))\n        {\n            int16_t * __restrict dPtr = static_cast<int16_t*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(int16_t) + 1); icount += sizeof(int16_t))\n            {\n                if (sPtr >= ePtr) break;\n                float v = XMVectorGetX(*sPtr++);\n                v = std::max<float>(std::min<float>(v, 1.f), -1.f);\n                *(dPtr++) = static_cast<int16_t>(lroundf(v * 32767.f));\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R16_SINT:\n        if (size >= sizeof(int16_t))\n        {\n            int16_t * __restrict dPtr = static_cast<int16_t*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(int16_t) + 1); icount += sizeof(int16_t))\n            {\n                if (sPtr >= ePtr) break;\n                float v = XMVectorGetX(*sPtr++);\n                v = std::max<float>(std::min<float>(v, 32767.f), -32767.f);\n                *(dPtr++) = static_cast<int16_t>(v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R8_UNORM:\n        if (size >= sizeof(uint8_t))\n        {\n            uint8_t * __restrict dPtr = static_cast<uint8_t*>(pDestination);\n            for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))\n            {\n                if (sPtr >= ePtr) break;\n                float v = XMVectorGetX(*sPtr++);\n                v = std::max<float>(std::min<float>(v, 1.f), 0.f);\n                *(dPtr++) = static_cast<uint8_t>(v * 255.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R8_UINT:\n        if (size >= sizeof(uint8_t))\n        {\n            uint8_t * __restrict dPtr = static_cast<uint8_t*>(pDestination);\n            for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))\n            {\n                if (sPtr >= ePtr) break;\n                float v = XMVectorGetX(*sPtr++);\n                v = std::max<float>(std::min<float>(v, 255.f), 0.f);\n                *(dPtr++) = static_cast<uint8_t>(v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R8_SNORM:\n        if (size >= sizeof(int8_t))\n        {\n            int8_t * __restrict dPtr = static_cast<int8_t*>(pDestination);\n            for (size_t icount = 0; icount < size; icount += sizeof(int8_t))\n            {\n                if (sPtr >= ePtr) break;\n                float v = XMVectorGetX(*sPtr++);\n                v = std::max<float>(std::min<float>(v, 1.f), -1.f);\n                *(dPtr++) = static_cast<int8_t>(lroundf(v * 127.f));\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R8_SINT:\n        if (size >= sizeof(int8_t))\n        {\n            int8_t * __restrict dPtr = static_cast<int8_t*>(pDestination);\n            for (size_t icount = 0; icount < size; icount += sizeof(int8_t))\n            {\n                if (sPtr >= ePtr) break;\n                float v = XMVectorGetX(*sPtr++);\n                v = std::max<float>(std::min<float>(v, 127.f), -127.f);\n                *(dPtr++) = static_cast<int8_t>(v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_A8_UNORM:\n        if (size >= sizeof(uint8_t))\n        {\n            uint8_t * __restrict dPtr = static_cast<uint8_t*>(pDestination);\n            for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))\n            {\n                if (sPtr >= ePtr) break;\n                float v = XMVectorGetW(*sPtr++);\n                v = std::max<float>(std::min<float>(v, 1.f), 0.f);\n                *(dPtr++) = static_cast<uint8_t>(v * 255.f);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R1_UNORM:\n        if (size >= sizeof(uint8_t))\n        {\n            uint8_t * __restrict dPtr = static_cast<uint8_t*>(pDestination);\n            for (size_t icount = 0; icount < size; icount += sizeof(uint8_t))\n            {\n                uint8_t pixels = 0;\n                for (size_t bcount = 8; bcount > 0; --bcount)\n                {\n                    if (sPtr >= ePtr) break;\n                    const float v = XMVectorGetX(*sPtr++);\n\n                    // Absolute thresholding generally doesn't give good results for all images\n                    // Picking the 'right' threshold automatically requires whole-image analysis\n\n                    if (v > 0.25f)\n                        pixels |= 1 << (bcount - 1);\n                }\n                *(dPtr++) = pixels;\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:\n        STORE_SCANLINE(XMFLOAT3SE, StoreFloat3SE)\n\n    case DXGI_FORMAT_R8G8_B8G8_UNORM:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))\n            {\n                if (sPtr >= ePtr) break;\n                const XMVECTOR v0 = *sPtr++;\n                const XMVECTOR v1 = (sPtr < ePtr) ? XMVectorSplatY(*sPtr++) : XMVectorZero();\n                XMVECTOR v = XMVectorSelect(v1, v0, g_XMSelect1110);\n                v = XMVectorAdd(v, g_8BitBias);\n                XMStoreUByteN4(dPtr++, v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_G8R8_G8B8_UNORM:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            static XMVECTORU32 select1101 = { { { XM_SELECT_1, XM_SELECT_1, XM_SELECT_0, XM_SELECT_1 } } };\n\n            XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))\n            {\n                if (sPtr >= ePtr) break;\n                const XMVECTOR v0 = XMVectorSwizzle<1, 0, 3, 2>(*sPtr++);\n                const XMVECTOR v1 = (sPtr < ePtr) ? XMVectorSplatY(*sPtr++) : XMVectorZero();\n                XMVECTOR v = XMVectorSelect(v1, v0, select1101);\n                v = XMVectorAdd(v, g_8BitBias);\n                XMStoreUByteN4(dPtr++, v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B5G6R5_UNORM:\n        if (size >= sizeof(XMU565))\n        {\n            static const XMVECTORF32 s_Scale = { { { 31.f, 63.f, 31.f, 1.f } } };\n            XMU565 * __restrict dPtr = static_cast<XMU565*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMU565) + 1); icount += sizeof(XMU565))\n            {\n                if (sPtr >= ePtr) break;\n                XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(*sPtr++);\n                v = XMVectorMultiply(v, s_Scale);\n                XMStoreU565(dPtr++, v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B5G5R5A1_UNORM:\n        if (size >= sizeof(XMU555))\n        {\n            static const XMVECTORF32 s_Scale = { { { 31.f, 31.f, 31.f, 1.f } } };\n            XMU555 * __restrict dPtr = static_cast<XMU555*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMU555) + 1); icount += sizeof(XMU555))\n            {\n                if (sPtr >= ePtr) break;\n                XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(*sPtr++);\n                v = XMVectorMultiply(v, s_Scale);\n                XMStoreU555(dPtr, v);\n                dPtr->w = (XMVectorGetW(v) > threshold) ? 1u : 0u;\n                ++dPtr;\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B8G8R8A8_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))\n            {\n                if (sPtr >= ePtr) break;\n                XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(*sPtr++);\n                v = XMVectorAdd(v, g_8BitBias);\n                XMStoreUByteN4(dPtr++, v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B8G8R8X8_UNORM:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))\n            {\n                if (sPtr >= ePtr) break;\n                XMVECTOR v = XMVectorPermute<2, 1, 0, 7>(*sPtr++, g_XMIdentityR3);\n                v = XMVectorAdd(v, g_8BitBias);\n                XMStoreUByteN4(dPtr++, v);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_AYUV:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))\n            {\n                if (sPtr >= ePtr) break;\n\n                XMUBYTEN4 rgba;\n                XMStoreUByteN4(&rgba, *sPtr++);\n\n                // http://msdn.microsoft.com/en-us/library/windows/desktop/dd206750.aspx\n\n                // Y  =  0.2568R + 0.5041G + 0.1001B + 16\n                // Cb = -0.1482R - 0.2910G + 0.4392B + 128\n                // Cr =  0.4392R - 0.3678G - 0.0714B + 128\n\n                const int y = ((66 * rgba.x + 129 * rgba.y + 25 * rgba.z + 128) >> 8) + 16;\n                const int u = ((-38 * rgba.x - 74 * rgba.y + 112 * rgba.z + 128) >> 8) + 128;\n                const int v = ((112 * rgba.x - 94 * rgba.y - 18 * rgba.z + 128) >> 8) + 128;\n\n                dPtr->x = static_cast<uint8_t>(std::min<int>(std::max<int>(v, 0), 255));\n                dPtr->y = static_cast<uint8_t>(std::min<int>(std::max<int>(u, 0), 255));\n                dPtr->z = static_cast<uint8_t>(std::min<int>(std::max<int>(y, 0), 255));\n                dPtr->w = rgba.w;\n                ++dPtr;\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_Y410:\n        if (size >= sizeof(XMUDECN4))\n        {\n            XMUDECN4 * __restrict dPtr = static_cast<XMUDECN4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4))\n            {\n                if (sPtr >= ePtr) break;\n\n                XMUDECN4 rgba;\n                XMStoreUDecN4(&rgba, *sPtr++);\n\n                // http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx\n\n                // Y  =  0.2560R + 0.5027G + 0.0998B + 64\n                // Cb = -0.1478R - 0.2902G + 0.4379B + 512\n                // Cr =  0.4379R - 0.3667G - 0.0712B + 512\n\n                const int64_t r = rgba.x;\n                const int64_t g = rgba.y;\n                const int64_t b = rgba.z;\n\n                const int y = static_cast<int>((16780 * r + 32942 * g + 6544 * b + 32768) >> 16) + 64;\n                const int u = static_cast<int>((-9683 * r - 19017 * g + 28700 * b + 32768) >> 16) + 512;\n                const int v = static_cast<int>((28700 * r - 24033 * g - 4667 * b + 32768) >> 16) + 512;\n\n                dPtr->x = static_cast<uint32_t>(std::min<int>(std::max<int>(u, 0), 1023));\n                dPtr->y = static_cast<uint32_t>(std::min<int>(std::max<int>(y, 0), 1023));\n                dPtr->z = static_cast<uint32_t>(std::min<int>(std::max<int>(v, 0), 1023));\n                dPtr->w = rgba.w;\n                ++dPtr;\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_Y416:\n        if (size >= sizeof(XMUSHORTN4))\n        {\n            XMUSHORTN4 * __restrict dPtr = static_cast<XMUSHORTN4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4))\n            {\n                if (sPtr >= ePtr) break;\n\n                XMUSHORTN4 rgba;\n                XMStoreUShortN4(&rgba, *sPtr++);\n\n                // http://msdn.microsoft.com/en-us/library/windows/desktop/bb970578.aspx\n\n                // Y  =  0.2558R + 0.5022G + 0.0998B + 4096\n                // Cb = -0.1476R - 0.2899G + 0.4375B + 32768\n                // Cr =  0.4375R - 0.3664G - 0.0711B + 32768\n\n                const int64_t r = int64_t(rgba.x);\n                const int64_t g = int64_t(rgba.y);\n                const int64_t b = int64_t(rgba.z);\n\n                const int y = static_cast<int>((16763 * r + 32910 * g + 6537 * b + 32768) >> 16) + 4096;\n                const int u = static_cast<int>((-9674 * r - 18998 * g + 28672 * b + 32768) >> 16) + 32768;\n                const int v = static_cast<int>((28672 * r - 24010 * g - 4662 * b + 32768) >> 16) + 32768;\n\n                dPtr->x = static_cast<uint16_t>(std::min<int>(std::max<int>(u, 0), 65535));\n                dPtr->y = static_cast<uint16_t>(std::min<int>(std::max<int>(y, 0), 65535));\n                dPtr->z = static_cast<uint16_t>(std::min<int>(std::max<int>(v, 0), 65535));\n                dPtr->w = rgba.w;\n                ++dPtr;\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_YUY2:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            XMUBYTEN4 * __restrict dPtr = static_cast<XMUBYTEN4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUBYTEN4) + 1); icount += sizeof(XMUBYTEN4))\n            {\n                if (sPtr >= ePtr) break;\n\n                XMUBYTEN4 rgb1;\n                XMStoreUByteN4(&rgb1, *sPtr++);\n\n                // See AYUV\n                const int y0 = ((66 * rgb1.x + 129 * rgb1.y + 25 * rgb1.z + 128) >> 8) + 16;\n                const int u0 = ((-38 * rgb1.x - 74 * rgb1.y + 112 * rgb1.z + 128) >> 8) + 128;\n                const int v0 = ((112 * rgb1.x - 94 * rgb1.y - 18 * rgb1.z + 128) >> 8) + 128;\n\n                XMUBYTEN4 rgb2 = {};\n                if (sPtr < ePtr)\n                {\n                    XMStoreUByteN4(&rgb2, *sPtr++);\n                }\n\n                const int y1 = ((66 * rgb2.x + 129 * rgb2.y + 25 * rgb2.z + 128) >> 8) + 16;\n                const int u1 = ((-38 * rgb2.x - 74 * rgb2.y + 112 * rgb2.z + 128) >> 8) + 128;\n                const int v1 = ((112 * rgb2.x - 94 * rgb2.y - 18 * rgb2.z + 128) >> 8) + 128;\n\n                dPtr->x = static_cast<uint8_t>(std::min<int>(std::max<int>(y0, 0), 255));\n                dPtr->y = static_cast<uint8_t>(std::min<int>(std::max<int>((u0 + u1) >> 1, 0), 255));\n                dPtr->z = static_cast<uint8_t>(std::min<int>(std::max<int>(y1, 0), 255));\n                dPtr->w = static_cast<uint8_t>(std::min<int>(std::max<int>((v0 + v1) >> 1, 0), 255));\n                ++dPtr;\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_Y210:\n        // Same as Y216 with least significant 6 bits set to zero\n        if (size >= sizeof(XMUSHORTN4))\n        {\n            XMUSHORTN4 * __restrict dPtr = static_cast<XMUSHORTN4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4))\n            {\n                if (sPtr >= ePtr) break;\n\n                XMUDECN4 rgb1;\n                XMStoreUDecN4(&rgb1, *sPtr++);\n\n                // See Y410\n                int64_t r = rgb1.x;\n                int64_t g = rgb1.y;\n                int64_t b = rgb1.z;\n\n                const int y0 = static_cast<int>((16780 * r + 32942 * g + 6544 * b + 32768) >> 16) + 64;\n                const int u0 = static_cast<int>((-9683 * r - 19017 * g + 28700 * b + 32768) >> 16) + 512;\n                const int v0 = static_cast<int>((28700 * r - 24033 * g - 4667 * b + 32768) >> 16) + 512;\n\n                XMUDECN4 rgb2 = {};\n                if (sPtr < ePtr)\n                {\n                    XMStoreUDecN4(&rgb2, *sPtr++);\n                }\n\n                r = rgb2.x;\n                g = rgb2.y;\n                b = rgb2.z;\n\n                const int y1 = static_cast<int>((16780 * r + 32942 * g + 6544 * b + 32768) >> 16) + 64;\n                const int u1 = static_cast<int>((-9683 * r - 19017 * g + 28700 * b + 32768) >> 16) + 512;\n                const int v1 = static_cast<int>((28700 * r - 24033 * g - 4667 * b + 32768) >> 16) + 512;\n\n                dPtr->x = static_cast<uint16_t>(std::min<int>(std::max<int>(y0, 0), 1023) << 6);\n                dPtr->y = static_cast<uint16_t>(std::min<int>(std::max<int>((u0 + u1) >> 1, 0), 1023) << 6);\n                dPtr->z = static_cast<uint16_t>(std::min<int>(std::max<int>(y1, 0), 1023) << 6);\n                dPtr->w = static_cast<uint16_t>(std::min<int>(std::max<int>((v0 + v1) >> 1, 0), 1023) << 6);\n                ++dPtr;\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_Y216:\n        if (size >= sizeof(XMUSHORTN4))\n        {\n            XMUSHORTN4 * __restrict dPtr = static_cast<XMUSHORTN4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUSHORTN4) + 1); icount += sizeof(XMUSHORTN4))\n            {\n                if (sPtr >= ePtr) break;\n\n                XMUSHORTN4 rgb1;\n                XMStoreUShortN4(&rgb1, *sPtr++);\n\n                // See Y416\n                int64_t r = int64_t(rgb1.x);\n                int64_t g = int64_t(rgb1.y);\n                int64_t b = int64_t(rgb1.z);\n\n                const int y0 = static_cast<int>((16763 * r + 32910 * g + 6537 * b + 32768) >> 16) + 4096;\n                const int u0 = static_cast<int>((-9674 * r - 18998 * g + 28672 * b + 32768) >> 16) + 32768;\n                const int v0 = static_cast<int>((28672 * r - 24010 * g - 4662 * b + 32768) >> 16) + 32768;\n\n                XMUSHORTN4 rgb2 = {};\n                if (sPtr < ePtr)\n                {\n                    XMStoreUShortN4(&rgb2, *sPtr++);\n                }\n\n                r = int64_t(rgb2.x);\n                g = int64_t(rgb2.y);\n                b = int64_t(rgb2.z);\n\n                const int y1 = static_cast<int>((16763 * r + 32910 * g + 6537 * b + 32768) >> 16) + 4096;\n                const int u1 = static_cast<int>((-9674 * r - 18998 * g + 28672 * b + 32768) >> 16) + 32768;\n                const int v1 = static_cast<int>((28672 * r - 24010 * g - 4662 * b + 32768) >> 16) + 32768;\n\n                dPtr->x = static_cast<uint16_t>(std::min<int>(std::max<int>(y0, 0), 65535));\n                dPtr->y = static_cast<uint16_t>(std::min<int>(std::max<int>((u0 + u1) >> 1, 0), 65535));\n                dPtr->z = static_cast<uint16_t>(std::min<int>(std::max<int>(y1, 0), 65535));\n                dPtr->w = static_cast<uint16_t>(std::min<int>(std::max<int>((v0 + v1) >> 1, 0), 65535));\n                ++dPtr;\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B4G4R4A4_UNORM:\n        if (size >= sizeof(XMUNIBBLE4))\n        {\n            static const XMVECTORF32 s_Scale = { { { 15.f, 15.f, 15.f, 15.f } } };\n            XMUNIBBLE4 * __restrict dPtr = static_cast<XMUNIBBLE4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUNIBBLE4) + 1); icount += sizeof(XMUNIBBLE4))\n            {\n                if (sPtr >= ePtr) break;\n                XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(*sPtr++);\n                v = XMVectorMultiply(v, s_Scale);\n                XMStoreUNibble4(dPtr++, v);\n            }\n            return true;\n        }\n        return false;\n\n    case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT:\n        // Xbox One specific 7e3 format with alpha\n        if (size >= sizeof(XMUDECN4))\n        {\n            static const XMVECTORF32  Scale = { { { 1.0f, 1.0f, 1.0f, 3.0f } } };\n            static const XMVECTORF32  C = { { { 31.875f, 31.875f, 31.875f, 3.f } } };\n\n            XMUDECN4 * __restrict dPtr = static_cast<XMUDECN4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4))\n            {\n                if (sPtr >= ePtr) break;\n\n                XMVECTOR V = XMVectorMultiply(*sPtr++, Scale);\n                V = XMVectorClamp(V, g_XMZero, C);\n\n                XMFLOAT4A tmp;\n                XMStoreFloat4A(&tmp, V);\n\n                dPtr->x = FloatTo7e3(tmp.x);\n                dPtr->y = FloatTo7e3(tmp.y);\n                dPtr->z = FloatTo7e3(tmp.z);\n                dPtr->w = static_cast<uint32_t>(tmp.w);\n                ++dPtr;\n            }\n            return true;\n        }\n        return false;\n\n    case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT:\n        // Xbox One specific 6e4 format with alpha\n        if (size >= sizeof(XMUDECN4))\n        {\n            static const XMVECTORF32  Scale = { { { 1.0f, 1.0f, 1.0f, 3.0f } } };\n            static const XMVECTORF32  C = { { { 508.f, 508.f, 508.f, 3.f } } };\n\n            XMUDECN4 * __restrict dPtr = static_cast<XMUDECN4*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(XMUDECN4) + 1); icount += sizeof(XMUDECN4))\n            {\n                if (sPtr >= ePtr) break;\n\n                XMVECTOR V = XMVectorMultiply(*sPtr++, Scale);\n                V = XMVectorClamp(V, g_XMZero, C);\n\n                XMFLOAT4A tmp;\n                XMStoreFloat4A(&tmp, V);\n\n                dPtr->x = FloatTo6e4(tmp.x);\n                dPtr->y = FloatTo6e4(tmp.y);\n                dPtr->z = FloatTo6e4(tmp.z);\n                dPtr->w = static_cast<uint32_t>(tmp.w);\n                ++dPtr;\n            }\n            return true;\n        }\n        return false;\n\n    case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:\n        // Xbox One specific format\n        STORE_SCANLINE(XMXDECN4, XMStoreXDecN4)\n\n    case XBOX_DXGI_FORMAT_R4G4_UNORM:\n        // Xbox One specific format\n        if (size >= sizeof(uint8_t))\n        {\n            static const XMVECTORF32 s_Scale = { { { 15.f, 15.f, 0.f, 0.f } } };\n            uint8_t * __restrict dPtr = static_cast<uint8_t*>(pDestination);\n            for (size_t icount = 0; icount < (size - sizeof(uint8_t) + 1); icount += sizeof(uint8_t))\n            {\n                if (sPtr >= ePtr) break;\n                const XMVECTOR v = XMVectorMultiply(*sPtr++, s_Scale);\n\n                XMUNIBBLE4 nibble;\n                XMStoreUNibble4(&nibble, v);\n                *dPtr = static_cast<uint8_t>(nibble.v);\n                ++dPtr;\n            }\n            return true;\n        }\n        return false;\n\n        // We don't support the planar or palettized formats\n\n    default:\n        return false;\n    }\n}\n\n#undef STORE_SCANLINE\n\n\n//-------------------------------------------------------------------------------------\n// Convert DXGI image to/from GUID_WICPixelFormat128bppRGBAFloat (no range conversions)\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::Internal::ConvertToR32G32B32A32(const Image& srcImage, ScratchImage& image) noexcept\n{\n    if (!srcImage.pixels)\n        return E_POINTER;\n\n    HRESULT hr = image.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1);\n    if (FAILED(hr))\n        return hr;\n\n    const Image *img = image.GetImage(0, 0, 0);\n    if (!img)\n    {\n        image.Release();\n        return E_POINTER;\n    }\n\n    uint8_t* pDest = img->pixels;\n    if (!pDest)\n    {\n        image.Release();\n        return E_POINTER;\n    }\n\n    const uint8_t *pSrc = srcImage.pixels;\n    for (size_t h = 0; h < srcImage.height; ++h)\n    {\n        if (!LoadScanline(reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format))\n        {\n            image.Release();\n            return E_FAIL;\n        }\n\n        pSrc += srcImage.rowPitch;\n        pDest += img->rowPitch;\n    }\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::Internal::ConvertFromR32G32B32A32(const Image& srcImage, const Image& destImage) noexcept\n{\n    assert(srcImage.format == DXGI_FORMAT_R32G32B32A32_FLOAT);\n\n    if (!srcImage.pixels || !destImage.pixels)\n        return E_POINTER;\n\n    if (srcImage.width != destImage.width || srcImage.height != destImage.height)\n        return E_FAIL;\n\n    const uint8_t *pSrc = srcImage.pixels;\n    uint8_t* pDest = destImage.pixels;\n\n    for (size_t h = 0; h < srcImage.height; ++h)\n    {\n        if (!StoreScanline(pDest, destImage.rowPitch, destImage.format, reinterpret_cast<const XMVECTOR*>(pSrc), srcImage.width))\n            return E_FAIL;\n\n        pSrc += srcImage.rowPitch;\n        pDest += destImage.rowPitch;\n    }\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::Internal::ConvertFromR32G32B32A32(\n    const Image& srcImage,\n    DXGI_FORMAT format,\n    ScratchImage& image) noexcept\n{\n    if (!srcImage.pixels)\n        return E_POINTER;\n\n    HRESULT hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1);\n    if (FAILED(hr))\n        return hr;\n\n    const Image *img = image.GetImage(0, 0, 0);\n    if (!img)\n    {\n        image.Release();\n        return E_POINTER;\n    }\n\n    hr = ConvertFromR32G32B32A32(srcImage, *img);\n    if (FAILED(hr))\n    {\n        image.Release();\n        return hr;\n    }\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::Internal::ConvertFromR32G32B32A32(\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    DXGI_FORMAT format,\n    ScratchImage& result) noexcept\n{\n    if (!srcImages)\n        return E_POINTER;\n\n    result.Release();\n\n    assert(metadata.format == DXGI_FORMAT_R32G32B32A32_FLOAT);\n\n    TexMetadata mdata2 = metadata;\n    mdata2.format = format;\n    HRESULT hr = result.Initialize(mdata2);\n    if (FAILED(hr))\n        return hr;\n\n    if (nimages != result.GetImageCount())\n    {\n        result.Release();\n        return E_FAIL;\n    }\n\n    const Image* dest = result.GetImages();\n    if (!dest)\n    {\n        result.Release();\n        return E_POINTER;\n    }\n\n    for (size_t index = 0; index < nimages; ++index)\n    {\n        const Image& src = srcImages[index];\n        const Image& dst = dest[index];\n\n        assert(src.format == DXGI_FORMAT_R32G32B32A32_FLOAT);\n        assert(dst.format == format);\n\n        if (src.width != dst.width || src.height != dst.height)\n        {\n            result.Release();\n            return E_FAIL;\n        }\n\n        const uint8_t* pSrc = src.pixels;\n        uint8_t* pDest = dst.pixels;\n        if (!pSrc || !pDest)\n        {\n            result.Release();\n            return E_POINTER;\n        }\n\n        for (size_t h = 0; h < src.height; ++h)\n        {\n            if (!StoreScanline(pDest, dst.rowPitch, format, reinterpret_cast<const XMVECTOR*>(pSrc), src.width))\n            {\n                result.Release();\n                return E_FAIL;\n            }\n\n            pSrc += src.rowPitch;\n            pDest += dst.rowPitch;\n        }\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Convert DXGI image to/from GUID_WICPixelFormat64bppRGBAHalf (no range conversions)\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::Internal::ConvertToR16G16B16A16(const Image& srcImage, ScratchImage& image) noexcept\n{\n    if (!srcImage.pixels)\n        return E_POINTER;\n\n    HRESULT hr = image.Initialize2D(DXGI_FORMAT_R16G16B16A16_FLOAT, srcImage.width, srcImage.height, 1, 1);\n    if (FAILED(hr))\n        return hr;\n\n    auto scanline = make_AlignedArrayXMVECTOR(srcImage.width);\n    if (!scanline)\n    {\n        image.Release();\n        return E_OUTOFMEMORY;\n    }\n\n    const Image *img = image.GetImage(0, 0, 0);\n    if (!img)\n    {\n        image.Release();\n        return E_POINTER;\n    }\n\n    uint8_t* pDest = img->pixels;\n    if (!pDest)\n    {\n        image.Release();\n        return E_POINTER;\n    }\n\n    const uint8_t *pSrc = srcImage.pixels;\n    for (size_t h = 0; h < srcImage.height; ++h)\n    {\n        if (!LoadScanline(scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format))\n        {\n            image.Release();\n            return E_FAIL;\n        }\n\n        XMConvertFloatToHalfStream(\n            reinterpret_cast<HALF*>(pDest), sizeof(HALF),\n            reinterpret_cast<float*>(scanline.get()), sizeof(float),\n            srcImage.width * 4);\n\n        pSrc += srcImage.rowPitch;\n        pDest += img->rowPitch;\n    }\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::Internal::ConvertFromR16G16B16A16(const Image& srcImage, const Image& destImage) noexcept\n{\n    assert(srcImage.format == DXGI_FORMAT_R16G16B16A16_FLOAT);\n\n    if (!srcImage.pixels || !destImage.pixels)\n        return E_POINTER;\n\n    if (srcImage.width != destImage.width || srcImage.height != destImage.height)\n        return E_FAIL;\n\n    auto scanline = make_AlignedArrayXMVECTOR(srcImage.width);\n    if (!scanline)\n        return E_OUTOFMEMORY;\n\n    const uint8_t *pSrc = srcImage.pixels;\n    uint8_t* pDest = destImage.pixels;\n\n    for (size_t h = 0; h < srcImage.height; ++h)\n    {\n        XMConvertHalfToFloatStream(\n            reinterpret_cast<float*>(scanline.get()), sizeof(float),\n            reinterpret_cast<const HALF*>(pSrc), sizeof(HALF),\n            srcImage.width * 4);\n\n        if (!StoreScanline(pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width))\n            return E_FAIL;\n\n        pSrc += srcImage.rowPitch;\n        pDest += destImage.rowPitch;\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Convert from Linear RGB to sRGB\n//\n// if C_linear <= 0.0031308 -> C_srgb = 12.92 * C_linear\n// if C_linear >  0.0031308 -> C_srgb = ( 1 + a ) * pow( C_Linear, 1 / 2.4 ) - a\n//                             where a = 0.055\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nbool DirectX::Internal::StoreScanlineLinear(\n    void* pDestination,\n    size_t size,\n    DXGI_FORMAT format,\n    XMVECTOR* pSource,\n    size_t count,\n    TEX_FILTER_FLAGS flags,\n    float threshold) noexcept\n{\n    if (!pSource || !count)\n        return false;\n\n    assert((reinterpret_cast<uintptr_t>(pSource) & 0xF) == 0);\n\n    switch (format)\n    {\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n        flags |= TEX_FILTER_SRGB;\n        break;\n\n    case DXGI_FORMAT_R32G32B32A32_FLOAT:\n    case DXGI_FORMAT_R32G32B32_FLOAT:\n    case DXGI_FORMAT_R16G16B16A16_FLOAT:\n    case DXGI_FORMAT_R16G16B16A16_UNORM:\n    case DXGI_FORMAT_R32G32_FLOAT:\n    case DXGI_FORMAT_R10G10B10A2_UNORM:\n    case DXGI_FORMAT_R11G11B10_FLOAT:\n    case DXGI_FORMAT_R8G8B8A8_UNORM:\n    case DXGI_FORMAT_R16G16_FLOAT:\n    case DXGI_FORMAT_R16G16_UNORM:\n    case DXGI_FORMAT_R32_FLOAT:\n    case DXGI_FORMAT_R8G8_UNORM:\n    case DXGI_FORMAT_R16_FLOAT:\n    case DXGI_FORMAT_R16_UNORM:\n    case DXGI_FORMAT_R8_UNORM:\n    case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:\n    case DXGI_FORMAT_R8G8_B8G8_UNORM:\n    case DXGI_FORMAT_G8R8_G8B8_UNORM:\n    case DXGI_FORMAT_B5G6R5_UNORM:\n    case DXGI_FORMAT_B5G5R5A1_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_UNORM:\n    case DXGI_FORMAT_B8G8R8X8_UNORM:\n    case DXGI_FORMAT_B4G4R4A4_UNORM:\n        break;\n\n    default:\n        // can't treat A8, XR, Depth, SNORM, UINT, or SINT as sRGB\n        flags &= ~TEX_FILTER_SRGB;\n        break;\n    }\n\n    // sRGB output processing (Linear RGB -> sRGB)\n    if (flags & TEX_FILTER_SRGB_OUT)\n    {\n        // To avoid the need for another temporary scanline buffer, we allow this function to overwrite the source buffer in-place\n        // Given the intended usage in the filtering routines, this is not a problem.\n        XMVECTOR* ptr = pSource;\n        for (size_t i = 0; i < count; ++i, ++ptr)\n        {\n            *ptr = XMColorRGBToSRGB(*ptr);\n        }\n    }\n\n    return StoreScanline(pDestination, size, format, pSource, count, threshold);\n}\n\n\n//-------------------------------------------------------------------------------------\n// Convert from sRGB to Linear RGB\n//\n// if C_srgb <= 0.04045 -> C_linear = C_srgb / 12.92\n// if C_srgb >  0.04045 -> C_linear = pow( ( C_srgb + a ) / ( 1 + a ), 2.4 )\n//                         where a = 0.055\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nbool DirectX::Internal::LoadScanlineLinear(\n    XMVECTOR* pDestination,\n    size_t count,\n    const void* pSource,\n    size_t size,\n    DXGI_FORMAT format,\n    TEX_FILTER_FLAGS flags) noexcept\n{\n    switch (format)\n    {\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n        flags |= TEX_FILTER_SRGB;\n        break;\n\n    case DXGI_FORMAT_R32G32B32A32_FLOAT:\n    case DXGI_FORMAT_R32G32B32_FLOAT:\n    case DXGI_FORMAT_R16G16B16A16_FLOAT:\n    case DXGI_FORMAT_R16G16B16A16_UNORM:\n    case DXGI_FORMAT_R32G32_FLOAT:\n    case DXGI_FORMAT_R10G10B10A2_UNORM:\n    case DXGI_FORMAT_R11G11B10_FLOAT:\n    case DXGI_FORMAT_R8G8B8A8_UNORM:\n    case DXGI_FORMAT_R16G16_FLOAT:\n    case DXGI_FORMAT_R16G16_UNORM:\n    case DXGI_FORMAT_R32_FLOAT:\n    case DXGI_FORMAT_R8G8_UNORM:\n    case DXGI_FORMAT_R16_FLOAT:\n    case DXGI_FORMAT_R16_UNORM:\n    case DXGI_FORMAT_R8_UNORM:\n    case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:\n    case DXGI_FORMAT_R8G8_B8G8_UNORM:\n    case DXGI_FORMAT_G8R8_G8B8_UNORM:\n    case DXGI_FORMAT_B5G6R5_UNORM:\n    case DXGI_FORMAT_B5G5R5A1_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_UNORM:\n    case DXGI_FORMAT_B8G8R8X8_UNORM:\n    case DXGI_FORMAT_B4G4R4A4_UNORM:\n        break;\n\n    default:\n        // can't treat A8, XR, Depth, SNORM, UINT, or SINT as sRGB\n        flags &= ~TEX_FILTER_SRGB;\n        break;\n    }\n\n    if (LoadScanline(pDestination, count, pSource, size, format))\n    {\n        // sRGB input processing (sRGB -> Linear RGB)\n        if (flags & TEX_FILTER_SRGB_IN)\n        {\n            XMVECTOR* ptr = pDestination;\n            for (size_t i = 0; i < count; ++i, ++ptr)\n            {\n                *ptr = XMColorSRGBToRGB(*ptr);\n            }\n        }\n\n        return true;\n    }\n\n    return false;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Convert scanline based on source/target formats\n//-------------------------------------------------------------------------------------\nnamespace\n{\n    struct ConvertData\n    {\n        DXGI_FORMAT format;\n        size_t      datasize;\n        uint32_t    flags;\n    };\n\n    const ConvertData g_ConvertTable[] =\n    {\n        { DXGI_FORMAT_R32G32B32A32_FLOAT,           32, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R32G32B32A32_UINT,            32, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R32G32B32A32_SINT,            32, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R32G32B32_FLOAT,              32, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B },\n        { DXGI_FORMAT_R32G32B32_UINT,               32, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B },\n        { DXGI_FORMAT_R32G32B32_SINT,               32, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B },\n        { DXGI_FORMAT_R16G16B16A16_FLOAT,           16, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R16G16B16A16_UNORM,           16, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R16G16B16A16_UINT,            16, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R16G16B16A16_SNORM,           16, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R16G16B16A16_SINT,            16, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R32G32_FLOAT,                 32, CONVF_FLOAT | CONVF_R | CONVF_G },\n        { DXGI_FORMAT_R32G32_UINT,                  32, CONVF_UINT | CONVF_R | CONVF_G  },\n        { DXGI_FORMAT_R32G32_SINT,                  32, CONVF_SINT | CONVF_R | CONVF_G  },\n        { DXGI_FORMAT_D32_FLOAT_S8X24_UINT,         32, CONVF_FLOAT | CONVF_DEPTH | CONVF_STENCIL },\n        { DXGI_FORMAT_R10G10B10A2_UNORM,            10, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R10G10B10A2_UINT,             10, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R11G11B10_FLOAT,              10, CONVF_FLOAT | CONVF_POS_ONLY | CONVF_R | CONVF_G | CONVF_B },\n        { DXGI_FORMAT_R8G8B8A8_UNORM,                8, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,           8, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R8G8B8A8_UINT,                 8, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R8G8B8A8_SNORM,                8, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R8G8B8A8_SINT,                 8, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_R16G16_FLOAT,                 16, CONVF_FLOAT | CONVF_R | CONVF_G },\n        { DXGI_FORMAT_R16G16_UNORM,                 16, CONVF_UNORM | CONVF_R | CONVF_G },\n        { DXGI_FORMAT_R16G16_UINT,                  16, CONVF_UINT | CONVF_R | CONVF_G },\n        { DXGI_FORMAT_R16G16_SNORM,                 16, CONVF_SNORM | CONVF_R | CONVF_G },\n        { DXGI_FORMAT_R16G16_SINT,                  16, CONVF_SINT | CONVF_R | CONVF_G },\n        { DXGI_FORMAT_D32_FLOAT,                    32, CONVF_FLOAT | CONVF_DEPTH },\n        { DXGI_FORMAT_R32_FLOAT,                    32, CONVF_FLOAT | CONVF_R },\n        { DXGI_FORMAT_R32_UINT,                     32, CONVF_UINT | CONVF_R },\n        { DXGI_FORMAT_R32_SINT,                     32, CONVF_SINT | CONVF_R },\n        { DXGI_FORMAT_D24_UNORM_S8_UINT,            32, CONVF_UNORM | CONVF_DEPTH | CONVF_STENCIL },\n        { DXGI_FORMAT_R8G8_UNORM,                    8, CONVF_UNORM | CONVF_R | CONVF_G },\n        { DXGI_FORMAT_R8G8_UINT,                     8, CONVF_UINT | CONVF_R | CONVF_G },\n        { DXGI_FORMAT_R8G8_SNORM,                    8, CONVF_SNORM | CONVF_R | CONVF_G },\n        { DXGI_FORMAT_R8G8_SINT,                     8, CONVF_SINT | CONVF_R | CONVF_G },\n        { DXGI_FORMAT_R16_FLOAT,                    16, CONVF_FLOAT | CONVF_R },\n        { DXGI_FORMAT_D16_UNORM,                    16, CONVF_UNORM | CONVF_DEPTH },\n        { DXGI_FORMAT_R16_UNORM,                    16, CONVF_UNORM | CONVF_R },\n        { DXGI_FORMAT_R16_UINT,                     16, CONVF_UINT | CONVF_R },\n        { DXGI_FORMAT_R16_SNORM,                    16, CONVF_SNORM | CONVF_R },\n        { DXGI_FORMAT_R16_SINT,                     16, CONVF_SINT | CONVF_R },\n        { DXGI_FORMAT_R8_UNORM,                      8, CONVF_UNORM | CONVF_R },\n        { DXGI_FORMAT_R8_UINT,                       8, CONVF_UINT | CONVF_R },\n        { DXGI_FORMAT_R8_SNORM,                      8, CONVF_SNORM | CONVF_R },\n        { DXGI_FORMAT_R8_SINT,                       8, CONVF_SINT | CONVF_R },\n        { DXGI_FORMAT_A8_UNORM,                      8, CONVF_UNORM | CONVF_A },\n        { DXGI_FORMAT_R1_UNORM,                      1, CONVF_UNORM | CONVF_R },\n        { DXGI_FORMAT_R9G9B9E5_SHAREDEXP,            9, CONVF_FLOAT | CONVF_SHAREDEXP | CONVF_POS_ONLY | CONVF_R | CONVF_G | CONVF_B },\n        { DXGI_FORMAT_R8G8_B8G8_UNORM,               8, CONVF_UNORM | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },\n        { DXGI_FORMAT_G8R8_G8B8_UNORM,               8, CONVF_UNORM | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },\n        { DXGI_FORMAT_BC1_UNORM,                     8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_BC1_UNORM_SRGB,                8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_BC2_UNORM,                     8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_BC2_UNORM_SRGB,                8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_BC3_UNORM,                     8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_BC3_UNORM_SRGB,                8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_BC4_UNORM,                     8, CONVF_UNORM | CONVF_BC | CONVF_R },\n        { DXGI_FORMAT_BC4_SNORM,                     8, CONVF_SNORM | CONVF_BC | CONVF_R },\n        { DXGI_FORMAT_BC5_UNORM,                     8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G },\n        { DXGI_FORMAT_BC5_SNORM,                     8, CONVF_SNORM | CONVF_BC | CONVF_R | CONVF_G },\n        { DXGI_FORMAT_B5G6R5_UNORM,                  5, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B },\n        { DXGI_FORMAT_B5G5R5A1_UNORM,                5, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_B8G8R8A8_UNORM,                8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_B8G8R8X8_UNORM,                8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B },\n        { DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM,   10, CONVF_UNORM | CONVF_XR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,           8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_B8G8R8X8_UNORM_SRGB,           8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B },\n        { DXGI_FORMAT_BC6H_UF16,                    16, CONVF_FLOAT | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_BC6H_SF16,                    16, CONVF_FLOAT | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_BC7_UNORM,                     8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_BC7_UNORM_SRGB,                8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_AYUV,                          8, CONVF_UNORM | CONVF_YUV | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_Y410,                         10, CONVF_UNORM | CONVF_YUV | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_Y416,                         16, CONVF_UNORM | CONVF_YUV | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { DXGI_FORMAT_YUY2,                          8, CONVF_UNORM | CONVF_YUV | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },\n        { DXGI_FORMAT_Y210,                         10, CONVF_UNORM | CONVF_YUV | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },\n        { DXGI_FORMAT_Y216,                         16, CONVF_UNORM | CONVF_YUV | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },\n        { DXGI_FORMAT_B4G4R4A4_UNORM,                4, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT,  10, CONVF_FLOAT | CONVF_POS_ONLY | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT,  10, CONVF_FLOAT | CONVF_POS_ONLY | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM,10, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },\n        { XBOX_DXGI_FORMAT_R4G4_UNORM,               4, CONVF_UNORM | CONVF_R | CONVF_G },\n    };\n\n#pragma prefast( suppress : 25004, \"Signature must match bsearch\" );\n    int __cdecl ConvertCompare(const void* ptr1, const void *ptr2) noexcept\n    {\n        auto p1 = static_cast<const ConvertData*>(ptr1);\n        auto p2 = static_cast<const ConvertData*>(ptr2);\n        if (p1->format == p2->format) return 0;\n        else return (p1->format < p2->format) ? -1 : 1;\n    }\n}\n\n_Use_decl_annotations_\nuint32_t DirectX::Internal::GetConvertFlags(DXGI_FORMAT format) noexcept\n{\n#ifdef _DEBUG\n    // Ensure conversion table is in ascending order\n    assert(std::size(g_ConvertTable) > 0);\n    DXGI_FORMAT lastvalue = g_ConvertTable[0].format;\n    for (size_t index = 1; index < std::size(g_ConvertTable); ++index)\n    {\n        assert(g_ConvertTable[index].format > lastvalue);\n        lastvalue = g_ConvertTable[index].format;\n    }\n#endif\n\n    ConvertData key = { format, 0, 0 };\n    auto in = reinterpret_cast<const ConvertData*>(bsearch(&key, g_ConvertTable, std::size(g_ConvertTable), sizeof(ConvertData),\n        ConvertCompare));\n    return (in) ? in->flags : 0;\n}\n\n_Use_decl_annotations_\nvoid DirectX::Internal::ConvertScanline(\n    XMVECTOR* pBuffer,\n    size_t count,\n    DXGI_FORMAT outFormat,\n    DXGI_FORMAT inFormat,\n    TEX_FILTER_FLAGS flags) noexcept\n{\n    assert(pBuffer && count > 0 && ((reinterpret_cast<uintptr_t>(pBuffer) & 0xF) == 0));\n    assert(IsValid(outFormat) && !IsTypeless(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat));\n    assert(IsValid(inFormat) && !IsTypeless(inFormat) && !IsPlanar(inFormat) && !IsPalettized(inFormat));\n\n    if (!pBuffer)\n        return;\n\n#ifdef _DEBUG\n    // Ensure conversion table is in ascending order\n    assert(std::size(g_ConvertTable) > 0);\n    DXGI_FORMAT lastvalue = g_ConvertTable[0].format;\n    for (size_t index = 1; index < std::size(g_ConvertTable); ++index)\n    {\n        assert(g_ConvertTable[index].format > lastvalue);\n        lastvalue = g_ConvertTable[index].format;\n    }\n#endif\n\n    // Determine conversion details about source and dest formats\n    ConvertData key = { inFormat, 0, 0 };\n    auto in = reinterpret_cast<const ConvertData*>(\n        bsearch(&key, g_ConvertTable, std::size(g_ConvertTable), sizeof(ConvertData), ConvertCompare));\n    key.format = outFormat;\n    auto out = reinterpret_cast<const ConvertData*>(\n        bsearch(&key, g_ConvertTable, std::size(g_ConvertTable), sizeof(ConvertData), ConvertCompare));\n    if (!in || !out)\n    {\n        assert(false);\n        return;\n    }\n\n    assert(GetConvertFlags(inFormat) == in->flags);\n    assert(GetConvertFlags(outFormat) == out->flags);\n\n    // Handle SRGB filtering modes\n    switch (inFormat)\n    {\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n    case DXGI_FORMAT_BC1_UNORM_SRGB:\n    case DXGI_FORMAT_BC2_UNORM_SRGB:\n    case DXGI_FORMAT_BC3_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n        flags |= TEX_FILTER_SRGB_IN;\n        break;\n\n    case DXGI_FORMAT_A8_UNORM:\n    case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:\n        flags &= ~TEX_FILTER_SRGB_IN;\n        break;\n\n    default:\n        break;\n    }\n\n    switch (outFormat)\n    {\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n    case DXGI_FORMAT_BC1_UNORM_SRGB:\n    case DXGI_FORMAT_BC2_UNORM_SRGB:\n    case DXGI_FORMAT_BC3_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n        flags |= TEX_FILTER_SRGB_OUT;\n        break;\n\n    case DXGI_FORMAT_A8_UNORM:\n    case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:\n        flags &= ~TEX_FILTER_SRGB_OUT;\n        break;\n\n    default:\n        break;\n    }\n\n    if ((flags & (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT))\n    {\n        flags &= ~(TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT);\n    }\n\n    // sRGB input processing (sRGB -> Linear RGB)\n    if (flags & TEX_FILTER_SRGB_IN)\n    {\n        if (!(in->flags & CONVF_DEPTH) && ((in->flags & CONVF_FLOAT) || (in->flags & CONVF_UNORM)))\n        {\n            XMVECTOR* ptr = pBuffer;\n            for (size_t i = 0; i < count; ++i, ++ptr)\n            {\n                *ptr = XMColorSRGBToRGB(*ptr);\n            }\n        }\n    }\n\n    // Handle conversion special cases\n    const uint32_t diffFlags = in->flags ^ out->flags;\n    if (diffFlags != 0)\n    {\n        if (diffFlags & CONVF_DEPTH)\n        {\n            //--- Depth conversions ---\n            if (in->flags & CONVF_DEPTH)\n            {\n                // CONVF_DEPTH -> !CONVF_DEPTH\n                if (in->flags & CONVF_STENCIL)\n                {\n                    // Stencil -> Alpha\n                    static const XMVECTORF32 S = { { { 1.f, 1.f, 1.f, 255.f } } };\n\n                    if (out->flags & CONVF_UNORM)\n                    {\n                        // UINT -> UNORM\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            XMVECTOR v1 = XMVectorSplatY(v);\n                            v1 = XMVectorClamp(v1, g_XMZero, S);\n                            v1 = XMVectorDivide(v1, S);\n                            *ptr++ = XMVectorSelect(v1, v, g_XMSelect1110);\n                        }\n                    }\n                    else if (out->flags & CONVF_SNORM)\n                    {\n                        // UINT -> SNORM\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            XMVECTOR v1 = XMVectorSplatY(v);\n                            v1 = XMVectorClamp(v1, g_XMZero, S);\n                            v1 = XMVectorDivide(v1, S);\n                            v1 = XMVectorMultiplyAdd(v1, g_XMTwo, g_XMNegativeOne);\n                            *ptr++ = XMVectorSelect(v1, v, g_XMSelect1110);\n                        }\n                    }\n                    else\n                    {\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            const XMVECTOR v1 = XMVectorSplatY(v);\n                            *ptr++ = XMVectorSelect(v1, v, g_XMSelect1110);\n                        }\n                    }\n                }\n\n                // Depth -> RGB\n                if ((out->flags & CONVF_UNORM) && (in->flags & CONVF_FLOAT))\n                {\n                    // Depth FLOAT -> UNORM\n                    XMVECTOR* ptr = pBuffer;\n                    for (size_t i = 0; i < count; ++i)\n                    {\n                        const XMVECTOR v = *ptr;\n                        XMVECTOR v1 = XMVectorSaturate(v);\n                        v1 = XMVectorSplatX(v1);\n                        *ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);\n                    }\n                }\n                else if (out->flags & CONVF_SNORM)\n                {\n                    if (in->flags & CONVF_UNORM)\n                    {\n                        // Depth UNORM -> SNORM\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            XMVECTOR v1 = XMVectorMultiplyAdd(v, g_XMTwo, g_XMNegativeOne);\n                            v1 = XMVectorSplatX(v1);\n                            *ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);\n                        }\n                    }\n                    else\n                    {\n                        // Depth FLOAT -> SNORM\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            XMVECTOR v1 = XMVectorClamp(v, g_XMNegativeOne, g_XMOne);\n                            v1 = XMVectorSplatX(v1);\n                            *ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);\n                        }\n                    }\n                }\n                else\n                {\n                    XMVECTOR* ptr = pBuffer;\n                    for (size_t i = 0; i < count; ++i)\n                    {\n                        const XMVECTOR v = *ptr;\n                        const XMVECTOR v1 = XMVectorSplatX(v);\n                        *ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);\n                    }\n                }\n            }\n            else\n            {\n                // !CONVF_DEPTH -> CONVF_DEPTH\n\n                // RGB -> Depth (red channel)\n                switch (flags & (TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE))\n                {\n                case TEX_FILTER_RGB_COPY_GREEN:\n                    {\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            const XMVECTOR v1 = XMVectorSplatY(v);\n                            *ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);\n                        }\n                    }\n                    break;\n\n                case TEX_FILTER_RGB_COPY_BLUE:\n                    {\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            const XMVECTOR v1 = XMVectorSplatZ(v);\n                            *ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);\n                        }\n                    }\n                    break;\n\n                default:\n                    if ((in->flags & CONVF_UNORM) && ((in->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G | CONVF_B)))\n                    {\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            const XMVECTOR v1 = XMVector3Dot(v, g_Grayscale);\n                            *ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);\n                        }\n                        break;\n                    }\n\n                #if (__cplusplus >= 201703L)\n                    [[fallthrough]];\n                #elif defined(__clang__)\n                    [[clang::fallthrough]];\n                #elif defined(_MSC_VER)\n                    __fallthrough;\n                #endif\n\n                case TEX_FILTER_RGB_COPY_RED:\n                    {\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            const XMVECTOR v1 = XMVectorSplatX(v);\n                            *ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);\n                        }\n                    }\n                    break;\n                }\n\n                // Finialize type conversion for depth (red channel)\n                if (out->flags & CONVF_UNORM)\n                {\n                    if (in->flags & CONVF_SNORM)\n                    {\n                        // SNORM -> UNORM\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            const XMVECTOR v1 = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf);\n                            *ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);\n                        }\n                    }\n                    else if (in->flags & CONVF_FLOAT)\n                    {\n                        // FLOAT -> UNORM\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            const XMVECTOR v1 = XMVectorSaturate(v);\n                            *ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);\n                        }\n                    }\n                }\n\n                if (out->flags & CONVF_STENCIL)\n                {\n                    // Alpha -> Stencil (green channel)\n                    static const XMVECTORU32 select0100 = { { { XM_SELECT_0, XM_SELECT_1, XM_SELECT_0, XM_SELECT_0 } } };\n                    static const XMVECTORF32 S = { { { 255.f, 255.f, 255.f, 255.f } } };\n\n                    if (in->flags & CONVF_UNORM)\n                    {\n                        // UNORM -> UINT\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            XMVECTOR v1 = XMVectorMultiply(v, S);\n                            v1 = XMVectorSplatW(v1);\n                            *ptr++ = XMVectorSelect(v, v1, select0100);\n                        }\n                    }\n                    else if (in->flags & CONVF_SNORM)\n                    {\n                        // SNORM -> UINT\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            XMVECTOR v1 = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf);\n                            v1 = XMVectorMultiply(v1, S);\n                            v1 = XMVectorSplatW(v1);\n                            *ptr++ = XMVectorSelect(v, v1, select0100);\n                        }\n                    }\n                    else\n                    {\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            const XMVECTOR v1 = XMVectorSplatW(v);\n                            *ptr++ = XMVectorSelect(v, v1, select0100);\n                        }\n                    }\n                }\n            }\n        }\n        else if (out->flags & CONVF_DEPTH)\n        {\n            // CONVF_DEPTH -> CONVF_DEPTH\n            if (diffFlags & CONVF_FLOAT)\n            {\n                if (in->flags & CONVF_FLOAT)\n                {\n                    // FLOAT -> UNORM depth, preserve stencil\n                    XMVECTOR* ptr = pBuffer;\n                    for (size_t i = 0; i < count; ++i)\n                    {\n                        const XMVECTOR v = *ptr;\n                        const XMVECTOR v1 = XMVectorSaturate(v);\n                        *ptr++ = XMVectorSelect(v, v1, g_XMSelect1000);\n                    }\n                }\n            }\n        }\n        else if (out->flags & CONVF_UNORM)\n        {\n            //--- Converting to a UNORM ---\n            if (in->flags & CONVF_SNORM)\n            {\n                // SNORM -> UNORM\n                XMVECTOR* ptr = pBuffer;\n                for (size_t i = 0; i < count; ++i)\n                {\n                    const XMVECTOR v = *ptr;\n                    *ptr++ = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf);\n                }\n            }\n            else if (in->flags & CONVF_FLOAT)\n            {\n                XMVECTOR* ptr = pBuffer;\n                if (!(in->flags & CONVF_POS_ONLY) && (flags & TEX_FILTER_FLOAT_X2BIAS))\n                {\n                    // FLOAT -> UNORM (x2 bias)\n                    for (size_t i = 0; i < count; ++i)\n                    {\n                        XMVECTOR v = *ptr;\n                        v = XMVectorClamp(v, g_XMNegativeOne, g_XMOne);\n                        *ptr++ = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf);\n                    }\n                }\n                else\n                {\n                    // FLOAT -> UNORM\n                    for (size_t i = 0; i < count; ++i)\n                    {\n                        const XMVECTOR v = *ptr;\n                        *ptr++ = XMVectorSaturate(v);\n                    }\n                }\n            }\n        }\n        else if (out->flags & CONVF_SNORM)\n        {\n            //--- Converting to a SNORM ---\n            if (in->flags & CONVF_UNORM)\n            {\n                // UNORM -> SNORM\n                XMVECTOR* ptr = pBuffer;\n                for (size_t i = 0; i < count; ++i)\n                {\n                    const XMVECTOR v = *ptr;\n                    *ptr++ = XMVectorMultiplyAdd(v, g_XMTwo, g_XMNegativeOne);\n                }\n            }\n            else if (in->flags & CONVF_FLOAT)\n            {\n                XMVECTOR* ptr = pBuffer;\n                if ((in->flags & CONVF_POS_ONLY) && (flags & TEX_FILTER_FLOAT_X2BIAS))\n                {\n                    // FLOAT (positive only, x2 bias) -> SNORM\n                    for (size_t i = 0; i < count; ++i)\n                    {\n                        XMVECTOR v = *ptr;\n                        v = XMVectorSaturate(v);\n                        *ptr++ = XMVectorMultiplyAdd(v, g_XMTwo, g_XMNegativeOne);\n                    }\n                }\n                else\n                {\n                    // FLOAT -> SNORM\n                    for (size_t i = 0; i < count; ++i)\n                    {\n                        const XMVECTOR v = *ptr;\n                        *ptr++ = XMVectorClamp(v, g_XMNegativeOne, g_XMOne);\n                    }\n                }\n            }\n        }\n        else if (diffFlags & CONVF_UNORM)\n        {\n            //--- Converting from a UNORM ---\n            assert(in->flags & CONVF_UNORM);\n            if (out->flags & CONVF_FLOAT)\n            {\n                if (!(out->flags & CONVF_POS_ONLY) && (flags & TEX_FILTER_FLOAT_X2BIAS))\n                {\n                    // UNORM (x2 bias) -> FLOAT\n                    XMVECTOR* ptr = pBuffer;\n                    for (size_t i = 0; i < count; ++i)\n                    {\n                        const XMVECTOR v = *ptr;\n                        *ptr++ = XMVectorMultiplyAdd(v, g_XMTwo, g_XMNegativeOne);\n                    }\n                }\n            }\n        }\n        else if (diffFlags & CONVF_POS_ONLY)\n        {\n            if (flags & TEX_FILTER_FLOAT_X2BIAS)\n            {\n                if (in->flags & CONVF_POS_ONLY)\n                {\n                    if (out->flags & CONVF_FLOAT)\n                    {\n                        // FLOAT (positive only, x2 bias) -> FLOAT\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            XMVECTOR v = *ptr;\n                            v = XMVectorSaturate(v);\n                            *ptr++ = XMVectorMultiplyAdd(v, g_XMTwo, g_XMNegativeOne);\n                        }\n                    }\n                }\n                else if (out->flags & CONVF_POS_ONLY)\n                {\n                    if (in->flags & CONVF_FLOAT)\n                    {\n                        // FLOAT -> FLOAT (positive only, x2 bias)\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            XMVECTOR v = *ptr;\n                            v = XMVectorClamp(v, g_XMNegativeOne, g_XMOne);\n                            *ptr++ = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf);\n                        }\n                    }\n                    else if (in->flags & CONVF_SNORM)\n                    {\n                        // SNORM -> FLOAT (positive only, x2 bias)\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            *ptr++ = XMVectorMultiplyAdd(v, g_XMOneHalf, g_XMOneHalf);\n                        }\n                    }\n                }\n            }\n        }\n\n        // !CONVF_A -> CONVF_A is handled because LoadScanline ensures alpha defaults to 1.0 for no-alpha formats\n\n        // CONVF_PACKED cases are handled because LoadScanline/StoreScanline handles packing/unpacking\n\n        if (((out->flags & CONVF_RGBA_MASK) == CONVF_A) && !(in->flags & CONVF_A))\n        {\n            // !CONVF_A -> A format\n            switch (flags & (TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE))\n            {\n            case TEX_FILTER_RGB_COPY_GREEN:\n                {\n                    XMVECTOR* ptr = pBuffer;\n                    for (size_t i = 0; i < count; ++i)\n                    {\n                        const XMVECTOR v = *ptr;\n                        *ptr++ = XMVectorSplatY(v);\n                    }\n                }\n                break;\n\n            case TEX_FILTER_RGB_COPY_BLUE:\n                {\n                    XMVECTOR* ptr = pBuffer;\n                    for (size_t i = 0; i < count; ++i)\n                    {\n                        const XMVECTOR v = *ptr;\n                        *ptr++ = XMVectorSplatZ(v);\n                    }\n                }\n                break;\n\n            default:\n                if ((in->flags & CONVF_UNORM) && ((in->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G | CONVF_B)))\n                {\n                    XMVECTOR* ptr = pBuffer;\n                    for (size_t i = 0; i < count; ++i)\n                    {\n                        const XMVECTOR v = *ptr;\n                        *ptr++ = XMVector3Dot(v, g_Grayscale);\n                    }\n                    break;\n                }\n\n            #if (__cplusplus >= 201703L)\n                [[fallthrough]];\n            #elif defined(__clang__)\n                [[clang::fallthrough]];\n            #elif defined(_MSC_VER)\n                __fallthrough;\n            #endif\n\n            case TEX_FILTER_RGB_COPY_RED:\n                {\n                    XMVECTOR* ptr = pBuffer;\n                    for (size_t i = 0; i < count; ++i)\n                    {\n                        const XMVECTOR v = *ptr;\n                        *ptr++ = XMVectorSplatX(v);\n                    }\n                }\n                break;\n            }\n        }\n        else if (((in->flags & CONVF_RGBA_MASK) == CONVF_A) && !(out->flags & CONVF_A))\n        {\n            // A format -> !CONVF_A\n            XMVECTOR* ptr = pBuffer;\n            for (size_t i = 0; i < count; ++i)\n            {\n                const XMVECTOR v = *ptr;\n                *ptr++ = XMVectorSplatW(v);\n            }\n        }\n        else if ((in->flags & CONVF_RGB_MASK) == CONVF_R)\n        {\n            if ((out->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G | CONVF_B))\n            {\n                // R format -> RGB format\n                XMVECTOR* ptr = pBuffer;\n                for (size_t i = 0; i < count; ++i)\n                {\n                    const XMVECTOR v = *ptr;\n                    const XMVECTOR v1 = XMVectorSplatX(v);\n                    *ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);\n                }\n            }\n            else if ((out->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G))\n            {\n                // R format -> RG format\n                XMVECTOR* ptr = pBuffer;\n                for (size_t i = 0; i < count; ++i)\n                {\n                    const XMVECTOR v = *ptr;\n                    const XMVECTOR v1 = XMVectorSplatX(v);\n                    *ptr++ = XMVectorSelect(v, v1, g_XMSelect1100);\n                }\n            }\n        }\n        else if ((in->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G | CONVF_B))\n        {\n            if ((out->flags & CONVF_RGB_MASK) == CONVF_R)\n            {\n                // RGB format -> R format\n                switch (flags & (TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE))\n                {\n                case TEX_FILTER_RGB_COPY_GREEN:\n                    {\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            const XMVECTOR v1 = XMVectorSplatY(v);\n                            *ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);\n                        }\n                    }\n                    break;\n\n                case TEX_FILTER_RGB_COPY_BLUE:\n                    {\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            const XMVECTOR v1 = XMVectorSplatZ(v);\n                            *ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);\n                        }\n                    }\n                    break;\n\n                default:\n                    if (in->flags & CONVF_UNORM)\n                    {\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            const XMVECTOR v1 = XMVector3Dot(v, g_Grayscale);\n                            *ptr++ = XMVectorSelect(v, v1, g_XMSelect1110);\n                        }\n                        break;\n                    }\n\n                #if (__cplusplus >= 201703L)\n                    [[fallthrough]];\n                #elif defined(__clang__)\n                    [[clang::fallthrough]];\n                #elif defined(_MSC_VER)\n                    __fallthrough;\n                #endif\n\n                case TEX_FILTER_RGB_COPY_RED:\n                    // Leave data unchanged and the store will handle this...\n                    break;\n                }\n            }\n            else if ((out->flags & CONVF_RGB_MASK) == (CONVF_R | CONVF_G))\n            {\n                // RGB format -> RG format\n                switch (static_cast<int>(flags & (TEX_FILTER_RGB_COPY_RED | TEX_FILTER_RGB_COPY_GREEN | TEX_FILTER_RGB_COPY_BLUE)))\n                {\n                case (static_cast<int>(TEX_FILTER_RGB_COPY_RED) | static_cast<int>(TEX_FILTER_RGB_COPY_BLUE)):\n                    {\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            const XMVECTOR v1 = XMVectorSwizzle<0, 2, 0, 2>(v);\n                            *ptr++ = XMVectorSelect(v, v1, g_XMSelect1100);\n                        }\n                    }\n                    break;\n\n                case (static_cast<int>(TEX_FILTER_RGB_COPY_GREEN) | static_cast<int>(TEX_FILTER_RGB_COPY_BLUE)):\n                    {\n                        XMVECTOR* ptr = pBuffer;\n                        for (size_t i = 0; i < count; ++i)\n                        {\n                            const XMVECTOR v = *ptr;\n                            const XMVECTOR v1 = XMVectorSwizzle<1, 2, 3, 0>(v);\n                            *ptr++ = XMVectorSelect(v, v1, g_XMSelect1100);\n                        }\n                    }\n                    break;\n\n                case (static_cast<int>(TEX_FILTER_RGB_COPY_RED) | static_cast<int>(TEX_FILTER_RGB_COPY_GREEN)):\n                default:\n                    // Leave data unchanged and the store will handle this...\n                    break;\n                }\n            }\n        }\n    }\n\n    // sRGB output processing (Linear RGB -> sRGB)\n    if (flags & TEX_FILTER_SRGB_OUT)\n    {\n        if (!(out->flags & CONVF_DEPTH) && ((out->flags & CONVF_FLOAT) || (out->flags & CONVF_UNORM)))\n        {\n            XMVECTOR* ptr = pBuffer;\n            for (size_t i = 0; i < count; ++i, ++ptr)\n            {\n                *ptr = XMColorRGBToSRGB(*ptr);\n            }\n        }\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// Dithering\n//-------------------------------------------------------------------------------------\nnamespace\n{\n    // 4X4X4 ordered dithering matrix\n    const float g_Dither[] =\n    {\n        // (z & 3) + ( (y & 3) * 8) + (x & 3)\n        0.468750f,  -0.031250f, 0.343750f, -0.156250f, 0.468750f, -0.031250f, 0.343750f, -0.156250f,\n        -0.281250f,  0.218750f, -0.406250f, 0.093750f, -0.281250f, 0.218750f, -0.406250f, 0.093750f,\n        0.281250f,  -0.218750f, 0.406250f, -0.093750f, 0.281250f, -0.218750f, 0.406250f, -0.093750f,\n        -0.468750f,  0.031250f, -0.343750f, 0.156250f, -0.468750f, 0.031250f, -0.343750f, 0.156250f,\n    };\n\n    const XMVECTORF32 g_Scale16pc = { { { 65535.f, 65535.f, 65535.f, 65535.f } } };\n    const XMVECTORF32 g_Scale15pc = { { { 32767.f, 32767.f, 32767.f, 32767.f } } };\n    const XMVECTORF32 g_Scale10pc = { { {  1023.f,  1023.f,  1023.f,     3.f } } };\n    const XMVECTORF32 g_Scale9pc = { { {   511.f,   511.f,   511.f,     3.f } } };\n    const XMVECTORF32 g_Scale8pc = { { {   255.f,   255.f,   255.f,   255.f } } };\n    const XMVECTORF32 g_Scale7pc = { { {   127.f,   127.f,   127.f,   127.f } } };\n    const XMVECTORF32 g_Scale565pc = { { {    31.f,    63.f,    31.f,     1.f } } };\n    const XMVECTORF32 g_Scale5551pc = { { {    31.f,    31.f,    31.f,     1.f } } };\n    const XMVECTORF32 g_Scale4pc = { { {    15.f,    15.f,    15.f,    15.f } } };\n\n    const XMVECTORF32 g_ErrorWeight3 = { { { 3.f / 16.f, 3.f / 16.f, 3.f / 16.f, 3.f / 16.f } } };\n    const XMVECTORF32 g_ErrorWeight5 = { { { 5.f / 16.f, 5.f / 16.f, 5.f / 16.f, 5.f / 16.f } } };\n    const XMVECTORF32 g_ErrorWeight1 = { { { 1.f / 16.f, 1.f / 16.f, 1.f / 16.f, 1.f / 16.f } } };\n    const XMVECTORF32 g_ErrorWeight7 = { { { 7.f / 16.f, 7.f / 16.f, 7.f / 16.f, 7.f / 16.f } } };\n\n#define STORE_SCANLINE( type, scalev, clampzero, norm, itype, mask, row, bgr ) \\\n        if (size >= sizeof(type)) \\\n        { \\\n            type * __restrict dest = reinterpret_cast<type*>(pDestination); \\\n            for(size_t i = 0; i < count; ++i) \\\n            { \\\n                auto index = static_cast<ptrdiff_t>((row & 1) ? (count - i - 1) : i ); \\\n                ptrdiff_t delta = (row & 1) ? -2 : 0; \\\n                \\\n                XMVECTOR v = sPtr[ index ]; \\\n                if (bgr) { v = XMVectorSwizzle<2, 1, 0, 3>(v); } \\\n                if (norm && clampzero) v = XMVectorSaturate(v) ; \\\n                else if (clampzero) v = XMVectorClamp(v, g_XMZero, scalev); \\\n                else if (norm) v = XMVectorClamp(v, g_XMNegativeOne, g_XMOne); \\\n                else v = XMVectorClamp(v, XMVectorAdd(XMVectorNegate(scalev), g_XMOne), scalev); \\\n                v = XMVectorAdd(v, vError); \\\n                if (norm) v = XMVectorMultiply(v, scalev); \\\n                \\\n                XMVECTOR target; \\\n                if (pDiffusionErrors) \\\n                { \\\n                    target = XMVectorRound(v); \\\n                    vError = XMVectorSubtract(v, target); \\\n                    if (norm) vError = XMVectorDivide(vError, scalev); \\\n                    \\\n                    /* Distribute error to next scanline and next pixel */ \\\n                    pDiffusionErrors[ index-delta ]   = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[ index-delta ]); \\\n                    pDiffusionErrors[ index+1 ]       = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[ index+1 ]); \\\n                    pDiffusionErrors[ index+2+delta ] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[ index+2+delta ]); \\\n                    vError = XMVectorMultiply(vError, g_ErrorWeight7); \\\n                } \\\n                else \\\n                { \\\n                    /* Applied ordered dither */ \\\n                    target = XMVectorAdd(v, ordered[ index & 3 ]); \\\n                    target = XMVectorRound(target); \\\n                } \\\n                \\\n                target = XMVectorMin(scalev, target); \\\n                target = XMVectorMax((clampzero) ? g_XMZero : (XMVectorAdd(XMVectorNegate(scalev), g_XMOne)), target); \\\n                \\\n                XMFLOAT4A tmp; \\\n                XMStoreFloat4A(&tmp, target); \\\n                \\\n                auto dPtr = &dest[ index ]; \\\n                if (dPtr >= ePtr) break; \\\n                dPtr->x = itype(static_cast<itype>(tmp.x) & mask); \\\n                dPtr->y = itype(static_cast<itype>(tmp.y) & mask); \\\n                dPtr->z = itype(static_cast<itype>(tmp.z) & mask); \\\n                dPtr->w = itype(static_cast<itype>(tmp.w) & mask); \\\n            } \\\n            return true; \\\n        } \\\n        return false;\n\n#define STORE_SCANLINE2( type, scalev, clampzero, norm, itype, mask, row ) \\\n        /* The 2 component cases are always bgr=false */ \\\n        if (size >= sizeof(type)) \\\n        { \\\n            type * __restrict dest = reinterpret_cast<type*>(pDestination); \\\n            for(size_t i = 0; i < count; ++i) \\\n            { \\\n                auto index = static_cast<ptrdiff_t>((row & 1) ? (count - i - 1) : i ); \\\n                ptrdiff_t delta = (row & 1) ? -2 : 0; \\\n                \\\n                XMVECTOR v = sPtr[ index ]; \\\n                if (norm && clampzero) v = XMVectorSaturate(v) ; \\\n                else if (clampzero) v = XMVectorClamp(v, g_XMZero, scalev); \\\n                else if (norm) v = XMVectorClamp(v, g_XMNegativeOne, g_XMOne); \\\n                else v = XMVectorClamp(v, XMVectorAdd(XMVectorNegate(scalev), g_XMOne), scalev); \\\n                v = XMVectorAdd(v, vError); \\\n                if (norm) v = XMVectorMultiply(v, scalev); \\\n                \\\n                XMVECTOR target; \\\n                if (pDiffusionErrors) \\\n                { \\\n                    target = XMVectorRound(v); \\\n                    vError = XMVectorSubtract(v, target); \\\n                    if (norm) vError = XMVectorDivide(vError, scalev); \\\n                    \\\n                    /* Distribute error to next scanline and next pixel */ \\\n                    pDiffusionErrors[ index-delta ]   = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[ index-delta ]); \\\n                    pDiffusionErrors[ index+1 ]       = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[ index+1 ]); \\\n                    pDiffusionErrors[ index+2+delta ] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[ index+2+delta ]); \\\n                    vError = XMVectorMultiply(vError, g_ErrorWeight7); \\\n                } \\\n                else \\\n                { \\\n                    /* Applied ordered dither */ \\\n                    target = XMVectorAdd(v, ordered[ index & 3 ]); \\\n                    target = XMVectorRound(target); \\\n                } \\\n                \\\n                target = XMVectorMin(scalev, target); \\\n                target = XMVectorMax((clampzero) ? g_XMZero : (XMVectorAdd(XMVectorNegate(scalev), g_XMOne)), target); \\\n                \\\n                XMFLOAT4A tmp; \\\n                XMStoreFloat4A(&tmp, target); \\\n                \\\n                auto dPtr = &dest[ index ]; \\\n                if (dPtr >= ePtr) break; \\\n                dPtr->x = itype(static_cast<itype>(tmp.x) & mask); \\\n                dPtr->y = itype(static_cast<itype>(tmp.y) & mask); \\\n            } \\\n            return true; \\\n        } \\\n        return false;\n\n#define STORE_SCANLINE1( type, scalev, clampzero, norm, mask, row, selectw ) \\\n        /* The 1 component cases are always bgr=false */ \\\n        if (size >= sizeof(type)) \\\n        { \\\n            type * __restrict dest = reinterpret_cast<type*>(pDestination); \\\n            for(size_t i = 0; i < count; ++i) \\\n            { \\\n                auto index = static_cast<ptrdiff_t>((row & 1) ? (count - i - 1) : i ); \\\n                ptrdiff_t delta = (row & 1) ? -2 : 0; \\\n                \\\n                XMVECTOR v = sPtr[ index ]; \\\n                if (norm && clampzero) v = XMVectorSaturate(v) ; \\\n                else if (clampzero) v = XMVectorClamp(v, g_XMZero, scalev); \\\n                else if (norm) v = XMVectorClamp(v, g_XMNegativeOne, g_XMOne); \\\n                else v = XMVectorClamp(v, XMVectorAdd(XMVectorNegate(scalev), g_XMOne), scalev); \\\n                v = XMVectorAdd(v, vError); \\\n                if (norm) v = XMVectorMultiply(v, scalev); \\\n                \\\n                XMVECTOR target; \\\n                if (pDiffusionErrors) \\\n                { \\\n                    target = XMVectorRound(v); \\\n                    vError = XMVectorSubtract(v, target); \\\n                    if (norm) vError = XMVectorDivide(vError, scalev); \\\n                    \\\n                    /* Distribute error to next scanline and next pixel */ \\\n                    pDiffusionErrors[ index-delta ]   = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[ index-delta ]); \\\n                    pDiffusionErrors[ index+1 ]       = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[ index+1 ]); \\\n                    pDiffusionErrors[ index+2+delta ] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[ index+2+delta ]); \\\n                    vError = XMVectorMultiply(vError, g_ErrorWeight7); \\\n                } \\\n                else \\\n                { \\\n                    /* Applied ordered dither */ \\\n                    target = XMVectorAdd(v, ordered[ index & 3 ]); \\\n                    target = XMVectorRound(target); \\\n                } \\\n                \\\n                target = XMVectorMin(scalev, target); \\\n                target = XMVectorMax((clampzero) ? g_XMZero : (XMVectorAdd(XMVectorNegate(scalev), g_XMOne)), target); \\\n                \\\n                auto dPtr = &dest[ index ]; \\\n                if (dPtr >= ePtr) break; \\\n                *dPtr = type(static_cast<type>((selectw) ? XMVectorGetW(target) : XMVectorGetX(target)) & mask); \\\n            } \\\n            return true; \\\n        } \\\n        return false;\n}\n\n#pragma warning(push)\n#pragma warning( disable : 4127 )\n\n_Use_decl_annotations_\nbool DirectX::Internal::StoreScanlineDither(\n    void* pDestination,\n    size_t size,\n    DXGI_FORMAT format,\n    XMVECTOR* pSource,\n    size_t count,\n    float threshold,\n    size_t y,\n    size_t z,\n    XMVECTOR* pDiffusionErrors) noexcept\n{\n    assert(pDestination != nullptr);\n    assert(IsValid(format) && !IsTypeless(format) && !IsCompressed(format) && !IsPlanar(format) && !IsPalettized(format));\n\n    if (!size || !count)\n        return false;\n\n    const XMVECTOR* __restrict sPtr = pSource;\n    if (!sPtr)\n        return false;\n\n    assert((reinterpret_cast<uintptr_t>(pSource) & 0xF) == 0);\n\n    XMVECTOR ordered[4];\n    if (pDiffusionErrors)\n    {\n        // If pDiffusionErrors != 0, then this function performs error diffusion dithering (aka Floyd-Steinberg dithering)\n\n        // To avoid the need for another temporary scanline buffer, we allow this function to overwrite the source buffer in-place\n        // Given the intended usage in the conversion routines, this is not a problem.\n\n        XMVECTOR* ptr = pSource;\n        const XMVECTOR* err = pDiffusionErrors + 1;\n        for (size_t i = 0; i < count; ++i)\n        {\n            // Add contribution from previous scanline\n            XMVECTOR v = XMVectorAdd(*ptr, *err++);\n            *ptr++ = v;\n        }\n\n        // Reset errors for next scanline\n        memset(pDiffusionErrors, 0, sizeof(XMVECTOR)*(count + 2));\n    }\n    else\n    {\n        // If pDiffusionErrors == 0, then this function performs ordered dithering\n\n        const XMVECTOR dither = XMLoadFloat4(reinterpret_cast<const XMFLOAT4*>(g_Dither + (z & 3) + ((y & 3) * 8)));\n\n        ordered[0] = XMVectorSplatX(dither);\n        ordered[1] = XMVectorSplatY(dither);\n        ordered[2] = XMVectorSplatZ(dither);\n        ordered[3] = XMVectorSplatW(dither);\n    }\n\n    const void* ePtr = static_cast<const uint8_t*>(pDestination) + size;\n\n#ifdef _PREFAST_\n    *reinterpret_cast<uint8_t*>(pDestination) = 0;\n#endif\n\n    XMVECTOR vError = XMVectorZero();\n\n    switch (static_cast<int>(format))\n    {\n    case DXGI_FORMAT_R16G16B16A16_UNORM:\n        STORE_SCANLINE(XMUSHORTN4, g_Scale16pc, true, true, uint16_t, 0xFFFF, y, false)\n\n    case DXGI_FORMAT_R16G16B16A16_UINT:\n        STORE_SCANLINE(XMUSHORT4, g_Scale16pc, true, false, uint16_t, 0xFFFF, y, false)\n\n    case DXGI_FORMAT_R16G16B16A16_SNORM:\n        STORE_SCANLINE(XMSHORTN4, g_Scale15pc, false, true, int16_t, 0xFFFF, y, false)\n\n    case DXGI_FORMAT_R16G16B16A16_SINT:\n        STORE_SCANLINE(XMSHORT4, g_Scale15pc, false, false, int16_t, 0xFFFF, y, false)\n\n    case DXGI_FORMAT_R10G10B10A2_UNORM:\n        STORE_SCANLINE(XMUDECN4, g_Scale10pc, true, true, uint16_t, 0x3FF, y, false)\n\n    case DXGI_FORMAT_R10G10B10A2_UINT:\n        STORE_SCANLINE(XMUDEC4, g_Scale10pc, true, false, uint16_t, 0x3FF, y, false)\n\n    case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:\n        if (size >= sizeof(XMUDEC4))\n        {\n            static const XMVECTORF32  Scale = { { { 510.0f, 510.0f, 510.0f, 3.0f } } };\n            static const XMVECTORF32  Bias = { { { 384.0f, 384.0f, 384.0f, 0.0f } } };\n            static const XMVECTORF32  MinXR = { { { -0.7529f, -0.7529f, -0.7529f, 0.f } } };\n            static const XMVECTORF32  MaxXR = { { { 1.2529f, 1.2529f, 1.2529f, 1.0f } } };\n\n            XMUDEC4 * __restrict dest = static_cast<XMUDEC4*>(pDestination);\n            for (size_t i = 0; i < count; ++i)\n            {\n                auto index = static_cast<ptrdiff_t>((y & 1) ? (count - i - 1) : i);\n                ptrdiff_t delta = (y & 1) ? -2 : 0;\n\n                XMVECTOR v = XMVectorClamp(sPtr[index], MinXR, MaxXR);\n                v = XMVectorMultiplyAdd(v, Scale, vError);\n\n                XMVECTOR target;\n                if (pDiffusionErrors)\n                {\n                    target = XMVectorRound(v);\n                    vError = XMVectorSubtract(v, target);\n                    vError = XMVectorDivide(vError, Scale);\n\n                    // Distribute error to next scanline and next pixel\n                    pDiffusionErrors[index - delta] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[index - delta]);\n                    pDiffusionErrors[index + 1] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[index + 1]);\n                    pDiffusionErrors[index + 2 + delta] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[index + 2 + delta]);\n                    vError = XMVectorMultiply(vError, g_ErrorWeight7);\n                }\n                else\n                {\n                    // Applied ordered dither\n                    target = XMVectorAdd(v, ordered[index & 3]);\n                    target = XMVectorRound(target);\n                }\n\n                target = XMVectorAdd(target, Bias);\n                target = XMVectorClamp(target, g_XMZero, g_Scale10pc);\n\n                XMFLOAT4A tmp;\n                XMStoreFloat4A(&tmp, target);\n\n                auto dPtr = &dest[index];\n                if (dPtr >= ePtr) break;\n                dPtr->x = uint16_t(static_cast<uint16_t>(tmp.x) & 0x3FF);\n                dPtr->y = uint16_t(static_cast<uint16_t>(tmp.y) & 0x3FF);\n                dPtr->z = uint16_t(static_cast<uint16_t>(tmp.z) & 0x3FF);\n                dPtr->w = static_cast<uint16_t>(tmp.w);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R8G8B8A8_UNORM:\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n        STORE_SCANLINE(XMUBYTEN4, g_Scale8pc, true, true, uint8_t, 0xFF, y, false)\n\n    case DXGI_FORMAT_R8G8B8A8_UINT:\n        STORE_SCANLINE(XMUBYTE4, g_Scale8pc, true, false, uint8_t, 0xFF, y, false)\n\n    case DXGI_FORMAT_R8G8B8A8_SNORM:\n        STORE_SCANLINE(XMBYTEN4, g_Scale7pc, false, true, int8_t, 0xFF, y, false)\n\n    case DXGI_FORMAT_R8G8B8A8_SINT:\n        STORE_SCANLINE(XMBYTE4, g_Scale7pc, false, false, int8_t, 0xFF, y, false)\n\n    case DXGI_FORMAT_R16G16_UNORM:\n        STORE_SCANLINE2(XMUSHORTN2, g_Scale16pc, true, true, uint16_t, 0xFFFF, y)\n\n    case DXGI_FORMAT_R16G16_UINT:\n        STORE_SCANLINE2(XMUSHORT2, g_Scale16pc, true, false, uint16_t, 0xFFFF, y)\n\n    case DXGI_FORMAT_R16G16_SNORM:\n        STORE_SCANLINE2(XMSHORTN2, g_Scale15pc, false, true, int16_t, 0xFFFF, y)\n\n    case DXGI_FORMAT_R16G16_SINT:\n        STORE_SCANLINE2(XMSHORT2, g_Scale15pc, false, false, int16_t, 0xFFFF, y)\n\n    case DXGI_FORMAT_D24_UNORM_S8_UINT:\n        if (size >= sizeof(uint32_t))\n        {\n            static const XMVECTORF32 Clamp = { { { 1.f,  255.f, 0.f, 0.f } } };\n            static const XMVECTORF32 Scale = { { { 16777215.f,   1.f, 0.f, 0.f } } };\n            static const XMVECTORF32 Scale2 = { { { 16777215.f, 255.f, 0.f, 0.f } } };\n\n            uint32_t * __restrict dest = static_cast<uint32_t*>(pDestination);\n            for (size_t i = 0; i < count; ++i)\n            {\n                auto index = static_cast<ptrdiff_t>((y & 1) ? (count - i - 1) : i);\n                ptrdiff_t delta = (y & 1) ? -2 : 0;\n\n                XMVECTOR v = XMVectorClamp(sPtr[index], g_XMZero, Clamp);\n                v = XMVectorAdd(v, vError);\n                v = XMVectorMultiply(v, Scale);\n\n                XMVECTOR target;\n                if (pDiffusionErrors)\n                {\n                    target = XMVectorRound(v);\n                    vError = XMVectorSubtract(v, target);\n                    vError = XMVectorDivide(vError, Scale);\n\n                    // Distribute error to next scanline and next pixel\n                    pDiffusionErrors[index - delta] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[index - delta]);\n                    pDiffusionErrors[index + 1] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[index + 1]);\n                    pDiffusionErrors[index + 2 + delta] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[index + 2 + delta]);\n                    vError = XMVectorMultiply(vError, g_ErrorWeight7);\n                }\n                else\n                {\n                    // Applied ordered dither\n                    target = XMVectorAdd(v, ordered[index & 3]);\n                    target = XMVectorRound(target);\n                }\n\n                target = XMVectorClamp(target, g_XMZero, Scale2);\n\n                XMFLOAT4A tmp;\n                XMStoreFloat4A(&tmp, target);\n\n                auto dPtr = &dest[index];\n                if (dPtr >= ePtr) break;\n                *dPtr = (static_cast<uint32_t>(tmp.x) & 0xFFFFFF)\n                    | ((static_cast<uint32_t>(tmp.y) & 0xFF) << 24);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_R8G8_UNORM:\n        STORE_SCANLINE2(XMUBYTEN2, g_Scale8pc, true, true, uint8_t, 0xFF, y)\n\n    case DXGI_FORMAT_R8G8_UINT:\n        STORE_SCANLINE2(XMUBYTE2, g_Scale8pc, true, false, uint8_t, 0xFF, y)\n\n    case DXGI_FORMAT_R8G8_SNORM:\n        STORE_SCANLINE2(XMBYTEN2, g_Scale7pc, false, true, int8_t, 0xFF, y)\n\n    case DXGI_FORMAT_R8G8_SINT:\n        STORE_SCANLINE2(XMBYTE2, g_Scale7pc, false, false, int8_t, 0xFF, y)\n\n    case DXGI_FORMAT_D16_UNORM:\n    case DXGI_FORMAT_R16_UNORM:\n        STORE_SCANLINE1(uint16_t, g_Scale16pc, true, true, 0xFFFF, y, false)\n\n    case DXGI_FORMAT_R16_UINT:\n        STORE_SCANLINE1(uint16_t, g_Scale16pc, true, false, 0xFFFF, y, false)\n\n    case DXGI_FORMAT_R16_SNORM:\n        STORE_SCANLINE1(int16_t, g_Scale15pc, false, true, 0xFFFF, y, false)\n\n    case DXGI_FORMAT_R16_SINT:\n        STORE_SCANLINE1(int16_t, g_Scale15pc, false, false, 0xFFFF, y, false)\n\n    case DXGI_FORMAT_R8_UNORM:\n        STORE_SCANLINE1(uint8_t, g_Scale8pc, true, true, 0xFF, y, false)\n\n    case DXGI_FORMAT_R8_UINT:\n        STORE_SCANLINE1(uint8_t, g_Scale8pc, true, false, 0xFF, y, false)\n\n    case DXGI_FORMAT_R8_SNORM:\n        STORE_SCANLINE1(int8_t, g_Scale7pc, false, true, 0xFF, y, false)\n\n    case DXGI_FORMAT_R8_SINT:\n        STORE_SCANLINE1(int8_t, g_Scale7pc, false, false, 0xFF, y, false)\n\n    case DXGI_FORMAT_A8_UNORM:\n        STORE_SCANLINE1(uint8_t, g_Scale8pc, true, true, 0xFF, y, true)\n\n    case DXGI_FORMAT_B5G6R5_UNORM:\n        if (size >= sizeof(XMU565))\n        {\n            XMU565 * __restrict dest = static_cast<XMU565*>(pDestination);\n            for (size_t i = 0; i < count; ++i)\n            {\n                auto index = static_cast<ptrdiff_t>((y & 1) ? (count - i - 1) : i);\n                ptrdiff_t delta = (y & 1) ? -2 : 0;\n\n                XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(sPtr[index]);\n                v = XMVectorSaturate(v);\n                v = XMVectorAdd(v, vError);\n                v = XMVectorMultiply(v, g_Scale565pc);\n\n                XMVECTOR target;\n                if (pDiffusionErrors)\n                {\n                    target = XMVectorRound(v);\n                    vError = XMVectorSubtract(v, target);\n                    vError = XMVectorDivide(vError, g_Scale565pc);\n\n                    // Distribute error to next scanline and next pixel\n                    pDiffusionErrors[index - delta] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[index - delta]);\n                    pDiffusionErrors[index + 1] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[index + 1]);\n                    pDiffusionErrors[index + 2 + delta] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[index + 2 + delta]);\n                    vError = XMVectorMultiply(vError, g_ErrorWeight7);\n                }\n                else\n                {\n                    // Applied ordered dither\n                    target = XMVectorAdd(v, ordered[index & 3]);\n                    target = XMVectorRound(target);\n                }\n\n                target = XMVectorClamp(target, g_XMZero, g_Scale565pc);\n\n                XMFLOAT4A tmp;\n                XMStoreFloat4A(&tmp, target);\n\n                auto dPtr = &dest[index];\n                if (dPtr >= ePtr) break;\n                dPtr->x = uint16_t(static_cast<uint16_t>(tmp.x) & 0x1F);\n                dPtr->y = uint16_t(static_cast<uint16_t>(tmp.y) & 0x3F);\n                dPtr->z = uint16_t(static_cast<uint16_t>(tmp.z) & 0x1F);\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B5G5R5A1_UNORM:\n        if (size >= sizeof(XMU555))\n        {\n            XMU555 * __restrict dest = static_cast<XMU555*>(pDestination);\n            for (size_t i = 0; i < count; ++i)\n            {\n                auto index = static_cast<ptrdiff_t>((y & 1) ? (count - i - 1) : i);\n                ptrdiff_t delta = (y & 1) ? -2 : 0;\n\n                XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(sPtr[index]);\n                v = XMVectorSaturate(v);\n                v = XMVectorAdd(v, vError);\n                v = XMVectorMultiply(v, g_Scale5551pc);\n\n                XMVECTOR target;\n                if (pDiffusionErrors)\n                {\n                    target = XMVectorRound(v);\n                    vError = XMVectorSubtract(v, target);\n                    vError = XMVectorDivide(vError, g_Scale5551pc);\n\n                    // Distribute error to next scanline and next pixel\n                    pDiffusionErrors[index - delta] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[index - delta]);\n                    pDiffusionErrors[index + 1] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[index + 1]);\n                    pDiffusionErrors[index + 2 + delta] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[index + 2 + delta]);\n                    vError = XMVectorMultiply(vError, g_ErrorWeight7);\n                }\n                else\n                {\n                    // Applied ordered dither\n                    target = XMVectorAdd(v, ordered[index & 3]);\n                    target = XMVectorRound(target);\n                }\n\n                target = XMVectorClamp(target, g_XMZero, g_Scale5551pc);\n\n                XMFLOAT4A tmp;\n                XMStoreFloat4A(&tmp, target);\n\n                auto dPtr = &dest[index];\n                if (dPtr >= ePtr) break;\n                dPtr->x = uint16_t(static_cast<uint16_t>(tmp.x) & 0x1F);\n                dPtr->y = uint16_t(static_cast<uint16_t>(tmp.y) & 0x1F);\n                dPtr->z = uint16_t(static_cast<uint16_t>(tmp.z) & 0x1F);\n                dPtr->w = (XMVectorGetW(target) > threshold) ? 1u : 0u;\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B8G8R8A8_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n        STORE_SCANLINE(XMUBYTEN4, g_Scale8pc, true, true, uint8_t, 0xFF, y, true)\n\n    case DXGI_FORMAT_B8G8R8X8_UNORM:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n        if (size >= sizeof(XMUBYTEN4))\n        {\n            XMUBYTEN4 * __restrict dest = static_cast<XMUBYTEN4*>(pDestination);\n            for (size_t i = 0; i < count; ++i)\n            {\n                auto index = static_cast<ptrdiff_t>((y & 1) ? (count - i - 1) : i);\n                ptrdiff_t delta = (y & 1) ? -2 : 0;\n\n                XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>(sPtr[index]);\n                v = XMVectorSaturate(v);\n                v = XMVectorAdd(v, vError);\n                v = XMVectorMultiply(v, g_Scale8pc);\n\n                XMVECTOR target;\n                if (pDiffusionErrors)\n                {\n                    target = XMVectorRound(v);\n                    vError = XMVectorSubtract(v, target);\n                    vError = XMVectorDivide(vError, g_Scale8pc);\n\n                    // Distribute error to next scanline and next pixel\n                    pDiffusionErrors[index - delta] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[index - delta]);\n                    pDiffusionErrors[index + 1] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[index + 1]);\n                    pDiffusionErrors[index + 2 + delta] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[index + 2 + delta]);\n                    vError = XMVectorMultiply(vError, g_ErrorWeight7);\n                }\n                else\n                {\n                    // Applied ordered dither\n                    target = XMVectorAdd(v, ordered[index & 3]);\n                    target = XMVectorRound(target);\n                }\n\n                target = XMVectorClamp(target, g_XMZero, g_Scale8pc);\n\n                XMFLOAT4A tmp;\n                XMStoreFloat4A(&tmp, target);\n\n                auto dPtr = &dest[index];\n                if (dPtr >= ePtr) break;\n                dPtr->x = uint8_t(static_cast<uint8_t>(tmp.x) & 0xFF);\n                dPtr->y = uint8_t(static_cast<uint8_t>(tmp.y) & 0xFF);\n                dPtr->z = uint8_t(static_cast<uint8_t>(tmp.z) & 0xFF);\n                dPtr->w = 0;\n            }\n            return true;\n        }\n        return false;\n\n    case DXGI_FORMAT_B4G4R4A4_UNORM:\n        STORE_SCANLINE(XMUNIBBLE4, g_Scale4pc, true, true, uint8_t, 0xF, y, true)\n\n    case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:\n        STORE_SCANLINE(XMXDECN4, g_Scale9pc, false, true, uint16_t, 0x3FF, y, false)\n\n    case XBOX_DXGI_FORMAT_R4G4_UNORM:\n        if (size >= sizeof(uint8_t))\n        {\n            uint8_t * __restrict dest = static_cast<uint8_t*>(pDestination);\n            for (size_t i = 0; i < count; ++i)\n            {\n                auto index = static_cast<ptrdiff_t>((y & 1) ? (count - i - 1) : i);\n                ptrdiff_t delta = (y & 1) ? -2 : 0;\n\n                XMVECTOR v = XMVectorSaturate(sPtr[index]);\n                v = XMVectorAdd(v, vError);\n                v = XMVectorMultiply(v, g_Scale4pc);\n\n                XMVECTOR target;\n                if (pDiffusionErrors)\n                {\n                    target = XMVectorRound(v);\n                    vError = XMVectorSubtract(v, target);\n                    vError = XMVectorDivide(vError, g_Scale4pc);\n\n                    // Distribute error to next scanline and next pixel\n                    pDiffusionErrors[index - delta] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[index - delta]);\n                    pDiffusionErrors[index + 1] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[index + 1]);\n                    pDiffusionErrors[index + 2 + delta] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[index + 2 + delta]);\n                    vError = XMVectorMultiply(vError, g_ErrorWeight7);\n                }\n                else\n                {\n                    // Applied ordered dither\n                    target = XMVectorAdd(v, ordered[index & 3]);\n                    target = XMVectorRound(target);\n                }\n\n                target = XMVectorClamp(target, g_XMZero, g_Scale4pc);\n\n                XMFLOAT4A tmp;\n                XMStoreFloat4A(&tmp, target);\n\n                auto dPtr = &dest[index];\n                if (dPtr >= ePtr) break;\n                *dPtr = static_cast<uint8_t>((unsigned(tmp.x) & 0xF) | ((unsigned(tmp.y) & 0xF) << 4));\n            }\n            return true;\n        }\n        return false;\n\n    default:\n        return StoreScanline(pDestination, size, format, pSource, count, threshold);\n    }\n}\n\n#pragma warning(pop)\n\n#undef STORE_SCANLINE\n#undef STORE_SCANLINE2\n#undef STORE_SCANLINE1\n\nnamespace\n{\n    //-------------------------------------------------------------------------------------\n    // Selection logic for using WIC vs. our own routines\n    //-------------------------------------------------------------------------------------\n    inline bool UseWICConversion(\n        _In_ TEX_FILTER_FLAGS filter,\n        _In_ DXGI_FORMAT sformat,\n        _In_ DXGI_FORMAT tformat,\n        _Out_ WICPixelFormatGUID& pfGUID,\n        _Out_ WICPixelFormatGUID& targetGUID) noexcept\n    {\n    #ifndef _WIN32\n        UNREFERENCED_PARAMETER(filter);\n        UNREFERENCED_PARAMETER(sformat);\n        UNREFERENCED_PARAMETER(tformat);\n        UNREFERENCED_PARAMETER(pfGUID);\n        UNREFERENCED_PARAMETER(targetGUID);\n        return false;\n    #else\n        memset(&pfGUID, 0, sizeof(GUID));\n        memset(&targetGUID, 0, sizeof(GUID));\n\n        if (filter & TEX_FILTER_FORCE_NON_WIC)\n        {\n            // Explicit flag indicates use of non-WIC code paths\n            return false;\n        }\n\n        if (!DXGIToWIC(sformat, pfGUID) || !DXGIToWIC(tformat, targetGUID))\n        {\n            // Source or target format are not WIC supported native pixel formats\n            return false;\n        }\n\n        if (filter & TEX_FILTER_FORCE_WIC)\n        {\n            // Explicit flag to use WIC code paths, skips all the case checks below\n            return true;\n        }\n\n        if (filter & TEX_FILTER_SEPARATE_ALPHA)\n        {\n            // Alpha is not premultiplied, so use non-WIC code paths\n            return false;\n        }\n\n        if (filter & TEX_FILTER_FLOAT_X2BIAS)\n        {\n            // X2 Scale & Bias conversions not supported by WIC code paths\n            return false;\n        }\n\n        // Check for special cases\n    #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n        if (sformat == DXGI_FORMAT_R16G16B16A16_FLOAT\n            || sformat == DXGI_FORMAT_R16_FLOAT\n            || tformat == DXGI_FORMAT_R16G16B16A16_FLOAT\n            || tformat == DXGI_FORMAT_R16_FLOAT)\n        {\n            // Use non-WIC code paths as these conversions are not supported by Xbox version of WIC\n            return false;\n        }\n    #endif\n\n        switch (sformat)\n        {\n        case DXGI_FORMAT_R32G32B32A32_FLOAT:\n        case DXGI_FORMAT_R32G32B32_FLOAT:\n        case DXGI_FORMAT_R32G32_FLOAT:\n        case DXGI_FORMAT_R32_FLOAT:\n        case DXGI_FORMAT_D32_FLOAT:\n            switch (tformat)\n            {\n            case DXGI_FORMAT_R16G16B16A16_FLOAT:\n            case DXGI_FORMAT_R16G16_FLOAT:\n            case DXGI_FORMAT_R16_FLOAT:\n                // WIC conversions for FP32->FP16 can result in NaN values instead of clamping for min/max value\n                return false;\n\n            default:\n                break;\n            }\n            break;\n\n        default:\n            break;\n        }\n\n        switch (sformat)\n        {\n        case DXGI_FORMAT_R32G32B32A32_FLOAT:\n        case DXGI_FORMAT_R32G32B32_FLOAT:\n        case DXGI_FORMAT_R16G16B16A16_FLOAT:\n            switch (tformat)\n            {\n            case DXGI_FORMAT_R16_FLOAT:\n            case DXGI_FORMAT_R32_FLOAT:\n            case DXGI_FORMAT_D32_FLOAT:\n                // WIC converts via UNORM formats and ends up converting colorspaces for these cases\n            case DXGI_FORMAT_A8_UNORM:\n                // Conversion logic for these kinds of textures is unintuitive for WIC code paths\n                return false;\n\n            default:\n                break;\n            }\n            break;\n\n        case DXGI_FORMAT_R16_FLOAT:\n            switch (tformat)\n            {\n            case DXGI_FORMAT_R32_FLOAT:\n            case DXGI_FORMAT_D32_FLOAT:\n                // WIC converts via UNORM formats and ends up converting colorspaces for these cases\n            case DXGI_FORMAT_A8_UNORM:\n                // Conversion logic for these kinds of textures is unintuitive for WIC code paths\n                return false;\n\n            default:\n                break;\n            }\n            break;\n\n        case DXGI_FORMAT_A8_UNORM:\n            // Conversion logic for these kinds of textures is unintuitive for WIC code paths\n            return false;\n\n        default:\n            switch (tformat)\n            {\n            case DXGI_FORMAT_A8_UNORM:\n                // Conversion logic for these kinds of textures is unintuitive for WIC code paths\n                return false;\n\n            default:\n                break;\n            }\n        }\n\n        // Check for implicit color space changes\n        if (IsSRGB(sformat))\n            filter |= TEX_FILTER_SRGB_IN;\n\n        if (IsSRGB(tformat))\n            filter |= TEX_FILTER_SRGB_OUT;\n\n        if ((filter & (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT))\n        {\n            filter &= ~(TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT);\n        }\n\n        auto const wicsrgb = CheckWICColorSpace(pfGUID, targetGUID);\n\n        if (wicsrgb != (filter & (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT)))\n        {\n            // WIC will perform a colorspace conversion we didn't request\n            return false;\n        }\n\n        return true;\n    #endif // WIN32\n    }\n\n    //-------------------------------------------------------------------------------------\n    // Convert the source image using WIC\n    //-------------------------------------------------------------------------------------\n    HRESULT ConvertUsingWIC(\n        _In_ const Image& srcImage,\n        _In_ const WICPixelFormatGUID& pfGUID,\n        _In_ const WICPixelFormatGUID& targetGUID,\n        _In_ TEX_FILTER_FLAGS filter,\n        _In_ float threshold,\n        _In_ const Image& destImage)\n    {\n    #ifndef _WIN32\n        UNREFERENCED_PARAMETER(srcImage);\n        UNREFERENCED_PARAMETER(pfGUID);\n        UNREFERENCED_PARAMETER(targetGUID);\n        UNREFERENCED_PARAMETER(filter);\n        UNREFERENCED_PARAMETER(threshold);\n        UNREFERENCED_PARAMETER(destImage);\n        return E_NOTIMPL;\n    #else\n        assert(srcImage.width == destImage.width);\n        assert(srcImage.height == destImage.height);\n\n        bool iswic2 = false;\n        auto pWIC = GetWICFactory(iswic2);\n        if (!pWIC)\n            return E_NOINTERFACE;\n\n        ComPtr<IWICFormatConverter> FC;\n        HRESULT hr = pWIC->CreateFormatConverter(FC.GetAddressOf());\n        if (FAILED(hr))\n            return hr;\n\n        // Note that WIC conversion ignores the TEX_FILTER_SRGB_IN and TEX_FILTER_SRGB_OUT flags,\n        // but also always assumes UNORM <-> FLOAT conversions are changing color spaces sRGB <-> scRGB\n\n        BOOL canConvert = FALSE;\n        hr = FC->CanConvert(pfGUID, targetGUID, &canConvert);\n        if (FAILED(hr) || !canConvert)\n        {\n            // This case is not an issue for the subset of WIC formats that map directly to DXGI\n            return E_UNEXPECTED;\n        }\n\n        if (srcImage.rowPitch > UINT32_MAX || srcImage.slicePitch > UINT32_MAX\n            || destImage.rowPitch > UINT32_MAX || destImage.slicePitch > UINT32_MAX)\n            return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n        ComPtr<IWICBitmap> source;\n        hr = pWIC->CreateBitmapFromMemory(static_cast<UINT>(srcImage.width), static_cast<UINT>(srcImage.height), pfGUID,\n            static_cast<UINT>(srcImage.rowPitch), static_cast<UINT>(srcImage.slicePitch),\n            srcImage.pixels, source.GetAddressOf());\n        if (FAILED(hr))\n            return hr;\n\n        hr = FC->Initialize(source.Get(), targetGUID, GetWICDither(filter), nullptr,\n            static_cast<double>(threshold) * 100.0, WICBitmapPaletteTypeMedianCut);\n        if (FAILED(hr))\n            return hr;\n\n        hr = FC->CopyPixels(nullptr, static_cast<UINT>(destImage.rowPitch), static_cast<UINT>(destImage.slicePitch), destImage.pixels);\n        if (FAILED(hr))\n            return hr;\n\n        return S_OK;\n    #endif // WIN32\n    }\n\n    //-------------------------------------------------------------------------------------\n    // Convert the source image (not using WIC)\n    //-------------------------------------------------------------------------------------\n    HRESULT ConvertCustom(\n        _In_ const Image& srcImage,\n        _In_ TEX_FILTER_FLAGS filter,\n        _In_ const Image& destImage,\n        _In_ float threshold,\n        size_t z) noexcept\n    {\n        assert(srcImage.width == destImage.width);\n        assert(srcImage.height == destImage.height);\n\n        const uint8_t *pSrc = srcImage.pixels;\n        uint8_t *pDest = destImage.pixels;\n        if (!pSrc || !pDest)\n            return E_POINTER;\n\n        size_t width = srcImage.width;\n\n        if (filter & TEX_FILTER_DITHER_DIFFUSION)\n        {\n            // Error diffusion dithering (aka Floyd-Steinberg dithering)\n            auto scanline = make_AlignedArrayXMVECTOR(uint64_t(width) * 2 + 2);\n            if (!scanline)\n                return E_OUTOFMEMORY;\n\n            XMVECTOR* pDiffusionErrors = scanline.get() + width;\n            memset(pDiffusionErrors, 0, sizeof(XMVECTOR)*(width + 2));\n\n            for (size_t h = 0; h < srcImage.height; ++h)\n            {\n                if (!LoadScanline(scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format))\n                    return E_FAIL;\n\n                ConvertScanline(scanline.get(), width, destImage.format, srcImage.format, filter);\n\n                if (!StoreScanlineDither(pDest, destImage.rowPitch, destImage.format, scanline.get(), width, threshold, h, z, pDiffusionErrors))\n                    return E_FAIL;\n\n                pSrc += srcImage.rowPitch;\n                pDest += destImage.rowPitch;\n            }\n        }\n        else\n        {\n            auto scanline = make_AlignedArrayXMVECTOR(width);\n            if (!scanline)\n                return E_OUTOFMEMORY;\n\n            if (filter & TEX_FILTER_DITHER)\n            {\n                // Ordered dithering\n                for (size_t h = 0; h < srcImage.height; ++h)\n                {\n                    if (!LoadScanline(scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format))\n                        return E_FAIL;\n\n                    ConvertScanline(scanline.get(), width, destImage.format, srcImage.format, filter);\n\n                    if (!StoreScanlineDither(pDest, destImage.rowPitch, destImage.format, scanline.get(), width, threshold, h, z, nullptr))\n                        return E_FAIL;\n\n                    pSrc += srcImage.rowPitch;\n                    pDest += destImage.rowPitch;\n                }\n            }\n            else\n            {\n                // No dithering\n                for (size_t h = 0; h < srcImage.height; ++h)\n                {\n                    if (!LoadScanline(scanline.get(), width, pSrc, srcImage.rowPitch, srcImage.format))\n                        return E_FAIL;\n\n                    ConvertScanline(scanline.get(), width, destImage.format, srcImage.format, filter);\n\n                    if (!StoreScanline(pDest, destImage.rowPitch, destImage.format, scanline.get(), width, threshold))\n                        return E_FAIL;\n\n                    pSrc += srcImage.rowPitch;\n                    pDest += destImage.rowPitch;\n                }\n            }\n        }\n\n        return S_OK;\n    }\n\n    //-------------------------------------------------------------------------------------\n    DXGI_FORMAT PlanarToSingle(_In_ DXGI_FORMAT format) noexcept\n    {\n        switch (format)\n        {\n        case DXGI_FORMAT_NV12:\n        case DXGI_FORMAT_NV11:\n            return DXGI_FORMAT_YUY2;\n\n        case DXGI_FORMAT_P010:\n            return DXGI_FORMAT_Y210;\n\n        case DXGI_FORMAT_P016:\n            return DXGI_FORMAT_Y216;\n\n            // We currently do not support conversion for Xbox One specific 16-bit depth formats\n\n            // We can't do anything with DXGI_FORMAT_420_OPAQUE because it's an opaque blob of bits\n\n            // We don't support conversion of JPEG Hardware decode formats\n\n        default:\n            return DXGI_FORMAT_UNKNOWN;\n        }\n    }\n\n    //-------------------------------------------------------------------------------------\n    // Convert the image from a planar to non-planar image\n    //-------------------------------------------------------------------------------------\n#define CONVERT_420_TO_422( srcType, destType )\\\n        {\\\n            const size_t rowPitch = srcImage.rowPitch;\\\n            \\\n            auto const sourceE = reinterpret_cast<const srcType*>(pSrc + srcImage.slicePitch);\\\n            auto pSrcUV = pSrc + (srcImage.height * rowPitch);\\\n            \\\n            for(size_t y = 0; y < srcImage.height; y+= 2)\\\n            {\\\n                auto sPtrY0 = reinterpret_cast<const srcType*>(pSrc);\\\n                auto sPtrY2 = reinterpret_cast<const srcType*>(pSrc + rowPitch);\\\n                auto sPtrUV = reinterpret_cast<const srcType*>(pSrcUV);\\\n                \\\n                destType * __restrict dPtr0 = reinterpret_cast<destType*>(pDest);\\\n                destType * __restrict dPtr1 = reinterpret_cast<destType*>(pDest + destImage.rowPitch);\\\n                \\\n                for(size_t x = 0; x < srcImage.width; x+= 2)\\\n                {\\\n                    if ((sPtrUV+1) >= sourceE) break;\\\n                    \\\n                    const srcType u = *(sPtrUV++);\\\n                    const srcType v = *(sPtrUV++);\\\n                    \\\n                    dPtr0->x = *(sPtrY0++);\\\n                    dPtr0->y = u;\\\n                    dPtr0->z = *(sPtrY0++);\\\n                    dPtr0->w = v;\\\n                    ++dPtr0;\\\n                    \\\n                    dPtr1->x = *(sPtrY2++);\\\n                    dPtr1->y = u;\\\n                    dPtr1->z = *(sPtrY2++);\\\n                    dPtr1->w = v;\\\n                    ++dPtr1;\\\n                }\\\n                \\\n                pSrc += rowPitch * 2;\\\n                pSrcUV += rowPitch;\\\n                \\\n                pDest += destImage.rowPitch * 2;\\\n            }\\\n        }\n\n#ifdef __clang__\n#pragma clang diagnostic ignored \"-Wextra-semi-stmt\"\n#endif\n\n    HRESULT ConvertToSinglePlane_(_In_ const Image& srcImage, _In_ const Image& destImage) noexcept\n    {\n        assert(srcImage.width == destImage.width);\n        assert(srcImage.height == destImage.height);\n\n        const uint8_t *pSrc = srcImage.pixels;\n        uint8_t *pDest = destImage.pixels;\n        if (!pSrc || !pDest)\n            return E_POINTER;\n\n        switch (srcImage.format)\n        {\n        case DXGI_FORMAT_NV12:\n            assert(destImage.format == DXGI_FORMAT_YUY2);\n            CONVERT_420_TO_422(uint8_t, XMUBYTEN4);\n            return S_OK;\n\n        case DXGI_FORMAT_P010:\n            assert(destImage.format == DXGI_FORMAT_Y210);\n            CONVERT_420_TO_422(uint16_t, XMUSHORTN4);\n            return S_OK;\n\n        case DXGI_FORMAT_P016:\n            assert(destImage.format == DXGI_FORMAT_Y216);\n            CONVERT_420_TO_422(uint16_t, XMUSHORTN4);\n            return S_OK;\n\n        case DXGI_FORMAT_NV11:\n            assert(destImage.format == DXGI_FORMAT_YUY2);\n            // Convert 4:1:1 to 4:2:2\n            {\n                const size_t rowPitch = srcImage.rowPitch;\n\n                const uint8_t* sourceE = pSrc + srcImage.slicePitch;\n                const uint8_t* pSrcUV = pSrc + (srcImage.height * rowPitch);\n\n                for (size_t y = 0; y < srcImage.height; ++y)\n                {\n                    const uint8_t* sPtrY = pSrc;\n                    const uint8_t* sPtrUV = pSrcUV;\n\n                    XMUBYTEN4 * __restrict dPtr = reinterpret_cast<XMUBYTEN4*>(pDest);\n\n                    for (size_t x = 0; x < srcImage.width; x += 4)\n                    {\n                        if ((sPtrUV + 1) >= sourceE) break;\n\n                        const uint8_t u = *(sPtrUV++);\n                        const uint8_t v = *(sPtrUV++);\n\n                        dPtr->x = *(sPtrY++);\n                        dPtr->y = u;\n                        dPtr->z = *(sPtrY++);\n                        dPtr->w = v;\n                        ++dPtr;\n\n                        dPtr->x = *(sPtrY++);\n                        dPtr->y = u;\n                        dPtr->z = *(sPtrY++);\n                        dPtr->w = v;\n                        ++dPtr;\n                    }\n\n                    pSrc += rowPitch;\n                    pSrcUV += (rowPitch >> 1);\n\n                    pDest += destImage.rowPitch;\n                }\n            }\n            return S_OK;\n\n        default:\n            return E_UNEXPECTED;\n        }\n    }\n\n#undef CONVERT_420_TO_422\n}\n\n\n//=====================================================================================\n// Entry-points\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n// Convert image\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::Convert(\n    const Image& srcImage,\n    DXGI_FORMAT format,\n    TEX_FILTER_FLAGS filter,\n    float threshold,\n    ScratchImage& image) noexcept\n{\n    if ((srcImage.format == format) || !IsValid(format))\n        return E_INVALIDARG;\n\n    if (!srcImage.pixels)\n        return E_POINTER;\n\n    if (IsCompressed(srcImage.format) || IsCompressed(format)\n        || IsPlanar(srcImage.format) || IsPlanar(format)\n        || IsPalettized(srcImage.format) || IsPalettized(format)\n        || IsTypeless(srcImage.format) || IsTypeless(format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if ((srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX))\n        return E_INVALIDARG;\n\n    HRESULT hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1);\n    if (FAILED(hr))\n        return hr;\n\n    const Image *rimage = image.GetImage(0, 0, 0);\n    if (!rimage)\n    {\n        image.Release();\n        return E_POINTER;\n    }\n\n    WICPixelFormatGUID pfGUID, targetGUID;\n    if (UseWICConversion(filter, srcImage.format, format, pfGUID, targetGUID))\n    {\n        hr = ConvertUsingWIC(srcImage, pfGUID, targetGUID, filter, threshold, *rimage);\n    }\n    else\n    {\n        hr = ConvertCustom(srcImage, filter, *rimage, threshold, 0);\n    }\n\n    if (FAILED(hr))\n    {\n        image.Release();\n        return hr;\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Convert image (complex)\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::Convert(\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    DXGI_FORMAT format,\n    TEX_FILTER_FLAGS filter,\n    float threshold,\n    ScratchImage& result) noexcept\n{\n    if (!srcImages || !nimages || (metadata.format == format) || !IsValid(format))\n        return E_INVALIDARG;\n\n    if (IsCompressed(metadata.format) || IsCompressed(format)\n        || IsPlanar(metadata.format) || IsPlanar(format)\n        || IsPalettized(metadata.format) || IsPalettized(format)\n        || IsTypeless(metadata.format) || IsTypeless(format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if ((metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX))\n        return E_INVALIDARG;\n\n    TexMetadata mdata2 = metadata;\n    mdata2.format = format;\n    HRESULT hr = result.Initialize(mdata2);\n    if (FAILED(hr))\n        return hr;\n\n    if (nimages != result.GetImageCount())\n    {\n        result.Release();\n        return E_FAIL;\n    }\n\n    const Image* dest = result.GetImages();\n    if (!dest)\n    {\n        result.Release();\n        return E_POINTER;\n    }\n\n    WICPixelFormatGUID pfGUID, targetGUID;\n    const bool usewic = !metadata.IsPMAlpha() && UseWICConversion(filter, metadata.format, format, pfGUID, targetGUID);\n\n    switch (metadata.dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n    case TEX_DIMENSION_TEXTURE2D:\n        for (size_t index = 0; index < nimages; ++index)\n        {\n            const Image& src = srcImages[index];\n            if (src.format != metadata.format)\n            {\n                result.Release();\n                return E_FAIL;\n            }\n\n            if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX))\n            {\n                result.Release();\n                return E_FAIL;\n            }\n\n            const Image& dst = dest[index];\n            assert(dst.format == format);\n\n            if (src.width != dst.width || src.height != dst.height)\n            {\n                result.Release();\n                return E_FAIL;\n            }\n\n            if (usewic)\n            {\n                hr = ConvertUsingWIC(src, pfGUID, targetGUID, filter, threshold, dst);\n            }\n            else\n            {\n                hr = ConvertCustom(src, filter, dst, threshold, 0);\n            }\n\n            if (FAILED(hr))\n            {\n                result.Release();\n                return hr;\n            }\n        }\n        break;\n\n    case TEX_DIMENSION_TEXTURE3D:\n        {\n            size_t index = 0;\n            size_t d = metadata.depth;\n            for (size_t level = 0; level < metadata.mipLevels; ++level)\n            {\n                for (size_t slice = 0; slice < d; ++slice, ++index)\n                {\n                    if (index >= nimages)\n                    {\n                        result.Release();\n                        return E_FAIL;\n                    }\n\n                    const Image& src = srcImages[index];\n                    if (src.format != metadata.format)\n                    {\n                        result.Release();\n                        return E_FAIL;\n                    }\n\n                    if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX))\n                    {\n                        result.Release();\n                        return E_FAIL;\n                    }\n\n                    const Image& dst = dest[index];\n                    assert(dst.format == format);\n\n                    if (src.width != dst.width || src.height != dst.height)\n                    {\n                        result.Release();\n                        return E_FAIL;\n                    }\n\n                    if (usewic)\n                    {\n                        hr = ConvertUsingWIC(src, pfGUID, targetGUID, filter, threshold, dst);\n                    }\n                    else\n                    {\n                        hr = ConvertCustom(src, filter, dst, threshold, slice);\n                    }\n\n                    if (FAILED(hr))\n                    {\n                        result.Release();\n                        return hr;\n                    }\n                }\n\n                if (d > 1)\n                    d >>= 1;\n            }\n        }\n        break;\n\n    default:\n        result.Release();\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Convert image from planar to single plane (image)\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::ConvertToSinglePlane(const Image& srcImage, ScratchImage& image) noexcept\n{\n    if (!IsPlanar(srcImage.format))\n        return E_INVALIDARG;\n\n    if (!srcImage.pixels)\n        return E_POINTER;\n\n    const DXGI_FORMAT format = PlanarToSingle(srcImage.format);\n    if (format == DXGI_FORMAT_UNKNOWN)\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if ((srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX))\n        return E_INVALIDARG;\n\n    HRESULT hr = image.Initialize2D(format, srcImage.width, srcImage.height, 1, 1);\n    if (FAILED(hr))\n        return hr;\n\n    const Image *rimage = image.GetImage(0, 0, 0);\n    if (!rimage)\n    {\n        image.Release();\n        return E_POINTER;\n    }\n\n    hr = ConvertToSinglePlane_(srcImage, *rimage);\n    if (FAILED(hr))\n    {\n        image.Release();\n        return hr;\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Convert image from planar to single plane (complex)\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::ConvertToSinglePlane(\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    ScratchImage& result) noexcept\n{\n    if (!srcImages || !nimages)\n        return E_INVALIDARG;\n\n    if (metadata.IsVolumemap())\n    {\n        // Direct3D does not support any planar formats for Texture3D\n        return HRESULT_E_NOT_SUPPORTED;\n    }\n\n    const DXGI_FORMAT format = PlanarToSingle(metadata.format);\n    if (format == DXGI_FORMAT_UNKNOWN)\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if ((metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX))\n        return E_INVALIDARG;\n\n    TexMetadata mdata2 = metadata;\n    mdata2.format = format;\n    HRESULT hr = result.Initialize(mdata2);\n    if (FAILED(hr))\n        return hr;\n\n    if (nimages != result.GetImageCount())\n    {\n        result.Release();\n        return E_FAIL;\n    }\n\n    const Image* dest = result.GetImages();\n    if (!dest)\n    {\n        result.Release();\n        return E_POINTER;\n    }\n\n    for (size_t index = 0; index < nimages; ++index)\n    {\n        const Image& src = srcImages[index];\n        if (src.format != metadata.format)\n        {\n            result.Release();\n            return E_FAIL;\n        }\n\n        if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX))\n            return E_FAIL;\n\n        const Image& dst = dest[index];\n        assert(dst.format == format);\n\n        if (src.width != dst.width || src.height != dst.height)\n        {\n            result.Release();\n            return E_FAIL;\n        }\n\n        hr = ConvertToSinglePlane_(src, dst);\n        if (FAILED(hr))\n        {\n            result.Release();\n            return hr;\n        }\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Returns the data type of a DXGI_FORMAT\n//-------------------------------------------------------------------------------------\nDirectX::FORMAT_TYPE DirectX::FormatDataType(_In_ DXGI_FORMAT fmt) noexcept\n{\n    const auto cflags = GetConvertFlags(fmt);\n\n    switch (cflags & (CONVF_FLOAT | CONVF_UNORM | CONVF_UINT | CONVF_SNORM | CONVF_SINT))\n    {\n    case CONVF_FLOAT:\n        return FORMAT_TYPE_FLOAT;\n\n    case CONVF_UNORM:\n        return FORMAT_TYPE_UNORM;\n\n    case CONVF_UINT:\n        return FORMAT_TYPE_UINT;\n\n    case CONVF_SNORM:\n        return FORMAT_TYPE_SNORM;\n\n    case CONVF_SINT:\n        return FORMAT_TYPE_SINT;\n\n    default:\n        return FORMAT_TYPE_TYPELESS;\n    }\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTexD3D11.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTexD3D11.cpp\n//\n// DirectX Texture Library - Direct3D 11 helpers\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\n#ifdef _GAMING_XBOX\n#error This module is not supported for GDK\n#elif !defined(_XBOX_ONE) || !defined(_TITLE)\n#include <d3d10.h>\n#endif\n\n#ifndef IID_GRAPHICS_PPV_ARGS\n#define IID_GRAPHICS_PPV_ARGS(x) IID_PPV_ARGS(x)\n#endif\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\nstatic_assert(static_cast<int>(TEX_DIMENSION_TEXTURE1D) == static_cast<int>(D3D11_RESOURCE_DIMENSION_TEXTURE1D), \"header enum mismatch\");\nstatic_assert(static_cast<int>(TEX_DIMENSION_TEXTURE2D) == static_cast<int>(D3D11_RESOURCE_DIMENSION_TEXTURE2D), \"header enum mismatch\");\nstatic_assert(static_cast<int>(TEX_DIMENSION_TEXTURE3D) == static_cast<int>(D3D11_RESOURCE_DIMENSION_TEXTURE3D), \"header enum mismatch\");\n\nnamespace\n{\n    HRESULT Capture(\n        _In_ ID3D11DeviceContext* pContext,\n        _In_ ID3D11Resource* pSource,\n        const TexMetadata& metadata,\n        const ScratchImage& result) noexcept\n    {\n        if (!pContext || !pSource || !result.GetPixels())\n            return E_POINTER;\n\n    #if defined(_XBOX_ONE) && defined(_TITLE)\n\n        ComPtr<ID3D11Device> d3dDevice;\n        pContext->GetDevice(d3dDevice.GetAddressOf());\n\n        if (d3dDevice->GetCreationFlags() & D3D11_CREATE_DEVICE_IMMEDIATE_CONTEXT_FAST_SEMANTICS)\n        {\n            ComPtr<ID3D11DeviceX> d3dDeviceX;\n            HRESULT hr = d3dDevice.As(&d3dDeviceX);\n            if (FAILED(hr))\n                return hr;\n\n            ComPtr<ID3D11DeviceContextX> d3dContextX;\n            hr = pContext->QueryInterface(IID_GRAPHICS_PPV_ARGS(d3dContextX.GetAddressOf()));\n            if (FAILED(hr))\n                return hr;\n\n            UINT64 copyFence = d3dContextX->InsertFence(0);\n\n            while (d3dDeviceX->IsFencePending(copyFence))\n            {\n                SwitchToThread();\n            }\n        }\n\n    #endif\n\n        if (metadata.IsVolumemap())\n        {\n            //--- Volume texture ----------------------------------------------------------\n            assert(metadata.arraySize == 1);\n\n            size_t height = metadata.height;\n            size_t depth = metadata.depth;\n\n            for (size_t level = 0; level < metadata.mipLevels; ++level)\n            {\n                const UINT dindex = D3D11CalcSubresource(static_cast<UINT>(level), 0, static_cast<UINT>(metadata.mipLevels));\n\n                D3D11_MAPPED_SUBRESOURCE mapped;\n                HRESULT hr = pContext->Map(pSource, dindex, D3D11_MAP_READ, 0, &mapped);\n                if (FAILED(hr))\n                    return hr;\n\n                auto pslice = static_cast<const uint8_t*>(mapped.pData);\n                if (!pslice)\n                {\n                    pContext->Unmap(pSource, dindex);\n                    return E_POINTER;\n                }\n\n                const size_t lines = ComputeScanlines(metadata.format, height);\n                if (!lines)\n                {\n                    pContext->Unmap(pSource, dindex);\n                    return E_UNEXPECTED;\n                }\n\n                for (size_t slice = 0; slice < depth; ++slice)\n                {\n                    const Image* img = result.GetImage(level, 0, slice);\n                    if (!img)\n                    {\n                        pContext->Unmap(pSource, dindex);\n                        return E_FAIL;\n                    }\n\n                    if (!img->pixels)\n                    {\n                        pContext->Unmap(pSource, dindex);\n                        return E_POINTER;\n                    }\n\n                    const uint8_t* sptr = pslice;\n                    uint8_t* dptr = img->pixels;\n                    for (size_t h = 0; h < lines; ++h)\n                    {\n                        const size_t msize = std::min<size_t>(img->rowPitch, mapped.RowPitch);\n                        memcpy(dptr, sptr, msize);\n                        sptr += mapped.RowPitch;\n                        dptr += img->rowPitch;\n                    }\n\n                    pslice += mapped.DepthPitch;\n                }\n\n                pContext->Unmap(pSource, dindex);\n\n                if (height > 1)\n                    height >>= 1;\n                if (depth > 1)\n                    depth >>= 1;\n            }\n        }\n        else\n        {\n            //--- 1D or 2D texture --------------------------------------------------------\n            assert(metadata.depth == 1);\n\n            for (size_t item = 0; item < metadata.arraySize; ++item)\n            {\n                size_t height = metadata.height;\n\n                for (size_t level = 0; level < metadata.mipLevels; ++level)\n                {\n                    const UINT dindex = D3D11CalcSubresource(static_cast<UINT>(level), static_cast<UINT>(item), static_cast<UINT>(metadata.mipLevels));\n\n                    D3D11_MAPPED_SUBRESOURCE mapped;\n                    HRESULT hr = pContext->Map(pSource, dindex, D3D11_MAP_READ, 0, &mapped);\n                    if (FAILED(hr))\n                        return hr;\n\n                    const Image* img = result.GetImage(level, item, 0);\n                    if (!img)\n                    {\n                        pContext->Unmap(pSource, dindex);\n                        return E_FAIL;\n                    }\n\n                    if (!img->pixels)\n                    {\n                        pContext->Unmap(pSource, dindex);\n                        return E_POINTER;\n                    }\n\n                    const size_t lines = ComputeScanlines(metadata.format, height);\n                    if (!lines)\n                    {\n                        pContext->Unmap(pSource, dindex);\n                        return E_UNEXPECTED;\n                    }\n\n                    const size_t msize = (metadata.dimension == TEX_DIMENSION_TEXTURE2D)\n                        ? std::min<size_t>(img->rowPitch, mapped.RowPitch) : img->rowPitch;\n\n                    auto sptr = static_cast<const uint8_t*>(mapped.pData);\n                    uint8_t* dptr = img->pixels;\n                    for (size_t h = 0; h < lines; ++h)\n                    {\n                        memcpy(dptr, sptr, msize);\n                        sptr += mapped.RowPitch;\n                        dptr += img->rowPitch;\n                    }\n\n                    pContext->Unmap(pSource, dindex);\n\n                    if (height > 1)\n                        height >>= 1;\n                }\n            }\n        }\n\n        return S_OK;\n    }\n}\n\n\n//=====================================================================================\n// Entry-points\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n// Determine if given texture metadata is supported on the given device\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nbool DirectX::IsSupportedTexture(\n    ID3D11Device* pDevice,\n    const TexMetadata& metadata) noexcept\n{\n    if (!pDevice)\n        return false;\n\n    const D3D_FEATURE_LEVEL fl = pDevice->GetFeatureLevel();\n\n    // Validate format\n    const DXGI_FORMAT fmt = metadata.format;\n\n    if (!IsValid(fmt))\n        return false;\n\n    switch (fmt)\n    {\n    case DXGI_FORMAT_BC4_TYPELESS:\n    case DXGI_FORMAT_BC4_UNORM:\n    case DXGI_FORMAT_BC4_SNORM:\n    case DXGI_FORMAT_BC5_TYPELESS:\n    case DXGI_FORMAT_BC5_UNORM:\n    case DXGI_FORMAT_BC5_SNORM:\n        if (fl < D3D_FEATURE_LEVEL_10_0)\n            return false;\n        break;\n\n    case DXGI_FORMAT_BC6H_TYPELESS:\n    case DXGI_FORMAT_BC6H_UF16:\n    case DXGI_FORMAT_BC6H_SF16:\n    case DXGI_FORMAT_BC7_TYPELESS:\n    case DXGI_FORMAT_BC7_UNORM:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n        if (fl < D3D_FEATURE_LEVEL_11_0)\n            return false;\n        break;\n\n    default:\n        break;\n    }\n\n    // Validate miplevel count\n    if (metadata.mipLevels > D3D11_REQ_MIP_LEVELS)\n        return false;\n\n    // Validate array size, dimension, and width/height\n    const size_t arraySize = metadata.arraySize;\n    const size_t iWidth = metadata.width;\n    const size_t iHeight = metadata.height;\n    const size_t iDepth = metadata.depth;\n\n    // Most cases are known apriori based on feature level, but we use this for robustness to handle the few optional cases\n    UINT formatSupport = 0;\n    HRESULT hr = pDevice->CheckFormatSupport(fmt, &formatSupport);\n    if (FAILED(hr))\n    {\n        formatSupport = 0;\n    }\n\n    if (metadata.mipLevels > 1 && !(formatSupport & D3D11_FORMAT_SUPPORT_MIP))\n    {\n        return false;\n    }\n\n    switch (metadata.dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n        if (!(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE1D))\n            return false;\n\n        if ((arraySize > D3D11_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION)\n            || (iWidth > D3D11_REQ_TEXTURE1D_U_DIMENSION))\n            return false;\n\n        if (fl < D3D_FEATURE_LEVEL_11_0)\n        {\n            if ((arraySize > D3D10_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION)\n                || (iWidth > D3D10_REQ_TEXTURE1D_U_DIMENSION))\n                return false;\n\n            if (fl < D3D_FEATURE_LEVEL_10_0)\n            {\n                if ((arraySize > 1) || (iWidth > D3D_FL9_3_REQ_TEXTURE1D_U_DIMENSION))\n                    return false;\n\n                if ((fl < D3D_FEATURE_LEVEL_9_3) && (iWidth > D3D_FL9_1_REQ_TEXTURE1D_U_DIMENSION))\n                    return false;\n            }\n        }\n        break;\n\n    case TEX_DIMENSION_TEXTURE2D:\n        if (metadata.IsCubemap())\n        {\n            if (!(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURECUBE))\n                return false;\n\n            if ((arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION)\n                || (iWidth > D3D11_REQ_TEXTURECUBE_DIMENSION)\n                || (iHeight > D3D11_REQ_TEXTURECUBE_DIMENSION))\n                return false;\n\n            if (fl < D3D_FEATURE_LEVEL_11_0)\n            {\n                if ((arraySize > D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION)\n                    || (iWidth > D3D10_REQ_TEXTURECUBE_DIMENSION)\n                    || (iHeight > D3D10_REQ_TEXTURECUBE_DIMENSION))\n                    return false;\n\n                if ((fl < D3D_FEATURE_LEVEL_10_1) && (arraySize != 6))\n                    return false;\n\n                if (fl < D3D_FEATURE_LEVEL_10_0)\n                {\n                    if ((iWidth > D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION)\n                        || (iHeight > D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION))\n                        return false;\n\n                    if ((fl < D3D_FEATURE_LEVEL_9_3)\n                        && ((iWidth > D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION)\n                            || (iHeight > D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION)))\n                        return false;\n                }\n            }\n        }\n        else // Not a cube map\n        {\n            if (!(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D))\n                return false;\n\n            if ((arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION)\n                || (iWidth > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION)\n                || (iHeight > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION))\n                return false;\n\n            if (fl < D3D_FEATURE_LEVEL_11_0)\n            {\n                if ((arraySize > D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION)\n                    || (iWidth > D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION)\n                    || (iHeight > D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION))\n                    return false;\n\n                if (fl < D3D_FEATURE_LEVEL_10_0)\n                {\n                    if ((arraySize > 1)\n                        || (iWidth > D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION)\n                        || (iHeight > D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION))\n                        return false;\n\n                    if ((fl < D3D_FEATURE_LEVEL_9_3)\n                        && ((iWidth > D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION)\n                            || (iHeight > D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION)))\n                        return false;\n                }\n            }\n        }\n        break;\n\n    case TEX_DIMENSION_TEXTURE3D:\n        if (!(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE3D))\n            return false;\n\n        if ((arraySize > 1)\n            || (iWidth > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION)\n            || (iHeight > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION)\n            || (iDepth > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION))\n            return false;\n\n        if (fl < D3D_FEATURE_LEVEL_11_0)\n        {\n            if ((iWidth > D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION)\n                || (iHeight > D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION)\n                || (iDepth > D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION))\n                return false;\n\n            if (fl < D3D_FEATURE_LEVEL_10_0)\n            {\n                if ((iWidth > D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION)\n                    || (iHeight > D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION)\n                    || (iDepth > D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION))\n                    return false;\n            }\n        }\n        break;\n\n    default:\n        // Not a supported dimension\n        return false;\n    }\n\n    return true;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Create a texture resource\n//-------------------------------------------------------------------------------------\n#if 0\n\n_Use_decl_annotations_\nHRESULT DirectX::CreateTexture(\n    ID3D11Device* pDevice,\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    ID3D11Resource** ppResource) noexcept\n{\n    return CreateTextureEx(\n        pDevice, srcImages, nimages, metadata,\n        D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0, false,\n        ppResource);\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::CreateTextureEx(\n    ID3D11Device* pDevice,\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    D3D11_USAGE usage,\n    unsigned int bindFlags,\n    unsigned int cpuAccessFlags,\n    unsigned int miscFlags,\n    bool forceSRGB,\n    ID3D11Resource** ppResource) noexcept\n{\n    if (!pDevice || !srcImages || !nimages || !ppResource)\n        return E_INVALIDARG;\n\n    *ppResource = nullptr;\n\n    if (!metadata.mipLevels || !metadata.arraySize)\n        return E_INVALIDARG;\n\n    if ((metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX)\n        || (metadata.mipLevels > UINT16_MAX) || (metadata.arraySize > UINT16_MAX))\n        return E_INVALIDARG;\n\n    std::unique_ptr<D3D11_SUBRESOURCE_DATA[]> initData(new (std::nothrow) D3D11_SUBRESOURCE_DATA[metadata.mipLevels * metadata.arraySize]);\n    if (!initData)\n        return E_OUTOFMEMORY;\n\n    // Fill out subresource array\n    if (metadata.IsVolumemap())\n    {\n        //--- Volume case -------------------------------------------------------------\n        if (!metadata.depth)\n            return E_INVALIDARG;\n\n        if (metadata.depth > UINT16_MAX)\n            return E_INVALIDARG;\n\n        if (metadata.arraySize > 1)\n            // Direct3D 11 doesn't support arrays of 3D textures\n            return HRESULT_E_NOT_SUPPORTED;\n\n        size_t depth = metadata.depth;\n\n        size_t idx = 0;\n        for (size_t level = 0; level < metadata.mipLevels; ++level)\n        {\n            const size_t index = metadata.ComputeIndex(level, 0, 0);\n            if (index >= nimages)\n                return E_FAIL;\n\n            const Image& img = srcImages[index];\n\n            if (img.format != metadata.format)\n                return E_FAIL;\n\n            if (!img.pixels)\n                return E_POINTER;\n\n            // Verify pixels in image 1 .. (depth-1) are exactly image->slicePitch apart\n            // For 3D textures, this relies on all slices of the same miplevel being continous in memory\n            // (this is how ScratchImage lays them out), which is why we just give the 0th slice to Direct3D 11\n            const uint8_t* pSlice = img.pixels + img.slicePitch;\n            for (size_t slice = 1; slice < depth; ++slice)\n            {\n                const size_t tindex = metadata.ComputeIndex(level, 0, slice);\n                if (tindex >= nimages)\n                    return E_FAIL;\n\n                const Image& timg = srcImages[tindex];\n\n                if (!timg.pixels)\n                    return E_POINTER;\n\n                if (timg.pixels != pSlice\n                    || timg.format != metadata.format\n                    || timg.rowPitch != img.rowPitch\n                    || timg.slicePitch != img.slicePitch)\n                    return E_FAIL;\n\n                pSlice = timg.pixels + img.slicePitch;\n            }\n\n            assert(idx < (metadata.mipLevels * metadata.arraySize));\n\n            initData[idx].pSysMem = img.pixels;\n            initData[idx].SysMemPitch = static_cast<DWORD>(img.rowPitch);\n            initData[idx].SysMemSlicePitch = static_cast<DWORD>(img.slicePitch);\n            ++idx;\n\n            if (depth > 1)\n                depth >>= 1;\n        }\n    }\n    else\n    {\n        //--- 1D or 2D texture case ---------------------------------------------------\n        size_t idx = 0;\n        for (size_t item = 0; item < metadata.arraySize; ++item)\n        {\n            for (size_t level = 0; level < metadata.mipLevels; ++level)\n            {\n                const size_t index = metadata.ComputeIndex(level, item, 0);\n                if (index >= nimages)\n                    return E_FAIL;\n\n                const Image& img = srcImages[index];\n\n                if (img.format != metadata.format)\n                    return E_FAIL;\n\n                if (!img.pixels)\n                    return E_POINTER;\n\n                assert(idx < (metadata.mipLevels * metadata.arraySize));\n\n                initData[idx].pSysMem = img.pixels;\n                initData[idx].SysMemPitch = static_cast<DWORD>(img.rowPitch);\n                initData[idx].SysMemSlicePitch = static_cast<DWORD>(img.slicePitch);\n                ++idx;\n            }\n        }\n    }\n\n    // Create texture using static initialization data\n    HRESULT hr = E_UNEXPECTED;\n\n    const DXGI_FORMAT tformat = (forceSRGB) ? MakeSRGB(metadata.format) : metadata.format;\n\n    switch (metadata.dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n        {\n            D3D11_TEXTURE1D_DESC desc = {};\n            desc.Width = static_cast<UINT>(metadata.width);\n            desc.MipLevels = static_cast<UINT>(metadata.mipLevels);\n            desc.ArraySize = static_cast<UINT>(metadata.arraySize);\n            desc.Format = tformat;\n            desc.Usage = usage;\n            desc.BindFlags = bindFlags;\n            desc.CPUAccessFlags = cpuAccessFlags;\n            desc.MiscFlags = miscFlags & ~static_cast<uint32_t>(D3D11_RESOURCE_MISC_TEXTURECUBE);\n\n            hr = pDevice->CreateTexture1D(&desc, initData.get(), reinterpret_cast<ID3D11Texture1D**>(ppResource));\n        }\n        break;\n\n    case TEX_DIMENSION_TEXTURE2D:\n        {\n            D3D11_TEXTURE2D_DESC desc = {};\n            desc.Width = static_cast<UINT>(metadata.width);\n            desc.Height = static_cast<UINT>(metadata.height);\n            desc.MipLevels = static_cast<UINT>(metadata.mipLevels);\n            desc.ArraySize = static_cast<UINT>(metadata.arraySize);\n            desc.Format = tformat;\n            desc.SampleDesc.Count = 1;\n            desc.SampleDesc.Quality = 0;\n            desc.Usage = usage;\n            desc.BindFlags = bindFlags;\n            desc.CPUAccessFlags = cpuAccessFlags;\n            if (metadata.IsCubemap())\n                desc.MiscFlags = miscFlags | D3D11_RESOURCE_MISC_TEXTURECUBE;\n            else\n                desc.MiscFlags = miscFlags & ~static_cast<uint32_t>(D3D11_RESOURCE_MISC_TEXTURECUBE);\n\n            hr = pDevice->CreateTexture2D(&desc, initData.get(), reinterpret_cast<ID3D11Texture2D**>(ppResource));\n        }\n        break;\n\n    case TEX_DIMENSION_TEXTURE3D:\n        {\n            D3D11_TEXTURE3D_DESC desc = {};\n            desc.Width = static_cast<UINT>(metadata.width);\n            desc.Height = static_cast<UINT>(metadata.height);\n            desc.Depth = static_cast<UINT>(metadata.depth);\n            desc.MipLevels = static_cast<UINT>(metadata.mipLevels);\n            desc.Format = tformat;\n            desc.Usage = usage;\n            desc.BindFlags = bindFlags;\n            desc.CPUAccessFlags = cpuAccessFlags;\n            desc.MiscFlags = miscFlags & ~static_cast<uint32_t>(D3D11_RESOURCE_MISC_TEXTURECUBE);\n\n            hr = pDevice->CreateTexture3D(&desc, initData.get(), reinterpret_cast<ID3D11Texture3D**>(ppResource));\n        }\n        break;\n    }\n\n    return hr;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Create a shader resource view and associated texture\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::CreateShaderResourceView(\n    ID3D11Device* pDevice,\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    ID3D11ShaderResourceView** ppSRV) noexcept\n{\n    return CreateShaderResourceViewEx(\n        pDevice, srcImages, nimages, metadata,\n        D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0, false,\n        ppSRV);\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::CreateShaderResourceViewEx(\n    ID3D11Device* pDevice,\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    D3D11_USAGE usage,\n    unsigned int bindFlags,\n    unsigned int cpuAccessFlags,\n    unsigned int miscFlags,\n    bool forceSRGB,\n    ID3D11ShaderResourceView** ppSRV) noexcept\n{\n    if (!ppSRV)\n        return E_INVALIDARG;\n\n    *ppSRV = nullptr;\n\n    if (!(bindFlags & D3D11_BIND_SHADER_RESOURCE))\n        return E_INVALIDARG;\n\n    ComPtr<ID3D11Resource> resource;\n    HRESULT hr = CreateTextureEx(pDevice, srcImages, nimages, metadata,\n        usage, bindFlags, cpuAccessFlags, miscFlags, forceSRGB,\n        resource.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    assert(resource);\n\n    D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc = {};\n    if (forceSRGB)\n        SRVDesc.Format = MakeSRGB(metadata.format);\n    else\n        SRVDesc.Format = metadata.format;\n\n    switch (metadata.dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n        if (metadata.arraySize > 1)\n        {\n            SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1DARRAY;\n            SRVDesc.Texture1DArray.MipLevels = static_cast<UINT>(metadata.mipLevels);\n            SRVDesc.Texture1DArray.ArraySize = static_cast<UINT>(metadata.arraySize);\n        }\n        else\n        {\n            SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1D;\n            SRVDesc.Texture1D.MipLevels = static_cast<UINT>(metadata.mipLevels);\n        }\n        break;\n\n    case TEX_DIMENSION_TEXTURE2D:\n        if (metadata.IsCubemap())\n        {\n            if (metadata.arraySize > 6)\n            {\n                assert((metadata.arraySize % 6) == 0);\n                SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBEARRAY;\n                SRVDesc.TextureCubeArray.MipLevels = static_cast<UINT>(metadata.mipLevels);\n                SRVDesc.TextureCubeArray.NumCubes = static_cast<UINT>(metadata.arraySize / 6);\n            }\n            else\n            {\n                SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBE;\n                SRVDesc.TextureCube.MipLevels = static_cast<UINT>(metadata.mipLevels);\n            }\n        }\n        else if (metadata.arraySize > 1)\n        {\n            SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2DARRAY;\n            SRVDesc.Texture2DArray.MipLevels = static_cast<UINT>(metadata.mipLevels);\n            SRVDesc.Texture2DArray.ArraySize = static_cast<UINT>(metadata.arraySize);\n        }\n        else\n        {\n            SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2D;\n            SRVDesc.Texture2D.MipLevels = static_cast<UINT>(metadata.mipLevels);\n        }\n        break;\n\n    case TEX_DIMENSION_TEXTURE3D:\n        assert(metadata.arraySize == 1);\n        SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE3D;\n        SRVDesc.Texture3D.MipLevels = static_cast<UINT>(metadata.mipLevels);\n        break;\n\n    default:\n        return E_FAIL;\n    }\n\n    hr = pDevice->CreateShaderResourceView(resource.Get(), &SRVDesc, ppSRV);\n    if (FAILED(hr))\n        return hr;\n\n    assert(*ppSRV);\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Save a texture resource\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::CaptureTexture(\n    ID3D11Device* pDevice,\n    ID3D11DeviceContext* pContext,\n    ID3D11Resource* pSource,\n    ScratchImage& result) noexcept\n{\n    if (!pDevice || !pContext || !pSource)\n        return E_INVALIDARG;\n\n    D3D11_RESOURCE_DIMENSION resType = D3D11_RESOURCE_DIMENSION_UNKNOWN;\n    pSource->GetType(&resType);\n\n    HRESULT hr = E_UNEXPECTED;\n\n    switch (resType)\n    {\n    case D3D11_RESOURCE_DIMENSION_TEXTURE1D:\n        {\n            ComPtr<ID3D11Texture1D> pTexture;\n            hr = pSource->QueryInterface(IID_GRAPHICS_PPV_ARGS(pTexture.GetAddressOf()));\n            if (FAILED(hr))\n                break;\n\n            assert(pTexture);\n\n            D3D11_TEXTURE1D_DESC desc;\n            pTexture->GetDesc(&desc);\n\n            ComPtr<ID3D11Texture1D> pStaging;\n            if ((desc.Usage == D3D11_USAGE_STAGING) && (desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ))\n            {\n                // Handle case where the source is already a staging texture we can use directly\n                pStaging = pTexture;\n            }\n            else\n            {\n                desc.BindFlags = 0;\n                desc.MiscFlags = 0;\n                desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;\n                desc.Usage = D3D11_USAGE_STAGING;\n\n                hr = pDevice->CreateTexture1D(&desc, nullptr, pStaging.GetAddressOf());\n                if (FAILED(hr))\n                    break;\n\n                assert(pStaging);\n\n                pContext->CopyResource(pStaging.Get(), pSource);\n            }\n\n            TexMetadata mdata;\n            mdata.width = desc.Width;\n            mdata.height = mdata.depth = 1;\n            mdata.arraySize = desc.ArraySize;\n            mdata.mipLevels = desc.MipLevels;\n            mdata.miscFlags = 0;\n            mdata.miscFlags2 = 0;\n            mdata.format = desc.Format;\n            mdata.dimension = TEX_DIMENSION_TEXTURE1D;\n\n            hr = result.Initialize(mdata);\n            if (FAILED(hr))\n                break;\n\n            hr = Capture(pContext, pStaging.Get(), mdata, result);\n        }\n        break;\n\n    case D3D11_RESOURCE_DIMENSION_TEXTURE2D:\n        {\n            ComPtr<ID3D11Texture2D> pTexture;\n            hr = pSource->QueryInterface(IID_GRAPHICS_PPV_ARGS(pTexture.GetAddressOf()));\n            if (FAILED(hr))\n                break;\n\n            assert(pTexture);\n\n            D3D11_TEXTURE2D_DESC desc;\n            pTexture->GetDesc(&desc);\n\n            ComPtr<ID3D11Texture2D> pStaging;\n            if (desc.SampleDesc.Count > 1)\n            {\n                desc.SampleDesc.Count = 1;\n                desc.SampleDesc.Quality = 0;\n\n                ComPtr<ID3D11Texture2D> pTemp;\n                hr = pDevice->CreateTexture2D(&desc, nullptr, pTemp.GetAddressOf());\n                if (FAILED(hr))\n                    break;\n\n                assert(pTemp);\n\n                DXGI_FORMAT fmt = desc.Format;\n                if (IsTypeless(fmt))\n                {\n                    // Assume a UNORM if it exists otherwise use FLOAT\n                    fmt = MakeTypelessUNORM(fmt);\n                    fmt = MakeTypelessFLOAT(fmt);\n                }\n\n                UINT support = 0;\n                hr = pDevice->CheckFormatSupport(fmt, &support);\n                if (FAILED(hr))\n                    break;\n\n                if (!(support & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE))\n                {\n                    hr = E_FAIL;\n                    break;\n                }\n\n                for (UINT item = 0; item < desc.ArraySize; ++item)\n                {\n                    for (UINT level = 0; level < desc.MipLevels; ++level)\n                    {\n                        const UINT index = D3D11CalcSubresource(level, item, desc.MipLevels);\n                        pContext->ResolveSubresource(pTemp.Get(), index, pSource, index, fmt);\n                    }\n                }\n\n                desc.BindFlags = 0;\n                desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE;\n                desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;\n                desc.Usage = D3D11_USAGE_STAGING;\n\n                hr = pDevice->CreateTexture2D(&desc, nullptr, pStaging.GetAddressOf());\n                if (FAILED(hr))\n                    break;\n\n                assert(pStaging);\n\n                pContext->CopyResource(pStaging.Get(), pTemp.Get());\n            }\n            else if ((desc.Usage == D3D11_USAGE_STAGING) && (desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ))\n            {\n                // Handle case where the source is already a staging texture we can use directly\n                pStaging = pTexture;\n            }\n            else\n            {\n                desc.BindFlags = 0;\n                desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE;\n                desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;\n                desc.Usage = D3D11_USAGE_STAGING;\n\n                hr = pDevice->CreateTexture2D(&desc, nullptr, &pStaging);\n                if (FAILED(hr))\n                    break;\n\n                assert(pStaging);\n\n                pContext->CopyResource(pStaging.Get(), pSource);\n            }\n\n            TexMetadata mdata;\n            mdata.width = desc.Width;\n            mdata.height = desc.Height;\n            mdata.depth = 1;\n            mdata.arraySize = desc.ArraySize;\n            mdata.mipLevels = desc.MipLevels;\n            mdata.miscFlags = (desc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) ? TEX_MISC_TEXTURECUBE : 0u;\n            mdata.miscFlags2 = 0;\n            mdata.format = desc.Format;\n            mdata.dimension = TEX_DIMENSION_TEXTURE2D;\n\n            hr = result.Initialize(mdata);\n            if (FAILED(hr))\n                break;\n\n            hr = Capture(pContext, pStaging.Get(), mdata, result);\n        }\n        break;\n\n    case D3D11_RESOURCE_DIMENSION_TEXTURE3D:\n        {\n            ComPtr<ID3D11Texture3D> pTexture;\n            hr = pSource->QueryInterface(IID_GRAPHICS_PPV_ARGS(pTexture.GetAddressOf()));\n            if (FAILED(hr))\n                break;\n\n            assert(pTexture);\n\n            D3D11_TEXTURE3D_DESC desc;\n            pTexture->GetDesc(&desc);\n\n            ComPtr<ID3D11Texture3D> pStaging;\n            if ((desc.Usage == D3D11_USAGE_STAGING) && (desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ))\n            {\n                // Handle case where the source is already a staging texture we can use directly\n                pStaging = pTexture;\n            }\n            else\n            {\n                desc.BindFlags = 0;\n                desc.MiscFlags = 0;\n                desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;\n                desc.Usage = D3D11_USAGE_STAGING;\n\n                hr = pDevice->CreateTexture3D(&desc, nullptr, pStaging.GetAddressOf());\n                if (FAILED(hr))\n                    break;\n\n                assert(pStaging);\n\n                pContext->CopyResource(pStaging.Get(), pSource);\n            }\n\n            TexMetadata mdata;\n            mdata.width = desc.Width;\n            mdata.height = desc.Height;\n            mdata.depth = desc.Depth;\n            mdata.arraySize = 1;\n            mdata.mipLevels = desc.MipLevels;\n            mdata.miscFlags = 0;\n            mdata.miscFlags2 = 0;\n            mdata.format = desc.Format;\n            mdata.dimension = TEX_DIMENSION_TEXTURE3D;\n\n            hr = result.Initialize(mdata);\n            if (FAILED(hr))\n                break;\n\n            hr = Capture(pContext, pStaging.Get(), mdata, result);\n        }\n        break;\n\n    default:\n        hr = E_FAIL;\n        break;\n    }\n\n    if (FAILED(hr))\n    {\n        result.Release();\n        return hr;\n    }\n\n    return S_OK;\n}\n\n#endif\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTexDDS.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTexDDS.cpp\n//\n// DirectX Texture Library - Microsoft DirectDraw Surface (DDS) file format reader/writer\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\n#include \"DDS.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::Internal;\n\nstatic_assert(static_cast<int>(TEX_DIMENSION_TEXTURE1D) == static_cast<int>(DDS_DIMENSION_TEXTURE1D), \"header enum mismatch\");\nstatic_assert(static_cast<int>(TEX_DIMENSION_TEXTURE2D) == static_cast<int>(DDS_DIMENSION_TEXTURE2D), \"header enum mismatch\");\nstatic_assert(static_cast<int>(TEX_DIMENSION_TEXTURE3D) == static_cast<int>(DDS_DIMENSION_TEXTURE3D), \"header enum mismatch\");\n\nnamespace\n{\n    constexpr size_t MAX_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10);\n\n    //-------------------------------------------------------------------------------------\n    // Legacy format mapping table (used for DDS files without 'DX10' extended header)\n    //-------------------------------------------------------------------------------------\n    enum CONVERSION_FLAGS : uint32_t\n    {\n        CONV_FLAGS_NONE = 0x0,\n        CONV_FLAGS_EXPAND = 0x1,      // Conversion requires expanded pixel size\n        CONV_FLAGS_NOALPHA = 0x2,      // Conversion requires setting alpha to known value\n        CONV_FLAGS_SWIZZLE = 0x4,      // BGR/RGB order swizzling required\n        CONV_FLAGS_PAL8 = 0x8,      // Has an 8-bit palette\n        CONV_FLAGS_888 = 0x10,     // Source is an 8:8:8 (24bpp) format\n        CONV_FLAGS_565 = 0x20,     // Source is a 5:6:5 (16bpp) format\n        CONV_FLAGS_5551 = 0x40,     // Source is a 5:5:5:1 (16bpp) format\n        CONV_FLAGS_4444 = 0x80,     // Source is a 4:4:4:4 (16bpp) format\n        CONV_FLAGS_44 = 0x100,    // Source is a 4:4 (8bpp) format\n        CONV_FLAGS_332 = 0x200,    // Source is a 3:3:2 (8bpp) format\n        CONV_FLAGS_8332 = 0x400,    // Source is a 8:3:3:2 (16bpp) format\n        CONV_FLAGS_A8P8 = 0x800,    // Has an 8-bit palette with an alpha channel\n        CONV_FLAGS_DX10 = 0x10000,  // Has the 'DX10' extension header\n        CONV_FLAGS_PMALPHA = 0x20000,  // Contains premultiplied alpha data\n        CONV_FLAGS_L8 = 0x40000,  // Source is a 8 luminance format\n        CONV_FLAGS_L16 = 0x80000,  // Source is a 16 luminance format\n        CONV_FLAGS_A8L8 = 0x100000, // Source is a 8:8 luminance format\n    };\n\n    struct LegacyDDS\n    {\n        DXGI_FORMAT     format;\n        uint32_t        convFlags;\n        DDS_PIXELFORMAT ddpf;\n    };\n\n    const LegacyDDS g_LegacyDDSMap[] =\n    {\n        { DXGI_FORMAT_BC1_UNORM,          CONV_FLAGS_NONE,        DDSPF_DXT1 }, // D3DFMT_DXT1\n        { DXGI_FORMAT_BC2_UNORM,          CONV_FLAGS_NONE,        DDSPF_DXT3 }, // D3DFMT_DXT3\n        { DXGI_FORMAT_BC3_UNORM,          CONV_FLAGS_NONE,        DDSPF_DXT5 }, // D3DFMT_DXT5\n\n        { DXGI_FORMAT_BC2_UNORM,          CONV_FLAGS_PMALPHA,     DDSPF_DXT2 }, // D3DFMT_DXT2\n        { DXGI_FORMAT_BC3_UNORM,          CONV_FLAGS_PMALPHA,     DDSPF_DXT4 }, // D3DFMT_DXT4\n\n        { DXGI_FORMAT_BC4_UNORM,          CONV_FLAGS_NONE,        DDSPF_BC4_UNORM },\n        { DXGI_FORMAT_BC4_SNORM,          CONV_FLAGS_NONE,        DDSPF_BC4_SNORM },\n        { DXGI_FORMAT_BC5_UNORM,          CONV_FLAGS_NONE,        DDSPF_BC5_UNORM },\n        { DXGI_FORMAT_BC5_SNORM,          CONV_FLAGS_NONE,        DDSPF_BC5_SNORM },\n\n        { DXGI_FORMAT_BC4_UNORM,          CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'T', 'I', '1'), 0, 0, 0, 0, 0 } },\n        { DXGI_FORMAT_BC5_UNORM,          CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'T', 'I', '2'), 0, 0, 0, 0, 0 } },\n\n        { DXGI_FORMAT_BC6H_UF16,          CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B', 'C', '6', 'H'), 0, 0, 0, 0, 0 } },\n        { DXGI_FORMAT_BC7_UNORM,          CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B', 'C', '7', 'L'), 0, 0, 0, 0, 0 } },\n        { DXGI_FORMAT_BC7_UNORM,          CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B', 'C', '7', '\\0'), 0, 0, 0, 0, 0 } },\n\n        { DXGI_FORMAT_R8G8_B8G8_UNORM,    CONV_FLAGS_NONE,        DDSPF_R8G8_B8G8 }, // D3DFMT_R8G8_B8G8\n        { DXGI_FORMAT_G8R8_G8B8_UNORM,    CONV_FLAGS_NONE,        DDSPF_G8R8_G8B8 }, // D3DFMT_G8R8_G8B8\n\n        { DXGI_FORMAT_B8G8R8A8_UNORM,     CONV_FLAGS_NONE,        DDSPF_A8R8G8B8 }, // D3DFMT_A8R8G8B8 (uses DXGI 1.1 format)\n        { DXGI_FORMAT_B8G8R8X8_UNORM,     CONV_FLAGS_NONE,        DDSPF_X8R8G8B8 }, // D3DFMT_X8R8G8B8 (uses DXGI 1.1 format)\n        { DXGI_FORMAT_R8G8B8A8_UNORM,     CONV_FLAGS_NONE,        DDSPF_A8B8G8R8 }, // D3DFMT_A8B8G8R8\n        { DXGI_FORMAT_R8G8B8A8_UNORM,     CONV_FLAGS_NOALPHA,     DDSPF_X8B8G8R8 }, // D3DFMT_X8B8G8R8\n        { DXGI_FORMAT_R16G16_UNORM,       CONV_FLAGS_NONE,        DDSPF_G16R16   }, // D3DFMT_G16R16\n\n        { DXGI_FORMAT_R10G10B10A2_UNORM,  CONV_FLAGS_SWIZZLE,     DDSPF_A2R10G10B10 }, // D3DFMT_A2R10G10B10 (D3DX reversal issue)\n        { DXGI_FORMAT_R10G10B10A2_UNORM,  CONV_FLAGS_NONE,        DDSPF_A2B10G10R10 }, // D3DFMT_A2B10G10R10 (D3DX reversal issue)\n\n        { DXGI_FORMAT_R8G8B8A8_UNORM,     CONV_FLAGS_EXPAND\n                                          | CONV_FLAGS_NOALPHA\n                                          | CONV_FLAGS_888,       DDSPF_R8G8B8 }, // D3DFMT_R8G8B8\n\n        { DXGI_FORMAT_B5G6R5_UNORM,       CONV_FLAGS_565,         DDSPF_R5G6B5 }, // D3DFMT_R5G6B5\n        { DXGI_FORMAT_B5G5R5A1_UNORM,     CONV_FLAGS_5551,        DDSPF_A1R5G5B5 }, // D3DFMT_A1R5G5B5\n        { DXGI_FORMAT_B5G5R5A1_UNORM,     CONV_FLAGS_5551\n                                          | CONV_FLAGS_NOALPHA,   DDSPF_X1R5G5B5 }, // D3DFMT_X1R5G5B5\n\n        { DXGI_FORMAT_R8G8B8A8_UNORM,     CONV_FLAGS_EXPAND\n                                          | CONV_FLAGS_8332,      DDSPF_A8R3G3B2 }, // D3DFMT_A8R3G3B2\n        { DXGI_FORMAT_B5G6R5_UNORM,       CONV_FLAGS_EXPAND\n                                          | CONV_FLAGS_332,       DDSPF_R3G3B2 }, // D3DFMT_R3G3B2\n\n        { DXGI_FORMAT_R8_UNORM,           CONV_FLAGS_NONE,        DDSPF_L8 }, // D3DFMT_L8\n        { DXGI_FORMAT_R16_UNORM,          CONV_FLAGS_NONE,        DDSPF_L16 }, // D3DFMT_L16\n        { DXGI_FORMAT_R8G8_UNORM,         CONV_FLAGS_NONE,        DDSPF_A8L8 }, // D3DFMT_A8L8\n        { DXGI_FORMAT_R8G8_UNORM,         CONV_FLAGS_NONE,        DDSPF_A8L8_ALT }, // D3DFMT_A8L8 (alternative bitcount)\n\n        // NVTT v1 wrote these with RGB instead of LUMINANCE\n        { DXGI_FORMAT_R8_UNORM,           CONV_FLAGS_NONE,        DDSPF_L8_NVTT1 }, // D3DFMT_L8\n        { DXGI_FORMAT_R16_UNORM,          CONV_FLAGS_NONE,        DDSPF_L16_NVTT1  }, // D3DFMT_L16\n        { DXGI_FORMAT_R8G8_UNORM,         CONV_FLAGS_NONE,        DDSPF_A8L8_NVTT1 }, // D3DFMT_A8L8\n\n        { DXGI_FORMAT_A8_UNORM,           CONV_FLAGS_NONE,        DDSPF_A8   }, // D3DFMT_A8\n\n        { DXGI_FORMAT_R16G16B16A16_UNORM, CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_FOURCC,   36,  0, 0, 0, 0, 0 } }, // D3DFMT_A16B16G16R16\n        { DXGI_FORMAT_R16G16B16A16_SNORM, CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_FOURCC,  110,  0, 0, 0, 0, 0 } }, // D3DFMT_Q16W16V16U16\n        { DXGI_FORMAT_R16_FLOAT,          CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_FOURCC,  111,  0, 0, 0, 0, 0 } }, // D3DFMT_R16F\n        { DXGI_FORMAT_R16G16_FLOAT,       CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_FOURCC,  112,  0, 0, 0, 0, 0 } }, // D3DFMT_G16R16F\n        { DXGI_FORMAT_R16G16B16A16_FLOAT, CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_FOURCC,  113,  0, 0, 0, 0, 0 } }, // D3DFMT_A16B16G16R16F\n        { DXGI_FORMAT_R32_FLOAT,          CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_FOURCC,  114,  0, 0, 0, 0, 0 } }, // D3DFMT_R32F\n        { DXGI_FORMAT_R32G32_FLOAT,       CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_FOURCC,  115,  0, 0, 0, 0, 0 } }, // D3DFMT_G32R32F\n        { DXGI_FORMAT_R32G32B32A32_FLOAT, CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_FOURCC,  116,  0, 0, 0, 0, 0 } }, // D3DFMT_A32B32G32R32F\n\n        { DXGI_FORMAT_R32_FLOAT,          CONV_FLAGS_NONE,        { sizeof(DDS_PIXELFORMAT), DDS_RGB,       0, 32, 0xffffffff, 0, 0, 0 } }, // D3DFMT_R32F (D3DX uses FourCC 114 instead)\n\n        { DXGI_FORMAT_R8G8B8A8_UNORM,     CONV_FLAGS_EXPAND\n                                          | CONV_FLAGS_PAL8\n                                          | CONV_FLAGS_A8P8,      { sizeof(DDS_PIXELFORMAT), DDS_PAL8A,     0, 16, 0, 0, 0, 0 } }, // D3DFMT_A8P8\n        { DXGI_FORMAT_R8G8B8A8_UNORM,     CONV_FLAGS_EXPAND\n                                          | CONV_FLAGS_PAL8,      { sizeof(DDS_PIXELFORMAT), DDS_PAL8,      0,  8, 0, 0, 0, 0 } }, // D3DFMT_P8\n\n        { DXGI_FORMAT_B4G4R4A4_UNORM,     CONV_FLAGS_4444,        DDSPF_A4R4G4B4 }, // D3DFMT_A4R4G4B4 (uses DXGI 1.2 format)\n        { DXGI_FORMAT_B4G4R4A4_UNORM,     CONV_FLAGS_NOALPHA\n                                          | CONV_FLAGS_4444,      DDSPF_X4R4G4B4 }, // D3DFMT_X4R4G4B4 (uses DXGI 1.2 format)\n        { DXGI_FORMAT_B4G4R4A4_UNORM,     CONV_FLAGS_EXPAND\n                                          | CONV_FLAGS_44,        DDSPF_A4L4 }, // D3DFMT_A4L4 (uses DXGI 1.2 format)\n\n        { DXGI_FORMAT_YUY2,               CONV_FLAGS_NONE,        DDSPF_YUY2 }, // D3DFMT_YUY2 (uses DXGI 1.2 format)\n        { DXGI_FORMAT_YUY2,               CONV_FLAGS_SWIZZLE,     DDSPF_UYVY }, // D3DFMT_UYVY (uses DXGI 1.2 format)\n\n        { DXGI_FORMAT_R8G8_SNORM,         CONV_FLAGS_NONE,        DDSPF_V8U8 },     // D3DFMT_V8U8\n        { DXGI_FORMAT_R8G8B8A8_SNORM,     CONV_FLAGS_NONE,        DDSPF_Q8W8V8U8 }, // D3DFMT_Q8W8V8U8\n        { DXGI_FORMAT_R16G16_SNORM,       CONV_FLAGS_NONE,        DDSPF_V16U16 },   // D3DFMT_V16U16\n    };\n\n    // Note that many common DDS reader/writers (including D3DX) swap the\n    // the RED/BLUE masks for 10:10:10:2 formats. We assumme\n    // below that the 'backwards' header mask is being used since it is most\n    // likely written by D3DX. The more robust solution is to use the 'DX10'\n    // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly\n\n    // We do not support the following legacy Direct3D 9 formats:\n    //      BumpDuDv D3DFMT_A2W10V10U10\n    //      BumpLuminance D3DFMT_L6V5U5, D3DFMT_X8L8V8U8\n    //      FourCC 117 D3DFMT_CxV8U8\n    //      ZBuffer D3DFMT_D16_LOCKABLE\n    //      FourCC 82 D3DFMT_D32F_LOCKABLE\n\n    // We do not support the following known FourCC codes:\n    //      FourCC CTX1 (Xbox 360 only)\n    //      FourCC EAR, EARG, ET2, ET2A (Ericsson Texture Compression)\n\n    DXGI_FORMAT GetDXGIFormat(const DDS_HEADER& hdr, const DDS_PIXELFORMAT& ddpf,\n        DDS_FLAGS flags,\n        _Inout_ uint32_t& convFlags) noexcept\n    {\n        uint32_t ddpfFlags = ddpf.flags;\n        if (hdr.reserved1[9] == MAKEFOURCC('N', 'V', 'T', 'T'))\n        {\n            // Clear out non-standard nVidia DDS flags\n            ddpfFlags &= ~0xC0000000 /* DDPF_SRGB | DDPF_NORMAL */;\n        }\n\n        constexpr size_t MAP_SIZE = sizeof(g_LegacyDDSMap) / sizeof(LegacyDDS);\n        size_t index = 0;\n        for (index = 0; index < MAP_SIZE; ++index)\n        {\n            const LegacyDDS* entry = &g_LegacyDDSMap[index];\n\n            if ((ddpfFlags & DDS_FOURCC) && (entry->ddpf.flags & DDS_FOURCC))\n            {\n                // In case of FourCC codes, ignore any other bits in ddpf.flags\n                if (ddpf.fourCC == entry->ddpf.fourCC)\n                    break;\n            }\n            else if (ddpfFlags == entry->ddpf.flags)\n            {\n                if (entry->ddpf.flags & DDS_PAL8)\n                {\n                    if (ddpf.RGBBitCount == entry->ddpf.RGBBitCount)\n                        break;\n                }\n                else if (entry->ddpf.flags & DDS_ALPHA)\n                {\n                    if (ddpf.RGBBitCount == entry->ddpf.RGBBitCount\n                        && ddpf.ABitMask == entry->ddpf.ABitMask)\n                        break;\n                }\n                else if (entry->ddpf.flags & DDS_LUMINANCE)\n                {\n                    if (entry->ddpf.flags & DDS_ALPHAPIXELS)\n                    {\n                        // LUMINANCEA\n                        if (ddpf.RGBBitCount == entry->ddpf.RGBBitCount\n                            && ddpf.RBitMask == entry->ddpf.RBitMask\n                            && ddpf.ABitMask == entry->ddpf.ABitMask)\n                            break;\n                    }\n                    else\n                    {\n                        // LUMINANCE\n                        if (ddpf.RGBBitCount == entry->ddpf.RGBBitCount\n                            && ddpf.RBitMask == entry->ddpf.RBitMask)\n                            break;\n                    }\n                }\n                else if (entry->ddpf.flags & DDS_BUMPDUDV)\n                {\n                    if (ddpf.RGBBitCount == entry->ddpf.RGBBitCount\n                        && ddpf.RBitMask == entry->ddpf.RBitMask\n                        && ddpf.GBitMask == entry->ddpf.GBitMask\n                        && ddpf.BBitMask == entry->ddpf.BBitMask\n                        && ddpf.ABitMask == entry->ddpf.ABitMask)\n                        break;\n                }\n                else if (ddpf.RGBBitCount == entry->ddpf.RGBBitCount)\n                {\n                    if (entry->ddpf.flags & DDS_ALPHAPIXELS)\n                    {\n                        // RGBA\n                        if (ddpf.RBitMask == entry->ddpf.RBitMask\n                            && ddpf.GBitMask == entry->ddpf.GBitMask\n                            && ddpf.BBitMask == entry->ddpf.BBitMask\n                            && ddpf.ABitMask == entry->ddpf.ABitMask)\n                            break;\n                    }\n                    else\n                    {\n                        // RGB\n                        if (ddpf.RBitMask == entry->ddpf.RBitMask\n                            && ddpf.GBitMask == entry->ddpf.GBitMask\n                            && ddpf.BBitMask == entry->ddpf.BBitMask)\n                            break;\n                    }\n                }\n            }\n        }\n\n        if (index >= MAP_SIZE)\n            return DXGI_FORMAT_UNKNOWN;\n\n        uint32_t cflags = g_LegacyDDSMap[index].convFlags;\n        DXGI_FORMAT format = g_LegacyDDSMap[index].format;\n\n        if ((cflags & CONV_FLAGS_EXPAND) && (flags & DDS_FLAGS_NO_LEGACY_EXPANSION))\n            return DXGI_FORMAT_UNKNOWN;\n\n        if ((format == DXGI_FORMAT_R10G10B10A2_UNORM) && (flags & DDS_FLAGS_NO_R10B10G10A2_FIXUP))\n        {\n            cflags ^= CONV_FLAGS_SWIZZLE;\n        }\n\n        if ((hdr.reserved1[9] == MAKEFOURCC('N', 'V', 'T', 'T'))\n            && (ddpf.flags & 0x40000000 /* DDPF_SRGB */))\n        {\n            format = MakeSRGB(format);\n        }\n\n        convFlags = cflags;\n\n        return format;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    // Decodes DDS header including optional DX10 extended header\n    //-------------------------------------------------------------------------------------\n    HRESULT DecodeDDSHeader(\n        _In_reads_bytes_(size) const void* pSource,\n        size_t size,\n        DDS_FLAGS flags,\n        _Out_ TexMetadata& metadata,\n        _Inout_ uint32_t& convFlags) noexcept\n    {\n        if (!pSource)\n            return E_INVALIDARG;\n\n        memset(&metadata, 0, sizeof(TexMetadata));\n\n        if (size < (sizeof(DDS_HEADER) + sizeof(uint32_t)))\n        {\n            return HRESULT_E_INVALID_DATA;\n        }\n\n        // DDS files always start with the same magic number (\"DDS \")\n        auto const dwMagicNumber = *static_cast<const uint32_t*>(pSource);\n        if (dwMagicNumber != DDS_MAGIC)\n        {\n            return E_FAIL;\n        }\n\n        auto pHeader = reinterpret_cast<const DDS_HEADER*>(static_cast<const uint8_t*>(pSource) + sizeof(uint32_t));\n\n        // Verify header to validate DDS file\n        if (pHeader->size != sizeof(DDS_HEADER)\n            || pHeader->ddspf.size != sizeof(DDS_PIXELFORMAT))\n        {\n            return E_FAIL;\n        }\n\n        metadata.mipLevels = pHeader->mipMapCount;\n        if (metadata.mipLevels == 0)\n            metadata.mipLevels = 1;\n\n        // Check for DX10 extension\n        if ((pHeader->ddspf.flags & DDS_FOURCC)\n            && (MAKEFOURCC('D', 'X', '1', '0') == pHeader->ddspf.fourCC))\n        {\n            // Buffer must be big enough for both headers and magic value\n            if (size < (sizeof(DDS_HEADER) + sizeof(uint32_t) + sizeof(DDS_HEADER_DXT10)))\n            {\n                return E_FAIL;\n            }\n\n            auto d3d10ext = reinterpret_cast<const DDS_HEADER_DXT10*>(static_cast<const uint8_t*>(pSource) + sizeof(uint32_t) + sizeof(DDS_HEADER));\n            convFlags |= CONV_FLAGS_DX10;\n\n            metadata.arraySize = d3d10ext->arraySize;\n            if (metadata.arraySize == 0)\n            {\n                return HRESULT_E_INVALID_DATA;\n            }\n\n            metadata.format = d3d10ext->dxgiFormat;\n            if (!IsValid(metadata.format) || IsPalettized(metadata.format))\n            {\n                return HRESULT_E_NOT_SUPPORTED;\n            }\n\n            static_assert(static_cast<int>(TEX_MISC_TEXTURECUBE) == static_cast<int>(DDS_RESOURCE_MISC_TEXTURECUBE), \"DDS header mismatch\");\n\n            metadata.miscFlags = d3d10ext->miscFlag & ~static_cast<uint32_t>(TEX_MISC_TEXTURECUBE);\n\n            switch (d3d10ext->resourceDimension)\n            {\n            case DDS_DIMENSION_TEXTURE1D:\n\n                // D3DX writes 1D textures with a fixed Height of 1\n                if ((pHeader->flags & DDS_HEIGHT) && pHeader->height != 1)\n                {\n                    return HRESULT_E_INVALID_DATA;\n                }\n\n                metadata.width = pHeader->width;\n                metadata.height = 1;\n                metadata.depth = 1;\n                metadata.dimension = TEX_DIMENSION_TEXTURE1D;\n                break;\n\n            case DDS_DIMENSION_TEXTURE2D:\n                if (d3d10ext->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE)\n                {\n                    metadata.miscFlags |= TEX_MISC_TEXTURECUBE;\n                    metadata.arraySize *= 6;\n                }\n\n                metadata.width = pHeader->width;\n                metadata.height = pHeader->height;\n                metadata.depth = 1;\n                metadata.dimension = TEX_DIMENSION_TEXTURE2D;\n                break;\n\n            case DDS_DIMENSION_TEXTURE3D:\n                if (!(pHeader->flags & DDS_HEADER_FLAGS_VOLUME))\n                {\n                    return HRESULT_E_INVALID_DATA;\n                }\n\n                if (metadata.arraySize > 1)\n                    return HRESULT_E_NOT_SUPPORTED;\n\n                metadata.width = pHeader->width;\n                metadata.height = pHeader->height;\n                metadata.depth = pHeader->depth;\n                metadata.dimension = TEX_DIMENSION_TEXTURE3D;\n                break;\n\n            default:\n                return HRESULT_E_INVALID_DATA;\n            }\n\n            static_assert(static_cast<int>(TEX_MISC2_ALPHA_MODE_MASK) == static_cast<int>(DDS_MISC_FLAGS2_ALPHA_MODE_MASK), \"DDS header mismatch\");\n\n            static_assert(static_cast<int>(TEX_ALPHA_MODE_UNKNOWN) == static_cast<int>(DDS_ALPHA_MODE_UNKNOWN), \"DDS header mismatch\");\n            static_assert(static_cast<int>(TEX_ALPHA_MODE_STRAIGHT) == static_cast<int>(DDS_ALPHA_MODE_STRAIGHT), \"DDS header mismatch\");\n            static_assert(static_cast<int>(TEX_ALPHA_MODE_PREMULTIPLIED) == static_cast<int>(DDS_ALPHA_MODE_PREMULTIPLIED), \"DDS header mismatch\");\n            static_assert(static_cast<int>(TEX_ALPHA_MODE_OPAQUE) == static_cast<int>(DDS_ALPHA_MODE_OPAQUE), \"DDS header mismatch\");\n            static_assert(static_cast<int>(TEX_ALPHA_MODE_CUSTOM) == static_cast<int>(DDS_ALPHA_MODE_CUSTOM), \"DDS header mismatch\");\n\n            metadata.miscFlags2 = d3d10ext->miscFlags2;\n        }\n        else\n        {\n            metadata.arraySize = 1;\n\n            if (pHeader->flags & DDS_HEADER_FLAGS_VOLUME)\n            {\n                metadata.width = pHeader->width;\n                metadata.height = pHeader->height;\n                metadata.depth = pHeader->depth;\n                metadata.dimension = TEX_DIMENSION_TEXTURE3D;\n            }\n            else\n            {\n                if (pHeader->caps2 & DDS_CUBEMAP)\n                {\n                    // We require all six faces to be defined\n                    if ((pHeader->caps2 & DDS_CUBEMAP_ALLFACES) != DDS_CUBEMAP_ALLFACES)\n                        return HRESULT_E_NOT_SUPPORTED;\n\n                    metadata.arraySize = 6;\n                    metadata.miscFlags |= TEX_MISC_TEXTURECUBE;\n                }\n\n                metadata.width = pHeader->width;\n                metadata.height = pHeader->height;\n                metadata.depth = 1;\n                metadata.dimension = TEX_DIMENSION_TEXTURE2D;\n\n                // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture\n            }\n\n            metadata.format = GetDXGIFormat(*pHeader, pHeader->ddspf, flags, convFlags);\n\n            if (metadata.format == DXGI_FORMAT_UNKNOWN)\n                return HRESULT_E_NOT_SUPPORTED;\n\n            // Special flag for handling LUMINANCE legacy formats\n            if (flags & DDS_FLAGS_EXPAND_LUMINANCE)\n            {\n                switch (metadata.format)\n                {\n                case DXGI_FORMAT_R8_UNORM:\n                    metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM;\n                    convFlags |= CONV_FLAGS_L8 | CONV_FLAGS_EXPAND;\n                    break;\n\n                case DXGI_FORMAT_R8G8_UNORM:\n                    metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM;\n                    convFlags |= CONV_FLAGS_A8L8 | CONV_FLAGS_EXPAND;\n                    break;\n\n                case DXGI_FORMAT_R16_UNORM:\n                    metadata.format = DXGI_FORMAT_R16G16B16A16_UNORM;\n                    convFlags |= CONV_FLAGS_L16 | CONV_FLAGS_EXPAND;\n                    break;\n\n                default:\n                    break;\n                }\n            }\n        }\n\n        // Special flag for handling BGR DXGI 1.1 formats\n        if (flags & DDS_FLAGS_FORCE_RGB)\n        {\n            switch (metadata.format)\n            {\n            case DXGI_FORMAT_B8G8R8A8_UNORM:\n                metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM;\n                convFlags |= CONV_FLAGS_SWIZZLE;\n                break;\n\n            case DXGI_FORMAT_B8G8R8X8_UNORM:\n                metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM;\n                convFlags |= CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA;\n                break;\n\n            case DXGI_FORMAT_B8G8R8A8_TYPELESS:\n                metadata.format = DXGI_FORMAT_R8G8B8A8_TYPELESS;\n                convFlags |= CONV_FLAGS_SWIZZLE;\n                break;\n\n            case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n                metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;\n                convFlags |= CONV_FLAGS_SWIZZLE;\n                break;\n\n            case DXGI_FORMAT_B8G8R8X8_TYPELESS:\n                metadata.format = DXGI_FORMAT_R8G8B8A8_TYPELESS;\n                convFlags |= CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA;\n                break;\n\n            case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n                metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;\n                convFlags |= CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA;\n                break;\n\n            default:\n                break;\n            }\n        }\n\n        // Special flag for handling 16bpp formats\n        if (flags & DDS_FLAGS_NO_16BPP)\n        {\n            switch (metadata.format)\n            {\n            case DXGI_FORMAT_B5G6R5_UNORM:\n            case DXGI_FORMAT_B5G5R5A1_UNORM:\n            case DXGI_FORMAT_B4G4R4A4_UNORM:\n                if (metadata.format == DXGI_FORMAT_B5G6R5_UNORM)\n                    convFlags |= CONV_FLAGS_NOALPHA;\n                metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM;\n                convFlags |= CONV_FLAGS_EXPAND;\n                break;\n\n            default:\n                break;\n            }\n        }\n\n        // Implicit alpha mode\n        if (convFlags & CONV_FLAGS_NOALPHA)\n        {\n            metadata.SetAlphaMode(TEX_ALPHA_MODE_OPAQUE);\n        }\n        else if (convFlags & CONV_FLAGS_PMALPHA)\n        {\n            metadata.SetAlphaMode(TEX_ALPHA_MODE_PREMULTIPLIED);\n        }\n\n        // Check for .dds files that exceed known hardware support\n        if (!(flags & DDS_FLAGS_ALLOW_LARGE_FILES))\n        {\n            // 16k is the maximum required resource size supported by Direct3D\n            if (metadata.width > 16384u /* D3D12_REQ_TEXTURE1D_U_DIMENSION, D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION */\n                || metadata.height > 16384u /* D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION */\n                || metadata.mipLevels > 15u /* D3D12_REQ_MIP_LEVELS */)\n            {\n                return HRESULT_E_NOT_SUPPORTED;\n            }\n\n            // 2048 is the maximum required depth/array size supported by Direct3D\n            if (metadata.arraySize > 2048u /* D3D12_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION, D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION */\n                || metadata.depth > 2048u /* D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION */)\n            {\n                return HRESULT_E_NOT_SUPPORTED;\n            }\n        }\n\n        return S_OK;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// Encodes DDS file header (magic value, header, optional DX10 extended header)\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::EncodeDDSHeader(\n    const TexMetadata& metadata,\n    DDS_FLAGS flags,\n    void* pDestination,\n    size_t maxsize,\n    size_t& required) noexcept\n{\n    if (!IsValid(metadata.format))\n        return E_INVALIDARG;\n\n    if (IsPalettized(metadata.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if (metadata.arraySize > 1)\n    {\n        if ((metadata.arraySize != 6) || (metadata.dimension != TEX_DIMENSION_TEXTURE2D) || !(metadata.IsCubemap()))\n        {\n            // Texture1D arrays, Texture2D arrays, and Cubemap arrays must be stored using 'DX10' extended header\n            if (flags & DDS_FLAGS_FORCE_DX9_LEGACY)\n                return HRESULT_E_CANNOT_MAKE;\n\n            flags |= DDS_FLAGS_FORCE_DX10_EXT;\n        }\n    }\n\n    if (flags & DDS_FLAGS_FORCE_DX10_EXT_MISC2)\n    {\n        flags |= DDS_FLAGS_FORCE_DX10_EXT;\n    }\n\n    DDS_PIXELFORMAT ddpf = {};\n    if (!(flags & DDS_FLAGS_FORCE_DX10_EXT))\n    {\n        switch (metadata.format)\n        {\n        case DXGI_FORMAT_R8G8B8A8_UNORM:        memcpy(&ddpf, &DDSPF_A8B8G8R8, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_R16G16_UNORM:          memcpy(&ddpf, &DDSPF_G16R16, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_R8G8_UNORM:            memcpy(&ddpf, &DDSPF_A8L8, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_R16_UNORM:             memcpy(&ddpf, &DDSPF_L16, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_R8_UNORM:              memcpy(&ddpf, &DDSPF_L8, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_A8_UNORM:              memcpy(&ddpf, &DDSPF_A8, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_R8G8_B8G8_UNORM:       memcpy(&ddpf, &DDSPF_R8G8_B8G8, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_G8R8_G8B8_UNORM:       memcpy(&ddpf, &DDSPF_G8R8_G8B8, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_BC1_UNORM:             memcpy(&ddpf, &DDSPF_DXT1, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_BC2_UNORM:             memcpy(&ddpf, metadata.IsPMAlpha() ? (&DDSPF_DXT2) : (&DDSPF_DXT3), sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_BC3_UNORM:             memcpy(&ddpf, metadata.IsPMAlpha() ? (&DDSPF_DXT4) : (&DDSPF_DXT5), sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_BC4_SNORM:             memcpy(&ddpf, &DDSPF_BC4_SNORM, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_BC5_SNORM:             memcpy(&ddpf, &DDSPF_BC5_SNORM, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_B5G6R5_UNORM:          memcpy(&ddpf, &DDSPF_R5G6B5, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_B5G5R5A1_UNORM:        memcpy(&ddpf, &DDSPF_A1R5G5B5, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_R8G8_SNORM:            memcpy(&ddpf, &DDSPF_V8U8, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_R8G8B8A8_SNORM:        memcpy(&ddpf, &DDSPF_Q8W8V8U8, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_R16G16_SNORM:          memcpy(&ddpf, &DDSPF_V16U16, sizeof(DDS_PIXELFORMAT)); break;\n        case DXGI_FORMAT_B8G8R8A8_UNORM:        memcpy(&ddpf, &DDSPF_A8R8G8B8, sizeof(DDS_PIXELFORMAT)); break; // DXGI 1.1\n        case DXGI_FORMAT_B8G8R8X8_UNORM:        memcpy(&ddpf, &DDSPF_X8R8G8B8, sizeof(DDS_PIXELFORMAT)); break; // DXGI 1.1\n        case DXGI_FORMAT_B4G4R4A4_UNORM:        memcpy(&ddpf, &DDSPF_A4R4G4B4, sizeof(DDS_PIXELFORMAT)); break; // DXGI 1.2\n        case DXGI_FORMAT_YUY2:                  memcpy(&ddpf, &DDSPF_YUY2, sizeof(DDS_PIXELFORMAT)); break; // DXGI 1.2\n\n        // Legacy D3DX formats using D3DFMT enum value as FourCC\n        case DXGI_FORMAT_R32G32B32A32_FLOAT:\n            ddpf.size = sizeof(DDS_PIXELFORMAT); ddpf.flags = DDS_FOURCC; ddpf.fourCC = 116;  // D3DFMT_A32B32G32R32F\n            break;\n        case DXGI_FORMAT_R16G16B16A16_FLOAT:\n            ddpf.size = sizeof(DDS_PIXELFORMAT); ddpf.flags = DDS_FOURCC; ddpf.fourCC = 113;  // D3DFMT_A16B16G16R16F\n            break;\n        case DXGI_FORMAT_R16G16B16A16_UNORM:\n            ddpf.size = sizeof(DDS_PIXELFORMAT); ddpf.flags = DDS_FOURCC; ddpf.fourCC = 36;  // D3DFMT_A16B16G16R16\n            break;\n        case DXGI_FORMAT_R16G16B16A16_SNORM:\n            ddpf.size = sizeof(DDS_PIXELFORMAT); ddpf.flags = DDS_FOURCC; ddpf.fourCC = 110;  // D3DFMT_Q16W16V16U16\n            break;\n        case DXGI_FORMAT_R32G32_FLOAT:\n            ddpf.size = sizeof(DDS_PIXELFORMAT); ddpf.flags = DDS_FOURCC; ddpf.fourCC = 115;  // D3DFMT_G32R32F\n            break;\n        case DXGI_FORMAT_R16G16_FLOAT:\n            ddpf.size = sizeof(DDS_PIXELFORMAT); ddpf.flags = DDS_FOURCC; ddpf.fourCC = 112;  // D3DFMT_G16R16F\n            break;\n        case DXGI_FORMAT_R32_FLOAT:\n            ddpf.size = sizeof(DDS_PIXELFORMAT); ddpf.flags = DDS_FOURCC; ddpf.fourCC = 114;  // D3DFMT_R32F\n            break;\n        case DXGI_FORMAT_R16_FLOAT:\n            ddpf.size = sizeof(DDS_PIXELFORMAT); ddpf.flags = DDS_FOURCC; ddpf.fourCC = 111;  // D3DFMT_R16F\n            break;\n\n        // DX9 legacy pixel formats\n        case DXGI_FORMAT_R10G10B10A2_UNORM:\n            if (flags & DDS_FLAGS_FORCE_DX9_LEGACY)\n            {\n                // Write using the 'incorrect' mask version to match D3DX bug\n                memcpy(&ddpf, &DDSPF_A2B10G10R10, sizeof(DDS_PIXELFORMAT));\n            }\n            break;\n\n        case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n            if (flags & DDS_FLAGS_FORCE_DX9_LEGACY)\n            {\n                memcpy(&ddpf, &DDSPF_A8B8G8R8, sizeof(DDS_PIXELFORMAT));\n            }\n            break;\n\n        case DXGI_FORMAT_BC1_UNORM_SRGB:\n            if (flags & DDS_FLAGS_FORCE_DX9_LEGACY)\n            {\n                memcpy(&ddpf, &DDSPF_DXT1, sizeof(DDS_PIXELFORMAT));\n            }\n            break;\n\n        case DXGI_FORMAT_BC2_UNORM_SRGB:\n            if (flags & DDS_FLAGS_FORCE_DX9_LEGACY)\n            {\n                memcpy(&ddpf, metadata.IsPMAlpha() ? (&DDSPF_DXT2) : (&DDSPF_DXT3), sizeof(DDS_PIXELFORMAT));\n            }\n            break;\n\n        case DXGI_FORMAT_BC3_UNORM_SRGB:\n            if (flags & DDS_FLAGS_FORCE_DX9_LEGACY)\n            {\n                memcpy(&ddpf, metadata.IsPMAlpha() ? (&DDSPF_DXT4) : (&DDSPF_DXT5), sizeof(DDS_PIXELFORMAT));\n            }\n            break;\n\n        case DXGI_FORMAT_BC4_UNORM:\n            memcpy(&ddpf, &DDSPF_BC4_UNORM, sizeof(DDS_PIXELFORMAT));\n            if (flags & DDS_FLAGS_FORCE_DX9_LEGACY)\n            {\n                ddpf.fourCC = MAKEFOURCC('A', 'T', 'I', '1');\n            }\n            break;\n\n        case DXGI_FORMAT_BC5_UNORM:\n            memcpy(&ddpf, &DDSPF_BC5_UNORM, sizeof(DDS_PIXELFORMAT));\n            if (flags & DDS_FLAGS_FORCE_DX9_LEGACY)\n            {\n                ddpf.fourCC = MAKEFOURCC('A', 'T', 'I', '2');\n            }\n            break;\n\n        case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n            if (flags & DDS_FLAGS_FORCE_DX9_LEGACY)\n            {\n                memcpy(&ddpf, &DDSPF_A8R8G8B8, sizeof(DDS_PIXELFORMAT));\n            }\n            break;\n\n        case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n            if (flags & DDS_FLAGS_FORCE_DX9_LEGACY)\n            {\n                memcpy(&ddpf, &DDSPF_X8R8G8B8, sizeof(DDS_PIXELFORMAT));\n            }\n            break;\n\n        default:\n            break;\n        }\n    }\n\n    required = sizeof(uint32_t) + sizeof(DDS_HEADER);\n\n    if (ddpf.size == 0)\n    {\n        if (flags & DDS_FLAGS_FORCE_DX9_LEGACY)\n            return HRESULT_E_CANNOT_MAKE;\n\n        required += sizeof(DDS_HEADER_DXT10);\n    }\n\n    if (!pDestination)\n        return S_OK;\n\n    if (maxsize < required)\n        return E_NOT_SUFFICIENT_BUFFER;\n\n    *static_cast<uint32_t*>(pDestination) = DDS_MAGIC;\n\n    auto header = reinterpret_cast<DDS_HEADER*>(static_cast<uint8_t*>(pDestination) + sizeof(uint32_t));\n    assert(header);\n\n    memset(header, 0, sizeof(DDS_HEADER));\n    header->size = sizeof(DDS_HEADER);\n    header->flags = DDS_HEADER_FLAGS_TEXTURE;\n    header->caps = DDS_SURFACE_FLAGS_TEXTURE;\n\n    if (metadata.mipLevels > 0)\n    {\n        header->flags |= DDS_HEADER_FLAGS_MIPMAP;\n\n        if (metadata.mipLevels > UINT16_MAX)\n            return E_INVALIDARG;\n\n        header->mipMapCount = static_cast<uint32_t>(metadata.mipLevels);\n\n        if (header->mipMapCount > 1)\n            header->caps |= DDS_SURFACE_FLAGS_MIPMAP;\n    }\n\n    switch (metadata.dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n        if (metadata.width > UINT32_MAX)\n            return E_INVALIDARG;\n\n        header->width = static_cast<uint32_t>(metadata.width);\n        header->height = header->depth = 1;\n        break;\n\n    case TEX_DIMENSION_TEXTURE2D:\n        if (metadata.height > UINT32_MAX\n            || metadata.width > UINT32_MAX)\n            return E_INVALIDARG;\n\n        header->height = static_cast<uint32_t>(metadata.height);\n        header->width = static_cast<uint32_t>(metadata.width);\n        header->depth = 1;\n\n        if (metadata.IsCubemap())\n        {\n            header->caps |= DDS_SURFACE_FLAGS_CUBEMAP;\n            header->caps2 |= DDS_CUBEMAP_ALLFACES;\n        }\n        break;\n\n    case TEX_DIMENSION_TEXTURE3D:\n        if (metadata.height > UINT32_MAX\n            || metadata.width > UINT32_MAX\n            || metadata.depth > UINT16_MAX)\n            return E_INVALIDARG;\n\n        header->flags |= DDS_HEADER_FLAGS_VOLUME;\n        header->caps2 |= DDS_FLAGS_VOLUME;\n        header->height = static_cast<uint32_t>(metadata.height);\n        header->width = static_cast<uint32_t>(metadata.width);\n        header->depth = static_cast<uint32_t>(metadata.depth);\n        break;\n\n    default:\n        return E_FAIL;\n    }\n\n    size_t rowPitch, slicePitch;\n    HRESULT hr = ComputePitch(metadata.format, metadata.width, metadata.height, rowPitch, slicePitch, CP_FLAGS_NONE);\n    if (FAILED(hr))\n        return hr;\n\n    if (slicePitch > UINT32_MAX\n        || rowPitch > UINT32_MAX)\n        return E_FAIL;\n\n    if (IsCompressed(metadata.format))\n    {\n        header->flags |= DDS_HEADER_FLAGS_LINEARSIZE;\n        header->pitchOrLinearSize = static_cast<uint32_t>(slicePitch);\n    }\n    else\n    {\n        header->flags |= DDS_HEADER_FLAGS_PITCH;\n        header->pitchOrLinearSize = static_cast<uint32_t>(rowPitch);\n    }\n\n    if (ddpf.size == 0)\n    {\n        memcpy(&header->ddspf, &DDSPF_DX10, sizeof(DDS_PIXELFORMAT));\n\n        auto ext = reinterpret_cast<DDS_HEADER_DXT10*>(reinterpret_cast<uint8_t*>(header) + sizeof(DDS_HEADER));\n        assert(ext);\n\n        memset(ext, 0, sizeof(DDS_HEADER_DXT10));\n        ext->dxgiFormat = metadata.format;\n        ext->resourceDimension = metadata.dimension;\n\n        if (metadata.arraySize > UINT16_MAX)\n            return E_INVALIDARG;\n\n        static_assert(static_cast<int>(TEX_MISC_TEXTURECUBE) == static_cast<int>(DDS_RESOURCE_MISC_TEXTURECUBE), \"DDS header mismatch\");\n\n        ext->miscFlag = metadata.miscFlags & ~static_cast<uint32_t>(TEX_MISC_TEXTURECUBE);\n\n        if (metadata.miscFlags & TEX_MISC_TEXTURECUBE)\n        {\n            ext->miscFlag |= TEX_MISC_TEXTURECUBE;\n            assert((metadata.arraySize % 6) == 0);\n            ext->arraySize = static_cast<UINT>(metadata.arraySize / 6);\n        }\n        else\n        {\n            ext->arraySize = static_cast<UINT>(metadata.arraySize);\n        }\n\n        static_assert(static_cast<int>(TEX_MISC2_ALPHA_MODE_MASK) == static_cast<int>(DDS_MISC_FLAGS2_ALPHA_MODE_MASK), \"DDS header mismatch\");\n\n        static_assert(static_cast<int>(TEX_ALPHA_MODE_UNKNOWN) == static_cast<int>(DDS_ALPHA_MODE_UNKNOWN), \"DDS header mismatch\");\n        static_assert(static_cast<int>(TEX_ALPHA_MODE_STRAIGHT) == static_cast<int>(DDS_ALPHA_MODE_STRAIGHT), \"DDS header mismatch\");\n        static_assert(static_cast<int>(TEX_ALPHA_MODE_PREMULTIPLIED) == static_cast<int>(DDS_ALPHA_MODE_PREMULTIPLIED), \"DDS header mismatch\");\n        static_assert(static_cast<int>(TEX_ALPHA_MODE_OPAQUE) == static_cast<int>(DDS_ALPHA_MODE_OPAQUE), \"DDS header mismatch\");\n        static_assert(static_cast<int>(TEX_ALPHA_MODE_CUSTOM) == static_cast<int>(DDS_ALPHA_MODE_CUSTOM), \"DDS header mismatch\");\n\n        if (flags & DDS_FLAGS_FORCE_DX10_EXT_MISC2)\n        {\n            // This was formerly 'reserved'. D3DX10 and D3DX11 will fail if this value is anything other than 0\n            ext->miscFlags2 = metadata.miscFlags2;\n        }\n    }\n    else\n    {\n        memcpy(&header->ddspf, &ddpf, sizeof(ddpf));\n    }\n\n    return S_OK;\n}\n\n\nnamespace\n{\n    //-------------------------------------------------------------------------------------\n    // Converts an image row with optional clearing of alpha value to 1.0\n    // Returns true if supported, false if expansion case not supported\n    //-------------------------------------------------------------------------------------\n    enum TEXP_LEGACY_FORMAT\n    {\n        TEXP_LEGACY_UNKNOWN = 0,\n        TEXP_LEGACY_R8G8B8,\n        TEXP_LEGACY_R3G3B2,\n        TEXP_LEGACY_A8R3G3B2,\n        TEXP_LEGACY_P8,\n        TEXP_LEGACY_A8P8,\n        TEXP_LEGACY_A4L4,\n        TEXP_LEGACY_B4G4R4A4,\n        TEXP_LEGACY_L8,\n        TEXP_LEGACY_L16,\n        TEXP_LEGACY_A8L8\n    };\n\n    constexpr TEXP_LEGACY_FORMAT FindLegacyFormat(uint32_t flags) noexcept\n    {\n        TEXP_LEGACY_FORMAT lformat = TEXP_LEGACY_UNKNOWN;\n\n        if (flags & CONV_FLAGS_PAL8)\n        {\n            lformat = (flags & CONV_FLAGS_A8P8) ? TEXP_LEGACY_A8P8 : TEXP_LEGACY_P8;\n        }\n        else if (flags & CONV_FLAGS_888)\n            lformat = TEXP_LEGACY_R8G8B8;\n        else if (flags & CONV_FLAGS_332)\n            lformat = TEXP_LEGACY_R3G3B2;\n        else if (flags & CONV_FLAGS_8332)\n            lformat = TEXP_LEGACY_A8R3G3B2;\n        else if (flags & CONV_FLAGS_44)\n            lformat = TEXP_LEGACY_A4L4;\n        else if (flags & CONV_FLAGS_4444)\n            lformat = TEXP_LEGACY_B4G4R4A4;\n        else if (flags & CONV_FLAGS_L8)\n            lformat = TEXP_LEGACY_L8;\n        else if (flags & CONV_FLAGS_L16)\n            lformat = TEXP_LEGACY_L16;\n        else if (flags & CONV_FLAGS_A8L8)\n            lformat = TEXP_LEGACY_A8L8;\n\n        return lformat;\n    }\n\n    _Success_(return)\n        bool LegacyExpandScanline(\n            _Out_writes_bytes_(outSize) void* pDestination,\n            size_t outSize,\n            _In_ DXGI_FORMAT outFormat,\n            _In_reads_bytes_(inSize) const void* pSource,\n            size_t inSize,\n            _In_ TEXP_LEGACY_FORMAT inFormat,\n            _In_reads_opt_(256) const uint32_t* pal8,\n            _In_ uint32_t tflags) noexcept\n    {\n        assert(pDestination && outSize > 0);\n        assert(pSource && inSize > 0);\n        assert(IsValid(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat));\n\n        switch (inFormat)\n        {\n        case TEXP_LEGACY_R8G8B8:\n            if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)\n                return false;\n\n            // D3DFMT_R8G8B8 -> DXGI_FORMAT_R8G8B8A8_UNORM\n            if (inSize >= 3 && outSize >= 4)\n            {\n                const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);\n                uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n\n                for (size_t ocount = 0, icount = 0; ((icount < (inSize - 2)) && (ocount < (outSize - 3))); icount += 3, ocount += 4)\n                {\n                    // 24bpp Direct3D 9 files are actually BGR, so need to swizzle as well\n                    uint32_t t1 = uint32_t(*(sPtr) << 16);\n                    uint32_t t2 = uint32_t(*(sPtr + 1) << 8);\n                    uint32_t t3 = uint32_t(*(sPtr + 2));\n\n                    *(dPtr++) = t1 | t2 | t3 | 0xff000000;\n                    sPtr += 3;\n                }\n                return true;\n            }\n            return false;\n\n        case TEXP_LEGACY_R3G3B2:\n            switch (outFormat)\n            {\n            case DXGI_FORMAT_R8G8B8A8_UNORM:\n                // D3DFMT_R3G3B2 -> DXGI_FORMAT_R8G8B8A8_UNORM\n                if (inSize >= 1 && outSize >= 4)\n                {\n                    const uint8_t* __restrict sPtr = static_cast<const uint8_t*>(pSource);\n                    uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n\n                    for (size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 3))); ++icount, ocount += 4)\n                    {\n                        const uint8_t t = *(sPtr++);\n\n                        uint32_t t1 = uint32_t((t & 0xe0) | ((t & 0xe0) >> 3) | ((t & 0xc0) >> 6));\n                        uint32_t t2 = uint32_t(((t & 0x1c) << 11) | ((t & 0x1c) << 8) | ((t & 0x18) << 5));\n                        uint32_t t3 = uint32_t(((t & 0x03) << 22) | ((t & 0x03) << 20) | ((t & 0x03) << 18) | ((t & 0x03) << 16));\n\n                        *(dPtr++) = t1 | t2 | t3 | 0xff000000;\n                    }\n                    return true;\n                }\n                return false;\n\n            case DXGI_FORMAT_B5G6R5_UNORM:\n                // D3DFMT_R3G3B2 -> DXGI_FORMAT_B5G6R5_UNORM\n                if (inSize >= 1 && outSize >= 2)\n                {\n                    const uint8_t* __restrict sPtr = static_cast<const uint8_t*>(pSource);\n                    uint16_t * __restrict dPtr = static_cast<uint16_t*>(pDestination);\n\n                    for (size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 1))); ++icount, ocount += 2)\n                    {\n                        const unsigned t = *(sPtr++);\n\n                        unsigned t1 = ((t & 0xe0u) << 8) | ((t & 0xc0u) << 5);\n                        unsigned t2 = ((t & 0x1cu) << 6) | ((t & 0x1cu) << 3);\n                        unsigned t3 = ((t & 0x03u) << 3) | ((t & 0x03u) << 1) | ((t & 0x02) >> 1);\n\n                        *(dPtr++) = static_cast<uint16_t>(t1 | t2 | t3);\n                    }\n                    return true;\n                }\n                return false;\n\n            default:\n                return false;\n            }\n\n        case TEXP_LEGACY_A8R3G3B2:\n            if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)\n                return false;\n\n            // D3DFMT_A8R3G3B2 -> DXGI_FORMAT_R8G8B8A8_UNORM\n            if (inSize >= 2 && outSize >= 4)\n            {\n                const uint16_t* __restrict sPtr = static_cast<const uint16_t*>(pSource);\n                uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n\n                for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4)\n                {\n                    const uint16_t t = *(sPtr++);\n\n                    uint32_t t1 = uint32_t((t & 0x00e0) | ((t & 0x00e0) >> 3) | ((t & 0x00c0) >> 6));\n                    uint32_t t2 = uint32_t(((t & 0x001c) << 11) | ((t & 0x001c) << 8) | ((t & 0x0018) << 5));\n                    uint32_t t3 = uint32_t(((t & 0x0003) << 22) | ((t & 0x0003) << 20) | ((t & 0x0003) << 18) | ((t & 0x0003) << 16));\n                    uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : uint32_t((t & 0xff00) << 16);\n\n                    *(dPtr++) = t1 | t2 | t3 | ta;\n                }\n                return true;\n            }\n            return false;\n\n        case TEXP_LEGACY_P8:\n            if ((outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) || !pal8)\n                return false;\n\n            // D3DFMT_P8 -> DXGI_FORMAT_R8G8B8A8_UNORM\n            if (inSize >= 1 && outSize >= 4)\n            {\n                const uint8_t* __restrict sPtr = static_cast<const uint8_t*>(pSource);\n                uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n\n                for (size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 3))); ++icount, ocount += 4)\n                {\n                    uint8_t t = *(sPtr++);\n\n                    *(dPtr++) = pal8[t];\n                }\n                return true;\n            }\n            return false;\n\n        case TEXP_LEGACY_A8P8:\n            if ((outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) || !pal8)\n                return false;\n\n            // D3DFMT_A8P8 -> DXGI_FORMAT_R8G8B8A8_UNORM\n            if (inSize >= 2 && outSize >= 4)\n            {\n                const uint16_t* __restrict sPtr = static_cast<const uint16_t*>(pSource);\n                uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n\n                for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4)\n                {\n                    const uint16_t t = *(sPtr++);\n\n                    uint32_t t1 = pal8[t & 0xff];\n                    uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : uint32_t((t & 0xff00) << 16);\n\n                    *(dPtr++) = t1 | ta;\n                }\n                return true;\n            }\n            return false;\n\n        case TEXP_LEGACY_A4L4:\n            switch (outFormat)\n            {\n            case DXGI_FORMAT_B4G4R4A4_UNORM:\n                // D3DFMT_A4L4 -> DXGI_FORMAT_B4G4R4A4_UNORM\n                if (inSize >= 1 && outSize >= 2)\n                {\n                    const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);\n                    uint16_t * __restrict dPtr = static_cast<uint16_t*>(pDestination);\n\n                    for (size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 1))); ++icount, ocount += 2)\n                    {\n                        const unsigned t = *(sPtr++);\n\n                        unsigned t1 = (t & 0x0fu);\n                        unsigned ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xf000u : ((t & 0xf0u) << 8);\n\n                        *(dPtr++) = static_cast<uint16_t>(t1 | (t1 << 4) | (t1 << 8) | ta);\n                    }\n                    return true;\n                }\n                return false;\n\n            case DXGI_FORMAT_R8G8B8A8_UNORM:\n                // D3DFMT_A4L4 -> DXGI_FORMAT_R8G8B8A8_UNORM\n                if (inSize >= 1 && outSize >= 4)\n                {\n                    const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);\n                    uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n\n                    for (size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 3))); ++icount, ocount += 4)\n                    {\n                        const uint8_t t = *(sPtr++);\n\n                        uint32_t t1 = uint32_t(((t & 0x0f) << 4) | (t & 0x0f));\n                        uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : uint32_t(((t & 0xf0) << 24) | ((t & 0xf0) << 20));\n\n                        *(dPtr++) = t1 | (t1 << 8) | (t1 << 16) | ta;\n                    }\n                    return true;\n                }\n                return false;\n\n            default:\n                return false;\n            }\n\n        case TEXP_LEGACY_B4G4R4A4:\n            if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)\n                return false;\n\n            // D3DFMT_A4R4G4B4 -> DXGI_FORMAT_R8G8B8A8_UNORM\n            if (inSize >= 2 && outSize >= 4)\n            {\n                const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);\n                uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n\n                for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4)\n                {\n                    const uint32_t t = *(sPtr++);\n\n                    uint32_t t1 = uint32_t((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8);\n                    uint32_t t2 = uint32_t((t & 0x00f0) << 8) | ((t & 0x00f0) << 4);\n                    uint32_t t3 = uint32_t((t & 0x000f) << 20) | ((t & 0x000f) << 16);\n                    uint32_t ta = uint32_t((tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : (((t & 0xf000) << 16) | ((t & 0xf000) << 12)));\n\n                    *(dPtr++) = t1 | t2 | t3 | ta;\n                }\n                return true;\n            }\n            return false;\n\n        case TEXP_LEGACY_L8:\n            if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)\n                return false;\n\n            // D3DFMT_L8 -> DXGI_FORMAT_R8G8B8A8_UNORM\n            if (inSize >= 1 && outSize >= 4)\n            {\n                const uint8_t * __restrict sPtr = static_cast<const uint8_t*>(pSource);\n                uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n\n                for (size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 3))); ++icount, ocount += 4)\n                {\n                    uint32_t t1 = *(sPtr++);\n                    uint32_t t2 = (t1 << 8);\n                    uint32_t t3 = (t1 << 16);\n\n                    *(dPtr++) = t1 | t2 | t3 | 0xff000000;\n                }\n                return true;\n            }\n            return false;\n\n        case TEXP_LEGACY_L16:\n            if (outFormat != DXGI_FORMAT_R16G16B16A16_UNORM)\n                return false;\n\n            // D3DFMT_L16 -> DXGI_FORMAT_R16G16B16A16_UNORM\n            if (inSize >= 2 && outSize >= 8)\n            {\n                const uint16_t* __restrict sPtr = static_cast<const uint16_t*>(pSource);\n                uint64_t * __restrict dPtr = static_cast<uint64_t*>(pDestination);\n\n                for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 7))); icount += 2, ocount += 8)\n                {\n                    const uint16_t t = *(sPtr++);\n\n                    uint64_t t1 = t;\n                    uint64_t t2 = (t1 << 16);\n                    uint64_t t3 = (t1 << 32);\n\n                    *(dPtr++) = t1 | t2 | t3 | 0xffff000000000000;\n                }\n                return true;\n            }\n            return false;\n\n        case TEXP_LEGACY_A8L8:\n            if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)\n                return false;\n\n            // D3DFMT_A8L8 -> DXGI_FORMAT_R8G8B8A8_UNORM\n            if (inSize >= 2 && outSize >= 4)\n            {\n                const uint16_t* __restrict sPtr = static_cast<const uint16_t*>(pSource);\n                uint32_t * __restrict dPtr = static_cast<uint32_t*>(pDestination);\n\n                for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4)\n                {\n                    const uint16_t t = *(sPtr++);\n\n                    uint32_t t1 = uint32_t(t & 0xff);\n                    uint32_t t2 = uint32_t(t1 << 8);\n                    uint32_t t3 = uint32_t(t1 << 16);\n                    uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : uint32_t((t & 0xff00) << 16);\n\n                    *(dPtr++) = t1 | t2 | t3 | ta;\n                }\n                return true;\n            }\n            return false;\n\n        default:\n            return false;\n        }\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    // Converts or copies image data from pPixels into scratch image data\n    //-------------------------------------------------------------------------------------\n    HRESULT CopyImage(\n        _In_reads_bytes_(size) const void* pPixels,\n        _In_ size_t size,\n        _In_ const TexMetadata& metadata,\n        _In_ CP_FLAGS cpFlags,\n        _In_ uint32_t convFlags,\n        _In_reads_opt_(256) const uint32_t *pal8,\n        _In_ const ScratchImage& image) noexcept\n    {\n        assert(pPixels);\n        assert(image.GetPixels());\n\n        if (!size)\n            return E_FAIL;\n\n        if (convFlags & CONV_FLAGS_EXPAND)\n        {\n            if (convFlags & CONV_FLAGS_888)\n                cpFlags |= CP_FLAGS_24BPP;\n            else if (convFlags & (CONV_FLAGS_565 | CONV_FLAGS_5551 | CONV_FLAGS_4444 | CONV_FLAGS_8332 | CONV_FLAGS_A8P8 | CONV_FLAGS_L16 | CONV_FLAGS_A8L8))\n                cpFlags |= CP_FLAGS_16BPP;\n            else if (convFlags & (CONV_FLAGS_44 | CONV_FLAGS_332 | CONV_FLAGS_PAL8 | CONV_FLAGS_L8))\n                cpFlags |= CP_FLAGS_8BPP;\n        }\n\n        size_t pixelSize, nimages;\n        if (!DetermineImageArray(metadata, cpFlags, nimages, pixelSize))\n            return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n        if ((nimages == 0) || (nimages != image.GetImageCount()))\n        {\n            return E_FAIL;\n        }\n\n        if (pixelSize > size)\n        {\n            return HRESULT_E_HANDLE_EOF;\n        }\n\n        std::unique_ptr<Image[]> timages(new (std::nothrow) Image[nimages]);\n        if (!timages)\n        {\n            return E_OUTOFMEMORY;\n        }\n\n        if (!SetupImageArray(\n            const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(pPixels)),\n            pixelSize,\n            metadata,\n            cpFlags,\n            timages.get(),\n            nimages))\n        {\n            return E_FAIL;\n        }\n\n        if (nimages != image.GetImageCount())\n        {\n            return E_FAIL;\n        }\n\n        const Image* images = image.GetImages();\n        if (!images)\n        {\n            return E_FAIL;\n        }\n\n        uint32_t tflags = (convFlags & CONV_FLAGS_NOALPHA) ? TEXP_SCANLINE_SETALPHA : 0u;\n        if (convFlags & CONV_FLAGS_SWIZZLE)\n            tflags |= TEXP_SCANLINE_LEGACY;\n\n        switch (metadata.dimension)\n        {\n        case TEX_DIMENSION_TEXTURE1D:\n        case TEX_DIMENSION_TEXTURE2D:\n            {\n                size_t index = 0;\n                for (size_t item = 0; item < metadata.arraySize; ++item)\n                {\n                    size_t lastgood = 0;\n                    for (size_t level = 0; level < metadata.mipLevels; ++level, ++index)\n                    {\n                        if (index >= nimages)\n                            return E_FAIL;\n\n                        if (images[index].height != timages[index].height)\n                            return E_FAIL;\n\n                        size_t dpitch = images[index].rowPitch;\n                        const size_t spitch = timages[index].rowPitch;\n\n                        const uint8_t *pSrc = timages[index].pixels;\n                        if (!pSrc)\n                            return E_POINTER;\n\n                        uint8_t *pDest = images[index].pixels;\n                        if (!pDest)\n                            return E_POINTER;\n\n                        if (IsCompressed(metadata.format))\n                        {\n                            size_t csize = std::min<size_t>(images[index].slicePitch, timages[index].slicePitch);\n                            memcpy(pDest, pSrc, csize);\n\n                            if (cpFlags & CP_FLAGS_BAD_DXTN_TAILS)\n                            {\n                                if (images[index].width < 4 || images[index].height < 4)\n                                {\n                                    csize = std::min<size_t>(images[index].slicePitch, timages[lastgood].slicePitch);\n                                    memcpy(pDest, timages[lastgood].pixels, csize);\n                                }\n                                else\n                                {\n                                    lastgood = index;\n                                }\n                            }\n                        }\n                        else if (IsPlanar(metadata.format))\n                        {\n                            const size_t count = ComputeScanlines(metadata.format, images[index].height);\n                            if (!count)\n                                return E_UNEXPECTED;\n\n                            const size_t csize = std::min<size_t>(dpitch, spitch);\n                            for (size_t h = 0; h < count; ++h)\n                            {\n                                memcpy(pDest, pSrc, csize);\n                                pSrc += spitch;\n                                pDest += dpitch;\n                            }\n                        }\n                        else\n                        {\n                            for (size_t h = 0; h < images[index].height; ++h)\n                            {\n                                if (convFlags & CONV_FLAGS_EXPAND)\n                                {\n                                    if (convFlags & (CONV_FLAGS_565 | CONV_FLAGS_5551 | CONV_FLAGS_4444))\n                                    {\n                                        if (!ExpandScanline(pDest, dpitch, DXGI_FORMAT_R8G8B8A8_UNORM,\n                                            pSrc, spitch,\n                                            (convFlags & CONV_FLAGS_565) ? DXGI_FORMAT_B5G6R5_UNORM : DXGI_FORMAT_B5G5R5A1_UNORM,\n                                            tflags))\n                                            return E_FAIL;\n                                    }\n                                    else\n                                    {\n                                        const TEXP_LEGACY_FORMAT lformat = FindLegacyFormat(convFlags);\n                                        if (!LegacyExpandScanline(pDest, dpitch, metadata.format,\n                                            pSrc, spitch, lformat, pal8,\n                                            tflags))\n                                            return E_FAIL;\n                                    }\n                                }\n                                else if (convFlags & CONV_FLAGS_SWIZZLE)\n                                {\n                                    SwizzleScanline(pDest, dpitch, pSrc, spitch,\n                                        metadata.format, tflags);\n                                }\n                                else\n                                {\n                                    CopyScanline(pDest, dpitch, pSrc, spitch,\n                                        metadata.format, tflags);\n                                }\n\n                                pSrc += spitch;\n                                pDest += dpitch;\n                            }\n                        }\n                    }\n                }\n            }\n            break;\n\n        case TEX_DIMENSION_TEXTURE3D:\n            {\n                size_t index = 0;\n                size_t d = metadata.depth;\n\n                size_t lastgood = 0;\n                for (size_t level = 0; level < metadata.mipLevels; ++level)\n                {\n                    for (size_t slice = 0; slice < d; ++slice, ++index)\n                    {\n                        if (index >= nimages)\n                            return E_FAIL;\n\n                        if (images[index].height != timages[index].height)\n                            return E_FAIL;\n\n                        size_t dpitch = images[index].rowPitch;\n                        const size_t spitch = timages[index].rowPitch;\n\n                        const uint8_t *pSrc = timages[index].pixels;\n                        if (!pSrc)\n                            return E_POINTER;\n\n                        uint8_t *pDest = images[index].pixels;\n                        if (!pDest)\n                            return E_POINTER;\n\n                        if (IsCompressed(metadata.format))\n                        {\n                            size_t csize = std::min<size_t>(images[index].slicePitch, timages[index].slicePitch);\n                            memcpy(pDest, pSrc, csize);\n\n                            if (cpFlags & CP_FLAGS_BAD_DXTN_TAILS)\n                            {\n                                if (images[index].width < 4 || images[index].height < 4)\n                                {\n                                    csize = std::min<size_t>(images[index].slicePitch, timages[lastgood + slice].slicePitch);\n                                    memcpy(pDest, timages[lastgood + slice].pixels, csize);\n                                }\n                                else if (!slice)\n                                {\n                                    lastgood = index;\n                                }\n                            }\n                        }\n                        else if (IsPlanar(metadata.format))\n                        {\n                            // Direct3D does not support any planar formats for Texture3D\n                            return HRESULT_E_NOT_SUPPORTED;\n                        }\n                        else\n                        {\n                            for (size_t h = 0; h < images[index].height; ++h)\n                            {\n                                if (convFlags & CONV_FLAGS_EXPAND)\n                                {\n                                    if (convFlags & (CONV_FLAGS_565 | CONV_FLAGS_5551 | CONV_FLAGS_4444))\n                                    {\n                                        if (!ExpandScanline(pDest, dpitch, DXGI_FORMAT_R8G8B8A8_UNORM,\n                                            pSrc, spitch,\n                                            (convFlags & CONV_FLAGS_565) ? DXGI_FORMAT_B5G6R5_UNORM : DXGI_FORMAT_B5G5R5A1_UNORM,\n                                            tflags))\n                                            return E_FAIL;\n                                    }\n                                    else\n                                    {\n                                        const TEXP_LEGACY_FORMAT lformat = FindLegacyFormat(convFlags);\n                                        if (!LegacyExpandScanline(pDest, dpitch, metadata.format,\n                                            pSrc, spitch, lformat, pal8,\n                                            tflags))\n                                            return E_FAIL;\n                                    }\n                                }\n                                else if (convFlags & CONV_FLAGS_SWIZZLE)\n                                {\n                                    SwizzleScanline(pDest, dpitch, pSrc, spitch, metadata.format, tflags);\n                                }\n                                else\n                                {\n                                    CopyScanline(pDest, dpitch, pSrc, spitch, metadata.format, tflags);\n                                }\n\n                                pSrc += spitch;\n                                pDest += dpitch;\n                            }\n                        }\n                    }\n\n                    if (d > 1)\n                        d >>= 1;\n                }\n            }\n            break;\n\n        default:\n            return E_FAIL;\n        }\n\n        return S_OK;\n    }\n\n    HRESULT CopyImageInPlace(uint32_t convFlags, _In_ const ScratchImage& image) noexcept\n    {\n        if (!image.GetPixels())\n            return E_FAIL;\n\n        const Image* images = image.GetImages();\n        if (!images)\n            return E_FAIL;\n\n        const TexMetadata& metadata = image.GetMetadata();\n\n        if (IsPlanar(metadata.format))\n            return HRESULT_E_NOT_SUPPORTED;\n\n        uint32_t tflags = (convFlags & CONV_FLAGS_NOALPHA) ? TEXP_SCANLINE_SETALPHA : 0u;\n        if (convFlags & CONV_FLAGS_SWIZZLE)\n            tflags |= TEXP_SCANLINE_LEGACY;\n\n        for (size_t i = 0; i < image.GetImageCount(); ++i)\n        {\n            const Image* img = &images[i];\n            uint8_t *pPixels = img->pixels;\n            if (!pPixels)\n                return E_POINTER;\n\n            size_t rowPitch = img->rowPitch;\n\n            for (size_t h = 0; h < img->height; ++h)\n            {\n                if (convFlags & CONV_FLAGS_SWIZZLE)\n                {\n                    SwizzleScanline(pPixels, rowPitch, pPixels, rowPitch, metadata.format, tflags);\n                }\n                else\n                {\n                    CopyScanline(pPixels, rowPitch, pPixels, rowPitch, metadata.format, tflags);\n                }\n\n                pPixels += rowPitch;\n            }\n        }\n\n        return S_OK;\n    }\n}\n\n\n//=====================================================================================\n// Entry-points\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n// Obtain metadata from DDS file in memory/on disk\n//-------------------------------------------------------------------------------------\n\n_Use_decl_annotations_\nHRESULT DirectX::GetMetadataFromDDSMemory(\n    const void* pSource,\n    size_t size,\n    DDS_FLAGS flags,\n    TexMetadata& metadata) noexcept\n{\n    if (!pSource || size == 0)\n        return E_INVALIDARG;\n\n    uint32_t convFlags = 0;\n    return DecodeDDSHeader(pSource, size, flags, metadata, convFlags);\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::GetMetadataFromDDSFile(\n    const wchar_t* szFile,\n    DDS_FLAGS flags,\n    TexMetadata& metadata) noexcept\n{\n    if (!szFile)\n        return E_INVALIDARG;\n\n#ifdef _WIN32\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n    ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr)));\n#else\n    ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,\n        FILE_FLAG_SEQUENTIAL_SCAN, nullptr)));\n#endif\n    if (!hFile)\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    // Get the file size\n    FILE_STANDARD_INFO fileInfo;\n    if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    // File is too big for 32-bit allocation, so reject read (4 GB should be plenty large enough for a valid DDS file)\n    if (fileInfo.EndOfFile.HighPart > 0)\n    {\n        return HRESULT_E_FILE_TOO_LARGE;\n    }\n\n    const size_t len = fileInfo.EndOfFile.LowPart;\n#else // !WIN32\n    std::ifstream inFile(std::filesystem::path(szFile), std::ios::in | std::ios::binary | std::ios::ate);\n    if (!inFile)\n        return E_FAIL;\n\n    std::streampos fileLen = inFile.tellg();\n    if (!inFile)\n        return E_FAIL;\n\n    if (fileLen > UINT32_MAX)\n        return HRESULT_E_FILE_TOO_LARGE;\n\n    inFile.seekg(0, std::ios::beg);\n    if (!inFile)\n        return E_FAIL;\n\n    const size_t len = fileLen;\n#endif\n\n    // Need at least enough data to fill the standard header and magic number to be a valid DDS\n    if (len < (sizeof(DDS_HEADER) + sizeof(uint32_t)))\n    {\n        return E_FAIL;\n    }\n\n    // Read the header in (including extended header if present)\n    uint8_t header[MAX_HEADER_SIZE] = {};\n\n#ifdef _WIN32\n    DWORD bytesRead = 0;\n    if (!ReadFile(hFile.get(), header, MAX_HEADER_SIZE, &bytesRead, nullptr))\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    auto const headerLen = static_cast<size_t>(bytesRead);\n#else\n    auto const headerLen = std::min<size_t>(len, MAX_HEADER_SIZE);\n\n    inFile.read(reinterpret_cast<char*>(header), headerLen);\n    if (!inFile)\n        return E_FAIL;\n#endif\n\n    uint32_t convFlags = 0;\n    return DecodeDDSHeader(header, headerLen, flags, metadata, convFlags);\n}\n\n\n//-------------------------------------------------------------------------------------\n// Load a DDS file in memory\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadFromDDSMemory(\n    const void* pSource,\n    size_t size,\n    DDS_FLAGS flags,\n    TexMetadata* metadata,\n    ScratchImage& image) noexcept\n{\n    if (!pSource || size == 0)\n        return E_INVALIDARG;\n\n    image.Release();\n\n    uint32_t convFlags = 0;\n    TexMetadata mdata;\n    HRESULT hr = DecodeDDSHeader(pSource, size, flags, mdata, convFlags);\n    if (FAILED(hr))\n        return hr;\n\n    size_t offset = sizeof(uint32_t) + sizeof(DDS_HEADER);\n    if (convFlags & CONV_FLAGS_DX10)\n        offset += sizeof(DDS_HEADER_DXT10);\n\n    assert(offset <= size);\n\n    const uint32_t *pal8 = nullptr;\n    if (convFlags & CONV_FLAGS_PAL8)\n    {\n        pal8 = reinterpret_cast<const uint32_t*>(static_cast<const uint8_t*>(pSource) + offset);\n        assert(pal8);\n        offset += (256 * sizeof(uint32_t));\n        if (size < offset)\n            return E_FAIL;\n    }\n\n    hr = image.Initialize(mdata);\n    if (FAILED(hr))\n        return hr;\n\n    CP_FLAGS cflags = CP_FLAGS_NONE;\n    if (flags & DDS_FLAGS_LEGACY_DWORD)\n    {\n        cflags |= CP_FLAGS_LEGACY_DWORD;\n    }\n    if (flags & DDS_FLAGS_BAD_DXTN_TAILS)\n    {\n        cflags |= CP_FLAGS_BAD_DXTN_TAILS;\n    }\n\n    const void* pPixels = static_cast<const uint8_t*>(pSource) + offset;\n    assert(pPixels);\n    hr = CopyImage(pPixels,\n        size - offset,\n        mdata,\n        cflags,\n        convFlags,\n        pal8,\n        image);\n    if (FAILED(hr))\n    {\n        image.Release();\n        return hr;\n    }\n    if (metadata)\n        memcpy(metadata, &mdata, sizeof(TexMetadata));\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Load a DDS file from disk\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadFromDDSFile(\n    const wchar_t* szFile,\n    DDS_FLAGS flags,\n    TexMetadata* metadata,\n    ScratchImage& image) noexcept\n{\n    if (!szFile)\n        return E_INVALIDARG;\n\n    image.Release();\n\n#ifdef _WIN32\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n    ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr)));\n#else\n    ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,\n        FILE_FLAG_SEQUENTIAL_SCAN, nullptr)));\n#endif\n    if (!hFile)\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    // Get the file size\n    FILE_STANDARD_INFO fileInfo;\n    if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    // File is too big for 32-bit allocation, so reject read (4 GB should be plenty large enough for a valid DDS file)\n    if (fileInfo.EndOfFile.HighPart > 0)\n        return HRESULT_E_FILE_TOO_LARGE;\n\n    const size_t len = fileInfo.EndOfFile.LowPart;\n#else // !WIN32\n    std::ifstream inFile(std::filesystem::path(szFile), std::ios::in | std::ios::binary | std::ios::ate);\n    if (!inFile)\n        return E_FAIL;\n\n    std::streampos fileLen = inFile.tellg();\n    if (!inFile)\n        return E_FAIL;\n\n    if (fileLen > UINT32_MAX)\n        return HRESULT_E_FILE_TOO_LARGE;\n\n    inFile.seekg(0, std::ios::beg);\n    if (!inFile)\n        return E_FAIL;\n\n    const size_t len = fileLen;\n#endif\n\n    // Need at least enough data to fill the standard header and magic number to be a valid DDS\n    if (len < (sizeof(DDS_HEADER) + sizeof(uint32_t)))\n    {\n        return E_FAIL;\n    }\n\n    // Read the header in (including extended header if present)\n    uint8_t header[MAX_HEADER_SIZE] = {};\n\n#ifdef _WIN32\n    DWORD bytesRead = 0;\n    if (!ReadFile(hFile.get(), header, MAX_HEADER_SIZE, &bytesRead, nullptr))\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    auto const headerLen = static_cast<size_t>(bytesRead);\n#else\n    auto const headerLen = std::min<size_t>(len, MAX_HEADER_SIZE);\n\n    inFile.read(reinterpret_cast<char*>(header), headerLen);\n    if (!inFile)\n        return E_FAIL;\n#endif\n\n    uint32_t convFlags = 0;\n    TexMetadata mdata;\n    HRESULT hr = DecodeDDSHeader(header, headerLen, flags, mdata, convFlags);\n    if (FAILED(hr))\n        return hr;\n\n    size_t offset = MAX_HEADER_SIZE;\n\n    if (!(convFlags & CONV_FLAGS_DX10))\n    {\n    #ifdef _WIN32\n            // Must reset file position since we read more than the standard header above\n        const LARGE_INTEGER filePos = { { sizeof(uint32_t) + sizeof(DDS_HEADER), 0 } };\n        if (!SetFilePointerEx(hFile.get(), filePos, nullptr, FILE_BEGIN))\n        {\n            return HRESULT_FROM_WIN32(GetLastError());\n        }\n    #else\n        inFile.seekg(sizeof(uint32_t) + sizeof(DDS_HEADER), std::ios::beg);\n        if (!inFile)\n            return E_FAIL;\n    #endif\n\n        offset = sizeof(uint32_t) + sizeof(DDS_HEADER);\n    }\n\n    std::unique_ptr<uint32_t[]> pal8;\n    if (convFlags & CONV_FLAGS_PAL8)\n    {\n        pal8.reset(new (std::nothrow) uint32_t[256]);\n        if (!pal8)\n        {\n            return E_OUTOFMEMORY;\n        }\n\n    #ifdef _WIN32\n        if (!ReadFile(hFile.get(), pal8.get(), 256 * sizeof(uint32_t), &bytesRead, nullptr))\n        {\n            return HRESULT_FROM_WIN32(GetLastError());\n        }\n\n        if (bytesRead != (256 * sizeof(uint32_t)))\n        {\n            return E_FAIL;\n        }\n    #else\n        inFile.read(reinterpret_cast<char*>(pal8.get()), 256 * sizeof(uint32_t));\n        if (!inFile)\n            return E_FAIL;\n    #endif\n\n        offset += (256 * sizeof(uint32_t));\n    }\n\n    const size_t remaining = len - offset;\n    if (remaining == 0)\n        return E_FAIL;\n\n    hr = image.Initialize(mdata);\n    if (FAILED(hr))\n        return hr;\n\n    if ((convFlags & CONV_FLAGS_EXPAND) || (flags & (DDS_FLAGS_LEGACY_DWORD | DDS_FLAGS_BAD_DXTN_TAILS)))\n    {\n        std::unique_ptr<uint8_t[]> temp(new (std::nothrow) uint8_t[remaining]);\n        if (!temp)\n        {\n            image.Release();\n            return E_OUTOFMEMORY;\n        }\n\n    #ifdef _WIN32\n        if (!ReadFile(hFile.get(), temp.get(), static_cast<DWORD>(remaining), &bytesRead, nullptr))\n        {\n            image.Release();\n            return HRESULT_FROM_WIN32(GetLastError());\n        }\n\n        if (bytesRead != remaining)\n        {\n            image.Release();\n            return E_FAIL;\n        }\n    #else\n        inFile.read(reinterpret_cast<char*>(temp.get()), remaining);\n        if (!inFile)\n        {\n            image.Release();\n            return E_FAIL;\n        }\n    #endif\n\n        CP_FLAGS cflags = CP_FLAGS_NONE;\n        if (flags & DDS_FLAGS_LEGACY_DWORD)\n        {\n            cflags |= CP_FLAGS_LEGACY_DWORD;\n        }\n        if (flags & DDS_FLAGS_BAD_DXTN_TAILS)\n        {\n            cflags |= CP_FLAGS_BAD_DXTN_TAILS;\n        }\n\n        hr = CopyImage(temp.get(),\n            remaining,\n            mdata,\n            cflags,\n            convFlags,\n            pal8.get(),\n            image);\n        if (FAILED(hr))\n        {\n            image.Release();\n            return hr;\n        }\n    }\n    else\n    {\n        if (remaining < image.GetPixelsSize())\n        {\n            image.Release();\n            return HRESULT_E_HANDLE_EOF;\n        }\n\n        if (image.GetPixelsSize() > UINT32_MAX)\n        {\n            image.Release();\n            return HRESULT_E_ARITHMETIC_OVERFLOW;\n        }\n\n    #ifdef _WIN32\n        auto const pixelBytes = static_cast<DWORD>(image.GetPixelsSize());\n        if (!ReadFile(hFile.get(), image.GetPixels(), pixelBytes, &bytesRead, nullptr))\n        {\n            image.Release();\n            return HRESULT_FROM_WIN32(GetLastError());\n        }\n\n        if (bytesRead != pixelBytes)\n        {\n            image.Release();\n            return E_FAIL;\n        }\n    #else\n        inFile.read(reinterpret_cast<char*>(image.GetPixels()), image.GetPixelsSize());\n        if (!inFile)\n        {\n            image.Release();\n            return E_FAIL;\n        }\n    #endif\n\n        if (convFlags & (CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA))\n        {\n            // Swizzle/copy image in place\n            hr = CopyImageInPlace(convFlags, image);\n            if (FAILED(hr))\n            {\n                image.Release();\n                return hr;\n            }\n        }\n    }\n\n    if (metadata)\n        memcpy(metadata, &mdata, sizeof(TexMetadata));\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Save a DDS file to memory\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::SaveToDDSMemory(\n    const Image* images,\n    size_t nimages,\n    const TexMetadata& metadata,\n    DDS_FLAGS flags,\n    Blob& blob) noexcept\n{\n    if (!images || (nimages == 0))\n        return E_INVALIDARG;\n\n    // Determine memory required\n    size_t required = 0;\n    HRESULT hr = EncodeDDSHeader(metadata, flags, nullptr, 0, required);\n    if (FAILED(hr))\n        return hr;\n\n    bool fastpath = true;\n\n    for (size_t i = 0; i < nimages; ++i)\n    {\n        if (!images[i].pixels)\n            return E_POINTER;\n\n        if (images[i].format != metadata.format)\n            return E_FAIL;\n\n        size_t ddsRowPitch, ddsSlicePitch;\n        hr = ComputePitch(metadata.format, images[i].width, images[i].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);\n        if (FAILED(hr))\n            return hr;\n\n        assert(images[i].rowPitch > 0);\n        assert(images[i].slicePitch > 0);\n\n        if ((images[i].rowPitch != ddsRowPitch) || (images[i].slicePitch != ddsSlicePitch))\n        {\n            fastpath = false;\n        }\n\n        required += ddsSlicePitch;\n    }\n\n    assert(required > 0);\n\n    blob.Release();\n\n    hr = blob.Initialize(required);\n    if (FAILED(hr))\n        return hr;\n\n    auto pDestination = static_cast<uint8_t*>(blob.GetBufferPointer());\n    assert(pDestination);\n\n    hr = EncodeDDSHeader(metadata, flags, pDestination, blob.GetBufferSize(), required);\n    if (FAILED(hr))\n    {\n        blob.Release();\n        return hr;\n    }\n\n    size_t remaining = blob.GetBufferSize() - required;\n    pDestination += required;\n\n    if (!remaining)\n    {\n        blob.Release();\n        return E_FAIL;\n    }\n\n    switch (static_cast<DDS_RESOURCE_DIMENSION>(metadata.dimension))\n    {\n    case DDS_DIMENSION_TEXTURE1D:\n    case DDS_DIMENSION_TEXTURE2D:\n        {\n            size_t index = 0;\n            for (size_t item = 0; item < metadata.arraySize; ++item)\n            {\n                for (size_t level = 0; level < metadata.mipLevels; ++level)\n                {\n                    if (index >= nimages)\n                    {\n                        blob.Release();\n                        return E_FAIL;\n                    }\n\n                    if (fastpath)\n                    {\n                        size_t pixsize = images[index].slicePitch;\n                        memcpy(pDestination, images[index].pixels, pixsize);\n\n                        pDestination += pixsize;\n                        remaining -= pixsize;\n                    }\n                    else\n                    {\n                        size_t ddsRowPitch, ddsSlicePitch;\n                        hr = ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);\n                        if (FAILED(hr))\n                        {\n                            blob.Release();\n                            return hr;\n                        }\n\n                        const size_t rowPitch = images[index].rowPitch;\n\n                        const uint8_t * __restrict sPtr = images[index].pixels;\n                        uint8_t * __restrict dPtr = pDestination;\n\n                        const size_t lines = ComputeScanlines(metadata.format, images[index].height);\n                        const size_t csize = std::min<size_t>(rowPitch, ddsRowPitch);\n                        size_t tremaining = remaining;\n                        for (size_t j = 0; j < lines; ++j)\n                        {\n                            if (tremaining < csize)\n                            {\n                                blob.Release();\n                                return E_FAIL;\n                            }\n\n                            memcpy(dPtr, sPtr, csize);\n\n                            sPtr += rowPitch;\n                            dPtr += ddsRowPitch;\n                            tremaining -= ddsRowPitch;\n                        }\n\n                        pDestination += ddsSlicePitch;\n                        remaining -= ddsSlicePitch;\n                    }\n\n                    ++index;\n                }\n            }\n        }\n        break;\n\n    case DDS_DIMENSION_TEXTURE3D:\n        {\n            if (metadata.arraySize != 1)\n            {\n                blob.Release();\n                return E_FAIL;\n            }\n\n            size_t d = metadata.depth;\n\n            size_t index = 0;\n            for (size_t level = 0; level < metadata.mipLevels; ++level)\n            {\n                for (size_t slice = 0; slice < d; ++slice)\n                {\n                    if (index >= nimages)\n                    {\n                        blob.Release();\n                        return E_FAIL;\n                    }\n\n                    if (fastpath)\n                    {\n                        size_t pixsize = images[index].slicePitch;\n                        memcpy(pDestination, images[index].pixels, pixsize);\n\n                        pDestination += pixsize;\n                        remaining -= pixsize;\n                    }\n                    else\n                    {\n                        size_t ddsRowPitch, ddsSlicePitch;\n                        hr = ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);\n                        if (FAILED(hr))\n                        {\n                            blob.Release();\n                            return hr;\n                        }\n\n                        const size_t rowPitch = images[index].rowPitch;\n\n                        const uint8_t * __restrict sPtr = images[index].pixels;\n                        uint8_t * __restrict dPtr = pDestination;\n\n                        const size_t lines = ComputeScanlines(metadata.format, images[index].height);\n                        const size_t csize = std::min<size_t>(rowPitch, ddsRowPitch);\n                        size_t tremaining = remaining;\n                        for (size_t j = 0; j < lines; ++j)\n                        {\n                            if (tremaining < csize)\n                            {\n                                blob.Release();\n                                return E_FAIL;\n                            }\n\n                            memcpy(dPtr, sPtr, csize);\n\n                            sPtr += rowPitch;\n                            dPtr += ddsRowPitch;\n                            tremaining -= ddsRowPitch;\n                        }\n\n                        pDestination += ddsSlicePitch;\n                        remaining -= ddsSlicePitch;\n                    }\n\n                    ++index;\n                }\n\n                if (d > 1)\n                    d >>= 1;\n            }\n        }\n        break;\n\n    default:\n        blob.Release();\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Save a DDS file to disk\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::SaveToDDSFile(\n    const Image* images,\n    size_t nimages,\n    const TexMetadata& metadata,\n    DDS_FLAGS flags,\n    const wchar_t* szFile) noexcept\n{\n    if (!szFile)\n        return E_INVALIDARG;\n\n    // Create DDS Header\n    uint8_t header[MAX_HEADER_SIZE];\n    size_t required;\n    HRESULT hr = EncodeDDSHeader(metadata, flags, header, MAX_HEADER_SIZE, required);\n    if (FAILED(hr))\n        return hr;\n\n    // Create file and write header\n#ifdef _WIN32\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n    ScopedHandle hFile(safe_handle(CreateFile2(szFile,\n        GENERIC_WRITE | DELETE, 0, CREATE_ALWAYS, nullptr)));\n#else\n    ScopedHandle hFile(safe_handle(CreateFileW(szFile,\n        GENERIC_WRITE | DELETE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr)));\n#endif\n    if (!hFile)\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    auto_delete_file delonfail(hFile.get());\n\n    DWORD bytesWritten;\n    if (!WriteFile(hFile.get(), header, static_cast<DWORD>(required), &bytesWritten, nullptr))\n    {\n        return HRESULT_FROM_WIN32(GetLastError());\n    }\n\n    if (bytesWritten != required)\n    {\n        return E_FAIL;\n    }\n#else // !WIN32\n    std::ofstream outFile(std::filesystem::path(szFile), std::ios::out | std::ios::binary | std::ios::trunc);\n    if (!outFile)\n        return E_FAIL;\n\n    outFile.write(reinterpret_cast<char*>(header), static_cast<std::streamsize>(required));\n    if (!outFile)\n        return E_FAIL;\n#endif\n\n    // Write images\n    switch (static_cast<DDS_RESOURCE_DIMENSION>(metadata.dimension))\n    {\n    case DDS_DIMENSION_TEXTURE1D:\n    case DDS_DIMENSION_TEXTURE2D:\n        {\n            size_t index = 0;\n            for (size_t item = 0; item < metadata.arraySize; ++item)\n            {\n                for (size_t level = 0; level < metadata.mipLevels; ++level, ++index)\n                {\n                    if (index >= nimages)\n                        return E_FAIL;\n\n                    if (!images[index].pixels)\n                        return E_POINTER;\n\n                    assert(images[index].rowPitch > 0);\n                    assert(images[index].slicePitch > 0);\n\n                    size_t ddsRowPitch, ddsSlicePitch;\n                    hr = ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);\n                    if (FAILED(hr))\n                        return hr;\n\n                    if ((images[index].slicePitch == ddsSlicePitch) && (ddsSlicePitch <= UINT32_MAX))\n                    {\n                    #ifdef _WIN32\n                        if (!WriteFile(hFile.get(), images[index].pixels, static_cast<DWORD>(ddsSlicePitch), &bytesWritten, nullptr))\n                        {\n                            return HRESULT_FROM_WIN32(GetLastError());\n                        }\n\n                        if (bytesWritten != ddsSlicePitch)\n                        {\n                            return E_FAIL;\n                        }\n                    #else\n                        outFile.write(reinterpret_cast<char*>(images[index].pixels), static_cast<std::streamsize>(ddsSlicePitch));\n                        if (!outFile)\n                            return E_FAIL;\n                    #endif\n                    }\n                    else\n                    {\n                        const size_t rowPitch = images[index].rowPitch;\n                        if (rowPitch < ddsRowPitch)\n                        {\n                            // DDS uses 1-byte alignment, so if this is happening then the input pitch isn't actually a full line of data\n                            return E_FAIL;\n                        }\n\n                        if (ddsRowPitch > UINT32_MAX)\n                            return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n                        const uint8_t * __restrict sPtr = images[index].pixels;\n\n                        const size_t lines = ComputeScanlines(metadata.format, images[index].height);\n                        for (size_t j = 0; j < lines; ++j)\n                        {\n                        #ifdef _WIN32\n                            if (!WriteFile(hFile.get(), sPtr, static_cast<DWORD>(ddsRowPitch), &bytesWritten, nullptr))\n                            {\n                                return HRESULT_FROM_WIN32(GetLastError());\n                            }\n\n                            if (bytesWritten != ddsRowPitch)\n                            {\n                                return E_FAIL;\n                            }\n                        #else\n                            outFile.write(reinterpret_cast<const char*>(sPtr), static_cast<std::streamsize>(ddsRowPitch));\n                            if (!outFile)\n                                return E_FAIL;\n                        #endif\n\n                            sPtr += rowPitch;\n                        }\n                    }\n                }\n            }\n        }\n        break;\n\n    case DDS_DIMENSION_TEXTURE3D:\n        {\n            if (metadata.arraySize != 1)\n                return E_FAIL;\n\n            size_t d = metadata.depth;\n\n            size_t index = 0;\n            for (size_t level = 0; level < metadata.mipLevels; ++level)\n            {\n                for (size_t slice = 0; slice < d; ++slice, ++index)\n                {\n                    if (index >= nimages)\n                        return E_FAIL;\n\n                    if (!images[index].pixels)\n                        return E_POINTER;\n\n                    assert(images[index].rowPitch > 0);\n                    assert(images[index].slicePitch > 0);\n\n                    size_t ddsRowPitch, ddsSlicePitch;\n                    hr = ComputePitch(metadata.format, images[index].width, images[index].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE);\n                    if (FAILED(hr))\n                        return hr;\n\n                    if ((images[index].slicePitch == ddsSlicePitch) && (ddsSlicePitch <= UINT32_MAX))\n                    {\n                    #ifdef _WIN32\n                        if (!WriteFile(hFile.get(), images[index].pixels, static_cast<DWORD>(ddsSlicePitch), &bytesWritten, nullptr))\n                        {\n                            return HRESULT_FROM_WIN32(GetLastError());\n                        }\n\n                        if (bytesWritten != ddsSlicePitch)\n                        {\n                            return E_FAIL;\n                        }\n                    #else\n                        outFile.write(reinterpret_cast<char*>(images[index].pixels), static_cast<std::streamsize>(ddsSlicePitch));\n                        if (!outFile)\n                            return E_FAIL;\n                    #endif\n                    }\n                    else\n                    {\n                        const size_t rowPitch = images[index].rowPitch;\n                        if (rowPitch < ddsRowPitch)\n                        {\n                            // DDS uses 1-byte alignment, so if this is happening then the input pitch isn't actually a full line of data\n                            return E_FAIL;\n                        }\n\n                        if (ddsRowPitch > UINT32_MAX)\n                            return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n                        const uint8_t * __restrict sPtr = images[index].pixels;\n\n                        const size_t lines = ComputeScanlines(metadata.format, images[index].height);\n                        for (size_t j = 0; j < lines; ++j)\n                        {\n                        #ifdef _WIN32\n                            if (!WriteFile(hFile.get(), sPtr, static_cast<DWORD>(ddsRowPitch), &bytesWritten, nullptr))\n                            {\n                                return HRESULT_FROM_WIN32(GetLastError());\n                            }\n\n                            if (bytesWritten != ddsRowPitch)\n                            {\n                                return E_FAIL;\n                            }\n                        #else\n                            outFile.write(reinterpret_cast<const char*>(sPtr), static_cast<std::streamsize>(ddsRowPitch));\n                            if (!outFile)\n                                return E_FAIL;\n                        #endif\n                            sPtr += rowPitch;\n                        }\n                    }\n                }\n\n                if (d > 1)\n                    d >>= 1;\n            }\n        }\n        break;\n\n    default:\n        return E_FAIL;\n    }\n\n#ifdef _WIN32\n    delonfail.clear();\n#endif\n\n    return S_OK;\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTexFlipRotate.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTexFlipRotate.cpp\n//\n// DirectX Texture Library - Image flip/rotate operations\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::Internal;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    //-------------------------------------------------------------------------------------\n    // Do flip/rotate operation using WIC\n    //-------------------------------------------------------------------------------------\n    HRESULT PerformFlipRotateUsingWIC(\n        const Image& srcImage,\n        TEX_FR_FLAGS flags,\n        const WICPixelFormatGUID& pfGUID,\n        const Image& destImage) noexcept\n    {\n        if (!srcImage.pixels || !destImage.pixels)\n            return E_POINTER;\n\n        assert(srcImage.format == destImage.format);\n\n        bool iswic2 = false;\n        auto pWIC = GetWICFactory(iswic2);\n        if (!pWIC)\n            return E_NOINTERFACE;\n\n        if (srcImage.rowPitch > UINT32_MAX || srcImage.slicePitch > UINT32_MAX\n            || destImage.rowPitch > UINT32_MAX || destImage.slicePitch > UINT32_MAX)\n            return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n        ComPtr<IWICBitmap> source;\n        HRESULT hr = pWIC->CreateBitmapFromMemory(static_cast<UINT>(srcImage.width), static_cast<UINT>(srcImage.height), pfGUID,\n            static_cast<UINT>(srcImage.rowPitch), static_cast<UINT>(srcImage.slicePitch),\n            srcImage.pixels, source.GetAddressOf());\n        if (FAILED(hr))\n            return hr;\n\n        ComPtr<IWICBitmapFlipRotator> FR;\n        hr = pWIC->CreateBitmapFlipRotator(FR.GetAddressOf());\n        if (FAILED(hr))\n            return hr;\n\n        hr = FR->Initialize(source.Get(), static_cast<WICBitmapTransformOptions>(flags));\n        if (FAILED(hr))\n            return hr;\n\n        WICPixelFormatGUID pfFR;\n        hr = FR->GetPixelFormat(&pfFR);\n        if (FAILED(hr))\n            return hr;\n\n        if (memcmp(&pfFR, &pfGUID, sizeof(GUID)) != 0)\n        {\n            // Flip/rotate should return the same format as the source...\n            return HRESULT_E_NOT_SUPPORTED;\n        }\n\n        UINT nwidth, nheight;\n        hr = FR->GetSize(&nwidth, &nheight);\n        if (FAILED(hr))\n            return hr;\n\n        if (destImage.width != nwidth || destImage.height != nheight)\n            return E_FAIL;\n\n        hr = FR->CopyPixels(nullptr, static_cast<UINT>(destImage.rowPitch), static_cast<UINT>(destImage.slicePitch), destImage.pixels);\n        if (FAILED(hr))\n            return hr;\n\n        return S_OK;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    // Do conversion, flip/rotate using WIC, conversion cycle\n    //\n    // For large images we have to use F16 instead of F32 to avoid exceeding the 32-bit\n    // memory limitations of WIC.\n    //-------------------------------------------------------------------------------------\n    HRESULT PerformFlipRotateViaF16(\n        const Image& srcImage,\n        TEX_FR_FLAGS flags,\n        const Image& destImage) noexcept\n    {\n        if (!srcImage.pixels || !destImage.pixels)\n            return E_POINTER;\n\n        assert(srcImage.format != DXGI_FORMAT_R16G16B16A16_FLOAT);\n        assert(srcImage.format == destImage.format);\n\n        ScratchImage temp;\n        HRESULT hr = ConvertToR16G16B16A16(srcImage, temp);\n        if (FAILED(hr))\n            return hr;\n\n        const Image *tsrc = temp.GetImage(0, 0, 0);\n        if (!tsrc)\n            return E_POINTER;\n\n        ScratchImage rtemp;\n        hr = rtemp.Initialize2D(DXGI_FORMAT_R16G16B16A16_FLOAT, destImage.width, destImage.height, 1, 1);\n        if (FAILED(hr))\n            return hr;\n\n        const Image *tdest = rtemp.GetImage(0, 0, 0);\n        if (!tdest)\n            return E_POINTER;\n\n        hr = PerformFlipRotateUsingWIC(*tsrc, flags, GUID_WICPixelFormat64bppRGBAHalf, *tdest);\n        if (FAILED(hr))\n            return hr;\n\n        temp.Release();\n\n        hr = ConvertFromR16G16B16A16(*tdest, destImage);\n        if (FAILED(hr))\n            return hr;\n\n        return S_OK;\n    }\n\n    HRESULT PerformFlipRotateViaF32(\n        const Image& srcImage,\n        TEX_FR_FLAGS flags,\n        const Image& destImage) noexcept\n    {\n        if (!srcImage.pixels || !destImage.pixels)\n            return E_POINTER;\n\n        assert(srcImage.format != DXGI_FORMAT_R32G32B32A32_FLOAT);\n        assert(srcImage.format == destImage.format);\n\n        ScratchImage temp;\n        HRESULT hr = ConvertToR32G32B32A32(srcImage, temp);\n        if (FAILED(hr))\n            return hr;\n\n        const Image *tsrc = temp.GetImage(0, 0, 0);\n        if (!tsrc)\n            return E_POINTER;\n\n        ScratchImage rtemp;\n        hr = rtemp.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, destImage.width, destImage.height, 1, 1);\n        if (FAILED(hr))\n            return hr;\n\n        const Image *tdest = rtemp.GetImage(0, 0, 0);\n        if (!tdest)\n            return E_POINTER;\n\n        hr = PerformFlipRotateUsingWIC(*tsrc, flags, GUID_WICPixelFormat128bppRGBAFloat, *tdest);\n        if (FAILED(hr))\n            return hr;\n\n        temp.Release();\n\n        hr = ConvertFromR32G32B32A32(*tdest, destImage);\n        if (FAILED(hr))\n            return hr;\n\n        return S_OK;\n    }\n}\n\n\n//=====================================================================================\n// Entry-points\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n// Flip/rotate image\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::FlipRotate(\n    const Image& srcImage,\n    TEX_FR_FLAGS flags,\n    ScratchImage& image) noexcept\n{\n    if (!srcImage.pixels)\n        return E_POINTER;\n\n    if (!flags)\n        return E_INVALIDARG;\n\n    if ((srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX))\n        return E_INVALIDARG;\n\n    if (IsCompressed(srcImage.format))\n    {\n        // We don't support flip/rotate operations on compressed images\n        return HRESULT_E_NOT_SUPPORTED;\n    }\n\n    static_assert(static_cast<int>(TEX_FR_ROTATE0) == static_cast<int>(WICBitmapTransformRotate0), \"TEX_FR_ROTATE0 no longer matches WIC\");\n    static_assert(static_cast<int>(TEX_FR_ROTATE90) == static_cast<int>(WICBitmapTransformRotate90), \"TEX_FR_ROTATE90 no longer matches WIC\");\n    static_assert(static_cast<int>(TEX_FR_ROTATE180) == static_cast<int>(WICBitmapTransformRotate180), \"TEX_FR_ROTATE180 no longer matches WIC\");\n    static_assert(static_cast<int>(TEX_FR_ROTATE270) == static_cast<int>(WICBitmapTransformRotate270), \"TEX_FR_ROTATE270 no longer matches WIC\");\n    static_assert(static_cast<int>(TEX_FR_FLIP_HORIZONTAL) == static_cast<int>(WICBitmapTransformFlipHorizontal), \"TEX_FR_FLIP_HORIZONTAL no longer matches WIC\");\n    static_assert(static_cast<int>(TEX_FR_FLIP_VERTICAL) == static_cast<int>(WICBitmapTransformFlipVertical), \"TEX_FR_FLIP_VERTICAL no longer matches WIC\");\n\n    // Only supports 90, 180, 270, or no rotation flags... not a combination of rotation flags\n    const int rotateMode = static_cast<int>(flags & (TEX_FR_ROTATE0 | TEX_FR_ROTATE90 | TEX_FR_ROTATE180 | TEX_FR_ROTATE270));\n\n    switch (rotateMode)\n    {\n    case 0:\n    case TEX_FR_ROTATE90:\n    case TEX_FR_ROTATE180:\n    case TEX_FR_ROTATE270:\n        break;\n\n    default:\n        return E_INVALIDARG;\n    }\n\n    size_t nwidth = srcImage.width;\n    size_t nheight = srcImage.height;\n\n    if ((rotateMode == TEX_FR_ROTATE90) || (rotateMode == TEX_FR_ROTATE270))\n    {\n        nwidth = srcImage.height;\n        nheight = srcImage.width;\n    }\n\n    HRESULT hr = image.Initialize2D(srcImage.format, nwidth, nheight, 1, 1);\n    if (FAILED(hr))\n        return hr;\n\n    const Image *rimage = image.GetImage(0, 0, 0);\n    if (!rimage)\n    {\n        image.Release();\n        return E_POINTER;\n    }\n\n    WICPixelFormatGUID pfGUID;\n    if (DXGIToWIC(srcImage.format, pfGUID))\n    {\n        // Case 1: Source format is supported by Windows Imaging Component\n        hr = PerformFlipRotateUsingWIC(srcImage, flags, pfGUID, *rimage);\n    }\n    else\n    {\n        // Case 2: Source format is not supported by WIC, so we have to convert, flip/rotate, and convert back\n        const uint64_t expandedSize = uint64_t(srcImage.width) * uint64_t(srcImage.height) * sizeof(float) * 4;\n        if (expandedSize > UINT32_MAX)\n        {\n            // Image is too large for float32, so have to use float16 instead\n            hr = PerformFlipRotateViaF16(srcImage, flags, *rimage);\n        }\n        else\n        {\n            hr = PerformFlipRotateViaF32(srcImage, flags, *rimage);\n        }\n    }\n\n    if (FAILED(hr))\n    {\n        image.Release();\n        return hr;\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Flip/rotate image (complex)\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::FlipRotate(\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    TEX_FR_FLAGS flags,\n    ScratchImage& result) noexcept\n{\n    if (!srcImages || !nimages)\n        return E_INVALIDARG;\n\n    if (IsCompressed(metadata.format))\n    {\n        // We don't support flip/rotate operations on compressed images\n        return HRESULT_E_NOT_SUPPORTED;\n    }\n\n    static_assert(static_cast<int>(TEX_FR_ROTATE0) == static_cast<int>(WICBitmapTransformRotate0), \"TEX_FR_ROTATE0 no longer matches WIC\");\n    static_assert(static_cast<int>(TEX_FR_ROTATE90) == static_cast<int>(WICBitmapTransformRotate90), \"TEX_FR_ROTATE90 no longer matches WIC\");\n    static_assert(static_cast<int>(TEX_FR_ROTATE180) == static_cast<int>(WICBitmapTransformRotate180), \"TEX_FR_ROTATE180 no longer matches WIC\");\n    static_assert(static_cast<int>(TEX_FR_ROTATE270) == static_cast<int>(WICBitmapTransformRotate270), \"TEX_FR_ROTATE270 no longer matches WIC\");\n    static_assert(static_cast<int>(TEX_FR_FLIP_HORIZONTAL) == static_cast<int>(WICBitmapTransformFlipHorizontal), \"TEX_FR_FLIP_HORIZONTAL no longer matches WIC\");\n    static_assert(static_cast<int>(TEX_FR_FLIP_VERTICAL) == static_cast<int>(WICBitmapTransformFlipVertical), \"TEX_FR_FLIP_VERTICAL no longer matches WIC\");\n\n    // Only supports 90, 180, 270, or no rotation flags... not a combination of rotation flags\n    const int rotateMode = static_cast<int>(flags & (TEX_FR_ROTATE0 | TEX_FR_ROTATE90 | TEX_FR_ROTATE180 | TEX_FR_ROTATE270));\n\n    switch (rotateMode)\n    {\n    case 0:\n    case TEX_FR_ROTATE90:\n    case TEX_FR_ROTATE180:\n    case TEX_FR_ROTATE270:\n        break;\n\n    default:\n        return E_INVALIDARG;\n    }\n\n    TexMetadata mdata2 = metadata;\n\n    bool flipwh = false;\n    if ((rotateMode == TEX_FR_ROTATE90) || (rotateMode == TEX_FR_ROTATE270))\n    {\n        flipwh = true;\n        mdata2.width = metadata.height;\n        mdata2.height = metadata.width;\n    }\n\n    HRESULT hr = result.Initialize(mdata2);\n    if (FAILED(hr))\n        return hr;\n\n    if (nimages != result.GetImageCount())\n    {\n        result.Release();\n        return E_FAIL;\n    }\n\n    const Image* dest = result.GetImages();\n    if (!dest)\n    {\n        result.Release();\n        return E_POINTER;\n    }\n\n    WICPixelFormatGUID pfGUID;\n    const bool wicpf = DXGIToWIC(metadata.format, pfGUID);\n\n    for (size_t index = 0; index < nimages; ++index)\n    {\n        const Image& src = srcImages[index];\n        if (src.format != metadata.format)\n        {\n            result.Release();\n            return E_FAIL;\n        }\n\n        if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX))\n            return E_FAIL;\n\n        const Image& dst = dest[index];\n        assert(dst.format == metadata.format);\n\n        if (flipwh)\n        {\n            if (src.width != dst.height || src.height != dst.width)\n            {\n                result.Release();\n                return E_FAIL;\n            }\n        }\n        else\n        {\n            if (src.width != dst.width || src.height != dst.height)\n            {\n                result.Release();\n                return E_FAIL;\n            }\n        }\n\n        if (wicpf)\n        {\n            // Case 1: Source format is supported by Windows Imaging Component\n            hr = PerformFlipRotateUsingWIC(src, flags, pfGUID, dst);\n        }\n        else\n        {\n            // Case 2: Source format is not supported by WIC, so we have to convert, flip/rotate, and convert back\n            const uint64_t expandedSize = uint64_t(src.width) * uint64_t(src.height) * sizeof(float) * 4;\n            if (expandedSize > UINT32_MAX)\n            {\n                // Image is too large for float32, so have to use float16 instead\n                hr = PerformFlipRotateViaF16(src, flags, dst);\n            }\n            else\n            {\n                hr = PerformFlipRotateViaF32(src, flags, dst);\n            }\n        }\n\n        if (FAILED(hr))\n        {\n            result.Release();\n            return hr;\n        }\n    }\n\n    return S_OK;\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTexImage.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTexImage.cpp\n//\n// DirectX Texture Library - Image container\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::Internal;\n\n#ifndef _WIN32\nnamespace\n{\n    inline void * _aligned_malloc(size_t size, size_t alignment)\n    {\n        size = (size + alignment - 1) & ~(alignment - 1);\n        return std::aligned_alloc(alignment, size);\n    }\n\n#define _aligned_free free\n}\n#endif\n\n//-------------------------------------------------------------------------------------\n// Determines number of image array entries and pixel size\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nbool DirectX::Internal::DetermineImageArray(\n    const TexMetadata& metadata,\n    CP_FLAGS cpFlags,\n    size_t& nImages,\n    size_t& pixelSize) noexcept\n{\n    assert(metadata.width > 0 && metadata.height > 0 && metadata.depth > 0);\n    assert(metadata.arraySize > 0);\n    assert(metadata.mipLevels > 0);\n\n    uint64_t totalPixelSize = 0;\n    size_t nimages = 0;\n\n    switch (metadata.dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n    case TEX_DIMENSION_TEXTURE2D:\n        for (size_t item = 0; item < metadata.arraySize; ++item)\n        {\n            size_t w = metadata.width;\n            size_t h = metadata.height;\n\n            for (size_t level = 0; level < metadata.mipLevels; ++level)\n            {\n                size_t rowPitch, slicePitch;\n                if (FAILED(ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags)))\n                {\n                    nImages = pixelSize = 0;\n                    return false;\n                }\n\n                totalPixelSize += uint64_t(slicePitch);\n                ++nimages;\n\n                if (h > 1)\n                    h >>= 1;\n\n                if (w > 1)\n                    w >>= 1;\n            }\n        }\n        break;\n\n    case TEX_DIMENSION_TEXTURE3D:\n        {\n            size_t w = metadata.width;\n            size_t h = metadata.height;\n            size_t d = metadata.depth;\n\n            for (size_t level = 0; level < metadata.mipLevels; ++level)\n            {\n                size_t rowPitch, slicePitch;\n                if (FAILED(ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags)))\n                {\n                    nImages = pixelSize = 0;\n                    return false;\n                }\n\n                for (size_t slice = 0; slice < d; ++slice)\n                {\n                    totalPixelSize += uint64_t(slicePitch);\n                    ++nimages;\n                }\n\n                if (h > 1)\n                    h >>= 1;\n\n                if (w > 1)\n                    w >>= 1;\n\n                if (d > 1)\n                    d >>= 1;\n            }\n        }\n        break;\n\n    default:\n        nImages = pixelSize = 0;\n        return false;\n    }\n\n#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)\n    static_assert(sizeof(size_t) == 4, \"Not a 32-bit platform!\");\n    if (totalPixelSize > UINT32_MAX)\n    {\n        nImages = pixelSize = 0;\n        return false;\n    }\n#else\n    static_assert(sizeof(size_t) == 8, \"Not a 64-bit platform!\");\n#endif\n\n    nImages = nimages;\n    pixelSize = static_cast<size_t>(totalPixelSize);\n\n    return true;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Fills in the image array entries\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nbool DirectX::Internal::SetupImageArray(\n    uint8_t *pMemory,\n    size_t pixelSize,\n    const TexMetadata& metadata,\n    CP_FLAGS cpFlags,\n    Image* images,\n    size_t nImages) noexcept\n{\n    assert(pMemory);\n    assert(pixelSize > 0);\n    assert(nImages > 0);\n\n    if (!images)\n        return false;\n\n    size_t index = 0;\n    uint8_t* pixels = pMemory;\n    const uint8_t* pEndBits = pMemory + pixelSize;\n\n    switch (metadata.dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n    case TEX_DIMENSION_TEXTURE2D:\n        if (metadata.arraySize == 0 || metadata.mipLevels == 0)\n        {\n            return false;\n        }\n\n        for (size_t item = 0; item < metadata.arraySize; ++item)\n        {\n            size_t w = metadata.width;\n            size_t h = metadata.height;\n\n            for (size_t level = 0; level < metadata.mipLevels; ++level)\n            {\n                if (index >= nImages)\n                {\n                    return false;\n                }\n\n                size_t rowPitch, slicePitch;\n                if (FAILED(ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags)))\n                    return false;\n\n                images[index].width = w;\n                images[index].height = h;\n                images[index].format = metadata.format;\n                images[index].rowPitch = rowPitch;\n                images[index].slicePitch = slicePitch;\n                images[index].pixels = pixels;\n                ++index;\n\n                pixels += slicePitch;\n                if (pixels > pEndBits)\n                {\n                    return false;\n                }\n\n                if (h > 1)\n                    h >>= 1;\n\n                if (w > 1)\n                    w >>= 1;\n            }\n        }\n        return true;\n\n    case TEX_DIMENSION_TEXTURE3D:\n        {\n            if (metadata.mipLevels == 0 || metadata.depth == 0)\n            {\n                return false;\n            }\n\n            size_t w = metadata.width;\n            size_t h = metadata.height;\n            size_t d = metadata.depth;\n\n            for (size_t level = 0; level < metadata.mipLevels; ++level)\n            {\n                size_t rowPitch, slicePitch;\n                if (FAILED(ComputePitch(metadata.format, w, h, rowPitch, slicePitch, cpFlags)))\n                    return false;\n\n                for (size_t slice = 0; slice < d; ++slice)\n                {\n                    if (index >= nImages)\n                    {\n                        return false;\n                    }\n\n                    // We use the same memory organization that Direct3D 11 needs for D3D11_SUBRESOURCE_DATA\n                    // with all slices of a given miplevel being continuous in memory\n                    images[index].width = w;\n                    images[index].height = h;\n                    images[index].format = metadata.format;\n                    images[index].rowPitch = rowPitch;\n                    images[index].slicePitch = slicePitch;\n                    images[index].pixels = pixels;\n                    ++index;\n\n                    pixels += slicePitch;\n                    if (pixels > pEndBits)\n                    {\n                        return false;\n                    }\n                }\n\n                if (h > 1)\n                    h >>= 1;\n\n                if (w > 1)\n                    w >>= 1;\n\n                if (d > 1)\n                    d >>= 1;\n            }\n        }\n        return true;\n\n    default:\n        return false;\n    }\n}\n\n\n//=====================================================================================\n// ScratchImage - Bitmap image container\n//=====================================================================================\n\nScratchImage& ScratchImage::operator= (ScratchImage&& moveFrom) noexcept\n{\n    if (this != &moveFrom)\n    {\n        Release();\n\n        m_nimages = moveFrom.m_nimages;\n        m_size = moveFrom.m_size;\n        m_metadata = moveFrom.m_metadata;\n        m_image = moveFrom.m_image;\n        m_memory = moveFrom.m_memory;\n\n        moveFrom.m_nimages = 0;\n        moveFrom.m_size = 0;\n        moveFrom.m_image = nullptr;\n        moveFrom.m_memory = nullptr;\n    }\n    return *this;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Methods\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT ScratchImage::Initialize(const TexMetadata& mdata, CP_FLAGS flags) noexcept\n{\n    if (!IsValid(mdata.format))\n        return E_INVALIDARG;\n\n    if (IsPalettized(mdata.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    size_t mipLevels = mdata.mipLevels;\n\n    switch (mdata.dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n        if (!mdata.width || mdata.height != 1 || mdata.depth != 1 || !mdata.arraySize)\n            return E_INVALIDARG;\n\n        if (!CalculateMipLevels(mdata.width, 1, mipLevels))\n            return E_INVALIDARG;\n        break;\n\n    case TEX_DIMENSION_TEXTURE2D:\n        if (!mdata.width || !mdata.height || mdata.depth != 1 || !mdata.arraySize)\n            return E_INVALIDARG;\n\n        if (mdata.IsCubemap())\n        {\n            if ((mdata.arraySize % 6) != 0)\n                return E_INVALIDARG;\n        }\n\n        if (!CalculateMipLevels(mdata.width, mdata.height, mipLevels))\n            return E_INVALIDARG;\n        break;\n\n    case TEX_DIMENSION_TEXTURE3D:\n        if (!mdata.width || !mdata.height || !mdata.depth || mdata.arraySize != 1)\n            return E_INVALIDARG;\n\n        if (!CalculateMipLevels3D(mdata.width, mdata.height, mdata.depth, mipLevels))\n            return E_INVALIDARG;\n        break;\n\n    default:\n        return HRESULT_E_NOT_SUPPORTED;\n    }\n\n    Release();\n\n    m_metadata.width = mdata.width;\n    m_metadata.height = mdata.height;\n    m_metadata.depth = mdata.depth;\n    m_metadata.arraySize = mdata.arraySize;\n    m_metadata.mipLevels = mipLevels;\n    m_metadata.miscFlags = mdata.miscFlags;\n    m_metadata.miscFlags2 = mdata.miscFlags2;\n    m_metadata.format = mdata.format;\n    m_metadata.dimension = mdata.dimension;\n\n    size_t pixelSize, nimages;\n    if (!DetermineImageArray(m_metadata, flags, nimages, pixelSize))\n        return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n    m_image = new (std::nothrow) Image[nimages];\n    if (!m_image)\n        return E_OUTOFMEMORY;\n\n    m_nimages = nimages;\n    memset(m_image, 0, sizeof(Image) * nimages);\n\n    m_memory = static_cast<uint8_t*>(_aligned_malloc(pixelSize, 16));\n    if (!m_memory)\n    {\n        Release();\n        return E_OUTOFMEMORY;\n    }\n    m_size = pixelSize;\n    if (!SetupImageArray(m_memory, pixelSize, m_metadata, flags, m_image, nimages))\n    {\n        Release();\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT ScratchImage::Initialize1D(DXGI_FORMAT fmt, size_t length, size_t arraySize, size_t mipLevels, CP_FLAGS flags) noexcept\n{\n    if (!length || !arraySize)\n        return E_INVALIDARG;\n\n    // 1D is a special case of the 2D case\n    HRESULT hr = Initialize2D(fmt, length, 1, arraySize, mipLevels, flags);\n    if (FAILED(hr))\n        return hr;\n\n    m_metadata.dimension = TEX_DIMENSION_TEXTURE1D;\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT ScratchImage::Initialize2D(DXGI_FORMAT fmt, size_t width, size_t height, size_t arraySize, size_t mipLevels, CP_FLAGS flags) noexcept\n{\n    if (!IsValid(fmt) || !width || !height || !arraySize)\n        return E_INVALIDARG;\n\n    if (IsPalettized(fmt))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if (!CalculateMipLevels(width, height, mipLevels))\n        return E_INVALIDARG;\n\n    Release();\n\n    m_metadata.width = width;\n    m_metadata.height = height;\n    m_metadata.depth = 1;\n    m_metadata.arraySize = arraySize;\n    m_metadata.mipLevels = mipLevels;\n    m_metadata.miscFlags = 0;\n    m_metadata.miscFlags2 = 0;\n    m_metadata.format = fmt;\n    m_metadata.dimension = TEX_DIMENSION_TEXTURE2D;\n\n    size_t pixelSize, nimages;\n    if (!DetermineImageArray(m_metadata, flags, nimages, pixelSize))\n        return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n    m_image = new (std::nothrow) Image[nimages];\n    if (!m_image)\n        return E_OUTOFMEMORY;\n\n    m_nimages = nimages;\n    memset(m_image, 0, sizeof(Image) * nimages);\n\n    m_memory = static_cast<uint8_t*>(_aligned_malloc(pixelSize, 16));\n    if (!m_memory)\n    {\n        Release();\n        return E_OUTOFMEMORY;\n    }\n    m_size = pixelSize;\n    if (!SetupImageArray(m_memory, pixelSize, m_metadata, flags, m_image, nimages))\n    {\n        Release();\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT ScratchImage::Initialize3D(DXGI_FORMAT fmt, size_t width, size_t height, size_t depth, size_t mipLevels, CP_FLAGS flags) noexcept\n{\n    if (!IsValid(fmt) || !width || !height || !depth)\n        return E_INVALIDARG;\n\n    if (IsPalettized(fmt))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if (!CalculateMipLevels3D(width, height, depth, mipLevels))\n        return E_INVALIDARG;\n\n    Release();\n\n    m_metadata.width = width;\n    m_metadata.height = height;\n    m_metadata.depth = depth;\n    m_metadata.arraySize = 1;    // Direct3D 10.x/11 does not support arrays of 3D textures\n    m_metadata.mipLevels = mipLevels;\n    m_metadata.miscFlags = 0;\n    m_metadata.miscFlags2 = 0;\n    m_metadata.format = fmt;\n    m_metadata.dimension = TEX_DIMENSION_TEXTURE3D;\n\n    size_t pixelSize, nimages;\n    if (!DetermineImageArray(m_metadata, flags, nimages, pixelSize))\n        return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n    m_image = new (std::nothrow) Image[nimages];\n    if (!m_image)\n    {\n        Release();\n        return E_OUTOFMEMORY;\n    }\n    m_nimages = nimages;\n    memset(m_image, 0, sizeof(Image) * nimages);\n\n    m_memory = static_cast<uint8_t*>(_aligned_malloc(pixelSize, 16));\n    if (!m_memory)\n    {\n        Release();\n        return E_OUTOFMEMORY;\n    }\n    m_size = pixelSize;\n\n    if (!SetupImageArray(m_memory, pixelSize, m_metadata, flags, m_image, nimages))\n    {\n        Release();\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT ScratchImage::InitializeCube(DXGI_FORMAT fmt, size_t width, size_t height, size_t nCubes, size_t mipLevels, CP_FLAGS flags) noexcept\n{\n    if (!width || !height || !nCubes)\n        return E_INVALIDARG;\n\n    // A DirectX11 cubemap is just a 2D texture array that is a multiple of 6 for each cube\n    HRESULT hr = Initialize2D(fmt, width, height, nCubes * 6, mipLevels, flags);\n    if (FAILED(hr))\n        return hr;\n\n    m_metadata.miscFlags |= TEX_MISC_TEXTURECUBE;\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT ScratchImage::InitializeFromImage(const Image& srcImage, bool allow1D, CP_FLAGS flags) noexcept\n{\n    HRESULT hr = (srcImage.height > 1 || !allow1D)\n        ? Initialize2D(srcImage.format, srcImage.width, srcImage.height, 1, 1, flags)\n        : Initialize1D(srcImage.format, srcImage.width, 1, 1, flags);\n\n    if (FAILED(hr))\n        return hr;\n\n    const size_t rowCount = ComputeScanlines(srcImage.format, srcImage.height);\n    if (!rowCount)\n        return E_UNEXPECTED;\n\n    const uint8_t* sptr = srcImage.pixels;\n    if (!sptr)\n        return E_POINTER;\n\n    uint8_t* dptr = m_image[0].pixels;\n    if (!dptr)\n        return E_POINTER;\n\n    const size_t spitch = srcImage.rowPitch;\n    const size_t dpitch = m_image[0].rowPitch;\n\n    const size_t size = std::min<size_t>(dpitch, spitch);\n\n    for (size_t y = 0; y < rowCount; ++y)\n    {\n        memcpy(dptr, sptr, size);\n        sptr += spitch;\n        dptr += dpitch;\n    }\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT ScratchImage::InitializeArrayFromImages(const Image* images, size_t nImages, bool allow1D, CP_FLAGS flags) noexcept\n{\n    if (!images || !nImages)\n        return E_INVALIDARG;\n\n    const DXGI_FORMAT format = images[0].format;\n    const size_t width = images[0].width;\n    const size_t height = images[0].height;\n\n    for (size_t index = 0; index < nImages; ++index)\n    {\n        if (!images[index].pixels)\n            return E_POINTER;\n\n        if (images[index].format != format || images[index].width != width || images[index].height != height)\n        {\n            // All images must be the same format, width, and height\n            return E_FAIL;\n        }\n    }\n\n    HRESULT hr = (height > 1 || !allow1D)\n        ? Initialize2D(format, width, height, nImages, 1, flags)\n        : Initialize1D(format, width, nImages, 1, flags);\n\n    if (FAILED(hr))\n        return hr;\n\n    const size_t rowCount = ComputeScanlines(format, height);\n    if (!rowCount)\n        return E_UNEXPECTED;\n\n    for (size_t index = 0; index < nImages; ++index)\n    {\n        const uint8_t* sptr = images[index].pixels;\n        if (!sptr)\n            return E_POINTER;\n\n        assert(index < m_nimages);\n        uint8_t* dptr = m_image[index].pixels;\n        if (!dptr)\n            return E_POINTER;\n\n        const size_t spitch = images[index].rowPitch;\n        const size_t dpitch = m_image[index].rowPitch;\n\n        const size_t size = std::min<size_t>(dpitch, spitch);\n\n        for (size_t y = 0; y < rowCount; ++y)\n        {\n            memcpy(dptr, sptr, size);\n            sptr += spitch;\n            dptr += dpitch;\n        }\n    }\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT ScratchImage::InitializeCubeFromImages(const Image* images, size_t nImages, CP_FLAGS flags) noexcept\n{\n    if (!images || !nImages)\n        return E_INVALIDARG;\n\n    // A DirectX11 cubemap is just a 2D texture array that is a multiple of 6 for each cube\n    if ((nImages % 6) != 0)\n        return E_INVALIDARG;\n\n    HRESULT hr = InitializeArrayFromImages(images, nImages, false, flags);\n    if (FAILED(hr))\n        return hr;\n\n    m_metadata.miscFlags |= TEX_MISC_TEXTURECUBE;\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT ScratchImage::Initialize3DFromImages(const Image* images, size_t depth, CP_FLAGS flags) noexcept\n{\n    if (!images || !depth)\n        return E_INVALIDARG;\n\n    const DXGI_FORMAT format = images[0].format;\n    const size_t width = images[0].width;\n    const size_t height = images[0].height;\n\n    for (size_t slice = 0; slice < depth; ++slice)\n    {\n        if (!images[slice].pixels)\n            return E_POINTER;\n\n        if (images[slice].format != format || images[slice].width != width || images[slice].height != height)\n        {\n            // All images must be the same format, width, and height\n            return E_FAIL;\n        }\n    }\n\n    HRESULT hr = Initialize3D(format, width, height, depth, 1, flags);\n    if (FAILED(hr))\n        return hr;\n\n    const size_t rowCount = ComputeScanlines(format, height);\n    if (!rowCount)\n        return E_UNEXPECTED;\n\n    for (size_t slice = 0; slice < depth; ++slice)\n    {\n        const uint8_t* sptr = images[slice].pixels;\n        if (!sptr)\n            return E_POINTER;\n\n        assert(slice < m_nimages);\n        uint8_t* dptr = m_image[slice].pixels;\n        if (!dptr)\n            return E_POINTER;\n\n        const size_t spitch = images[slice].rowPitch;\n        const size_t dpitch = m_image[slice].rowPitch;\n\n        const size_t size = std::min<size_t>(dpitch, spitch);\n\n        for (size_t y = 0; y < rowCount; ++y)\n        {\n            memcpy(dptr, sptr, size);\n            sptr += spitch;\n            dptr += dpitch;\n        }\n    }\n\n    return S_OK;\n}\n\nvoid ScratchImage::Release() noexcept\n{\n    m_nimages = 0;\n    m_size = 0;\n\n    if (m_image)\n    {\n        delete[] m_image;\n        m_image = nullptr;\n    }\n\n    if (m_memory)\n    {\n        _aligned_free(m_memory);\n        m_memory = nullptr;\n    }\n\n    memset(&m_metadata, 0, sizeof(m_metadata));\n}\n\n_Use_decl_annotations_\nbool ScratchImage::OverrideFormat(DXGI_FORMAT f) noexcept\n{\n    if (!m_image)\n        return false;\n\n    if (!IsValid(f) || IsPlanar(f) || IsPalettized(f))\n        return false;\n\n    for (size_t index = 0; index < m_nimages; ++index)\n    {\n        m_image[index].format = f;\n    }\n\n    m_metadata.format = f;\n\n    return true;\n}\n\n_Use_decl_annotations_\nconst Image* ScratchImage::GetImage(size_t mip, size_t item, size_t slice) const noexcept\n{\n    if (mip >= m_metadata.mipLevels)\n        return nullptr;\n\n    size_t index = 0;\n\n    switch (m_metadata.dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n    case TEX_DIMENSION_TEXTURE2D:\n        if (slice > 0)\n            return nullptr;\n\n        if (item >= m_metadata.arraySize)\n            return nullptr;\n\n        index = item*(m_metadata.mipLevels) + mip;\n        break;\n\n    case TEX_DIMENSION_TEXTURE3D:\n        if (item > 0)\n        {\n            // No support for arrays of volumes\n            return nullptr;\n        }\n        else\n        {\n            size_t d = m_metadata.depth;\n\n            for (size_t level = 0; level < mip; ++level)\n            {\n                index += d;\n                if (d > 1)\n                    d >>= 1;\n            }\n\n            if (slice >= d)\n                return nullptr;\n\n            index += slice;\n        }\n        break;\n\n    default:\n        return nullptr;\n    }\n\n    return &m_image[index];\n}\n\nbool ScratchImage::IsAlphaAllOpaque() const noexcept\n{\n    if (!m_image)\n        return false;\n\n    if (!HasAlpha(m_metadata.format))\n        return true;\n\n    if (IsCompressed(m_metadata.format))\n    {\n        for (size_t index = 0; index < m_nimages; ++index)\n        {\n            if (!IsAlphaAllOpaqueBC(m_image[index]))\n                return false;\n        }\n    }\n    else\n    {\n        auto scanline = make_AlignedArrayXMVECTOR(m_metadata.width);\n        if (!scanline)\n            return false;\n\n        static const XMVECTORF32 threshold = { { { 0.997f, 0.997f, 0.997f, 0.997f } } };\n\n        for (size_t index = 0; index < m_nimages; ++index)\n        {\n        #pragma warning( suppress : 6011 )\n            const Image& img = m_image[index];\n\n            const uint8_t *pPixels = img.pixels;\n            assert(pPixels);\n\n            for (size_t h = 0; h < img.height; ++h)\n            {\n                if (!LoadScanline(scanline.get(), img.width, pPixels, img.rowPitch, img.format))\n                    return false;\n\n                const XMVECTOR* ptr = scanline.get();\n                for (size_t w = 0; w < img.width; ++w)\n                {\n                    const XMVECTOR alpha = XMVectorSplatW(*ptr);\n                    if (XMVector4Less(alpha, threshold))\n                        return false;\n                    ++ptr;\n                }\n\n                pPixels += img.rowPitch;\n            }\n        }\n    }\n\n    return true;\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTexMipmaps.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTexMipMaps.cpp\n//\n// DirectX Texture Library - Mip-map generation\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\n#include \"filters.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::Internal;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    constexpr bool ispow2(_In_ size_t x) noexcept\n    {\n        return ((x != 0) && !(x & (x - 1)));\n    }\n\n\n    size_t CountMips(_In_ size_t width, _In_ size_t height) noexcept\n    {\n        size_t mipLevels = 1;\n\n        while (height > 1 || width > 1)\n        {\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n\n            ++mipLevels;\n        }\n\n        return mipLevels;\n    }\n\n\n    size_t CountMips3D(_In_ size_t width, _In_ size_t height, _In_ size_t depth) noexcept\n    {\n        size_t mipLevels = 1;\n\n        while (height > 1 || width > 1 || depth > 1)\n        {\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n\n            if (depth > 1)\n                depth >>= 1;\n\n            ++mipLevels;\n        }\n\n        return mipLevels;\n    }\n\n#ifdef _WIN32\n    HRESULT EnsureWicBitmapPixelFormat(\n        _In_ IWICImagingFactory* pWIC,\n        _In_ IWICBitmap* src,\n        _In_ TEX_FILTER_FLAGS filter,\n        _In_ const WICPixelFormatGUID& desiredPixelFormat,\n        _Deref_out_ IWICBitmap** dest) noexcept\n    {\n        if (!pWIC || !src || !dest)\n            return E_POINTER;\n\n        *dest = nullptr;\n\n        WICPixelFormatGUID actualPixelFormat;\n        HRESULT hr = src->GetPixelFormat(&actualPixelFormat);\n\n        if (SUCCEEDED(hr))\n        {\n            if (memcmp(&actualPixelFormat, &desiredPixelFormat, sizeof(WICPixelFormatGUID)) == 0)\n            {\n                src->AddRef();\n                *dest = src;\n            }\n            else\n            {\n                ComPtr<IWICFormatConverter> converter;\n                hr = pWIC->CreateFormatConverter(converter.GetAddressOf());\n\n                if (SUCCEEDED(hr))\n                {\n                    BOOL canConvert = FALSE;\n                    hr = converter->CanConvert(actualPixelFormat, desiredPixelFormat, &canConvert);\n                    if (FAILED(hr) || !canConvert)\n                    {\n                        return E_UNEXPECTED;\n                    }\n                }\n\n                if (SUCCEEDED(hr))\n                {\n                    hr = converter->Initialize(src, desiredPixelFormat, GetWICDither(filter), nullptr,\n                        0, WICBitmapPaletteTypeMedianCut);\n                }\n\n                if (SUCCEEDED(hr))\n                {\n                    hr = pWIC->CreateBitmapFromSource(converter.Get(), WICBitmapCacheOnDemand, dest);\n                }\n            }\n        }\n\n        return hr;\n    }\n#endif // WIN32\n\n\n#if DIRECTX_MATH_VERSION >= 310\n#define VectorSum XMVectorSum\n#else\n    inline XMVECTOR XM_CALLCONV VectorSum\n    (\n        FXMVECTOR V\n    )\n    {\n        XMVECTOR vTemp = XMVectorSwizzle<2, 3, 0, 1>(V);\n        XMVECTOR vTemp2 = XMVectorAdd(V, vTemp);\n        vTemp = XMVectorSwizzle<1, 0, 3, 2>(vTemp2);\n        return XMVectorAdd(vTemp, vTemp2);\n    }\n#endif\n\n\n    HRESULT ScaleAlpha(\n        const Image& srcImage,\n        float alphaScale,\n        const Image& destImage) noexcept\n    {\n        assert(srcImage.width == destImage.width);\n        assert(srcImage.height == destImage.height);\n\n        auto scanline = make_AlignedArrayXMVECTOR(srcImage.width);\n        if (!scanline)\n        {\n            return E_OUTOFMEMORY;\n        }\n\n        const uint8_t* pSrc = srcImage.pixels;\n        uint8_t* pDest = destImage.pixels;\n        if (!pSrc || !pDest)\n        {\n            return E_POINTER;\n        }\n\n        const XMVECTOR vscale = XMVectorReplicate(alphaScale);\n\n        for (size_t h = 0; h < srcImage.height; ++h)\n        {\n            if (!LoadScanline(scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format))\n            {\n                return E_FAIL;\n            }\n\n            XMVECTOR* ptr = scanline.get();\n            for (size_t w = 0; w < srcImage.width; ++w)\n            {\n                const XMVECTOR v = *ptr;\n                const XMVECTOR alpha = XMVectorMultiply(XMVectorSplatW(v), vscale);\n                *(ptr++) = XMVectorSelect(alpha, v, g_XMSelect1110);\n            }\n\n            if (!StoreScanline(pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width))\n            {\n                return E_FAIL;\n            }\n\n            pSrc += srcImage.rowPitch;\n            pDest += destImage.rowPitch;\n        }\n\n        return S_OK;\n    }\n\n\n    void GenerateAlphaCoverageConvolutionVectors(\n        _In_ size_t N,\n        _Out_writes_(N*N) XMVECTOR* vectors) noexcept\n    {\n        for (size_t sy = 0; sy < N; ++sy)\n        {\n            const float fy = (float(sy) + 0.5f) / float(N);\n            const float ify = 1.0f - fy;\n\n            for (size_t sx = 0; sx < N; ++sx)\n            {\n                const float fx = (float(sx) + 0.5f) / float(N);\n                const float ifx = 1.0f - fx;\n\n                // [0]=(x+0, y+0), [1]=(x+0, y+1), [2]=(x+1, y+0), [3]=(x+1, y+1)\n                vectors[sy * N + sx] = XMVectorSet(ifx * ify, ifx * fy, fx * ify, fx * fy);\n            }\n        }\n    }\n\n\n    HRESULT CalculateAlphaCoverage(\n        const Image& srcImage,\n        float alphaReference,\n        float alphaScale,\n        float& coverage) noexcept\n    {\n        coverage = 0.0f;\n\n        auto row0 = make_AlignedArrayXMVECTOR(srcImage.width);\n        if (!row0)\n        {\n            return E_OUTOFMEMORY;\n        }\n\n        auto row1 = make_AlignedArrayXMVECTOR(srcImage.width);\n        if (!row1)\n        {\n            return E_OUTOFMEMORY;\n        }\n\n        const XMVECTOR scale = XMVectorReplicate(alphaScale);\n\n        const uint8_t *pSrcRow0 = srcImage.pixels;\n        if (!pSrcRow0)\n        {\n            return E_POINTER;\n        }\n\n        constexpr size_t N = 8;\n        XMVECTOR convolution[N * N];\n        GenerateAlphaCoverageConvolutionVectors(N, convolution);\n\n        size_t coverageCount = 0;\n        for (size_t y = 0; y < srcImage.height - 1; ++y)\n        {\n            if (!LoadScanlineLinear(row0.get(), srcImage.width, pSrcRow0, srcImage.rowPitch, srcImage.format, TEX_FILTER_DEFAULT))\n            {\n                return E_FAIL;\n            }\n\n            const uint8_t *pSrcRow1 = pSrcRow0 + srcImage.rowPitch;\n            if (!LoadScanlineLinear(row1.get(), srcImage.width, pSrcRow1, srcImage.rowPitch, srcImage.format, TEX_FILTER_DEFAULT))\n            {\n                return E_FAIL;\n            }\n\n            const XMVECTOR* pRow0 = row0.get();\n            const XMVECTOR* pRow1 = row1.get();\n            for (size_t x = 0; x < srcImage.width - 1; ++x)\n            {\n                // [0]=(x+0, y+0), [1]=(x+0, y+1), [2]=(x+1, y+0), [3]=(x+1, y+1)\n                XMVECTOR r0 = XMVectorSplatW(*pRow0);\n                XMVECTOR r1 = XMVectorSplatW(*pRow1);\n\n                XMVECTOR v1 = XMVectorSaturate(XMVectorMultiply(r0, scale));\n                const XMVECTOR v2 = XMVectorSaturate(XMVectorMultiply(r1, scale));\n\n                r0 = XMVectorSplatW(*(++pRow0));\n                r1 = XMVectorSplatW(*(++pRow1));\n\n                XMVECTOR v3 = XMVectorSaturate(XMVectorMultiply(XMVectorSplatW(r0), scale));\n                const XMVECTOR v4 = XMVectorSaturate(XMVectorMultiply(XMVectorSplatW(r1), scale));\n\n                v1 = XMVectorMergeXY(v1, v2); // [v1.x v2.x --- ---]\n                v3 = XMVectorMergeXY(v3, v4); // [v3.x v4.x --- ---]\n\n                XMVECTOR v = XMVectorPermute<0, 1, 4, 5>(v1, v3); // [v1.x v2.x v3.x v4.x]\n\n                for (size_t sy = 0; sy < N; ++sy)\n                {\n                    const size_t ry = sy * N;\n                    for (size_t sx = 0; sx < N; ++sx)\n                    {\n                        v = VectorSum(XMVectorMultiply(v, convolution[ry + sx]));\n                        if (XMVectorGetX(v) > alphaReference)\n                        {\n                            ++coverageCount;\n                        }\n                    }\n                }\n            }\n\n            pSrcRow0 = pSrcRow1;\n        }\n\n        float cscale = static_cast<float>((srcImage.width - 1) * (srcImage.height - 1) * N * N);\n        if (cscale > 0.f)\n        {\n            coverage = static_cast<float>(coverageCount) / cscale;\n        }\n\n        return S_OK;\n    }\n\n\n    HRESULT EstimateAlphaScaleForCoverage(\n        const Image& srcImage,\n        float alphaReference,\n        float targetCoverage,\n        float& alphaScale) noexcept\n    {\n        float minAlphaScale = 0.0f;\n        float maxAlphaScale = 4.0f;\n        float bestError = FLT_MAX;\n\n        // Determine desired scale using a binary search. Hardcoded to 10 steps max.\n        alphaScale = 1.0f;\n        constexpr size_t N = 10;\n        for (size_t i = 0; i < N; ++i)\n        {\n            float currentCoverage = 0.0f;\n            HRESULT hr = CalculateAlphaCoverage(srcImage, alphaReference, alphaScale, currentCoverage);\n            if (FAILED(hr))\n            {\n                return hr;\n            }\n\n            const float error = fabsf(currentCoverage - targetCoverage);\n            if (error < bestError)\n            {\n                bestError = error;\n            }\n\n            if (currentCoverage < targetCoverage)\n            {\n                minAlphaScale = alphaScale;\n            }\n            else if (currentCoverage > targetCoverage)\n            {\n                maxAlphaScale = alphaScale;\n            }\n            else\n            {\n                break;\n            }\n\n            alphaScale = (minAlphaScale + maxAlphaScale) * 0.5f;\n        }\n\n        return S_OK;\n    }\n}\n\n_Use_decl_annotations_\nbool DirectX::Internal::CalculateMipLevels(\n    size_t width,\n    size_t height,\n    size_t& mipLevels) noexcept\n{\n    if (mipLevels > 1)\n    {\n        const size_t maxMips = CountMips(width, height);\n        if (mipLevels > maxMips)\n            return false;\n    }\n    else if (mipLevels == 0)\n    {\n        mipLevels = CountMips(width, height);\n    }\n    else\n    {\n        mipLevels = 1;\n    }\n    return true;\n}\n\n_Use_decl_annotations_\nbool DirectX::Internal::CalculateMipLevels3D(\n    size_t width,\n    size_t height,\n    size_t depth,\n    size_t& mipLevels) noexcept\n{\n    if (mipLevels > 1)\n    {\n        const size_t maxMips = CountMips3D(width, height, depth);\n        if (mipLevels > maxMips)\n            return false;\n    }\n    else if (mipLevels == 0)\n    {\n        mipLevels = CountMips3D(width, height, depth);\n    }\n    else\n    {\n        mipLevels = 1;\n    }\n    return true;\n}\n\n#ifdef _WIN32\n//--- Resizing color and alpha channels separately using WIC ---\n_Use_decl_annotations_\nHRESULT DirectX::Internal::ResizeSeparateColorAndAlpha(\n    IWICImagingFactory* pWIC,\n    bool iswic2,\n    IWICBitmap* original,\n    size_t newWidth,\n    size_t newHeight,\n    TEX_FILTER_FLAGS filter,\n    const Image* img) noexcept\n{\n    if (!pWIC || !original || !img)\n        return E_POINTER;\n\n    const WICBitmapInterpolationMode interpolationMode = GetWICInterp(filter);\n\n    WICPixelFormatGUID desiredPixelFormat = GUID_WICPixelFormatUndefined;\n    HRESULT hr = original->GetPixelFormat(&desiredPixelFormat);\n\n    size_t colorBytesInPixel = 0;\n    size_t colorBytesPerPixel = 0;\n    size_t colorWithAlphaBytesPerPixel = 0;\n    WICPixelFormatGUID colorPixelFormat = GUID_WICPixelFormatUndefined;\n    WICPixelFormatGUID colorWithAlphaPixelFormat = GUID_WICPixelFormatUndefined;\n\n    if (SUCCEEDED(hr))\n    {\n        ComPtr<IWICComponentInfo> componentInfo;\n        hr = pWIC->CreateComponentInfo(desiredPixelFormat, componentInfo.GetAddressOf());\n\n        ComPtr<IWICPixelFormatInfo> pixelFormatInfo;\n        if (SUCCEEDED(hr))\n        {\n            hr = componentInfo.As(&pixelFormatInfo);\n        }\n\n        UINT bitsPerPixel = 0;\n        if (SUCCEEDED(hr))\n        {\n            hr = pixelFormatInfo->GetBitsPerPixel(&bitsPerPixel);\n        }\n\n        if (SUCCEEDED(hr))\n        {\n            if (bitsPerPixel <= 32)\n            {\n                colorBytesInPixel = colorBytesPerPixel = 3;\n                colorPixelFormat = GUID_WICPixelFormat24bppBGR;\n\n                colorWithAlphaBytesPerPixel = 4;\n                colorWithAlphaPixelFormat = GUID_WICPixelFormat32bppBGRA;\n            }\n            else\n            {\n            #if(_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE)\n                if (iswic2)\n                {\n                    colorBytesInPixel = colorBytesPerPixel = 12;\n                    colorPixelFormat = GUID_WICPixelFormat96bppRGBFloat;\n                }\n                else\n                #else\n                UNREFERENCED_PARAMETER(iswic2);\n            #endif\n                {\n                    colorBytesInPixel = 12;\n                    colorBytesPerPixel = 16;\n                    colorPixelFormat = GUID_WICPixelFormat128bppRGBFloat;\n                }\n\n                colorWithAlphaBytesPerPixel = 16;\n                colorWithAlphaPixelFormat = GUID_WICPixelFormat128bppRGBAFloat;\n            }\n        }\n    }\n\n    // Resize color only image (no alpha channel)\n    ComPtr<IWICBitmap> resizedColor;\n    if (SUCCEEDED(hr))\n    {\n        ComPtr<IWICBitmapScaler> colorScaler;\n        hr = pWIC->CreateBitmapScaler(colorScaler.GetAddressOf());\n        if (SUCCEEDED(hr))\n        {\n            ComPtr<IWICBitmap> converted;\n            hr = EnsureWicBitmapPixelFormat(pWIC, original, filter, colorPixelFormat, converted.GetAddressOf());\n            if (SUCCEEDED(hr))\n            {\n                hr = colorScaler->Initialize(converted.Get(), static_cast<UINT>(newWidth), static_cast<UINT>(newHeight), interpolationMode);\n            }\n        }\n\n        if (SUCCEEDED(hr))\n        {\n            ComPtr<IWICBitmap> resized;\n            hr = pWIC->CreateBitmapFromSource(colorScaler.Get(), WICBitmapCacheOnDemand, resized.GetAddressOf());\n            if (SUCCEEDED(hr))\n            {\n                hr = EnsureWicBitmapPixelFormat(pWIC, resized.Get(), filter, colorPixelFormat, resizedColor.GetAddressOf());\n            }\n        }\n    }\n\n    // Resize color+alpha image\n    ComPtr<IWICBitmap> resizedColorWithAlpha;\n    if (SUCCEEDED(hr))\n    {\n        ComPtr<IWICBitmapScaler> colorWithAlphaScaler;\n        hr = pWIC->CreateBitmapScaler(colorWithAlphaScaler.GetAddressOf());\n        if (SUCCEEDED(hr))\n        {\n            ComPtr<IWICBitmap> converted;\n            hr = EnsureWicBitmapPixelFormat(pWIC, original, filter, colorWithAlphaPixelFormat, converted.GetAddressOf());\n            if (SUCCEEDED(hr))\n            {\n                hr = colorWithAlphaScaler->Initialize(converted.Get(), static_cast<UINT>(newWidth), static_cast<UINT>(newHeight), interpolationMode);\n            }\n        }\n\n        if (SUCCEEDED(hr))\n        {\n            ComPtr<IWICBitmap> resized;\n            hr = pWIC->CreateBitmapFromSource(colorWithAlphaScaler.Get(), WICBitmapCacheOnDemand, resized.GetAddressOf());\n            if (SUCCEEDED(hr))\n            {\n                hr = EnsureWicBitmapPixelFormat(pWIC, resized.Get(), filter, colorWithAlphaPixelFormat, resizedColorWithAlpha.GetAddressOf());\n            }\n        }\n    }\n\n    // Merge pixels (copying color channels from color only image to color+alpha image)\n    if (SUCCEEDED(hr))\n    {\n        ComPtr<IWICBitmapLock> colorLock;\n        ComPtr<IWICBitmapLock> colorWithAlphaLock;\n        hr = resizedColor->Lock(nullptr, WICBitmapLockRead, colorLock.GetAddressOf());\n        if (SUCCEEDED(hr))\n        {\n            hr = resizedColorWithAlpha->Lock(nullptr, WICBitmapLockWrite, colorWithAlphaLock.GetAddressOf());\n        }\n\n        if (SUCCEEDED(hr))\n        {\n            BYTE* colorWithAlphaData = nullptr;\n            UINT colorWithAlphaSizeInBytes = 0;\n            UINT colorWithAlphaStride = 0;\n\n            hr = colorWithAlphaLock->GetDataPointer(&colorWithAlphaSizeInBytes, &colorWithAlphaData);\n            if (SUCCEEDED(hr))\n            {\n                if (!colorWithAlphaData)\n                {\n                    hr = E_POINTER;\n                }\n                else\n                {\n                    hr = colorWithAlphaLock->GetStride(&colorWithAlphaStride);\n                }\n            }\n\n            BYTE* colorData = nullptr;\n            UINT colorSizeInBytes = 0;\n            UINT colorStride = 0;\n            if (SUCCEEDED(hr))\n            {\n                hr = colorLock->GetDataPointer(&colorSizeInBytes, &colorData);\n                if (SUCCEEDED(hr))\n                {\n                    if (!colorData)\n                    {\n                        hr = E_POINTER;\n                    }\n                    else\n                    {\n                        hr = colorLock->GetStride(&colorStride);\n                    }\n                }\n            }\n\n            for (size_t j = 0; SUCCEEDED(hr) && j < newHeight; j++)\n            {\n                for (size_t i = 0; SUCCEEDED(hr) && i < newWidth; i++)\n                {\n                    size_t colorWithAlphaIndex = (j * colorWithAlphaStride) + (i * colorWithAlphaBytesPerPixel);\n                    const size_t colorIndex = (j * colorStride) + (i * colorBytesPerPixel);\n\n                    if (((colorWithAlphaIndex + colorBytesInPixel) > colorWithAlphaSizeInBytes)\n                        || ((colorIndex + colorBytesPerPixel) > colorSizeInBytes))\n                    {\n                        hr = E_INVALIDARG;\n                    }\n                    else\n                    {\n                    #pragma warning( suppress : 26014 6386 ) // No overflow possible here\n                        memcpy_s(colorWithAlphaData + colorWithAlphaIndex, colorWithAlphaBytesPerPixel, colorData + colorIndex, colorBytesInPixel);\n                    }\n                }\n            }\n        }\n    }\n\n    if (SUCCEEDED(hr))\n    {\n        if (img->rowPitch > UINT32_MAX || img->slicePitch > UINT32_MAX)\n            return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n        ComPtr<IWICBitmap> wicBitmap;\n        hr = EnsureWicBitmapPixelFormat(pWIC, resizedColorWithAlpha.Get(), filter, desiredPixelFormat, wicBitmap.GetAddressOf());\n        if (SUCCEEDED(hr))\n        {\n            hr = wicBitmap->CopyPixels(nullptr, static_cast<UINT>(img->rowPitch), static_cast<UINT>(img->slicePitch), img->pixels);\n        }\n    }\n\n    return hr;\n}\n#endif // WIN32\n\nnamespace\n{\n#ifdef _WIN32\n    //--- determine when to use WIC vs. non-WIC paths ---\n    bool UseWICFiltering(_In_ DXGI_FORMAT format, _In_ TEX_FILTER_FLAGS filter) noexcept\n    {\n        if (filter & TEX_FILTER_FORCE_NON_WIC)\n        {\n            // Explicit flag indicates use of non-WIC code paths\n            return false;\n        }\n\n        if (filter & TEX_FILTER_FORCE_WIC)\n        {\n            // Explicit flag to use WIC code paths, skips all the case checks below\n            return true;\n        }\n\n        if (IsSRGB(format) || (filter & TEX_FILTER_SRGB))\n        {\n            // Use non-WIC code paths for sRGB correct filtering\n            return false;\n        }\n\n    #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n        if (format == DXGI_FORMAT_R16G16B16A16_FLOAT\n            || format == DXGI_FORMAT_R16_FLOAT)\n        {\n            // Use non-WIC code paths as these conversions are not supported by Xbox version of WIC\n            return false;\n        }\n    #endif\n\n        static_assert(TEX_FILTER_POINT == 0x100000, \"TEX_FILTER_ flag values don't match TEX_FILTER_MODE_MASK\");\n\n        switch (filter & TEX_FILTER_MODE_MASK)\n        {\n        case TEX_FILTER_LINEAR:\n            if (filter & TEX_FILTER_WRAP)\n            {\n                // WIC only supports 'clamp' semantics (MIRROR is equivalent to clamp for linear)\n                return false;\n            }\n\n            if (BitsPerColor(format) > 8)\n            {\n                // Avoid the WIC bitmap scaler when doing Linear filtering of XR/HDR formats\n                return false;\n            }\n            break;\n\n        case TEX_FILTER_CUBIC:\n            if (filter & (TEX_FILTER_WRAP | TEX_FILTER_MIRROR))\n            {\n                // WIC only supports 'clamp' semantics\n                return false;\n            }\n\n            if (BitsPerColor(format) > 8)\n            {\n                // Avoid the WIC bitmap scaler when doing Cubic filtering of XR/HDR formats\n                return false;\n            }\n            break;\n\n        case TEX_FILTER_TRIANGLE:\n            // WIC does not implement this filter\n            return false;\n\n        default:\n            if (BitsPerColor(format) > 8)\n            {\n                // Avoid the WIC bitmap scaler when doing filtering of XR/HDR formats\n                return false;\n            }\n            break;\n        }\n\n        return true;\n    }\n\n\n    //--- mipmap (1D/2D) generation using WIC image scalar ---\n    HRESULT GenerateMipMapsUsingWIC(\n        _In_ const Image& baseImage,\n        _In_ TEX_FILTER_FLAGS filter,\n        _In_ size_t levels,\n        _In_ const WICPixelFormatGUID& pfGUID,\n        _In_ const ScratchImage& mipChain,\n        _In_ size_t item) noexcept\n    {\n        assert(levels > 1);\n\n        if (!baseImage.pixels || !mipChain.GetPixels())\n            return E_POINTER;\n\n        bool iswic2 = false;\n        auto pWIC = GetWICFactory(iswic2);\n        if (!pWIC)\n            return E_NOINTERFACE;\n\n        size_t width = baseImage.width;\n        size_t height = baseImage.height;\n\n        if (baseImage.rowPitch > UINT32_MAX || baseImage.slicePitch > UINT32_MAX)\n            return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n        ComPtr<IWICBitmap> source;\n        HRESULT hr = pWIC->CreateBitmapFromMemory(static_cast<UINT>(width), static_cast<UINT>(height), pfGUID,\n            static_cast<UINT>(baseImage.rowPitch), static_cast<UINT>(baseImage.slicePitch),\n            baseImage.pixels, source.GetAddressOf());\n        if (FAILED(hr))\n            return hr;\n\n        // Copy base image to top miplevel\n        const Image *img0 = mipChain.GetImage(0, item, 0);\n        if (!img0)\n            return E_POINTER;\n\n        uint8_t* pDest = img0->pixels;\n        if (!pDest)\n            return E_POINTER;\n\n        const uint8_t *pSrc = baseImage.pixels;\n        for (size_t h = 0; h < height; ++h)\n        {\n            const size_t msize = std::min<size_t>(img0->rowPitch, baseImage.rowPitch);\n            memcpy_s(pDest, img0->rowPitch, pSrc, msize);\n            pSrc += baseImage.rowPitch;\n            pDest += img0->rowPitch;\n        }\n\n        ComPtr<IWICComponentInfo> componentInfo;\n        hr = pWIC->CreateComponentInfo(pfGUID, componentInfo.GetAddressOf());\n        if (FAILED(hr))\n            return hr;\n\n        ComPtr<IWICPixelFormatInfo2> pixelFormatInfo;\n        hr = componentInfo.As(&pixelFormatInfo);\n        if (FAILED(hr))\n            return hr;\n\n        BOOL supportsTransparency = FALSE;\n        hr = pixelFormatInfo->SupportsTransparency(&supportsTransparency);\n        if (FAILED(hr))\n            return hr;\n\n        // Resize base image to each target mip level\n        for (size_t level = 1; level < levels; ++level)\n        {\n            const Image *img = mipChain.GetImage(level, item, 0);\n            if (!img)\n                return E_POINTER;\n\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n\n            assert(img->width == width && img->height == height && img->format == baseImage.format);\n\n            if ((filter & TEX_FILTER_SEPARATE_ALPHA) && supportsTransparency)\n            {\n                hr = ResizeSeparateColorAndAlpha(pWIC, iswic2, source.Get(), width, height, filter, img);\n                if (FAILED(hr))\n                    return hr;\n            }\n            else\n            {\n                ComPtr<IWICBitmapScaler> scaler;\n                hr = pWIC->CreateBitmapScaler(scaler.GetAddressOf());\n                if (FAILED(hr))\n                    return hr;\n\n                if (img->rowPitch > UINT32_MAX || img->slicePitch > UINT32_MAX)\n                    return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n                hr = scaler->Initialize(source.Get(),\n                    static_cast<UINT>(width), static_cast<UINT>(height),\n                    GetWICInterp(filter));\n                if (FAILED(hr))\n                    return hr;\n\n                WICPixelFormatGUID pfScaler;\n                hr = scaler->GetPixelFormat(&pfScaler);\n                if (FAILED(hr))\n                    return hr;\n\n                if (memcmp(&pfScaler, &pfGUID, sizeof(WICPixelFormatGUID)) == 0)\n                {\n                    hr = scaler->CopyPixels(nullptr, static_cast<UINT>(img->rowPitch), static_cast<UINT>(img->slicePitch), img->pixels);\n                    if (FAILED(hr))\n                        return hr;\n                }\n                else\n                {\n                    // The WIC bitmap scaler is free to return a different pixel format than the source image, so here we\n                    // convert it back\n                    ComPtr<IWICFormatConverter> FC;\n                    hr = pWIC->CreateFormatConverter(FC.GetAddressOf());\n                    if (FAILED(hr))\n                        return hr;\n\n                    BOOL canConvert = FALSE;\n                    hr = FC->CanConvert(pfScaler, pfGUID, &canConvert);\n                    if (FAILED(hr) || !canConvert)\n                    {\n                        return E_UNEXPECTED;\n                    }\n\n                    hr = FC->Initialize(scaler.Get(), pfGUID, GetWICDither(filter), nullptr,\n                        0, WICBitmapPaletteTypeMedianCut);\n                    if (FAILED(hr))\n                        return hr;\n\n                    hr = FC->CopyPixels(nullptr, static_cast<UINT>(img->rowPitch), static_cast<UINT>(img->slicePitch), img->pixels);\n                    if (FAILED(hr))\n                        return hr;\n                }\n            }\n        }\n\n        return S_OK;\n    }\n#endif // WIN32\n\n\n    //-------------------------------------------------------------------------------------\n    // Generate (1D/2D) mip-map helpers (custom filtering)\n    //-------------------------------------------------------------------------------------\n    HRESULT Setup2DMips(\n        _In_reads_(nimages) const Image* baseImages,\n        _In_ size_t nimages,\n        _In_ const TexMetadata& mdata,\n        _Out_ ScratchImage& mipChain) noexcept\n    {\n        if (!baseImages || !nimages)\n            return E_INVALIDARG;\n\n        assert(mdata.mipLevels > 1);\n        assert(mdata.arraySize == nimages);\n        assert(mdata.depth == 1 && mdata.dimension != TEX_DIMENSION_TEXTURE3D);\n        assert(mdata.width == baseImages[0].width);\n        assert(mdata.height == baseImages[0].height);\n        assert(mdata.format == baseImages[0].format);\n\n        HRESULT hr = mipChain.Initialize(mdata);\n        if (FAILED(hr))\n            return hr;\n\n        // Copy base image(s) to top of mip chain\n        for (size_t item = 0; item < nimages; ++item)\n        {\n            const Image& src = baseImages[item];\n\n            const Image *dest = mipChain.GetImage(0, item, 0);\n            if (!dest)\n            {\n                mipChain.Release();\n                return E_POINTER;\n            }\n\n            assert(src.format == dest->format);\n\n            uint8_t* pDest = dest->pixels;\n            if (!pDest)\n            {\n                mipChain.Release();\n                return E_POINTER;\n            }\n\n            const uint8_t *pSrc = src.pixels;\n            const size_t rowPitch = src.rowPitch;\n            for (size_t h = 0; h < mdata.height; ++h)\n            {\n                const size_t msize = std::min<size_t>(dest->rowPitch, rowPitch);\n                memcpy(pDest, pSrc, msize);\n                pSrc += rowPitch;\n                pDest += dest->rowPitch;\n            }\n        }\n\n        return S_OK;\n    }\n\n    //--- 2D Point Filter ---\n    HRESULT Generate2DMipsPointFilter(size_t levels, const ScratchImage& mipChain, size_t item) noexcept\n    {\n        if (!mipChain.GetImages())\n            return E_INVALIDARG;\n\n        // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips)\n\n        assert(levels > 1);\n\n        size_t width = mipChain.GetMetadata().width;\n        size_t height = mipChain.GetMetadata().height;\n\n        // Allocate temporary space (2 scanlines)\n        auto scanline = make_AlignedArrayXMVECTOR(uint64_t(width) * 2);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        XMVECTOR* target = scanline.get();\n\n        XMVECTOR* row = target + width;\n\n        // Resize base image to each target mip level\n        for (size_t level = 1; level < levels; ++level)\n        {\n        #ifdef _DEBUG\n            memset(row, 0xCD, sizeof(XMVECTOR)*width);\n        #endif\n\n            // 2D point filter\n            const Image* src = mipChain.GetImage(level - 1, item, 0);\n            const Image* dest = mipChain.GetImage(level, item, 0);\n\n            if (!src || !dest)\n                return E_POINTER;\n\n            const uint8_t* pSrc = src->pixels;\n            uint8_t* pDest = dest->pixels;\n\n            const size_t rowPitch = src->rowPitch;\n\n            const size_t nwidth = (width > 1) ? (width >> 1) : 1;\n            const size_t nheight = (height > 1) ? (height >> 1) : 1;\n\n            const size_t xinc = (width << 16) / nwidth;\n            const size_t yinc = (height << 16) / nheight;\n\n            size_t lasty = size_t(-1);\n\n            size_t sy = 0;\n            for (size_t y = 0; y < nheight; ++y)\n            {\n                if ((lasty ^ sy) >> 16)\n                {\n                    if (!LoadScanline(row, width, pSrc + (rowPitch * (sy >> 16)), rowPitch, src->format))\n                        return E_FAIL;\n                    lasty = sy;\n                }\n\n                size_t sx = 0;\n                for (size_t x = 0; x < nwidth; ++x)\n                {\n                    target[x] = row[sx >> 16];\n                    sx += xinc;\n                }\n\n                if (!StoreScanline(pDest, dest->rowPitch, dest->format, target, nwidth))\n                    return E_FAIL;\n                pDest += dest->rowPitch;\n\n                sy += yinc;\n            }\n\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n        }\n\n        return S_OK;\n    }\n\n\n    //--- 2D Box Filter ---\n    HRESULT Generate2DMipsBoxFilter(size_t levels, TEX_FILTER_FLAGS filter, const ScratchImage& mipChain, size_t item) noexcept\n    {\n        using namespace DirectX::Filters;\n\n        if (!mipChain.GetImages())\n            return E_INVALIDARG;\n\n        // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips)\n\n        assert(levels > 1);\n\n        size_t width = mipChain.GetMetadata().width;\n        size_t height = mipChain.GetMetadata().height;\n\n        if (!ispow2(width) || !ispow2(height))\n            return E_FAIL;\n\n        // Allocate temporary space (3 scanlines)\n        auto scanline = make_AlignedArrayXMVECTOR(uint64_t(width) * 3);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        XMVECTOR* target = scanline.get();\n\n        XMVECTOR* urow0 = target + width;\n        XMVECTOR* urow1 = target + width * 2;\n\n        const XMVECTOR* urow2 = urow0 + 1;\n        const XMVECTOR* urow3 = urow1 + 1;\n\n        // Resize base image to each target mip level\n        for (size_t level = 1; level < levels; ++level)\n        {\n            if (height <= 1)\n            {\n                urow1 = urow0;\n            }\n\n            if (width <= 1)\n            {\n                urow2 = urow0;\n                urow3 = urow1;\n            }\n\n            // 2D box filter\n            const Image* src = mipChain.GetImage(level - 1, item, 0);\n            const Image* dest = mipChain.GetImage(level, item, 0);\n\n            if (!src || !dest)\n                return E_POINTER;\n\n            const uint8_t* pSrc = src->pixels;\n            uint8_t* pDest = dest->pixels;\n\n            const size_t rowPitch = src->rowPitch;\n\n            const size_t nwidth = (width > 1) ? (width >> 1) : 1;\n            const size_t nheight = (height > 1) ? (height >> 1) : 1;\n\n            for (size_t y = 0; y < nheight; ++y)\n            {\n                if (!LoadScanlineLinear(urow0, width, pSrc, rowPitch, src->format, filter))\n                    return E_FAIL;\n                pSrc += rowPitch;\n\n                if (urow0 != urow1)\n                {\n                    if (!LoadScanlineLinear(urow1, width, pSrc, rowPitch, src->format, filter))\n                        return E_FAIL;\n                    pSrc += rowPitch;\n                }\n\n                for (size_t x = 0; x < nwidth; ++x)\n                {\n                    const size_t x2 = x << 1;\n\n                    AVERAGE4(target[x], urow0[x2], urow1[x2], urow2[x2], urow3[x2])\n                }\n\n                if (!StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter))\n                    return E_FAIL;\n                pDest += dest->rowPitch;\n            }\n\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n        }\n\n        return S_OK;\n    }\n\n\n    //--- 2D Linear Filter ---\n    HRESULT Generate2DMipsLinearFilter(size_t levels, TEX_FILTER_FLAGS filter, const ScratchImage& mipChain, size_t item) noexcept\n    {\n        using namespace DirectX::Filters;\n\n        if (!mipChain.GetImages())\n            return E_INVALIDARG;\n\n        // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips)\n\n        assert(levels > 1);\n\n        size_t width = mipChain.GetMetadata().width;\n        size_t height = mipChain.GetMetadata().height;\n\n        // Allocate temporary space (3 scanlines, plus X and Y filters)\n        auto scanline = make_AlignedArrayXMVECTOR(uint64_t(width) * 3);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        std::unique_ptr<LinearFilter[]> lf(new (std::nothrow) LinearFilter[width + height]);\n        if (!lf)\n            return E_OUTOFMEMORY;\n\n        LinearFilter* lfX = lf.get();\n        LinearFilter* lfY = lf.get() + width;\n\n        XMVECTOR* target = scanline.get();\n\n        XMVECTOR* row0 = target + width;\n        XMVECTOR* row1 = target + width * 2;\n\n        // Resize base image to each target mip level\n        for (size_t level = 1; level < levels; ++level)\n        {\n            // 2D linear filter\n            const Image* src = mipChain.GetImage(level - 1, item, 0);\n            const Image* dest = mipChain.GetImage(level, item, 0);\n\n            if (!src || !dest)\n                return E_POINTER;\n\n            const uint8_t* pSrc = src->pixels;\n            uint8_t* pDest = dest->pixels;\n\n            const size_t rowPitch = src->rowPitch;\n\n            const size_t nwidth = (width > 1) ? (width >> 1) : 1;\n            CreateLinearFilter(width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, lfX);\n\n            const size_t nheight = (height > 1) ? (height >> 1) : 1;\n            CreateLinearFilter(height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, lfY);\n\n        #ifdef _DEBUG\n            memset(row0, 0xCD, sizeof(XMVECTOR)*width);\n            memset(row1, 0xDD, sizeof(XMVECTOR)*width);\n        #endif\n\n            size_t u0 = size_t(-1);\n            size_t u1 = size_t(-1);\n\n            for (size_t y = 0; y < nheight; ++y)\n            {\n                auto const& toY = lfY[y];\n\n                if (toY.u0 != u0)\n                {\n                    if (toY.u0 != u1)\n                    {\n                        u0 = toY.u0;\n\n                        if (!LoadScanlineLinear(row0, width, pSrc + (rowPitch * u0), rowPitch, src->format, filter))\n                            return E_FAIL;\n                    }\n                    else\n                    {\n                        u0 = u1;\n                        u1 = size_t(-1);\n\n                        std::swap(row0, row1);\n                    }\n                }\n\n                if (toY.u1 != u1)\n                {\n                    u1 = toY.u1;\n\n                    if (!LoadScanlineLinear(row1, width, pSrc + (rowPitch * u1), rowPitch, src->format, filter))\n                        return E_FAIL;\n                }\n\n                for (size_t x = 0; x < nwidth; ++x)\n                {\n                    auto const& toX = lfX[x];\n\n                    BILINEAR_INTERPOLATE(target[x], toX, toY, row0, row1)\n                }\n\n                if (!StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter))\n                    return E_FAIL;\n                pDest += dest->rowPitch;\n            }\n\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n        }\n\n        return S_OK;\n    }\n\n    //--- 2D Cubic Filter ---\n#ifdef __clang__\n#pragma clang diagnostic ignored \"-Wextra-semi-stmt\"\n#endif\n\n    HRESULT Generate2DMipsCubicFilter(size_t levels, TEX_FILTER_FLAGS filter, const ScratchImage& mipChain, size_t item) noexcept\n    {\n        using namespace DirectX::Filters;\n\n        if (!mipChain.GetImages())\n            return E_INVALIDARG;\n\n        // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips)\n\n        assert(levels > 1);\n\n        size_t width = mipChain.GetMetadata().width;\n        size_t height = mipChain.GetMetadata().height;\n\n        // Allocate temporary space (5 scanlines, plus X and Y filters)\n        auto scanline = make_AlignedArrayXMVECTOR(uint64_t(width) * 5);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        std::unique_ptr<CubicFilter[]> cf(new (std::nothrow) CubicFilter[width + height]);\n        if (!cf)\n            return E_OUTOFMEMORY;\n\n        CubicFilter* cfX = cf.get();\n        CubicFilter* cfY = cf.get() + width;\n\n        XMVECTOR* target = scanline.get();\n\n        XMVECTOR* row0 = target + width;\n        XMVECTOR* row1 = target + width * 2;\n        XMVECTOR* row2 = target + width * 3;\n        XMVECTOR* row3 = target + width * 4;\n\n        // Resize base image to each target mip level\n        for (size_t level = 1; level < levels; ++level)\n        {\n            // 2D cubic filter\n            const Image* src = mipChain.GetImage(level - 1, item, 0);\n            const Image* dest = mipChain.GetImage(level, item, 0);\n\n            if (!src || !dest)\n                return E_POINTER;\n\n            const uint8_t* pSrc = src->pixels;\n            uint8_t* pDest = dest->pixels;\n\n            const size_t rowPitch = src->rowPitch;\n\n            const size_t nwidth = (width > 1) ? (width >> 1) : 1;\n            CreateCubicFilter(width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, (filter & TEX_FILTER_MIRROR_U) != 0, cfX);\n\n            const size_t nheight = (height > 1) ? (height >> 1) : 1;\n            CreateCubicFilter(height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, (filter & TEX_FILTER_MIRROR_V) != 0, cfY);\n\n        #ifdef _DEBUG\n            memset(row0, 0xCD, sizeof(XMVECTOR)*width);\n            memset(row1, 0xDD, sizeof(XMVECTOR)*width);\n            memset(row2, 0xED, sizeof(XMVECTOR)*width);\n            memset(row3, 0xFD, sizeof(XMVECTOR)*width);\n        #endif\n\n            size_t u0 = size_t(-1);\n            size_t u1 = size_t(-1);\n            size_t u2 = size_t(-1);\n            size_t u3 = size_t(-1);\n\n            for (size_t y = 0; y < nheight; ++y)\n            {\n                auto const& toY = cfY[y];\n\n                // Scanline 1\n                if (toY.u0 != u0)\n                {\n                    if (toY.u0 != u1 && toY.u0 != u2 && toY.u0 != u3)\n                    {\n                        u0 = toY.u0;\n\n                        if (!LoadScanlineLinear(row0, width, pSrc + (rowPitch * u0), rowPitch, src->format, filter))\n                            return E_FAIL;\n                    }\n                    else if (toY.u0 == u1)\n                    {\n                        u0 = u1;\n                        u1 = size_t(-1);\n\n                        std::swap(row0, row1);\n                    }\n                    else if (toY.u0 == u2)\n                    {\n                        u0 = u2;\n                        u2 = size_t(-1);\n\n                        std::swap(row0, row2);\n                    }\n                    else if (toY.u0 == u3)\n                    {\n                        u0 = u3;\n                        u3 = size_t(-1);\n\n                        std::swap(row0, row3);\n                    }\n                }\n\n                // Scanline 2\n                if (toY.u1 != u1)\n                {\n                    if (toY.u1 != u2 && toY.u1 != u3)\n                    {\n                        u1 = toY.u1;\n\n                        if (!LoadScanlineLinear(row1, width, pSrc + (rowPitch * u1), rowPitch, src->format, filter))\n                            return E_FAIL;\n                    }\n                    else if (toY.u1 == u2)\n                    {\n                        u1 = u2;\n                        u2 = size_t(-1);\n\n                        std::swap(row1, row2);\n                    }\n                    else if (toY.u1 == u3)\n                    {\n                        u1 = u3;\n                        u3 = size_t(-1);\n\n                        std::swap(row1, row3);\n                    }\n                }\n\n                // Scanline 3\n                if (toY.u2 != u2)\n                {\n                    if (toY.u2 != u3)\n                    {\n                        u2 = toY.u2;\n\n                        if (!LoadScanlineLinear(row2, width, pSrc + (rowPitch * u2), rowPitch, src->format, filter))\n                            return E_FAIL;\n                    }\n                    else\n                    {\n                        u2 = u3;\n                        u3 = size_t(-1);\n\n                        std::swap(row2, row3);\n                    }\n                }\n\n                // Scanline 4\n                if (toY.u3 != u3)\n                {\n                    u3 = toY.u3;\n\n                    if (!LoadScanlineLinear(row3, width, pSrc + (rowPitch * u3), rowPitch, src->format, filter))\n                        return E_FAIL;\n                }\n\n                for (size_t x = 0; x < nwidth; ++x)\n                {\n                    auto const& toX = cfX[x];\n\n                    XMVECTOR C0, C1, C2, C3;\n\n                    CUBIC_INTERPOLATE(C0, toX.x, row0[toX.u0], row0[toX.u1], row0[toX.u2], row0[toX.u3]);\n                    CUBIC_INTERPOLATE(C1, toX.x, row1[toX.u0], row1[toX.u1], row1[toX.u2], row1[toX.u3]);\n                    CUBIC_INTERPOLATE(C2, toX.x, row2[toX.u0], row2[toX.u1], row2[toX.u2], row2[toX.u3]);\n                    CUBIC_INTERPOLATE(C3, toX.x, row3[toX.u0], row3[toX.u1], row3[toX.u2], row3[toX.u3]);\n\n                    CUBIC_INTERPOLATE(target[x], toY.x, C0, C1, C2, C3);\n                }\n\n                if (!StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter))\n                    return E_FAIL;\n                pDest += dest->rowPitch;\n            }\n\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n        }\n\n        return S_OK;\n    }\n\n\n    //--- 2D Triangle Filter ---\n    HRESULT Generate2DMipsTriangleFilter(size_t levels, TEX_FILTER_FLAGS filter, const ScratchImage& mipChain, size_t item) noexcept\n    {\n        using namespace DirectX::Filters;\n\n        if (!mipChain.GetImages())\n            return E_INVALIDARG;\n\n        // This assumes that the base image is already placed into the mipChain at the top level... (see _Setup2DMips)\n\n        assert(levels > 1);\n\n        size_t width = mipChain.GetMetadata().width;\n        size_t height = mipChain.GetMetadata().height;\n\n        // Allocate initial temporary space (1 scanline, accumulation rows, plus X and Y filters)\n        auto scanline = make_AlignedArrayXMVECTOR(width);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        std::unique_ptr<TriangleRow[]> rowActive(new (std::nothrow) TriangleRow[height]);\n        if (!rowActive)\n            return E_OUTOFMEMORY;\n\n        TriangleRow * rowFree = nullptr;\n\n        std::unique_ptr<Filter> tfX, tfY;\n\n        XMVECTOR* row = scanline.get();\n\n        // Resize base image to each target mip level\n        for (size_t level = 1; level < levels; ++level)\n        {\n            // 2D triangle filter\n            const Image* src = mipChain.GetImage(level - 1, item, 0);\n            const Image* dest = mipChain.GetImage(level, item, 0);\n\n            if (!src || !dest)\n                return E_POINTER;\n\n            const uint8_t* pSrc = src->pixels;\n            const size_t rowPitch = src->rowPitch;\n            const uint8_t* pEndSrc = pSrc + rowPitch * height;\n\n            uint8_t* pDest = dest->pixels;\n\n            const size_t nwidth = (width > 1) ? (width >> 1) : 1;\n            HRESULT hr = CreateTriangleFilter(width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, tfX);\n            if (FAILED(hr))\n                return hr;\n\n            const size_t nheight = (height > 1) ? (height >> 1) : 1;\n            hr = CreateTriangleFilter(height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, tfY);\n            if (FAILED(hr))\n                return hr;\n\n        #ifdef _DEBUG\n            memset(row, 0xCD, sizeof(XMVECTOR)*width);\n        #endif\n\n            auto xFromEnd = reinterpret_cast<const FilterFrom*>(reinterpret_cast<const uint8_t*>(tfX.get()) + tfX->sizeInBytes);\n            auto yFromEnd = reinterpret_cast<const FilterFrom*>(reinterpret_cast<const uint8_t*>(tfY.get()) + tfY->sizeInBytes);\n\n            // Count times rows get written (and clear out any leftover accumulation rows from last miplevel)\n            for (FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; )\n            {\n                for (size_t j = 0; j < yFrom->count; ++j)\n                {\n                    const size_t v = yFrom->to[j].u;\n                    assert(v < nheight);\n                    TriangleRow* rowAcc = &rowActive[v];\n\n                    ++rowAcc->remaining;\n\n                    if (rowAcc->scanline)\n                    {\n                        memset(rowAcc->scanline.get(), 0, sizeof(XMVECTOR) * nwidth);\n                    }\n                }\n\n                yFrom = reinterpret_cast<FilterFrom*>(reinterpret_cast<uint8_t*>(yFrom) + yFrom->sizeInBytes);\n            }\n\n            // Filter image\n            for (FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; )\n            {\n                // Create accumulation rows as needed\n                for (size_t j = 0; j < yFrom->count; ++j)\n                {\n                    const size_t v = yFrom->to[j].u;\n                    assert(v < nheight);\n                    TriangleRow* rowAcc = &rowActive[v];\n\n                    if (!rowAcc->scanline)\n                    {\n                        if (rowFree)\n                        {\n                            // Steal and reuse scanline from 'free row' list\n                            // (it will always be at least as wide as nwidth due to loop decending order)\n                            assert(rowFree->scanline != nullptr);\n                            rowAcc->scanline.reset(rowFree->scanline.release());\n                            rowFree = rowFree->next;\n                        }\n                        else\n                        {\n                            auto nscanline = make_AlignedArrayXMVECTOR(nwidth);\n                            if (!nscanline)\n                                return E_OUTOFMEMORY;\n                            rowAcc->scanline.swap(nscanline);\n                        }\n\n                        memset(rowAcc->scanline.get(), 0, sizeof(XMVECTOR) * nwidth);\n                    }\n                }\n\n                // Load source scanline\n                if ((pSrc + rowPitch) > pEndSrc)\n                    return E_FAIL;\n\n                if (!LoadScanlineLinear(row, width, pSrc, rowPitch, src->format, filter))\n                    return E_FAIL;\n\n                pSrc += rowPitch;\n\n                // Process row\n                size_t x = 0;\n                for (FilterFrom* xFrom = tfX->from; xFrom < xFromEnd; ++x)\n                {\n                    for (size_t j = 0; j < yFrom->count; ++j)\n                    {\n                        const size_t v = yFrom->to[j].u;\n                        assert(v < nheight);\n                        const float yweight = yFrom->to[j].weight;\n\n                        XMVECTOR* accPtr = rowActive[v].scanline.get();\n                        if (!accPtr)\n                            return E_POINTER;\n\n                        for (size_t k = 0; k < xFrom->count; ++k)\n                        {\n                            size_t u = xFrom->to[k].u;\n                            assert(u < nwidth);\n\n                            const XMVECTOR weight = XMVectorReplicate(yweight * xFrom->to[k].weight);\n\n                            assert(x < width);\n                            accPtr[u] = XMVectorMultiplyAdd(row[x], weight, accPtr[u]);\n                        }\n                    }\n\n                    xFrom = reinterpret_cast<FilterFrom*>(reinterpret_cast<uint8_t*>(xFrom) + xFrom->sizeInBytes);\n                }\n\n                // Write completed accumulation rows\n                for (size_t j = 0; j < yFrom->count; ++j)\n                {\n                    size_t v = yFrom->to[j].u;\n                    assert(v < nheight);\n                    TriangleRow* rowAcc = &rowActive[v];\n\n                    assert(rowAcc->remaining > 0);\n                    --rowAcc->remaining;\n\n                    if (!rowAcc->remaining)\n                    {\n                        XMVECTOR* pAccSrc = rowAcc->scanline.get();\n                        if (!pAccSrc)\n                            return E_POINTER;\n\n                        switch (dest->format)\n                        {\n                        case DXGI_FORMAT_R10G10B10A2_UNORM:\n                        case DXGI_FORMAT_R10G10B10A2_UINT:\n                            {\n                                // Need to slightly bias results for floating-point error accumulation which can\n                                // be visible with harshly quantized values\n                                static const XMVECTORF32 Bias = { { { 0.f, 0.f, 0.f, 0.1f } } };\n\n                                XMVECTOR* ptr = pAccSrc;\n                                for (size_t i = 0; i < dest->width; ++i, ++ptr)\n                                {\n                                    *ptr = XMVectorAdd(*ptr, Bias);\n                                }\n                            }\n                            break;\n\n                        default:\n                            break;\n                        }\n\n                        // This performs any required clamping\n                        if (!StoreScanlineLinear(pDest + (dest->rowPitch * v), dest->rowPitch, dest->format, pAccSrc, dest->width, filter))\n                            return E_FAIL;\n\n                        // Put row on freelist to reuse it's allocated scanline\n                        rowAcc->next = rowFree;\n                        rowFree = rowAcc;\n                    }\n                }\n\n                yFrom = reinterpret_cast<FilterFrom*>(reinterpret_cast<uint8_t*>(yFrom) + yFrom->sizeInBytes);\n            }\n\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n        }\n\n        return S_OK;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    // Generate volume mip-map helpers\n    //-------------------------------------------------------------------------------------\n    HRESULT Setup3DMips(\n        _In_reads_(depth) const Image* baseImages,\n        size_t depth,\n        size_t levels,\n        _Out_ ScratchImage& mipChain) noexcept\n    {\n        if (!baseImages || !depth)\n            return E_INVALIDARG;\n\n        assert(levels > 1);\n\n        const size_t width = baseImages[0].width;\n        const size_t height = baseImages[0].height;\n\n        HRESULT hr = mipChain.Initialize3D(baseImages[0].format, width, height, depth, levels);\n        if (FAILED(hr))\n            return hr;\n\n        // Copy base images to top slice\n        for (size_t slice = 0; slice < depth; ++slice)\n        {\n            const Image& src = baseImages[slice];\n\n            const Image *dest = mipChain.GetImage(0, 0, slice);\n            if (!dest)\n            {\n                mipChain.Release();\n                return E_POINTER;\n            }\n\n            assert(src.format == dest->format);\n\n            uint8_t* pDest = dest->pixels;\n            if (!pDest)\n            {\n                mipChain.Release();\n                return E_POINTER;\n            }\n\n            const uint8_t *pSrc = src.pixels;\n            const size_t rowPitch = src.rowPitch;\n            for (size_t h = 0; h < height; ++h)\n            {\n                const size_t msize = std::min<size_t>(dest->rowPitch, rowPitch);\n                memcpy(pDest, pSrc, msize);\n                pSrc += rowPitch;\n                pDest += dest->rowPitch;\n            }\n        }\n\n        return S_OK;\n    }\n\n\n    //--- 3D Point Filter ---\n    HRESULT Generate3DMipsPointFilter(size_t depth, size_t levels, const ScratchImage& mipChain) noexcept\n    {\n        if (!depth || !mipChain.GetImages())\n            return E_INVALIDARG;\n\n        // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips)\n\n        assert(levels > 1);\n\n        size_t width = mipChain.GetMetadata().width;\n        size_t height = mipChain.GetMetadata().height;\n\n        // Allocate temporary space (2 scanlines)\n        auto scanline = make_AlignedArrayXMVECTOR(uint64_t(width) * 2);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        XMVECTOR* target = scanline.get();\n\n        XMVECTOR* row = target + width;\n\n        // Resize base image to each target mip level\n        for (size_t level = 1; level < levels; ++level)\n        {\n        #ifdef _DEBUG\n            memset(row, 0xCD, sizeof(XMVECTOR)*width);\n        #endif\n\n            if (depth > 1)\n            {\n                // 3D point filter\n                const size_t ndepth = depth >> 1;\n\n                const size_t zinc = (depth << 16) / ndepth;\n\n                size_t sz = 0;\n                for (size_t slice = 0; slice < ndepth; ++slice)\n                {\n                    const Image* src = mipChain.GetImage(level - 1, 0, (sz >> 16));\n                    const Image* dest = mipChain.GetImage(level, 0, slice);\n\n                    if (!src || !dest)\n                        return E_POINTER;\n\n                    const uint8_t* pSrc = src->pixels;\n                    uint8_t* pDest = dest->pixels;\n\n                    const size_t rowPitch = src->rowPitch;\n\n                    const size_t nwidth = (width > 1) ? (width >> 1) : 1;\n                    const size_t nheight = (height > 1) ? (height >> 1) : 1;\n\n                    const size_t xinc = (width << 16) / nwidth;\n                    const size_t yinc = (height << 16) / nheight;\n\n                    size_t lasty = size_t(-1);\n\n                    size_t sy = 0;\n                    for (size_t y = 0; y < nheight; ++y)\n                    {\n                        if ((lasty ^ sy) >> 16)\n                        {\n                            if (!LoadScanline(row, width, pSrc + (rowPitch * (sy >> 16)), rowPitch, src->format))\n                                return E_FAIL;\n                            lasty = sy;\n                        }\n\n                        size_t sx = 0;\n                        for (size_t x = 0; x < nwidth; ++x)\n                        {\n                            target[x] = row[sx >> 16];\n                            sx += xinc;\n                        }\n\n                        if (!StoreScanline(pDest, dest->rowPitch, dest->format, target, nwidth))\n                            return E_FAIL;\n                        pDest += dest->rowPitch;\n\n                        sy += yinc;\n                    }\n\n                    sz += zinc;\n                }\n            }\n            else\n            {\n                // 2D point filter\n                const Image* src = mipChain.GetImage(level - 1, 0, 0);\n                const Image* dest = mipChain.GetImage(level, 0, 0);\n\n                if (!src || !dest)\n                    return E_POINTER;\n\n                const uint8_t* pSrc = src->pixels;\n                uint8_t* pDest = dest->pixels;\n\n                const size_t rowPitch = src->rowPitch;\n\n                const size_t nwidth = (width > 1) ? (width >> 1) : 1;\n                const size_t nheight = (height > 1) ? (height >> 1) : 1;\n\n                const size_t xinc = (width << 16) / nwidth;\n                const size_t yinc = (height << 16) / nheight;\n\n                size_t lasty = size_t(-1);\n\n                size_t sy = 0;\n                for (size_t y = 0; y < nheight; ++y)\n                {\n                    if ((lasty ^ sy) >> 16)\n                    {\n                        if (!LoadScanline(row, width, pSrc + (rowPitch * (sy >> 16)), rowPitch, src->format))\n                            return E_FAIL;\n                        lasty = sy;\n                    }\n\n                    size_t sx = 0;\n                    for (size_t x = 0; x < nwidth; ++x)\n                    {\n                        target[x] = row[sx >> 16];\n                        sx += xinc;\n                    }\n\n                    if (!StoreScanline(pDest, dest->rowPitch, dest->format, target, nwidth))\n                        return E_FAIL;\n                    pDest += dest->rowPitch;\n\n                    sy += yinc;\n                }\n            }\n\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n\n            if (depth > 1)\n                depth >>= 1;\n        }\n\n        return S_OK;\n    }\n\n\n    //--- 3D Box Filter ---\n    HRESULT Generate3DMipsBoxFilter(size_t depth, size_t levels, TEX_FILTER_FLAGS filter, const ScratchImage& mipChain) noexcept\n    {\n        using namespace DirectX::Filters;\n\n        if (!depth || !mipChain.GetImages())\n            return E_INVALIDARG;\n\n        // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips)\n\n        assert(levels > 1);\n\n        size_t width = mipChain.GetMetadata().width;\n        size_t height = mipChain.GetMetadata().height;\n\n        if (!ispow2(width) || !ispow2(height) || !ispow2(depth))\n            return E_FAIL;\n\n        // Allocate temporary space (5 scanlines)\n        auto scanline = make_AlignedArrayXMVECTOR(uint64_t(width) * 5);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        XMVECTOR* target = scanline.get();\n\n        XMVECTOR* urow0 = target + width;\n        XMVECTOR* urow1 = target + width * 2;\n        XMVECTOR* vrow0 = target + width * 3;\n        XMVECTOR* vrow1 = target + width * 4;\n\n        const XMVECTOR* urow2 = urow0 + 1;\n        const XMVECTOR* urow3 = urow1 + 1;\n        const XMVECTOR* vrow2 = vrow0 + 1;\n        const XMVECTOR* vrow3 = vrow1 + 1;\n\n        // Resize base image to each target mip level\n        for (size_t level = 1; level < levels; ++level)\n        {\n            if (height <= 1)\n            {\n                urow1 = urow0;\n                vrow1 = vrow0;\n            }\n\n            if (width <= 1)\n            {\n                urow2 = urow0;\n                urow3 = urow1;\n                vrow2 = vrow0;\n                vrow3 = vrow1;\n            }\n\n            if (depth > 1)\n            {\n                // 3D box filter\n                const size_t ndepth = depth >> 1;\n\n                for (size_t slice = 0; slice < ndepth; ++slice)\n                {\n                    const size_t slicea = std::min<size_t>(slice * 2, depth - 1);\n                    const size_t sliceb = std::min<size_t>(slicea + 1, depth - 1);\n\n                    const Image* srca = mipChain.GetImage(level - 1, 0, slicea);\n                    const Image* srcb = mipChain.GetImage(level - 1, 0, sliceb);\n                    const Image* dest = mipChain.GetImage(level, 0, slice);\n\n                    if (!srca || !srcb || !dest)\n                        return E_POINTER;\n\n                    const uint8_t* pSrc1 = srca->pixels;\n                    const uint8_t* pSrc2 = srcb->pixels;\n                    uint8_t* pDest = dest->pixels;\n\n                    const size_t aRowPitch = srca->rowPitch;\n                    const size_t bRowPitch = srcb->rowPitch;\n\n                    const size_t nwidth = (width > 1) ? (width >> 1) : 1;\n                    const size_t nheight = (height > 1) ? (height >> 1) : 1;\n\n                    for (size_t y = 0; y < nheight; ++y)\n                    {\n                        if (!LoadScanlineLinear(urow0, width, pSrc1, aRowPitch, srca->format, filter))\n                            return E_FAIL;\n                        pSrc1 += aRowPitch;\n\n                        if (urow0 != urow1)\n                        {\n                            if (!LoadScanlineLinear(urow1, width, pSrc1, aRowPitch, srca->format, filter))\n                                return E_FAIL;\n                            pSrc1 += aRowPitch;\n                        }\n\n                        if (!LoadScanlineLinear(vrow0, width, pSrc2, bRowPitch, srcb->format, filter))\n                            return E_FAIL;\n                        pSrc2 += bRowPitch;\n\n                        if (vrow0 != vrow1)\n                        {\n                            if (!LoadScanlineLinear(vrow1, width, pSrc2, bRowPitch, srcb->format, filter))\n                                return E_FAIL;\n                            pSrc2 += bRowPitch;\n                        }\n\n                        for (size_t x = 0; x < nwidth; ++x)\n                        {\n                            const size_t x2 = x << 1;\n\n                            AVERAGE8(target[x], urow0[x2], urow1[x2], urow2[x2], urow3[x2],\n                                vrow0[x2], vrow1[x2], vrow2[x2], vrow3[x2])\n                        }\n\n                        if (!StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter))\n                            return E_FAIL;\n                        pDest += dest->rowPitch;\n                    }\n                }\n            }\n            else\n            {\n                // 2D box filter\n                const Image* src = mipChain.GetImage(level - 1, 0, 0);\n                const Image* dest = mipChain.GetImage(level, 0, 0);\n\n                if (!src || !dest)\n                    return E_POINTER;\n\n                const uint8_t* pSrc = src->pixels;\n                uint8_t* pDest = dest->pixels;\n\n                const size_t rowPitch = src->rowPitch;\n\n                const size_t nwidth = (width > 1) ? (width >> 1) : 1;\n                const size_t nheight = (height > 1) ? (height >> 1) : 1;\n\n                for (size_t y = 0; y < nheight; ++y)\n                {\n                    if (!LoadScanlineLinear(urow0, width, pSrc, rowPitch, src->format, filter))\n                        return E_FAIL;\n                    pSrc += rowPitch;\n\n                    if (urow0 != urow1)\n                    {\n                        if (!LoadScanlineLinear(urow1, width, pSrc, rowPitch, src->format, filter))\n                            return E_FAIL;\n                        pSrc += rowPitch;\n                    }\n\n                    for (size_t x = 0; x < nwidth; ++x)\n                    {\n                        const size_t x2 = x << 1;\n\n                        AVERAGE4(target[x], urow0[x2], urow1[x2], urow2[x2], urow3[x2])\n                    }\n\n                    if (!StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter))\n                        return E_FAIL;\n                    pDest += dest->rowPitch;\n                }\n            }\n\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n\n            if (depth > 1)\n                depth >>= 1;\n        }\n\n        return S_OK;\n    }\n\n\n    //--- 3D Linear Filter ---\n    HRESULT Generate3DMipsLinearFilter(size_t depth, size_t levels, TEX_FILTER_FLAGS filter, const ScratchImage& mipChain) noexcept\n    {\n        using namespace DirectX::Filters;\n\n        if (!depth || !mipChain.GetImages())\n            return E_INVALIDARG;\n\n        // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips)\n\n        assert(levels > 1);\n\n        size_t width = mipChain.GetMetadata().width;\n        size_t height = mipChain.GetMetadata().height;\n\n        // Allocate temporary space (5 scanlines, plus X/Y/Z filters)\n        auto scanline = make_AlignedArrayXMVECTOR(uint64_t(width) * 5);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        std::unique_ptr<LinearFilter[]> lf(new (std::nothrow) LinearFilter[width + height + depth]);\n        if (!lf)\n            return E_OUTOFMEMORY;\n\n        LinearFilter* lfX = lf.get();\n        LinearFilter* lfY = lf.get() + width;\n        LinearFilter* lfZ = lf.get() + width + height;\n\n        XMVECTOR* target = scanline.get();\n\n        XMVECTOR* urow0 = target + width;\n        XMVECTOR* urow1 = target + width * 2;\n        XMVECTOR* vrow0 = target + width * 3;\n        XMVECTOR* vrow1 = target + width * 4;\n\n        // Resize base image to each target mip level\n        for (size_t level = 1; level < levels; ++level)\n        {\n            const size_t nwidth = (width > 1) ? (width >> 1) : 1;\n            CreateLinearFilter(width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, lfX);\n\n            const size_t nheight = (height > 1) ? (height >> 1) : 1;\n            CreateLinearFilter(height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, lfY);\n\n        #ifdef _DEBUG\n            memset(urow0, 0xCD, sizeof(XMVECTOR)*width);\n            memset(urow1, 0xDD, sizeof(XMVECTOR)*width);\n            memset(vrow0, 0xED, sizeof(XMVECTOR)*width);\n            memset(vrow1, 0xFD, sizeof(XMVECTOR)*width);\n        #endif\n\n            if (depth > 1)\n            {\n                // 3D linear filter\n                const size_t ndepth = depth >> 1;\n                CreateLinearFilter(depth, ndepth, (filter & TEX_FILTER_WRAP_W) != 0, lfZ);\n\n                for (size_t slice = 0; slice < ndepth; ++slice)\n                {\n                    auto const& toZ = lfZ[slice];\n\n                    const Image* srca = mipChain.GetImage(level - 1, 0, toZ.u0);\n                    const Image* srcb = mipChain.GetImage(level - 1, 0, toZ.u1);\n                    if (!srca || !srcb)\n                        return E_POINTER;\n\n                    size_t u0 = size_t(-1);\n                    size_t u1 = size_t(-1);\n\n                    const Image* dest = mipChain.GetImage(level, 0, slice);\n                    if (!dest)\n                        return E_POINTER;\n\n                    uint8_t* pDest = dest->pixels;\n\n                    for (size_t y = 0; y < nheight; ++y)\n                    {\n                        auto const& toY = lfY[y];\n\n                        if (toY.u0 != u0)\n                        {\n                            if (toY.u0 != u1)\n                            {\n                                u0 = toY.u0;\n\n                                if (!LoadScanlineLinear(urow0, width, srca->pixels + (srca->rowPitch * u0), srca->rowPitch, srca->format, filter)\n                                    || !LoadScanlineLinear(vrow0, width, srcb->pixels + (srcb->rowPitch * u0), srcb->rowPitch, srcb->format, filter))\n                                    return E_FAIL;\n                            }\n                            else\n                            {\n                                u0 = u1;\n                                u1 = size_t(-1);\n\n                                std::swap(urow0, urow1);\n                                std::swap(vrow0, vrow1);\n                            }\n                        }\n\n                        if (toY.u1 != u1)\n                        {\n                            u1 = toY.u1;\n\n                            if (!LoadScanlineLinear(urow1, width, srca->pixels + (srca->rowPitch * u1), srca->rowPitch, srca->format, filter)\n                                || !LoadScanlineLinear(vrow1, width, srcb->pixels + (srcb->rowPitch * u1), srcb->rowPitch, srcb->format, filter))\n                                return E_FAIL;\n                        }\n\n                        for (size_t x = 0; x < nwidth; ++x)\n                        {\n                            auto const& toX = lfX[x];\n\n                            TRILINEAR_INTERPOLATE(target[x], toX, toY, toZ, urow0, urow1, vrow0, vrow1)\n                        }\n\n                        if (!StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter))\n                            return E_FAIL;\n                        pDest += dest->rowPitch;\n                    }\n                }\n            }\n            else\n            {\n                // 2D linear filter\n                const Image* src = mipChain.GetImage(level - 1, 0, 0);\n                const Image* dest = mipChain.GetImage(level, 0, 0);\n\n                if (!src || !dest)\n                    return E_POINTER;\n\n                const uint8_t* pSrc = src->pixels;\n                uint8_t* pDest = dest->pixels;\n\n                const size_t rowPitch = src->rowPitch;\n\n                size_t u0 = size_t(-1);\n                size_t u1 = size_t(-1);\n\n                for (size_t y = 0; y < nheight; ++y)\n                {\n                    auto const& toY = lfY[y];\n\n                    if (toY.u0 != u0)\n                    {\n                        if (toY.u0 != u1)\n                        {\n                            u0 = toY.u0;\n\n                            if (!LoadScanlineLinear(urow0, width, pSrc + (rowPitch * u0), rowPitch, src->format, filter))\n                                return E_FAIL;\n                        }\n                        else\n                        {\n                            u0 = u1;\n                            u1 = size_t(-1);\n\n                            std::swap(urow0, urow1);\n                        }\n                    }\n\n                    if (toY.u1 != u1)\n                    {\n                        u1 = toY.u1;\n\n                        if (!LoadScanlineLinear(urow1, width, pSrc + (rowPitch * u1), rowPitch, src->format, filter))\n                            return E_FAIL;\n                    }\n\n                    for (size_t x = 0; x < nwidth; ++x)\n                    {\n                        auto const& toX = lfX[x];\n\n                        BILINEAR_INTERPOLATE(target[x], toX, toY, urow0, urow1)\n                    }\n\n                    if (!StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter))\n                        return E_FAIL;\n                    pDest += dest->rowPitch;\n                }\n            }\n\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n\n            if (depth > 1)\n                depth >>= 1;\n        }\n\n        return S_OK;\n    }\n\n\n    //--- 3D Cubic Filter ---\n    HRESULT Generate3DMipsCubicFilter(size_t depth, size_t levels, TEX_FILTER_FLAGS filter, const ScratchImage& mipChain) noexcept\n    {\n        using namespace DirectX::Filters;\n\n        if (!depth || !mipChain.GetImages())\n            return E_INVALIDARG;\n\n        // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips)\n\n        assert(levels > 1);\n\n        size_t width = mipChain.GetMetadata().width;\n        size_t height = mipChain.GetMetadata().height;\n\n        // Allocate temporary space (17 scanlines, plus X/Y/Z filters)\n        auto scanline = make_AlignedArrayXMVECTOR(uint64_t(width) * 17);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        std::unique_ptr<CubicFilter[]> cf(new (std::nothrow) CubicFilter[width + height + depth]);\n        if (!cf)\n            return E_OUTOFMEMORY;\n\n        CubicFilter* cfX = cf.get();\n        CubicFilter* cfY = cf.get() + width;\n        CubicFilter* cfZ = cf.get() + width + height;\n\n        XMVECTOR* target = scanline.get();\n\n        XMVECTOR* urow[4];\n        XMVECTOR* vrow[4];\n        XMVECTOR* srow[4];\n        XMVECTOR* trow[4];\n\n        XMVECTOR *ptr = scanline.get() + width;\n        for (size_t j = 0; j < 4; ++j)\n        {\n            urow[j] = ptr;  ptr += width;\n            vrow[j] = ptr;  ptr += width;\n            srow[j] = ptr;  ptr += width;\n            trow[j] = ptr;  ptr += width;\n        }\n\n        // Resize base image to each target mip level\n        for (size_t level = 1; level < levels; ++level)\n        {\n            const size_t nwidth = (width > 1) ? (width >> 1) : 1;\n            CreateCubicFilter(width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, (filter & TEX_FILTER_MIRROR_U) != 0, cfX);\n\n            const size_t nheight = (height > 1) ? (height >> 1) : 1;\n            CreateCubicFilter(height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, (filter & TEX_FILTER_MIRROR_V) != 0, cfY);\n\n        #ifdef _DEBUG\n            for (size_t j = 0; j < 4; ++j)\n            {\n                memset(urow[j], 0xCD, sizeof(XMVECTOR)*width);\n                memset(vrow[j], 0xDD, sizeof(XMVECTOR)*width);\n                memset(srow[j], 0xED, sizeof(XMVECTOR)*width);\n                memset(trow[j], 0xFD, sizeof(XMVECTOR)*width);\n            }\n        #endif\n\n            if (depth > 1)\n            {\n                // 3D cubic filter\n                const size_t ndepth = depth >> 1;\n                CreateCubicFilter(depth, ndepth, (filter & TEX_FILTER_WRAP_W) != 0, (filter & TEX_FILTER_MIRROR_W) != 0, cfZ);\n\n                for (size_t slice = 0; slice < ndepth; ++slice)\n                {\n                    auto const& toZ = cfZ[slice];\n\n                    const Image* srca = mipChain.GetImage(level - 1, 0, toZ.u0);\n                    const Image* srcb = mipChain.GetImage(level - 1, 0, toZ.u1);\n                    const Image* srcc = mipChain.GetImage(level - 1, 0, toZ.u2);\n                    const Image* srcd = mipChain.GetImage(level - 1, 0, toZ.u3);\n                    if (!srca || !srcb || !srcc || !srcd)\n                        return E_POINTER;\n\n                    size_t u0 = size_t(-1);\n                    size_t u1 = size_t(-1);\n                    size_t u2 = size_t(-1);\n                    size_t u3 = size_t(-1);\n\n                    const Image* dest = mipChain.GetImage(level, 0, slice);\n                    if (!dest)\n                        return E_POINTER;\n\n                    uint8_t* pDest = dest->pixels;\n\n                    for (size_t y = 0; y < nheight; ++y)\n                    {\n                        auto const& toY = cfY[y];\n\n                        // Scanline 1\n                        if (toY.u0 != u0)\n                        {\n                            if (toY.u0 != u1 && toY.u0 != u2 && toY.u0 != u3)\n                            {\n                                u0 = toY.u0;\n\n                                if (!LoadScanlineLinear(urow[0], width, srca->pixels + (srca->rowPitch * u0), srca->rowPitch, srca->format, filter)\n                                    || !LoadScanlineLinear(urow[1], width, srcb->pixels + (srcb->rowPitch * u0), srcb->rowPitch, srcb->format, filter)\n                                    || !LoadScanlineLinear(urow[2], width, srcc->pixels + (srcc->rowPitch * u0), srcc->rowPitch, srcc->format, filter)\n                                    || !LoadScanlineLinear(urow[3], width, srcd->pixels + (srcd->rowPitch * u0), srcd->rowPitch, srcd->format, filter))\n                                    return E_FAIL;\n                            }\n                            else if (toY.u0 == u1)\n                            {\n                                u0 = u1;\n                                u1 = size_t(-1);\n\n                                std::swap(urow[0], vrow[0]);\n                                std::swap(urow[1], vrow[1]);\n                                std::swap(urow[2], vrow[2]);\n                                std::swap(urow[3], vrow[3]);\n                            }\n                            else if (toY.u0 == u2)\n                            {\n                                u0 = u2;\n                                u2 = size_t(-1);\n\n                                std::swap(urow[0], srow[0]);\n                                std::swap(urow[1], srow[1]);\n                                std::swap(urow[2], srow[2]);\n                                std::swap(urow[3], srow[3]);\n                            }\n                            else if (toY.u0 == u3)\n                            {\n                                u0 = u3;\n                                u3 = size_t(-1);\n\n                                std::swap(urow[0], trow[0]);\n                                std::swap(urow[1], trow[1]);\n                                std::swap(urow[2], trow[2]);\n                                std::swap(urow[3], trow[3]);\n                            }\n                        }\n\n                        // Scanline 2\n                        if (toY.u1 != u1)\n                        {\n                            if (toY.u1 != u2 && toY.u1 != u3)\n                            {\n                                u1 = toY.u1;\n\n                                if (!LoadScanlineLinear(vrow[0], width, srca->pixels + (srca->rowPitch * u1), srca->rowPitch, srca->format, filter)\n                                    || !LoadScanlineLinear(vrow[1], width, srcb->pixels + (srcb->rowPitch * u1), srcb->rowPitch, srcb->format, filter)\n                                    || !LoadScanlineLinear(vrow[2], width, srcc->pixels + (srcc->rowPitch * u1), srcc->rowPitch, srcc->format, filter)\n                                    || !LoadScanlineLinear(vrow[3], width, srcd->pixels + (srcd->rowPitch * u1), srcd->rowPitch, srcd->format, filter))\n                                    return E_FAIL;\n                            }\n                            else if (toY.u1 == u2)\n                            {\n                                u1 = u2;\n                                u2 = size_t(-1);\n\n                                std::swap(vrow[0], srow[0]);\n                                std::swap(vrow[1], srow[1]);\n                                std::swap(vrow[2], srow[2]);\n                                std::swap(vrow[3], srow[3]);\n                            }\n                            else if (toY.u1 == u3)\n                            {\n                                u1 = u3;\n                                u3 = size_t(-1);\n\n                                std::swap(vrow[0], trow[0]);\n                                std::swap(vrow[1], trow[1]);\n                                std::swap(vrow[2], trow[2]);\n                                std::swap(vrow[3], trow[3]);\n                            }\n                        }\n\n                        // Scanline 3\n                        if (toY.u2 != u2)\n                        {\n                            if (toY.u2 != u3)\n                            {\n                                u2 = toY.u2;\n\n                                if (!LoadScanlineLinear(srow[0], width, srca->pixels + (srca->rowPitch * u2), srca->rowPitch, srca->format, filter)\n                                    || !LoadScanlineLinear(srow[1], width, srcb->pixels + (srcb->rowPitch * u2), srcb->rowPitch, srcb->format, filter)\n                                    || !LoadScanlineLinear(srow[2], width, srcc->pixels + (srcc->rowPitch * u2), srcc->rowPitch, srcc->format, filter)\n                                    || !LoadScanlineLinear(srow[3], width, srcd->pixels + (srcd->rowPitch * u2), srcd->rowPitch, srcd->format, filter))\n                                    return E_FAIL;\n                            }\n                            else\n                            {\n                                u2 = u3;\n                                u3 = size_t(-1);\n\n                                std::swap(srow[0], trow[0]);\n                                std::swap(srow[1], trow[1]);\n                                std::swap(srow[2], trow[2]);\n                                std::swap(srow[3], trow[3]);\n                            }\n                        }\n\n                        // Scanline 4\n                        if (toY.u3 != u3)\n                        {\n                            u3 = toY.u3;\n\n                            if (!LoadScanlineLinear(trow[0], width, srca->pixels + (srca->rowPitch * u3), srca->rowPitch, srca->format, filter)\n                                || !LoadScanlineLinear(trow[1], width, srcb->pixels + (srcb->rowPitch * u3), srcb->rowPitch, srcb->format, filter)\n                                || !LoadScanlineLinear(trow[2], width, srcc->pixels + (srcc->rowPitch * u3), srcc->rowPitch, srcc->format, filter)\n                                || !LoadScanlineLinear(trow[3], width, srcd->pixels + (srcd->rowPitch * u3), srcd->rowPitch, srcd->format, filter))\n                                return E_FAIL;\n                        }\n\n                        for (size_t x = 0; x < nwidth; ++x)\n                        {\n                            auto const& toX = cfX[x];\n\n                            XMVECTOR D[4];\n\n                            for (size_t j = 0; j < 4; ++j)\n                            {\n                                XMVECTOR C0, C1, C2, C3;\n                                CUBIC_INTERPOLATE(C0, toX.x, urow[j][toX.u0], urow[j][toX.u1], urow[j][toX.u2], urow[j][toX.u3]);\n                                CUBIC_INTERPOLATE(C1, toX.x, vrow[j][toX.u0], vrow[j][toX.u1], vrow[j][toX.u2], vrow[j][toX.u3]);\n                                CUBIC_INTERPOLATE(C2, toX.x, srow[j][toX.u0], srow[j][toX.u1], srow[j][toX.u2], srow[j][toX.u3]);\n                                CUBIC_INTERPOLATE(C3, toX.x, trow[j][toX.u0], trow[j][toX.u1], trow[j][toX.u2], trow[j][toX.u3]);\n\n                                CUBIC_INTERPOLATE(D[j], toY.x, C0, C1, C2, C3);\n                            }\n\n                            CUBIC_INTERPOLATE(target[x], toZ.x, D[0], D[1], D[2], D[3]);\n                        }\n\n                        if (!StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter))\n                            return E_FAIL;\n                        pDest += dest->rowPitch;\n                    }\n                }\n            }\n            else\n            {\n                // 2D cubic filter\n                const Image* src = mipChain.GetImage(level - 1, 0, 0);\n                const Image* dest = mipChain.GetImage(level, 0, 0);\n\n                if (!src || !dest)\n                    return E_POINTER;\n\n                const uint8_t* pSrc = src->pixels;\n                uint8_t* pDest = dest->pixels;\n\n                const size_t rowPitch = src->rowPitch;\n\n                size_t u0 = size_t(-1);\n                size_t u1 = size_t(-1);\n                size_t u2 = size_t(-1);\n                size_t u3 = size_t(-1);\n\n                for (size_t y = 0; y < nheight; ++y)\n                {\n                    auto const& toY = cfY[y];\n\n                    // Scanline 1\n                    if (toY.u0 != u0)\n                    {\n                        if (toY.u0 != u1 && toY.u0 != u2 && toY.u0 != u3)\n                        {\n                            u0 = toY.u0;\n\n                            if (!LoadScanlineLinear(urow[0], width, pSrc + (rowPitch * u0), rowPitch, src->format, filter))\n                                return E_FAIL;\n                        }\n                        else if (toY.u0 == u1)\n                        {\n                            u0 = u1;\n                            u1 = size_t(-1);\n\n                            std::swap(urow[0], vrow[0]);\n                        }\n                        else if (toY.u0 == u2)\n                        {\n                            u0 = u2;\n                            u2 = size_t(-1);\n\n                            std::swap(urow[0], srow[0]);\n                        }\n                        else if (toY.u0 == u3)\n                        {\n                            u0 = u3;\n                            u3 = size_t(-1);\n\n                            std::swap(urow[0], trow[0]);\n                        }\n                    }\n\n                    // Scanline 2\n                    if (toY.u1 != u1)\n                    {\n                        if (toY.u1 != u2 && toY.u1 != u3)\n                        {\n                            u1 = toY.u1;\n\n                            if (!LoadScanlineLinear(vrow[0], width, pSrc + (rowPitch * u1), rowPitch, src->format, filter))\n                                return E_FAIL;\n                        }\n                        else if (toY.u1 == u2)\n                        {\n                            u1 = u2;\n                            u2 = size_t(-1);\n\n                            std::swap(vrow[0], srow[0]);\n                        }\n                        else if (toY.u1 == u3)\n                        {\n                            u1 = u3;\n                            u3 = size_t(-1);\n\n                            std::swap(vrow[0], trow[0]);\n                        }\n                    }\n\n                    // Scanline 3\n                    if (toY.u2 != u2)\n                    {\n                        if (toY.u2 != u3)\n                        {\n                            u2 = toY.u2;\n\n                            if (!LoadScanlineLinear(srow[0], width, pSrc + (rowPitch * u2), rowPitch, src->format, filter))\n                                return E_FAIL;\n                        }\n                        else\n                        {\n                            u2 = u3;\n                            u3 = size_t(-1);\n\n                            std::swap(srow[0], trow[0]);\n                        }\n                    }\n\n                    // Scanline 4\n                    if (toY.u3 != u3)\n                    {\n                        u3 = toY.u3;\n\n                        if (!LoadScanlineLinear(trow[0], width, pSrc + (rowPitch * u3), rowPitch, src->format, filter))\n                            return E_FAIL;\n                    }\n\n                    for (size_t x = 0; x < nwidth; ++x)\n                    {\n                        auto const& toX = cfX[x];\n\n                        XMVECTOR C0, C1, C2, C3;\n                        CUBIC_INTERPOLATE(C0, toX.x, urow[0][toX.u0], urow[0][toX.u1], urow[0][toX.u2], urow[0][toX.u3]);\n                        CUBIC_INTERPOLATE(C1, toX.x, vrow[0][toX.u0], vrow[0][toX.u1], vrow[0][toX.u2], vrow[0][toX.u3]);\n                        CUBIC_INTERPOLATE(C2, toX.x, srow[0][toX.u0], srow[0][toX.u1], srow[0][toX.u2], srow[0][toX.u3]);\n                        CUBIC_INTERPOLATE(C3, toX.x, trow[0][toX.u0], trow[0][toX.u1], trow[0][toX.u2], trow[0][toX.u3]);\n\n                        CUBIC_INTERPOLATE(target[x], toY.x, C0, C1, C2, C3);\n                    }\n\n                    if (!StoreScanlineLinear(pDest, dest->rowPitch, dest->format, target, nwidth, filter))\n                        return E_FAIL;\n                    pDest += dest->rowPitch;\n                }\n            }\n\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n\n            if (depth > 1)\n                depth >>= 1;\n        }\n\n        return S_OK;\n    }\n\n\n    //--- 3D Triangle Filter ---\n    HRESULT Generate3DMipsTriangleFilter(size_t depth, size_t levels, TEX_FILTER_FLAGS filter, const ScratchImage& mipChain) noexcept\n    {\n        using namespace DirectX::Filters;\n\n        if (!depth || !mipChain.GetImages())\n            return E_INVALIDARG;\n\n        // This assumes that the base images are already placed into the mipChain at the top level... (see _Setup3DMips)\n\n        assert(levels > 1);\n\n        size_t width = mipChain.GetMetadata().width;\n        size_t height = mipChain.GetMetadata().height;\n\n        // Allocate initial temporary space (1 scanline, accumulation rows, plus X/Y/Z filters)\n        auto scanline = make_AlignedArrayXMVECTOR(width);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        std::unique_ptr<TriangleRow[]> sliceActive(new (std::nothrow) TriangleRow[depth]);\n        if (!sliceActive)\n            return E_OUTOFMEMORY;\n\n        TriangleRow * sliceFree = nullptr;\n\n        std::unique_ptr<Filter> tfX, tfY, tfZ;\n\n        XMVECTOR* row = scanline.get();\n\n        // Resize base image to each target mip level\n        for (size_t level = 1; level < levels; ++level)\n        {\n            const size_t nwidth = (width > 1) ? (width >> 1) : 1;\n            HRESULT hr = CreateTriangleFilter(width, nwidth, (filter & TEX_FILTER_WRAP_U) != 0, tfX);\n            if (FAILED(hr))\n                return hr;\n\n            const size_t nheight = (height > 1) ? (height >> 1) : 1;\n            hr = CreateTriangleFilter(height, nheight, (filter & TEX_FILTER_WRAP_V) != 0, tfY);\n            if (FAILED(hr))\n                return hr;\n\n            const size_t ndepth = (depth > 1) ? (depth >> 1) : 1;\n            hr = CreateTriangleFilter(depth, ndepth, (filter & TEX_FILTER_WRAP_W) != 0, tfZ);\n            if (FAILED(hr))\n                return hr;\n\n        #ifdef _DEBUG\n            memset(row, 0xCD, sizeof(XMVECTOR)*width);\n        #endif\n\n            auto xFromEnd = reinterpret_cast<const FilterFrom*>(reinterpret_cast<const uint8_t*>(tfX.get()) + tfX->sizeInBytes);\n            auto yFromEnd = reinterpret_cast<const FilterFrom*>(reinterpret_cast<const uint8_t*>(tfY.get()) + tfY->sizeInBytes);\n            auto zFromEnd = reinterpret_cast<const FilterFrom*>(reinterpret_cast<const uint8_t*>(tfZ.get()) + tfZ->sizeInBytes);\n\n            // Count times slices get written (and clear out any leftover accumulation slices from last miplevel)\n            for (FilterFrom* zFrom = tfZ->from; zFrom < zFromEnd; )\n            {\n                for (size_t j = 0; j < zFrom->count; ++j)\n                {\n                    const size_t w = zFrom->to[j].u;\n                    assert(w < ndepth);\n                    TriangleRow* sliceAcc = &sliceActive[w];\n\n                    ++sliceAcc->remaining;\n\n                    if (sliceAcc->scanline)\n                    {\n                        memset(sliceAcc->scanline.get(), 0, sizeof(XMVECTOR) * nwidth * nheight);\n                    }\n                }\n\n                zFrom = reinterpret_cast<FilterFrom*>(reinterpret_cast<uint8_t*>(zFrom) + zFrom->sizeInBytes);\n            }\n\n            // Filter image\n            size_t z = 0;\n            for (FilterFrom* zFrom = tfZ->from; zFrom < zFromEnd; ++z)\n            {\n                // Create accumulation slices as needed\n                for (size_t j = 0; j < zFrom->count; ++j)\n                {\n                    const size_t w = zFrom->to[j].u;\n                    assert(w < ndepth);\n                    TriangleRow* sliceAcc = &sliceActive[w];\n\n                    if (!sliceAcc->scanline)\n                    {\n                        if (sliceFree)\n                        {\n                            // Steal and reuse scanline from 'free slice' list\n                            // (it will always be at least as large as nwidth*nheight due to loop decending order)\n                            assert(sliceFree->scanline != nullptr);\n                            sliceAcc->scanline.reset(sliceFree->scanline.release());\n                            sliceFree = sliceFree->next;\n                        }\n                        else\n                        {\n                            auto nscanline = make_AlignedArrayXMVECTOR(uint64_t(nwidth) * uint64_t(nheight));\n                            if (!nscanline)\n                                return E_OUTOFMEMORY;\n                            sliceAcc->scanline.swap(nscanline);\n                        }\n\n                        memset(sliceAcc->scanline.get(), 0, sizeof(XMVECTOR) * nwidth * nheight);\n                    }\n                }\n\n                assert(z < depth);\n                const Image* src = mipChain.GetImage(level - 1, 0, z);\n                if (!src)\n                    return E_POINTER;\n\n                const uint8_t* pSrc = src->pixels;\n                const size_t rowPitch = src->rowPitch;\n                const uint8_t* pEndSrc = pSrc + rowPitch * height;\n\n                for (FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; )\n                {\n                    // Load source scanline\n                    if ((pSrc + rowPitch) > pEndSrc)\n                        return E_FAIL;\n\n                    if (!LoadScanlineLinear(row, width, pSrc, rowPitch, src->format, filter))\n                        return E_FAIL;\n\n                    pSrc += rowPitch;\n\n                    // Process row\n                    size_t x = 0;\n                    for (FilterFrom* xFrom = tfX->from; xFrom < xFromEnd; ++x)\n                    {\n                        for (size_t j = 0; j < zFrom->count; ++j)\n                        {\n                            const size_t w = zFrom->to[j].u;\n                            assert(w < ndepth);\n                            const float zweight = zFrom->to[j].weight;\n\n                            XMVECTOR* accSlice = sliceActive[w].scanline.get();\n                            if (!accSlice)\n                                return E_POINTER;\n\n                            for (size_t k = 0; k < yFrom->count; ++k)\n                            {\n                                size_t v = yFrom->to[k].u;\n                                assert(v < nheight);\n                                const float yweight = yFrom->to[k].weight;\n\n                                XMVECTOR * accPtr = accSlice + v * nwidth;\n\n                                for (size_t l = 0; l < xFrom->count; ++l)\n                                {\n                                    size_t u = xFrom->to[l].u;\n                                    assert(u < nwidth);\n\n                                    const XMVECTOR weight = XMVectorReplicate(zweight * yweight * xFrom->to[l].weight);\n\n                                    assert(x < width);\n                                    accPtr[u] = XMVectorMultiplyAdd(row[x], weight, accPtr[u]);\n                                }\n                            }\n                        }\n\n                        xFrom = reinterpret_cast<FilterFrom*>(reinterpret_cast<uint8_t*>(xFrom) + xFrom->sizeInBytes);\n                    }\n\n                    yFrom = reinterpret_cast<FilterFrom*>(reinterpret_cast<uint8_t*>(yFrom) + yFrom->sizeInBytes);\n                }\n\n                // Write completed accumulation slices\n                for (size_t j = 0; j < zFrom->count; ++j)\n                {\n                    const size_t w = zFrom->to[j].u;\n                    assert(w < ndepth);\n                    TriangleRow* sliceAcc = &sliceActive[w];\n\n                    assert(sliceAcc->remaining > 0);\n                    --sliceAcc->remaining;\n\n                    if (!sliceAcc->remaining)\n                    {\n                        const Image* dest = mipChain.GetImage(level, 0, w);\n                        XMVECTOR* pAccSrc = sliceAcc->scanline.get();\n                        if (!dest || !pAccSrc)\n                            return E_POINTER;\n\n                        uint8_t* pDest = dest->pixels;\n\n                        for (size_t h = 0; h < nheight; ++h)\n                        {\n                            switch (dest->format)\n                            {\n                            case DXGI_FORMAT_R10G10B10A2_UNORM:\n                            case DXGI_FORMAT_R10G10B10A2_UINT:\n                                {\n                                    // Need to slightly bias results for floating-point error accumulation which can\n                                    // be visible with harshly quantized values\n                                    static const XMVECTORF32 Bias = { { { 0.f, 0.f, 0.f, 0.1f } } };\n\n                                    XMVECTOR* ptr = pAccSrc;\n                                    for (size_t i = 0; i < dest->width; ++i, ++ptr)\n                                    {\n                                        *ptr = XMVectorAdd(*ptr, Bias);\n                                    }\n                                }\n                                break;\n\n                            default:\n                                break;\n                            }\n\n                            // This performs any required clamping\n                            if (!StoreScanlineLinear(pDest, dest->rowPitch, dest->format, pAccSrc, dest->width, filter))\n                                return E_FAIL;\n\n                            pDest += dest->rowPitch;\n                            pAccSrc += nwidth;\n                        }\n\n                        // Put slice on freelist to reuse it's allocated scanline\n                        sliceAcc->next = sliceFree;\n                        sliceFree = sliceAcc;\n                    }\n                }\n\n                zFrom = reinterpret_cast<FilterFrom*>(reinterpret_cast<uint8_t*>(zFrom) + zFrom->sizeInBytes);\n            }\n\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n\n            if (depth > 1)\n                depth >>= 1;\n        }\n\n        return S_OK;\n    }\n}\n\n\n//=====================================================================================\n// Entry-points\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n// Generate mipmap chain\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::GenerateMipMaps(\n    const Image& baseImage,\n    TEX_FILTER_FLAGS filter,\n    size_t levels,\n    ScratchImage& mipChain,\n    bool allow1D) noexcept\n{\n    if (!IsValid(baseImage.format))\n        return E_INVALIDARG;\n\n    if (!baseImage.pixels)\n        return E_POINTER;\n\n    if (!CalculateMipLevels(baseImage.width, baseImage.height, levels))\n        return E_INVALIDARG;\n\n    if (levels <= 1)\n        return E_INVALIDARG;\n\n    if (IsCompressed(baseImage.format) || IsTypeless(baseImage.format) || IsPlanar(baseImage.format) || IsPalettized(baseImage.format))\n    {\n        return HRESULT_E_NOT_SUPPORTED;\n    }\n\n    HRESULT hr = E_UNEXPECTED;\n\n    static_assert(TEX_FILTER_POINT == 0x100000, \"TEX_FILTER_ flag values don't match TEX_FILTER_MODE_MASK\");\n\n#ifdef _WIN32\n    bool usewic = UseWICFiltering(baseImage.format, filter);\n\n    WICPixelFormatGUID pfGUID = {};\n    const bool wicpf = (usewic) ? DXGIToWIC(baseImage.format, pfGUID, true) : false;\n\n    if (usewic && !wicpf)\n    {\n        // Check to see if the source and/or result size is too big for WIC\n        const uint64_t expandedSize = uint64_t(std::max<size_t>(1, baseImage.width >> 1)) * uint64_t(std::max<size_t>(1, baseImage.height >> 1)) * sizeof(float) * 4;\n        const uint64_t expandedSize2 = uint64_t(baseImage.width) * uint64_t(baseImage.height) * sizeof(float) * 4;\n        if (expandedSize > UINT32_MAX || expandedSize2 > UINT32_MAX)\n        {\n            if (filter & TEX_FILTER_FORCE_WIC)\n                return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n            usewic = false;\n        }\n    }\n\n    if (usewic)\n    {\n        //--- Use WIC filtering to generate mipmaps -----------------------------------\n        switch (filter & TEX_FILTER_MODE_MASK)\n        {\n        case 0:\n        case TEX_FILTER_POINT:\n        case TEX_FILTER_FANT: // Equivalent to Box filter\n        case TEX_FILTER_LINEAR:\n        case TEX_FILTER_CUBIC:\n            {\n                static_assert(TEX_FILTER_FANT == TEX_FILTER_BOX, \"TEX_FILTER_ flag alias mismatch\");\n\n                if (wicpf)\n                {\n                    // Case 1: Base image format is supported by Windows Imaging Component\n                    hr = (baseImage.height > 1 || !allow1D)\n                        ? mipChain.Initialize2D(baseImage.format, baseImage.width, baseImage.height, 1, levels)\n                        : mipChain.Initialize1D(baseImage.format, baseImage.width, 1, levels);\n                    if (FAILED(hr))\n                        return hr;\n\n                    return GenerateMipMapsUsingWIC(baseImage, filter, levels, pfGUID, mipChain, 0);\n                }\n                else\n                {\n                    // Case 2: Base image format is not supported by WIC, so we have to convert, generate, and convert back\n                    assert(baseImage.format != DXGI_FORMAT_R32G32B32A32_FLOAT);\n                    ScratchImage temp;\n                    hr = ConvertToR32G32B32A32(baseImage, temp);\n                    if (FAILED(hr))\n                        return hr;\n\n                    const Image *timg = temp.GetImage(0, 0, 0);\n                    if (!timg)\n                        return E_POINTER;\n\n                    ScratchImage tMipChain;\n                    hr = (baseImage.height > 1 || !allow1D)\n                        ? tMipChain.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, baseImage.width, baseImage.height, 1, levels)\n                        : tMipChain.Initialize1D(DXGI_FORMAT_R32G32B32A32_FLOAT, baseImage.width, 1, levels);\n                    if (FAILED(hr))\n                        return hr;\n\n                    hr = GenerateMipMapsUsingWIC(*timg, filter, levels, GUID_WICPixelFormat128bppRGBAFloat, tMipChain, 0);\n                    if (FAILED(hr))\n                        return hr;\n\n                    temp.Release();\n\n                    return ConvertFromR32G32B32A32(tMipChain.GetImages(), tMipChain.GetImageCount(), tMipChain.GetMetadata(), baseImage.format, mipChain);\n                }\n            }\n\n        default:\n            return HRESULT_E_NOT_SUPPORTED;\n        }\n    }\n    else\n    #endif // WIN32\n    {\n        //--- Use custom filters to generate mipmaps ----------------------------------\n        TexMetadata mdata = {};\n        mdata.width = baseImage.width;\n        if (baseImage.height > 1 || !allow1D)\n        {\n            mdata.height = baseImage.height;\n            mdata.dimension = TEX_DIMENSION_TEXTURE2D;\n        }\n        else\n        {\n            mdata.height = 1;\n            mdata.dimension = TEX_DIMENSION_TEXTURE1D;\n        }\n        mdata.depth = mdata.arraySize = 1;\n        mdata.mipLevels = levels;\n        mdata.format = baseImage.format;\n\n        unsigned long filter_select = (filter & TEX_FILTER_MODE_MASK);\n        if (!filter_select)\n        {\n            // Default filter choice\n            filter_select = (ispow2(baseImage.width) && ispow2(baseImage.height)) ? TEX_FILTER_BOX : TEX_FILTER_LINEAR;\n        }\n\n        switch (filter_select)\n        {\n        case TEX_FILTER_BOX:\n            hr = Setup2DMips(&baseImage, 1, mdata, mipChain);\n            if (FAILED(hr))\n                return hr;\n\n            hr = Generate2DMipsBoxFilter(levels, filter, mipChain, 0);\n            if (FAILED(hr))\n                mipChain.Release();\n            return hr;\n\n        case TEX_FILTER_POINT:\n            hr = Setup2DMips(&baseImage, 1, mdata, mipChain);\n            if (FAILED(hr))\n                return hr;\n\n            hr = Generate2DMipsPointFilter(levels, mipChain, 0);\n            if (FAILED(hr))\n                mipChain.Release();\n            return hr;\n\n        case TEX_FILTER_LINEAR:\n            hr = Setup2DMips(&baseImage, 1, mdata, mipChain);\n            if (FAILED(hr))\n                return hr;\n\n            hr = Generate2DMipsLinearFilter(levels, filter, mipChain, 0);\n            if (FAILED(hr))\n                mipChain.Release();\n            return hr;\n\n        case TEX_FILTER_CUBIC:\n            hr = Setup2DMips(&baseImage, 1, mdata, mipChain);\n            if (FAILED(hr))\n                return hr;\n\n            hr = Generate2DMipsCubicFilter(levels, filter, mipChain, 0);\n            if (FAILED(hr))\n                mipChain.Release();\n            return hr;\n\n        case TEX_FILTER_TRIANGLE:\n            hr = Setup2DMips(&baseImage, 1, mdata, mipChain);\n            if (FAILED(hr))\n                return hr;\n\n            hr = Generate2DMipsTriangleFilter(levels, filter, mipChain, 0);\n            if (FAILED(hr))\n                mipChain.Release();\n            return hr;\n\n        default:\n            return HRESULT_E_NOT_SUPPORTED;\n        }\n    }\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::GenerateMipMaps(\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    TEX_FILTER_FLAGS filter,\n    size_t levels,\n    ScratchImage& mipChain)\n{\n    if (!srcImages || !nimages || !IsValid(metadata.format))\n        return E_INVALIDARG;\n\n    if (metadata.IsVolumemap()\n        || IsCompressed(metadata.format) || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if (!CalculateMipLevels(metadata.width, metadata.height, levels))\n        return E_INVALIDARG;\n\n    if (levels <= 1)\n        return E_INVALIDARG;\n\n    std::vector<Image> baseImages;\n    baseImages.reserve(metadata.arraySize);\n    for (size_t item = 0; item < metadata.arraySize; ++item)\n    {\n        const size_t index = metadata.ComputeIndex(0, item, 0);\n        if (index >= nimages)\n            return E_FAIL;\n\n        const Image& src = srcImages[index];\n        if (!src.pixels)\n            return E_POINTER;\n\n        if (src.format != metadata.format || src.width != metadata.width || src.height != metadata.height)\n        {\n            // All base images must be the same format, width, and height\n            return E_FAIL;\n        }\n\n        baseImages.push_back(src);\n    }\n\n    assert(baseImages.size() == metadata.arraySize);\n\n    HRESULT hr = E_UNEXPECTED;\n\n    if (baseImages.empty())\n        return hr;\n\n    static_assert(TEX_FILTER_POINT == 0x100000, \"TEX_FILTER_ flag values don't match TEX_FILTER_MODE_MASK\");\n\n#ifdef _WIN32\n    bool usewic = !metadata.IsPMAlpha() && UseWICFiltering(metadata.format, filter);\n\n    WICPixelFormatGUID pfGUID = {};\n    const bool wicpf = (usewic) ? DXGIToWIC(metadata.format, pfGUID, true) : false;\n\n    if (usewic && !wicpf)\n    {\n        // Check to see if the source and/or result size is too big for WIC\n        const uint64_t expandedSize = uint64_t(std::max<size_t>(1, metadata.width >> 1)) * uint64_t(std::max<size_t>(1, metadata.height >> 1)) * sizeof(float) * 4;\n        const uint64_t expandedSize2 = uint64_t(metadata.width) * uint64_t(metadata.height) * sizeof(float) * 4;\n        if (expandedSize > UINT32_MAX || expandedSize2 > UINT32_MAX)\n        {\n            if (filter & TEX_FILTER_FORCE_WIC)\n                return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n            usewic = false;\n        }\n    }\n\n    if (usewic)\n    {\n        //--- Use WIC filtering to generate mipmaps -----------------------------------\n        switch (filter & TEX_FILTER_MODE_MASK)\n        {\n        case 0:\n        case TEX_FILTER_POINT:\n        case TEX_FILTER_FANT: // Equivalent to Box filter\n        case TEX_FILTER_LINEAR:\n        case TEX_FILTER_CUBIC:\n            {\n                static_assert(TEX_FILTER_FANT == TEX_FILTER_BOX, \"TEX_FILTER_ flag alias mismatch\");\n\n                if (wicpf)\n                {\n                    // Case 1: Base image format is supported by Windows Imaging Component\n                    TexMetadata mdata2 = metadata;\n                    mdata2.mipLevels = levels;\n                    hr = mipChain.Initialize(mdata2);\n                    if (FAILED(hr))\n                        return hr;\n\n                    for (size_t item = 0; item < metadata.arraySize; ++item)\n                    {\n                        hr = GenerateMipMapsUsingWIC(baseImages[item], filter, levels, pfGUID, mipChain, item);\n                        if (FAILED(hr))\n                        {\n                            mipChain.Release();\n                            return hr;\n                        }\n                    }\n\n                    return S_OK;\n                }\n                else\n                {\n                    // Case 2: Base image format is not supported by WIC, so we have to convert, generate, and convert back\n                    assert(metadata.format != DXGI_FORMAT_R32G32B32A32_FLOAT);\n\n                    TexMetadata mdata2 = metadata;\n                    mdata2.mipLevels = levels;\n                    mdata2.format = DXGI_FORMAT_R32G32B32A32_FLOAT;\n                    ScratchImage tMipChain;\n                    hr = tMipChain.Initialize(mdata2);\n                    if (FAILED(hr))\n                        return hr;\n\n                    for (size_t item = 0; item < metadata.arraySize; ++item)\n                    {\n                        ScratchImage temp;\n                        hr = ConvertToR32G32B32A32(baseImages[item], temp);\n                        if (FAILED(hr))\n                            return hr;\n\n                        const Image *timg = temp.GetImage(0, 0, 0);\n                        if (!timg)\n                            return E_POINTER;\n\n                        hr = GenerateMipMapsUsingWIC(*timg, filter, levels, GUID_WICPixelFormat128bppRGBAFloat, tMipChain, item);\n                        if (FAILED(hr))\n                            return hr;\n                    }\n\n                    return ConvertFromR32G32B32A32(tMipChain.GetImages(), tMipChain.GetImageCount(), tMipChain.GetMetadata(), metadata.format, mipChain);\n                }\n            }\n\n        default:\n            return HRESULT_E_NOT_SUPPORTED;\n        }\n    }\n    else\n    #endif // WIN32\n    {\n        //--- Use custom filters to generate mipmaps ----------------------------------\n        TexMetadata mdata2 = metadata;\n        mdata2.mipLevels = levels;\n\n        unsigned long filter_select = (filter & TEX_FILTER_MODE_MASK);\n        if (!filter_select)\n        {\n            // Default filter choice\n            filter_select = (ispow2(metadata.width) && ispow2(metadata.height)) ? TEX_FILTER_BOX : TEX_FILTER_LINEAR;\n        }\n\n        switch (filter_select)\n        {\n        case TEX_FILTER_BOX:\n            hr = Setup2DMips(&baseImages[0], metadata.arraySize, mdata2, mipChain);\n            if (FAILED(hr))\n                return hr;\n\n            for (size_t item = 0; item < metadata.arraySize; ++item)\n            {\n                hr = Generate2DMipsBoxFilter(levels, filter, mipChain, item);\n                if (FAILED(hr))\n                    mipChain.Release();\n            }\n            return hr;\n\n        case TEX_FILTER_POINT:\n            hr = Setup2DMips(&baseImages[0], metadata.arraySize, mdata2, mipChain);\n            if (FAILED(hr))\n                return hr;\n\n            for (size_t item = 0; item < metadata.arraySize; ++item)\n            {\n                hr = Generate2DMipsPointFilter(levels, mipChain, item);\n                if (FAILED(hr))\n                    mipChain.Release();\n            }\n            return hr;\n\n        case TEX_FILTER_LINEAR:\n            hr = Setup2DMips(&baseImages[0], metadata.arraySize, mdata2, mipChain);\n            if (FAILED(hr))\n                return hr;\n\n            for (size_t item = 0; item < metadata.arraySize; ++item)\n            {\n                hr = Generate2DMipsLinearFilter(levels, filter, mipChain, item);\n                if (FAILED(hr))\n                    mipChain.Release();\n            }\n            return hr;\n\n        case TEX_FILTER_CUBIC:\n            hr = Setup2DMips(&baseImages[0], metadata.arraySize, mdata2, mipChain);\n            if (FAILED(hr))\n                return hr;\n\n            for (size_t item = 0; item < metadata.arraySize; ++item)\n            {\n                hr = Generate2DMipsCubicFilter(levels, filter, mipChain, item);\n                if (FAILED(hr))\n                    mipChain.Release();\n            }\n            return hr;\n\n        case TEX_FILTER_TRIANGLE:\n            hr = Setup2DMips(&baseImages[0], metadata.arraySize, mdata2, mipChain);\n            if (FAILED(hr))\n                return hr;\n\n            for (size_t item = 0; item < metadata.arraySize; ++item)\n            {\n                hr = Generate2DMipsTriangleFilter(levels, filter, mipChain, item);\n                if (FAILED(hr))\n                    mipChain.Release();\n            }\n            return hr;\n\n        default:\n            return HRESULT_E_NOT_SUPPORTED;\n        }\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// Generate mipmap chain for volume texture\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::GenerateMipMaps3D(\n    const Image* baseImages,\n    size_t depth,\n    TEX_FILTER_FLAGS filter,\n    size_t levels,\n    ScratchImage& mipChain) noexcept\n{\n    if (!baseImages || !depth)\n        return E_INVALIDARG;\n\n    if (filter & TEX_FILTER_FORCE_WIC)\n        return HRESULT_E_NOT_SUPPORTED;\n\n    const DXGI_FORMAT format = baseImages[0].format;\n    const size_t width = baseImages[0].width;\n    const size_t height = baseImages[0].height;\n\n    if (!CalculateMipLevels3D(width, height, depth, levels))\n        return E_INVALIDARG;\n\n    if (levels <= 1)\n        return E_INVALIDARG;\n\n    for (size_t slice = 0; slice < depth; ++slice)\n    {\n        if (!baseImages[slice].pixels)\n            return E_POINTER;\n\n        if (baseImages[slice].format != format || baseImages[slice].width != width || baseImages[slice].height != height)\n        {\n            // All base images must be the same format, width, and height\n            return E_FAIL;\n        }\n    }\n\n    if (IsCompressed(format) || IsTypeless(format) || IsPlanar(format) || IsPalettized(format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    static_assert(TEX_FILTER_POINT == 0x100000, \"TEX_FILTER_ flag values don't match TEX_FILTER_MODE_MASK\");\n\n    HRESULT hr = E_UNEXPECTED;\n\n    unsigned long filter_select = (filter & TEX_FILTER_MODE_MASK);\n    if (!filter_select)\n    {\n        // Default filter choice\n        filter_select = (ispow2(width) && ispow2(height) && ispow2(depth)) ? TEX_FILTER_BOX : TEX_FILTER_TRIANGLE;\n    }\n\n    switch (filter_select)\n    {\n    case TEX_FILTER_BOX:\n        hr = Setup3DMips(baseImages, depth, levels, mipChain);\n        if (FAILED(hr))\n            return hr;\n\n        hr = Generate3DMipsBoxFilter(depth, levels, filter, mipChain);\n        if (FAILED(hr))\n            mipChain.Release();\n        return hr;\n\n    case TEX_FILTER_POINT:\n        hr = Setup3DMips(baseImages, depth, levels, mipChain);\n        if (FAILED(hr))\n            return hr;\n\n        hr = Generate3DMipsPointFilter(depth, levels, mipChain);\n        if (FAILED(hr))\n            mipChain.Release();\n        return hr;\n\n    case TEX_FILTER_LINEAR:\n        hr = Setup3DMips(baseImages, depth, levels, mipChain);\n        if (FAILED(hr))\n            return hr;\n\n        hr = Generate3DMipsLinearFilter(depth, levels, filter, mipChain);\n        if (FAILED(hr))\n            mipChain.Release();\n        return hr;\n\n    case TEX_FILTER_CUBIC:\n        hr = Setup3DMips(baseImages, depth, levels, mipChain);\n        if (FAILED(hr))\n            return hr;\n\n        hr = Generate3DMipsCubicFilter(depth, levels, filter, mipChain);\n        if (FAILED(hr))\n            mipChain.Release();\n        return hr;\n\n    case TEX_FILTER_TRIANGLE:\n        hr = Setup3DMips(baseImages, depth, levels, mipChain);\n        if (FAILED(hr))\n            return hr;\n\n        hr = Generate3DMipsTriangleFilter(depth, levels, filter, mipChain);\n        if (FAILED(hr))\n            mipChain.Release();\n        return hr;\n\n    default:\n        return HRESULT_E_NOT_SUPPORTED;\n    }\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::GenerateMipMaps3D(\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    TEX_FILTER_FLAGS filter,\n    size_t levels,\n    ScratchImage& mipChain)\n{\n    if (!srcImages || !nimages || !IsValid(metadata.format))\n        return E_INVALIDARG;\n\n    if (filter & TEX_FILTER_FORCE_WIC)\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if (!metadata.IsVolumemap()\n        || IsCompressed(metadata.format) || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if (!CalculateMipLevels3D(metadata.width, metadata.height, metadata.depth, levels))\n        return E_INVALIDARG;\n\n    if (levels <= 1)\n        return E_INVALIDARG;\n\n    std::vector<Image> baseImages;\n    baseImages.reserve(metadata.depth);\n    for (size_t slice = 0; slice < metadata.depth; ++slice)\n    {\n        const size_t index = metadata.ComputeIndex(0, 0, slice);\n        if (index >= nimages)\n            return E_FAIL;\n\n        const Image& src = srcImages[index];\n        if (!src.pixels)\n            return E_POINTER;\n\n        if (src.format != metadata.format || src.width != metadata.width || src.height != metadata.height)\n        {\n            // All base images must be the same format, width, and height\n            return E_FAIL;\n        }\n\n        baseImages.push_back(src);\n    }\n\n    assert(baseImages.size() == metadata.depth);\n\n    HRESULT hr = E_UNEXPECTED;\n\n    static_assert(TEX_FILTER_POINT == 0x100000, \"TEX_FILTER_ flag values don't match TEX_FILTER_MODE_MASK\");\n\n    unsigned long filter_select = (filter & TEX_FILTER_MODE_MASK);\n    if (!filter_select)\n    {\n        // Default filter choice\n        filter_select = (ispow2(metadata.width) && ispow2(metadata.height) && ispow2(metadata.depth)) ? TEX_FILTER_BOX : TEX_FILTER_TRIANGLE;\n    }\n\n    switch (filter_select)\n    {\n    case TEX_FILTER_BOX:\n        hr = Setup3DMips(&baseImages[0], metadata.depth, levels, mipChain);\n        if (FAILED(hr))\n            return hr;\n\n        hr = Generate3DMipsBoxFilter(metadata.depth, levels, filter, mipChain);\n        if (FAILED(hr))\n            mipChain.Release();\n        return hr;\n\n    case TEX_FILTER_POINT:\n        hr = Setup3DMips(&baseImages[0], metadata.depth, levels, mipChain);\n        if (FAILED(hr))\n            return hr;\n\n        hr = Generate3DMipsPointFilter(metadata.depth, levels, mipChain);\n        if (FAILED(hr))\n            mipChain.Release();\n        return hr;\n\n    case TEX_FILTER_LINEAR:\n        hr = Setup3DMips(&baseImages[0], metadata.depth, levels, mipChain);\n        if (FAILED(hr))\n            return hr;\n\n        hr = Generate3DMipsLinearFilter(metadata.depth, levels, filter, mipChain);\n        if (FAILED(hr))\n            mipChain.Release();\n        return hr;\n\n    case TEX_FILTER_CUBIC:\n        hr = Setup3DMips(&baseImages[0], metadata.depth, levels, mipChain);\n        if (FAILED(hr))\n            return hr;\n\n        hr = Generate3DMipsCubicFilter(metadata.depth, levels, filter, mipChain);\n        if (FAILED(hr))\n            mipChain.Release();\n        return hr;\n\n    case TEX_FILTER_TRIANGLE:\n        hr = Setup3DMips(&baseImages[0], metadata.depth, levels, mipChain);\n        if (FAILED(hr))\n            return hr;\n\n        hr = Generate3DMipsTriangleFilter(metadata.depth, levels, filter, mipChain);\n        if (FAILED(hr))\n            mipChain.Release();\n        return hr;\n\n    default:\n        return HRESULT_E_NOT_SUPPORTED;\n    }\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::ScaleMipMapsAlphaForCoverage(\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    size_t item,\n    float alphaReference,\n    ScratchImage& mipChain) noexcept\n{\n    if (!srcImages || !nimages || !IsValid(metadata.format) || nimages > metadata.mipLevels || !mipChain.GetImages())\n        return E_INVALIDARG;\n\n    if (metadata.IsVolumemap()\n        || IsCompressed(metadata.format) || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if (srcImages[0].format != metadata.format || srcImages[0].width != metadata.width || srcImages[0].height != metadata.height)\n    {\n        // Base image must be the same format, width, and height\n        return E_FAIL;\n    }\n\n    float targetCoverage = 0.0f;\n    HRESULT hr = CalculateAlphaCoverage(srcImages[0], alphaReference, 1.0f, targetCoverage);\n    if (FAILED(hr))\n        return hr;\n\n    // Copy base image\n    {\n        const Image& src = srcImages[0];\n\n        const Image *dest = mipChain.GetImage(0, item, 0);\n        if (!dest)\n            return E_POINTER;\n\n        uint8_t* pDest = dest->pixels;\n        if (!pDest)\n            return E_POINTER;\n\n        const uint8_t *pSrc = src.pixels;\n        const size_t rowPitch = src.rowPitch;\n        for (size_t h = 0; h < metadata.height; ++h)\n        {\n            const size_t msize = std::min<size_t>(dest->rowPitch, rowPitch);\n            memcpy(pDest, pSrc, msize);\n            pSrc += rowPitch;\n            pDest += dest->rowPitch;\n        }\n    }\n\n    for (size_t level = 1; level < metadata.mipLevels; ++level)\n    {\n        if (level >= nimages)\n            return E_FAIL;\n\n        float alphaScale = 0.0f;\n        hr = EstimateAlphaScaleForCoverage(srcImages[level], alphaReference, targetCoverage, alphaScale);\n        if (FAILED(hr))\n            return hr;\n\n        const Image* mipImage = mipChain.GetImage(level, item, 0);\n        if (!mipImage)\n            return E_POINTER;\n\n        hr = ScaleAlpha(srcImages[level], alphaScale, *mipImage);\n        if (FAILED(hr))\n            return hr;\n    }\n\n    return S_OK;\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTexMisc.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTexMisc.cpp\n//\n// DirectX Texture Library - Misc image operations\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::Internal;\n\n#ifdef __GNUC__\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wignored-attributes\"\n#endif\n\nnamespace\n{\n    const XMVECTORF32 g_Gamma22 = { { { 2.2f, 2.2f, 2.2f, 1.f } } };\n\n    //-------------------------------------------------------------------------------------\n    HRESULT ComputeMSE_(\n        const Image& image1,\n        const Image& image2,\n        float& mse,\n        _Out_writes_opt_(4) float* mseV,\n        CMSE_FLAGS flags) noexcept\n    {\n        if (!image1.pixels || !image2.pixels)\n            return E_POINTER;\n\n        assert(image1.width == image2.width && image1.height == image2.height);\n        assert(!IsCompressed(image1.format) && !IsCompressed(image2.format));\n\n        const size_t width = image1.width;\n\n        auto scanline = make_AlignedArrayXMVECTOR(uint64_t(width) * 2);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        // Flags implied from image formats\n        switch (image1.format)\n        {\n        case DXGI_FORMAT_B8G8R8X8_UNORM:\n            flags |= CMSE_IGNORE_ALPHA;\n            break;\n\n        case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n            flags |= CMSE_IMAGE1_SRGB | CMSE_IGNORE_ALPHA;\n            break;\n\n        case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n        case DXGI_FORMAT_BC1_UNORM_SRGB:\n        case DXGI_FORMAT_BC2_UNORM_SRGB:\n        case DXGI_FORMAT_BC3_UNORM_SRGB:\n        case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n        case DXGI_FORMAT_BC7_UNORM_SRGB:\n            flags |= CMSE_IMAGE1_SRGB;\n            break;\n\n        default:\n            break;\n        }\n\n        switch (image2.format)\n        {\n        case DXGI_FORMAT_B8G8R8X8_UNORM:\n            flags |= CMSE_IGNORE_ALPHA;\n            break;\n\n        case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n            flags |= CMSE_IMAGE2_SRGB | CMSE_IGNORE_ALPHA;\n            break;\n\n        case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n        case DXGI_FORMAT_BC1_UNORM_SRGB:\n        case DXGI_FORMAT_BC2_UNORM_SRGB:\n        case DXGI_FORMAT_BC3_UNORM_SRGB:\n        case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n        case DXGI_FORMAT_BC7_UNORM_SRGB:\n            flags |= CMSE_IMAGE2_SRGB;\n            break;\n\n        default:\n            break;\n        }\n\n        const uint8_t *pSrc1 = image1.pixels;\n        const size_t rowPitch1 = image1.rowPitch;\n\n        const uint8_t *pSrc2 = image2.pixels;\n        const size_t rowPitch2 = image2.rowPitch;\n\n        XMVECTOR acc = g_XMZero;\n        static XMVECTORF32 two = { { { 2.0f, 2.0f, 2.0f, 2.0f } } };\n\n        for (size_t h = 0; h < image1.height; ++h)\n        {\n            XMVECTOR* ptr1 = scanline.get();\n            if (!LoadScanline(ptr1, width, pSrc1, rowPitch1, image1.format))\n                return E_FAIL;\n\n            XMVECTOR* ptr2 = scanline.get() + width;\n            if (!LoadScanline(ptr2, width, pSrc2, rowPitch2, image2.format))\n                return E_FAIL;\n\n            for (size_t i = 0; i < width; ++i)\n            {\n                XMVECTOR v1 = *(ptr1++);\n                if (flags & CMSE_IMAGE1_SRGB)\n                {\n                    v1 = XMVectorPow(v1, g_Gamma22);\n                }\n                if (flags & CMSE_IMAGE1_X2_BIAS)\n                {\n                    v1 = XMVectorMultiplyAdd(v1, two, g_XMNegativeOne);\n                }\n\n                XMVECTOR v2 = *(ptr2++);\n                if (flags & CMSE_IMAGE2_SRGB)\n                {\n                    v2 = XMVectorPow(v2, g_Gamma22);\n                }\n                if (flags & CMSE_IMAGE2_X2_BIAS)\n                {\n                    v2 = XMVectorMultiplyAdd(v2, two, g_XMNegativeOne);\n                }\n\n                // sum[ (I1 - I2)^2 ]\n                XMVECTOR v = XMVectorSubtract(v1, v2);\n                if (flags & CMSE_IGNORE_RED)\n                {\n                    v = XMVectorSelect(v, g_XMZero, g_XMMaskX);\n                }\n                if (flags & CMSE_IGNORE_GREEN)\n                {\n                    v = XMVectorSelect(v, g_XMZero, g_XMMaskY);\n                }\n                if (flags & CMSE_IGNORE_BLUE)\n                {\n                    v = XMVectorSelect(v, g_XMZero, g_XMMaskZ);\n                }\n                if (flags & CMSE_IGNORE_ALPHA)\n                {\n                    v = XMVectorSelect(v, g_XMZero, g_XMMaskW);\n                }\n\n                acc = XMVectorMultiplyAdd(v, v, acc);\n            }\n\n            pSrc1 += rowPitch1;\n            pSrc2 += rowPitch2;\n        }\n\n        // MSE = sum[ (I1 - I2)^2 ] / w*h\n        const XMVECTOR d = XMVectorReplicate(float(image1.width * image1.height));\n        const XMVECTOR v = XMVectorDivide(acc, d);\n        if (mseV)\n        {\n            XMStoreFloat4(reinterpret_cast<XMFLOAT4*>(mseV), v);\n            mse = mseV[0] + mseV[1] + mseV[2] + mseV[3];\n        }\n        else\n        {\n            XMFLOAT4 _mseV;\n            XMStoreFloat4(&_mseV, v);\n            mse = _mseV.x + _mseV.y + _mseV.z + _mseV.w;\n        }\n\n        return S_OK;\n    }\n\n    //-------------------------------------------------------------------------------------\n    HRESULT EvaluateImage_(\n        const Image& image,\n        const std::function<void __cdecl(_In_reads_(width) const XMVECTOR* pixels, size_t width, size_t y)>& pixelFunc)\n    {\n        if (!pixelFunc)\n            return E_INVALIDARG;\n\n        if (!image.pixels)\n            return E_POINTER;\n\n        assert(!IsCompressed(image.format));\n\n        const size_t width = image.width;\n\n        auto scanline = make_AlignedArrayXMVECTOR(width);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        const uint8_t *pSrc = image.pixels;\n        const size_t rowPitch = image.rowPitch;\n\n        for (size_t h = 0; h < image.height; ++h)\n        {\n            if (!LoadScanline(scanline.get(), width, pSrc, rowPitch, image.format))\n                return E_FAIL;\n\n            pixelFunc(scanline.get(), width, h);\n\n            pSrc += rowPitch;\n        }\n\n        return S_OK;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    HRESULT TransformImage_(\n        const Image& srcImage,\n        const std::function<void __cdecl(_Out_writes_(width) XMVECTOR* outPixels, _In_reads_(width) const XMVECTOR* inPixels, size_t width, size_t y)>& pixelFunc,\n        const Image& destImage)\n    {\n        if (!pixelFunc)\n            return E_INVALIDARG;\n\n        if (!srcImage.pixels || !destImage.pixels)\n            return E_POINTER;\n\n        if (srcImage.width != destImage.width || srcImage.height != destImage.height || srcImage.format != destImage.format)\n            return E_FAIL;\n\n        const size_t width = srcImage.width;\n\n        auto scanlines = make_AlignedArrayXMVECTOR(uint64_t(width) * 2);\n        if (!scanlines)\n            return E_OUTOFMEMORY;\n\n        XMVECTOR* sScanline = scanlines.get();\n        XMVECTOR* dScanline = scanlines.get() + width;\n\n        const uint8_t *pSrc = srcImage.pixels;\n        const size_t spitch = srcImage.rowPitch;\n\n        uint8_t *pDest = destImage.pixels;\n        const size_t dpitch = destImage.rowPitch;\n\n        for (size_t h = 0; h < srcImage.height; ++h)\n        {\n            if (!LoadScanline(sScanline, width, pSrc, spitch, srcImage.format))\n                return E_FAIL;\n\n        #ifdef _DEBUG\n            memset(dScanline, 0xCD, sizeof(XMVECTOR)*width);\n        #endif\n\n            pixelFunc(dScanline, sScanline, width, h);\n\n            if (!StoreScanline(pDest, destImage.rowPitch, destImage.format, dScanline, width))\n                return E_FAIL;\n\n            pSrc += spitch;\n            pDest += dpitch;\n        }\n\n        return S_OK;\n    }\n};\n\n\n//=====================================================================================\n// Entry points\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n// Copies a rectangle from one image into another\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::CopyRectangle(\n    const Image& srcImage,\n    const Rect& srcRect,\n    const Image& dstImage,\n    TEX_FILTER_FLAGS filter,\n    size_t xOffset,\n    size_t yOffset) noexcept\n{\n    if (!srcImage.pixels || !dstImage.pixels)\n        return E_POINTER;\n\n    if (IsCompressed(srcImage.format) || IsCompressed(dstImage.format)\n        || IsPlanar(srcImage.format) || IsPlanar(dstImage.format)\n        || IsPalettized(srcImage.format) || IsPalettized(dstImage.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    // Validate rectangle/offset\n    if (!srcRect.w || !srcRect.h || ((srcRect.x + srcRect.w) > srcImage.width) || ((srcRect.y + srcRect.h) > srcImage.height))\n    {\n        return E_INVALIDARG;\n    }\n\n    if (((xOffset + srcRect.w) > dstImage.width) || ((yOffset + srcRect.h) > dstImage.height))\n    {\n        return E_INVALIDARG;\n    }\n\n    // Compute source bytes-per-pixel\n    size_t sbpp = BitsPerPixel(srcImage.format);\n    if (!sbpp)\n        return E_FAIL;\n\n    if (sbpp < 8)\n    {\n        // We don't support monochrome (DXGI_FORMAT_R1_UNORM)\n        return HRESULT_E_NOT_SUPPORTED;\n    }\n\n    const uint8_t* pEndSrc = srcImage.pixels + srcImage.rowPitch*srcImage.height;\n    const uint8_t* pEndDest = dstImage.pixels + dstImage.rowPitch*dstImage.height;\n\n    // Round to bytes\n    sbpp = (sbpp + 7) / 8;\n\n    const uint8_t* pSrc = srcImage.pixels + (srcRect.y * srcImage.rowPitch) + (srcRect.x * sbpp);\n\n    if (srcImage.format == dstImage.format)\n    {\n        // Direct copy case (avoid intermediate conversions)\n        uint8_t* pDest = dstImage.pixels + (yOffset * dstImage.rowPitch) + (xOffset * sbpp);\n        const size_t copyW = srcRect.w * sbpp;\n        for (size_t h = 0; h < srcRect.h; ++h)\n        {\n            if (((pSrc + copyW) > pEndSrc) || (pDest > pEndDest))\n                return E_FAIL;\n\n            memcpy(pDest, pSrc, copyW);\n\n            pSrc += srcImage.rowPitch;\n            pDest += dstImage.rowPitch;\n        }\n\n        return S_OK;\n    }\n\n    // Compute destination bytes-per-pixel (not the same format as source)\n    size_t dbpp = BitsPerPixel(dstImage.format);\n    if (!dbpp)\n        return E_FAIL;\n\n    if (dbpp < 8)\n    {\n        // We don't support monochrome (DXGI_FORMAT_R1_UNORM)\n        return HRESULT_E_NOT_SUPPORTED;\n    }\n\n    // Round to bytes\n    dbpp = (dbpp + 7) / 8;\n\n    uint8_t* pDest = dstImage.pixels + (yOffset * dstImage.rowPitch) + (xOffset * dbpp);\n\n    auto scanline = make_AlignedArrayXMVECTOR(srcRect.w);\n    if (!scanline)\n        return E_OUTOFMEMORY;\n\n    const size_t copyS = srcRect.w * sbpp;\n    const size_t copyD = srcRect.w * dbpp;\n\n    for (size_t h = 0; h < srcRect.h; ++h)\n    {\n        if (((pSrc + copyS) > pEndSrc) || ((pDest + copyD) > pEndDest))\n            return E_FAIL;\n\n        if (!LoadScanline(scanline.get(), srcRect.w, pSrc, copyS, srcImage.format))\n            return E_FAIL;\n\n        ConvertScanline(scanline.get(), srcRect.w, dstImage.format, srcImage.format, filter);\n\n        if (!StoreScanline(pDest, copyD, dstImage.format, scanline.get(), srcRect.w))\n            return E_FAIL;\n\n        pSrc += srcImage.rowPitch;\n        pDest += dstImage.rowPitch;\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Computes the Mean-Squared-Error (MSE) between two images\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::ComputeMSE(\n    const Image& image1,\n    const Image& image2,\n    float& mse,\n    float* mseV,\n    CMSE_FLAGS flags) noexcept\n{\n    if (!image1.pixels || !image2.pixels)\n        return E_POINTER;\n\n    if (image1.width != image2.width || image1.height != image2.height)\n        return E_INVALIDARG;\n\n    if (!IsValid(image1.format) || !IsValid(image2.format))\n        return E_INVALIDARG;\n\n    if (IsPlanar(image1.format) || IsPlanar(image2.format)\n        || IsPalettized(image1.format) || IsPalettized(image2.format)\n        || IsTypeless(image1.format) || IsTypeless(image2.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if (IsCompressed(image1.format))\n    {\n        if (IsCompressed(image2.format))\n        {\n            // Case 1: both images are compressed, expand to RGBA32F\n            ScratchImage temp1;\n            HRESULT hr = Decompress(image1, DXGI_FORMAT_R32G32B32A32_FLOAT, temp1);\n            if (FAILED(hr))\n                return hr;\n\n            ScratchImage temp2;\n            hr = Decompress(image2, DXGI_FORMAT_R32G32B32A32_FLOAT, temp2);\n            if (FAILED(hr))\n                return hr;\n\n            const Image* img1 = temp1.GetImage(0, 0, 0);\n            const Image* img2 = temp2.GetImage(0, 0, 0);\n            if (!img1 || !img2)\n                return E_POINTER;\n\n            return ComputeMSE_(*img1, *img2, mse, mseV, flags);\n        }\n        else\n        {\n            // Case 2: image1 is compressed, expand to RGBA32F\n            ScratchImage temp;\n            HRESULT hr = Decompress(image1, DXGI_FORMAT_R32G32B32A32_FLOAT, temp);\n            if (FAILED(hr))\n                return hr;\n\n            const Image* img = temp.GetImage(0, 0, 0);\n            if (!img)\n                return E_POINTER;\n\n            return ComputeMSE_(*img, image2, mse, mseV, flags);\n        }\n    }\n    else\n    {\n        if (IsCompressed(image2.format))\n        {\n            // Case 3: image2 is compressed, expand to RGBA32F\n            ScratchImage temp;\n            HRESULT hr = Decompress(image2, DXGI_FORMAT_R32G32B32A32_FLOAT, temp);\n            if (FAILED(hr))\n                return hr;\n\n            const Image* img = temp.GetImage(0, 0, 0);\n            if (!img)\n                return E_POINTER;\n\n            return ComputeMSE_(image1, *img, mse, mseV, flags);\n        }\n        else\n        {\n            // Case 4: neither image is compressed\n            return ComputeMSE_(image1, image2, mse, mseV, flags);\n        }\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// Evaluates a user-supplied function for all the pixels in the image\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::EvaluateImage(\n    const Image& image,\n    std::function<void __cdecl(_In_reads_(width) const XMVECTOR* pixels, size_t width, size_t y)> pixelFunc)\n{\n    if (image.width > UINT32_MAX\n        || image.height > UINT32_MAX)\n        return E_INVALIDARG;\n\n    if (!IsValid(image.format))\n        return E_INVALIDARG;\n\n    if (IsPlanar(image.format) || IsPalettized(image.format) || IsTypeless(image.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if (IsCompressed(image.format))\n    {\n        ScratchImage temp;\n        HRESULT hr = Decompress(image, DXGI_FORMAT_R32G32B32A32_FLOAT, temp);\n        if (FAILED(hr))\n            return hr;\n\n        const Image* img = temp.GetImage(0, 0, 0);\n        if (!img)\n            return E_POINTER;\n\n        return EvaluateImage_(*img, pixelFunc);\n    }\n    else\n    {\n        return EvaluateImage_(image, pixelFunc);\n    }\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::EvaluateImage(\n    const Image* images,\n    size_t nimages,\n    const TexMetadata& metadata,\n    std::function<void __cdecl(_In_reads_(width) const XMVECTOR* pixels, size_t width, size_t y)> pixelFunc)\n{\n    if (!images || !nimages)\n        return E_INVALIDARG;\n\n    if (!IsValid(metadata.format))\n        return E_INVALIDARG;\n\n    if (IsPlanar(metadata.format) || IsPalettized(metadata.format) || IsTypeless(metadata.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if (metadata.width > UINT32_MAX\n        || metadata.height > UINT32_MAX)\n        return E_INVALIDARG;\n\n    if (metadata.IsVolumemap() && metadata.depth > UINT16_MAX)\n        return E_INVALIDARG;\n\n    ScratchImage temp;\n    DXGI_FORMAT format = metadata.format;\n    if (IsCompressed(format))\n    {\n        HRESULT hr = Decompress(images, nimages, metadata, DXGI_FORMAT_R32G32B32A32_FLOAT, temp);\n        if (FAILED(hr))\n            return hr;\n\n        if (nimages != temp.GetImageCount())\n            return E_UNEXPECTED;\n\n        images = temp.GetImages();\n        format = DXGI_FORMAT_R32G32B32A32_FLOAT;\n    }\n\n    switch (metadata.dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n    case TEX_DIMENSION_TEXTURE2D:\n        for (size_t index = 0; index < nimages; ++index)\n        {\n            const Image& img = images[index];\n            if (img.format != format)\n                return E_FAIL;\n\n            if ((img.width > UINT32_MAX) || (img.height > UINT32_MAX))\n                return E_FAIL;\n\n            HRESULT hr = EvaluateImage_(img, pixelFunc);\n            if (FAILED(hr))\n                return hr;\n        }\n        break;\n\n    case TEX_DIMENSION_TEXTURE3D:\n        {\n            size_t index = 0;\n            size_t d = metadata.depth;\n            for (size_t level = 0; level < metadata.mipLevels; ++level)\n            {\n                for (size_t slice = 0; slice < d; ++slice, ++index)\n                {\n                    if (index >= nimages)\n                        return E_FAIL;\n\n                    const Image& img = images[index];\n                    if (img.format != format)\n                        return E_FAIL;\n\n                    if ((img.width > UINT32_MAX) || (img.height > UINT32_MAX))\n                        return E_FAIL;\n\n                    HRESULT hr = EvaluateImage_(img, pixelFunc);\n                    if (FAILED(hr))\n                        return hr;\n                }\n\n                if (d > 1)\n                    d >>= 1;\n            }\n        }\n        break;\n\n    default:\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Use a user-supplied function to compute a new image from an input image\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::TransformImage(\n    const Image& image,\n    std::function<void __cdecl(_Out_writes_(width) XMVECTOR* outPixels, _In_reads_(width) const XMVECTOR* inPixels, size_t width, size_t y)> pixelFunc,\n    ScratchImage& result)\n{\n    if (image.width > UINT32_MAX\n        || image.height > UINT32_MAX)\n        return E_INVALIDARG;\n\n    if (IsPlanar(image.format) || IsPalettized(image.format) || IsCompressed(image.format) || IsTypeless(image.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    HRESULT hr = result.Initialize2D(image.format, image.width, image.height, 1, 1);\n    if (FAILED(hr))\n        return hr;\n\n    const Image* dimg = result.GetImage(0, 0, 0);\n    if (!dimg)\n    {\n        result.Release();\n        return E_POINTER;\n    }\n\n    hr = TransformImage_(image, pixelFunc, *dimg);\n    if (FAILED(hr))\n    {\n        result.Release();\n        return hr;\n    }\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::TransformImage(\n    const Image* srcImages,\n    size_t nimages, const TexMetadata& metadata,\n    std::function<void __cdecl(_Out_writes_(width) XMVECTOR* outPixels, _In_reads_(width) const XMVECTOR* inPixels, size_t width, size_t y)> pixelFunc,\n    ScratchImage& result)\n{\n    if (!srcImages || !nimages)\n        return E_INVALIDARG;\n\n    if (IsPlanar(metadata.format) || IsPalettized(metadata.format) || IsCompressed(metadata.format) || IsTypeless(metadata.format))\n        return HRESULT_E_NOT_SUPPORTED;\n\n    if (metadata.width > UINT32_MAX\n        || metadata.height > UINT32_MAX)\n        return E_INVALIDARG;\n\n    if (metadata.IsVolumemap() && metadata.depth > UINT16_MAX)\n        return E_INVALIDARG;\n\n    HRESULT hr = result.Initialize(metadata);\n    if (FAILED(hr))\n        return hr;\n\n    if (nimages != result.GetImageCount())\n    {\n        result.Release();\n        return E_FAIL;\n    }\n\n    const Image* dest = result.GetImages();\n    if (!dest)\n    {\n        result.Release();\n        return E_POINTER;\n    }\n\n    switch (metadata.dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n    case TEX_DIMENSION_TEXTURE2D:\n        for (size_t index = 0; index < nimages; ++index)\n        {\n            const Image& src = srcImages[index];\n            if (src.format != metadata.format)\n            {\n                result.Release();\n                return E_FAIL;\n            }\n\n            if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX))\n            {\n                result.Release();\n                return E_FAIL;\n            }\n\n            const Image& dst = dest[index];\n\n            if (src.width != dst.width || src.height != dst.height)\n            {\n                result.Release();\n                return E_FAIL;\n            }\n\n            hr = TransformImage_(src, pixelFunc, dst);\n            if (FAILED(hr))\n            {\n                result.Release();\n                return hr;\n            }\n        }\n        break;\n\n    case TEX_DIMENSION_TEXTURE3D:\n        {\n            size_t index = 0;\n            size_t d = metadata.depth;\n            for (size_t level = 0; level < metadata.mipLevels; ++level)\n            {\n                for (size_t slice = 0; slice < d; ++slice, ++index)\n                {\n                    if (index >= nimages)\n                    {\n                        result.Release();\n                        return E_FAIL;\n                    }\n\n                    const Image& src = srcImages[index];\n                    if (src.format != metadata.format)\n                    {\n                        result.Release();\n                        return E_FAIL;\n                    }\n\n                    if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX))\n                    {\n                        result.Release();\n                        return E_FAIL;\n                    }\n\n                    const Image& dst = dest[index];\n\n                    if (src.width != dst.width || src.height != dst.height)\n                    {\n                        result.Release();\n                        return E_FAIL;\n                    }\n\n                    hr = TransformImage_(src, pixelFunc, dst);\n                    if (FAILED(hr))\n                    {\n                        result.Release();\n                        return hr;\n                    }\n                }\n\n                if (d > 1)\n                    d >>= 1;\n            }\n        }\n        break;\n\n    default:\n        result.Release();\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTexP.h",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTexP.h\n//\n// DirectX Texture Library - Private header\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n// Off by default warnings\n#pragma warning(disable : 4619 4616 4061 4265 4365 4571 4623 4625 4626 4628 4668 4710 4711 4746 4774 4820 4987 5026 5027 5031 5032 5039 5045 5219 5246 26812)\n// C4619/4616 #pragma warning warnings\n// C4061 enumerator 'X' in switch of enum 'X' is not explicitly handled by a case label\n// C4265 class has virtual functions, but destructor is not virtual\n// C4365 signed/unsigned mismatch\n// C4571 behavior change\n// C4623 default constructor was implicitly defined as deleted\n// C4625 copy constructor was implicitly defined as deleted\n// C4626 assignment operator was implicitly defined as deleted\n// C4628 digraphs not supported\n// C4668 not defined as a preprocessor macro\n// C4710 function not inlined\n// C4711 selected for automatic inline expansion\n// C4746 volatile access of '<expression>' is subject to /volatile:<iso|ms> setting\n// C4774 format string expected in argument 3 is not a string literal\n// C4820 padding added after data member\n// C4987 nonstandard extension used\n// C5026 move constructor was implicitly defined as deleted\n// C5027 move assignment operator was implicitly defined as deleted\n// C5031/5032 push/pop mismatches in windows headers\n// C5039 pointer or reference to potentially throwing function passed to extern C function under - EHc\n// C5045 Spectre mitigation warning\n// C5219 implicit conversion from 'int' to 'float', possible loss of data\n// C5246 the initialization of a subobject should be wrapped in braces\n// 26812: The enum type 'x' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).\n\n// Windows 8.1 SDK related Off by default warnings\n#pragma warning(disable : 4471 4917 4986 5029)\n// C4471 forward declaration of an unscoped enumeration must have an underlying type\n// C4917 a GUID can only be associated with a class, interface or namespace\n// C4986 exception specification does not match previous declaration\n// C5029 nonstandard extension used\n\n// Xbox One XDK related Off by default warnings\n#pragma warning(disable : 4643)\n// C4643 Forward declaring in namespace std is not permitted by the C++ Standard\n\n#ifdef __INTEL_COMPILER\n#pragma warning(disable : 161)\n// warning #161: unrecognized #pragma\n#endif\n\n#ifdef __clang__\n#pragma clang diagnostic ignored \"-Wc++98-compat\"\n#pragma clang diagnostic ignored \"-Wc++98-compat-pedantic\"\n#pragma clang diagnostic ignored \"-Wc++98-compat-local-type-template-args\"\n#pragma clang diagnostic ignored \"-Wcovered-switch-default\"\n#pragma clang diagnostic ignored \"-Wfloat-equal\"\n#pragma clang diagnostic ignored \"-Wglobal-constructors\"\n#pragma clang diagnostic ignored \"-Wgnu-anonymous-struct\"\n#pragma clang diagnostic ignored \"-Wlanguage-extension-token\"\n#pragma clang diagnostic ignored \"-Wmissing-variable-declarations\"\n#pragma clang diagnostic ignored \"-Wnested-anon-types\"\n#pragma clang diagnostic ignored \"-Wreserved-id-macro\"\n#pragma clang diagnostic ignored \"-Wswitch-enum\"\n#pragma clang diagnostic ignored \"-Wtautological-type-limit-compare\"\n#pragma clang diagnostic ignored \"-Wunknown-pragmas\"\n#endif\n\n#include <App/ZetaRay.h>\n#include <Win32/Win32.h>\n\n#include <algorithm>\n#include <cassert>\n#include <cstdlib>\n#include <ctime>\n#include <cstring>\n#include <iterator>\n#include <memory>\n#include <new>\n#include <tuple>\n\n#define _XM_NO_XMVECTOR_OVERLOADS_\n\n#include <DirectXPackedVector.h>\n\n#if (DIRECTX_MATH_VERSION < 315)\n#define XM_ALIGNED_DATA(x) __declspec(align(x))\n#endif\n\n#include \"DirectXTex.h\"\n\n#include <malloc.h>\n\n#ifdef _WIN32\n#if defined(NTDDI_WIN10_FE) || defined(__MINGW32__)\n#include <ole2.h>\n#else\n#include <Ole2.h>\n#endif\n#include <wincodec.h>\n#include <wrl\\client.h>\n#else\nusing WICPixelFormatGUID = GUID;\n#endif\n\n#include \"scoped.h\"\n\n#define XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT DXGI_FORMAT(116)\n#define XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT DXGI_FORMAT(117)\n#define XBOX_DXGI_FORMAT_D16_UNORM_S8_UINT DXGI_FORMAT(118)\n#define XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS DXGI_FORMAT(119)\n#define XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT DXGI_FORMAT(120)\n\n#define WIN10_DXGI_FORMAT_P208 DXGI_FORMAT(130)\n#define WIN10_DXGI_FORMAT_V208 DXGI_FORMAT(131)\n#define WIN10_DXGI_FORMAT_V408 DXGI_FORMAT(132)\n\n#ifndef XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM\n#define XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM DXGI_FORMAT(189)\n#endif\n\n#define XBOX_DXGI_FORMAT_R4G4_UNORM DXGI_FORMAT(190)\n\n#if defined(__MINGW32__) && !defined(E_BOUNDS)\n#define E_BOUNDS static_cast<HRESULT>(0x8000000BL)\n#endif\n\n// HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW)\n#define HRESULT_E_ARITHMETIC_OVERFLOW static_cast<HRESULT>(0x80070216L)\n\n// HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)\n#define HRESULT_E_NOT_SUPPORTED static_cast<HRESULT>(0x80070032L)\n\n// HRESULT_FROM_WIN32(ERROR_HANDLE_EOF)\n#define HRESULT_E_HANDLE_EOF static_cast<HRESULT>(0x80070026L)\n\n// HRESULT_FROM_WIN32(ERROR_INVALID_DATA)\n#define HRESULT_E_INVALID_DATA static_cast<HRESULT>(0x8007000DL)\n\n// HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE)\n#define HRESULT_E_FILE_TOO_LARGE static_cast<HRESULT>(0x800700DFL)\n\n// HRESULT_FROM_WIN32(ERROR_CANNOT_MAKE)\n#define HRESULT_E_CANNOT_MAKE static_cast<HRESULT>(0x80070052L)\n\n// HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)\n#ifndef E_NOT_SUFFICIENT_BUFFER\n#define E_NOT_SUFFICIENT_BUFFER static_cast<HRESULT>(0x8007007AL)\n#endif\n\n//-------------------------------------------------------------------------------------\nnamespace DirectX\n{\n    namespace Internal\n    {\n        //-----------------------------------------------------------------------------\n        // WIC helper functions\n    #ifdef _WIN32\n        DXGI_FORMAT __cdecl WICToDXGI(_In_ const GUID& guid) noexcept;\n        bool __cdecl DXGIToWIC(_In_ DXGI_FORMAT format, _Out_ GUID& guid, _In_ bool ignoreRGBvsBGR = false) noexcept;\n\n        TEX_FILTER_FLAGS __cdecl CheckWICColorSpace(_In_ const GUID& sourceGUID, _In_ const GUID& targetGUID) noexcept;\n\n        inline WICBitmapDitherType __cdecl GetWICDither(_In_ TEX_FILTER_FLAGS flags) noexcept\n        {\n            static_assert(TEX_FILTER_DITHER == 0x10000, \"TEX_FILTER_DITHER* flag values don't match mask\");\n\n            static_assert(static_cast<int>(TEX_FILTER_DITHER) == static_cast<int>(WIC_FLAGS_DITHER), \"TEX_FILTER_DITHER* should match WIC_FLAGS_DITHER*\");\n            static_assert(static_cast<int>(TEX_FILTER_DITHER_DIFFUSION) == static_cast<int>(WIC_FLAGS_DITHER_DIFFUSION), \"TEX_FILTER_DITHER* should match WIC_FLAGS_DITHER*\");\n\n            switch (flags & TEX_FILTER_DITHER_MASK)\n            {\n            case TEX_FILTER_DITHER:\n                return WICBitmapDitherTypeOrdered4x4;\n\n            case TEX_FILTER_DITHER_DIFFUSION:\n                return WICBitmapDitherTypeErrorDiffusion;\n\n            default:\n                return WICBitmapDitherTypeNone;\n            }\n        }\n\n        inline WICBitmapDitherType __cdecl GetWICDither(_In_ WIC_FLAGS flags) noexcept\n        {\n            switch (flags & TEX_FILTER_DITHER_MASK)\n            {\n            case WIC_FLAGS_DITHER:\n                return WICBitmapDitherTypeOrdered4x4;\n\n            case WIC_FLAGS_DITHER_DIFFUSION:\n                return WICBitmapDitherTypeErrorDiffusion;\n\n            default:\n                return WICBitmapDitherTypeNone;\n            }\n        }\n\n        inline WICBitmapInterpolationMode __cdecl GetWICInterp(_In_ WIC_FLAGS flags) noexcept\n        {\n            static_assert(TEX_FILTER_POINT == 0x100000, \"TEX_FILTER_ flag values don't match TEX_FILTER_MASK\");\n\n            static_assert(static_cast<int>(TEX_FILTER_POINT) == static_cast<int>(WIC_FLAGS_FILTER_POINT), \"TEX_FILTER_* flags should match WIC_FLAGS_FILTER_*\");\n            static_assert(static_cast<int>(TEX_FILTER_LINEAR) == static_cast<int>(WIC_FLAGS_FILTER_LINEAR), \"TEX_FILTER_* flags should match WIC_FLAGS_FILTER_*\");\n            static_assert(static_cast<int>(TEX_FILTER_CUBIC) == static_cast<int>(WIC_FLAGS_FILTER_CUBIC), \"TEX_FILTER_* flags should match WIC_FLAGS_FILTER_*\");\n            static_assert(static_cast<int>(TEX_FILTER_FANT) == static_cast<int>(WIC_FLAGS_FILTER_FANT), \"TEX_FILTER_* flags should match WIC_FLAGS_FILTER_*\");\n\n            switch (flags & TEX_FILTER_MODE_MASK)\n            {\n            case TEX_FILTER_POINT:\n                return WICBitmapInterpolationModeNearestNeighbor;\n\n            case TEX_FILTER_LINEAR:\n                return WICBitmapInterpolationModeLinear;\n\n            case TEX_FILTER_CUBIC:\n                return WICBitmapInterpolationModeCubic;\n\n            case TEX_FILTER_FANT:\n            default:\n                return WICBitmapInterpolationModeFant;\n            }\n        }\n\n        inline WICBitmapInterpolationMode __cdecl GetWICInterp(_In_ TEX_FILTER_FLAGS flags) noexcept\n        {\n            switch (flags & TEX_FILTER_MODE_MASK)\n            {\n            case TEX_FILTER_POINT:\n                return WICBitmapInterpolationModeNearestNeighbor;\n\n            case TEX_FILTER_LINEAR:\n                return WICBitmapInterpolationModeLinear;\n\n            case TEX_FILTER_CUBIC:\n                return WICBitmapInterpolationModeCubic;\n\n            case TEX_FILTER_FANT:\n            default:\n                return WICBitmapInterpolationModeFant;\n            }\n        }\n    #endif // WIN32\n\n        //---------------------------------------------------------------------------------\n        // Image helper functions\n        _Success_(return) bool __cdecl DetermineImageArray(\n            _In_ const TexMetadata& metadata, _In_ CP_FLAGS cpFlags,\n            _Out_ size_t& nImages, _Out_ size_t& pixelSize) noexcept;\n\n        _Success_(return) bool __cdecl SetupImageArray(\n            _In_reads_bytes_(pixelSize) uint8_t* pMemory, _In_ size_t pixelSize,\n            _In_ const TexMetadata& metadata, _In_ CP_FLAGS cpFlags,\n            _Out_writes_(nImages) Image* images, _In_ size_t nImages) noexcept;\n\n        //---------------------------------------------------------------------------------\n        // Conversion helper functions\n\n        enum TEXP_SCANLINE_FLAGS : uint32_t\n        {\n            TEXP_SCANLINE_NONE = 0,\n\n            TEXP_SCANLINE_SETALPHA = 0x1,\n            // Set alpha channel to known opaque value\n\n            TEXP_SCANLINE_LEGACY = 0x2,\n            // Enables specific legacy format conversion cases\n        };\n\n        enum CONVERT_FLAGS : uint32_t\n        {\n            CONVF_FLOAT = 0x1,\n            CONVF_UNORM = 0x2,\n            CONVF_UINT = 0x4,\n            CONVF_SNORM = 0x8,\n            CONVF_SINT = 0x10,\n            CONVF_DEPTH = 0x20,\n            CONVF_STENCIL = 0x40,\n            CONVF_SHAREDEXP = 0x80,\n            CONVF_BGR = 0x100,\n            CONVF_XR = 0x200,\n            CONVF_PACKED = 0x400,\n            CONVF_BC = 0x800,\n            CONVF_YUV = 0x1000,\n            CONVF_POS_ONLY = 0x2000,\n            CONVF_R = 0x10000,\n            CONVF_G = 0x20000,\n            CONVF_B = 0x40000,\n            CONVF_A = 0x80000,\n            CONVF_RGB_MASK = 0x70000,\n            CONVF_RGBA_MASK = 0xF0000,\n        };\n\n        uint32_t __cdecl GetConvertFlags(_In_ DXGI_FORMAT format) noexcept;\n\n        void __cdecl CopyScanline(\n            _When_(pDestination == pSource, _Inout_updates_bytes_(outSize))\n            _When_(pDestination != pSource, _Out_writes_bytes_(outSize))\n            void* pDestination, _In_ size_t outSize,\n            _In_reads_bytes_(inSize) const void* pSource, _In_ size_t inSize,\n            _In_ DXGI_FORMAT format, _In_ uint32_t tflags) noexcept;\n\n        void __cdecl SwizzleScanline(\n            _When_(pDestination == pSource, _In_)\n            _When_(pDestination != pSource, _Out_writes_bytes_(outSize))\n            void* pDestination, _In_ size_t outSize,\n            _In_reads_bytes_(inSize) const void* pSource, _In_ size_t inSize,\n            _In_ DXGI_FORMAT format, _In_ uint32_t tflags) noexcept;\n\n        _Success_(return) bool __cdecl ExpandScanline(\n            _Out_writes_bytes_(outSize) void* pDestination, _In_ size_t outSize,\n            _In_ DXGI_FORMAT outFormat,\n            _In_reads_bytes_(inSize) const void* pSource, _In_ size_t inSize,\n            _In_ DXGI_FORMAT inFormat, _In_ uint32_t tflags) noexcept;\n\n        _Success_(return) bool __cdecl LoadScanline(\n            _Out_writes_(count) XMVECTOR* pDestination, _In_ size_t count,\n            _In_reads_bytes_(size) const void* pSource, _In_ size_t size,\n            _In_ DXGI_FORMAT format) noexcept;\n\n        _Success_(return) bool __cdecl LoadScanlineLinear(\n            _Out_writes_(count) XMVECTOR* pDestination, _In_ size_t count,\n            _In_reads_bytes_(size) const void* pSource, _In_ size_t size,\n            _In_ DXGI_FORMAT format, _In_ TEX_FILTER_FLAGS flags) noexcept;\n\n        _Success_(return) bool __cdecl StoreScanline(\n            _Out_writes_bytes_(size) void* pDestination, _In_ size_t size, _In_ DXGI_FORMAT format,\n            _In_reads_(count) const XMVECTOR* pSource, _In_ size_t count, _In_ float threshold = 0) noexcept;\n\n        _Success_(return) bool __cdecl StoreScanlineLinear(\n            _Out_writes_bytes_(size) void* pDestination, _In_ size_t size, _In_ DXGI_FORMAT format,\n            _Inout_updates_all_(count) XMVECTOR* pSource, _In_ size_t count,\n            _In_ TEX_FILTER_FLAGS flags, _In_ float threshold = 0) noexcept;\n\n        _Success_(return) bool __cdecl StoreScanlineDither(\n            _Out_writes_bytes_(size) void* pDestination, _In_ size_t size, _In_ DXGI_FORMAT format,\n            _Inout_updates_all_(count) XMVECTOR* pSource, _In_ size_t count,\n            _In_ float threshold, size_t y, size_t z,\n            _Inout_updates_all_opt_(count + 2) XMVECTOR* pDiffusionErrors) noexcept;\n\n        HRESULT __cdecl ConvertToR32G32B32A32(_In_ const Image& srcImage, _Inout_ ScratchImage& image) noexcept;\n\n        HRESULT __cdecl ConvertFromR32G32B32A32(_In_ const Image& srcImage, _In_ const Image& destImage) noexcept;\n        HRESULT __cdecl ConvertFromR32G32B32A32(\n            _In_ const Image& srcImage, _In_ DXGI_FORMAT format, _Inout_ ScratchImage& image) noexcept;\n        HRESULT __cdecl ConvertFromR32G32B32A32(\n            _In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata,\n            _In_ DXGI_FORMAT format, _Out_ ScratchImage& result) noexcept;\n\n        HRESULT __cdecl ConvertToR16G16B16A16(_In_ const Image& srcImage, _Inout_ ScratchImage& image) noexcept;\n\n        HRESULT __cdecl ConvertFromR16G16B16A16(_In_ const Image& srcImage, _In_ const Image& destImage) noexcept;\n\n        void __cdecl ConvertScanline(\n            _Inout_updates_all_(count) XMVECTOR* pBuffer, _In_ size_t count,\n            _In_ DXGI_FORMAT outFormat, _In_ DXGI_FORMAT inFormat, _In_ TEX_FILTER_FLAGS flags) noexcept;\n\n        //---------------------------------------------------------------------------------\n        // Misc helper functions\n        bool __cdecl IsAlphaAllOpaqueBC(_In_ const Image& cImage) noexcept;\n        bool __cdecl CalculateMipLevels(_In_ size_t width, _In_ size_t height, _Inout_ size_t& mipLevels) noexcept;\n        bool __cdecl CalculateMipLevels3D(_In_ size_t width, _In_ size_t height, _In_ size_t depth,\n            _Inout_ size_t& mipLevels) noexcept;\n\n    #ifdef _WIN32\n        HRESULT __cdecl ResizeSeparateColorAndAlpha(_In_ IWICImagingFactory* pWIC,\n            _In_ bool iswic2,\n            _In_ IWICBitmap* original,\n            _In_ size_t newWidth, _In_ size_t newHeight, _In_ TEX_FILTER_FLAGS filter,\n            _Inout_ const Image* img) noexcept;\n    #endif\n\n    } // namespace Internal\n} // namespace DirectX\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTexResize.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTexResize.cpp\n//\n// DirectX Texture Library - Image resizing operations\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\n#include \"filters.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::Internal;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n#ifdef _WIN32\n    //--- Do image resize using WIC ---\n    HRESULT PerformResizeUsingWIC(\n        const Image& srcImage,\n        TEX_FILTER_FLAGS filter,\n        const WICPixelFormatGUID& pfGUID,\n        const Image& destImage) noexcept\n    {\n        if (!srcImage.pixels || !destImage.pixels)\n            return E_POINTER;\n\n        assert(srcImage.format == destImage.format);\n\n        bool iswic2 = false;\n        auto pWIC = GetWICFactory(iswic2);\n        if (!pWIC)\n            return E_NOINTERFACE;\n\n        ComPtr<IWICComponentInfo> componentInfo;\n        HRESULT hr = pWIC->CreateComponentInfo(pfGUID, componentInfo.GetAddressOf());\n        if (FAILED(hr))\n            return hr;\n\n        ComPtr<IWICPixelFormatInfo2> pixelFormatInfo;\n        hr = componentInfo.As(&pixelFormatInfo);\n        if (FAILED(hr))\n            return hr;\n\n        BOOL supportsTransparency = FALSE;\n        hr = pixelFormatInfo->SupportsTransparency(&supportsTransparency);\n        if (FAILED(hr))\n            return hr;\n\n        if (srcImage.rowPitch > UINT32_MAX || srcImage.slicePitch > UINT32_MAX\n            || destImage.rowPitch > UINT32_MAX || destImage.slicePitch > UINT32_MAX)\n            return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n        ComPtr<IWICBitmap> source;\n        hr = pWIC->CreateBitmapFromMemory(static_cast<UINT>(srcImage.width), static_cast<UINT>(srcImage.height), pfGUID,\n            static_cast<UINT>(srcImage.rowPitch), static_cast<UINT>(srcImage.slicePitch),\n            srcImage.pixels, source.GetAddressOf());\n        if (FAILED(hr))\n            return hr;\n\n        if ((filter & TEX_FILTER_SEPARATE_ALPHA) && supportsTransparency)\n        {\n            hr = ResizeSeparateColorAndAlpha(pWIC, iswic2, source.Get(), destImage.width, destImage.height, filter, &destImage);\n            if (FAILED(hr))\n                return hr;\n        }\n        else\n        {\n            ComPtr<IWICBitmapScaler> scaler;\n            hr = pWIC->CreateBitmapScaler(scaler.GetAddressOf());\n            if (FAILED(hr))\n                return hr;\n\n            hr = scaler->Initialize(source.Get(),\n                static_cast<UINT>(destImage.width), static_cast<UINT>(destImage.height),\n                GetWICInterp(filter));\n            if (FAILED(hr))\n                return hr;\n\n            WICPixelFormatGUID pfScaler;\n            hr = scaler->GetPixelFormat(&pfScaler);\n            if (FAILED(hr))\n                return hr;\n\n            if (memcmp(&pfScaler, &pfGUID, sizeof(WICPixelFormatGUID)) == 0)\n            {\n                hr = scaler->CopyPixels(nullptr, static_cast<UINT>(destImage.rowPitch), static_cast<UINT>(destImage.slicePitch), destImage.pixels);\n                if (FAILED(hr))\n                    return hr;\n            }\n            else\n            {\n                // The WIC bitmap scaler is free to return a different pixel format than the source image, so here we\n                // convert it back\n                ComPtr<IWICFormatConverter> FC;\n                hr = pWIC->CreateFormatConverter(FC.GetAddressOf());\n                if (FAILED(hr))\n                    return hr;\n\n                BOOL canConvert = FALSE;\n                hr = FC->CanConvert(pfScaler, pfGUID, &canConvert);\n                if (FAILED(hr) || !canConvert)\n                {\n                    return E_UNEXPECTED;\n                }\n\n                hr = FC->Initialize(scaler.Get(), pfGUID, GetWICDither(filter), nullptr,\n                    0, WICBitmapPaletteTypeMedianCut);\n                if (FAILED(hr))\n                    return hr;\n\n                hr = FC->CopyPixels(nullptr, static_cast<UINT>(destImage.rowPitch), static_cast<UINT>(destImage.slicePitch), destImage.pixels);\n                if (FAILED(hr))\n                    return hr;\n            }\n        }\n\n        return S_OK;\n    }\n\n\n    //--- Do conversion, resize using WIC, conversion cycle ---\n    HRESULT PerformResizeViaF32(\n        const Image& srcImage,\n        TEX_FILTER_FLAGS filter,\n        const Image& destImage) noexcept\n    {\n        if (!srcImage.pixels || !destImage.pixels)\n            return E_POINTER;\n\n        assert(srcImage.format != DXGI_FORMAT_R32G32B32A32_FLOAT);\n        assert(srcImage.format == destImage.format);\n\n        ScratchImage temp;\n        HRESULT hr = ConvertToR32G32B32A32(srcImage, temp);\n        if (FAILED(hr))\n            return hr;\n\n        const Image *tsrc = temp.GetImage(0, 0, 0);\n        if (!tsrc)\n            return E_POINTER;\n\n        ScratchImage rtemp;\n        hr = rtemp.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, destImage.width, destImage.height, 1, 1);\n        if (FAILED(hr))\n            return hr;\n\n        const Image *tdest = rtemp.GetImage(0, 0, 0);\n        if (!tdest)\n            return E_POINTER;\n\n        hr = PerformResizeUsingWIC(*tsrc, filter, GUID_WICPixelFormat128bppRGBAFloat, *tdest);\n        if (FAILED(hr))\n            return hr;\n\n        temp.Release();\n\n        hr = ConvertFromR32G32B32A32(*tdest, destImage);\n        if (FAILED(hr))\n            return hr;\n\n        return S_OK;\n    }\n\n\n    //--- determine when to use WIC vs. non-WIC paths ---\n    bool UseWICFiltering(_In_ DXGI_FORMAT format, _In_ TEX_FILTER_FLAGS filter) noexcept\n    {\n        if (filter & TEX_FILTER_FORCE_NON_WIC)\n        {\n            // Explicit flag indicates use of non-WIC code paths\n            return false;\n        }\n\n        if (filter & TEX_FILTER_FORCE_WIC)\n        {\n            // Explicit flag to use WIC code paths, skips all the case checks below\n            return true;\n        }\n\n        if (IsSRGB(format) || (filter & TEX_FILTER_SRGB))\n        {\n            // Use non-WIC code paths for sRGB correct filtering\n            return false;\n        }\n\n    #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n        if (format == DXGI_FORMAT_R16G16B16A16_FLOAT\n            || format == DXGI_FORMAT_R16_FLOAT)\n        {\n            // Use non-WIC code paths as these conversions are not supported by Xbox version of WIC\n            return false;\n        }\n    #endif\n\n        static_assert(TEX_FILTER_POINT == 0x100000, \"TEX_FILTER_ flag values don't match TEX_FILTER_MASK\");\n\n        switch (filter & TEX_FILTER_MODE_MASK)\n        {\n        case TEX_FILTER_LINEAR:\n            if (filter & TEX_FILTER_WRAP)\n            {\n                // WIC only supports 'clamp' semantics (MIRROR is equivalent to clamp for linear)\n                return false;\n            }\n\n            if (BitsPerColor(format) > 8)\n            {\n                // Avoid the WIC bitmap scaler when doing Linear filtering of XR/HDR formats\n                return false;\n            }\n            break;\n\n        case TEX_FILTER_CUBIC:\n            if (filter & (TEX_FILTER_WRAP | TEX_FILTER_MIRROR))\n            {\n                // WIC only supports 'clamp' semantics\n                return false;\n            }\n\n            if (BitsPerColor(format) > 8)\n            {\n                // Avoid the WIC bitmap scaler when doing Cubic filtering of XR/HDR formats\n                return false;\n            }\n            break;\n\n        case TEX_FILTER_TRIANGLE:\n            // WIC does not implement this filter\n            return false;\n\n        default:\n            if (BitsPerColor(format) > 8)\n            {\n                // Avoid the WIC bitmap scaler when doing filtering of XR/HDR formats\n                return false;\n            }\n            break;\n        }\n\n        return true;\n    }\n#endif // WIN32\n\n    //-------------------------------------------------------------------------------------\n    // Resize custom filters\n    //-------------------------------------------------------------------------------------\n\n    //--- Point Filter ---\n    HRESULT ResizePointFilter(const Image& srcImage, const Image& destImage) noexcept\n    {\n        assert(srcImage.pixels && destImage.pixels);\n        assert(srcImage.format == destImage.format);\n\n        // Allocate temporary space (2 scanlines)\n        auto scanline = make_AlignedArrayXMVECTOR(uint64_t(srcImage.width) + destImage.width);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        XMVECTOR* target = scanline.get();\n\n        XMVECTOR* row = target + destImage.width;\n\n    #ifdef _DEBUG\n        memset(row, 0xCD, sizeof(XMVECTOR)*srcImage.width);\n    #endif\n\n        const uint8_t* pSrc = srcImage.pixels;\n        uint8_t* pDest = destImage.pixels;\n\n        const size_t rowPitch = srcImage.rowPitch;\n\n        const size_t xinc = (srcImage.width << 16) / destImage.width;\n        const size_t yinc = (srcImage.height << 16) / destImage.height;\n\n        size_t lasty = size_t(-1);\n\n        size_t sy = 0;\n        for (size_t y = 0; y < destImage.height; ++y)\n        {\n            if ((lasty ^ sy) >> 16)\n            {\n                if (!LoadScanline(row, srcImage.width, pSrc + (rowPitch * (sy >> 16)), rowPitch, srcImage.format))\n                    return E_FAIL;\n                lasty = sy;\n            }\n\n            size_t sx = 0;\n            for (size_t x = 0; x < destImage.width; ++x)\n            {\n                target[x] = row[sx >> 16];\n                sx += xinc;\n            }\n\n            if (!StoreScanline(pDest, destImage.rowPitch, destImage.format, target, destImage.width))\n                return E_FAIL;\n            pDest += destImage.rowPitch;\n\n            sy += yinc;\n        }\n\n        return S_OK;\n    }\n\n\n    //--- Box Filter ---\n    HRESULT ResizeBoxFilter(const Image& srcImage, TEX_FILTER_FLAGS filter, const Image& destImage) noexcept\n    {\n        using namespace DirectX::Filters;\n\n        assert(srcImage.pixels && destImage.pixels);\n        assert(srcImage.format == destImage.format);\n\n        if (((destImage.width << 1) != srcImage.width) || ((destImage.height << 1) != srcImage.height))\n            return E_FAIL;\n\n        // Allocate temporary space (3 scanlines)\n        auto scanline = make_AlignedArrayXMVECTOR(uint64_t(srcImage.width) * 2 + destImage.width);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        XMVECTOR* target = scanline.get();\n\n        XMVECTOR* urow0 = target + destImage.width;\n        XMVECTOR* urow1 = urow0 + srcImage.width;\n\n    #ifdef _DEBUG\n        memset(urow0, 0xCD, sizeof(XMVECTOR)*srcImage.width);\n        memset(urow1, 0xDD, sizeof(XMVECTOR)*srcImage.width);\n    #endif\n\n        const XMVECTOR* urow2 = urow0 + 1;\n        const XMVECTOR* urow3 = urow1 + 1;\n\n        const uint8_t* pSrc = srcImage.pixels;\n        uint8_t* pDest = destImage.pixels;\n\n        const size_t rowPitch = srcImage.rowPitch;\n\n        for (size_t y = 0; y < destImage.height; ++y)\n        {\n            if (!LoadScanlineLinear(urow0, srcImage.width, pSrc, rowPitch, srcImage.format, filter))\n                return E_FAIL;\n            pSrc += rowPitch;\n\n            if (urow0 != urow1)\n            {\n                if (!LoadScanlineLinear(urow1, srcImage.width, pSrc, rowPitch, srcImage.format, filter))\n                    return E_FAIL;\n                pSrc += rowPitch;\n            }\n\n            for (size_t x = 0; x < destImage.width; ++x)\n            {\n                const size_t x2 = x << 1;\n\n                AVERAGE4(target[x], urow0[x2], urow1[x2], urow2[x2], urow3[x2])\n            }\n\n            if (!StoreScanlineLinear(pDest, destImage.rowPitch, destImage.format, target, destImage.width, filter))\n                return E_FAIL;\n            pDest += destImage.rowPitch;\n        }\n\n        return S_OK;\n    }\n\n\n    //--- Linear Filter ---\n    HRESULT ResizeLinearFilter(const Image& srcImage, TEX_FILTER_FLAGS filter, const Image& destImage) noexcept\n    {\n        using namespace DirectX::Filters;\n\n        assert(srcImage.pixels && destImage.pixels);\n        assert(srcImage.format == destImage.format);\n\n        // Allocate temporary space (3 scanlines, plus X and Y filters)\n        auto scanline = make_AlignedArrayXMVECTOR(uint64_t(srcImage.width) * 2 + destImage.width);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        std::unique_ptr<LinearFilter[]> lf(new (std::nothrow) LinearFilter[destImage.width + destImage.height]);\n        if (!lf)\n            return E_OUTOFMEMORY;\n\n        LinearFilter* lfX = lf.get();\n        LinearFilter* lfY = lf.get() + destImage.width;\n\n        CreateLinearFilter(srcImage.width, destImage.width, (filter & TEX_FILTER_WRAP_U) != 0, lfX);\n        CreateLinearFilter(srcImage.height, destImage.height, (filter & TEX_FILTER_WRAP_V) != 0, lfY);\n\n        XMVECTOR* target = scanline.get();\n\n        XMVECTOR* row0 = target + destImage.width;\n        XMVECTOR* row1 = row0 + srcImage.width;\n\n    #ifdef _DEBUG\n        memset(row0, 0xCD, sizeof(XMVECTOR)*srcImage.width);\n        memset(row1, 0xDD, sizeof(XMVECTOR)*srcImage.width);\n    #endif\n\n        const uint8_t* pSrc = srcImage.pixels;\n        uint8_t* pDest = destImage.pixels;\n\n        const size_t rowPitch = srcImage.rowPitch;\n\n        size_t u0 = size_t(-1);\n        size_t u1 = size_t(-1);\n\n        for (size_t y = 0; y < destImage.height; ++y)\n        {\n            auto const& toY = lfY[y];\n\n            if (toY.u0 != u0)\n            {\n                if (toY.u0 != u1)\n                {\n                    u0 = toY.u0;\n\n                    if (!LoadScanlineLinear(row0, srcImage.width, pSrc + (rowPitch * u0), rowPitch, srcImage.format, filter))\n                        return E_FAIL;\n                }\n                else\n                {\n                    u0 = u1;\n                    u1 = size_t(-1);\n\n                    std::swap(row0, row1);\n                }\n            }\n\n            if (toY.u1 != u1)\n            {\n                u1 = toY.u1;\n\n                if (!LoadScanlineLinear(row1, srcImage.width, pSrc + (rowPitch * u1), rowPitch, srcImage.format, filter))\n                    return E_FAIL;\n            }\n\n            for (size_t x = 0; x < destImage.width; ++x)\n            {\n                auto const& toX = lfX[x];\n\n                BILINEAR_INTERPOLATE(target[x], toX, toY, row0, row1)\n            }\n\n            if (!StoreScanlineLinear(pDest, destImage.rowPitch, destImage.format, target, destImage.width, filter))\n                return E_FAIL;\n            pDest += destImage.rowPitch;\n        }\n\n        return S_OK;\n    }\n\n\n    //--- Cubic Filter ---\n#ifdef __clang__\n#pragma clang diagnostic ignored \"-Wextra-semi-stmt\"\n#endif\n\n    HRESULT ResizeCubicFilter(const Image& srcImage, TEX_FILTER_FLAGS filter, const Image& destImage) noexcept\n    {\n        using namespace DirectX::Filters;\n\n        assert(srcImage.pixels && destImage.pixels);\n        assert(srcImage.format == destImage.format);\n\n        // Allocate temporary space (5 scanlines, plus X and Y filters)\n        auto scanline = make_AlignedArrayXMVECTOR(uint64_t(srcImage.width) * 4 + destImage.width);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        std::unique_ptr<CubicFilter[]> cf(new (std::nothrow) CubicFilter[destImage.width + destImage.height]);\n        if (!cf)\n            return E_OUTOFMEMORY;\n\n        CubicFilter* cfX = cf.get();\n        CubicFilter* cfY = cf.get() + destImage.width;\n\n        CreateCubicFilter(srcImage.width, destImage.width, (filter & TEX_FILTER_WRAP_U) != 0, (filter & TEX_FILTER_MIRROR_U) != 0, cfX);\n        CreateCubicFilter(srcImage.height, destImage.height, (filter & TEX_FILTER_WRAP_V) != 0, (filter & TEX_FILTER_MIRROR_V) != 0, cfY);\n\n        XMVECTOR* target = scanline.get();\n\n        XMVECTOR* row0 = target + destImage.width;\n        XMVECTOR* row1 = row0 + srcImage.width;\n        XMVECTOR* row2 = row0 + srcImage.width * 2;\n        XMVECTOR* row3 = row0 + srcImage.width * 3;\n\n    #ifdef _DEBUG\n        memset(row0, 0xCD, sizeof(XMVECTOR)*srcImage.width);\n        memset(row1, 0xDD, sizeof(XMVECTOR)*srcImage.width);\n        memset(row2, 0xED, sizeof(XMVECTOR)*srcImage.width);\n        memset(row3, 0xFD, sizeof(XMVECTOR)*srcImage.width);\n    #endif\n\n        const uint8_t* pSrc = srcImage.pixels;\n        uint8_t* pDest = destImage.pixels;\n\n        const size_t rowPitch = srcImage.rowPitch;\n\n        size_t u0 = size_t(-1);\n        size_t u1 = size_t(-1);\n        size_t u2 = size_t(-1);\n        size_t u3 = size_t(-1);\n\n        for (size_t y = 0; y < destImage.height; ++y)\n        {\n            auto const& toY = cfY[y];\n\n            // Scanline 1\n            if (toY.u0 != u0)\n            {\n                if (toY.u0 != u1 && toY.u0 != u2 && toY.u0 != u3)\n                {\n                    u0 = toY.u0;\n\n                    if (!LoadScanlineLinear(row0, srcImage.width, pSrc + (rowPitch * u0), rowPitch, srcImage.format, filter))\n                        return E_FAIL;\n                }\n                else if (toY.u0 == u1)\n                {\n                    u0 = u1;\n                    u1 = size_t(-1);\n\n                    std::swap(row0, row1);\n                }\n                else if (toY.u0 == u2)\n                {\n                    u0 = u2;\n                    u2 = size_t(-1);\n\n                    std::swap(row0, row2);\n                }\n                else if (toY.u0 == u3)\n                {\n                    u0 = u3;\n                    u3 = size_t(-1);\n\n                    std::swap(row0, row3);\n                }\n            }\n\n            // Scanline 2\n            if (toY.u1 != u1)\n            {\n                if (toY.u1 != u2 && toY.u1 != u3)\n                {\n                    u1 = toY.u1;\n\n                    if (!LoadScanlineLinear(row1, srcImage.width, pSrc + (rowPitch * u1), rowPitch, srcImage.format, filter))\n                        return E_FAIL;\n                }\n                else if (toY.u1 == u2)\n                {\n                    u1 = u2;\n                    u2 = size_t(-1);\n\n                    std::swap(row1, row2);\n                }\n                else if (toY.u1 == u3)\n                {\n                    u1 = u3;\n                    u3 = size_t(-1);\n\n                    std::swap(row1, row3);\n                }\n            }\n\n            // Scanline 3\n            if (toY.u2 != u2)\n            {\n                if (toY.u2 != u3)\n                {\n                    u2 = toY.u2;\n\n                    if (!LoadScanlineLinear(row2, srcImage.width, pSrc + (rowPitch * u2), rowPitch, srcImage.format, filter))\n                        return E_FAIL;\n                }\n                else\n                {\n                    u2 = u3;\n                    u3 = size_t(-1);\n\n                    std::swap(row2, row3);\n                }\n            }\n\n            // Scanline 4\n            if (toY.u3 != u3)\n            {\n                u3 = toY.u3;\n\n                if (!LoadScanlineLinear(row3, srcImage.width, pSrc + (rowPitch * u3), rowPitch, srcImage.format, filter))\n                    return E_FAIL;\n            }\n\n            for (size_t x = 0; x < destImage.width; ++x)\n            {\n                auto const& toX = cfX[x];\n\n                XMVECTOR C0, C1, C2, C3;\n\n                CUBIC_INTERPOLATE(C0, toX.x, row0[toX.u0], row0[toX.u1], row0[toX.u2], row0[toX.u3]);\n                CUBIC_INTERPOLATE(C1, toX.x, row1[toX.u0], row1[toX.u1], row1[toX.u2], row1[toX.u3]);\n                CUBIC_INTERPOLATE(C2, toX.x, row2[toX.u0], row2[toX.u1], row2[toX.u2], row2[toX.u3]);\n                CUBIC_INTERPOLATE(C3, toX.x, row3[toX.u0], row3[toX.u1], row3[toX.u2], row3[toX.u3]);\n\n                CUBIC_INTERPOLATE(target[x], toY.x, C0, C1, C2, C3);\n            }\n\n            if (!StoreScanlineLinear(pDest, destImage.rowPitch, destImage.format, target, destImage.width, filter))\n                return E_FAIL;\n            pDest += destImage.rowPitch;\n        }\n\n        return S_OK;\n    }\n\n\n    //--- Triangle Filter ---\n    HRESULT ResizeTriangleFilter(const Image& srcImage, TEX_FILTER_FLAGS filter, const Image& destImage) noexcept\n    {\n        using namespace DirectX::Filters;\n\n        assert(srcImage.pixels && destImage.pixels);\n        assert(srcImage.format == destImage.format);\n\n        // Allocate initial temporary space (1 scanline, accumulation rows, plus X and Y filters)\n        auto scanline = make_AlignedArrayXMVECTOR(srcImage.width);\n        if (!scanline)\n            return E_OUTOFMEMORY;\n\n        std::unique_ptr<TriangleRow[]> rowActive(new (std::nothrow) TriangleRow[destImage.height]);\n        if (!rowActive)\n            return E_OUTOFMEMORY;\n\n        TriangleRow * rowFree = nullptr;\n\n        std::unique_ptr<Filter> tfX;\n        HRESULT hr = CreateTriangleFilter(srcImage.width, destImage.width, (filter & TEX_FILTER_WRAP_U) != 0, tfX);\n        if (FAILED(hr))\n            return hr;\n\n        std::unique_ptr<Filter> tfY;\n        hr = CreateTriangleFilter(srcImage.height, destImage.height, (filter & TEX_FILTER_WRAP_V) != 0, tfY);\n        if (FAILED(hr))\n            return hr;\n\n        XMVECTOR* row = scanline.get();\n\n    #ifdef _DEBUG\n        memset(row, 0xCD, sizeof(XMVECTOR)*srcImage.width);\n    #endif\n\n        auto xFromEnd = reinterpret_cast<const FilterFrom*>(reinterpret_cast<const uint8_t*>(tfX.get()) + tfX->sizeInBytes);\n        auto yFromEnd = reinterpret_cast<const FilterFrom*>(reinterpret_cast<const uint8_t*>(tfY.get()) + tfY->sizeInBytes);\n\n        // Count times rows get written\n        for (FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; )\n        {\n            for (size_t j = 0; j < yFrom->count; ++j)\n            {\n                const size_t v = yFrom->to[j].u;\n                assert(v < destImage.height);\n                ++rowActive[v].remaining;\n            }\n\n            yFrom = reinterpret_cast<FilterFrom*>(reinterpret_cast<uint8_t*>(yFrom) + yFrom->sizeInBytes);\n        }\n\n        // Filter image\n        const uint8_t* pSrc = srcImage.pixels;\n        const size_t rowPitch = srcImage.rowPitch;\n        const uint8_t* pEndSrc = pSrc + rowPitch * srcImage.height;\n\n        uint8_t* pDest = destImage.pixels;\n\n        for (FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; )\n        {\n            // Create accumulation rows as needed\n            for (size_t j = 0; j < yFrom->count; ++j)\n            {\n                const size_t v = yFrom->to[j].u;\n                assert(v < destImage.height);\n                TriangleRow* rowAcc = &rowActive[v];\n\n                if (!rowAcc->scanline)\n                {\n                    if (rowFree)\n                    {\n                        // Steal and reuse scanline from 'free row' list\n                        assert(rowFree->scanline != nullptr);\n                        rowAcc->scanline.reset(rowFree->scanline.release());\n                        rowFree = rowFree->next;\n                    }\n                    else\n                    {\n                        auto nscanline = make_AlignedArrayXMVECTOR(destImage.width);\n                        if (!nscanline)\n                            return E_OUTOFMEMORY;\n                        rowAcc->scanline.swap(nscanline);\n                    }\n\n                    memset(rowAcc->scanline.get(), 0, sizeof(XMVECTOR) * destImage.width);\n                }\n            }\n\n            // Load source scanline\n            if ((pSrc + rowPitch) > pEndSrc)\n                return E_FAIL;\n\n            if (!LoadScanlineLinear(row, srcImage.width, pSrc, rowPitch, srcImage.format, filter))\n                return E_FAIL;\n\n            pSrc += rowPitch;\n\n            // Process row\n            size_t x = 0;\n            for (FilterFrom* xFrom = tfX->from; xFrom < xFromEnd; ++x)\n            {\n                for (size_t j = 0; j < yFrom->count; ++j)\n                {\n                    const size_t v = yFrom->to[j].u;\n                    assert(v < destImage.height);\n                    const float yweight = yFrom->to[j].weight;\n\n                    XMVECTOR* accPtr = rowActive[v].scanline.get();\n                    if (!accPtr)\n                        return E_POINTER;\n\n                    for (size_t k = 0; k < xFrom->count; ++k)\n                    {\n                        size_t u = xFrom->to[k].u;\n                        assert(u < destImage.width);\n\n                        const XMVECTOR weight = XMVectorReplicate(yweight * xFrom->to[k].weight);\n\n                        assert(x < srcImage.width);\n                        accPtr[u] = XMVectorMultiplyAdd(row[x], weight, accPtr[u]);\n                    }\n                }\n\n                xFrom = reinterpret_cast<FilterFrom*>(reinterpret_cast<uint8_t*>(xFrom) + xFrom->sizeInBytes);\n            }\n\n            // Write completed accumulation rows\n            for (size_t j = 0; j < yFrom->count; ++j)\n            {\n                size_t v = yFrom->to[j].u;\n                assert(v < destImage.height);\n                TriangleRow* rowAcc = &rowActive[v];\n\n                assert(rowAcc->remaining > 0);\n                --rowAcc->remaining;\n\n                if (!rowAcc->remaining)\n                {\n                    XMVECTOR* pAccSrc = rowAcc->scanline.get();\n                    if (!pAccSrc)\n                        return E_POINTER;\n\n                    switch (destImage.format)\n                    {\n                    case DXGI_FORMAT_R10G10B10A2_UNORM:\n                    case DXGI_FORMAT_R10G10B10A2_UINT:\n                        {\n                            // Need to slightly bias results for floating-point error accumulation which can\n                            // be visible with harshly quantized values\n                            static const XMVECTORF32 Bias = { { { 0.f, 0.f, 0.f, 0.1f } } };\n\n                            XMVECTOR* ptr = pAccSrc;\n                            for (size_t i = 0; i < destImage.width; ++i, ++ptr)\n                            {\n                                *ptr = XMVectorAdd(*ptr, Bias);\n                            }\n                        }\n                        break;\n\n                    default:\n                        break;\n                    }\n\n                    // This performs any required clamping\n                    if (!StoreScanlineLinear(pDest + (destImage.rowPitch * v), destImage.rowPitch, destImage.format, pAccSrc, destImage.width, filter))\n                        return E_FAIL;\n\n                    // Put row on freelist to reuse it's allocated scanline\n                    rowAcc->next = rowFree;\n                    rowFree = rowAcc;\n                }\n            }\n\n            yFrom = reinterpret_cast<FilterFrom*>(reinterpret_cast<uint8_t*>(yFrom) + yFrom->sizeInBytes);\n        }\n\n        return S_OK;\n    }\n\n\n    //--- Custom filter resize ---\n    HRESULT PerformResizeUsingCustomFilters(const Image& srcImage, TEX_FILTER_FLAGS filter, const Image& destImage) noexcept\n    {\n        if (!srcImage.pixels || !destImage.pixels)\n            return E_POINTER;\n\n        static_assert(TEX_FILTER_POINT == 0x100000, \"TEX_FILTER_ flag values don't match TEX_FILTER_MASK\");\n\n        unsigned long filter_select = filter & TEX_FILTER_MODE_MASK;\n        if (!filter_select)\n        {\n            // Default filter choice\n            filter_select = (((destImage.width << 1) == srcImage.width) && ((destImage.height << 1) == srcImage.height))\n                ? TEX_FILTER_BOX : TEX_FILTER_LINEAR;\n        }\n\n        switch (filter_select)\n        {\n        case TEX_FILTER_POINT:\n            return ResizePointFilter(srcImage, destImage);\n\n        case TEX_FILTER_BOX:\n            return ResizeBoxFilter(srcImage, filter, destImage);\n\n        case TEX_FILTER_LINEAR:\n            return ResizeLinearFilter(srcImage, filter, destImage);\n\n        case TEX_FILTER_CUBIC:\n            return ResizeCubicFilter(srcImage, filter, destImage);\n\n        case TEX_FILTER_TRIANGLE:\n            return ResizeTriangleFilter(srcImage, filter, destImage);\n\n        default:\n            return HRESULT_E_NOT_SUPPORTED;\n        }\n    }\n}\n\n\n//=====================================================================================\n// Entry-points\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n// Resize image\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::Resize(\n    const Image& srcImage,\n    size_t width,\n    size_t height,\n    TEX_FILTER_FLAGS filter,\n    ScratchImage& image) noexcept\n{\n    if (width == 0 || height == 0)\n        return E_INVALIDARG;\n\n    if ((srcImage.width > UINT32_MAX) || (srcImage.height > UINT32_MAX))\n        return E_INVALIDARG;\n\n    if ((width > UINT32_MAX) || (height > UINT32_MAX))\n        return E_INVALIDARG;\n\n    if (!srcImage.pixels)\n        return E_POINTER;\n\n    if (IsCompressed(srcImage.format))\n    {\n        // We don't support resizing compressed images\n        return HRESULT_E_NOT_SUPPORTED;\n    }\n\n#ifdef _WIN32\n    bool usewic = UseWICFiltering(srcImage.format, filter);\n\n    WICPixelFormatGUID pfGUID = {};\n    const bool wicpf = (usewic) ? DXGIToWIC(srcImage.format, pfGUID, true) : false;\n\n    if (usewic && !wicpf)\n    {\n        // Check to see if the source and/or result size is too big for WIC\n        const uint64_t expandedSize = uint64_t(width) * uint64_t(height) * sizeof(float) * 4;\n        const uint64_t expandedSize2 = uint64_t(srcImage.width) * uint64_t(srcImage.height) * sizeof(float) * 4;\n        if (expandedSize > UINT32_MAX || expandedSize2 > UINT32_MAX)\n        {\n            if (filter & TEX_FILTER_FORCE_WIC)\n                return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n            usewic = false;\n        }\n    }\n#endif // WIN32\n\n    HRESULT hr = image.Initialize2D(srcImage.format, width, height, 1, 1);\n    if (FAILED(hr))\n        return hr;\n\n    const Image *rimage = image.GetImage(0, 0, 0);\n    if (!rimage)\n        return E_POINTER;\n\n#ifdef _WIN32\n    if (usewic)\n    {\n        if (wicpf)\n        {\n            // Case 1: Source format is supported by Windows Imaging Component\n            hr = PerformResizeUsingWIC(srcImage, filter, pfGUID, *rimage);\n        }\n        else\n        {\n            // Case 2: Source format is not supported by WIC, so we have to convert, resize, and convert back\n            hr = PerformResizeViaF32(srcImage, filter, *rimage);\n        }\n    }\n    else\n    #endif\n    {\n        // Case 3: not using WIC resizing\n        hr = PerformResizeUsingCustomFilters(srcImage, filter, *rimage);\n    }\n\n    if (FAILED(hr))\n    {\n        image.Release();\n        return hr;\n    }\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Resize image (complex)\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::Resize(\n    const Image* srcImages,\n    size_t nimages,\n    const TexMetadata& metadata,\n    size_t width,\n    size_t height,\n    TEX_FILTER_FLAGS filter,\n    ScratchImage& result) noexcept\n{\n    if (!srcImages || !nimages || width == 0 || height == 0)\n        return E_INVALIDARG;\n\n    if ((width > UINT32_MAX) || (height > UINT32_MAX))\n        return E_INVALIDARG;\n\n    TexMetadata mdata2 = metadata;\n    mdata2.width = width;\n    mdata2.height = height;\n    mdata2.mipLevels = 1;\n    HRESULT hr = result.Initialize(mdata2);\n    if (FAILED(hr))\n        return hr;\n\n#ifdef _WIN32\n    bool usewic = !metadata.IsPMAlpha() && UseWICFiltering(metadata.format, filter);\n\n    WICPixelFormatGUID pfGUID = {};\n    const bool wicpf = (usewic) ? DXGIToWIC(metadata.format, pfGUID, true) : false;\n\n    if (usewic && !wicpf)\n    {\n        // Check to see if the source and/or result size is too big for WIC\n        const uint64_t expandedSize = uint64_t(width) * uint64_t(height) * sizeof(float) * 4;\n        const uint64_t expandedSize2 = uint64_t(metadata.width) * uint64_t(metadata.height) * sizeof(float) * 4;\n        if (expandedSize > UINT32_MAX || expandedSize2 > UINT32_MAX)\n        {\n            if (filter & TEX_FILTER_FORCE_WIC)\n                return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n            usewic = false;\n        }\n    }\n#endif\n\n    switch (metadata.dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n    case TEX_DIMENSION_TEXTURE2D:\n        assert(metadata.depth == 1);\n\n        for (size_t item = 0; item < metadata.arraySize; ++item)\n        {\n            const size_t srcIndex = metadata.ComputeIndex(0, item, 0);\n            if (srcIndex >= nimages)\n            {\n                result.Release();\n                return E_FAIL;\n            }\n\n            const Image* srcimg = &srcImages[srcIndex];\n            const Image* destimg = result.GetImage(0, item, 0);\n            if (!srcimg || !destimg)\n            {\n                result.Release();\n                return E_POINTER;\n            }\n\n            if (srcimg->format != metadata.format)\n            {\n                result.Release();\n                return E_FAIL;\n            }\n\n            if ((srcimg->width > UINT32_MAX) || (srcimg->height > UINT32_MAX))\n            {\n                result.Release();\n                return E_FAIL;\n            }\n\n        #ifdef _WIN32\n            if (usewic)\n            {\n                if (wicpf)\n                {\n                    // Case 1: Source format is supported by Windows Imaging Component\n                    hr = PerformResizeUsingWIC(*srcimg, filter, pfGUID, *destimg);\n                }\n                else\n                {\n                    // Case 2: Source format is not supported by WIC, so we have to convert, resize, and convert back\n                    hr = PerformResizeViaF32(*srcimg, filter, *destimg);\n                }\n            }\n            else\n            #endif\n            {\n                // Case 3: not using WIC resizing\n                hr = PerformResizeUsingCustomFilters(*srcimg, filter, *destimg);\n            }\n\n            if (FAILED(hr))\n            {\n                result.Release();\n                return hr;\n            }\n        }\n        break;\n\n    case TEX_DIMENSION_TEXTURE3D:\n        assert(metadata.arraySize == 1);\n\n        for (size_t slice = 0; slice < metadata.depth; ++slice)\n        {\n            const size_t srcIndex = metadata.ComputeIndex(0, 0, slice);\n            if (srcIndex >= nimages)\n            {\n                result.Release();\n                return E_FAIL;\n            }\n\n            const Image* srcimg = &srcImages[srcIndex];\n            const Image* destimg = result.GetImage(0, 0, slice);\n            if (!srcimg || !destimg)\n            {\n                result.Release();\n                return E_POINTER;\n            }\n\n            if (srcimg->format != metadata.format)\n            {\n                result.Release();\n                return E_FAIL;\n            }\n\n            if ((srcimg->width > UINT32_MAX) || (srcimg->height > UINT32_MAX))\n            {\n                result.Release();\n                return E_FAIL;\n            }\n\n        #ifdef _WIN32\n            if (usewic)\n            {\n                if (wicpf)\n                {\n                    // Case 1: Source format is supported by Windows Imaging Component\n                    hr = PerformResizeUsingWIC(*srcimg, filter, pfGUID, *destimg);\n                }\n                else\n                {\n                    // Case 2: Source format is not supported by WIC, so we have to convert, resize, and convert back\n                    hr = PerformResizeViaF32(*srcimg, filter, *destimg);\n                }\n            }\n            else\n            #endif\n            {\n                // Case 3: not using WIC resizing\n                hr = PerformResizeUsingCustomFilters(*srcimg, filter, *destimg);\n            }\n\n            if (FAILED(hr))\n            {\n                result.Release();\n                return hr;\n            }\n        }\n        break;\n\n    default:\n        result.Release();\n        return E_FAIL;\n    }\n\n    return S_OK;\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTexUtil.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTexUtil.cpp\n//\n// DirectX Texture Library - Utilities\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\n#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\nstatic_assert(XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT == DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT, \"Xbox mismatch detected\");\nstatic_assert(XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT == DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT, \"Xbox mismatch detected\");\nstatic_assert(XBOX_DXGI_FORMAT_D16_UNORM_S8_UINT == DXGI_FORMAT_D16_UNORM_S8_UINT, \"Xbox mismatch detected\");\nstatic_assert(XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS == DXGI_FORMAT_R16_UNORM_X8_TYPELESS, \"Xbox mismatch detected\");\nstatic_assert(XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT == DXGI_FORMAT_X16_TYPELESS_G8_UINT, \"Xbox mismatch detected\");\nstatic_assert(XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM == DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM, \"Xbox mismatch detected\");\nstatic_assert(XBOX_DXGI_FORMAT_R4G4_UNORM == DXGI_FORMAT_R4G4_UNORM, \"Xbox mismatch detected\");\n#endif\n\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10)\nstatic_assert(WIN10_DXGI_FORMAT_P208 == DXGI_FORMAT_P208, \"Windows SDK mismatch detected\");\nstatic_assert(WIN10_DXGI_FORMAT_V208 == DXGI_FORMAT_V208, \"Windows SDK mismatch detected\");\nstatic_assert(WIN10_DXGI_FORMAT_V408 == DXGI_FORMAT_V408, \"Windows SDK mismatch detected\");\n#endif\n\nusing namespace DirectX;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n#ifdef _WIN32\n    //-------------------------------------------------------------------------------------\n    // WIC Pixel Format Translation Data\n    //-------------------------------------------------------------------------------------\n    struct WICTranslate\n    {\n        const GUID& wic;\n        DXGI_FORMAT format;\n        bool        srgb;\n    };\n\n    constexpr WICTranslate g_WICFormats[] =\n    {\n        { GUID_WICPixelFormat128bppRGBAFloat,       DXGI_FORMAT_R32G32B32A32_FLOAT,         false },\n\n        { GUID_WICPixelFormat64bppRGBAHalf,         DXGI_FORMAT_R16G16B16A16_FLOAT,         false },\n        { GUID_WICPixelFormat64bppRGBA,             DXGI_FORMAT_R16G16B16A16_UNORM,         true },\n\n        { GUID_WICPixelFormat32bppRGBA,             DXGI_FORMAT_R8G8B8A8_UNORM,             true },\n        { GUID_WICPixelFormat32bppBGRA,             DXGI_FORMAT_B8G8R8A8_UNORM,             true }, // DXGI 1.1\n        { GUID_WICPixelFormat32bppBGR,              DXGI_FORMAT_B8G8R8X8_UNORM,             true }, // DXGI 1.1\n\n        { GUID_WICPixelFormat32bppRGBA1010102XR,    DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, true }, // DXGI 1.1\n        { GUID_WICPixelFormat32bppRGBA1010102,      DXGI_FORMAT_R10G10B10A2_UNORM,          true },\n\n        { GUID_WICPixelFormat16bppBGRA5551,         DXGI_FORMAT_B5G5R5A1_UNORM,             true },\n        { GUID_WICPixelFormat16bppBGR565,           DXGI_FORMAT_B5G6R5_UNORM,               true },\n\n        { GUID_WICPixelFormat32bppGrayFloat,        DXGI_FORMAT_R32_FLOAT,                  false },\n        { GUID_WICPixelFormat16bppGrayHalf,         DXGI_FORMAT_R16_FLOAT,                  false },\n        { GUID_WICPixelFormat16bppGray,             DXGI_FORMAT_R16_UNORM,                  true },\n        { GUID_WICPixelFormat8bppGray,              DXGI_FORMAT_R8_UNORM,                   true },\n\n        { GUID_WICPixelFormat8bppAlpha,             DXGI_FORMAT_A8_UNORM,                   false },\n\n        { GUID_WICPixelFormatBlackWhite,            DXGI_FORMAT_R1_UNORM,                   false },\n    };\n\n    bool g_WIC2 = false;\n    IWICImagingFactory* g_Factory = nullptr;\n\n    BOOL WINAPI InitializeWICFactory(PINIT_ONCE, PVOID, PVOID *ifactory) noexcept\n    {\n    #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE)\n        HRESULT hr = CoCreateInstance(\n            CLSID_WICImagingFactory2,\n            nullptr,\n            CLSCTX_INPROC_SERVER,\n            __uuidof(IWICImagingFactory2),\n            ifactory\n        );\n\n        if (SUCCEEDED(hr))\n        {\n            // WIC2 is available on Windows 10, Windows 8.x, and Windows 7 SP1 with KB 2670838 installed\n            g_WIC2 = true;\n            return TRUE;\n        }\n        else\n        {\n            g_WIC2 = false;\n\n            hr = CoCreateInstance(\n                CLSID_WICImagingFactory1,\n                nullptr,\n                CLSCTX_INPROC_SERVER,\n                __uuidof(IWICImagingFactory),\n                ifactory\n            );\n            return SUCCEEDED(hr) ? TRUE : FALSE;\n        }\n    #else\n        g_WIC2 = false;\n\n        return SUCCEEDED(CoCreateInstance(\n            CLSID_WICImagingFactory,\n            nullptr,\n            CLSCTX_INPROC_SERVER,\n            __uuidof(IWICImagingFactory),\n            ifactory)) ? TRUE : FALSE;\n    #endif\n    }\n\n#else // !WIN32\n    inline void * _aligned_malloc(size_t size, size_t alignment)\n    {\n        size = (size + alignment - 1) & ~(alignment - 1);\n        return std::aligned_alloc(alignment, size);\n    }\n\n#define _aligned_free free\n#endif\n}\n\n\n#ifdef _WIN32\n//=====================================================================================\n// WIC Utilities\n//=====================================================================================\n\n_Use_decl_annotations_\nDXGI_FORMAT DirectX::Internal::WICToDXGI(const GUID& guid) noexcept\n{\n    for (size_t i = 0; i < std::size(g_WICFormats); ++i)\n    {\n        if (memcmp(&g_WICFormats[i].wic, &guid, sizeof(GUID)) == 0)\n            return g_WICFormats[i].format;\n    }\n\n#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE)\n    if (g_WIC2)\n    {\n        if (memcmp(&GUID_WICPixelFormat96bppRGBFloat, &guid, sizeof(GUID)) == 0)\n            return DXGI_FORMAT_R32G32B32_FLOAT;\n    }\n#endif\n\n    return DXGI_FORMAT_UNKNOWN;\n}\n\n_Use_decl_annotations_\nbool DirectX::Internal::DXGIToWIC(DXGI_FORMAT format, GUID& guid, bool ignoreRGBvsBGR) noexcept\n{\n    switch (format)\n    {\n    case DXGI_FORMAT_R8G8B8A8_UNORM:\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n        if (ignoreRGBvsBGR)\n        {\n            // If we are not doing conversion so don't really care about BGR vs RGB color-order,\n            // we can use the canonical WIC 32bppBGRA format which avoids an extra format conversion when using the WIC scaler\n            memcpy(&guid, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));\n        }\n        else\n        {\n            memcpy(&guid, &GUID_WICPixelFormat32bppRGBA, sizeof(GUID));\n        }\n        return true;\n\n    case DXGI_FORMAT_D32_FLOAT:\n        memcpy(&guid, &GUID_WICPixelFormat32bppGrayFloat, sizeof(GUID));\n        return true;\n\n    case DXGI_FORMAT_D16_UNORM:\n        memcpy(&guid, &GUID_WICPixelFormat16bppGray, sizeof(GUID));\n        return true;\n\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n        memcpy(&guid, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));\n        return true;\n\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n        memcpy(&guid, &GUID_WICPixelFormat32bppBGR, sizeof(GUID));\n        return true;\n\n    #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE)\n    case DXGI_FORMAT_R32G32B32_FLOAT:\n        if (g_WIC2)\n        {\n            memcpy(&guid, &GUID_WICPixelFormat96bppRGBFloat, sizeof(GUID));\n            return true;\n        }\n        break;\n    #endif\n\n    default:\n        for (size_t i = 0; i < std::size(g_WICFormats); ++i)\n        {\n            if (g_WICFormats[i].format == format)\n            {\n                memcpy(&guid, &g_WICFormats[i].wic, sizeof(GUID));\n                return true;\n            }\n        }\n        break;\n    }\n\n    memset(&guid, 0, sizeof(GUID));\n    return false;\n}\n\nTEX_FILTER_FLAGS DirectX::Internal::CheckWICColorSpace(_In_ const GUID& sourceGUID, _In_ const GUID& targetGUID) noexcept\n{\n    TEX_FILTER_FLAGS srgb = TEX_FILTER_DEFAULT;\n\n    for (size_t i = 0; i < std::size(g_WICFormats); ++i)\n    {\n        if (memcmp(&g_WICFormats[i].wic, &sourceGUID, sizeof(GUID)) == 0)\n        {\n            if (g_WICFormats[i].srgb)\n                srgb |= TEX_FILTER_SRGB_IN;\n        }\n\n        if (memcmp(&g_WICFormats[i].wic, &targetGUID, sizeof(GUID)) == 0)\n        {\n            if (g_WICFormats[i].srgb)\n                srgb |= TEX_FILTER_SRGB_OUT;\n        }\n    }\n\n    if ((srgb & (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT))\n    {\n        srgb &= ~(TEX_FILTER_SRGB_IN | TEX_FILTER_SRGB_OUT);\n    }\n\n    return srgb;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Public helper function to get common WIC codec GUIDs\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nREFGUID DirectX::GetWICCodec(WICCodecs codec) noexcept\n{\n    switch (codec)\n    {\n    case WIC_CODEC_BMP:\n        return GUID_ContainerFormatBmp;\n\n    case WIC_CODEC_JPEG:\n        return GUID_ContainerFormatJpeg;\n\n    case WIC_CODEC_PNG:\n        return GUID_ContainerFormatPng;\n\n    case WIC_CODEC_TIFF:\n        return GUID_ContainerFormatTiff;\n\n    case WIC_CODEC_GIF:\n        return GUID_ContainerFormatGif;\n\n    case WIC_CODEC_WMP:\n        return GUID_ContainerFormatWmp;\n\n    case WIC_CODEC_ICO:\n        return GUID_ContainerFormatIco;\n\n#ifdef NTDDI_WIN10_RS4\n    case WIC_CODEC_HEIF:\n        // This requires installing https://aka.ms/heif\n        return GUID_ContainerFormatHeif;\n#endif\n\n    default:\n        return GUID_NULL;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// Singleton function for WIC factory\n//-------------------------------------------------------------------------------------\nIWICImagingFactory* DirectX::GetWICFactory(bool& iswic2) noexcept\n{\n    if (g_Factory)\n    {\n        iswic2 = g_WIC2;\n        return g_Factory;\n    }\n\n    static INIT_ONCE s_initOnce = INIT_ONCE_STATIC_INIT;\n\n    if (!InitOnceExecuteOnce(&s_initOnce,\n        InitializeWICFactory,\n        nullptr,\n        reinterpret_cast<LPVOID*>(&g_Factory)))\n    {\n        return nullptr;\n    }\n\n    iswic2 = g_WIC2;\n    return g_Factory;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Optional initializer for WIC factory\n//-------------------------------------------------------------------------------------\nvoid DirectX::SetWICFactory(_In_opt_ IWICImagingFactory* pWIC) noexcept\n{\n    if (pWIC == g_Factory)\n        return;\n\n    bool iswic2 = false;\n    if (pWIC)\n    {\n    #if(_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE)\n        ComPtr<IWICImagingFactory2> wic2;\n        HRESULT hr = pWIC->QueryInterface(IID_PPV_ARGS(wic2.GetAddressOf()));\n        if (SUCCEEDED(hr))\n        {\n            iswic2 = true;\n        }\n    #endif\n        pWIC->AddRef();\n    }\n\n    g_WIC2 = iswic2;\n    std::swap(pWIC, g_Factory);\n    if (pWIC)\n        pWIC->Release();\n}\n#endif // WIN32\n\n\n//=====================================================================================\n// DXGI Format Utilities\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nbool DirectX::IsPacked(DXGI_FORMAT fmt) noexcept\n{\n    switch (static_cast<int>(fmt))\n    {\n    case DXGI_FORMAT_R8G8_B8G8_UNORM:\n    case DXGI_FORMAT_G8R8_G8B8_UNORM:\n    case DXGI_FORMAT_YUY2: // 4:2:2 8-bit\n    case DXGI_FORMAT_Y210: // 4:2:2 10-bit\n    case DXGI_FORMAT_Y216: // 4:2:2 16-bit\n        return true;\n\n    default:\n        return false;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nbool DirectX::IsVideo(DXGI_FORMAT fmt) noexcept\n{\n    switch (static_cast<int>(fmt))\n    {\n    case DXGI_FORMAT_AYUV:\n    case DXGI_FORMAT_Y410:\n    case DXGI_FORMAT_Y416:\n    case DXGI_FORMAT_NV12:\n    case DXGI_FORMAT_P010:\n    case DXGI_FORMAT_P016:\n    case DXGI_FORMAT_YUY2:\n    case DXGI_FORMAT_Y210:\n    case DXGI_FORMAT_Y216:\n    case DXGI_FORMAT_NV11:\n        // These video formats can be used with the 3D pipeline through special view mappings\n\n    case DXGI_FORMAT_420_OPAQUE:\n    case DXGI_FORMAT_AI44:\n    case DXGI_FORMAT_IA44:\n    case DXGI_FORMAT_P8:\n    case DXGI_FORMAT_A8P8:\n        // These are limited use video formats not usable in any way by the 3D pipeline\n\n    case WIN10_DXGI_FORMAT_P208:\n    case WIN10_DXGI_FORMAT_V208:\n    case WIN10_DXGI_FORMAT_V408:\n        // These video formats are for JPEG Hardware decode (DXGI 1.4)\n        return true;\n\n    default:\n        return false;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nbool DirectX::IsPlanar(DXGI_FORMAT fmt) noexcept\n{\n    switch (static_cast<int>(fmt))\n    {\n    case DXGI_FORMAT_NV12:      // 4:2:0 8-bit\n    case DXGI_FORMAT_P010:      // 4:2:0 10-bit\n    case DXGI_FORMAT_P016:      // 4:2:0 16-bit\n    case DXGI_FORMAT_420_OPAQUE:// 4:2:0 8-bit\n    case DXGI_FORMAT_NV11:      // 4:1:1 8-bit\n\n    case WIN10_DXGI_FORMAT_P208: // 4:2:2 8-bit\n    case WIN10_DXGI_FORMAT_V208: // 4:4:0 8-bit\n    case WIN10_DXGI_FORMAT_V408: // 4:4:4 8-bit\n        // These are JPEG Hardware decode formats (DXGI 1.4)\n\n    case XBOX_DXGI_FORMAT_D16_UNORM_S8_UINT:\n    case XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS:\n    case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT:\n        // These are Xbox One platform specific types\n        return true;\n\n    default:\n        return false;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nbool DirectX::IsDepthStencil(DXGI_FORMAT fmt) noexcept\n{\n    switch (static_cast<int>(fmt))\n    {\n    case DXGI_FORMAT_R32G8X24_TYPELESS:\n    case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:\n    case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:\n    case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:\n    case DXGI_FORMAT_D32_FLOAT:\n    case DXGI_FORMAT_R24G8_TYPELESS:\n    case DXGI_FORMAT_D24_UNORM_S8_UINT:\n    case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:\n    case DXGI_FORMAT_X24_TYPELESS_G8_UINT:\n    case DXGI_FORMAT_D16_UNORM:\n    case XBOX_DXGI_FORMAT_D16_UNORM_S8_UINT:\n    case XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS:\n    case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT:\n        return true;\n\n    default:\n        return false;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nbool DirectX::IsTypeless(DXGI_FORMAT fmt, bool partialTypeless) noexcept\n{\n    switch (static_cast<int>(fmt))\n    {\n    case DXGI_FORMAT_R32G32B32A32_TYPELESS:\n    case DXGI_FORMAT_R32G32B32_TYPELESS:\n    case DXGI_FORMAT_R16G16B16A16_TYPELESS:\n    case DXGI_FORMAT_R32G32_TYPELESS:\n    case DXGI_FORMAT_R32G8X24_TYPELESS:\n    case DXGI_FORMAT_R10G10B10A2_TYPELESS:\n    case DXGI_FORMAT_R8G8B8A8_TYPELESS:\n    case DXGI_FORMAT_R16G16_TYPELESS:\n    case DXGI_FORMAT_R32_TYPELESS:\n    case DXGI_FORMAT_R24G8_TYPELESS:\n    case DXGI_FORMAT_R8G8_TYPELESS:\n    case DXGI_FORMAT_R16_TYPELESS:\n    case DXGI_FORMAT_R8_TYPELESS:\n    case DXGI_FORMAT_BC1_TYPELESS:\n    case DXGI_FORMAT_BC2_TYPELESS:\n    case DXGI_FORMAT_BC3_TYPELESS:\n    case DXGI_FORMAT_BC4_TYPELESS:\n    case DXGI_FORMAT_BC5_TYPELESS:\n    case DXGI_FORMAT_B8G8R8A8_TYPELESS:\n    case DXGI_FORMAT_B8G8R8X8_TYPELESS:\n    case DXGI_FORMAT_BC6H_TYPELESS:\n    case DXGI_FORMAT_BC7_TYPELESS:\n        return true;\n\n    case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:\n    case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:\n    case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:\n    case DXGI_FORMAT_X24_TYPELESS_G8_UINT:\n    case XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS:\n    case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT:\n        return partialTypeless;\n\n    default:\n        return false;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nbool DirectX::HasAlpha(DXGI_FORMAT fmt) noexcept\n{\n    switch (static_cast<int>(fmt))\n    {\n    case DXGI_FORMAT_R32G32B32A32_TYPELESS:\n    case DXGI_FORMAT_R32G32B32A32_FLOAT:\n    case DXGI_FORMAT_R32G32B32A32_UINT:\n    case DXGI_FORMAT_R32G32B32A32_SINT:\n    case DXGI_FORMAT_R16G16B16A16_TYPELESS:\n    case DXGI_FORMAT_R16G16B16A16_FLOAT:\n    case DXGI_FORMAT_R16G16B16A16_UNORM:\n    case DXGI_FORMAT_R16G16B16A16_UINT:\n    case DXGI_FORMAT_R16G16B16A16_SNORM:\n    case DXGI_FORMAT_R16G16B16A16_SINT:\n    case DXGI_FORMAT_R10G10B10A2_TYPELESS:\n    case DXGI_FORMAT_R10G10B10A2_UNORM:\n    case DXGI_FORMAT_R10G10B10A2_UINT:\n    case DXGI_FORMAT_R8G8B8A8_TYPELESS:\n    case DXGI_FORMAT_R8G8B8A8_UNORM:\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n    case DXGI_FORMAT_R8G8B8A8_UINT:\n    case DXGI_FORMAT_R8G8B8A8_SNORM:\n    case DXGI_FORMAT_R8G8B8A8_SINT:\n    case DXGI_FORMAT_A8_UNORM:\n    case DXGI_FORMAT_BC1_TYPELESS:\n    case DXGI_FORMAT_BC1_UNORM:\n    case DXGI_FORMAT_BC1_UNORM_SRGB:\n    case DXGI_FORMAT_BC2_TYPELESS:\n    case DXGI_FORMAT_BC2_UNORM:\n    case DXGI_FORMAT_BC2_UNORM_SRGB:\n    case DXGI_FORMAT_BC3_TYPELESS:\n    case DXGI_FORMAT_BC3_UNORM:\n    case DXGI_FORMAT_BC3_UNORM_SRGB:\n    case DXGI_FORMAT_B5G5R5A1_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_UNORM:\n    case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_TYPELESS:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n    case DXGI_FORMAT_BC7_TYPELESS:\n    case DXGI_FORMAT_BC7_UNORM:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n    case DXGI_FORMAT_AYUV:\n    case DXGI_FORMAT_Y410:\n    case DXGI_FORMAT_Y416:\n    case DXGI_FORMAT_AI44:\n    case DXGI_FORMAT_IA44:\n    case DXGI_FORMAT_A8P8:\n    case DXGI_FORMAT_B4G4R4A4_UNORM:\n    case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT:\n    case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT:\n    case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:\n        return true;\n\n    default:\n        return false;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// Returns bits-per-pixel for a given DXGI format, or 0 on failure\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nsize_t DirectX::BitsPerPixel(DXGI_FORMAT fmt) noexcept\n{\n    switch (static_cast<int>(fmt))\n    {\n    case DXGI_FORMAT_R32G32B32A32_TYPELESS:\n    case DXGI_FORMAT_R32G32B32A32_FLOAT:\n    case DXGI_FORMAT_R32G32B32A32_UINT:\n    case DXGI_FORMAT_R32G32B32A32_SINT:\n        return 128;\n\n    case DXGI_FORMAT_R32G32B32_TYPELESS:\n    case DXGI_FORMAT_R32G32B32_FLOAT:\n    case DXGI_FORMAT_R32G32B32_UINT:\n    case DXGI_FORMAT_R32G32B32_SINT:\n        return 96;\n\n    case DXGI_FORMAT_R16G16B16A16_TYPELESS:\n    case DXGI_FORMAT_R16G16B16A16_FLOAT:\n    case DXGI_FORMAT_R16G16B16A16_UNORM:\n    case DXGI_FORMAT_R16G16B16A16_UINT:\n    case DXGI_FORMAT_R16G16B16A16_SNORM:\n    case DXGI_FORMAT_R16G16B16A16_SINT:\n    case DXGI_FORMAT_R32G32_TYPELESS:\n    case DXGI_FORMAT_R32G32_FLOAT:\n    case DXGI_FORMAT_R32G32_UINT:\n    case DXGI_FORMAT_R32G32_SINT:\n    case DXGI_FORMAT_R32G8X24_TYPELESS:\n    case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:\n    case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:\n    case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:\n    case DXGI_FORMAT_Y416:\n    case DXGI_FORMAT_Y210:\n    case DXGI_FORMAT_Y216:\n        return 64;\n\n    case DXGI_FORMAT_R10G10B10A2_TYPELESS:\n    case DXGI_FORMAT_R10G10B10A2_UNORM:\n    case DXGI_FORMAT_R10G10B10A2_UINT:\n    case DXGI_FORMAT_R11G11B10_FLOAT:\n    case DXGI_FORMAT_R8G8B8A8_TYPELESS:\n    case DXGI_FORMAT_R8G8B8A8_UNORM:\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n    case DXGI_FORMAT_R8G8B8A8_UINT:\n    case DXGI_FORMAT_R8G8B8A8_SNORM:\n    case DXGI_FORMAT_R8G8B8A8_SINT:\n    case DXGI_FORMAT_R16G16_TYPELESS:\n    case DXGI_FORMAT_R16G16_FLOAT:\n    case DXGI_FORMAT_R16G16_UNORM:\n    case DXGI_FORMAT_R16G16_UINT:\n    case DXGI_FORMAT_R16G16_SNORM:\n    case DXGI_FORMAT_R16G16_SINT:\n    case DXGI_FORMAT_R32_TYPELESS:\n    case DXGI_FORMAT_D32_FLOAT:\n    case DXGI_FORMAT_R32_FLOAT:\n    case DXGI_FORMAT_R32_UINT:\n    case DXGI_FORMAT_R32_SINT:\n    case DXGI_FORMAT_R24G8_TYPELESS:\n    case DXGI_FORMAT_D24_UNORM_S8_UINT:\n    case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:\n    case DXGI_FORMAT_X24_TYPELESS_G8_UINT:\n    case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:\n    case DXGI_FORMAT_R8G8_B8G8_UNORM:\n    case DXGI_FORMAT_G8R8_G8B8_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_UNORM:\n    case DXGI_FORMAT_B8G8R8X8_UNORM:\n    case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_TYPELESS:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8X8_TYPELESS:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n    case DXGI_FORMAT_AYUV:\n    case DXGI_FORMAT_Y410:\n    case DXGI_FORMAT_YUY2:\n    case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT:\n    case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT:\n    case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:\n        return 32;\n\n    case DXGI_FORMAT_P010:\n    case DXGI_FORMAT_P016:\n    case XBOX_DXGI_FORMAT_D16_UNORM_S8_UINT:\n    case XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS:\n    case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT:\n    case WIN10_DXGI_FORMAT_V408:\n        return 24;\n\n    case DXGI_FORMAT_R8G8_TYPELESS:\n    case DXGI_FORMAT_R8G8_UNORM:\n    case DXGI_FORMAT_R8G8_UINT:\n    case DXGI_FORMAT_R8G8_SNORM:\n    case DXGI_FORMAT_R8G8_SINT:\n    case DXGI_FORMAT_R16_TYPELESS:\n    case DXGI_FORMAT_R16_FLOAT:\n    case DXGI_FORMAT_D16_UNORM:\n    case DXGI_FORMAT_R16_UNORM:\n    case DXGI_FORMAT_R16_UINT:\n    case DXGI_FORMAT_R16_SNORM:\n    case DXGI_FORMAT_R16_SINT:\n    case DXGI_FORMAT_B5G6R5_UNORM:\n    case DXGI_FORMAT_B5G5R5A1_UNORM:\n    case DXGI_FORMAT_A8P8:\n    case DXGI_FORMAT_B4G4R4A4_UNORM:\n    case WIN10_DXGI_FORMAT_P208:\n    case WIN10_DXGI_FORMAT_V208:\n        return 16;\n\n    case DXGI_FORMAT_NV12:\n    case DXGI_FORMAT_420_OPAQUE:\n    case DXGI_FORMAT_NV11:\n        return 12;\n\n    case DXGI_FORMAT_R8_TYPELESS:\n    case DXGI_FORMAT_R8_UNORM:\n    case DXGI_FORMAT_R8_UINT:\n    case DXGI_FORMAT_R8_SNORM:\n    case DXGI_FORMAT_R8_SINT:\n    case DXGI_FORMAT_A8_UNORM:\n    case DXGI_FORMAT_BC2_TYPELESS:\n    case DXGI_FORMAT_BC2_UNORM:\n    case DXGI_FORMAT_BC2_UNORM_SRGB:\n    case DXGI_FORMAT_BC3_TYPELESS:\n    case DXGI_FORMAT_BC3_UNORM:\n    case DXGI_FORMAT_BC3_UNORM_SRGB:\n    case DXGI_FORMAT_BC5_TYPELESS:\n    case DXGI_FORMAT_BC5_UNORM:\n    case DXGI_FORMAT_BC5_SNORM:\n    case DXGI_FORMAT_BC6H_TYPELESS:\n    case DXGI_FORMAT_BC6H_UF16:\n    case DXGI_FORMAT_BC6H_SF16:\n    case DXGI_FORMAT_BC7_TYPELESS:\n    case DXGI_FORMAT_BC7_UNORM:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n    case DXGI_FORMAT_AI44:\n    case DXGI_FORMAT_IA44:\n    case DXGI_FORMAT_P8:\n    case XBOX_DXGI_FORMAT_R4G4_UNORM:\n        return 8;\n\n    case DXGI_FORMAT_R1_UNORM:\n        return 1;\n\n    case DXGI_FORMAT_BC1_TYPELESS:\n    case DXGI_FORMAT_BC1_UNORM:\n    case DXGI_FORMAT_BC1_UNORM_SRGB:\n    case DXGI_FORMAT_BC4_TYPELESS:\n    case DXGI_FORMAT_BC4_UNORM:\n    case DXGI_FORMAT_BC4_SNORM:\n        return 4;\n\n    default:\n        return 0;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// Returns bits-per-color-channel for a given DXGI format, or 0 on failure\n// For mixed formats, it returns the largest color-depth in the format\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nsize_t DirectX::BitsPerColor(DXGI_FORMAT fmt) noexcept\n{\n    switch (static_cast<int>(fmt))\n    {\n    case DXGI_FORMAT_R32G32B32A32_TYPELESS:\n    case DXGI_FORMAT_R32G32B32A32_FLOAT:\n    case DXGI_FORMAT_R32G32B32A32_UINT:\n    case DXGI_FORMAT_R32G32B32A32_SINT:\n    case DXGI_FORMAT_R32G32B32_TYPELESS:\n    case DXGI_FORMAT_R32G32B32_FLOAT:\n    case DXGI_FORMAT_R32G32B32_UINT:\n    case DXGI_FORMAT_R32G32B32_SINT:\n    case DXGI_FORMAT_R32G32_TYPELESS:\n    case DXGI_FORMAT_R32G32_FLOAT:\n    case DXGI_FORMAT_R32G32_UINT:\n    case DXGI_FORMAT_R32G32_SINT:\n    case DXGI_FORMAT_R32G8X24_TYPELESS:\n    case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:\n    case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:\n    case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:\n    case DXGI_FORMAT_R32_TYPELESS:\n    case DXGI_FORMAT_D32_FLOAT:\n    case DXGI_FORMAT_R32_FLOAT:\n    case DXGI_FORMAT_R32_UINT:\n    case DXGI_FORMAT_R32_SINT:\n        return 32;\n\n    case DXGI_FORMAT_R24G8_TYPELESS:\n    case DXGI_FORMAT_D24_UNORM_S8_UINT:\n    case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:\n    case DXGI_FORMAT_X24_TYPELESS_G8_UINT:\n        return 24;\n\n    case DXGI_FORMAT_R16G16B16A16_TYPELESS:\n    case DXGI_FORMAT_R16G16B16A16_FLOAT:\n    case DXGI_FORMAT_R16G16B16A16_UNORM:\n    case DXGI_FORMAT_R16G16B16A16_UINT:\n    case DXGI_FORMAT_R16G16B16A16_SNORM:\n    case DXGI_FORMAT_R16G16B16A16_SINT:\n    case DXGI_FORMAT_R16G16_TYPELESS:\n    case DXGI_FORMAT_R16G16_FLOAT:\n    case DXGI_FORMAT_R16G16_UNORM:\n    case DXGI_FORMAT_R16G16_UINT:\n    case DXGI_FORMAT_R16G16_SNORM:\n    case DXGI_FORMAT_R16G16_SINT:\n    case DXGI_FORMAT_R16_TYPELESS:\n    case DXGI_FORMAT_R16_FLOAT:\n    case DXGI_FORMAT_D16_UNORM:\n    case DXGI_FORMAT_R16_UNORM:\n    case DXGI_FORMAT_R16_UINT:\n    case DXGI_FORMAT_R16_SNORM:\n    case DXGI_FORMAT_R16_SINT:\n    case DXGI_FORMAT_BC6H_TYPELESS:\n    case DXGI_FORMAT_BC6H_UF16:\n    case DXGI_FORMAT_BC6H_SF16:\n    case DXGI_FORMAT_Y416:\n    case DXGI_FORMAT_P016:\n    case DXGI_FORMAT_Y216:\n    case XBOX_DXGI_FORMAT_D16_UNORM_S8_UINT:\n    case XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS:\n    case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT:\n        return 16;\n\n    case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:\n        return 14;\n\n    case DXGI_FORMAT_R11G11B10_FLOAT:\n        return 11;\n\n    case DXGI_FORMAT_R10G10B10A2_TYPELESS:\n    case DXGI_FORMAT_R10G10B10A2_UNORM:\n    case DXGI_FORMAT_R10G10B10A2_UINT:\n    case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:\n    case DXGI_FORMAT_Y410:\n    case DXGI_FORMAT_P010:\n    case DXGI_FORMAT_Y210:\n    case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT:\n    case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT:\n    case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:\n        return 10;\n\n    case DXGI_FORMAT_R8G8B8A8_TYPELESS:\n    case DXGI_FORMAT_R8G8B8A8_UNORM:\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n    case DXGI_FORMAT_R8G8B8A8_UINT:\n    case DXGI_FORMAT_R8G8B8A8_SNORM:\n    case DXGI_FORMAT_R8G8B8A8_SINT:\n    case DXGI_FORMAT_R8G8_TYPELESS:\n    case DXGI_FORMAT_R8G8_UNORM:\n    case DXGI_FORMAT_R8G8_UINT:\n    case DXGI_FORMAT_R8G8_SNORM:\n    case DXGI_FORMAT_R8G8_SINT:\n    case DXGI_FORMAT_R8_TYPELESS:\n    case DXGI_FORMAT_R8_UNORM:\n    case DXGI_FORMAT_R8_UINT:\n    case DXGI_FORMAT_R8_SNORM:\n    case DXGI_FORMAT_R8_SINT:\n    case DXGI_FORMAT_A8_UNORM:\n    case DXGI_FORMAT_R8G8_B8G8_UNORM:\n    case DXGI_FORMAT_G8R8_G8B8_UNORM:\n    case DXGI_FORMAT_BC4_TYPELESS:\n    case DXGI_FORMAT_BC4_UNORM:\n    case DXGI_FORMAT_BC4_SNORM:\n    case DXGI_FORMAT_BC5_TYPELESS:\n    case DXGI_FORMAT_BC5_UNORM:\n    case DXGI_FORMAT_BC5_SNORM:\n    case DXGI_FORMAT_B8G8R8A8_UNORM:\n    case DXGI_FORMAT_B8G8R8X8_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_TYPELESS:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n    case DXGI_FORMAT_B8G8R8X8_TYPELESS:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n    case DXGI_FORMAT_AYUV:\n    case DXGI_FORMAT_NV12:\n    case DXGI_FORMAT_420_OPAQUE:\n    case DXGI_FORMAT_YUY2:\n    case DXGI_FORMAT_NV11:\n    case WIN10_DXGI_FORMAT_P208:\n    case WIN10_DXGI_FORMAT_V208:\n    case WIN10_DXGI_FORMAT_V408:\n        return 8;\n\n    case DXGI_FORMAT_BC7_TYPELESS:\n    case DXGI_FORMAT_BC7_UNORM:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n        return 7;\n\n    case DXGI_FORMAT_BC1_TYPELESS:\n    case DXGI_FORMAT_BC1_UNORM:\n    case DXGI_FORMAT_BC1_UNORM_SRGB:\n    case DXGI_FORMAT_BC2_TYPELESS:\n    case DXGI_FORMAT_BC2_UNORM:\n    case DXGI_FORMAT_BC2_UNORM_SRGB:\n    case DXGI_FORMAT_BC3_TYPELESS:\n    case DXGI_FORMAT_BC3_UNORM:\n    case DXGI_FORMAT_BC3_UNORM_SRGB:\n    case DXGI_FORMAT_B5G6R5_UNORM:\n        return 6;\n\n    case DXGI_FORMAT_B5G5R5A1_UNORM:\n        return 5;\n\n    case DXGI_FORMAT_B4G4R4A4_UNORM:\n    case XBOX_DXGI_FORMAT_R4G4_UNORM:\n        return 4;\n\n    case DXGI_FORMAT_R1_UNORM:\n        return 1;\n\n    case DXGI_FORMAT_AI44:\n    case DXGI_FORMAT_IA44:\n    case DXGI_FORMAT_P8:\n    case DXGI_FORMAT_A8P8:\n        // Palettized formats return 0 for this function\n\n    default:\n        return 0;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// Computes the image row pitch in bytes, and the slice ptich (size in bytes of the image)\n// based on DXGI format, width, and height\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height,\n    size_t& rowPitch, size_t& slicePitch, CP_FLAGS flags) noexcept\n{\n    uint64_t pitch = 0;\n    uint64_t slice = 0;\n\n    switch (static_cast<int>(fmt))\n    {\n    case DXGI_FORMAT_BC1_TYPELESS:\n    case DXGI_FORMAT_BC1_UNORM:\n    case DXGI_FORMAT_BC1_UNORM_SRGB:\n    case DXGI_FORMAT_BC4_TYPELESS:\n    case DXGI_FORMAT_BC4_UNORM:\n    case DXGI_FORMAT_BC4_SNORM:\n        assert(IsCompressed(fmt));\n        {\n            if (flags & CP_FLAGS_BAD_DXTN_TAILS)\n            {\n                const size_t nbw = width >> 2;\n                const size_t nbh = height >> 2;\n                pitch = std::max<uint64_t>(1u, uint64_t(nbw) * 8u);\n                slice = std::max<uint64_t>(1u, pitch * uint64_t(nbh));\n            }\n            else\n            {\n                const uint64_t nbw = std::max<uint64_t>(1u, (uint64_t(width) + 3u) / 4u);\n                const uint64_t nbh = std::max<uint64_t>(1u, (uint64_t(height) + 3u) / 4u);\n                pitch = nbw * 8u;\n                slice = pitch * nbh;\n            }\n        }\n        break;\n\n    case DXGI_FORMAT_BC2_TYPELESS:\n    case DXGI_FORMAT_BC2_UNORM:\n    case DXGI_FORMAT_BC2_UNORM_SRGB:\n    case DXGI_FORMAT_BC3_TYPELESS:\n    case DXGI_FORMAT_BC3_UNORM:\n    case DXGI_FORMAT_BC3_UNORM_SRGB:\n    case DXGI_FORMAT_BC5_TYPELESS:\n    case DXGI_FORMAT_BC5_UNORM:\n    case DXGI_FORMAT_BC5_SNORM:\n    case DXGI_FORMAT_BC6H_TYPELESS:\n    case DXGI_FORMAT_BC6H_UF16:\n    case DXGI_FORMAT_BC6H_SF16:\n    case DXGI_FORMAT_BC7_TYPELESS:\n    case DXGI_FORMAT_BC7_UNORM:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n        assert(IsCompressed(fmt));\n        {\n            if (flags & CP_FLAGS_BAD_DXTN_TAILS)\n            {\n                const size_t nbw = width >> 2;\n                const size_t nbh = height >> 2;\n                pitch = std::max<uint64_t>(1u, uint64_t(nbw) * 16u);\n                slice = std::max<uint64_t>(1u, pitch * uint64_t(nbh));\n            }\n            else\n            {\n                const uint64_t nbw = std::max<uint64_t>(1u, (uint64_t(width) + 3u) / 4u);\n                const uint64_t nbh = std::max<uint64_t>(1u, (uint64_t(height) + 3u) / 4u);\n                pitch = nbw * 16u;\n                slice = pitch * nbh;\n            }\n        }\n        break;\n\n    case DXGI_FORMAT_R8G8_B8G8_UNORM:\n    case DXGI_FORMAT_G8R8_G8B8_UNORM:\n    case DXGI_FORMAT_YUY2:\n        assert(IsPacked(fmt));\n        pitch = ((uint64_t(width) + 1u) >> 1) * 4u;\n        slice = pitch * uint64_t(height);\n        break;\n\n    case DXGI_FORMAT_Y210:\n    case DXGI_FORMAT_Y216:\n        assert(IsPacked(fmt));\n        pitch = ((uint64_t(width) + 1u) >> 1) * 8u;\n        slice = pitch * uint64_t(height);\n        break;\n\n    case DXGI_FORMAT_NV12:\n    case DXGI_FORMAT_420_OPAQUE:\n        assert(IsPlanar(fmt));\n        pitch = ((uint64_t(width) + 1u) >> 1) * 2u;\n        slice = pitch * (uint64_t(height) + ((uint64_t(height) + 1u) >> 1));\n        break;\n\n    case DXGI_FORMAT_P010:\n    case DXGI_FORMAT_P016:\n    case XBOX_DXGI_FORMAT_D16_UNORM_S8_UINT:\n    case XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS:\n    case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT:\n        assert(IsPlanar(fmt));\n        pitch = ((uint64_t(width) + 1u) >> 1) * 4u;\n        slice = pitch * (uint64_t(height) + ((uint64_t(height) + 1u) >> 1));\n        break;\n\n    case DXGI_FORMAT_NV11:\n        assert(IsPlanar(fmt));\n        pitch = ((uint64_t(width) + 3u) >> 2) * 4u;\n        slice = pitch * uint64_t(height) * 2u;\n        break;\n\n    case WIN10_DXGI_FORMAT_P208:\n        assert(IsPlanar(fmt));\n        pitch = ((uint64_t(width) + 1u) >> 1) * 2u;\n        slice = pitch * uint64_t(height) * 2u;\n        break;\n\n    case WIN10_DXGI_FORMAT_V208:\n        assert(IsPlanar(fmt));\n        pitch = uint64_t(width);\n        slice = pitch * (uint64_t(height) + (((uint64_t(height) + 1u) >> 1) * 2u));\n        break;\n\n    case WIN10_DXGI_FORMAT_V408:\n        assert(IsPlanar(fmt));\n        pitch = uint64_t(width);\n        slice = pitch * (uint64_t(height) + (uint64_t(height >> 1) * 4u));\n        break;\n\n    default:\n        assert(!IsCompressed(fmt) && !IsPacked(fmt) && !IsPlanar(fmt));\n        {\n            size_t bpp;\n\n            if (flags & CP_FLAGS_24BPP)\n                bpp = 24;\n            else if (flags & CP_FLAGS_16BPP)\n                bpp = 16;\n            else if (flags & CP_FLAGS_8BPP)\n                bpp = 8;\n            else\n                bpp = BitsPerPixel(fmt);\n\n            if (!bpp)\n                return E_INVALIDARG;\n\n            if (flags & (CP_FLAGS_LEGACY_DWORD | CP_FLAGS_PARAGRAPH | CP_FLAGS_YMM | CP_FLAGS_ZMM | CP_FLAGS_PAGE4K))\n            {\n                if (flags & CP_FLAGS_PAGE4K)\n                {\n                    pitch = ((uint64_t(width) * bpp + 32767u) / 32768u) * 4096u;\n                    slice = pitch * uint64_t(height);\n                }\n                else if (flags & CP_FLAGS_ZMM)\n                {\n                    pitch = ((uint64_t(width) * bpp + 511u) / 512u) * 64u;\n                    slice = pitch * uint64_t(height);\n                }\n                else if (flags & CP_FLAGS_YMM)\n                {\n                    pitch = ((uint64_t(width) * bpp + 255u) / 256u) * 32u;\n                    slice = pitch * uint64_t(height);\n                }\n                else if (flags & CP_FLAGS_PARAGRAPH)\n                {\n                    pitch = ((uint64_t(width) * bpp + 127u) / 128u) * 16u;\n                    slice = pitch * uint64_t(height);\n                }\n                else // DWORD alignment\n                {\n                    // Special computation for some incorrectly created DDS files based on\n                    // legacy DirectDraw assumptions about pitch alignment\n                    pitch = ((uint64_t(width) * bpp + 31u) / 32u) * sizeof(uint32_t);\n                    slice = pitch * uint64_t(height);\n                }\n            }\n            else\n            {\n                // Default byte alignment\n                pitch = (uint64_t(width) * bpp + 7u) / 8u;\n                slice = pitch * uint64_t(height);\n            }\n        }\n        break;\n    }\n\n#if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64)\n    static_assert(sizeof(size_t) == 4, \"Not a 32-bit platform!\");\n    if (pitch > UINT32_MAX || slice > UINT32_MAX)\n    {\n        rowPitch = slicePitch = 0;\n        return HRESULT_E_ARITHMETIC_OVERFLOW;\n    }\n#else\n    static_assert(sizeof(size_t) == 8, \"Not a 64-bit platform!\");\n#endif\n\n    rowPitch = static_cast<size_t>(pitch);\n    slicePitch = static_cast<size_t>(slice);\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nsize_t DirectX::ComputeScanlines(DXGI_FORMAT fmt, size_t height) noexcept\n{\n    switch (static_cast<int>(fmt))\n    {\n    case DXGI_FORMAT_BC1_TYPELESS:\n    case DXGI_FORMAT_BC1_UNORM:\n    case DXGI_FORMAT_BC1_UNORM_SRGB:\n    case DXGI_FORMAT_BC2_TYPELESS:\n    case DXGI_FORMAT_BC2_UNORM:\n    case DXGI_FORMAT_BC2_UNORM_SRGB:\n    case DXGI_FORMAT_BC3_TYPELESS:\n    case DXGI_FORMAT_BC3_UNORM:\n    case DXGI_FORMAT_BC3_UNORM_SRGB:\n    case DXGI_FORMAT_BC4_TYPELESS:\n    case DXGI_FORMAT_BC4_UNORM:\n    case DXGI_FORMAT_BC4_SNORM:\n    case DXGI_FORMAT_BC5_TYPELESS:\n    case DXGI_FORMAT_BC5_UNORM:\n    case DXGI_FORMAT_BC5_SNORM:\n    case DXGI_FORMAT_BC6H_TYPELESS:\n    case DXGI_FORMAT_BC6H_UF16:\n    case DXGI_FORMAT_BC6H_SF16:\n    case DXGI_FORMAT_BC7_TYPELESS:\n    case DXGI_FORMAT_BC7_UNORM:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n        assert(IsCompressed(fmt));\n        return std::max<size_t>(1, (height + 3) / 4);\n\n    case DXGI_FORMAT_NV11:\n    case WIN10_DXGI_FORMAT_P208:\n        assert(IsPlanar(fmt));\n        return height * 2;\n\n    case WIN10_DXGI_FORMAT_V208:\n        assert(IsPlanar(fmt));\n        return height + (((height + 1) >> 1) * 2);\n\n    case WIN10_DXGI_FORMAT_V408:\n        assert(IsPlanar(fmt));\n        return height + ((height >> 1) * 4);\n\n    case DXGI_FORMAT_NV12:\n    case DXGI_FORMAT_P010:\n    case DXGI_FORMAT_P016:\n    case DXGI_FORMAT_420_OPAQUE:\n    case XBOX_DXGI_FORMAT_D16_UNORM_S8_UINT:\n    case XBOX_DXGI_FORMAT_R16_UNORM_X8_TYPELESS:\n    case XBOX_DXGI_FORMAT_X16_TYPELESS_G8_UINT:\n        assert(IsPlanar(fmt));\n        return height + ((height + 1) >> 1);\n\n    default:\n        assert(IsValid(fmt));\n        assert(!IsCompressed(fmt) && !IsPlanar(fmt));\n        return height;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// Converts to an SRGB equivalent type if available\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nDXGI_FORMAT DirectX::MakeSRGB(DXGI_FORMAT fmt) noexcept\n{\n    switch (fmt)\n    {\n    case DXGI_FORMAT_R8G8B8A8_UNORM:\n        return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;\n\n    case DXGI_FORMAT_BC1_UNORM:\n        return DXGI_FORMAT_BC1_UNORM_SRGB;\n\n    case DXGI_FORMAT_BC2_UNORM:\n        return DXGI_FORMAT_BC2_UNORM_SRGB;\n\n    case DXGI_FORMAT_BC3_UNORM:\n        return DXGI_FORMAT_BC3_UNORM_SRGB;\n\n    case DXGI_FORMAT_B8G8R8A8_UNORM:\n        return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;\n\n    case DXGI_FORMAT_B8G8R8X8_UNORM:\n        return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB;\n\n    case DXGI_FORMAT_BC7_UNORM:\n        return DXGI_FORMAT_BC7_UNORM_SRGB;\n\n    default:\n        return fmt;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// Converts to a format to an equivalent TYPELESS format if available\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nDXGI_FORMAT DirectX::MakeTypeless(DXGI_FORMAT fmt) noexcept\n{\n    switch (static_cast<int>(fmt))\n    {\n    case DXGI_FORMAT_R32G32B32A32_FLOAT:\n    case DXGI_FORMAT_R32G32B32A32_UINT:\n    case DXGI_FORMAT_R32G32B32A32_SINT:\n        return DXGI_FORMAT_R32G32B32A32_TYPELESS;\n\n    case DXGI_FORMAT_R32G32B32_FLOAT:\n    case DXGI_FORMAT_R32G32B32_UINT:\n    case DXGI_FORMAT_R32G32B32_SINT:\n        return DXGI_FORMAT_R32G32B32_TYPELESS;\n\n    case DXGI_FORMAT_R16G16B16A16_FLOAT:\n    case DXGI_FORMAT_R16G16B16A16_UNORM:\n    case DXGI_FORMAT_R16G16B16A16_UINT:\n    case DXGI_FORMAT_R16G16B16A16_SNORM:\n    case DXGI_FORMAT_R16G16B16A16_SINT:\n        return DXGI_FORMAT_R16G16B16A16_TYPELESS;\n\n    case DXGI_FORMAT_R32G32_FLOAT:\n    case DXGI_FORMAT_R32G32_UINT:\n    case DXGI_FORMAT_R32G32_SINT:\n        return DXGI_FORMAT_R32G32_TYPELESS;\n\n    case DXGI_FORMAT_R10G10B10A2_UNORM:\n    case DXGI_FORMAT_R10G10B10A2_UINT:\n    case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT:\n    case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT:\n    case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM:\n        return DXGI_FORMAT_R10G10B10A2_TYPELESS;\n\n    case DXGI_FORMAT_R8G8B8A8_UNORM:\n    case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n    case DXGI_FORMAT_R8G8B8A8_UINT:\n    case DXGI_FORMAT_R8G8B8A8_SNORM:\n    case DXGI_FORMAT_R8G8B8A8_SINT:\n        return DXGI_FORMAT_R8G8B8A8_TYPELESS;\n\n    case DXGI_FORMAT_R16G16_FLOAT:\n    case DXGI_FORMAT_R16G16_UNORM:\n    case DXGI_FORMAT_R16G16_UINT:\n    case DXGI_FORMAT_R16G16_SNORM:\n    case DXGI_FORMAT_R16G16_SINT:\n        return DXGI_FORMAT_R16G16_TYPELESS;\n\n    case DXGI_FORMAT_D32_FLOAT:\n    case DXGI_FORMAT_R32_FLOAT:\n    case DXGI_FORMAT_R32_UINT:\n    case DXGI_FORMAT_R32_SINT:\n        return DXGI_FORMAT_R32_TYPELESS;\n\n    case DXGI_FORMAT_R8G8_UNORM:\n    case DXGI_FORMAT_R8G8_UINT:\n    case DXGI_FORMAT_R8G8_SNORM:\n    case DXGI_FORMAT_R8G8_SINT:\n        return DXGI_FORMAT_R8G8_TYPELESS;\n\n    case DXGI_FORMAT_R16_FLOAT:\n    case DXGI_FORMAT_D16_UNORM:\n    case DXGI_FORMAT_R16_UNORM:\n    case DXGI_FORMAT_R16_UINT:\n    case DXGI_FORMAT_R16_SNORM:\n    case DXGI_FORMAT_R16_SINT:\n        return DXGI_FORMAT_R16_TYPELESS;\n\n    case DXGI_FORMAT_R8_UNORM:\n    case DXGI_FORMAT_R8_UINT:\n    case DXGI_FORMAT_R8_SNORM:\n    case DXGI_FORMAT_R8_SINT:\n    case XBOX_DXGI_FORMAT_R4G4_UNORM:\n        return DXGI_FORMAT_R8_TYPELESS;\n\n    case DXGI_FORMAT_BC1_UNORM:\n    case DXGI_FORMAT_BC1_UNORM_SRGB:\n        return DXGI_FORMAT_BC1_TYPELESS;\n\n    case DXGI_FORMAT_BC2_UNORM:\n    case DXGI_FORMAT_BC2_UNORM_SRGB:\n        return DXGI_FORMAT_BC2_TYPELESS;\n\n    case DXGI_FORMAT_BC3_UNORM:\n    case DXGI_FORMAT_BC3_UNORM_SRGB:\n        return DXGI_FORMAT_BC3_TYPELESS;\n\n    case DXGI_FORMAT_BC4_UNORM:\n    case DXGI_FORMAT_BC4_SNORM:\n        return DXGI_FORMAT_BC4_TYPELESS;\n\n    case DXGI_FORMAT_BC5_UNORM:\n    case DXGI_FORMAT_BC5_SNORM:\n        return DXGI_FORMAT_BC5_TYPELESS;\n\n    case DXGI_FORMAT_B8G8R8A8_UNORM:\n    case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n        return DXGI_FORMAT_B8G8R8A8_TYPELESS;\n\n    case DXGI_FORMAT_B8G8R8X8_UNORM:\n    case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:\n        return DXGI_FORMAT_B8G8R8X8_TYPELESS;\n\n    case DXGI_FORMAT_BC6H_UF16:\n    case DXGI_FORMAT_BC6H_SF16:\n        return DXGI_FORMAT_BC6H_TYPELESS;\n\n    case DXGI_FORMAT_BC7_UNORM:\n    case DXGI_FORMAT_BC7_UNORM_SRGB:\n        return DXGI_FORMAT_BC7_TYPELESS;\n\n    default:\n        return fmt;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// Converts to a TYPELESS format to an equivalent UNORM format if available\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nDXGI_FORMAT DirectX::MakeTypelessUNORM(DXGI_FORMAT fmt) noexcept\n{\n    switch (fmt)\n    {\n    case DXGI_FORMAT_R16G16B16A16_TYPELESS:\n        return DXGI_FORMAT_R16G16B16A16_UNORM;\n\n    case DXGI_FORMAT_R10G10B10A2_TYPELESS:\n        return DXGI_FORMAT_R10G10B10A2_UNORM;\n\n    case DXGI_FORMAT_R8G8B8A8_TYPELESS:\n        return DXGI_FORMAT_R8G8B8A8_UNORM;\n\n    case DXGI_FORMAT_R16G16_TYPELESS:\n        return DXGI_FORMAT_R16G16_UNORM;\n\n    case DXGI_FORMAT_R8G8_TYPELESS:\n        return DXGI_FORMAT_R8G8_UNORM;\n\n    case DXGI_FORMAT_R16_TYPELESS:\n        return DXGI_FORMAT_R16_UNORM;\n\n    case DXGI_FORMAT_R8_TYPELESS:\n        return DXGI_FORMAT_R8_UNORM;\n\n    case DXGI_FORMAT_BC1_TYPELESS:\n        return DXGI_FORMAT_BC1_UNORM;\n\n    case DXGI_FORMAT_BC2_TYPELESS:\n        return DXGI_FORMAT_BC2_UNORM;\n\n    case DXGI_FORMAT_BC3_TYPELESS:\n        return DXGI_FORMAT_BC3_UNORM;\n\n    case DXGI_FORMAT_BC4_TYPELESS:\n        return DXGI_FORMAT_BC4_UNORM;\n\n    case DXGI_FORMAT_BC5_TYPELESS:\n        return DXGI_FORMAT_BC5_UNORM;\n\n    case DXGI_FORMAT_B8G8R8A8_TYPELESS:\n        return DXGI_FORMAT_B8G8R8A8_UNORM;\n\n    case DXGI_FORMAT_B8G8R8X8_TYPELESS:\n        return DXGI_FORMAT_B8G8R8X8_UNORM;\n\n    case DXGI_FORMAT_BC7_TYPELESS:\n        return DXGI_FORMAT_BC7_UNORM;\n\n    default:\n        return fmt;\n    }\n}\n\n\n//-------------------------------------------------------------------------------------\n// Converts to a TYPELESS format to an equivalent FLOAT format if available\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nDXGI_FORMAT DirectX::MakeTypelessFLOAT(DXGI_FORMAT fmt) noexcept\n{\n    switch (fmt)\n    {\n    case DXGI_FORMAT_R32G32B32A32_TYPELESS:\n        return DXGI_FORMAT_R32G32B32A32_FLOAT;\n\n    case DXGI_FORMAT_R32G32B32_TYPELESS:\n        return DXGI_FORMAT_R32G32B32_FLOAT;\n\n    case DXGI_FORMAT_R16G16B16A16_TYPELESS:\n        return DXGI_FORMAT_R16G16B16A16_FLOAT;\n\n    case DXGI_FORMAT_R32G32_TYPELESS:\n        return DXGI_FORMAT_R32G32_FLOAT;\n\n    case DXGI_FORMAT_R16G16_TYPELESS:\n        return DXGI_FORMAT_R16G16_FLOAT;\n\n    case DXGI_FORMAT_R32_TYPELESS:\n        return DXGI_FORMAT_R32_FLOAT;\n\n    case DXGI_FORMAT_R16_TYPELESS:\n        return DXGI_FORMAT_R16_FLOAT;\n\n    default:\n        return fmt;\n    }\n}\n\n\n//=====================================================================================\n// TexMetadata\n//=====================================================================================\n\n_Use_decl_annotations_\nsize_t TexMetadata::ComputeIndex(size_t mip, size_t item, size_t slice) const noexcept\n{\n    if (mip >= mipLevels)\n        return size_t(-1);\n\n    switch (dimension)\n    {\n    case TEX_DIMENSION_TEXTURE1D:\n    case TEX_DIMENSION_TEXTURE2D:\n        if (slice > 0)\n            return size_t(-1);\n\n        if (item >= arraySize)\n            return size_t(-1);\n\n        return (item*(mipLevels)+mip);\n\n    case TEX_DIMENSION_TEXTURE3D:\n        if (item > 0)\n        {\n            // No support for arrays of volumes\n            return size_t(-1);\n        }\n        else\n        {\n            size_t index = 0;\n            size_t d = depth;\n\n            for (size_t level = 0; level < mip; ++level)\n            {\n                index += d;\n                if (d > 1)\n                    d >>= 1;\n            }\n\n            if (slice >= d)\n                return size_t(-1);\n\n            index += slice;\n\n            return index;\n        }\n\n    default:\n        return size_t(-1);\n    }\n}\n\n\n//=====================================================================================\n// Blob - Bitmap image container\n//=====================================================================================\n\nBlob& Blob::operator= (Blob&& moveFrom) noexcept\n{\n    if (this != &moveFrom)\n    {\n        Release();\n\n        m_buffer = moveFrom.m_buffer;\n        m_size = moveFrom.m_size;\n\n        moveFrom.m_buffer = nullptr;\n        moveFrom.m_size = 0;\n    }\n    return *this;\n}\n\nvoid Blob::Release() noexcept\n{\n    if (m_buffer)\n    {\n        _aligned_free(m_buffer);\n        m_buffer = nullptr;\n    }\n\n    m_size = 0;\n}\n\n_Use_decl_annotations_\nHRESULT Blob::Initialize(size_t size) noexcept\n{\n    if (!size)\n        return E_INVALIDARG;\n\n    Release();\n\n    m_buffer = _aligned_malloc(size, 16);\n    if (!m_buffer)\n    {\n        Release();\n        return E_OUTOFMEMORY;\n    }\n\n    m_size = size;\n\n    return S_OK;\n}\n\nHRESULT Blob::Trim(size_t size) noexcept\n{\n    if (!size)\n        return E_INVALIDARG;\n\n    if (!m_buffer)\n        return E_UNEXPECTED;\n\n    if (size > m_size)\n        return E_INVALIDARG;\n\n    m_size = size;\n\n    return S_OK;\n}\n\nHRESULT Blob::Resize(size_t size) noexcept\n{\n    if (!size)\n        return E_INVALIDARG;\n\n    if (!m_buffer || !m_size)\n        return E_UNEXPECTED;\n\n    void *tbuffer = _aligned_malloc(size, 16);\n    if (!tbuffer)\n        return E_OUTOFMEMORY;\n\n    memcpy(tbuffer, m_buffer, std::min(m_size, size));\n\n    Release();\n\n    m_buffer = tbuffer;\n    m_size = size;\n\n    return S_OK;\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/DirectXTexWIC.cpp",
    "content": "//-------------------------------------------------------------------------------------\n// DirectXTexWIC.cpp\n//\n// DirectX Texture Library - WIC-based file reader/writer\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//-------------------------------------------------------------------------------------\n\n#include \"DirectXTexP.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::Internal;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    //-------------------------------------------------------------------------------------\n    // WIC Pixel Format nearest conversion table\n    //-------------------------------------------------------------------------------------\n    struct WICConvert\n    {\n        const GUID&     source;\n        const GUID&     target;\n        TEX_ALPHA_MODE  alphaMode;\n    };\n\n    constexpr WICConvert g_WICConvert[] =\n    {\n        // Directly support the formats listed in XnaTexUtil::g_WICFormats, so no conversion required\n        // Note target GUID in this conversion table must be one of those directly supported formats.\n\n        { GUID_WICPixelFormat1bppIndexed,           GUID_WICPixelFormat32bppRGBA, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R8G8B8A8_UNORM\n        { GUID_WICPixelFormat2bppIndexed,           GUID_WICPixelFormat32bppRGBA, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R8G8B8A8_UNORM\n        { GUID_WICPixelFormat4bppIndexed,           GUID_WICPixelFormat32bppRGBA, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R8G8B8A8_UNORM\n        { GUID_WICPixelFormat8bppIndexed,           GUID_WICPixelFormat32bppRGBA, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R8G8B8A8_UNORM\n\n        { GUID_WICPixelFormat2bppGray,              GUID_WICPixelFormat8bppGray, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R8_UNORM\n        { GUID_WICPixelFormat4bppGray,              GUID_WICPixelFormat8bppGray, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R8_UNORM\n\n        { GUID_WICPixelFormat16bppGrayFixedPoint,   GUID_WICPixelFormat16bppGrayHalf, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R16_FLOAT\n        { GUID_WICPixelFormat32bppGrayFixedPoint,   GUID_WICPixelFormat32bppGrayFloat, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R32_FLOAT\n\n        { GUID_WICPixelFormat16bppBGR555,           GUID_WICPixelFormat16bppBGRA5551, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_B5G5R5A1_UNORM\n        { GUID_WICPixelFormat32bppBGR101010,        GUID_WICPixelFormat32bppRGBA1010102, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R10G10B10A2_UNORM\n\n        { GUID_WICPixelFormat24bppBGR,              GUID_WICPixelFormat32bppRGBA, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R8G8B8A8_UNORM\n        { GUID_WICPixelFormat24bppRGB,              GUID_WICPixelFormat32bppRGBA, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R8G8B8A8_UNORM\n        { GUID_WICPixelFormat32bppPBGRA,            GUID_WICPixelFormat32bppRGBA, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R8G8B8A8_UNORM\n        { GUID_WICPixelFormat32bppPRGBA,            GUID_WICPixelFormat32bppRGBA, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R8G8B8A8_UNORM\n\n        { GUID_WICPixelFormat48bppRGB,              GUID_WICPixelFormat64bppRGBA, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R16G16B16A16_UNORM\n        { GUID_WICPixelFormat48bppBGR,              GUID_WICPixelFormat64bppRGBA, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R16G16B16A16_UNORM\n        { GUID_WICPixelFormat64bppBGRA,             GUID_WICPixelFormat64bppRGBA, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R16G16B16A16_UNORM\n        { GUID_WICPixelFormat64bppPRGBA,            GUID_WICPixelFormat64bppRGBA, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R16G16B16A16_UNORM\n        { GUID_WICPixelFormat64bppPBGRA,            GUID_WICPixelFormat64bppRGBA, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R16G16B16A16_UNORM\n\n        { GUID_WICPixelFormat48bppRGBFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R16G16B16A16_FLOAT\n        { GUID_WICPixelFormat48bppBGRFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R16G16B16A16_FLOAT\n        { GUID_WICPixelFormat64bppRGBAFixedPoint,   GUID_WICPixelFormat64bppRGBAHalf, TEX_ALPHA_MODE_UNKNOWN  }, // DXGI_FORMAT_R16G16B16A16_FLOAT\n        { GUID_WICPixelFormat64bppBGRAFixedPoint,   GUID_WICPixelFormat64bppRGBAHalf, TEX_ALPHA_MODE_UNKNOWN  }, // DXGI_FORMAT_R16G16B16A16_FLOAT\n        { GUID_WICPixelFormat64bppRGBFixedPoint,    GUID_WICPixelFormat64bppRGBAHalf, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R16G16B16A16_FLOAT\n        { GUID_WICPixelFormat64bppRGBHalf,          GUID_WICPixelFormat64bppRGBAHalf, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R16G16B16A16_FLOAT\n        { GUID_WICPixelFormat48bppRGBHalf,          GUID_WICPixelFormat64bppRGBAHalf, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R16G16B16A16_FLOAT\n\n        { GUID_WICPixelFormat128bppPRGBAFloat,      GUID_WICPixelFormat128bppRGBAFloat, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R32G32B32A32_FLOAT\n        { GUID_WICPixelFormat128bppRGBFloat,        GUID_WICPixelFormat128bppRGBAFloat, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R32G32B32A32_FLOAT\n        { GUID_WICPixelFormat128bppRGBAFixedPoint,  GUID_WICPixelFormat128bppRGBAFloat, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R32G32B32A32_FLOAT\n        { GUID_WICPixelFormat128bppRGBFixedPoint,   GUID_WICPixelFormat128bppRGBAFloat, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R32G32B32A32_FLOAT\n        { GUID_WICPixelFormat32bppRGBE,             GUID_WICPixelFormat128bppRGBAFloat, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R32G32B32A32_FLOAT\n\n        { GUID_WICPixelFormat32bppCMYK,             GUID_WICPixelFormat32bppRGBA, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R8G8B8A8_UNORM\n        { GUID_WICPixelFormat64bppCMYK,             GUID_WICPixelFormat64bppRGBA, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R16G16B16A16_UNORM\n        { GUID_WICPixelFormat40bppCMYKAlpha,        GUID_WICPixelFormat32bppRGBA, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R8G8B8A8_UNORM\n        { GUID_WICPixelFormat80bppCMYKAlpha,        GUID_WICPixelFormat64bppRGBA, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R16G16B16A16_UNORM\n\n    #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE)\n        { GUID_WICPixelFormat32bppRGB,              GUID_WICPixelFormat32bppRGBA, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R8G8B8A8_UNORM\n        { GUID_WICPixelFormat64bppRGB,              GUID_WICPixelFormat64bppRGBA, TEX_ALPHA_MODE_OPAQUE }, // DXGI_FORMAT_R16G16B16A16_UNORM\n        { GUID_WICPixelFormat64bppPRGBAHalf,        GUID_WICPixelFormat64bppRGBAHalf, TEX_ALPHA_MODE_UNKNOWN }, // DXGI_FORMAT_R16G16B16A16_FLOAT\n    #endif\n\n        // We don't support n-channel formats\n    };\n\n    //-------------------------------------------------------------------------------------\n    // Returns the DXGI format and optionally the WIC pixel GUID to convert to\n    //-------------------------------------------------------------------------------------\n    DXGI_FORMAT DetermineFormat(\n        _In_ const WICPixelFormatGUID& pixelFormat,\n        WIC_FLAGS flags,\n        bool iswic2,\n        _Out_opt_ WICPixelFormatGUID* pConvert,\n        _Out_ TEX_ALPHA_MODE* alphaMode) noexcept\n    {\n        if (pConvert)\n            memset(pConvert, 0, sizeof(WICPixelFormatGUID));\n\n        *alphaMode = TEX_ALPHA_MODE_UNKNOWN;\n\n        DXGI_FORMAT format = WICToDXGI(pixelFormat);\n\n        if (format == DXGI_FORMAT_UNKNOWN)\n        {\n            if (memcmp(&GUID_WICPixelFormat96bppRGBFixedPoint, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0)\n            {\n            #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE)\n                if (iswic2)\n                {\n                    if (pConvert)\n                        memcpy_s(pConvert, sizeof(WICPixelFormatGUID), &GUID_WICPixelFormat96bppRGBFloat, sizeof(GUID));\n                    format = DXGI_FORMAT_R32G32B32_FLOAT;\n                }\n                else\n                #else\n                UNREFERENCED_PARAMETER(iswic2);\n            #endif\n                {\n                    if (pConvert)\n                        memcpy_s(pConvert, sizeof(WICPixelFormatGUID), &GUID_WICPixelFormat128bppRGBAFloat, sizeof(GUID));\n                    format = DXGI_FORMAT_R32G32B32A32_FLOAT;\n                    *alphaMode = TEX_ALPHA_MODE_OPAQUE;\n                }\n            }\n            else\n            {\n                for (size_t i = 0; i < std::size(g_WICConvert); ++i)\n                {\n                    if (memcmp(&g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0)\n                    {\n                        if (pConvert)\n                            memcpy_s(pConvert, sizeof(WICPixelFormatGUID), &g_WICConvert[i].target, sizeof(GUID));\n\n                        format = WICToDXGI(g_WICConvert[i].target);\n                        assert(format != DXGI_FORMAT_UNKNOWN);\n                        *alphaMode = g_WICConvert[i].alphaMode;\n                        break;\n                    }\n                }\n            }\n        }\n\n        // Handle special cases based on flags\n        switch (format)\n        {\n        case DXGI_FORMAT_B8G8R8A8_UNORM:    // BGRA\n        case DXGI_FORMAT_B8G8R8X8_UNORM:    // BGRX\n            if (flags & WIC_FLAGS_FORCE_RGB)\n            {\n                format = DXGI_FORMAT_R8G8B8A8_UNORM;\n                if (pConvert)\n                    memcpy_s(pConvert, sizeof(WICPixelFormatGUID), &GUID_WICPixelFormat32bppRGBA, sizeof(GUID));\n            }\n            break;\n\n        case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:\n            if (flags & WIC_FLAGS_NO_X2_BIAS)\n            {\n                format = DXGI_FORMAT_R10G10B10A2_UNORM;\n                if (pConvert)\n                    memcpy_s(pConvert, sizeof(WICPixelFormatGUID), &GUID_WICPixelFormat32bppRGBA1010102, sizeof(GUID));\n            }\n            break;\n\n        case DXGI_FORMAT_B5G5R5A1_UNORM:\n        case DXGI_FORMAT_B5G6R5_UNORM:\n            if (flags & WIC_FLAGS_NO_16BPP)\n            {\n                format = DXGI_FORMAT_R8G8B8A8_UNORM;\n                if (pConvert)\n                    memcpy_s(pConvert, sizeof(WICPixelFormatGUID), &GUID_WICPixelFormat32bppRGBA, sizeof(GUID));\n            }\n            break;\n\n        case DXGI_FORMAT_R1_UNORM:\n            if (!(flags & WIC_FLAGS_ALLOW_MONO))\n            {\n                // By default we want to promote a black & white to gresycale since R1 is not a generally supported D3D format\n                format = DXGI_FORMAT_R8_UNORM;\n                if (pConvert)\n                    memcpy_s(pConvert, sizeof(WICPixelFormatGUID), &GUID_WICPixelFormat8bppGray, sizeof(GUID));\n            }\n            break;\n\n        default:\n            break;\n        }\n\n        return format;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    // IStream over a Blob for WIC in-memory write functions\n    //-------------------------------------------------------------------------------------\n    class MemoryStreamOnBlob : public IStream\n    {\n        MemoryStreamOnBlob(Blob& blob) noexcept :\n            mBlob(blob),\n            m_streamPosition(0),\n            m_streamEOF(0),\n            mRefCount(1)\n        {\n            assert(mBlob.GetBufferPointer() && mBlob.GetBufferSize() > 0);\n        }\n\n    public:\n        virtual ~MemoryStreamOnBlob() = default;\n\n        MemoryStreamOnBlob(MemoryStreamOnBlob&&) = delete;\n        MemoryStreamOnBlob& operator= (MemoryStreamOnBlob&&) = delete;\n\n        MemoryStreamOnBlob(MemoryStreamOnBlob const&) = delete;\n        MemoryStreamOnBlob& operator= (MemoryStreamOnBlob const&) = delete;\n\n        // IUnknown\n        HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject) override\n        {\n            if (iid == __uuidof(IUnknown)\n                || iid == __uuidof(IStream)\n                || iid == __uuidof(ISequentialStream))\n            {\n                *ppvObject = static_cast<IStream*>(this);\n                AddRef();\n                return S_OK;\n            }\n            else\n                return E_NOINTERFACE;\n        }\n\n        ULONG STDMETHODCALLTYPE AddRef() override\n        {\n            return InterlockedIncrement(&mRefCount);\n        }\n\n        ULONG STDMETHODCALLTYPE Release() override\n        {\n            const ULONG res = InterlockedDecrement(&mRefCount);\n            if (res == 0)\n            {\n                delete this;\n            }\n            return res;\n        }\n\n        // ISequentialStream\n        HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead) override\n        {\n            size_t maxRead = m_streamEOF - m_streamPosition;\n            auto ptr = static_cast<const uint8_t*>(mBlob.GetBufferPointer());\n            if (cb > maxRead)\n            {\n                const uint64_t pos = uint64_t(m_streamPosition) + uint64_t(maxRead);\n                if (pos > UINT32_MAX)\n                    return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n                memcpy(pv, &ptr[m_streamPosition], maxRead);\n\n                m_streamPosition = static_cast<size_t>(pos);\n\n                if (pcbRead)\n                {\n                    *pcbRead = static_cast<ULONG>(maxRead);\n                }\n                return E_BOUNDS;\n            }\n            else\n            {\n                const uint64_t pos = uint64_t(m_streamPosition) + uint64_t(cb);\n                if (pos > UINT32_MAX)\n                    return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n                memcpy(pv, &ptr[m_streamPosition], cb);\n\n                m_streamPosition = static_cast<size_t>(pos);\n\n                if (pcbRead)\n                {\n                    *pcbRead = cb;\n                }\n                return S_OK;\n            }\n        }\n\n        HRESULT STDMETHODCALLTYPE Write(void const* pv, ULONG cb, ULONG* pcbWritten) override\n        {\n            const size_t blobSize = mBlob.GetBufferSize();\n            const size_t spaceAvailable = blobSize - m_streamPosition;\n            size_t growAmount = cb;\n\n            if (spaceAvailable > 0)\n            {\n                if (spaceAvailable >= growAmount)\n                {\n                    growAmount = 0;\n                }\n                else\n                {\n                    growAmount -= spaceAvailable;\n                }\n            }\n\n            if (growAmount > 0)\n            {\n                uint64_t newSize = uint64_t(blobSize);\n                const uint64_t targetSize = uint64_t(blobSize) + growAmount;\n                HRESULT hr = ComputeGrowSize(newSize, targetSize);\n                if (FAILED(hr))\n                    return hr;\n\n                hr = mBlob.Resize(static_cast<size_t>(newSize));\n                if (FAILED(hr))\n                    return hr;\n            }\n\n            const uint64_t pos = uint64_t(m_streamPosition) + uint64_t(cb);\n            if (pos > UINT32_MAX)\n                return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n            auto ptr = static_cast<uint8_t*>(mBlob.GetBufferPointer());\n            memcpy(&ptr[m_streamPosition], pv, cb);\n\n            m_streamPosition = static_cast<size_t>(pos);\n            m_streamEOF = std::max(m_streamEOF, m_streamPosition);\n\n            if (pcbWritten)\n            {\n                *pcbWritten = cb;\n            }\n            return S_OK;\n        }\n\n        // IStream\n        HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER size) override\n        {\n            if (size.HighPart > 0)\n                return E_OUTOFMEMORY;\n\n            const size_t blobSize = mBlob.GetBufferSize();\n\n            if (blobSize >= size.LowPart)\n            {\n                auto ptr = static_cast<uint8_t*>(mBlob.GetBufferPointer());\n                if (m_streamEOF < size.LowPart)\n                {\n                    memset(&ptr[m_streamEOF], 0, size.LowPart - m_streamEOF);\n                }\n\n                m_streamEOF = static_cast<size_t>(size.LowPart);\n            }\n            else\n            {\n                uint64_t newSize = uint64_t(blobSize);\n                const uint64_t targetSize = uint64_t(size.QuadPart);\n                HRESULT hr = ComputeGrowSize(newSize, targetSize);\n                if (FAILED(hr))\n                    return hr;\n\n                hr = mBlob.Resize(static_cast<size_t>(newSize));\n                if (FAILED(hr))\n                    return hr;\n\n                auto ptr = static_cast<uint8_t*>(mBlob.GetBufferPointer());\n                if (m_streamEOF < size.LowPart)\n                {\n                    memset(&ptr[m_streamEOF], 0, size.LowPart - m_streamEOF);\n                }\n\n                m_streamEOF = static_cast<size_t>(size.LowPart);\n            }\n\n            if (m_streamPosition > m_streamEOF)\n            {\n                m_streamPosition = m_streamEOF;\n            }\n\n            return S_OK;\n        }\n\n        HRESULT STDMETHODCALLTYPE CopyTo(IStream*, ULARGE_INTEGER, ULARGE_INTEGER*, ULARGE_INTEGER*) override\n        {\n            return E_NOTIMPL;\n        }\n\n        HRESULT STDMETHODCALLTYPE Commit(DWORD) override\n        {\n            return E_NOTIMPL;\n        }\n\n        HRESULT STDMETHODCALLTYPE Revert() override\n        {\n            return E_NOTIMPL;\n        }\n\n        HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) override\n        {\n            return E_NOTIMPL;\n        }\n\n        HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) override\n        {\n            return E_NOTIMPL;\n        }\n\n        HRESULT STDMETHODCALLTYPE Clone(IStream**) override\n        {\n            return E_NOTIMPL;\n        }\n\n        HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove, DWORD dwOrigin, ULARGE_INTEGER* lpNewFilePointer) override\n        {\n            LONGLONG newPosition = 0;\n\n            switch (dwOrigin)\n            {\n            case STREAM_SEEK_SET:\n                newPosition = liDistanceToMove.QuadPart;\n                break;\n\n            case STREAM_SEEK_CUR:\n                newPosition = static_cast<LONGLONG>(m_streamPosition) + liDistanceToMove.QuadPart;\n                break;\n\n            case STREAM_SEEK_END:\n                newPosition = static_cast<LONGLONG>(m_streamEOF) + liDistanceToMove.QuadPart;\n                break;\n\n            default:\n                return STG_E_INVALIDFUNCTION;\n            }\n\n            HRESULT result = S_OK;\n\n            if (newPosition > static_cast<LONGLONG>(m_streamEOF))\n            {\n                m_streamPosition = m_streamEOF;\n                result = E_BOUNDS;\n            }\n            else if (newPosition < 0)\n            {\n                m_streamPosition = 0;\n                result = E_BOUNDS;\n            }\n            else\n            {\n                m_streamPosition = static_cast<size_t>(newPosition);\n            }\n\n            if (lpNewFilePointer)\n            {\n                lpNewFilePointer->QuadPart = static_cast<ULONGLONG>(m_streamPosition);\n            }\n\n            return result;\n        }\n\n        HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg, DWORD) override\n        {\n            if (!pStatstg)\n                return E_INVALIDARG;\n            pStatstg->cbSize.QuadPart = static_cast<ULONGLONG>(m_streamEOF);\n            return S_OK;\n        }\n\n        HRESULT Finialize() noexcept\n        {\n            if (mRefCount > 1)\n                return E_FAIL;\n\n            return mBlob.Trim(m_streamEOF);\n        }\n\n        static HRESULT CreateMemoryStream(_Outptr_ MemoryStreamOnBlob** stream, Blob& blob) noexcept\n        {\n            if (!stream)\n                return E_INVALIDARG;\n\n            *stream = nullptr;\n\n            auto ptr = new (std::nothrow) MemoryStreamOnBlob(blob);\n            if (!ptr)\n                return E_OUTOFMEMORY;\n\n            *stream = ptr;\n\n            return S_OK;\n        }\n\n    private:\n        Blob& mBlob;\n        size_t m_streamPosition;\n        size_t m_streamEOF;\n        ULONG mRefCount;\n\n        static HRESULT ComputeGrowSize(uint64_t& newSize, const uint64_t targetSize) noexcept\n        {\n            // We grow by doubling until we hit 256MB, then we add 16MB at a time.\n            while (newSize < targetSize)\n            {\n                if (newSize < (256 * 1024 * 1024))\n                {\n                    newSize <<= 1;\n                }\n                else\n                {\n                    newSize += 16 * 1024 * 1024;\n                }\n                if (newSize > UINT32_MAX)\n                    return E_OUTOFMEMORY;\n            }\n\n            return S_OK;\n        }\n    };\n\n    //-------------------------------------------------------------------------------------\n    // Determines metadata for image\n    //-------------------------------------------------------------------------------------\n    HRESULT DecodeMetadata(\n        WIC_FLAGS flags,\n        bool iswic2,\n        _In_ IWICBitmapDecoder *decoder,\n        _In_ IWICBitmapFrameDecode *frame,\n        _Out_ TexMetadata& metadata,\n        _Out_opt_ WICPixelFormatGUID* pConvert,\n        _In_opt_ std::function<void(IWICMetadataQueryReader*)> getMQR)\n    {\n        if (!decoder || !frame)\n            return E_POINTER;\n\n        memset(&metadata, 0, sizeof(TexMetadata));\n        metadata.depth = 1;\n        metadata.mipLevels = 1;\n        metadata.dimension = TEX_DIMENSION_TEXTURE2D;\n\n        UINT w, h;\n        HRESULT hr = frame->GetSize(&w, &h);\n        if (FAILED(hr))\n            return hr;\n\n        metadata.width = w;\n        metadata.height = h;\n\n        if (flags & WIC_FLAGS_ALL_FRAMES)\n        {\n            UINT fcount;\n            hr = decoder->GetFrameCount(&fcount);\n            if (FAILED(hr))\n                return hr;\n\n            metadata.arraySize = fcount;\n        }\n        else\n            metadata.arraySize = 1;\n\n        WICPixelFormatGUID pixelFormat;\n        hr = frame->GetPixelFormat(&pixelFormat);\n        if (FAILED(hr))\n            return hr;\n\n        TEX_ALPHA_MODE alphaMode;\n        metadata.format = DetermineFormat(pixelFormat, flags, iswic2, pConvert, &alphaMode);\n        if (metadata.format == DXGI_FORMAT_UNKNOWN)\n            return HRESULT_E_NOT_SUPPORTED;\n\n        metadata.SetAlphaMode(alphaMode);\n\n        if (!(flags & WIC_FLAGS_IGNORE_SRGB))\n        {\n            GUID containerFormat;\n            hr = decoder->GetContainerFormat(&containerFormat);\n            if (FAILED(hr))\n                return hr;\n\n            ComPtr<IWICMetadataQueryReader> metareader;\n            hr = frame->GetMetadataQueryReader(metareader.GetAddressOf());\n            if (SUCCEEDED(hr))\n            {\n                // Check for sRGB colorspace metadata\n                bool sRGB = false;\n\n                PROPVARIANT value;\n                PropVariantInit(&value);\n\n                // Check for colorspace chunks\n                if (memcmp(&containerFormat, &GUID_ContainerFormatPng, sizeof(GUID)) == 0)\n                {\n                    if (SUCCEEDED(metareader->GetMetadataByName(L\"/sRGB/RenderingIntent\", &value)) && value.vt == VT_UI1)\n                    {\n                        sRGB = true;\n                    }\n                    else if (SUCCEEDED(metareader->GetMetadataByName(L\"/gAMA/ImageGamma\", &value)) && value.vt == VT_UI4)\n                    {\n                        sRGB = (value.uintVal == 45455);\n                    }\n                    else\n                    {\n                        sRGB = (flags & WIC_FLAGS_DEFAULT_SRGB) != 0;\n                    }\n                }\n            #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n                else if (memcmp(&containerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID)) == 0)\n                {\n                    if (SUCCEEDED(metareader->GetMetadataByName(L\"/app1/ifd/exif/{ushort=40961}\", &value)) && value.vt == VT_UI2)\n                    {\n                        sRGB = (value.uiVal == 1);\n                    }\n                    else\n                    {\n                        sRGB = (flags & WIC_FLAGS_DEFAULT_SRGB) != 0;\n                    }\n                }\n                else if (memcmp(&containerFormat, &GUID_ContainerFormatTiff, sizeof(GUID)) == 0)\n                {\n                    if (SUCCEEDED(metareader->GetMetadataByName(L\"/ifd/exif/{ushort=40961}\", &value)) && value.vt == VT_UI2)\n                    {\n                        sRGB = (value.uiVal == 1);\n                    }\n                    else\n                    {\n                        sRGB = (flags & WIC_FLAGS_DEFAULT_SRGB) != 0;\n                    }\n                }\n            #else\n                else if (SUCCEEDED(metareader->GetMetadataByName(L\"System.Image.ColorSpace\", &value)) && value.vt == VT_UI2)\n                {\n                    sRGB = (value.uiVal == 1);\n                }\n                else\n                {\n                    sRGB = (flags & WIC_FLAGS_DEFAULT_SRGB) != 0;\n                }\n            #endif\n\n                std::ignore = PropVariantClear(&value);\n\n                if (sRGB)\n                    metadata.format = MakeSRGB(metadata.format);\n            }\n            else if (hr == WINCODEC_ERR_UNSUPPORTEDOPERATION)\n            {\n                // Some formats just don't support metadata (BMP, ICO, etc.), so ignore this failure\n                hr = S_OK;\n            }\n        }\n\n        if (getMQR)\n        {\n            ComPtr<IWICMetadataQueryReader> metareader;\n            if (SUCCEEDED(frame->GetMetadataQueryReader(metareader.GetAddressOf())))\n            {\n                getMQR(metareader.Get());\n            }\n        }\n\n        return hr;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    // Decodes a single frame\n    //-------------------------------------------------------------------------------------\n    HRESULT DecodeSingleFrame(\n        WIC_FLAGS flags,\n        const TexMetadata& metadata,\n        const WICPixelFormatGUID& convertGUID,\n        _In_ IWICBitmapFrameDecode *frame,\n        _Inout_ ScratchImage& image)\n    {\n        if (!frame)\n            return E_POINTER;\n\n        HRESULT hr = image.Initialize2D(metadata.format, metadata.width, metadata.height, 1, 1);\n        if (FAILED(hr))\n            return hr;\n\n        const Image *img = image.GetImage(0, 0, 0);\n        if (!img)\n            return E_POINTER;\n\n        bool iswic2 = false;\n        auto pWIC = GetWICFactory(iswic2);\n        if (!pWIC)\n            return E_NOINTERFACE;\n\n        if (img->rowPitch > UINT32_MAX || img->slicePitch > UINT32_MAX)\n            return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n        if (memcmp(&convertGUID, &GUID_NULL, sizeof(GUID)) == 0)\n        {\n            hr = frame->CopyPixels(nullptr, static_cast<UINT>(img->rowPitch), static_cast<UINT>(img->slicePitch), img->pixels);\n            if (FAILED(hr))\n                return hr;\n        }\n        else\n        {\n            ComPtr<IWICFormatConverter> FC;\n            hr = pWIC->CreateFormatConverter(FC.GetAddressOf());\n            if (FAILED(hr))\n                return hr;\n\n            WICPixelFormatGUID pixelFormat;\n            hr = frame->GetPixelFormat(&pixelFormat);\n            if (FAILED(hr))\n                return hr;\n\n            BOOL canConvert = FALSE;\n            hr = FC->CanConvert(pixelFormat, convertGUID, &canConvert);\n            if (FAILED(hr) || !canConvert)\n            {\n                return E_UNEXPECTED;\n            }\n\n            hr = FC->Initialize(frame, convertGUID, GetWICDither(flags), nullptr,\n                0, WICBitmapPaletteTypeMedianCut);\n            if (FAILED(hr))\n                return hr;\n\n            hr = FC->CopyPixels(nullptr, static_cast<UINT>(img->rowPitch), static_cast<UINT>(img->slicePitch), img->pixels);\n            if (FAILED(hr))\n                return hr;\n        }\n\n        return S_OK;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    // Decodes an image array, resizing/format converting as needed\n    //-------------------------------------------------------------------------------------\n    HRESULT DecodeMultiframe(\n        WIC_FLAGS flags,\n        const TexMetadata& metadata,\n        _In_ IWICBitmapDecoder *decoder,\n        _Inout_ ScratchImage& image)\n    {\n        if (!decoder)\n            return E_POINTER;\n\n        HRESULT hr = image.Initialize2D(metadata.format, metadata.width, metadata.height, metadata.arraySize, 1);\n        if (FAILED(hr))\n            return hr;\n\n        bool iswic2 = false;\n        auto pWIC = GetWICFactory(iswic2);\n        if (!pWIC)\n            return E_NOINTERFACE;\n\n        WICPixelFormatGUID sourceGUID;\n        if (!DXGIToWIC(metadata.format, sourceGUID))\n            return E_FAIL;\n\n        for (size_t index = 0; index < metadata.arraySize; ++index)\n        {\n            const Image* img = image.GetImage(0, index, 0);\n            if (!img)\n                return E_POINTER;\n\n            if (img->rowPitch > UINT32_MAX || img->slicePitch > UINT32_MAX)\n                return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n            ComPtr<IWICBitmapFrameDecode> frame;\n            hr = decoder->GetFrame(static_cast<UINT>(index), frame.GetAddressOf());\n            if (FAILED(hr))\n                return hr;\n\n            WICPixelFormatGUID pfGuid;\n            hr = frame->GetPixelFormat(&pfGuid);\n            if (FAILED(hr))\n                return hr;\n\n            UINT w, h;\n            hr = frame->GetSize(&w, &h);\n            if (FAILED(hr))\n                return hr;\n\n            if (w == metadata.width && h == metadata.height)\n            {\n                // This frame does not need resized\n                if (memcmp(&pfGuid, &sourceGUID, sizeof(WICPixelFormatGUID)) == 0)\n                {\n                    hr = frame->CopyPixels(nullptr, static_cast<UINT>(img->rowPitch), static_cast<UINT>(img->slicePitch), img->pixels);\n                    if (FAILED(hr))\n                        return hr;\n                }\n                else\n                {\n                    ComPtr<IWICFormatConverter> FC;\n                    hr = pWIC->CreateFormatConverter(FC.GetAddressOf());\n                    if (FAILED(hr))\n                        return hr;\n\n                    BOOL canConvert = FALSE;\n                    hr = FC->CanConvert(pfGuid, sourceGUID, &canConvert);\n                    if (FAILED(hr) || !canConvert)\n                    {\n                        return E_UNEXPECTED;\n                    }\n\n                    hr = FC->Initialize(frame.Get(), sourceGUID, GetWICDither(flags), nullptr,\n                        0, WICBitmapPaletteTypeMedianCut);\n                    if (FAILED(hr))\n                        return hr;\n\n                    hr = FC->CopyPixels(nullptr, static_cast<UINT>(img->rowPitch), static_cast<UINT>(img->slicePitch), img->pixels);\n                    if (FAILED(hr))\n                        return hr;\n                }\n            }\n            else\n            {\n                // This frame needs resizing\n                ComPtr<IWICBitmapScaler> scaler;\n                hr = pWIC->CreateBitmapScaler(scaler.GetAddressOf());\n                if (FAILED(hr))\n                    return hr;\n\n                hr = scaler->Initialize(frame.Get(),\n                    static_cast<UINT>(metadata.width), static_cast<UINT>(metadata.height),\n                    GetWICInterp(flags));\n                if (FAILED(hr))\n                    return hr;\n\n                WICPixelFormatGUID pfScaler;\n                hr = scaler->GetPixelFormat(&pfScaler);\n                if (FAILED(hr))\n                    return hr;\n\n                if (memcmp(&pfScaler, &sourceGUID, sizeof(WICPixelFormatGUID)) == 0)\n                {\n                    hr = scaler->CopyPixels(nullptr, static_cast<UINT>(img->rowPitch), static_cast<UINT>(img->slicePitch), img->pixels);\n                    if (FAILED(hr))\n                        return hr;\n                }\n                else\n                {\n                    // The WIC bitmap scaler is free to return a different pixel format than the source image, so here we\n                    // convert it to our desired format\n                    ComPtr<IWICFormatConverter> FC;\n                    hr = pWIC->CreateFormatConverter(FC.GetAddressOf());\n                    if (FAILED(hr))\n                        return hr;\n\n                    BOOL canConvert = FALSE;\n                    hr = FC->CanConvert(pfScaler, sourceGUID, &canConvert);\n                    if (FAILED(hr) || !canConvert)\n                    {\n                        return E_UNEXPECTED;\n                    }\n\n                    hr = FC->Initialize(scaler.Get(), sourceGUID, GetWICDither(flags), nullptr,\n                        0, WICBitmapPaletteTypeMedianCut);\n                    if (FAILED(hr))\n                        return hr;\n\n                    hr = FC->CopyPixels(nullptr, static_cast<UINT>(img->rowPitch), static_cast<UINT>(img->slicePitch), img->pixels);\n                    if (FAILED(hr))\n                        return hr;\n                }\n            }\n        }\n\n        return S_OK;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    // Encodes image metadata\n    //-------------------------------------------------------------------------------------\n    HRESULT EncodeMetadata(\n        WIC_FLAGS flags,\n        _In_ IWICBitmapFrameEncode* frame,\n        const GUID& containerFormat,\n        DXGI_FORMAT format)\n    {\n        if (!frame)\n            return E_POINTER;\n\n        ComPtr<IWICMetadataQueryWriter> metawriter;\n        HRESULT hr = frame->GetMetadataQueryWriter(metawriter.GetAddressOf());\n        if (SUCCEEDED(hr))\n        {\n            PROPVARIANT value;\n            PropVariantInit(&value);\n\n            const bool sRGB = ((flags & WIC_FLAGS_FORCE_LINEAR) == 0) && ((flags & WIC_FLAGS_FORCE_SRGB) != 0 || IsSRGB(format));\n\n            value.vt = VT_LPSTR;\n            value.pszVal = const_cast<char*>(\"DirectXTex\");\n\n            if (memcmp(&containerFormat, &GUID_ContainerFormatPng, sizeof(GUID)) == 0)\n            {\n                // Set Software name\n                std::ignore = metawriter->SetMetadataByName(L\"/tEXt/{str=Software}\", &value);\n\n                // Set sRGB chunk\n                if (sRGB)\n                {\n                    value.vt = VT_UI1;\n                    value.bVal = 0;\n                    std::ignore = metawriter->SetMetadataByName(L\"/sRGB/RenderingIntent\", &value);\n                }\n                else\n                {\n                    // add gAMA chunk with gamma 1.0\n                    value.vt = VT_UI4;\n                    value.uintVal = 100000; // gama value * 100,000 -- i.e. gamma 1.0\n                    std::ignore = metawriter->SetMetadataByName(L\"/gAMA/ImageGamma\", &value);\n\n                    // remove sRGB chunk which is added by default.\n                    std::ignore = metawriter->RemoveMetadataByName(L\"/sRGB/RenderingIntent\");\n                }\n            }\n        #if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)\n            else if (memcmp(&containerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID)) == 0)\n            {\n                // Set Software name\n                std::ignore = metawriter->SetMetadataByName(L\"/app1/ifd/{ushort=305}\", &value);\n\n                if (sRGB)\n                {\n                    // Set EXIF Colorspace of sRGB\n                    value.vt = VT_UI2;\n                    value.uiVal = 1;\n                    std::ignore = metawriter->SetMetadataByName(L\"/app1/ifd/exif/{ushort=40961}\", &value);\n                }\n            }\n            else if (memcmp(&containerFormat, &GUID_ContainerFormatTiff, sizeof(GUID)) == 0)\n            {\n                // Set Software name\n                std::ignore = metawriter->SetMetadataByName(L\"/ifd/{ushort=305}\", &value);\n\n                if (sRGB)\n                {\n                    // Set EXIF Colorspace of sRGB\n                    value.vt = VT_UI2;\n                    value.uiVal = 1;\n                    std::ignore = metawriter->SetMetadataByName(L\"/ifd/exif/{ushort=40961}\", &value);\n                }\n            }\n        #else\n            else\n            {\n                // Set Software name\n                std::ignore = metawriter->SetMetadataByName(L\"System.ApplicationName\", &value);\n\n                if (sRGB)\n                {\n                    // Set EXIF Colorspace of sRGB\n                    value.vt = VT_UI2;\n                    value.uiVal = 1;\n                    std::ignore = metawriter->SetMetadataByName(L\"System.Image.ColorSpace\", &value);\n                }\n            }\n        #endif\n        }\n        else if (hr == WINCODEC_ERR_UNSUPPORTEDOPERATION)\n        {\n            // Some formats just don't support metadata (BMP, ICO, etc.), so ignore this failure\n            hr = S_OK;\n        }\n\n        return hr;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    // Encodes a single frame\n    //-------------------------------------------------------------------------------------\n    HRESULT EncodeImage(\n        const Image& image,\n        WIC_FLAGS flags,\n        _In_ REFGUID containerFormat,\n        _In_ IWICBitmapFrameEncode* frame,\n        _In_opt_ IPropertyBag2* props,\n        _In_opt_ const GUID* targetFormat)\n    {\n        if (!frame)\n            return E_INVALIDARG;\n\n        if (!image.pixels)\n            return E_POINTER;\n\n        WICPixelFormatGUID pfGuid;\n        if (!DXGIToWIC(image.format, pfGuid))\n            return HRESULT_E_NOT_SUPPORTED;\n\n        HRESULT hr = frame->Initialize(props);\n        if (FAILED(hr))\n            return hr;\n\n        if ((image.width > UINT32_MAX) || (image.height > UINT32_MAX))\n            return E_INVALIDARG;\n\n        if (image.rowPitch > UINT32_MAX || image.slicePitch > UINT32_MAX)\n            return HRESULT_E_ARITHMETIC_OVERFLOW;\n\n        hr = frame->SetSize(static_cast<UINT>(image.width), static_cast<UINT>(image.height));\n        if (FAILED(hr))\n            return hr;\n\n        hr = frame->SetResolution(72, 72);\n        if (FAILED(hr))\n            return hr;\n\n        WICPixelFormatGUID targetGuid = (targetFormat) ? (*targetFormat) : pfGuid;\n        hr = frame->SetPixelFormat(&targetGuid);\n        if (FAILED(hr))\n            return hr;\n\n        if (targetFormat && memcmp(targetFormat, &targetGuid, sizeof(WICPixelFormatGUID)) != 0)\n        {\n            // Requested output pixel format is not supported by the WIC codec\n            return E_FAIL;\n        }\n\n        hr = EncodeMetadata(flags, frame, containerFormat, image.format);\n        if (FAILED(hr))\n            return hr;\n\n        if (memcmp(&targetGuid, &pfGuid, sizeof(WICPixelFormatGUID)) != 0)\n        {\n            // Conversion required to write\n            bool iswic2 = false;\n            auto pWIC = GetWICFactory(iswic2);\n            if (!pWIC)\n                return E_NOINTERFACE;\n\n            ComPtr<IWICBitmap> source;\n            hr = pWIC->CreateBitmapFromMemory(static_cast<UINT>(image.width), static_cast<UINT>(image.height), pfGuid,\n                static_cast<UINT>(image.rowPitch), static_cast<UINT>(image.slicePitch),\n                image.pixels, source.GetAddressOf());\n            if (FAILED(hr))\n                return hr;\n\n            ComPtr<IWICFormatConverter> FC;\n            hr = pWIC->CreateFormatConverter(FC.GetAddressOf());\n            if (FAILED(hr))\n                return hr;\n\n            BOOL canConvert = FALSE;\n            hr = FC->CanConvert(pfGuid, targetGuid, &canConvert);\n            if (FAILED(hr) || !canConvert)\n            {\n                return E_UNEXPECTED;\n            }\n\n            hr = FC->Initialize(source.Get(), targetGuid, GetWICDither(flags), nullptr,\n                0, WICBitmapPaletteTypeMedianCut);\n            if (FAILED(hr))\n                return hr;\n\n            WICRect rect = { 0, 0, static_cast<INT>(image.width), static_cast<INT>(image.height) };\n            hr = frame->WriteSource(FC.Get(), &rect);\n            if (FAILED(hr))\n                return hr;\n        }\n        else\n        {\n            // No conversion required\n            hr = frame->WritePixels(static_cast<UINT>(image.height), static_cast<UINT>(image.rowPitch), static_cast<UINT>(image.slicePitch),\n                reinterpret_cast<uint8_t*>(image.pixels));\n            if (FAILED(hr))\n                return hr;\n        }\n\n        hr = frame->Commit();\n        if (FAILED(hr))\n            return hr;\n\n        return S_OK;\n    }\n\n    HRESULT EncodeSingleFrame(\n        const Image& image,\n        WIC_FLAGS flags,\n        _In_ REFGUID containerFormat,\n        _Inout_ IStream* stream,\n        _In_opt_ const GUID* targetFormat,\n        _In_opt_ std::function<void(IPropertyBag2*)> setCustomProps)\n    {\n        if (!stream)\n            return E_INVALIDARG;\n\n        // Initialize WIC\n        bool iswic2 = false;\n        auto pWIC = GetWICFactory(iswic2);\n        if (!pWIC)\n            return E_NOINTERFACE;\n\n        ComPtr<IWICBitmapEncoder> encoder;\n        HRESULT hr = pWIC->CreateEncoder(containerFormat, nullptr, encoder.GetAddressOf());\n        if (FAILED(hr))\n            return hr;\n\n        hr = encoder->Initialize(stream, WICBitmapEncoderNoCache);\n        if (FAILED(hr))\n            return hr;\n\n        ComPtr<IWICBitmapFrameEncode> frame;\n        ComPtr<IPropertyBag2> props;\n        hr = encoder->CreateNewFrame(frame.GetAddressOf(), props.GetAddressOf());\n        if (FAILED(hr))\n            return hr;\n\n        if (memcmp(&containerFormat, &GUID_ContainerFormatBmp, sizeof(WICPixelFormatGUID)) == 0 && iswic2)\n        {\n            // Opt-in to the WIC2 support for writing 32-bit Windows BMP files with an alpha channel\n            PROPBAG2 option = {};\n            option.pstrName = const_cast<wchar_t*>(L\"EnableV5Header32bppBGRA\");\n\n            VARIANT varValue;\n            varValue.vt = VT_BOOL;\n            varValue.boolVal = VARIANT_TRUE;\n            std::ignore = props->Write(1, &option, &varValue);\n        }\n\n        if (setCustomProps)\n        {\n            setCustomProps(props.Get());\n        }\n\n        hr = EncodeImage(image, flags, containerFormat, frame.Get(), props.Get(), targetFormat);\n        if (FAILED(hr))\n            return hr;\n\n        hr = encoder->Commit();\n        if (FAILED(hr))\n            return hr;\n\n        return S_OK;\n    }\n\n\n    //-------------------------------------------------------------------------------------\n    // Encodes an image array\n    //-------------------------------------------------------------------------------------\n    HRESULT EncodeMultiframe(\n        _In_reads_(nimages) const Image* images,\n        size_t nimages,\n        WIC_FLAGS flags,\n        _In_ REFGUID containerFormat,\n        _Inout_ IStream* stream,\n        _In_opt_ const GUID* targetFormat,\n        _In_opt_ std::function<void(IPropertyBag2*)> setCustomProps)\n    {\n        if (!stream || nimages < 2)\n            return E_INVALIDARG;\n\n        if (!images)\n            return E_POINTER;\n\n        // Initialize WIC\n        bool iswic2 = false;\n        auto pWIC = GetWICFactory(iswic2);\n        if (!pWIC)\n            return E_NOINTERFACE;\n\n        ComPtr<IWICBitmapEncoder> encoder;\n        HRESULT hr = pWIC->CreateEncoder(containerFormat, nullptr, encoder.GetAddressOf());\n        if (FAILED(hr))\n            return hr;\n\n        ComPtr<IWICBitmapEncoderInfo> einfo;\n        hr = encoder->GetEncoderInfo(einfo.GetAddressOf());\n        if (FAILED(hr))\n            return hr;\n\n        BOOL mframe = FALSE;\n        hr = einfo->DoesSupportMultiframe(&mframe);\n        if (FAILED(hr))\n            return hr;\n\n        if (!mframe)\n            return HRESULT_E_NOT_SUPPORTED;\n\n        hr = encoder->Initialize(stream, WICBitmapEncoderNoCache);\n        if (FAILED(hr))\n            return hr;\n\n        for (size_t index = 0; index < nimages; ++index)\n        {\n            ComPtr<IWICBitmapFrameEncode> frame;\n            ComPtr<IPropertyBag2> props;\n            hr = encoder->CreateNewFrame(frame.GetAddressOf(), props.GetAddressOf());\n            if (FAILED(hr))\n                return hr;\n\n            if (setCustomProps)\n            {\n                setCustomProps(props.Get());\n            }\n\n            hr = EncodeImage(images[index], flags, containerFormat, frame.Get(), props.Get(), targetFormat);\n            if (FAILED(hr))\n                return hr;\n        }\n\n        hr = encoder->Commit();\n        if (FAILED(hr))\n            return hr;\n\n        return S_OK;\n    }\n}\n\n\n//=====================================================================================\n// Entry-points\n//=====================================================================================\n\n//-------------------------------------------------------------------------------------\n// Obtain metadata from WIC-supported file in memory\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::GetMetadataFromWICMemory(\n    const void* pSource,\n    size_t size,\n    WIC_FLAGS flags,\n    TexMetadata& metadata,\n    std::function<void(IWICMetadataQueryReader*)> getMQR)\n{\n    if (!pSource || size == 0)\n        return E_INVALIDARG;\n\n    if (size > UINT32_MAX)\n        return HRESULT_E_FILE_TOO_LARGE;\n\n    bool iswic2 = false;\n    auto pWIC = GetWICFactory(iswic2);\n    if (!pWIC)\n        return E_NOINTERFACE;\n\n    // Create input stream for memory\n    ComPtr<IWICStream> stream;\n    HRESULT hr = pWIC->CreateStream(stream.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    hr = stream->InitializeFromMemory(static_cast<BYTE*>(const_cast<void*>(pSource)),\n        static_cast<UINT>(size));\n    if (FAILED(hr))\n        return hr;\n\n    // Initialize WIC\n    ComPtr<IWICBitmapDecoder> decoder;\n    hr = pWIC->CreateDecoderFromStream(stream.Get(), nullptr, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    ComPtr<IWICBitmapFrameDecode> frame;\n    hr = decoder->GetFrame(0, frame.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    // Get metadata\n    hr = DecodeMetadata(flags, iswic2, decoder.Get(), frame.Get(), metadata, nullptr, getMQR);\n    if (FAILED(hr))\n        return hr;\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Obtain metadata from WIC-supported file on disk\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::GetMetadataFromWICFile(\n    const wchar_t* szFile,\n    WIC_FLAGS flags,\n    TexMetadata& metadata,\n    std::function<void(IWICMetadataQueryReader*)> getMQR)\n{\n    if (!szFile)\n        return E_INVALIDARG;\n\n    bool iswic2 = false;\n    auto pWIC = GetWICFactory(iswic2);\n    if (!pWIC)\n        return E_NOINTERFACE;\n\n    // Initialize WIC\n    ComPtr<IWICBitmapDecoder> decoder;\n    HRESULT hr = pWIC->CreateDecoderFromFilename(szFile, nullptr, GENERIC_READ, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    ComPtr<IWICBitmapFrameDecode> frame;\n    hr = decoder->GetFrame(0, frame.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    // Get metadata\n    hr = DecodeMetadata(flags, iswic2, decoder.Get(), frame.Get(), metadata, nullptr, getMQR);\n    if (FAILED(hr))\n        return hr;\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Load a WIC-supported file in memory\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadFromWICMemory(\n    const void* pSource,\n    size_t size,\n    WIC_FLAGS flags,\n    TexMetadata* metadata,\n    ScratchImage& image,\n    std::function<void(IWICMetadataQueryReader*)> getMQR)\n{\n    if (!pSource || size == 0)\n        return E_INVALIDARG;\n\n    if (size > UINT32_MAX)\n        return HRESULT_E_FILE_TOO_LARGE;\n\n    bool iswic2 = false;\n    auto pWIC = GetWICFactory(iswic2);\n    if (!pWIC)\n        return E_NOINTERFACE;\n\n    image.Release();\n\n    // Create input stream for memory\n    ComPtr<IWICStream> stream;\n    HRESULT hr = pWIC->CreateStream(stream.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    hr = stream->InitializeFromMemory(static_cast<uint8_t*>(const_cast<void*>(pSource)), static_cast<DWORD>(size));\n    if (FAILED(hr))\n        return hr;\n\n    // Initialize WIC\n    ComPtr<IWICBitmapDecoder> decoder;\n    hr = pWIC->CreateDecoderFromStream(stream.Get(), nullptr, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    ComPtr<IWICBitmapFrameDecode> frame;\n    hr = decoder->GetFrame(0, frame.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    // Get metadata\n    TexMetadata mdata = {};\n    WICPixelFormatGUID convertGUID = {};\n    hr = DecodeMetadata(flags, iswic2, decoder.Get(), frame.Get(), mdata, &convertGUID, getMQR);\n    if (FAILED(hr))\n        return hr;\n\n    if ((mdata.arraySize > 1) && (flags & WIC_FLAGS_ALL_FRAMES))\n    {\n        hr = DecodeMultiframe(flags, mdata, decoder.Get(), image);\n    }\n    else\n    {\n        hr = DecodeSingleFrame(flags, mdata, convertGUID, frame.Get(), image);\n    }\n\n    if (FAILED(hr))\n    {\n        image.Release();\n        return hr;\n    }\n\n    if (metadata)\n        memcpy(metadata, &mdata, sizeof(TexMetadata));\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Load a WIC-supported file from disk\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::LoadFromWICFile(\n    const wchar_t* szFile,\n    WIC_FLAGS flags,\n    TexMetadata* metadata,\n    ScratchImage& image,\n    std::function<void(IWICMetadataQueryReader*)> getMQR)\n{\n    if (!szFile)\n        return E_INVALIDARG;\n\n    bool iswic2 = false;\n    auto pWIC = GetWICFactory(iswic2);\n    if (!pWIC)\n        return E_NOINTERFACE;\n\n    image.Release();\n\n    // Initialize WIC\n    ComPtr<IWICBitmapDecoder> decoder;\n    HRESULT hr = pWIC->CreateDecoderFromFilename(szFile, nullptr, GENERIC_READ, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    ComPtr<IWICBitmapFrameDecode> frame;\n    hr = decoder->GetFrame(0, frame.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    // Get metadata\n    TexMetadata mdata = {};\n    WICPixelFormatGUID convertGUID = {};\n    hr = DecodeMetadata(flags, iswic2, decoder.Get(), frame.Get(), mdata, &convertGUID, getMQR);\n    if (FAILED(hr))\n        return hr;\n\n    if ((mdata.arraySize > 1) && (flags & WIC_FLAGS_ALL_FRAMES))\n    {\n        hr = DecodeMultiframe(flags, mdata, decoder.Get(), image);\n    }\n    else\n    {\n        hr = DecodeSingleFrame(flags, mdata, convertGUID, frame.Get(), image);\n    }\n\n    if (FAILED(hr))\n    {\n        image.Release();\n        return hr;\n    }\n\n    if (metadata)\n        memcpy(metadata, &mdata, sizeof(TexMetadata));\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Save a WIC-supported file to memory\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::SaveToWICMemory(\n    const Image& image,\n    WIC_FLAGS flags,\n    REFGUID containerFormat,\n    Blob& blob,\n    const GUID* targetFormat,\n    std::function<void(IPropertyBag2*)> setCustomProps)\n{\n    if (!image.pixels)\n        return E_POINTER;\n\n    HRESULT hr = blob.Initialize(65535u);\n    if (FAILED(hr))\n        return hr;\n\n    ComPtr<MemoryStreamOnBlob> stream;\n    hr = MemoryStreamOnBlob::CreateMemoryStream(&stream, blob);\n    if (FAILED(hr))\n    {\n        blob.Release();\n        return hr;\n    }\n\n    hr = EncodeSingleFrame(image, flags, containerFormat, stream.Get(), targetFormat, setCustomProps);\n    if (FAILED(hr))\n    {\n        blob.Release();\n        return hr;\n    }\n\n    hr = stream->Finialize();\n    if (FAILED(hr))\n    {\n        blob.Release();\n        return hr;\n    }\n\n    stream.Reset();\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::SaveToWICMemory(\n    const Image* images,\n    size_t nimages,\n    WIC_FLAGS flags,\n    REFGUID containerFormat,\n    Blob& blob,\n    const GUID* targetFormat,\n    std::function<void(IPropertyBag2*)> setCustomProps)\n{\n    if (!images || nimages == 0)\n        return E_INVALIDARG;\n\n    HRESULT hr = blob.Initialize(65535u);\n    if (FAILED(hr))\n        return hr;\n\n    ComPtr<MemoryStreamOnBlob> stream;\n    hr = MemoryStreamOnBlob::CreateMemoryStream(&stream, blob);\n    if (FAILED(hr))\n    {\n        blob.Release();\n        return hr;\n    }\n\n    if (nimages > 1)\n        hr = EncodeMultiframe(images, nimages, flags, containerFormat, stream.Get(), targetFormat, setCustomProps);\n    else\n        hr = EncodeSingleFrame(images[0], flags, containerFormat, stream.Get(), targetFormat, setCustomProps);\n\n    if (FAILED(hr))\n    {\n        blob.Release();\n        return hr;\n    }\n\n    hr = stream->Finialize();\n    if (FAILED(hr))\n    {\n        blob.Release();\n        return hr;\n    }\n\n    stream.Reset();\n\n    return S_OK;\n}\n\n\n//-------------------------------------------------------------------------------------\n// Save a WIC-supported file to disk\n//-------------------------------------------------------------------------------------\n_Use_decl_annotations_\nHRESULT DirectX::SaveToWICFile(\n    const Image& image,\n    WIC_FLAGS flags,\n    REFGUID containerFormat,\n    const wchar_t* szFile,\n    const GUID* targetFormat,\n    std::function<void(IPropertyBag2*)> setCustomProps)\n{\n    if (!szFile)\n        return E_INVALIDARG;\n\n    if (!image.pixels)\n        return E_POINTER;\n\n    bool iswic2 = false;\n    auto pWIC = GetWICFactory(iswic2);\n    if (!pWIC)\n        return E_NOINTERFACE;\n\n    ComPtr<IWICStream> stream;\n    HRESULT hr = pWIC->CreateStream(stream.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    hr = stream->InitializeFromFilename(szFile, GENERIC_WRITE);\n    if (FAILED(hr))\n        return hr;\n\n    hr = EncodeSingleFrame(image, flags, containerFormat, stream.Get(), targetFormat, setCustomProps);\n    if (FAILED(hr))\n    {\n        stream.Reset();\n        std::ignore = DeleteFileW(szFile);\n        return hr;\n    }\n\n    return S_OK;\n}\n\n_Use_decl_annotations_\nHRESULT DirectX::SaveToWICFile(\n    const Image* images,\n    size_t nimages,\n    WIC_FLAGS flags,\n    REFGUID containerFormat,\n    const wchar_t* szFile,\n    const GUID* targetFormat,\n    std::function<void(IPropertyBag2*)> setCustomProps)\n{\n    if (!szFile || !images || nimages == 0)\n        return E_INVALIDARG;\n\n    bool iswic2 = false;\n    auto pWIC = GetWICFactory(iswic2);\n    if (!pWIC)\n        return E_NOINTERFACE;\n\n    ComPtr<IWICStream> stream;\n    HRESULT hr = pWIC->CreateStream(stream.GetAddressOf());\n    if (FAILED(hr))\n        return hr;\n\n    hr = stream->InitializeFromFilename(szFile, GENERIC_WRITE);\n    if (FAILED(hr))\n        return hr;\n\n    if (nimages > 1)\n        hr = EncodeMultiframe(images, nimages, flags, containerFormat, stream.Get(), targetFormat, setCustomProps);\n    else\n        hr = EncodeSingleFrame(images[0], flags, containerFormat, stream.Get(), targetFormat, setCustomProps);\n\n    if (FAILED(hr))\n    {\n        stream.Reset();\n        std::ignore = DeleteFileW(szFile);\n        return hr;\n    }\n\n    return S_OK;\n}\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/Shaders/Compiled/BC6HEncode_EncodeBlockCS.inc",
    "content": "#if 0\n//\n// Generated by Microsoft (R) D3D Shader Disassembler\n//\n//\n// Input signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Input\n//\n// Output signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Output\ncs_4_0\ndcl_globalFlags refactoringAllowed\ndcl_immediateConstantBuffer { { 0x0000cccc, 15, 0, 0},\n                              { 0x00008888, 15, 0, 0},\n                              { 0x0000eeee, 15, 0, 0},\n                              { 0x0000ecc8, 15, 1, 0},\n                              { 0x0000c880, 15, 1, 0},\n                              { 0x0000feec, 15, 1, 1},\n                              { 0x0000fec8, 15, 1, 1},\n                              { 0x0000ec80, 15, 2, 1},\n                              { 0x0000c800, 15, 2, 1},\n                              { 0x0000ffec, 15, 2, 1},\n                              { 0x0000fe80, 15, 2, 1},\n                              { 0x0000e800, 15, 2, 1},\n                              { 0x0000ffe8, 15, 3, 1},\n                              { 0x0000ff00, 15, 3, 1},\n                              { 0x0000fff0, 15, 3, 2},\n                              { 0x0000f000, 15, 3, 2},\n                              { 0x0000f710, 15, 4, 2},\n                              { 142, 2, 4, 2},\n                              { 0x00007100, 8, 4, 2},\n                              { 2254, 2, 4, 2},\n                              { 140, 2, 5, 2},\n                              { 0x00007310, 8, 5, 2},\n                              { 0x00003100, 8, 5, 2},\n                              { 0x00008cce, 15, 5, 3},\n                              { 2188, 2, 6, 3},\n                              { 0x00003110, 8, 6, 3},\n                              { 0x00006666, 2, 6, 3},\n                              { 0x0000366c, 2, 6, 3},\n                              { 6120, 8, 6, 3},\n                              { 4080, 8, 7, 3},\n                              { 0x0000718e, 2, 7, 3},\n                              { 0x0000399c, 2, 7, 3},\n                              { -1, 0, 7, 3},\n                              { -1, 0, 8, 4},\n                              { -1, 0, 8, 4},\n                              { -1, 0, 8, 4},\n                              { -1, 0, 8, 4},\n                              { -1, 0, 9, 4},\n                              { -1, 0, 9, 4},\n                              { -1, 0, 9, 4},\n                              { -1, 0, 9, 4},\n                              { 0, 0, 10, 4},\n                              { 0, 0, 10, 5},\n                              { -1, 0, 10, 5},\n                              { -1, 0, 10, 5},\n                              { -1, 0, 10, 5},\n                              { 0, 0, 11, 5},\n                              { 0, 0, 11, 5},\n                              { 0, 0, 11, 5},\n                              { 0, 0, 11, 5},\n                              { 0, 0, 12, 5},\n                              { 0, 0, 12, 6},\n                              { 0, 0, 12, 6},\n                              { 0, 0, 12, 6},\n                              { 0, 0, 13, 6},\n                              { 0, 0, 13, 6},\n                              { 0, 0, 13, 6},\n                              { 0, 0, 13, 6},\n                              { 0, 0, 14, 6},\n                              { 0, 0, 14, 6},\n                              { 0, 0, 14, 7},\n                              { 0, 0, 14, 7},\n                              { 0, 0, 15, 7},\n                              { 0, 0, 15, 7},\n                              { 10, 5, 5, 5},\n                              { 7, 6, 6, 6},\n                              { 11, 5, 4, 4},\n                              { 11, 4, 5, 4},\n                              { 11, 4, 4, 5},\n                              { 9, 5, 5, 5},\n                              { 8, 6, 5, 5},\n                              { 8, 5, 6, 5},\n                              { 8, 5, 5, 6},\n                              { 6, 6, 6, 6},\n                              { 10, 10, 10, 10},\n                              { 11, 9, 9, 9},\n                              { 12, 8, 8, 8},\n                              { 16, 4, 4, 4} }\ndcl_constantbuffer CB0[2], immediateIndexed\ndcl_resource_texture2d (float,float,float,float) t0\ndcl_resource_structured t1, 16\ndcl_uav_structured u0, 16\ndcl_input vThreadIDInGroupFlattened\ndcl_input vThreadGroupID.x\ndcl_temps 18\ndcl_tgsm_structured g0, 84, 64\ndcl_thread_group 64, 1, 1\nushr r0.x, vThreadIDInGroupFlattened.x, l(5)\nishl r0.y, vThreadGroupID.x, l(1)\niadd r0.y, r0.y, cb0[1].x\niadd r0.x, r0.x, r0.y\nand r0.y, vThreadIDInGroupFlattened.x, l(32)\niadd r0.z, -r0.y, vThreadIDInGroupFlattened.x\nult r1.xyzw, r0.zzzz, l(16, 32, 2, 8)\nif_nz r1.x\n  udiv r0.w, null, r0.x, cb0[0].y\n  imad r2.x, -r0.w, cb0[0].y, r0.x\n  ishl r2.x, r2.x, l(2)\n  ishl r0.w, r0.w, l(2)\n  and r2.y, r0.z, l(3)\n  iadd r2.x, r2.y, r2.x\n  ushr r3.x, r0.z, l(2)\n  iadd r2.y, r0.w, r3.x\n  mov r2.zw, l(0,0,0,0)\n  ld r2.xyzw, r2.xyzw, t0.xyzw\n  dp3 r0.w, r2.xyzx, l(0.212600, 0.715200, 0.072200, 0.000000)\n  store_structured g0.x, vThreadIDInGroupFlattened.x, l(36), r0.w\n  ushr r3.xyz, r2.xyzx, l(16)\n  and r3.xyz, r3.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n  and r4.xyzw, r2.xxyy, l(0x7fffffff, 0x007fffff, 0x7fffffff, 0x007fffff)\n  ult r2.xy, l(0x47ffefff, 0x47ffefff, 0, 0), r4.xzxx\n  ult r5.xy, r4.xzxx, l(0x38800000, 0x38800000, 0, 0)\n  ushr r5.zw, r4.xxxz, l(23)\n  iadd r5.zw, -r5.zzzw, l(0, 0, 113, 113)\n  iadd r4.yw, r4.yyyw, l(0, 0x00800000, 0, 0x00800000)\n  ushr r6.x, r4.y, r5.z\n  ushr r6.y, r4.w, r5.w\n  iadd r4.xy, r4.xzxx, l(0xc8000000, 0xc8000000, 0, 0)\n  movc r4.xy, r5.xyxx, r6.xyxx, r4.xyxx\n  iadd r4.zw, r4.xxxy, l(0, 0, 4095, 4095)\n  ushr r4.xy, r4.xyxx, l(13)\n  and r4.xy, r4.xyxx, l(1, 1, 0, 0)\n  iadd r4.xy, r4.xyxx, r4.zwzz\n  ushr r4.xy, r4.xyxx, l(13)\n  and r4.xy, r4.xyxx, l(0x00007fff, 0x00007fff, 0, 0)\n  movc r2.xy, r2.xyxx, l(0x00007fff,0x00007fff,0,0), r4.xyxx\n  iadd r4.xy, r3.xyxx, r2.xyxx\n  and r2.xy, r2.zzzz, l(0x7fffffff, 0x007fffff, 0, 0)\n  ult r0.w, l(0x47ffefff), r2.x\n  ult r2.z, r2.x, l(0x38800000)\n  ushr r2.w, r2.x, l(23)\n  iadd r2.w, -r2.w, l(113)\n  iadd r2.y, r2.y, l(0x00800000)\n  ushr r2.y, r2.y, r2.w\n  iadd r2.x, r2.x, l(0xc8000000)\n  movc r2.x, r2.z, r2.y, r2.x\n  iadd r2.y, r2.x, l(4095)\n  ushr r2.x, r2.x, l(13)\n  and r2.x, r2.x, l(1)\n  iadd r2.x, r2.x, r2.y\n  ushr r2.x, r2.x, l(13)\n  and r2.x, r2.x, l(0x00007fff)\n  movc r0.w, r0.w, l(0x00007fff), r2.x\n  iadd r4.z, r3.z, r0.w\n  ieq r0.w, cb0[0].z, l(95)\n  ishl r2.xyz, r4.xyzx, l(6)\n  udiv r2.xyz, null, r2.xyzx, l(31, 31, 31, 0)\n  ult r3.xyz, r4.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n  ieq r5.xyz, r4.xyzx, l(0x00007bff, 0x00007bff, 0x00007bff, 0)\n  ishl r4.xyz, r4.xyzx, l(5)\n  udiv r6.xyz, null, r4.xyzx, l(31, 31, 31, 0)\n  movc r6.xyz, r5.xyzx, l(0x00007fff,0x00007fff,0x00007fff,0), r6.xyzx\n  and r4.xyz, r4.xyzx, l(0x000fffe0, 0x000fffe0, 0x000fffe0, 0)\n  udiv r4.xyz, null, r4.xyzx, l(31, 31, 31, 0)\n  ineg r4.xyz, r4.xyzx\n  movc r4.xyz, r5.xyzx, l(0xffff8001,0xffff8001,0xffff8001,0), r4.xyzx\n  movc r3.xyz, r3.xyzx, r6.xyzx, r4.xyzx\n  movc r2.xyz, r0.wwww, r2.xyzx, r3.xyzx\n  store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(12), r2.xyzx\nendif \nsync_g_t\nld_structured r2.xy, r0.x, l(4), t1.xyxx\nif_nz r1.y\n  and r0.w, r0.z, l(15)\n  iadd r1.y, r0.w, r0.y\n  ld_structured r3.xyz, r1.y, l(12), g0.xyzx\n  ld_structured r3.w, r1.y, l(36), g0.xxxx\n  if_nz r1.x\n    ult r1.y, l(10), r2.x\n    if_nz r1.y\n      mov r4.xyzw, r3.xyzx\n      mov r5.xyzw, r3.yzww\n    else \n      ushr r1.y, icb[r2.y + 0].x, r0.z\n      and r1.y, r1.y, l(1)\n      movc r4.xyzw, r1.yyyy, l(0x7fffffff,0x7fffffff,0x7fffffff,-0.000000), r3.xyzx\n      movc r5.xyzw, r1.yyyy, l(-0.000000,-0.000000,340282346638528859811704183484516925440.000000,-340282346638528859811704183484516925440.000000), r3.yzww\n    endif \n  else \n    uge r1.y, l(10), r2.x\n    if_nz r1.y\n      ushr r0.w, icb[r2.y + 0].x, r0.w\n      and r0.w, r0.w, l(1)\n      ieq r0.w, r0.w, l(1)\n      movc r4.xyzw, r0.wwww, r3.xyzx, l(0x7fffffff,0x7fffffff,0x7fffffff,-0.000000)\n      movc r5.xyzw, r0.wwww, r3.yzww, l(-0.000000,-0.000000,340282346638528859811704183484516925440.000000,-340282346638528859811704183484516925440.000000)\n    else \n      mov r4.xyzw, l(0x7fffffff,0x7fffffff,0x7fffffff,-0.000000)\n      mov r5.xyzw, l(-0.000000,-0.000000,340282346638528859811704183484516925440.000000,-340282346638528859811704183484516925440.000000)\n    endif \n  endif \n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r4.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(68), r5.xyzw\nendif \nsync_g_t\nand r0.w, r0.z, l(15)\nult r3.xyzw, r0.wwww, l(8, 4, 2, 1)\nif_nz r3.x\n  ld_structured r4.x, vThreadIDInGroupFlattened.x, l(76), g0.xxxx\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(8)\n  ld_structured r5.x, r0.w, l(76), g0.xxxx\n  lt r1.y, r5.x, r4.x\n  if_nz r1.y\n    ld_structured r4.xyz, r0.w, l(52), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(52), r4.xyzx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(76), r5.x\n  endif \n  ld_structured r4.x, vThreadIDInGroupFlattened.x, l(80), g0.xxxx\n  ld_structured r5.x, r0.w, l(80), g0.xxxx\n  lt r1.y, r4.x, r5.x\n  if_nz r1.y\n    ld_structured r4.xyz, r0.w, l(64), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(64), r4.xyzx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(80), r5.x\n  endif \nendif \nsync_g_t\nif_nz r3.y\n  ld_structured r4.x, vThreadIDInGroupFlattened.x, l(76), g0.xxxx\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(4)\n  ld_structured r5.x, r0.w, l(76), g0.xxxx\n  lt r1.y, r5.x, r4.x\n  if_nz r1.y\n    ld_structured r4.xyz, r0.w, l(52), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(52), r4.xyzx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(76), r5.x\n  endif \n  ld_structured r4.x, vThreadIDInGroupFlattened.x, l(80), g0.xxxx\n  ld_structured r5.x, r0.w, l(80), g0.xxxx\n  lt r1.y, r4.x, r5.x\n  if_nz r1.y\n    ld_structured r4.xyz, r0.w, l(64), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(64), r4.xyzx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(80), r5.x\n  endif \nendif \nsync_g_t\nif_nz r3.z\n  ld_structured r4.x, vThreadIDInGroupFlattened.x, l(76), g0.xxxx\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(2)\n  ld_structured r5.x, r0.w, l(76), g0.xxxx\n  lt r1.y, r5.x, r4.x\n  if_nz r1.y\n    ld_structured r4.xyz, r0.w, l(52), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(52), r4.xyzx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(76), r5.x\n  endif \n  ld_structured r4.x, vThreadIDInGroupFlattened.x, l(80), g0.xxxx\n  ld_structured r5.x, r0.w, l(80), g0.xxxx\n  lt r1.y, r4.x, r5.x\n  if_nz r1.y\n    ld_structured r4.xyz, r0.w, l(64), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(64), r4.xyzx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(80), r5.x\n  endif \nendif \nsync_g_t\nif_nz r3.w\n  ld_structured r3.x, vThreadIDInGroupFlattened.x, l(76), g0.xxxx\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(1)\n  ld_structured r4.x, r0.w, l(76), g0.xxxx\n  lt r1.y, r4.x, r3.x\n  if_nz r1.y\n    ld_structured r3.xyz, r0.w, l(52), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(52), r3.xyzx\n  endif \n  ld_structured r3.x, vThreadIDInGroupFlattened.x, l(80), g0.xxxx\n  ld_structured r4.x, r0.w, l(80), g0.xxxx\n  lt r1.y, r3.x, r4.x\n  if_nz r1.y\n    ld_structured r3.xyz, r0.w, l(64), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(64), r3.xyzx\n  endif \nendif \nsync_g_t\nif_nz r1.z\n  ishl r0.w, r0.z, l(4)\n  iadd r0.w, r0.w, r0.y\n  ld_structured r3.xyz, r0.w, l(52), g0.xyzx\n  ld_structured r4.xyz, r0.w, l(64), g0.xyzx\n  ieq r0.w, r0.z, l(1)\n  uge r1.y, l(10), r2.x\n  and r0.w, r0.w, r1.y\n  if_nz r0.w\n    mov r0.w, icb[r2.y + 0].y\n  else \n    mov r0.w, l(0)\n  endif \n  iadd r5.xyz, -r3.xyzx, r4.xyzx\n  itof r5.xyz, r5.xyzx\n  dp3 r1.y, r5.xyzx, r5.xyzx\n  iadd r0.w, r0.w, r0.y\n  ld_structured r6.xyz, r0.w, l(12), g0.xyzx\n  iadd r6.xyz, -r3.xyzx, r6.xyzx\n  itof r6.xyz, r6.xyzx\n  dp3 r0.w, r5.xyzx, r6.xyzx\n  lt r2.z, l(0.000000), r1.y\n  ge r2.w, r0.w, l(0.000000)\n  and r2.z, r2.w, r2.z\n  mul r0.w, r0.w, l(63.499989)\n  div r0.w, r0.w, r1.y\n  ftou r0.w, r0.w\n  ult r0.w, l(32), r0.w\n  and r0.w, r0.w, r2.z\n  mov r4.w, r3.x\n  mov r3.w, r4.x\n  movc r5.xyzw, r0.wwww, r4.xyzw, r3.xyzw\n  movc r2.zw, r0.wwww, r3.yyyz, r4.yyyz\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r5.xyzw\n  store_structured g0.xy, vThreadIDInGroupFlattened.x, l(68), r2.zwzz\nendif \nsync_g_t\nif_nz r1.x\n  ult r0.w, l(10), r2.x\n  if_nz r0.w\n    mov r1.x, l(0)\n  else \n    mov r1.x, icb[r2.y + 0].x\n  endif \n  ushr r1.x, r1.x, r0.z\n  and r1.x, r1.x, l(1)\n  if_nz r1.x\n    iadd r1.x, r0.y, l(1)\n    ld_structured r3.xyz, r1.x, l(64), g0.xyzx\n    ld_structured r4.xyz, r1.x, l(52), g0.xyzx\n    iadd r3.xyz, r3.xyzx, -r4.xyzx\n    itof r3.xyz, r3.xyzx\n    ld_structured r5.xyz, vThreadIDInGroupFlattened.x, l(12), g0.xyzx\n    iadd r4.xyz, -r4.xyzx, r5.xyzx\n    itof r4.xyz, r4.xyzx\n    dp3 r1.x, r3.xyzx, r4.xyzx\n  else \n    ld_structured r4.xyz, r0.y, l(64), g0.xyzx\n    ld_structured r5.xyz, r0.y, l(52), g0.xyzx\n    iadd r4.xyz, r4.xyzx, -r5.xyzx\n    itof r3.xyz, r4.xyzx\n    ld_structured r4.xyz, vThreadIDInGroupFlattened.x, l(12), g0.xyzx\n    iadd r4.xyz, -r5.xyzx, r4.xyzx\n    itof r4.xyz, r4.xyzx\n    dp3 r1.x, r3.xyzx, r4.xyzx\n  endif \n  dp3 r1.y, r3.xyzx, r3.xyzx\n  if_nz r0.w\n    ge r0.w, l(0.000000), r1.y\n    ge r2.z, l(0.000000), r1.x\n    or r0.w, r0.w, r2.z\n    lt r2.z, r1.x, r1.y\n    mul r2.w, r1.x, l(63.499989)\n    div r2.w, r2.w, r1.y\n    ftou r2.w, r2.w\n    movc r2.z, r2.z, icb[r2.w + 0].z, l(15)\n    movc r0.w, r0.w, l(0), r2.z\n    ishl r3.x, r0.w, l(1)\n    ult r2.z, r0.z, l(8)\n    ishl r2.w, r0.z, l(2)\n    ishl r4.x, r0.w, r2.w\n    iadd r2.w, r2.w, l(-32)\n    ishl r4.w, r0.w, r2.w\n    mov r4.yz, l(0,0,0,0)\n    movc r2.zw, r2.zzzz, r4.xxxy, r4.zzzw\n    mov r3.y, l(0)\n    movc r3.xy, r0.zzzz, r2.zwzz, r3.xyxx\n  else \n    ge r0.w, l(0.000000), r1.y\n    ge r2.z, l(0.000000), r1.x\n    or r0.w, r0.w, r2.z\n    lt r2.z, r1.x, r1.y\n    mul r1.x, r1.x, l(63.499989)\n    div r1.x, r1.x, r1.y\n    ftou r1.x, r1.x\n    movc r1.x, r2.z, icb[r1.x + 0].w, l(7)\n    movc r0.w, r0.w, l(0), r1.x\n    if_z r0.z\n      ishl r3.x, r0.w, l(18)\n      mov r3.y, l(0)\n    else \n      ult r1.x, r0.z, l(3)\n      if_nz r1.x\n        imad r1.x, r0.z, l(3), l(17)\n        ishl r3.x, r0.w, r1.x\n        mov r3.y, l(0)\n      else \n        ine r1.x, l(2), icb[r2.y + 0].y\n        ieq r1.y, l(15), icb[r2.y + 0].y\n        and r2.zw, r1.xxxy, l(0, 0, 1, 1)\n        ult r1.y, r0.z, l(5)\n        if_nz r1.y\n          imad r1.y, r0.z, l(3), r2.z\n          iadd r1.y, r1.y, l(16)\n          ishl r3.x, r0.w, r1.y\n          mov r3.y, l(0)\n        else \n          ieq r1.y, r0.z, l(5)\n          movc r4.x, r1.x, l(0), l(1)\n          ushr r4.y, r0.w, r4.x\n          ishl r4.z, r0.w, l(31)\n          movc r4.x, r1.x, l(0), r4.z\n          ult r1.x, r0.z, l(9)\n          imad r2.zw, r0.zzzz, l(0, 0, 3, 3), r2.zzzw\n          iadd r2.zw, r2.zzzw, l(0, 0, -16, -16)\n          ishl r2.z, r0.w, r2.z\n          ishl r0.w, r0.w, r2.w\n          movc r5.y, r1.x, r2.z, r0.w\n          mov r5.x, l(0)\n          movc r3.xy, r1.yyyy, r4.xyxx, r5.xyxx\n        endif \n      endif \n    endif \n  endif \n  store_structured g0.xy, vThreadIDInGroupFlattened.x, l(24), r3.xyxx\nelse \n  mov r3.xy, l(0,0,0,0)\nendif \nsync_g_t\nif_nz r1.w\n  ld_structured r4.xy, vThreadIDInGroupFlattened.x, l(24), g0.xyxx\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(8)\n  ld_structured r5.xy, r0.w, l(24), g0.xyxx\n  or r1.xy, r4.xyxx, r5.xyxx\n  store_structured g0.xy, vThreadIDInGroupFlattened.x, l(24), r1.xyxx\nendif \nsync_g_t\nult r1.xy, r0.zzzz, l(4, 1, 0, 0)\nif_nz r1.x\n  ld_structured r4.xy, vThreadIDInGroupFlattened.x, l(24), g0.xyxx\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(4)\n  ld_structured r5.xy, r0.w, l(24), g0.xyxx\n  or r1.xw, r4.xxxy, r5.xxxy\n  store_structured g0.xy, vThreadIDInGroupFlattened.x, l(24), r1.xwxx\nendif \nsync_g_t\nif_nz r1.z\n  ld_structured r4.xy, vThreadIDInGroupFlattened.x, l(24), g0.xyxx\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(2)\n  ld_structured r5.xy, r0.w, l(24), g0.xyxx\n  or r1.xw, r4.xxxy, r5.xxxy\n  store_structured g0.xy, vThreadIDInGroupFlattened.x, l(24), r1.xwxx\nendif \nsync_g_t\nif_nz r1.y\n  ld_structured r4.xy, vThreadIDInGroupFlattened.x, l(24), g0.xyxx\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(1)\n  ld_structured r5.xy, r0.w, l(24), g0.xyxx\n  or r3.xy, r4.xyxx, r5.xyxx\nendif \nsync_g_t\niadd r0.w, r2.x, l(-1)\nieq r1.xy, r0.zzzz, l(2, 3, 0, 0)\nif_nz r1.x\n  ld_structured r4.xyz, r0.y, l(52), g0.xyzx\n  ld_structured r5.xyz, r0.y, l(64), g0.xyzx\n  ieq r1.x, cb0[0].z, l(95)\n  if_nz r1.x\n    ige r1.x, icb[r0.w + 64].x, l(15)\n    and r1.x, r1.x, l(1)\n    movc r6.xyz, r4.xyzx, l(0,0,0,0), l(1,1,1,0)\n    movc r7.xyz, r5.xyzx, l(0,0,0,0), l(1,1,1,0)\n    or r6.xyz, r1.xxxx, r6.xyzx\n    or r7.xyz, r1.xxxx, r7.xyzx\n    ieq r8.xyz, r4.xyzx, l(0x0000ffff, 0x0000ffff, 0x0000ffff, 0)\n    ieq r9.xyz, r5.xyzx, l(0x0000ffff, 0x0000ffff, 0x0000ffff, 0)\n    ishl r1.x, l(1), icb[r0.w + 64].x\n    iadd r1.x, r1.x, l(-1)\n    ishl r10.xyz, r4.xyzx, icb[r0.w + 64].x\n    ishl r11.xyz, r5.xyzx, icb[r0.w + 64].x\n    ishr r10.xyz, r10.xyzx, l(16)\n    ishr r11.xyz, r11.xyzx, l(16)\n    movc r8.xyz, r8.xyzx, r1.xxxx, r10.xyzx\n    movc r9.xyz, r9.xyzx, r1.xxxx, r11.xyzx\n    movc r6.xyz, r6.xyzx, r4.xyzx, r8.xyzx\n    movc r7.xyz, r7.xyzx, r5.xyzx, r9.xyzx\n  else \n    ige r1.x, icb[r0.w + 64].x, l(16)\n    and r1.x, r1.x, l(1)\n    movc r8.xyz, r4.xyzx, l(0,0,0,0), l(1,1,1,0)\n    movc r9.xyz, r5.xyzx, l(0,0,0,0), l(1,1,1,0)\n    or r8.xyz, r1.xxxx, r8.xyzx\n    or r9.xyz, r1.xxxx, r9.xyzx\n    ige r10.xyz, r4.xyzx, l(0, 0, 0, 0)\n    ige r11.xyz, r5.xyzx, l(0, 0, 0, 0)\n    ieq r12.xyz, r4.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    ieq r13.xyz, r5.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    iadd r1.x, l(-1), icb[r0.w + 64].x\n    ishl r1.w, l(1), r1.x\n    iadd r2.z, r1.w, l(-1)\n    ishl r14.xyz, r4.xyzx, r1.x\n    ishl r15.xyz, r5.xyzx, r1.x\n    ishr r14.xyz, r14.xyzx, l(15)\n    ishr r15.xyz, r15.xyzx, l(15)\n    movc r12.xyz, r12.xyzx, r2.zzzz, r14.xyzx\n    movc r13.xyz, r13.xyzx, r2.zzzz, r15.xyzx\n    ineg r14.xyz, r4.xyzx\n    ineg r15.xyz, r5.xyzx\n    ieq r16.xyz, r14.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    ieq r17.xyz, r15.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    iadd r1.w, -r1.w, l(1)\n    ishl r14.xyz, r14.xyzx, r1.x\n    ishl r15.xyz, r15.xyzx, r1.x\n    ishr r14.xyz, r14.xyzx, l(15)\n    ishr r15.xyz, r15.xyzx, l(15)\n    ineg r14.xyz, r14.xyzx\n    ineg r15.xyz, r15.xyzx\n    movc r14.xyz, r16.xyzx, r1.wwww, r14.xyzx\n    movc r15.xyz, r17.xyzx, r1.wwww, r15.xyzx\n    movc r10.xyz, r10.xyzx, r12.xyzx, r14.xyzx\n    movc r11.xyz, r11.xyzx, r13.xyzx, r15.xyzx\n    movc r6.xyz, r8.xyzx, r4.xyzx, r10.xyzx\n    movc r7.xyz, r9.xyzx, r5.xyzx, r11.xyzx\n  endif \n  iadd r4.xyz, -r6.xyzx, r7.xyzx\n  movc r4.xyz, icb[r0.w + 32].xxxx, r4.xyzx, r7.xyzx\n  mov r6.w, r4.x\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r6.xyzw\n  store_structured g0.xy, vThreadIDInGroupFlattened.x, l(68), r4.yzyy\nendif \nsync_g_t\nif_nz r1.y\n  iadd r1.xy, r0.yyyy, l(2, 1, 0, 0)\n  ld_structured r4.xyz, r1.x, l(52), g0.xyzx\n  ld_structured r5.xyz, r1.y, l(52), g0.xyzx\n  ld_structured r6.xyz, r1.y, l(64), g0.xyzx\n  uge r1.x, l(10), r2.x\n  if_nz r1.x\n    ieq r1.x, cb0[0].z, l(95)\n    if_nz r1.x\n      ige r1.x, icb[r0.w + 64].x, l(15)\n      and r1.x, r1.x, l(1)\n      movc r7.xyz, r5.xyzx, l(0,0,0,0), l(1,1,1,0)\n      movc r8.xyz, r6.xyzx, l(0,0,0,0), l(1,1,1,0)\n      or r7.xyz, r1.xxxx, r7.xyzx\n      or r1.xyw, r1.xxxx, r8.xyxz\n      ieq r8.xyz, r5.xyzx, l(0x0000ffff, 0x0000ffff, 0x0000ffff, 0)\n      ieq r9.xyz, r6.xyzx, l(0x0000ffff, 0x0000ffff, 0x0000ffff, 0)\n      ishl r2.z, l(1), icb[r0.w + 64].x\n      iadd r2.z, r2.z, l(-1)\n      ishl r10.xyz, r5.xyzx, icb[r0.w + 64].x\n      ishl r11.xyz, r6.xyzx, icb[r0.w + 64].x\n      ishr r10.xyz, r10.xyzx, l(16)\n      ishr r11.xyz, r11.xyzx, l(16)\n      movc r8.xyz, r8.xyzx, r2.zzzz, r10.xyzx\n      movc r9.xyz, r9.xyzx, r2.zzzz, r11.xyzx\n      movc r7.xyz, r7.xyzx, r5.xyzx, r8.xyzx\n      movc r1.xyw, r1.xyxw, r6.xyxz, r9.xyxz\n    else \n      ige r2.z, icb[r0.w + 64].x, l(16)\n      and r2.z, r2.z, l(1)\n      movc r8.xyz, r5.xyzx, l(0,0,0,0), l(1,1,1,0)\n      movc r9.xyz, r6.xyzx, l(0,0,0,0), l(1,1,1,0)\n      or r8.xyz, r2.zzzz, r8.xyzx\n      or r9.xyz, r2.zzzz, r9.xyzx\n      ige r10.xyz, r5.xyzx, l(0, 0, 0, 0)\n      ige r11.xyz, r6.xyzx, l(0, 0, 0, 0)\n      ieq r12.xyz, r5.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n      ieq r13.xyz, r6.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n      iadd r2.z, l(-1), icb[r0.w + 64].x\n      ishl r2.w, l(1), r2.z\n      iadd r4.w, r2.w, l(-1)\n      ishl r14.xyz, r5.xyzx, r2.z\n      ishl r15.xyz, r6.xyzx, r2.z\n      ishr r14.xyz, r14.xyzx, l(15)\n      ishr r15.xyz, r15.xyzx, l(15)\n      movc r12.xyz, r12.xyzx, r4.wwww, r14.xyzx\n      movc r13.xyz, r13.xyzx, r4.wwww, r15.xyzx\n      ineg r14.xyz, r5.xyzx\n      ineg r15.xyz, r6.xyzx\n      ieq r16.xyz, r14.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n      ieq r17.xyz, r15.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n      iadd r2.w, -r2.w, l(1)\n      ishl r14.xyz, r14.xyzx, r2.z\n      ishl r15.xyz, r15.xyzx, r2.z\n      ishr r14.xyz, r14.xyzx, l(15)\n      ishr r15.xyz, r15.xyzx, l(15)\n      ineg r14.xyz, r14.xyzx\n      ineg r15.xyz, r15.xyzx\n      movc r14.xyz, r16.xyzx, r2.wwww, r14.xyzx\n      movc r15.xyz, r17.xyzx, r2.wwww, r15.xyzx\n      movc r10.xyz, r10.xyzx, r12.xyzx, r14.xyzx\n      movc r11.xyz, r11.xyzx, r13.xyzx, r15.xyzx\n      movc r7.xyz, r8.xyzx, r5.xyzx, r10.xyzx\n      movc r1.xyw, r9.xyxz, r6.xyxz, r11.xyxz\n    endif \n    iadd r5.xyz, -r4.xyzx, r7.xyzx\n    iadd r4.xyz, -r4.xyzx, r1.xywx\n    mov r5.w, r4.x\n    mov r7.w, r1.x\n    movc r5.xyzw, icb[r0.w + 32].xxxx, r5.xyzw, r7.xyzw\n    movc r1.xy, icb[r0.w + 32].xxxx, r4.yzyy, r1.ywyy\n    store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r5.xyzw\n    store_structured g0.xy, vThreadIDInGroupFlattened.x, l(68), r1.xyxx\n  endif \nendif \nsync_g_t\nif_nz r1.z\n  iadd r1.x, vThreadIDInGroupFlattened.x, l(2)\n  ld_structured r4.xyz, r1.x, l(52), g0.xyzx\n  ld_structured r1.xyz, r1.x, l(64), g0.yzxx\n  if_z r0.z\n    ult r1.w, l(10), r2.x\n    if_nz r1.w\n      ishl r5.x, l(1), icb[r0.w + 64].x\n      ishl r5.y, l(1), icb[r0.w + 64].y\n      ishl r5.z, l(1), icb[r0.w + 64].z\n      ishl r5.w, l(1), icb[r0.w + 64].w\n      ige r6.xyz, r1.zxyz, l(0, 0, 0, 0)\n      iadd r7.xyz, l(-1, -1, -1, 0), icb[r0.w + 64].yzwy\n      ishl r8.x, l(1), r7.x\n      ishl r8.y, l(1), r7.y\n      ishl r8.z, l(1), r7.z\n      ige r7.xyz, r1.zxyz, r8.xyzx\n      iadd r9.xyz, r8.xyzx, l(-1, -1, -1, 0)\n      movc r7.xyz, r7.xyzx, r9.xyzx, r1.zxyz\n      ineg r9.xyz, r1.zxyz\n      ilt r9.xyz, r8.xyzx, r9.xyzx\n      iadd r5.xyzw, r5.xyzw, l(-1, -1, -1, -1)\n      and r5.yzw, r1.zzxy, r5.yyzw\n      movc r5.yzw, r9.xxyz, r8.xxyz, r5.yyzw\n      movc r5.yzw, r6.xxyz, r7.xxyz, r5.yyzw\n      mov r4.w, r1.z\n      and r6.xyzw, r4.xyzw, r5.xxxx\n      and r2.zw, r1.xxxy, r5.xxxx\n      mov r7.xyz, r6.xyzx\n      mov r7.w, r5.y\n      movc r4.xyzw, icb[r0.w + 32].xxxx, r7.xyzw, r6.xyzw\n      movc r1.xy, icb[r0.w + 32].xxxx, r5.zwzz, r2.zwzz\n    else \n      if_nz icb[r0.w + 32].x\n        ishl r5.x, l(1), icb[r0.w + 64].x\n        ishl r5.y, l(1), icb[r0.w + 64].y\n        ishl r5.z, l(1), icb[r0.w + 64].z\n        ishl r5.w, l(1), icb[r0.w + 64].w\n        iadd r5.xyzw, r5.xyzw, l(-1, -1, -1, -1)\n        and r4.xyz, r4.xyzx, r5.xxxx\n        ige r6.xyz, r1.zxyz, l(0, 0, 0, 0)\n        iadd r7.xyz, l(-1, -1, -1, 0), icb[r0.w + 64].yzwy\n        ishl r8.x, l(1), r7.x\n        ishl r8.y, l(1), r7.y\n        ishl r8.z, l(1), r7.z\n        ige r7.xyz, r1.zxyz, r8.xyzx\n        iadd r9.xyz, r8.xyzx, l(-1, -1, -1, 0)\n        movc r7.xyz, r7.xyzx, r9.xyzx, r1.zxyz\n        ineg r9.xyz, r1.zxyz\n        ilt r9.xyz, r8.xyzx, r9.xyzx\n        and r5.xyz, r1.zxyz, r5.yzwy\n        movc r5.xyz, r9.xyzx, r8.xyzx, r5.xyzx\n        movc r1.xyz, r6.yzxy, r7.yzxy, r5.yzxy\n        mov r4.w, r1.z\n      else \n        ishl r1.w, l(1), icb[r0.w + 64].x\n        iadd r1.w, r1.w, l(-1)\n        mov r4.w, r1.z\n        and r4.xyzw, r1.wwww, r4.xyzw\n        and r1.xy, r1.wwww, r1.xyxx\n      endif \n    endif \n  else \n    uge r1.w, l(10), r2.x\n    if_nz r1.w\n      if_nz icb[r0.w + 32].x\n        ige r5.xyz, r4.xyzx, l(0, 0, 0, 0)\n        iadd r6.xyz, l(-1, -1, -1, 0), icb[r0.w + 64].yzwy\n        ishl r7.x, l(1), r6.x\n        ishl r7.y, l(1), r6.y\n        ishl r7.z, l(1), r6.z\n        ige r6.xyz, r4.xyzx, r7.xyzx\n        iadd r8.xyz, r7.xyzx, l(-1, -1, -1, 0)\n        movc r6.xyz, r6.xyzx, r8.xyzx, r4.xyzx\n        ineg r9.xyz, r4.xyzx\n        ilt r9.xyz, r7.xyzx, r9.xyzx\n        ishl r10.x, l(1), icb[r0.w + 64].y\n        ishl r10.y, l(1), icb[r0.w + 64].z\n        ishl r10.z, l(1), icb[r0.w + 64].w\n        iadd r10.xyz, r10.xyzx, l(-1, -1, -1, 0)\n        and r11.xyz, r4.xyzx, r10.xyzx\n        movc r9.xyz, r9.xyzx, r7.xyzx, r11.xyzx\n        movc r4.xyz, r5.xyzx, r6.xyzx, r9.xyzx\n        ige r5.xyz, r1.zxyz, l(0, 0, 0, 0)\n        ige r6.xyz, r1.zxyz, r7.xyzx\n        movc r6.xyz, r6.xyzx, r8.xyzx, r1.zxyz\n        ineg r8.xyz, r1.zxyz\n        ilt r8.xyz, r7.xyzx, r8.xyzx\n        and r9.xyz, r1.zxyz, r10.xyzx\n        movc r7.xyz, r8.xyzx, r7.xyzx, r9.xyzx\n        movc r1.xyz, r5.yzxy, r6.yzxy, r7.yzxy\n        mov r4.w, r1.z\n      else \n        ishl r0.w, l(1), icb[r0.w + 64].x\n        iadd r0.w, r0.w, l(-1)\n        mov r4.w, r1.z\n        and r4.xyzw, r0.wwww, r4.xyzw\n        and r1.xy, r0.wwww, r1.xyxx\n      endif \n    else \n      mov r4.w, r1.z\n    endif \n  endif \n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r4.xyzw\n  store_structured g0.xy, vThreadIDInGroupFlattened.x, l(68), r1.xyxx\nendif \nsync_g_t\nif_z r0.z\n  ld_structured r1.xyzw, r0.y, l(52), g0.xyzw\n  ld_structured r4.xy, r0.y, l(68), g0.xyxx\n  ult r0.z, l(10), r2.x\n  if_nz r0.z\n    and r3.w, r3.x, l(-2)\n    ieq r0.z, r2.x, l(11)\n    if_nz r0.z\n      ishl r5.x, r1.x, l(5)\n      ishl r5.y, r1.y, l(15)\n      ishl r5.z, r1.z, l(25)\n      ishl r5.w, r1.w, l(3)\n      and r5.xyzw, r5.xyzw, l(32, 0x00008000, 0x02000000, 8)\n      iadd r0.z, r5.x, l(3)\n      ishr r0.w, r1.x, l(1)\n      ishr r2.z, r1.x, l(2)\n      ishr r2.w, r1.x, l(3)\n      ishr r4.z, r1.x, l(4)\n      ishl r6.x, r0.w, l(6)\n      ishl r6.y, r2.z, l(7)\n      ishl r6.z, r2.w, l(8)\n      ishl r6.w, r4.z, l(9)\n      and r6.xyzw, r6.xyzw, l(64, 128, 256, 512)\n      iadd r0.z, r0.z, r6.x\n      iadd r0.z, r6.y, r0.z\n      iadd r0.z, r6.z, r0.z\n      iadd r0.z, r6.w, r0.z\n      ishr r0.w, r1.x, l(5)\n      ishr r2.z, r1.x, l(6)\n      ishr r2.w, r1.x, l(7)\n      ishr r4.z, r1.x, l(8)\n      ishl r6.x, r0.w, l(10)\n      ishl r6.y, r2.z, l(11)\n      ishl r6.z, r2.w, l(12)\n      ishl r6.w, r4.z, l(13)\n      and r6.xyzw, r6.xyzw, l(1024, 2048, 4096, 8192)\n      iadd r0.z, r0.z, r6.x\n      iadd r0.z, r6.y, r0.z\n      iadd r0.z, r6.z, r0.z\n      iadd r0.z, r6.w, r0.z\n      ishr r0.w, r1.x, l(9)\n      ishr r2.z, r1.y, l(1)\n      ishr r2.w, r1.y, l(2)\n      ishr r4.z, r1.y, l(3)\n      ishl r6.x, r0.w, l(14)\n      ishl r6.y, r2.z, l(16)\n      ishl r6.z, r2.w, l(17)\n      ishl r6.w, r4.z, l(18)\n      and r6.xyzw, r6.xyzw, l(0x00004000, 0x00010000, 0x00020000, 0x00040000)\n      iadd r0.z, r0.z, r6.x\n      iadd r0.z, r5.y, r0.z\n      iadd r0.z, r6.y, r0.z\n      iadd r0.z, r6.z, r0.z\n      iadd r0.z, r6.w, r0.z\n      ishr r0.w, r1.y, l(4)\n      ishr r2.z, r1.y, l(5)\n      ishr r2.w, r1.y, l(6)\n      ishr r4.z, r1.y, l(7)\n      ishl r6.x, r0.w, l(19)\n      ishl r6.y, r2.z, l(20)\n      ishl r6.z, r2.w, l(21)\n      ishl r6.w, r4.z, l(22)\n      and r6.xyzw, r6.xyzw, l(0x00080000, 0x00100000, 0x00200000, 0x00400000)\n      iadd r0.z, r0.z, r6.x\n      iadd r0.z, r6.y, r0.z\n      iadd r0.z, r6.z, r0.z\n      iadd r0.z, r6.w, r0.z\n      ishr r0.w, r1.y, l(8)\n      ishr r2.z, r1.y, l(9)\n      ishr r2.w, r1.z, l(1)\n      ishr r4.z, r1.z, l(2)\n      ishl r6.x, r0.w, l(23)\n      ishl r6.y, r2.z, l(24)\n      ishl r6.z, r2.w, l(26)\n      ishl r6.w, r4.z, l(27)\n      and r6.xyzw, r6.xyzw, l(0x00800000, 0x01000000, 0x04000000, 0x08000000)\n      iadd r0.z, r0.z, r6.x\n      iadd r0.z, r6.y, r0.z\n      iadd r0.z, r5.z, r0.z\n      iadd r0.z, r6.z, r0.z\n      iadd r0.z, r6.w, r0.z\n      ishr r0.w, r1.z, l(3)\n      ishr r2.z, r1.z, l(4)\n      ishr r2.w, r1.z, l(5)\n      ishr r4.z, r1.z, l(6)\n      ishl r5.x, r0.w, l(28)\n      ishl r5.y, r2.z, l(29)\n      ishl r5.z, r2.w, l(30)\n      ishl r0.w, r4.z, l(31)\n      and r5.xyz, r5.xyzx, l(0x10000000, 0x20000000, 0x40000000, 0)\n      iadd r0.z, r0.z, r5.x\n      iadd r0.z, r5.y, r0.z\n      iadd r0.z, r5.z, r0.z\n      iadd r3.x, r0.w, r0.z\n      ishr r0.z, r1.z, l(7)\n      ishr r0.w, r1.z, l(8)\n      ishr r2.z, r1.z, l(9)\n      ishr r2.w, r1.w, l(1)\n      and r0.z, r0.z, l(1)\n      ishl r5.x, r0.w, l(1)\n      ishl r5.y, r2.z, l(2)\n      ishl r5.z, r2.w, l(4)\n      and r5.xyz, r5.xyzx, l(2, 4, 16, 0)\n      iadd r0.z, r0.z, r5.x\n      iadd r0.z, r5.y, r0.z\n      iadd r0.z, r5.w, r0.z\n      iadd r0.z, r5.z, r0.z\n      ishr r0.w, r1.w, l(2)\n      ishr r2.z, r1.w, l(3)\n      ishr r2.w, r1.w, l(4)\n      ishr r4.z, r1.w, l(5)\n      ishl r5.x, r0.w, l(5)\n      ishl r5.y, r2.z, l(6)\n      ishl r5.z, r2.w, l(7)\n      ishl r5.w, r4.z, l(8)\n      and r5.xyzw, r5.xyzw, l(32, 64, 128, 256)\n      iadd r0.z, r0.z, r5.x\n      iadd r0.z, r5.y, r0.z\n      iadd r0.z, r5.z, r0.z\n      iadd r0.z, r5.w, r0.z\n      ishr r0.w, r1.w, l(6)\n      ishr r2.z, r1.w, l(7)\n      ishr r2.w, r1.w, l(8)\n      ishr r4.z, r1.w, l(9)\n      ishl r5.x, r0.w, l(9)\n      ishl r5.y, r2.z, l(10)\n      ishl r5.z, r2.w, l(11)\n      ishl r5.w, r4.z, l(12)\n      and r5.xyzw, r5.xyzw, l(512, 1024, 2048, 4096)\n      iadd r0.z, r0.z, r5.x\n      iadd r0.z, r5.y, r0.z\n      iadd r0.z, r5.z, r0.z\n      iadd r0.z, r5.w, r0.z\n      ishl r5.x, r4.x, l(13)\n      ishl r5.y, r4.y, l(23)\n      and r2.zw, r5.xxxy, l(0, 0, 8192, 0x00800000)\n      iadd r0.z, r0.z, r2.z\n      ishr r0.w, r4.x, l(1)\n      ishr r2.z, r4.x, l(2)\n      ishr r4.z, r4.x, l(3)\n      ishr r4.w, r4.x, l(4)\n      ishl r5.x, r0.w, l(14)\n      ishl r5.y, r2.z, l(15)\n      ishl r5.z, r4.z, l(16)\n      ishl r5.w, r4.w, l(17)\n      and r5.xyzw, r5.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n      iadd r0.z, r0.z, r5.x\n      iadd r0.z, r5.y, r0.z\n      iadd r0.z, r5.z, r0.z\n      iadd r0.z, r5.w, r0.z\n      ishr r0.w, r4.x, l(5)\n      ishr r2.z, r4.x, l(6)\n      ishr r4.z, r4.x, l(7)\n      ishr r4.w, r4.x, l(8)\n      ishl r5.x, r0.w, l(18)\n      ishl r5.y, r2.z, l(19)\n      ishl r5.z, r4.z, l(20)\n      ishl r5.w, r4.w, l(21)\n      and r5.xyzw, r5.xyzw, l(0x00040000, 0x00080000, 0x00100000, 0x00200000)\n      iadd r0.z, r0.z, r5.x\n      iadd r0.z, r5.y, r0.z\n      iadd r0.z, r5.z, r0.z\n      iadd r0.z, r5.w, r0.z\n      ishr r0.w, r4.x, l(9)\n      ishr r2.z, r4.y, l(1)\n      ishr r4.z, r4.y, l(2)\n      ishr r4.w, r4.y, l(3)\n      ishl r5.x, r0.w, l(22)\n      ishl r5.y, r2.z, l(24)\n      ishl r5.z, r4.z, l(25)\n      ishl r5.w, r4.w, l(26)\n      and r5.xyzw, r5.xyzw, l(0x00400000, 0x01000000, 0x02000000, 0x04000000)\n      iadd r0.z, r0.z, r5.x\n      iadd r0.z, r2.w, r0.z\n      iadd r0.z, r5.y, r0.z\n      iadd r0.z, r5.z, r0.z\n      iadd r0.z, r5.w, r0.z\n      ishr r0.w, r4.y, l(4)\n      ishr r2.z, r4.y, l(5)\n      ishr r2.w, r4.y, l(6)\n      ishr r4.z, r4.y, l(7)\n      ishl r5.x, r0.w, l(27)\n      ishl r5.y, r2.z, l(28)\n      ishl r5.z, r2.w, l(29)\n      ishl r5.w, r4.z, l(30)\n      and r5.xyzw, r5.xyzw, l(0x08000000, 0x10000000, 0x20000000, 0x40000000)\n      iadd r0.z, r0.z, r5.x\n      iadd r0.z, r5.y, r0.z\n      iadd r0.z, r5.z, r0.z\n      iadd r0.z, r5.w, r0.z\n      ishr r0.w, r4.y, l(8)\n      ishr r2.z, r4.y, l(9)\n      ishl r0.w, r0.w, l(31)\n      iadd r3.z, r0.w, r0.z\n      and r0.z, r2.z, l(1)\n      iadd r3.w, r0.z, r3.w\n    else \n      ieq r0.z, r2.x, l(12)\n      if_nz r0.z\n        ishl r5.x, r1.x, l(5)\n        ishl r5.y, r1.y, l(15)\n        ishl r5.z, r1.z, l(25)\n        ishl r5.w, r1.w, l(3)\n        and r5.xyzw, r5.xyzw, l(32, 0x00008000, 0x02000000, 8)\n        iadd r0.z, r5.x, l(7)\n        ishr r0.w, r1.x, l(1)\n        ishr r2.z, r1.x, l(2)\n        ishr r2.w, r1.x, l(3)\n        ishr r4.z, r1.x, l(4)\n        ishl r6.x, r0.w, l(6)\n        ishl r6.y, r2.z, l(7)\n        ishl r6.z, r2.w, l(8)\n        ishl r6.w, r4.z, l(9)\n        and r6.xyzw, r6.xyzw, l(64, 128, 256, 512)\n        iadd r0.z, r0.z, r6.x\n        iadd r0.z, r6.y, r0.z\n        iadd r0.z, r6.z, r0.z\n        iadd r0.z, r6.w, r0.z\n        ishr r0.w, r1.x, l(5)\n        ishr r2.z, r1.x, l(6)\n        ishr r2.w, r1.x, l(7)\n        ishr r4.z, r1.x, l(8)\n        ishl r6.x, r0.w, l(10)\n        ishl r6.y, r2.z, l(11)\n        ishl r6.z, r2.w, l(12)\n        ishl r6.w, r4.z, l(13)\n        and r6.xyzw, r6.xyzw, l(1024, 2048, 4096, 8192)\n        iadd r0.z, r0.z, r6.x\n        iadd r0.z, r6.y, r0.z\n        iadd r0.z, r6.z, r0.z\n        iadd r0.z, r6.w, r0.z\n        ishr r0.w, r1.x, l(9)\n        ishr r2.z, r1.y, l(1)\n        ishr r2.w, r1.y, l(2)\n        ishr r4.z, r1.y, l(3)\n        ishl r6.x, r0.w, l(14)\n        ishl r6.y, r2.z, l(16)\n        ishl r6.z, r2.w, l(17)\n        ishl r6.w, r4.z, l(18)\n        and r6.xyzw, r6.xyzw, l(0x00004000, 0x00010000, 0x00020000, 0x00040000)\n        iadd r0.z, r0.z, r6.x\n        iadd r0.z, r5.y, r0.z\n        iadd r0.z, r6.y, r0.z\n        iadd r0.z, r6.z, r0.z\n        iadd r0.z, r6.w, r0.z\n        ishr r0.w, r1.y, l(4)\n        ishr r2.z, r1.y, l(5)\n        ishr r2.w, r1.y, l(6)\n        ishr r4.z, r1.y, l(7)\n        ishl r6.x, r0.w, l(19)\n        ishl r6.y, r2.z, l(20)\n        ishl r6.z, r2.w, l(21)\n        ishl r6.w, r4.z, l(22)\n        and r6.xyzw, r6.xyzw, l(0x00080000, 0x00100000, 0x00200000, 0x00400000)\n        iadd r0.z, r0.z, r6.x\n        iadd r0.z, r6.y, r0.z\n        iadd r0.z, r6.z, r0.z\n        iadd r0.z, r6.w, r0.z\n        ishr r0.w, r1.y, l(8)\n        ishr r2.z, r1.y, l(9)\n        ishr r2.w, r1.z, l(1)\n        ishr r4.z, r1.z, l(2)\n        ishl r6.x, r0.w, l(23)\n        ishl r6.y, r2.z, l(24)\n        ishl r6.z, r2.w, l(26)\n        ishl r6.w, r4.z, l(27)\n        and r6.xyzw, r6.xyzw, l(0x00800000, 0x01000000, 0x04000000, 0x08000000)\n        iadd r0.z, r0.z, r6.x\n        iadd r0.z, r6.y, r0.z\n        iadd r0.z, r5.z, r0.z\n        iadd r0.z, r6.z, r0.z\n        iadd r0.z, r6.w, r0.z\n        ishr r0.w, r1.z, l(3)\n        ishr r2.z, r1.z, l(4)\n        ishr r2.w, r1.z, l(5)\n        ishr r4.z, r1.z, l(6)\n        ishl r5.x, r0.w, l(28)\n        ishl r5.y, r2.z, l(29)\n        ishl r5.z, r2.w, l(30)\n        ishl r0.w, r4.z, l(31)\n        and r5.xyz, r5.xyzx, l(0x10000000, 0x20000000, 0x40000000, 0)\n        iadd r0.z, r0.z, r5.x\n        iadd r0.z, r5.y, r0.z\n        iadd r0.z, r5.z, r0.z\n        iadd r3.x, r0.w, r0.z\n        ishr r0.z, r1.z, l(7)\n        ishr r0.w, r1.z, l(8)\n        ishr r2.z, r1.z, l(9)\n        ishr r2.w, r1.w, l(1)\n        and r0.z, r0.z, l(1)\n        ishl r5.x, r0.w, l(1)\n        ishl r5.y, r2.z, l(2)\n        ishl r5.z, r2.w, l(4)\n        and r5.xyz, r5.xyzx, l(2, 4, 16, 0)\n        iadd r0.z, r0.z, r5.x\n        iadd r0.z, r5.y, r0.z\n        iadd r0.z, r5.w, r0.z\n        iadd r0.z, r5.z, r0.z\n        ishr r0.w, r1.w, l(2)\n        ishr r2.z, r1.w, l(3)\n        ishr r2.w, r1.w, l(4)\n        ishr r4.z, r1.w, l(5)\n        ishl r5.x, r0.w, l(5)\n        ishl r5.y, r2.z, l(6)\n        ishl r5.z, r2.w, l(7)\n        ishl r5.w, r4.z, l(8)\n        and r5.xyzw, r5.xyzw, l(32, 64, 128, 256)\n        iadd r0.z, r0.z, r5.x\n        iadd r0.z, r5.y, r0.z\n        iadd r0.z, r5.z, r0.z\n        iadd r0.z, r5.w, r0.z\n        ishr r0.w, r1.w, l(6)\n        ishr r2.z, r1.w, l(7)\n        ishr r2.w, r1.w, l(8)\n        ishr r4.z, r1.x, l(10)\n        ishl r5.x, r0.w, l(9)\n        ishl r5.y, r2.z, l(10)\n        ishl r5.z, r2.w, l(11)\n        ishl r5.w, r4.z, l(12)\n        and r5.xyzw, r5.xyzw, l(512, 1024, 2048, 4096)\n        iadd r0.z, r0.z, r5.x\n        iadd r0.z, r5.y, r0.z\n        iadd r0.z, r5.z, r0.z\n        iadd r0.z, r5.w, r0.z\n        ishl r5.x, r4.x, l(13)\n        ishl r5.y, r4.y, l(23)\n        and r2.zw, r5.xxxy, l(0, 0, 8192, 0x00800000)\n        iadd r0.z, r0.z, r2.z\n        ishr r0.w, r4.x, l(1)\n        ishr r2.z, r4.x, l(2)\n        ishr r4.z, r4.x, l(3)\n        ishr r4.w, r4.x, l(4)\n        ishl r5.x, r0.w, l(14)\n        ishl r5.y, r2.z, l(15)\n        ishl r5.z, r4.z, l(16)\n        ishl r5.w, r4.w, l(17)\n        and r5.xyzw, r5.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n        iadd r0.z, r0.z, r5.x\n        iadd r0.z, r5.y, r0.z\n        iadd r0.z, r5.z, r0.z\n        iadd r0.z, r5.w, r0.z\n        ishr r0.w, r4.x, l(5)\n        ishr r2.z, r4.x, l(6)\n        ishr r4.z, r4.x, l(7)\n        ishr r4.w, r4.x, l(8)\n        ishl r5.x, r0.w, l(18)\n        ishl r5.y, r2.z, l(19)\n        ishl r5.z, r4.z, l(20)\n        ishl r5.w, r4.w, l(21)\n        and r5.xyzw, r5.xyzw, l(0x00040000, 0x00080000, 0x00100000, 0x00200000)\n        iadd r0.z, r0.z, r5.x\n        iadd r0.z, r5.y, r0.z\n        iadd r0.z, r5.z, r0.z\n        iadd r0.z, r5.w, r0.z\n        ishr r4.zw, r1.yyyz, l(10)\n        ishl r0.w, r4.z, l(22)\n        and r0.w, r0.w, l(0x00400000)\n        iadd r0.z, r0.w, r0.z\n        iadd r0.z, r2.w, r0.z\n        ishr r0.w, r4.y, l(1)\n        ishr r2.z, r4.y, l(2)\n        ishr r2.w, r4.y, l(3)\n        ishr r4.z, r4.y, l(4)\n        ishl r5.x, r0.w, l(24)\n        ishl r5.y, r2.z, l(25)\n        ishl r5.z, r2.w, l(26)\n        ishl r5.w, r4.z, l(27)\n        and r5.xyzw, r5.xyzw, l(0x01000000, 0x02000000, 0x04000000, 0x08000000)\n        iadd r0.z, r0.z, r5.x\n        iadd r0.z, r5.y, r0.z\n        iadd r0.z, r5.z, r0.z\n        iadd r0.z, r5.w, r0.z\n        ishr r0.w, r4.y, l(5)\n        ishr r2.z, r4.y, l(6)\n        ishr r2.w, r4.y, l(7)\n        ishr r4.z, r4.y, l(8)\n        ishl r5.x, r0.w, l(28)\n        ishl r5.y, r2.z, l(29)\n        ishl r5.z, r2.w, l(30)\n        ishl r0.w, r4.z, l(31)\n        and r5.xyz, r5.xyzx, l(0x10000000, 0x20000000, 0x40000000, 0)\n        iadd r0.z, r0.z, r5.x\n        iadd r0.z, r5.y, r0.z\n        iadd r0.z, r5.z, r0.z\n        iadd r3.z, r0.w, r0.z\n        and r0.z, r4.w, l(1)\n        iadd r3.w, r0.z, r3.w\n      else \n        ieq r0.z, r2.x, l(13)\n        if_nz r0.z\n          ishl r5.x, r1.x, l(5)\n          ishl r5.y, r1.y, l(15)\n          ishl r5.z, r1.z, l(25)\n          ishl r5.w, r1.w, l(3)\n          and r5.xyzw, r5.xyzw, l(32, 0x00008000, 0x02000000, 8)\n          iadd r0.z, r5.x, l(11)\n          ishr r0.w, r1.x, l(1)\n          ishr r2.z, r1.x, l(2)\n          ishr r2.w, r1.x, l(3)\n          ishr r4.z, r1.x, l(4)\n          ishl r6.x, r0.w, l(6)\n          ishl r6.y, r2.z, l(7)\n          ishl r6.z, r2.w, l(8)\n          ishl r6.w, r4.z, l(9)\n          and r6.xyzw, r6.xyzw, l(64, 128, 256, 512)\n          iadd r0.z, r0.z, r6.x\n          iadd r0.z, r6.y, r0.z\n          iadd r0.z, r6.z, r0.z\n          iadd r0.z, r6.w, r0.z\n          ishr r0.w, r1.x, l(5)\n          ishr r2.z, r1.x, l(6)\n          ishr r2.w, r1.x, l(7)\n          ishr r4.z, r1.x, l(8)\n          ishl r6.x, r0.w, l(10)\n          ishl r6.y, r2.z, l(11)\n          ishl r6.z, r2.w, l(12)\n          ishl r6.w, r4.z, l(13)\n          and r6.xyzw, r6.xyzw, l(1024, 2048, 4096, 8192)\n          iadd r0.z, r0.z, r6.x\n          iadd r0.z, r6.y, r0.z\n          iadd r0.z, r6.z, r0.z\n          iadd r0.z, r6.w, r0.z\n          ishr r0.w, r1.x, l(9)\n          ishr r2.z, r1.y, l(1)\n          ishr r2.w, r1.y, l(2)\n          ishr r4.z, r1.y, l(3)\n          ishl r6.x, r0.w, l(14)\n          ishl r6.y, r2.z, l(16)\n          ishl r6.z, r2.w, l(17)\n          ishl r6.w, r4.z, l(18)\n          and r6.xyzw, r6.xyzw, l(0x00004000, 0x00010000, 0x00020000, 0x00040000)\n          iadd r0.z, r0.z, r6.x\n          iadd r0.z, r5.y, r0.z\n          iadd r0.z, r6.y, r0.z\n          iadd r0.z, r6.z, r0.z\n          iadd r0.z, r6.w, r0.z\n          ishr r0.w, r1.y, l(4)\n          ishr r2.z, r1.y, l(5)\n          ishr r2.w, r1.y, l(6)\n          ishr r4.z, r1.y, l(7)\n          ishl r6.x, r0.w, l(19)\n          ishl r6.y, r2.z, l(20)\n          ishl r6.z, r2.w, l(21)\n          ishl r6.w, r4.z, l(22)\n          and r6.xyzw, r6.xyzw, l(0x00080000, 0x00100000, 0x00200000, 0x00400000)\n          iadd r0.z, r0.z, r6.x\n          iadd r0.z, r6.y, r0.z\n          iadd r0.z, r6.z, r0.z\n          iadd r0.z, r6.w, r0.z\n          ishr r0.w, r1.y, l(8)\n          ishr r2.z, r1.y, l(9)\n          ishr r2.w, r1.z, l(1)\n          ishr r4.z, r1.z, l(2)\n          ishl r6.x, r0.w, l(23)\n          ishl r6.y, r2.z, l(24)\n          ishl r6.z, r2.w, l(26)\n          ishl r6.w, r4.z, l(27)\n          and r6.xyzw, r6.xyzw, l(0x00800000, 0x01000000, 0x04000000, 0x08000000)\n          iadd r0.z, r0.z, r6.x\n          iadd r0.z, r6.y, r0.z\n          iadd r0.z, r5.z, r0.z\n          iadd r0.z, r6.z, r0.z\n          iadd r0.z, r6.w, r0.z\n          ishr r0.w, r1.z, l(3)\n          ishr r2.z, r1.z, l(4)\n          ishr r2.w, r1.z, l(5)\n          ishr r4.z, r1.z, l(6)\n          ishl r5.x, r0.w, l(28)\n          ishl r5.y, r2.z, l(29)\n          ishl r5.z, r2.w, l(30)\n          ishl r0.w, r4.z, l(31)\n          and r5.xyz, r5.xyzx, l(0x10000000, 0x20000000, 0x40000000, 0)\n          iadd r0.z, r0.z, r5.x\n          iadd r0.z, r5.y, r0.z\n          iadd r0.z, r5.z, r0.z\n          iadd r3.x, r0.w, r0.z\n          ishr r0.z, r1.z, l(7)\n          ishr r0.w, r1.z, l(8)\n          ishr r2.z, r1.z, l(9)\n          ishr r2.w, r1.w, l(1)\n          and r0.z, r0.z, l(1)\n          ishl r5.x, r0.w, l(1)\n          ishl r5.y, r2.z, l(2)\n          ishl r5.z, r2.w, l(4)\n          and r5.xyz, r5.xyzx, l(2, 4, 16, 0)\n          iadd r0.z, r0.z, r5.x\n          iadd r0.z, r5.y, r0.z\n          iadd r0.z, r5.w, r0.z\n          iadd r0.z, r5.z, r0.z\n          ishr r0.w, r1.w, l(2)\n          ishr r2.z, r1.w, l(3)\n          ishr r2.w, r1.w, l(4)\n          ishr r4.z, r1.w, l(5)\n          ishl r5.x, r0.w, l(5)\n          ishl r5.y, r2.z, l(6)\n          ishl r5.z, r2.w, l(7)\n          ishl r5.w, r4.z, l(8)\n          and r5.xyzw, r5.xyzw, l(32, 64, 128, 256)\n          iadd r0.z, r0.z, r5.x\n          iadd r0.z, r5.y, r0.z\n          iadd r0.z, r5.z, r0.z\n          iadd r0.z, r5.w, r0.z\n          ishr r0.w, r1.w, l(6)\n          ishr r2.z, r1.w, l(7)\n          ishr r2.w, r1.x, l(10)\n          ishr r4.z, r1.y, l(11)\n          ishl r5.x, r0.w, l(9)\n          ishl r5.y, r2.z, l(10)\n          ishl r5.z, r2.w, l(12)\n          ishl r5.w, r4.z, l(21)\n          and r5.xyzw, r5.xyzw, l(512, 1024, 4096, 0x00200000)\n          iadd r0.z, r0.z, r5.x\n          iadd r0.z, r5.y, r0.z\n          and r0.w, r1.x, l(2048)\n          iadd r0.z, r0.w, r0.z\n          iadd r0.z, r5.z, r0.z\n          ishl r5.x, r4.x, l(13)\n          ishl r5.y, r4.y, l(23)\n          and r2.zw, r5.xxxy, l(0, 0, 8192, 0x00800000)\n          iadd r0.z, r0.z, r2.z\n          ishr r0.w, r4.x, l(1)\n          ishr r2.z, r4.x, l(2)\n          ishr r4.z, r4.x, l(3)\n          ishr r4.w, r4.x, l(4)\n          ishl r6.x, r0.w, l(14)\n          ishl r6.y, r2.z, l(15)\n          ishl r6.z, r4.z, l(16)\n          ishl r6.w, r4.w, l(17)\n          and r6.xyzw, r6.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n          iadd r0.z, r0.z, r6.x\n          iadd r0.z, r6.y, r0.z\n          iadd r0.z, r6.z, r0.z\n          iadd r0.z, r6.w, r0.z\n          ishr r0.w, r4.x, l(5)\n          ishr r2.z, r4.x, l(6)\n          ishr r4.z, r4.x, l(7)\n          ishr r4.w, r4.y, l(1)\n          ishl r6.x, r0.w, l(18)\n          ishl r6.y, r2.z, l(19)\n          ishl r6.z, r4.z, l(20)\n          ishl r6.w, r4.w, l(24)\n          and r6.xyzw, r6.xyzw, l(0x00040000, 0x00080000, 0x00100000, 0x01000000)\n          iadd r0.z, r0.z, r6.x\n          iadd r0.z, r6.y, r0.z\n          iadd r0.z, r6.z, r0.z\n          iadd r0.z, r5.w, r0.z\n          ishr r4.zw, r1.yyyz, l(10)\n          ishr r0.w, r1.z, l(11)\n          ishl r2.z, r4.z, l(22)\n          ishl r0.w, r0.w, l(31)\n          and r2.z, r2.z, l(0x00400000)\n          iadd r0.z, r0.z, r2.z\n          iadd r0.z, r2.w, r0.z\n          iadd r0.z, r6.w, r0.z\n          ishr r2.z, r4.y, l(2)\n          ishr r2.w, r4.y, l(3)\n          ishr r4.z, r4.y, l(4)\n          ishr r5.x, r4.y, l(5)\n          ishl r6.x, r2.z, l(25)\n          ishl r6.y, r2.w, l(26)\n          ishl r6.z, r4.z, l(27)\n          ishl r6.w, r5.x, l(28)\n          and r5.xyzw, r6.xyzw, l(0x02000000, 0x04000000, 0x08000000, 0x10000000)\n          iadd r0.z, r0.z, r5.x\n          iadd r0.z, r5.y, r0.z\n          iadd r0.z, r5.z, r0.z\n          iadd r0.z, r5.w, r0.z\n          ishr r2.z, r4.y, l(6)\n          ishr r2.w, r4.y, l(7)\n          ishl r5.x, r2.z, l(29)\n          ishl r5.y, r2.w, l(30)\n          and r2.zw, r5.xxxy, l(0, 0, 0x20000000, 0x40000000)\n          iadd r0.z, r0.z, r2.z\n          iadd r0.z, r2.w, r0.z\n          iadd r3.z, r0.w, r0.z\n          and r0.z, r4.w, l(1)\n          iadd r3.w, r0.z, r3.w\n        else \n          ieq r0.z, r2.x, l(14)\n          if_nz r0.z\n            ishl r5.x, r1.x, l(5)\n            ishl r5.y, r1.y, l(15)\n            ishl r5.z, r1.z, l(25)\n            ishl r5.w, r1.w, l(3)\n            and r5.xyzw, r5.xyzw, l(32, 0x00008000, 0x02000000, 8)\n            iadd r0.z, r5.x, l(15)\n            ishr r0.w, r1.x, l(1)\n            ishr r2.z, r1.x, l(2)\n            ishr r2.w, r1.x, l(3)\n            ishr r4.z, r1.x, l(4)\n            ishl r6.x, r0.w, l(6)\n            ishl r6.y, r2.z, l(7)\n            ishl r6.z, r2.w, l(8)\n            ishl r6.w, r4.z, l(9)\n            and r6.xyzw, r6.xyzw, l(64, 128, 256, 512)\n            iadd r0.z, r0.z, r6.x\n            iadd r0.z, r6.y, r0.z\n            iadd r0.z, r6.z, r0.z\n            iadd r0.z, r6.w, r0.z\n            ishr r0.w, r1.x, l(5)\n            ishr r2.z, r1.x, l(6)\n            ishr r2.w, r1.x, l(7)\n            ishr r4.z, r1.x, l(8)\n            ishl r6.x, r0.w, l(10)\n            ishl r6.y, r2.z, l(11)\n            ishl r6.z, r2.w, l(12)\n            ishl r6.w, r4.z, l(13)\n            and r6.xyzw, r6.xyzw, l(1024, 2048, 4096, 8192)\n            iadd r0.z, r0.z, r6.x\n            iadd r0.z, r6.y, r0.z\n            iadd r0.z, r6.z, r0.z\n            iadd r0.z, r6.w, r0.z\n            ishr r0.w, r1.x, l(9)\n            ishr r2.z, r1.y, l(1)\n            ishr r2.w, r1.y, l(2)\n            ishr r4.z, r1.y, l(3)\n            ishl r6.x, r0.w, l(14)\n            ishl r6.y, r2.z, l(16)\n            ishl r6.z, r2.w, l(17)\n            ishl r6.w, r4.z, l(18)\n            and r6.xyzw, r6.xyzw, l(0x00004000, 0x00010000, 0x00020000, 0x00040000)\n            iadd r0.z, r0.z, r6.x\n            iadd r0.z, r5.y, r0.z\n            iadd r0.z, r6.y, r0.z\n            iadd r0.z, r6.z, r0.z\n            iadd r0.z, r6.w, r0.z\n            ishr r0.w, r1.y, l(4)\n            ishr r2.z, r1.y, l(5)\n            ishr r2.w, r1.y, l(6)\n            ishr r4.z, r1.y, l(7)\n            ishl r6.x, r0.w, l(19)\n            ishl r6.y, r2.z, l(20)\n            ishl r6.z, r2.w, l(21)\n            ishl r6.w, r4.z, l(22)\n            and r6.xyzw, r6.xyzw, l(0x00080000, 0x00100000, 0x00200000, 0x00400000)\n            iadd r0.z, r0.z, r6.x\n            iadd r0.z, r6.y, r0.z\n            iadd r0.z, r6.z, r0.z\n            iadd r0.z, r6.w, r0.z\n            ishr r0.w, r1.y, l(8)\n            ishr r2.z, r1.y, l(9)\n            ishr r2.w, r1.z, l(1)\n            ishr r4.z, r1.z, l(2)\n            ishl r6.x, r0.w, l(23)\n            ishl r6.y, r2.z, l(24)\n            ishl r6.z, r2.w, l(26)\n            ishl r6.w, r4.z, l(27)\n            and r6.xyzw, r6.xyzw, l(0x00800000, 0x01000000, 0x04000000, 0x08000000)\n            iadd r0.z, r0.z, r6.x\n            iadd r0.z, r6.y, r0.z\n            iadd r0.z, r5.z, r0.z\n            iadd r0.z, r6.z, r0.z\n            iadd r0.z, r6.w, r0.z\n            ishr r0.w, r1.z, l(3)\n            ishr r2.z, r1.z, l(4)\n            ishr r2.w, r1.z, l(5)\n            ishr r4.z, r1.z, l(6)\n            ishl r5.x, r0.w, l(28)\n            ishl r5.y, r2.z, l(29)\n            ishl r5.z, r2.w, l(30)\n            ishl r0.w, r4.z, l(31)\n            and r5.xyz, r5.xyzx, l(0x10000000, 0x20000000, 0x40000000, 0)\n            iadd r0.z, r0.z, r5.x\n            iadd r0.z, r5.y, r0.z\n            iadd r0.z, r5.z, r0.z\n            iadd r3.x, r0.w, r0.z\n            ishr r0.z, r1.z, l(7)\n            ishr r0.w, r1.z, l(8)\n            ishr r2.z, r1.z, l(9)\n            ishr r2.w, r1.w, l(1)\n            and r0.z, r0.z, l(1)\n            ishl r5.x, r0.w, l(1)\n            ishl r5.y, r2.z, l(2)\n            ishl r5.z, r2.w, l(4)\n            and r5.xyz, r5.xyzx, l(2, 4, 16, 0)\n            iadd r0.z, r0.z, r5.x\n            iadd r0.z, r5.y, r0.z\n            iadd r0.z, r5.w, r0.z\n            iadd r0.z, r5.z, r0.z\n            ishr r0.w, r1.w, l(2)\n            ishr r2.z, r1.w, l(3)\n            ishr r2.w, r1.x, l(15)\n            ishr r4.z, r1.x, l(14)\n            ishl r5.x, r0.w, l(5)\n            ishl r5.y, r2.z, l(6)\n            ishl r5.z, r2.w, l(7)\n            ishl r5.w, r4.z, l(8)\n            and r5.xyzw, r5.xyzw, l(32, 64, 128, 256)\n            iadd r0.z, r0.z, r5.x\n            iadd r0.z, r5.y, r0.z\n            iadd r0.z, r5.z, r0.z\n            iadd r0.z, r5.w, r0.z\n            ishr r0.w, r1.x, l(13)\n            ishr r2.z, r1.x, l(12)\n            ishr r2.w, r1.x, l(10)\n            ishr r4.z, r1.y, l(15)\n            ishl r5.x, r0.w, l(9)\n            ishl r5.y, r2.z, l(10)\n            ishl r5.z, r2.w, l(12)\n            ishl r5.w, r4.z, l(17)\n            and r5.xyzw, r5.xyzw, l(512, 1024, 4096, 0x00020000)\n            iadd r0.z, r0.z, r5.x\n            iadd r0.z, r5.y, r0.z\n            and r0.w, r1.x, l(2048)\n            iadd r0.z, r0.w, r0.z\n            iadd r0.z, r5.z, r0.z\n            ishl r5.x, r4.x, l(13)\n            ishl r5.y, r4.y, l(23)\n            and r2.zw, r5.xxxy, l(0, 0, 8192, 0x00800000)\n            iadd r0.z, r0.z, r2.z\n            ishr r4.zw, r4.xxxy, l(1)\n            ishr r0.w, r4.x, l(2)\n            ishr r2.z, r4.x, l(3)\n            ishl r6.x, r4.z, l(14)\n            ishl r6.y, r0.w, l(15)\n            ishl r6.z, r2.z, l(16)\n            ishl r6.w, r4.w, l(24)\n            and r6.xyzw, r6.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x01000000)\n            iadd r0.z, r0.z, r6.x\n            iadd r0.z, r6.y, r0.z\n            iadd r0.z, r6.z, r0.z\n            iadd r0.z, r5.w, r0.z\n            ishr r0.w, r1.y, l(14)\n            ishr r2.z, r1.y, l(13)\n            ishr r4.z, r1.y, l(12)\n            ishr r4.w, r1.y, l(11)\n            ishl r5.x, r0.w, l(18)\n            ishl r5.y, r2.z, l(19)\n            ishl r5.z, r4.z, l(20)\n            ishl r5.w, r4.w, l(21)\n            and r5.xyzw, r5.xyzw, l(0x00040000, 0x00080000, 0x00100000, 0x00200000)\n            iadd r0.z, r0.z, r5.x\n            iadd r0.z, r5.y, r0.z\n            iadd r0.z, r5.z, r0.z\n            iadd r0.z, r5.w, r0.z\n            ishr r0.w, r1.y, l(10)\n            ishr r2.z, r1.z, l(15)\n            ishr r4.z, r1.z, l(14)\n            ishr r4.w, r1.z, l(13)\n            ishl r5.x, r0.w, l(22)\n            ishl r5.y, r2.z, l(27)\n            ishl r5.z, r4.z, l(28)\n            ishl r5.w, r4.w, l(29)\n            and r5.xyzw, r5.xyzw, l(0x00400000, 0x08000000, 0x10000000, 0x20000000)\n            iadd r0.z, r0.z, r5.x\n            iadd r0.z, r2.w, r0.z\n            iadd r0.z, r6.w, r0.z\n            ishr r0.w, r4.y, l(2)\n            ishr r2.z, r4.y, l(3)\n            ishl r6.x, r0.w, l(25)\n            ishl r6.y, r2.z, l(26)\n            and r2.zw, r6.xxxy, l(0, 0, 0x02000000, 0x04000000)\n            iadd r0.z, r0.z, r2.z\n            iadd r0.z, r2.w, r0.z\n            iadd r0.z, r5.y, r0.z\n            iadd r0.z, r5.z, r0.z\n            iadd r0.z, r5.w, r0.z\n            ishr r0.w, r1.z, l(12)\n            ishr r2.z, r1.z, l(11)\n            ishr r2.w, r1.z, l(10)\n            ishl r0.w, r0.w, l(30)\n            ishl r2.z, r2.z, l(31)\n            and r0.w, r0.w, l(0x40000000)\n            iadd r0.z, r0.w, r0.z\n            iadd r3.z, r2.z, r0.z\n            and r0.z, r2.w, l(1)\n            iadd r3.w, r0.z, r3.w\n          else \n            mov r3.xz, l(0,0,0,0)\n          endif \n        endif \n      endif \n    endif \n  else \n    iadd r0.y, r0.y, l(1)\n    ld_structured r5.xyzw, r0.y, l(52), g0.xyzw\n    ld_structured r6.xy, r0.y, l(68), g0.xyxx\n    and r3.w, r3.x, l(0xfffc0000)\n    ieq r0.y, r2.x, l(1)\n    if_nz r0.y\n      ishr r0.yz, r5.yyzy, l(4)\n      ishr r0.w, r5.y, l(1)\n      ishr r2.z, r5.y, l(2)\n      ishl r7.x, r0.y, l(2)\n      ishl r7.y, r0.z, l(3)\n      ishl r7.z, r0.w, l(10)\n      ishl r7.w, r2.z, l(11)\n      and r7.xyzw, r7.xyzw, l(4, 8, 1024, 2048)\n      iadd r0.y, r7.y, r7.x\n      and r0.z, r6.y, l(16)\n      iadd r0.y, r0.z, r0.y\n      ishl r8.x, r1.x, l(5)\n      ishl r8.y, r1.y, l(15)\n      ishl r8.z, r1.z, l(25)\n      ishl r8.w, r1.w, l(3)\n      and r8.xyzw, r8.xyzw, l(32, 0x00008000, 0x02000000, 8)\n      iadd r0.y, r0.y, r8.x\n      ishr r0.z, r1.x, l(1)\n      ishr r0.w, r1.x, l(2)\n      ishr r2.z, r1.x, l(3)\n      ishr r2.w, r1.x, l(4)\n      ishl r9.x, r0.z, l(6)\n      ishl r9.y, r0.w, l(7)\n      ishl r9.z, r2.z, l(8)\n      ishl r9.w, r2.w, l(9)\n      and r9.xyzw, r9.xyzw, l(64, 128, 256, 512)\n      iadd r0.y, r0.y, r9.x\n      iadd r0.y, r9.y, r0.y\n      iadd r0.y, r9.z, r0.y\n      iadd r0.y, r9.w, r0.y\n      ishr r0.z, r1.x, l(5)\n      ishr r0.w, r1.x, l(6)\n      ishr r2.z, r1.x, l(7)\n      ishr r2.w, r1.x, l(8)\n      ishl r9.x, r0.z, l(10)\n      ishl r9.y, r0.w, l(11)\n      ishl r9.z, r2.z, l(12)\n      ishl r9.w, r2.w, l(13)\n      and r9.xyzw, r9.xyzw, l(1024, 2048, 4096, 8192)\n      iadd r0.y, r0.y, r9.x\n      iadd r0.y, r9.y, r0.y\n      iadd r0.y, r9.z, r0.y\n      iadd r0.y, r9.w, r0.y\n      ishr r0.z, r1.x, l(9)\n      ishr r0.w, r1.y, l(1)\n      ishr r2.z, r1.y, l(2)\n      ishr r2.w, r1.y, l(3)\n      ishl r9.x, r0.z, l(14)\n      ishl r9.y, r0.w, l(16)\n      ishl r9.z, r2.z, l(17)\n      ishl r9.w, r2.w, l(18)\n      and r9.xyzw, r9.xyzw, l(0x00004000, 0x00010000, 0x00020000, 0x00040000)\n      iadd r0.y, r0.y, r9.x\n      iadd r0.y, r8.y, r0.y\n      iadd r0.y, r9.y, r0.y\n      iadd r0.y, r9.z, r0.y\n      iadd r0.y, r9.w, r0.y\n      ishr r0.z, r1.y, l(4)\n      ishr r0.w, r1.y, l(5)\n      ishr r2.z, r1.y, l(6)\n      ishr r2.w, r1.y, l(7)\n      ishl r9.x, r0.z, l(19)\n      ishl r9.y, r0.w, l(20)\n      ishl r9.z, r2.z, l(21)\n      ishl r9.w, r2.w, l(22)\n      and r9.xyzw, r9.xyzw, l(0x00080000, 0x00100000, 0x00200000, 0x00400000)\n      iadd r0.y, r0.y, r9.x\n      iadd r0.y, r9.y, r0.y\n      iadd r0.y, r9.z, r0.y\n      iadd r0.y, r9.w, r0.y\n      ishr r0.z, r1.y, l(8)\n      ishr r0.w, r1.y, l(9)\n      ishr r2.z, r1.z, l(1)\n      ishr r2.w, r1.z, l(2)\n      ishl r9.x, r0.z, l(23)\n      ishl r9.y, r0.w, l(24)\n      ishl r9.z, r2.z, l(26)\n      ishl r9.w, r2.w, l(27)\n      and r9.xyzw, r9.xyzw, l(0x00800000, 0x01000000, 0x04000000, 0x08000000)\n      iadd r0.y, r0.y, r9.x\n      iadd r0.y, r9.y, r0.y\n      iadd r0.y, r8.z, r0.y\n      iadd r0.y, r9.z, r0.y\n      iadd r0.y, r9.w, r0.y\n      ishr r0.z, r1.z, l(3)\n      ishr r0.w, r1.z, l(4)\n      ishr r2.z, r1.z, l(5)\n      ishr r2.w, r1.z, l(6)\n      ishl r8.x, r0.z, l(28)\n      ishl r8.y, r0.w, l(29)\n      ishl r8.z, r2.z, l(30)\n      ishl r0.z, r2.w, l(31)\n      and r8.xyz, r8.xyzx, l(0x10000000, 0x20000000, 0x40000000, 0)\n      iadd r0.y, r0.y, r8.x\n      iadd r0.y, r8.y, r0.y\n      iadd r0.y, r8.z, r0.y\n      iadd r3.x, r0.z, r0.y\n      ishr r0.y, r1.z, l(7)\n      ishr r0.z, r1.z, l(8)\n      ishr r0.w, r1.z, l(9)\n      ishr r2.z, r1.w, l(1)\n      and r0.y, r0.y, l(1)\n      ishl r8.x, r0.z, l(1)\n      ishl r8.y, r0.w, l(2)\n      ishl r8.z, r2.z, l(4)\n      and r8.xyz, r8.xyzx, l(2, 4, 16, 0)\n      iadd r0.y, r0.y, r8.x\n      iadd r0.y, r8.y, r0.y\n      iadd r0.y, r8.w, r0.y\n      iadd r0.y, r8.z, r0.y\n      ishr r0.z, r1.w, l(2)\n      ishr r0.w, r1.w, l(3)\n      ishr r2.z, r1.w, l(4)\n      ishl r8.x, r0.z, l(5)\n      ishl r8.y, r0.w, l(6)\n      ishl r8.z, r2.z, l(7)\n      and r8.xyz, r8.xyzx, l(32, 64, 128, 0)\n      iadd r0.y, r0.y, r8.x\n      iadd r0.y, r8.y, r0.y\n      iadd r0.y, r8.z, r0.y\n      ishr r0.z, r6.x, l(4)\n      ishr r0.w, r6.x, l(1)\n      ishr r2.z, r6.x, l(2)\n      ishr r2.w, r6.x, l(3)\n      ishl r8.x, r0.z, l(8)\n      ishl r8.y, r0.w, l(20)\n      ishl r8.z, r2.z, l(21)\n      ishl r8.w, r2.w, l(22)\n      and r8.xyzw, r8.xyzw, l(256, 0x00100000, 0x00200000, 0x00400000)\n      iadd r0.y, r0.y, r8.x\n      ishl r9.x, r5.y, l(9)\n      ishl r9.y, r5.z, l(29)\n      ishl r9.z, r5.x, l(1)\n      ishl r9.w, r5.w, l(7)\n      and r9.xyzw, r9.xyzw, l(512, 0x20000000, 2, 128)\n      iadd r0.y, r0.y, r9.x\n      iadd r0.y, r7.z, r0.y\n      iadd r0.y, r7.w, r0.y\n      ishr r0.zw, r5.yyyz, l(3)\n      ishr r2.z, r5.z, l(1)\n      ishr r2.w, r5.z, l(2)\n      ishl r7.x, r0.z, l(12)\n      ishl r7.y, r2.z, l(30)\n      ishl r0.z, r2.w, l(31)\n      and r2.zw, r7.xxxy, l(0, 0, 4096, 0x40000000)\n      iadd r0.y, r0.y, r2.z\n      ishl r7.x, r4.x, l(13)\n      ishl r7.y, r4.y, l(23)\n      and r4.zw, r7.xxxy, l(0, 0, 8192, 0x00800000)\n      iadd r0.y, r0.y, r4.z\n      ishr r2.z, r4.x, l(1)\n      ishr r4.z, r4.x, l(2)\n      ishr r6.z, r4.x, l(3)\n      ishr r6.w, r4.x, l(4)\n      ishl r7.x, r2.z, l(14)\n      ishl r7.y, r4.z, l(15)\n      ishl r7.z, r6.z, l(16)\n      ishl r7.w, r6.w, l(17)\n      and r7.xyzw, r7.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n      iadd r0.y, r0.y, r7.x\n      iadd r0.y, r7.y, r0.y\n      iadd r0.y, r7.z, r0.y\n      iadd r0.y, r7.w, r0.y\n      ishl r7.x, r6.y, l(18)\n      ishl r7.y, r6.x, l(19)\n      and r6.zw, r7.xxxy, l(0, 0, 0x00040000, 0x00080000)\n      iadd r0.y, r0.y, r6.z\n      iadd r0.y, r6.w, r0.y\n      iadd r0.y, r8.y, r0.y\n      iadd r0.y, r8.z, r0.y\n      iadd r0.y, r8.w, r0.y\n      iadd r0.y, r4.w, r0.y\n      ishr r2.z, r4.y, l(1)\n      ishr r4.z, r4.y, l(2)\n      ishr r4.w, r4.y, l(3)\n      ishr r6.z, r4.y, l(4)\n      ishl r7.x, r2.z, l(24)\n      ishl r7.y, r4.z, l(25)\n      ishl r7.z, r4.w, l(26)\n      ishl r7.w, r6.z, l(27)\n      and r7.xyzw, r7.xyzw, l(0x01000000, 0x02000000, 0x04000000, 0x08000000)\n      iadd r0.y, r0.y, r7.x\n      iadd r0.y, r7.y, r0.y\n      iadd r0.y, r7.z, r0.y\n      iadd r0.y, r7.w, r0.y\n      ishr r2.z, r6.y, l(1)\n      ishr r4.z, r6.y, l(2)\n      ishr r4.w, r6.y, l(3)\n      ishl r7.x, r2.z, l(28)\n      ishl r7.y, r4.z, l(6)\n      ishl r7.z, r4.w, l(12)\n      and r7.xyz, r7.xyzx, l(0x10000000, 64, 4096, 0)\n      iadd r0.y, r0.y, r7.x\n      iadd r0.y, r9.y, r0.y\n      iadd r0.y, r2.w, r0.y\n      iadd r3.z, r0.z, r0.y\n      and r0.y, r0.w, l(1)\n      iadd r0.y, r0.y, r3.w\n      iadd r0.y, r9.z, r0.y\n      ishr r0.z, r5.x, l(1)\n      ishr r0.w, r5.x, l(2)\n      ishr r2.z, r5.x, l(3)\n      ishr r2.w, r5.x, l(4)\n      ishl r8.x, r0.z, l(2)\n      ishl r8.y, r0.w, l(3)\n      ishl r8.z, r2.z, l(4)\n      ishl r8.w, r2.w, l(5)\n      and r8.xyzw, r8.xyzw, l(4, 8, 16, 32)\n      iadd r0.y, r0.y, r8.x\n      iadd r0.y, r8.y, r0.y\n      iadd r0.y, r8.z, r0.y\n      iadd r0.y, r8.w, r0.y\n      iadd r0.y, r7.y, r0.y\n      iadd r0.y, r9.w, r0.y\n      ishr r0.z, r5.w, l(1)\n      ishr r0.w, r5.w, l(2)\n      ishr r2.z, r5.w, l(3)\n      ishr r2.w, r5.w, l(4)\n      ishl r8.x, r0.z, l(8)\n      ishl r8.y, r0.w, l(9)\n      ishl r8.z, r2.z, l(10)\n      ishl r8.w, r2.w, l(11)\n      and r8.xyzw, r8.xyzw, l(256, 512, 1024, 2048)\n      iadd r0.y, r0.y, r8.x\n      iadd r0.y, r8.y, r0.y\n      iadd r0.y, r8.z, r0.y\n      iadd r0.y, r8.w, r0.y\n      iadd r0.y, r7.z, r0.y\n      ishl r0.z, r2.y, l(13)\n      and r0.z, r0.z, l(8192)\n      iadd r0.y, r0.z, r0.y\n      ushr r0.z, r2.y, l(1)\n      ushr r0.w, r2.y, l(2)\n      ushr r2.z, r2.y, l(3)\n      ushr r2.w, r2.y, l(4)\n      ishl r7.x, r0.z, l(14)\n      ishl r7.y, r0.w, l(15)\n      ishl r7.z, r2.z, l(16)\n      ishl r7.w, r2.w, l(17)\n      and r7.xyzw, r7.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n      iadd r0.y, r0.y, r7.x\n      iadd r0.y, r7.y, r0.y\n      iadd r0.y, r7.z, r0.y\n      iadd r3.w, r7.w, r0.y\n    else \n      ieq r0.y, r2.x, l(2)\n      if_nz r0.y\n        ishr r0.yz, r5.yyzy, l(5)\n        ishr r2.zw, r5.zzzy, l(4)\n        ishl r7.x, r0.y, l(2)\n        ishl r7.y, r2.z, l(14)\n        ishl r7.z, r0.z, l(22)\n        ishl r7.w, r2.w, l(24)\n        and r7.xyzw, r7.xyzw, l(4, 0x00004000, 0x00400000, 0x01000000)\n        iadd r0.y, r7.x, l(1)\n        ishr r0.z, r6.x, l(4)\n        ishr r0.w, r6.x, l(5)\n        ishr r2.z, r6.y, l(1)\n        ishr r2.w, r6.y, l(2)\n        ishl r8.x, r0.z, l(3)\n        ishl r8.y, r0.w, l(4)\n        ishl r8.z, r2.z, l(13)\n        ishl r8.w, r2.w, l(23)\n        and r8.xyzw, r8.xyzw, l(8, 16, 8192, 0x00800000)\n        iadd r0.y, r0.y, r8.x\n        iadd r0.y, r8.y, r0.y\n        ishl r9.x, r1.x, l(5)\n        ishl r9.y, r1.y, l(15)\n        ishl r9.z, r1.z, l(25)\n        ishl r9.w, r1.w, l(3)\n        and r9.xyzw, r9.xyzw, l(32, 0x00008000, 0x02000000, 8)\n        iadd r0.y, r0.y, r9.x\n        ishr r0.z, r1.x, l(1)\n        ishr r0.w, r1.x, l(2)\n        ishr r2.z, r1.x, l(3)\n        ishr r2.w, r1.x, l(4)\n        ishl r10.x, r0.z, l(6)\n        ishl r10.y, r0.w, l(7)\n        ishl r10.z, r2.z, l(8)\n        ishl r10.w, r2.w, l(9)\n        and r10.xyzw, r10.xyzw, l(64, 128, 256, 512)\n        iadd r0.y, r0.y, r10.x\n        iadd r0.y, r10.y, r0.y\n        iadd r0.y, r10.z, r0.y\n        iadd r0.y, r10.w, r0.y\n        ishr r0.z, r1.x, l(5)\n        ishr r0.w, r1.x, l(6)\n        ishr r2.z, r1.y, l(1)\n        ishr r2.w, r1.y, l(2)\n        ishl r10.x, r0.z, l(10)\n        ishl r10.y, r0.w, l(11)\n        ishl r10.z, r2.z, l(16)\n        ishl r10.w, r2.w, l(17)\n        and r10.xyzw, r10.xyzw, l(1024, 2048, 0x00010000, 0x00020000)\n        iadd r0.y, r0.y, r10.x\n        iadd r0.y, r10.y, r0.y\n        ishl r8.x, r6.y, l(12)\n        ishl r8.y, r6.x, l(19)\n        and r0.zw, r8.xxxy, l(0, 0, 4096, 0x00080000)\n        iadd r0.y, r0.z, r0.y\n        iadd r0.y, r8.z, r0.y\n        iadd r0.y, r7.y, r0.y\n        iadd r0.y, r9.y, r0.y\n        iadd r0.y, r10.z, r0.y\n        iadd r0.y, r10.w, r0.y\n        ishr r0.z, r1.y, l(3)\n        ishr r2.z, r1.y, l(4)\n        ishr r2.w, r1.y, l(5)\n        ishr r4.z, r1.y, l(6)\n        ishl r10.x, r0.z, l(18)\n        ishl r10.y, r2.z, l(19)\n        ishl r10.z, r2.w, l(20)\n        ishl r10.w, r4.z, l(21)\n        and r10.xyzw, r10.xyzw, l(0x00040000, 0x00080000, 0x00100000, 0x00200000)\n        iadd r0.y, r0.y, r10.x\n        iadd r0.y, r10.y, r0.y\n        iadd r0.y, r10.z, r0.y\n        iadd r0.y, r10.w, r0.y\n        iadd r0.y, r7.z, r0.y\n        iadd r0.y, r8.w, r0.y\n        iadd r0.y, r7.w, r0.y\n        iadd r0.y, r9.z, r0.y\n        ishr r0.z, r1.z, l(1)\n        ishr r2.z, r1.z, l(2)\n        ishr r2.w, r1.z, l(3)\n        ishr r4.z, r1.z, l(4)\n        ishl r7.x, r0.z, l(26)\n        ishl r7.y, r2.z, l(27)\n        ishl r7.z, r2.w, l(28)\n        ishl r7.w, r4.z, l(29)\n        and r7.xyzw, r7.xyzw, l(0x04000000, 0x08000000, 0x10000000, 0x20000000)\n        iadd r0.y, r0.y, r7.x\n        iadd r0.y, r7.y, r0.y\n        iadd r0.y, r7.z, r0.y\n        iadd r0.y, r7.w, r0.y\n        ishr r0.z, r1.z, l(5)\n        ishr r2.z, r1.z, l(6)\n        ishr r2.w, r1.w, l(1)\n        ishr r4.z, r1.w, l(2)\n        ishl r7.x, r0.z, l(30)\n        ishl r0.z, r2.z, l(31)\n        ishl r7.z, r2.w, l(4)\n        ishl r7.w, r4.z, l(5)\n        and r7.xyz, r7.xzwx, l(0x40000000, 16, 32, 0)\n        iadd r0.y, r0.y, r7.x\n        iadd r3.x, r0.z, r0.y\n        ishr r0.y, r6.y, l(3)\n        ishr r0.z, r6.y, l(5)\n        ishr r2.z, r6.y, l(4)\n        ishr r2.w, r6.x, l(1)\n        and r0.y, r0.y, l(1)\n        ishl r8.x, r0.z, l(1)\n        ishl r8.y, r2.z, l(2)\n        ishl r8.z, r2.w, l(20)\n        and r8.xyz, r8.xyzx, l(2, 4, 0x00100000, 0)\n        iadd r0.y, r0.y, r8.x\n        iadd r0.y, r8.y, r0.y\n        iadd r0.y, r9.w, r0.y\n        iadd r0.y, r7.y, r0.y\n        iadd r0.y, r7.z, r0.y\n        ishr r0.z, r1.w, l(3)\n        ishr r2.z, r1.w, l(4)\n        ishr r2.w, r1.w, l(5)\n        ishl r7.x, r0.z, l(6)\n        ishl r7.y, r2.z, l(7)\n        ishl r7.z, r2.w, l(8)\n        and r7.xyz, r7.xyzx, l(64, 128, 256, 0)\n        iadd r0.y, r0.y, r7.x\n        iadd r0.y, r7.y, r0.y\n        iadd r0.y, r7.z, r0.y\n        ishl r7.x, r5.y, l(9)\n        ishl r7.y, r5.z, l(29)\n        ishl r7.z, r5.x, l(1)\n        ishl r7.w, r5.w, l(7)\n        and r7.xyzw, r7.xyzw, l(512, 0x20000000, 2, 128)\n        iadd r0.y, r0.y, r7.x\n        ishr r2.zw, r5.yyyz, l(1)\n        ishr r0.z, r5.y, l(2)\n        ishr r4.z, r5.y, l(3)\n        ishl r9.x, r2.z, l(10)\n        ishl r9.y, r0.z, l(11)\n        ishl r9.z, r4.z, l(12)\n        ishl r9.w, r2.w, l(30)\n        and r9.xyzw, r9.xyzw, l(1024, 2048, 4096, 0x40000000)\n        iadd r0.y, r0.y, r9.x\n        iadd r0.y, r9.y, r0.y\n        iadd r0.y, r9.z, r0.y\n        ishl r8.x, r4.x, l(13)\n        ishl r8.y, r4.y, l(23)\n        and r2.zw, r8.xxxy, l(0, 0, 8192, 0x00800000)\n        iadd r0.y, r0.y, r2.z\n        ishr r0.z, r4.x, l(1)\n        ishr r2.z, r4.x, l(2)\n        ishr r4.z, r4.x, l(3)\n        ishr r4.w, r4.x, l(4)\n        ishl r10.x, r0.z, l(14)\n        ishl r10.y, r2.z, l(15)\n        ishl r10.z, r4.z, l(16)\n        ishl r10.w, r4.w, l(17)\n        and r10.xyzw, r10.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n        iadd r0.y, r0.y, r10.x\n        iadd r0.y, r10.y, r0.y\n        iadd r0.y, r10.z, r0.y\n        iadd r0.y, r10.w, r0.y\n        ishr r0.z, r4.x, l(5)\n        ishr r2.z, r4.y, l(1)\n        ishr r4.z, r4.y, l(2)\n        ishr r4.w, r4.y, l(3)\n        ishl r10.x, r0.z, l(18)\n        ishl r10.y, r2.z, l(24)\n        ishl r10.z, r4.z, l(25)\n        ishl r10.w, r4.w, l(26)\n        and r10.xyzw, r10.xyzw, l(0x00040000, 0x01000000, 0x02000000, 0x04000000)\n        iadd r0.y, r0.y, r10.x\n        iadd r0.y, r0.w, r0.y\n        iadd r0.y, r8.z, r0.y\n        ishr r0.z, r6.x, l(2)\n        ishr r0.w, r6.x, l(3)\n        ishl r8.x, r0.z, l(21)\n        ishl r8.y, r0.w, l(22)\n        and r0.zw, r8.xxxy, l(0, 0, 0x00200000, 0x00400000)\n        iadd r0.y, r0.z, r0.y\n        iadd r0.y, r0.w, r0.y\n        iadd r0.y, r2.w, r0.y\n        iadd r0.y, r10.y, r0.y\n        iadd r0.y, r10.z, r0.y\n        iadd r0.y, r10.w, r0.y\n        ishr r0.z, r4.y, l(4)\n        ishr r0.w, r4.y, l(5)\n        ishl r8.x, r0.z, l(27)\n        ishl r8.y, r0.w, l(28)\n        and r0.zw, r8.xxxy, l(0, 0, 0x08000000, 0x10000000)\n        iadd r0.y, r0.z, r0.y\n        iadd r0.y, r0.w, r0.y\n        iadd r0.y, r7.y, r0.y\n        iadd r0.y, r9.w, r0.y\n        ishr r0.zw, r5.zzzx, l(2)\n        ishr r2.z, r5.z, l(3)\n        ishr r2.w, r5.x, l(1)\n        ishl r8.x, r0.z, l(31)\n        ishl r8.y, r2.w, l(2)\n        ishl r8.z, r0.w, l(3)\n        iadd r3.z, r0.y, r8.x\n        and r0.y, r2.z, l(1)\n        iadd r0.y, r0.y, r3.w\n        iadd r0.y, r7.z, r0.y\n        and r0.zw, r8.yyyz, l(0, 0, 4, 8)\n        iadd r0.y, r0.z, r0.y\n        iadd r0.y, r0.w, r0.y\n        ishr r0.z, r5.x, l(3)\n        ishr r0.w, r5.x, l(4)\n        ishr r2.z, r5.x, l(5)\n        ishr r2.w, r5.w, l(1)\n        ishl r8.x, r0.z, l(4)\n        ishl r8.y, r0.w, l(5)\n        ishl r8.z, r2.z, l(6)\n        ishl r8.w, r2.w, l(8)\n        and r8.xyzw, r8.xyzw, l(16, 32, 64, 256)\n        iadd r0.y, r0.y, r8.x\n        iadd r0.y, r8.y, r0.y\n        iadd r0.y, r8.z, r0.y\n        iadd r0.y, r7.w, r0.y\n        iadd r0.y, r8.w, r0.y\n        ishr r0.z, r5.w, l(2)\n        ishr r0.w, r5.w, l(3)\n        ishr r2.z, r5.w, l(4)\n        ishr r2.w, r5.w, l(5)\n        ishl r7.x, r0.z, l(9)\n        ishl r7.y, r0.w, l(10)\n        ishl r7.z, r2.z, l(11)\n        ishl r7.w, r2.w, l(12)\n        and r7.xyzw, r7.xyzw, l(512, 1024, 2048, 4096)\n        iadd r0.y, r0.y, r7.x\n        iadd r0.y, r7.y, r0.y\n        iadd r0.y, r7.z, r0.y\n        iadd r0.y, r7.w, r0.y\n        ishl r0.z, r2.y, l(13)\n        and r0.z, r0.z, l(8192)\n        iadd r0.y, r0.z, r0.y\n        ushr r0.z, r2.y, l(1)\n        ushr r0.w, r2.y, l(2)\n        ushr r2.z, r2.y, l(3)\n        ushr r2.w, r2.y, l(4)\n        ishl r7.x, r0.z, l(14)\n        ishl r7.y, r0.w, l(15)\n        ishl r7.z, r2.z, l(16)\n        ishl r7.w, r2.w, l(17)\n        and r7.xyzw, r7.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n        iadd r0.y, r0.y, r7.x\n        iadd r0.y, r7.y, r0.y\n        iadd r0.y, r7.z, r0.y\n        iadd r3.w, r7.w, r0.y\n      else \n        ieq r0.y, r2.x, l(3)\n        if_nz r0.y\n          ishl r7.x, r1.x, l(5)\n          ishl r7.y, r1.y, l(15)\n          ishl r7.z, r1.z, l(25)\n          ishl r7.w, r1.w, l(3)\n          and r7.xyzw, r7.xyzw, l(32, 0x00008000, 0x02000000, 8)\n          iadd r0.y, r7.x, l(2)\n          ishr r0.z, r1.x, l(1)\n          ishr r0.w, r1.x, l(2)\n          ishr r2.z, r1.x, l(3)\n          ishr r2.w, r1.x, l(4)\n          ishl r8.x, r0.z, l(6)\n          ishl r8.y, r0.w, l(7)\n          ishl r8.z, r2.z, l(8)\n          ishl r8.w, r2.w, l(9)\n          and r8.xyzw, r8.xyzw, l(64, 128, 256, 512)\n          iadd r0.y, r0.y, r8.x\n          iadd r0.y, r8.y, r0.y\n          iadd r0.y, r8.z, r0.y\n          iadd r0.y, r8.w, r0.y\n          ishr r0.z, r1.x, l(5)\n          ishr r0.w, r1.x, l(6)\n          ishr r2.z, r1.x, l(7)\n          ishr r2.w, r1.x, l(8)\n          ishl r8.x, r0.z, l(10)\n          ishl r8.y, r0.w, l(11)\n          ishl r8.z, r2.z, l(12)\n          ishl r8.w, r2.w, l(13)\n          and r8.xyzw, r8.xyzw, l(1024, 2048, 4096, 8192)\n          iadd r0.y, r0.y, r8.x\n          iadd r0.y, r8.y, r0.y\n          iadd r0.y, r8.z, r0.y\n          iadd r0.y, r8.w, r0.y\n          ishr r0.z, r1.x, l(9)\n          ishr r0.w, r1.y, l(1)\n          ishr r2.z, r1.y, l(2)\n          ishr r2.w, r1.y, l(3)\n          ishl r8.x, r0.z, l(14)\n          ishl r8.y, r0.w, l(16)\n          ishl r8.z, r2.z, l(17)\n          ishl r8.w, r2.w, l(18)\n          and r8.xyzw, r8.xyzw, l(0x00004000, 0x00010000, 0x00020000, 0x00040000)\n          iadd r0.y, r0.y, r8.x\n          iadd r0.y, r7.y, r0.y\n          iadd r0.y, r8.y, r0.y\n          iadd r0.y, r8.z, r0.y\n          iadd r0.y, r8.w, r0.y\n          ishr r0.z, r1.y, l(4)\n          ishr r0.w, r1.y, l(5)\n          ishr r2.z, r1.y, l(6)\n          ishr r2.w, r1.y, l(7)\n          ishl r8.x, r0.z, l(19)\n          ishl r8.y, r0.w, l(20)\n          ishl r8.z, r2.z, l(21)\n          ishl r8.w, r2.w, l(22)\n          and r8.xyzw, r8.xyzw, l(0x00080000, 0x00100000, 0x00200000, 0x00400000)\n          iadd r0.y, r0.y, r8.x\n          iadd r0.y, r8.y, r0.y\n          iadd r0.y, r8.z, r0.y\n          iadd r0.y, r8.w, r0.y\n          ishr r0.z, r1.y, l(8)\n          ishr r0.w, r1.y, l(9)\n          ishr r2.z, r1.z, l(1)\n          ishr r2.w, r1.z, l(2)\n          ishl r8.x, r0.z, l(23)\n          ishl r8.y, r0.w, l(24)\n          ishl r8.z, r2.z, l(26)\n          ishl r8.w, r2.w, l(27)\n          and r8.xyzw, r8.xyzw, l(0x00800000, 0x01000000, 0x04000000, 0x08000000)\n          iadd r0.y, r0.y, r8.x\n          iadd r0.y, r8.y, r0.y\n          iadd r0.y, r7.z, r0.y\n          iadd r0.y, r8.z, r0.y\n          iadd r0.y, r8.w, r0.y\n          ishr r0.z, r1.z, l(3)\n          ishr r0.w, r1.z, l(4)\n          ishr r2.z, r1.z, l(5)\n          ishr r2.w, r1.z, l(6)\n          ishl r7.x, r0.z, l(28)\n          ishl r7.y, r0.w, l(29)\n          ishl r7.z, r2.z, l(30)\n          ishl r0.z, r2.w, l(31)\n          and r7.xyz, r7.xyzx, l(0x10000000, 0x20000000, 0x40000000, 0)\n          iadd r0.y, r0.y, r7.x\n          iadd r0.y, r7.y, r0.y\n          iadd r0.y, r7.z, r0.y\n          iadd r3.x, r0.z, r0.y\n          ishr r0.y, r1.z, l(7)\n          ishr r0.z, r1.z, l(8)\n          ishr r0.w, r1.z, l(9)\n          ishr r2.z, r1.w, l(1)\n          and r0.y, r0.y, l(1)\n          ishl r7.x, r0.z, l(1)\n          ishl r7.y, r0.w, l(2)\n          ishl r7.z, r2.z, l(4)\n          and r7.xyz, r7.xyzx, l(2, 4, 16, 0)\n          iadd r0.y, r0.y, r7.x\n          iadd r0.y, r7.y, r0.y\n          iadd r0.y, r7.w, r0.y\n          iadd r0.y, r7.z, r0.y\n          ishr r0.z, r1.w, l(2)\n          ishr r0.w, r1.w, l(3)\n          ishr r2.z, r1.w, l(4)\n          ishr r2.w, r1.x, l(10)\n          ishl r7.x, r0.z, l(5)\n          ishl r7.y, r0.w, l(6)\n          ishl r7.z, r2.z, l(7)\n          ishl r7.w, r2.w, l(8)\n          and r7.xyzw, r7.xyzw, l(32, 64, 128, 256)\n          iadd r0.y, r0.y, r7.x\n          iadd r0.y, r7.y, r0.y\n          iadd r0.y, r7.z, r0.y\n          iadd r0.y, r7.w, r0.y\n          ishl r7.x, r5.y, l(9)\n          ishl r7.y, r5.z, l(29)\n          ishl r7.z, r5.x, l(1)\n          ishl r7.w, r5.w, l(7)\n          and r7.xyzw, r7.xyzw, l(512, 0x20000000, 2, 128)\n          iadd r0.y, r0.y, r7.x\n          ishr r0.zw, r5.yyyz, l(1)\n          ishr r2.z, r5.y, l(2)\n          ishr r2.w, r5.y, l(3)\n          ishl r8.x, r0.z, l(10)\n          ishl r8.y, r2.z, l(11)\n          ishl r8.z, r2.w, l(12)\n          ishl r8.w, r0.w, l(30)\n          and r8.xyzw, r8.xyzw, l(1024, 2048, 4096, 0x40000000)\n          iadd r0.y, r0.y, r8.x\n          iadd r0.y, r8.y, r0.y\n          iadd r0.y, r8.z, r0.y\n          ishl r8.x, r4.x, l(13)\n          ishl r8.y, r4.y, l(23)\n          and r0.zw, r8.xxxy, l(0, 0, 8192, 0x00800000)\n          iadd r0.y, r0.z, r0.y\n          ishr r2.zw, r4.xxxy, l(1)\n          ishr r0.z, r4.x, l(2)\n          ishr r4.z, r4.x, l(3)\n          ishl r9.x, r2.z, l(14)\n          ishl r9.y, r0.z, l(15)\n          ishl r9.z, r4.z, l(16)\n          ishl r9.w, r2.w, l(24)\n          and r9.xyzw, r9.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x01000000)\n          iadd r0.y, r0.y, r9.x\n          iadd r0.y, r9.y, r0.y\n          iadd r0.y, r9.z, r0.y\n          ishr r2.zw, r1.yyyz, l(10)\n          ishl r8.x, r2.z, l(17)\n          ishl r8.y, r2.w, l(27)\n          and r2.zw, r8.xxxy, l(0, 0, 0x00020000, 0x08000000)\n          iadd r0.y, r0.y, r2.z\n          ishl r8.x, r6.y, l(18)\n          ishl r8.y, r6.x, l(19)\n          and r4.zw, r8.xxxy, l(0, 0, 0x00040000, 0x00080000)\n          iadd r0.y, r0.y, r4.z\n          iadd r0.y, r4.w, r0.y\n          ishr r4.zw, r6.xxxy, l(1)\n          ishr r0.z, r6.x, l(2)\n          ishr r2.z, r6.x, l(3)\n          ishl r10.x, r4.z, l(20)\n          ishl r10.y, r0.z, l(21)\n          ishl r10.z, r2.z, l(22)\n          ishl r10.w, r4.w, l(28)\n          and r10.xyzw, r10.xyzw, l(0x00100000, 0x00200000, 0x00400000, 0x10000000)\n          iadd r0.y, r0.y, r10.x\n          iadd r0.y, r10.y, r0.y\n          iadd r0.y, r10.z, r0.y\n          iadd r0.y, r0.w, r0.y\n          iadd r0.y, r9.w, r0.y\n          ishr r0.z, r4.y, l(2)\n          ishr r0.w, r4.y, l(3)\n          ishl r8.x, r0.z, l(25)\n          ishl r8.y, r0.w, l(26)\n          and r0.zw, r8.xxxy, l(0, 0, 0x02000000, 0x04000000)\n          iadd r0.y, r0.z, r0.y\n          iadd r0.y, r0.w, r0.y\n          iadd r0.y, r2.w, r0.y\n          iadd r0.y, r10.w, r0.y\n          iadd r0.y, r7.y, r0.y\n          iadd r0.y, r8.w, r0.y\n          ishr r0.zw, r5.zzzx, l(2)\n          ishr r2.z, r5.z, l(3)\n          ishr r2.w, r5.x, l(1)\n          ishl r8.x, r0.z, l(31)\n          ishl r8.y, r2.w, l(2)\n          ishl r8.z, r0.w, l(3)\n          iadd r3.z, r0.y, r8.x\n          and r0.y, r2.z, l(1)\n          iadd r0.y, r0.y, r3.w\n          iadd r0.y, r7.z, r0.y\n          and r0.zw, r8.yyyz, l(0, 0, 4, 8)\n          iadd r0.y, r0.z, r0.y\n          iadd r0.y, r0.w, r0.y\n          ishr r0.z, r5.x, l(3)\n          ishr r0.w, r5.x, l(4)\n          ishr r2.z, r5.w, l(1)\n          ishr r2.w, r5.w, l(2)\n          ishl r8.x, r0.z, l(4)\n          ishl r8.y, r0.w, l(5)\n          ishl r8.z, r2.z, l(8)\n          ishl r8.w, r2.w, l(9)\n          and r8.xyzw, r8.xyzw, l(16, 32, 256, 512)\n          iadd r0.y, r0.y, r8.x\n          iadd r0.y, r8.y, r0.y\n          ishr r0.z, r6.y, l(2)\n          ishr r0.w, r6.y, l(3)\n          ishl r7.x, r0.z, l(6)\n          ishl r7.y, r0.w, l(12)\n          and r0.zw, r7.xxxy, l(0, 0, 64, 4096)\n          iadd r0.y, r0.z, r0.y\n          iadd r0.y, r7.w, r0.y\n          iadd r0.y, r8.z, r0.y\n          iadd r0.y, r8.w, r0.y\n          ishr r0.z, r5.w, l(3)\n          ishr r2.z, r5.w, l(4)\n          ishl r7.x, r0.z, l(10)\n          ishl r7.y, r2.z, l(11)\n          and r2.zw, r7.xxxy, l(0, 0, 1024, 2048)\n          iadd r0.y, r0.y, r2.z\n          iadd r0.y, r2.w, r0.y\n          iadd r0.y, r0.w, r0.y\n          ishl r0.z, r2.y, l(13)\n          and r0.z, r0.z, l(8192)\n          iadd r0.y, r0.z, r0.y\n          ushr r0.z, r2.y, l(1)\n          ushr r0.w, r2.y, l(2)\n          ushr r2.z, r2.y, l(3)\n          ushr r2.w, r2.y, l(4)\n          ishl r7.x, r0.z, l(14)\n          ishl r7.y, r0.w, l(15)\n          ishl r7.z, r2.z, l(16)\n          ishl r7.w, r2.w, l(17)\n          and r7.xyzw, r7.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n          iadd r0.y, r0.y, r7.x\n          iadd r0.y, r7.y, r0.y\n          iadd r0.y, r7.z, r0.y\n          iadd r3.w, r7.w, r0.y\n        else \n          ieq r0.y, r2.x, l(4)\n          if_nz r0.y\n            ishl r7.x, r1.x, l(5)\n            ishl r7.y, r1.y, l(15)\n            ishl r7.z, r1.z, l(25)\n            ishl r7.w, r1.w, l(3)\n            and r7.xyzw, r7.xyzw, l(32, 0x00008000, 0x02000000, 8)\n            iadd r0.y, r7.x, l(6)\n            ishr r0.z, r1.x, l(1)\n            ishr r0.w, r1.x, l(2)\n            ishr r2.z, r1.x, l(3)\n            ishr r2.w, r1.x, l(4)\n            ishl r8.x, r0.z, l(6)\n            ishl r8.y, r0.w, l(7)\n            ishl r8.z, r2.z, l(8)\n            ishl r8.w, r2.w, l(9)\n            and r8.xyzw, r8.xyzw, l(64, 128, 256, 512)\n            iadd r0.y, r0.y, r8.x\n            iadd r0.y, r8.y, r0.y\n            iadd r0.y, r8.z, r0.y\n            iadd r0.y, r8.w, r0.y\n            ishr r0.z, r1.x, l(5)\n            ishr r0.w, r1.x, l(6)\n            ishr r2.z, r1.x, l(7)\n            ishr r2.w, r1.x, l(8)\n            ishl r8.x, r0.z, l(10)\n            ishl r8.y, r0.w, l(11)\n            ishl r8.z, r2.z, l(12)\n            ishl r8.w, r2.w, l(13)\n            and r8.xyzw, r8.xyzw, l(1024, 2048, 4096, 8192)\n            iadd r0.y, r0.y, r8.x\n            iadd r0.y, r8.y, r0.y\n            iadd r0.y, r8.z, r0.y\n            iadd r0.y, r8.w, r0.y\n            ishr r0.z, r1.x, l(9)\n            ishr r0.w, r1.y, l(1)\n            ishr r2.z, r1.y, l(2)\n            ishr r2.w, r1.y, l(3)\n            ishl r8.x, r0.z, l(14)\n            ishl r8.y, r0.w, l(16)\n            ishl r8.z, r2.z, l(17)\n            ishl r8.w, r2.w, l(18)\n            and r8.xyzw, r8.xyzw, l(0x00004000, 0x00010000, 0x00020000, 0x00040000)\n            iadd r0.y, r0.y, r8.x\n            iadd r0.y, r7.y, r0.y\n            iadd r0.y, r8.y, r0.y\n            iadd r0.y, r8.z, r0.y\n            iadd r0.y, r8.w, r0.y\n            ishr r0.z, r1.y, l(4)\n            ishr r0.w, r1.y, l(5)\n            ishr r2.z, r1.y, l(6)\n            ishr r2.w, r1.y, l(7)\n            ishl r8.x, r0.z, l(19)\n            ishl r8.y, r0.w, l(20)\n            ishl r8.z, r2.z, l(21)\n            ishl r8.w, r2.w, l(22)\n            and r8.xyzw, r8.xyzw, l(0x00080000, 0x00100000, 0x00200000, 0x00400000)\n            iadd r0.y, r0.y, r8.x\n            iadd r0.y, r8.y, r0.y\n            iadd r0.y, r8.z, r0.y\n            iadd r0.y, r8.w, r0.y\n            ishr r0.z, r1.y, l(8)\n            ishr r0.w, r1.y, l(9)\n            ishr r2.z, r1.z, l(1)\n            ishr r2.w, r1.z, l(2)\n            ishl r8.x, r0.z, l(23)\n            ishl r8.y, r0.w, l(24)\n            ishl r8.z, r2.z, l(26)\n            ishl r8.w, r2.w, l(27)\n            and r8.xyzw, r8.xyzw, l(0x00800000, 0x01000000, 0x04000000, 0x08000000)\n            iadd r0.y, r0.y, r8.x\n            iadd r0.y, r8.y, r0.y\n            iadd r0.y, r7.z, r0.y\n            iadd r0.y, r8.z, r0.y\n            iadd r0.y, r8.w, r0.y\n            ishr r0.z, r1.z, l(3)\n            ishr r0.w, r1.z, l(4)\n            ishr r2.z, r1.z, l(5)\n            ishr r2.w, r1.z, l(6)\n            ishl r7.x, r0.z, l(28)\n            ishl r7.y, r0.w, l(29)\n            ishl r7.z, r2.z, l(30)\n            ishl r0.z, r2.w, l(31)\n            and r7.xyz, r7.xyzx, l(0x10000000, 0x20000000, 0x40000000, 0)\n            iadd r0.y, r0.y, r7.x\n            iadd r0.y, r7.y, r0.y\n            iadd r0.y, r7.z, r0.y\n            iadd r3.x, r0.z, r0.y\n            ishr r0.y, r1.z, l(7)\n            ishr r0.z, r1.z, l(8)\n            ishr r0.w, r1.z, l(9)\n            ishr r2.z, r1.w, l(1)\n            and r0.y, r0.y, l(1)\n            ishl r7.x, r0.z, l(1)\n            ishl r7.y, r0.w, l(2)\n            ishl r7.z, r2.z, l(4)\n            and r7.xyz, r7.xyzx, l(2, 4, 16, 0)\n            iadd r0.y, r0.y, r7.x\n            iadd r0.y, r7.y, r0.y\n            iadd r0.y, r7.w, r0.y\n            iadd r0.y, r7.z, r0.y\n            ishr r0.z, r1.w, l(2)\n            ishr r0.w, r1.w, l(3)\n            ishr r2.zw, r1.xxxy, l(10)\n            ishl r7.x, r0.z, l(5)\n            ishl r7.y, r0.w, l(6)\n            ishl r7.z, r2.z, l(7)\n            ishl r7.w, r2.w, l(18)\n            and r7.xyzw, r7.xyzw, l(32, 64, 128, 0x00040000)\n            iadd r0.y, r0.y, r7.x\n            iadd r0.y, r7.y, r0.y\n            iadd r0.y, r7.z, r0.y\n            ishr r0.z, r6.x, l(4)\n            ishr r0.w, r6.x, l(1)\n            ishr r2.z, r6.x, l(2)\n            ishr r2.w, r6.x, l(3)\n            ishl r8.x, r0.z, l(8)\n            ishl r8.y, r0.w, l(20)\n            ishl r8.z, r2.z, l(21)\n            ishl r8.w, r2.w, l(22)\n            and r8.xyzw, r8.xyzw, l(256, 0x00100000, 0x00200000, 0x00400000)\n            iadd r0.y, r0.y, r8.x\n            ishl r9.x, r5.y, l(9)\n            ishl r9.y, r5.z, l(29)\n            ishl r9.z, r5.x, l(1)\n            ishl r9.w, r5.w, l(7)\n            and r9.xyzw, r9.xyzw, l(512, 0x20000000, 2, 128)\n            iadd r0.y, r0.y, r9.x\n            ishr r0.zw, r5.yyyz, l(1)\n            ishr r2.z, r5.y, l(2)\n            ishr r2.w, r5.y, l(3)\n            ishl r10.x, r0.z, l(10)\n            ishl r10.y, r2.z, l(11)\n            ishl r10.z, r2.w, l(12)\n            ishl r10.w, r0.w, l(30)\n            and r10.xyzw, r10.xyzw, l(1024, 2048, 4096, 0x40000000)\n            iadd r0.y, r0.y, r10.x\n            iadd r0.y, r10.y, r0.y\n            iadd r0.y, r10.z, r0.y\n            ishl r7.x, r4.x, l(13)\n            ishl r7.y, r4.y, l(23)\n            and r0.zw, r7.xxxy, l(0, 0, 8192, 0x00800000)\n            iadd r0.y, r0.z, r0.y\n            ishr r0.z, r4.x, l(1)\n            ishr r2.z, r4.x, l(2)\n            ishr r2.w, r4.x, l(3)\n            ishr r4.z, r4.x, l(4)\n            ishl r11.x, r0.z, l(14)\n            ishl r11.y, r2.z, l(15)\n            ishl r11.z, r2.w, l(16)\n            ishl r11.w, r4.z, l(17)\n            and r11.xyzw, r11.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n            iadd r0.y, r0.y, r11.x\n            iadd r0.y, r11.y, r0.y\n            iadd r0.y, r11.z, r0.y\n            iadd r0.y, r11.w, r0.y\n            iadd r0.y, r7.w, r0.y\n            ishl r7.x, r6.x, l(19)\n            ishl r7.y, r6.y, l(5)\n            and r2.zw, r7.xxxy, l(0, 0, 0x00080000, 32)\n            iadd r0.y, r0.y, r2.z\n            iadd r0.y, r8.y, r0.y\n            iadd r0.y, r8.z, r0.y\n            iadd r0.y, r8.w, r0.y\n            iadd r0.y, r0.w, r0.y\n            ishr r0.z, r4.y, l(1)\n            ishr r0.w, r4.y, l(2)\n            ishr r2.z, r4.y, l(3)\n            ishl r7.x, r0.z, l(24)\n            ishl r7.y, r0.w, l(25)\n            ishl r7.z, r2.z, l(26)\n            and r7.xyz, r7.xyzx, l(0x01000000, 0x02000000, 0x04000000, 0)\n            iadd r0.y, r0.y, r7.x\n            iadd r0.y, r7.y, r0.y\n            iadd r0.y, r7.z, r0.y\n            ishr r0.z, r1.z, l(10)\n            ishl r0.z, r0.z, l(27)\n            and r0.z, r0.z, l(0x08000000)\n            iadd r0.y, r0.z, r0.y\n            ishr r0.z, r6.y, l(1)\n            ishr r0.w, r6.y, l(2)\n            ishr r2.z, r6.y, l(3)\n            ishl r7.x, r0.z, l(28)\n            ishl r7.y, r0.w, l(6)\n            ishl r7.z, r2.z, l(12)\n            and r7.xyz, r7.xyzx, l(0x10000000, 64, 4096, 0)\n            iadd r0.y, r0.y, r7.x\n            iadd r0.y, r9.y, r0.y\n            iadd r0.y, r10.w, r0.y\n            ishr r0.zw, r5.zzzx, l(2)\n            ishr r2.z, r5.z, l(3)\n            ishr r4.z, r5.x, l(1)\n            ishl r8.x, r0.z, l(31)\n            ishl r8.y, r4.z, l(2)\n            ishl r8.z, r0.w, l(3)\n            iadd r3.z, r0.y, r8.x\n            and r0.y, r2.z, l(1)\n            iadd r0.y, r0.y, r3.w\n            iadd r0.y, r9.z, r0.y\n            and r0.zw, r8.yyyz, l(0, 0, 4, 8)\n            iadd r0.y, r0.z, r0.y\n            iadd r0.y, r0.w, r0.y\n            ishr r0.zw, r5.xxxw, l(3)\n            ishr r2.z, r5.w, l(1)\n            ishr r4.z, r5.w, l(2)\n            ishl r8.x, r0.z, l(4)\n            ishl r8.y, r2.z, l(8)\n            ishl r8.z, r4.z, l(9)\n            ishl r8.w, r0.w, l(10)\n            and r8.xyzw, r8.xyzw, l(16, 256, 512, 1024)\n            iadd r0.y, r0.y, r8.x\n            iadd r0.y, r2.w, r0.y\n            iadd r0.y, r7.y, r0.y\n            iadd r0.y, r9.w, r0.y\n            iadd r0.y, r8.y, r0.y\n            iadd r0.y, r8.z, r0.y\n            iadd r0.y, r8.w, r0.y\n            ishr r0.z, r5.y, l(4)\n            ishl r0.z, r0.z, l(11)\n            and r0.z, r0.z, l(2048)\n            iadd r0.y, r0.z, r0.y\n            iadd r0.y, r7.z, r0.y\n            ishl r0.z, r2.y, l(13)\n            and r0.z, r0.z, l(8192)\n            iadd r0.y, r0.z, r0.y\n            ushr r0.z, r2.y, l(1)\n            ushr r0.w, r2.y, l(2)\n            ushr r2.z, r2.y, l(3)\n            ushr r2.w, r2.y, l(4)\n            ishl r7.x, r0.z, l(14)\n            ishl r7.y, r0.w, l(15)\n            ishl r7.z, r2.z, l(16)\n            ishl r7.w, r2.w, l(17)\n            and r7.xyzw, r7.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n            iadd r0.y, r0.y, r7.x\n            iadd r0.y, r7.y, r0.y\n            iadd r0.y, r7.z, r0.y\n            iadd r3.w, r7.w, r0.y\n          else \n            ieq r0.y, r2.x, l(5)\n            if_nz r0.y\n              ishl r7.x, r1.x, l(5)\n              ishl r7.y, r1.y, l(15)\n              ishl r7.z, r1.z, l(25)\n              ishl r7.w, r1.w, l(3)\n              and r7.xyzw, r7.xyzw, l(32, 0x00008000, 0x02000000, 8)\n              iadd r0.y, r7.x, l(10)\n              ishr r0.z, r1.x, l(1)\n              ishr r0.w, r1.x, l(2)\n              ishr r2.z, r1.x, l(3)\n              ishr r2.w, r1.x, l(4)\n              ishl r8.x, r0.z, l(6)\n              ishl r8.y, r0.w, l(7)\n              ishl r8.z, r2.z, l(8)\n              ishl r8.w, r2.w, l(9)\n              and r8.xyzw, r8.xyzw, l(64, 128, 256, 512)\n              iadd r0.y, r0.y, r8.x\n              iadd r0.y, r8.y, r0.y\n              iadd r0.y, r8.z, r0.y\n              iadd r0.y, r8.w, r0.y\n              ishr r0.z, r1.x, l(5)\n              ishr r0.w, r1.x, l(6)\n              ishr r2.z, r1.x, l(7)\n              ishr r2.w, r1.x, l(8)\n              ishl r8.x, r0.z, l(10)\n              ishl r8.y, r0.w, l(11)\n              ishl r8.z, r2.z, l(12)\n              ishl r8.w, r2.w, l(13)\n              and r8.xyzw, r8.xyzw, l(1024, 2048, 4096, 8192)\n              iadd r0.y, r0.y, r8.x\n              iadd r0.y, r8.y, r0.y\n              iadd r0.y, r8.z, r0.y\n              iadd r0.y, r8.w, r0.y\n              ishr r0.z, r1.x, l(9)\n              ishr r0.w, r1.y, l(1)\n              ishr r2.z, r1.y, l(2)\n              ishr r2.w, r1.y, l(3)\n              ishl r8.x, r0.z, l(14)\n              ishl r8.y, r0.w, l(16)\n              ishl r8.z, r2.z, l(17)\n              ishl r8.w, r2.w, l(18)\n              and r8.xyzw, r8.xyzw, l(0x00004000, 0x00010000, 0x00020000, 0x00040000)\n              iadd r0.y, r0.y, r8.x\n              iadd r0.y, r7.y, r0.y\n              iadd r0.y, r8.y, r0.y\n              iadd r0.y, r8.z, r0.y\n              iadd r0.y, r8.w, r0.y\n              ishr r0.z, r1.y, l(4)\n              ishr r0.w, r1.y, l(5)\n              ishr r2.z, r1.y, l(6)\n              ishr r2.w, r1.y, l(7)\n              ishl r8.x, r0.z, l(19)\n              ishl r8.y, r0.w, l(20)\n              ishl r8.z, r2.z, l(21)\n              ishl r8.w, r2.w, l(22)\n              and r8.xyzw, r8.xyzw, l(0x00080000, 0x00100000, 0x00200000, 0x00400000)\n              iadd r0.y, r0.y, r8.x\n              iadd r0.y, r8.y, r0.y\n              iadd r0.y, r8.z, r0.y\n              iadd r0.y, r8.w, r0.y\n              ishr r0.z, r1.y, l(8)\n              ishr r0.w, r1.y, l(9)\n              ishr r2.z, r1.z, l(1)\n              ishr r2.w, r1.z, l(2)\n              ishl r8.x, r0.z, l(23)\n              ishl r8.y, r0.w, l(24)\n              ishl r8.z, r2.z, l(26)\n              ishl r8.w, r2.w, l(27)\n              and r8.xyzw, r8.xyzw, l(0x00800000, 0x01000000, 0x04000000, 0x08000000)\n              iadd r0.y, r0.y, r8.x\n              iadd r0.y, r8.y, r0.y\n              iadd r0.y, r7.z, r0.y\n              iadd r0.y, r8.z, r0.y\n              iadd r0.y, r8.w, r0.y\n              ishr r0.z, r1.z, l(3)\n              ishr r0.w, r1.z, l(4)\n              ishr r2.z, r1.z, l(5)\n              ishr r2.w, r1.z, l(6)\n              ishl r7.x, r0.z, l(28)\n              ishl r7.y, r0.w, l(29)\n              ishl r7.z, r2.z, l(30)\n              ishl r0.z, r2.w, l(31)\n              and r7.xyz, r7.xyzx, l(0x10000000, 0x20000000, 0x40000000, 0)\n              iadd r0.y, r0.y, r7.x\n              iadd r0.y, r7.y, r0.y\n              iadd r0.y, r7.z, r0.y\n              iadd r3.x, r0.z, r0.y\n              ishr r0.y, r1.z, l(7)\n              ishr r0.z, r1.z, l(8)\n              ishr r0.w, r1.z, l(9)\n              ishr r2.z, r1.w, l(1)\n              and r0.y, r0.y, l(1)\n              ishl r7.x, r0.z, l(1)\n              ishl r7.y, r0.w, l(2)\n              ishl r7.z, r2.z, l(4)\n              and r7.xyz, r7.xyzx, l(2, 4, 16, 0)\n              iadd r0.y, r0.y, r7.x\n              iadd r0.y, r7.y, r0.y\n              iadd r0.y, r7.w, r0.y\n              iadd r0.y, r7.z, r0.y\n              ishr r0.z, r1.w, l(2)\n              ishr r0.w, r1.w, l(3)\n              ishr r2.zw, r1.xxxy, l(10)\n              ishl r7.x, r0.z, l(5)\n              ishl r7.y, r0.w, l(6)\n              ishl r7.z, r2.z, l(7)\n              ishl r7.w, r2.w, l(17)\n              and r7.xyzw, r7.xyzw, l(32, 64, 128, 0x00020000)\n              iadd r0.y, r0.y, r7.x\n              iadd r0.y, r7.y, r0.y\n              iadd r0.y, r7.z, r0.y\n              ishr r0.z, r5.z, l(4)\n              ishr r0.w, r5.y, l(1)\n              ishr r2.z, r5.y, l(2)\n              ishr r2.w, r5.y, l(3)\n              ishl r8.x, r0.z, l(8)\n              ishl r8.y, r0.w, l(10)\n              ishl r8.z, r2.z, l(11)\n              ishl r8.w, r2.w, l(12)\n              and r8.xyzw, r8.xyzw, l(256, 1024, 2048, 4096)\n              iadd r0.y, r0.y, r8.x\n              ishl r9.x, r5.y, l(9)\n              ishl r9.y, r5.z, l(29)\n              ishl r9.z, r5.x, l(1)\n              ishl r9.w, r5.w, l(7)\n              and r9.xyzw, r9.xyzw, l(512, 0x20000000, 2, 128)\n              iadd r0.y, r0.y, r9.x\n              iadd r0.y, r8.y, r0.y\n              iadd r0.y, r8.z, r0.y\n              iadd r0.y, r8.w, r0.y\n              ishl r7.x, r4.x, l(13)\n              ishl r7.y, r4.y, l(23)\n              and r0.zw, r7.xxxy, l(0, 0, 8192, 0x00800000)\n              iadd r0.y, r0.z, r0.y\n              ishr r2.zw, r4.xxxy, l(1)\n              ishr r0.z, r4.x, l(2)\n              ishr r4.z, r4.x, l(3)\n              ishl r8.x, r2.z, l(14)\n              ishl r8.y, r0.z, l(15)\n              ishl r8.z, r4.z, l(16)\n              ishl r8.w, r2.w, l(24)\n              and r8.xyzw, r8.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x01000000)\n              iadd r0.y, r0.y, r8.x\n              iadd r0.y, r8.y, r0.y\n              iadd r0.y, r8.z, r0.y\n              iadd r0.y, r7.w, r0.y\n              ishl r7.x, r6.y, l(18)\n              ishl r7.y, r6.x, l(19)\n              and r2.zw, r7.xxxy, l(0, 0, 0x00040000, 0x00080000)\n              iadd r0.y, r0.y, r2.z\n              iadd r0.y, r2.w, r0.y\n              ishr r2.zw, r6.xxxy, l(1)\n              ishr r0.z, r6.x, l(2)\n              ishr r4.z, r6.x, l(3)\n              ishl r7.x, r2.z, l(20)\n              ishl r7.y, r0.z, l(21)\n              ishl r7.z, r4.z, l(22)\n              ishl r7.w, r2.w, l(5)\n              and r7.xyzw, r7.xyzw, l(0x00100000, 0x00200000, 0x00400000, 32)\n              iadd r0.y, r0.y, r7.x\n              iadd r0.y, r7.y, r0.y\n              iadd r0.y, r7.z, r0.y\n              iadd r0.y, r0.w, r0.y\n              iadd r0.y, r8.w, r0.y\n              ishr r0.z, r4.y, l(2)\n              ishr r0.w, r4.y, l(3)\n              ishr r2.z, r4.y, l(4)\n              ishl r7.x, r0.z, l(25)\n              ishl r7.y, r0.w, l(26)\n              ishl r7.z, r2.z, l(27)\n              and r7.xyz, r7.xyzx, l(0x02000000, 0x04000000, 0x08000000, 0)\n              iadd r0.y, r0.y, r7.x\n              iadd r0.y, r7.y, r0.y\n              iadd r0.y, r7.z, r0.y\n              ishr r0.z, r1.z, l(10)\n              ishl r0.z, r0.z, l(28)\n              and r0.z, r0.z, l(0x10000000)\n              iadd r0.y, r0.z, r0.y\n              iadd r0.y, r9.y, r0.y\n              ishr r0.zw, r5.zzzx, l(1)\n              ishr r2.z, r5.z, l(2)\n              ishr r2.w, r5.z, l(3)\n              ishl r7.x, r0.z, l(30)\n              ishl r0.z, r2.z, l(31)\n              ishl r7.z, r0.w, l(2)\n              and r4.zw, r7.xxxz, l(0, 0, 0x40000000, 4)\n              iadd r0.y, r0.y, r4.z\n              iadd r3.z, r0.z, r0.y\n              and r0.y, r2.w, l(1)\n              iadd r0.y, r0.y, r3.w\n              iadd r0.y, r9.z, r0.y\n              iadd r0.y, r4.w, r0.y\n              ishr r0.zw, r5.xxxw, l(2)\n              ishr r2.z, r5.x, l(3)\n              ishr r2.w, r5.w, l(1)\n              ishl r8.x, r0.z, l(3)\n              ishl r8.y, r2.z, l(4)\n              ishl r8.z, r2.w, l(8)\n              ishl r8.w, r0.w, l(9)\n              and r8.xyzw, r8.xyzw, l(8, 16, 256, 512)\n              iadd r0.y, r0.y, r8.x\n              iadd r0.y, r8.y, r0.y\n              iadd r0.y, r7.w, r0.y\n              ishr r0.z, r6.y, l(2)\n              ishr r0.w, r6.y, l(4)\n              ishr r2.z, r6.y, l(3)\n              ishl r7.x, r0.z, l(6)\n              ishl r7.y, r0.w, l(11)\n              ishl r7.z, r2.z, l(12)\n              and r7.xyz, r7.xyzx, l(64, 2048, 4096, 0)\n              iadd r0.y, r0.y, r7.x\n              iadd r0.y, r9.w, r0.y\n              iadd r0.y, r8.z, r0.y\n              iadd r0.y, r8.w, r0.y\n              ishr r0.z, r5.w, l(3)\n              ishl r0.z, r0.z, l(10)\n              and r0.z, r0.z, l(1024)\n              iadd r0.y, r0.z, r0.y\n              iadd r0.y, r7.y, r0.y\n              iadd r0.y, r7.z, r0.y\n              ishl r0.z, r2.y, l(13)\n              and r0.z, r0.z, l(8192)\n              iadd r0.y, r0.z, r0.y\n              ushr r0.z, r2.y, l(1)\n              ushr r0.w, r2.y, l(2)\n              ushr r2.z, r2.y, l(3)\n              ushr r2.w, r2.y, l(4)\n              ishl r7.x, r0.z, l(14)\n              ishl r7.y, r0.w, l(15)\n              ishl r7.z, r2.z, l(16)\n              ishl r7.w, r2.w, l(17)\n              and r7.xyzw, r7.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n              iadd r0.y, r0.y, r7.x\n              iadd r0.y, r7.y, r0.y\n              iadd r0.y, r7.z, r0.y\n              iadd r3.w, r7.w, r0.y\n            else \n              ieq r0.y, r2.x, l(6)\n              if_nz r0.y\n                ishl r7.x, r1.x, l(5)\n                ishl r7.y, r1.y, l(15)\n                ishl r7.z, r1.z, l(25)\n                ishl r7.w, r1.w, l(3)\n                and r7.xyzw, r7.xyzw, l(32, 0x00008000, 0x02000000, 8)\n                iadd r0.y, r7.x, l(14)\n                ishr r0.z, r1.x, l(1)\n                ishr r0.w, r1.x, l(2)\n                ishr r2.z, r1.x, l(3)\n                ishr r2.w, r1.x, l(4)\n                ishl r8.x, r0.z, l(6)\n                ishl r8.y, r0.w, l(7)\n                ishl r8.z, r2.z, l(8)\n                ishl r8.w, r2.w, l(9)\n                and r8.xyzw, r8.xyzw, l(64, 128, 256, 512)\n                iadd r0.y, r0.y, r8.x\n                iadd r0.y, r8.y, r0.y\n                iadd r0.y, r8.z, r0.y\n                iadd r0.y, r8.w, r0.y\n                ishr r0.z, r1.x, l(5)\n                ishr r0.w, r1.x, l(6)\n                ishr r2.z, r1.x, l(7)\n                ishr r2.w, r1.x, l(8)\n                ishl r8.x, r0.z, l(10)\n                ishl r8.y, r0.w, l(11)\n                ishl r8.z, r2.z, l(12)\n                ishl r8.w, r2.w, l(13)\n                and r8.xyzw, r8.xyzw, l(1024, 2048, 4096, 8192)\n                iadd r0.y, r0.y, r8.x\n                iadd r0.y, r8.y, r0.y\n                iadd r0.y, r8.z, r0.y\n                iadd r0.y, r8.w, r0.y\n                ishr r0.zw, r5.zzzy, l(4)\n                ishr r2.z, r5.y, l(1)\n                ishr r2.w, r5.y, l(2)\n                ishl r8.x, r0.z, l(14)\n                ishl r8.y, r0.w, l(24)\n                ishl r8.z, r2.z, l(10)\n                ishl r8.w, r2.w, l(11)\n                and r8.xyzw, r8.xyzw, l(0x00004000, 0x01000000, 1024, 2048)\n                iadd r0.y, r0.y, r8.x\n                iadd r0.y, r7.y, r0.y\n                ishr r0.z, r1.y, l(1)\n                ishr r0.w, r1.y, l(2)\n                ishr r2.z, r1.y, l(3)\n                ishr r2.w, r1.y, l(4)\n                ishl r9.x, r0.z, l(16)\n                ishl r9.y, r0.w, l(17)\n                ishl r9.z, r2.z, l(18)\n                ishl r9.w, r2.w, l(19)\n                and r9.xyzw, r9.xyzw, l(0x00010000, 0x00020000, 0x00040000, 0x00080000)\n                iadd r0.y, r0.y, r9.x\n                iadd r0.y, r9.y, r0.y\n                iadd r0.y, r9.z, r0.y\n                iadd r0.y, r9.w, r0.y\n                ishr r0.z, r1.y, l(5)\n                ishr r0.w, r1.y, l(6)\n                ishr r2.z, r1.y, l(7)\n                ishr r2.w, r1.y, l(8)\n                ishl r9.x, r0.z, l(20)\n                ishl r9.y, r0.w, l(21)\n                ishl r9.z, r2.z, l(22)\n                ishl r9.w, r2.w, l(23)\n                and r9.xyzw, r9.xyzw, l(0x00100000, 0x00200000, 0x00400000, 0x00800000)\n                iadd r0.y, r0.y, r9.x\n                iadd r0.y, r9.y, r0.y\n                iadd r0.y, r9.z, r0.y\n                iadd r0.y, r9.w, r0.y\n                iadd r0.y, r8.y, r0.y\n                iadd r0.y, r7.z, r0.y\n                ishr r0.z, r1.z, l(1)\n                ishr r0.w, r1.z, l(2)\n                ishr r2.z, r1.z, l(3)\n                ishr r2.w, r1.z, l(4)\n                ishl r9.x, r0.z, l(26)\n                ishl r9.y, r0.w, l(27)\n                ishl r9.z, r2.z, l(28)\n                ishl r9.w, r2.w, l(29)\n                and r9.xyzw, r9.xyzw, l(0x04000000, 0x08000000, 0x10000000, 0x20000000)\n                iadd r0.y, r0.y, r9.x\n                iadd r0.y, r9.y, r0.y\n                iadd r0.y, r9.z, r0.y\n                iadd r0.y, r9.w, r0.y\n                ishr r0.z, r1.z, l(5)\n                ishr r0.w, r1.z, l(6)\n                ishr r2.z, r1.z, l(7)\n                ishr r2.w, r1.z, l(8)\n                ishl r7.x, r0.z, l(30)\n                ishl r0.z, r0.w, l(31)\n                ishl r7.z, r2.w, l(1)\n                and r4.zw, r7.xxxz, l(0, 0, 0x40000000, 2)\n                iadd r0.y, r0.y, r4.z\n                iadd r3.x, r0.z, r0.y\n                and r0.y, r2.z, l(1)\n                iadd r0.y, r4.w, r0.y\n                ishr r0.zw, r6.yyyx, l(4)\n                ishr r2.z, r6.x, l(1)\n                ishr r2.w, r6.x, l(2)\n                ishl r9.x, r0.z, l(2)\n                ishl r9.y, r0.w, l(8)\n                ishl r9.z, r2.z, l(20)\n                ishl r9.w, r2.w, l(21)\n                and r9.xyzw, r9.xyzw, l(4, 256, 0x00100000, 0x00200000)\n                iadd r0.y, r0.y, r9.x\n                iadd r0.y, r7.w, r0.y\n                ishr r0.z, r1.w, l(1)\n                ishr r0.w, r1.w, l(2)\n                ishr r2.z, r1.w, l(3)\n                ishr r2.w, r1.w, l(4)\n                ishl r7.x, r0.z, l(4)\n                ishl r7.y, r0.w, l(5)\n                ishl r7.z, r2.z, l(6)\n                ishl r7.w, r2.w, l(7)\n                and r7.xyzw, r7.xyzw, l(16, 32, 64, 128)\n                iadd r0.y, r0.y, r7.x\n                iadd r0.y, r7.y, r0.y\n                iadd r0.y, r7.z, r0.y\n                iadd r0.y, r7.w, r0.y\n                iadd r0.y, r9.y, r0.y\n                ishl r7.x, r5.y, l(9)\n                ishl r7.y, r5.z, l(29)\n                ishl r7.z, r5.x, l(1)\n                ishl r7.w, r5.w, l(7)\n                and r7.xyzw, r7.xyzw, l(512, 0x20000000, 2, 128)\n                iadd r0.y, r0.y, r7.x\n                iadd r0.y, r8.z, r0.y\n                iadd r0.y, r8.w, r0.y\n                ishr r0.zw, r5.yyyz, l(3)\n                ishr r2.z, r5.z, l(1)\n                ishr r2.w, r5.z, l(2)\n                ishl r8.x, r0.z, l(12)\n                ishl r8.y, r2.z, l(30)\n                ishl r0.z, r2.w, l(31)\n                and r2.zw, r8.xxxy, l(0, 0, 4096, 0x40000000)\n                iadd r0.y, r0.y, r2.z\n                ishl r8.x, r4.x, l(13)\n                ishl r8.y, r4.y, l(23)\n                and r4.zw, r8.xxxy, l(0, 0, 8192, 0x00800000)\n                iadd r0.y, r0.y, r4.z\n                ishr r2.z, r4.x, l(1)\n                ishr r4.z, r4.x, l(2)\n                ishr r6.z, r4.x, l(3)\n                ishr r6.w, r4.x, l(4)\n                ishl r8.x, r2.z, l(14)\n                ishl r8.y, r4.z, l(15)\n                ishl r8.z, r6.z, l(16)\n                ishl r8.w, r6.w, l(17)\n                and r8.xyzw, r8.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n                iadd r0.y, r0.y, r8.x\n                iadd r0.y, r8.y, r0.y\n                iadd r0.y, r8.z, r0.y\n                iadd r0.y, r8.w, r0.y\n                ishl r8.x, r6.y, l(18)\n                ishl r8.y, r6.x, l(19)\n                and r6.zw, r8.xxxy, l(0, 0, 0x00040000, 0x00080000)\n                iadd r0.y, r0.y, r6.z\n                iadd r0.y, r6.w, r0.y\n                iadd r0.y, r9.z, r0.y\n                iadd r0.y, r9.w, r0.y\n                ishr r6.zw, r6.xxxy, l(3)\n                ishr r2.z, r6.y, l(1)\n                ishr r4.z, r6.y, l(2)\n                ishl r8.x, r6.z, l(22)\n                ishl r8.y, r2.z, l(28)\n                ishl r8.z, r4.z, l(6)\n                ishl r8.w, r6.w, l(12)\n                and r8.xyzw, r8.xyzw, l(0x00400000, 0x10000000, 64, 4096)\n                iadd r0.y, r0.y, r8.x\n                iadd r0.y, r4.w, r0.y\n                ishr r2.z, r4.y, l(1)\n                ishr r4.z, r4.y, l(2)\n                ishr r4.w, r4.y, l(3)\n                ishr r6.z, r4.y, l(4)\n                ishl r9.x, r2.z, l(24)\n                ishl r9.y, r4.z, l(25)\n                ishl r9.z, r4.w, l(26)\n                ishl r9.w, r6.z, l(27)\n                and r9.xyzw, r9.xyzw, l(0x01000000, 0x02000000, 0x04000000, 0x08000000)\n                iadd r0.y, r0.y, r9.x\n                iadd r0.y, r9.y, r0.y\n                iadd r0.y, r9.z, r0.y\n                iadd r0.y, r9.w, r0.y\n                iadd r0.y, r8.y, r0.y\n                iadd r0.y, r7.y, r0.y\n                iadd r0.y, r2.w, r0.y\n                iadd r3.z, r0.z, r0.y\n                and r0.y, r0.w, l(1)\n                iadd r0.y, r0.y, r3.w\n                iadd r0.y, r7.z, r0.y\n                ishr r0.z, r5.x, l(1)\n                ishr r0.w, r5.x, l(2)\n                ishr r2.z, r5.x, l(3)\n                ishr r2.w, r5.x, l(4)\n                ishl r9.x, r0.z, l(2)\n                ishl r9.y, r0.w, l(3)\n                ishl r9.z, r2.z, l(4)\n                ishl r9.w, r2.w, l(5)\n                and r9.xyzw, r9.xyzw, l(4, 8, 16, 32)\n                iadd r0.y, r0.y, r9.x\n                iadd r0.y, r9.y, r0.y\n                iadd r0.y, r9.z, r0.y\n                iadd r0.y, r9.w, r0.y\n                iadd r0.y, r8.z, r0.y\n                iadd r0.y, r7.w, r0.y\n                ishr r0.z, r5.w, l(1)\n                ishr r0.w, r5.w, l(2)\n                ishr r2.z, r5.w, l(3)\n                ishr r2.w, r5.w, l(4)\n                ishl r7.x, r0.z, l(8)\n                ishl r7.y, r0.w, l(9)\n                ishl r7.z, r2.z, l(10)\n                ishl r7.w, r2.w, l(11)\n                and r7.xyzw, r7.xyzw, l(256, 512, 1024, 2048)\n                iadd r0.y, r0.y, r7.x\n                iadd r0.y, r7.y, r0.y\n                iadd r0.y, r7.z, r0.y\n                iadd r0.y, r7.w, r0.y\n                iadd r0.y, r8.w, r0.y\n                ishl r0.z, r2.y, l(13)\n                and r0.z, r0.z, l(8192)\n                iadd r0.y, r0.z, r0.y\n                ushr r0.z, r2.y, l(1)\n                ushr r0.w, r2.y, l(2)\n                ushr r2.z, r2.y, l(3)\n                ushr r2.w, r2.y, l(4)\n                ishl r7.x, r0.z, l(14)\n                ishl r7.y, r0.w, l(15)\n                ishl r7.z, r2.z, l(16)\n                ishl r7.w, r2.w, l(17)\n                and r7.xyzw, r7.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n                iadd r0.y, r0.y, r7.x\n                iadd r0.y, r7.y, r0.y\n                iadd r0.y, r7.z, r0.y\n                iadd r3.w, r7.w, r0.y\n              else \n                ieq r0.y, r2.x, l(7)\n                if_nz r0.y\n                  ishl r7.x, r1.x, l(5)\n                  ishl r7.y, r1.y, l(15)\n                  ishl r7.z, r1.z, l(25)\n                  ishl r7.w, r1.w, l(3)\n                  and r7.xyzw, r7.xyzw, l(32, 0x00008000, 0x02000000, 8)\n                  iadd r0.y, r7.x, l(18)\n                  ishr r0.z, r1.x, l(1)\n                  ishr r0.w, r1.x, l(2)\n                  ishr r2.z, r1.x, l(3)\n                  ishr r2.w, r1.x, l(4)\n                  ishl r8.x, r0.z, l(6)\n                  ishl r8.y, r0.w, l(7)\n                  ishl r8.z, r2.z, l(8)\n                  ishl r8.w, r2.w, l(9)\n                  and r8.xyzw, r8.xyzw, l(64, 128, 256, 512)\n                  iadd r0.y, r0.y, r8.x\n                  iadd r0.y, r8.y, r0.y\n                  iadd r0.y, r8.z, r0.y\n                  iadd r0.y, r8.w, r0.y\n                  ishr r0.z, r1.x, l(5)\n                  ishr r0.w, r1.x, l(6)\n                  ishr r2.z, r1.x, l(7)\n                  ishr r2.w, r1.y, l(1)\n                  ishl r8.x, r0.z, l(10)\n                  ishl r8.y, r0.w, l(11)\n                  ishl r8.z, r2.z, l(12)\n                  ishl r8.w, r2.w, l(16)\n                  and r8.xyzw, r8.xyzw, l(1024, 2048, 4096, 0x00010000)\n                  iadd r0.y, r0.y, r8.x\n                  iadd r0.y, r8.y, r0.y\n                  iadd r0.y, r8.z, r0.y\n                  ishr r0.zw, r6.xxxy, l(4)\n                  ishr r2.z, r6.y, l(2)\n                  ishr r2.w, r6.y, l(3)\n                  ishl r9.x, r0.z, l(13)\n                  ishl r9.y, r2.z, l(23)\n                  ishl r9.z, r2.w, l(1)\n                  ishl r9.w, r0.w, l(2)\n                  and r9.xyzw, r9.xyzw, l(8192, 0x00800000, 2, 4)\n                  iadd r0.y, r0.y, r9.x\n                  ishr r0.zw, r5.zzzy, l(4)\n                  ishr r2.z, r5.y, l(1)\n                  ishr r2.w, r5.y, l(2)\n                  ishl r10.x, r0.z, l(14)\n                  ishl r10.y, r0.w, l(24)\n                  ishl r10.z, r2.z, l(10)\n                  ishl r10.w, r2.w, l(11)\n                  and r10.xyzw, r10.xyzw, l(0x00004000, 0x01000000, 1024, 2048)\n                  iadd r0.y, r0.y, r10.x\n                  iadd r0.y, r7.y, r0.y\n                  iadd r0.y, r8.w, r0.y\n                  ishr r0.z, r1.y, l(2)\n                  ishr r0.w, r1.y, l(3)\n                  ishr r2.z, r1.y, l(4)\n                  ishr r2.w, r1.y, l(5)\n                  ishl r8.x, r0.z, l(17)\n                  ishl r8.y, r0.w, l(18)\n                  ishl r8.z, r2.z, l(19)\n                  ishl r8.w, r2.w, l(20)\n                  and r8.xyzw, r8.xyzw, l(0x00020000, 0x00040000, 0x00080000, 0x00100000)\n                  iadd r0.y, r0.y, r8.x\n                  iadd r0.y, r8.y, r0.y\n                  iadd r0.y, r8.z, r0.y\n                  iadd r0.y, r8.w, r0.y\n                  ishr r0.z, r1.y, l(6)\n                  ishr r0.w, r1.y, l(7)\n                  ishr r2.z, r1.z, l(1)\n                  ishr r2.w, r1.z, l(2)\n                  ishl r8.x, r0.z, l(21)\n                  ishl r8.y, r0.w, l(22)\n                  ishl r8.z, r2.z, l(26)\n                  ishl r8.w, r2.w, l(27)\n                  and r8.xyzw, r8.xyzw, l(0x00200000, 0x00400000, 0x04000000, 0x08000000)\n                  iadd r0.y, r0.y, r8.x\n                  iadd r0.y, r8.y, r0.y\n                  iadd r0.y, r9.y, r0.y\n                  iadd r0.y, r10.y, r0.y\n                  iadd r0.y, r7.z, r0.y\n                  iadd r0.y, r8.z, r0.y\n                  iadd r0.y, r8.w, r0.y\n                  ishr r0.z, r1.z, l(3)\n                  ishr r0.w, r1.z, l(4)\n                  ishr r2.z, r1.z, l(5)\n                  ishr r2.w, r1.z, l(6)\n                  ishl r7.x, r0.z, l(28)\n                  ishl r7.y, r0.w, l(29)\n                  ishl r7.z, r2.z, l(30)\n                  ishl r0.z, r2.w, l(31)\n                  and r7.xyz, r7.xyzx, l(0x10000000, 0x20000000, 0x40000000, 0)\n                  iadd r0.y, r0.y, r7.x\n                  iadd r0.y, r7.y, r0.y\n                  iadd r0.y, r7.z, r0.y\n                  iadd r3.x, r0.z, r0.y\n                  ishr r0.y, r1.z, l(7)\n                  ishr r0.z, r1.w, l(1)\n                  ishr r0.w, r1.w, l(2)\n                  ishr r2.z, r1.w, l(3)\n                  and r0.y, r0.y, l(1)\n                  iadd r0.y, r9.z, r0.y\n                  iadd r0.y, r9.w, r0.y\n                  iadd r0.y, r7.w, r0.y\n                  ishl r7.x, r0.z, l(4)\n                  ishl r7.y, r0.w, l(5)\n                  ishl r7.z, r2.z, l(6)\n                  and r7.xyz, r7.xyzx, l(16, 32, 64, 0)\n                  iadd r0.y, r0.y, r7.x\n                  iadd r0.y, r7.y, r0.y\n                  iadd r0.y, r7.z, r0.y\n                  ishr r0.z, r1.w, l(4)\n                  ishr r0.w, r1.w, l(5)\n                  ishl r7.x, r0.z, l(7)\n                  ishl r7.y, r0.w, l(8)\n                  and r0.zw, r7.xxxy, l(0, 0, 128, 256)\n                  iadd r0.y, r0.z, r0.y\n                  iadd r0.y, r0.w, r0.y\n                  ishl r7.x, r5.y, l(9)\n                  ishl r7.y, r5.z, l(29)\n                  ishl r7.z, r5.x, l(1)\n                  ishl r7.w, r5.w, l(7)\n                  and r7.xyzw, r7.xyzw, l(512, 0x20000000, 2, 128)\n                  iadd r0.y, r0.y, r7.x\n                  iadd r0.y, r10.z, r0.y\n                  iadd r0.y, r10.w, r0.y\n                  ishr r0.zw, r5.yyyz, l(3)\n                  ishr r2.z, r5.z, l(1)\n                  ishr r2.w, r5.z, l(2)\n                  ishl r8.x, r0.z, l(12)\n                  ishl r8.y, r2.z, l(30)\n                  ishl r0.z, r2.w, l(31)\n                  and r2.zw, r8.xxxy, l(0, 0, 4096, 0x40000000)\n                  iadd r0.y, r0.y, r2.z\n                  ishl r8.x, r4.x, l(13)\n                  ishl r8.y, r4.y, l(23)\n                  and r4.zw, r8.xxxy, l(0, 0, 8192, 0x00800000)\n                  iadd r0.y, r0.y, r4.z\n                  ishr r2.z, r4.x, l(1)\n                  ishr r4.z, r4.x, l(2)\n                  ishr r6.z, r4.x, l(3)\n                  ishr r6.w, r4.x, l(4)\n                  ishl r8.x, r2.z, l(14)\n                  ishl r8.y, r4.z, l(15)\n                  ishl r8.z, r6.z, l(16)\n                  ishl r8.w, r6.w, l(17)\n                  and r8.xyzw, r8.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n                  iadd r0.y, r0.y, r8.x\n                  iadd r0.y, r8.y, r0.y\n                  iadd r0.y, r8.z, r0.y\n                  iadd r0.y, r8.w, r0.y\n                  ishl r8.x, r6.y, l(18)\n                  ishl r8.y, r6.x, l(19)\n                  and r6.zw, r8.xxxy, l(0, 0, 0x00040000, 0x00080000)\n                  iadd r0.y, r0.y, r6.z\n                  iadd r0.y, r6.w, r0.y\n                  ishr r6.zw, r6.xxxy, l(1)\n                  ishr r2.z, r6.x, l(2)\n                  ishr r4.z, r6.x, l(3)\n                  ishl r8.x, r6.z, l(20)\n                  ishl r8.y, r2.z, l(21)\n                  ishl r8.z, r4.z, l(22)\n                  ishl r8.w, r6.w, l(28)\n                  and r8.xyzw, r8.xyzw, l(0x00100000, 0x00200000, 0x00400000, 0x10000000)\n                  iadd r0.y, r0.y, r8.x\n                  iadd r0.y, r8.y, r0.y\n                  iadd r0.y, r8.z, r0.y\n                  iadd r0.y, r4.w, r0.y\n                  ishr r2.z, r4.y, l(1)\n                  ishr r4.z, r4.y, l(2)\n                  ishr r4.w, r4.y, l(3)\n                  ishr r6.z, r4.y, l(4)\n                  ishl r9.x, r2.z, l(24)\n                  ishl r9.y, r4.z, l(25)\n                  ishl r9.z, r4.w, l(26)\n                  ishl r9.w, r6.z, l(27)\n                  and r9.xyzw, r9.xyzw, l(0x01000000, 0x02000000, 0x04000000, 0x08000000)\n                  iadd r0.y, r0.y, r9.x\n                  iadd r0.y, r9.y, r0.y\n                  iadd r0.y, r9.z, r0.y\n                  iadd r0.y, r9.w, r0.y\n                  iadd r0.y, r8.w, r0.y\n                  iadd r0.y, r7.y, r0.y\n                  iadd r0.y, r2.w, r0.y\n                  iadd r3.z, r0.z, r0.y\n                  and r0.y, r0.w, l(1)\n                  iadd r0.y, r0.y, r3.w\n                  iadd r0.y, r7.z, r0.y\n                  ishr r0.z, r5.x, l(1)\n                  ishr r0.w, r5.x, l(2)\n                  ishr r2.z, r5.x, l(3)\n                  ishr r2.w, r5.x, l(4)\n                  ishl r8.x, r0.z, l(2)\n                  ishl r8.y, r0.w, l(3)\n                  ishl r8.z, r2.z, l(4)\n                  ishl r8.w, r2.w, l(5)\n                  and r8.xyzw, r8.xyzw, l(4, 8, 16, 32)\n                  iadd r0.y, r0.y, r8.x\n                  iadd r0.y, r8.y, r0.y\n                  iadd r0.y, r8.z, r0.y\n                  iadd r0.y, r8.w, r0.y\n                  ishr r0.z, r5.x, l(5)\n                  ishr r0.w, r5.w, l(1)\n                  ishr r2.z, r5.w, l(2)\n                  ishr r2.w, r5.w, l(3)\n                  ishl r8.x, r0.z, l(6)\n                  ishl r8.y, r0.w, l(8)\n                  ishl r8.z, r2.z, l(9)\n                  ishl r8.w, r2.w, l(10)\n                  and r8.xyzw, r8.xyzw, l(64, 256, 512, 1024)\n                  iadd r0.y, r0.y, r8.x\n                  iadd r0.y, r7.w, r0.y\n                  iadd r0.y, r8.y, r0.y\n                  iadd r0.y, r8.z, r0.y\n                  iadd r0.y, r8.w, r0.y\n                  ishr r0.z, r5.w, l(4)\n                  ishr r0.w, r5.w, l(5)\n                  ishl r7.x, r0.z, l(11)\n                  ishl r7.y, r0.w, l(12)\n                  and r0.zw, r7.xxxy, l(0, 0, 2048, 4096)\n                  iadd r0.y, r0.z, r0.y\n                  iadd r0.y, r0.w, r0.y\n                  ishl r0.z, r2.y, l(13)\n                  and r0.z, r0.z, l(8192)\n                  iadd r0.y, r0.z, r0.y\n                  ushr r0.z, r2.y, l(1)\n                  ushr r0.w, r2.y, l(2)\n                  ushr r2.z, r2.y, l(3)\n                  ushr r2.w, r2.y, l(4)\n                  ishl r7.x, r0.z, l(14)\n                  ishl r7.y, r0.w, l(15)\n                  ishl r7.z, r2.z, l(16)\n                  ishl r7.w, r2.w, l(17)\n                  and r7.xyzw, r7.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n                  iadd r0.y, r0.y, r7.x\n                  iadd r0.y, r7.y, r0.y\n                  iadd r0.y, r7.z, r0.y\n                  iadd r3.w, r7.w, r0.y\n                else \n                  ieq r0.y, r2.x, l(8)\n                  if_nz r0.y\n                    ishl r7.x, r1.x, l(5)\n                    ishl r7.y, r1.y, l(15)\n                    ishl r7.z, r1.z, l(25)\n                    ishl r7.w, r1.w, l(3)\n                    and r7.xyzw, r7.xyzw, l(32, 0x00008000, 0x02000000, 8)\n                    iadd r0.y, r7.x, l(22)\n                    ishr r0.z, r1.x, l(1)\n                    ishr r0.w, r1.x, l(2)\n                    ishr r2.z, r1.x, l(3)\n                    ishr r2.w, r1.x, l(4)\n                    ishl r8.x, r0.z, l(6)\n                    ishl r8.y, r0.w, l(7)\n                    ishl r8.z, r2.z, l(8)\n                    ishl r8.w, r2.w, l(9)\n                    and r8.xyzw, r8.xyzw, l(64, 128, 256, 512)\n                    iadd r0.y, r0.y, r8.x\n                    iadd r0.y, r8.y, r0.y\n                    iadd r0.y, r8.z, r0.y\n                    iadd r0.y, r8.w, r0.y\n                    ishr r0.z, r1.x, l(5)\n                    ishr r0.w, r1.x, l(6)\n                    ishr r2.z, r1.x, l(7)\n                    ishr r2.w, r1.y, l(1)\n                    ishl r8.x, r0.z, l(10)\n                    ishl r8.y, r0.w, l(11)\n                    ishl r8.z, r2.z, l(12)\n                    ishl r8.w, r2.w, l(16)\n                    and r8.xyzw, r8.xyzw, l(1024, 2048, 4096, 0x00010000)\n                    iadd r0.y, r0.y, r8.x\n                    iadd r0.y, r8.y, r0.y\n                    iadd r0.y, r8.z, r0.y\n                    ishl r8.x, r6.y, l(13)\n                    ishl r8.y, r6.x, l(19)\n                    and r0.zw, r8.xxxy, l(0, 0, 8192, 0x00080000)\n                    iadd r0.y, r0.z, r0.y\n                    ishr r2.zw, r5.zzzy, l(4)\n                    ishr r0.z, r5.y, l(5)\n                    ishr r4.z, r5.y, l(1)\n                    ishl r9.x, r2.z, l(14)\n                    ishl r9.y, r0.z, l(23)\n                    ishl r9.z, r2.w, l(24)\n                    ishl r9.w, r4.z, l(10)\n                    and r9.xyzw, r9.xyzw, l(0x00004000, 0x00800000, 0x01000000, 1024)\n                    iadd r0.y, r0.y, r9.x\n                    iadd r0.y, r7.y, r0.y\n                    iadd r0.y, r8.w, r0.y\n                    ishr r0.z, r1.y, l(2)\n                    ishr r2.z, r1.y, l(3)\n                    ishr r2.w, r1.y, l(4)\n                    ishr r4.z, r1.y, l(5)\n                    ishl r8.x, r0.z, l(17)\n                    ishl r8.y, r2.z, l(18)\n                    ishl r8.z, r2.w, l(19)\n                    ishl r8.w, r4.z, l(20)\n                    and r8.xyzw, r8.xyzw, l(0x00020000, 0x00040000, 0x00080000, 0x00100000)\n                    iadd r0.y, r0.y, r8.x\n                    iadd r0.y, r8.y, r0.y\n                    iadd r0.y, r8.z, r0.y\n                    iadd r0.y, r8.w, r0.y\n                    ishr r0.z, r1.y, l(6)\n                    ishr r2.z, r1.y, l(7)\n                    ishr r2.w, r1.z, l(1)\n                    ishr r4.z, r1.z, l(2)\n                    ishl r8.x, r0.z, l(21)\n                    ishl r8.y, r2.z, l(22)\n                    ishl r8.z, r2.w, l(26)\n                    ishl r8.w, r4.z, l(27)\n                    and r8.xyzw, r8.xyzw, l(0x00200000, 0x00400000, 0x04000000, 0x08000000)\n                    iadd r0.y, r0.y, r8.x\n                    iadd r0.y, r8.y, r0.y\n                    iadd r0.y, r9.y, r0.y\n                    iadd r0.y, r9.z, r0.y\n                    iadd r0.y, r7.z, r0.y\n                    iadd r0.y, r8.z, r0.y\n                    iadd r0.y, r8.w, r0.y\n                    ishr r0.z, r1.z, l(3)\n                    ishr r2.z, r1.z, l(4)\n                    ishr r2.w, r1.z, l(5)\n                    ishr r4.z, r1.z, l(6)\n                    ishl r7.x, r0.z, l(28)\n                    ishl r7.y, r2.z, l(29)\n                    ishl r7.z, r2.w, l(30)\n                    ishl r0.z, r4.z, l(31)\n                    and r7.xyz, r7.xyzx, l(0x10000000, 0x20000000, 0x40000000, 0)\n                    iadd r0.y, r0.y, r7.x\n                    iadd r0.y, r7.y, r0.y\n                    iadd r0.y, r7.z, r0.y\n                    iadd r3.x, r0.z, r0.y\n                    ishr r0.y, r1.z, l(7)\n                    ishr r0.z, r1.w, l(1)\n                    ishr r2.z, r1.w, l(2)\n                    ishr r2.w, r1.w, l(3)\n                    and r0.y, r0.y, l(1)\n                    ishr r4.z, r6.x, l(5)\n                    ishr r6.zw, r6.yyyx, l(4)\n                    ishr r4.w, r6.x, l(1)\n                    ishl r8.x, r4.z, l(1)\n                    ishl r8.y, r6.z, l(2)\n                    ishl r8.z, r6.w, l(8)\n                    ishl r8.w, r4.w, l(20)\n                    and r8.xyzw, r8.xyzw, l(2, 4, 256, 0x00100000)\n                    iadd r0.y, r0.y, r8.x\n                    iadd r0.y, r8.y, r0.y\n                    iadd r0.y, r7.w, r0.y\n                    ishl r7.x, r0.z, l(4)\n                    ishl r7.y, r2.z, l(5)\n                    ishl r7.z, r2.w, l(6)\n                    and r7.xyz, r7.xyzx, l(16, 32, 64, 0)\n                    iadd r0.y, r0.y, r7.x\n                    iadd r0.y, r7.y, r0.y\n                    iadd r0.y, r7.z, r0.y\n                    ishr r0.z, r1.w, l(4)\n                    ishl r0.z, r0.z, l(7)\n                    and r0.z, r0.z, l(128)\n                    iadd r0.y, r0.z, r0.y\n                    iadd r0.y, r8.z, r0.y\n                    ishl r7.x, r5.y, l(9)\n                    ishl r7.y, r5.z, l(29)\n                    ishl r7.z, r5.x, l(1)\n                    ishl r7.w, r5.w, l(7)\n                    and r7.xyzw, r7.xyzw, l(512, 0x20000000, 2, 128)\n                    iadd r0.y, r0.y, r7.x\n                    iadd r0.y, r9.w, r0.y\n                    ishr r2.zw, r5.yyyz, l(2)\n                    ishr r0.z, r5.y, l(3)\n                    ishr r4.z, r5.z, l(1)\n                    ishl r8.x, r2.z, l(11)\n                    ishl r8.y, r0.z, l(12)\n                    ishl r8.z, r4.z, l(30)\n                    ishl r0.z, r2.w, l(31)\n                    and r8.xyz, r8.xyzx, l(2048, 4096, 0x40000000, 0)\n                    iadd r0.y, r0.y, r8.x\n                    iadd r0.y, r8.y, r0.y\n                    ishl r8.x, r4.x, l(13)\n                    ishl r8.y, r4.y, l(23)\n                    and r2.zw, r8.xxxy, l(0, 0, 8192, 0x00800000)\n                    iadd r0.y, r0.y, r2.z\n                    ishr r2.z, r4.x, l(1)\n                    ishr r4.z, r4.x, l(2)\n                    ishr r4.w, r4.x, l(3)\n                    ishr r6.z, r4.x, l(4)\n                    ishl r9.x, r2.z, l(14)\n                    ishl r9.y, r4.z, l(15)\n                    ishl r9.z, r4.w, l(16)\n                    ishl r9.w, r6.z, l(17)\n                    and r9.xyzw, r9.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n                    iadd r0.y, r0.y, r9.x\n                    iadd r0.y, r9.y, r0.y\n                    iadd r0.y, r9.z, r0.y\n                    iadd r0.y, r9.w, r0.y\n                    ishr r2.z, r4.x, l(5)\n                    ishr r4.z, r4.y, l(1)\n                    ishr r4.w, r4.y, l(2)\n                    ishr r6.z, r4.y, l(3)\n                    ishl r9.x, r2.z, l(18)\n                    ishl r9.y, r4.z, l(24)\n                    ishl r9.z, r4.w, l(25)\n                    ishl r9.w, r6.z, l(26)\n                    and r9.xyzw, r9.xyzw, l(0x00040000, 0x01000000, 0x02000000, 0x04000000)\n                    iadd r0.y, r0.y, r9.x\n                    iadd r0.y, r0.w, r0.y\n                    iadd r0.y, r8.w, r0.y\n                    ishr r4.zw, r6.xxxy, l(2)\n                    ishr r0.w, r6.x, l(3)\n                    ishr r2.z, r6.y, l(1)\n                    ishl r10.x, r4.z, l(21)\n                    ishl r10.y, r0.w, l(22)\n                    ishl r10.z, r2.z, l(28)\n                    ishl r10.w, r4.w, l(6)\n                    and r10.xyzw, r10.xyzw, l(0x00200000, 0x00400000, 0x10000000, 64)\n                    iadd r0.y, r0.y, r10.x\n                    iadd r0.y, r10.y, r0.y\n                    iadd r0.y, r2.w, r0.y\n                    iadd r0.y, r9.y, r0.y\n                    iadd r0.y, r9.z, r0.y\n                    iadd r0.y, r9.w, r0.y\n                    ishr r0.w, r4.y, l(4)\n                    ishl r0.w, r0.w, l(27)\n                    and r0.w, r0.w, l(0x08000000)\n                    iadd r0.y, r0.w, r0.y\n                    iadd r0.y, r10.z, r0.y\n                    iadd r0.y, r7.y, r0.y\n                    iadd r0.y, r8.z, r0.y\n                    iadd r3.z, r0.z, r0.y\n                    ishr r0.yz, r5.zzxz, l(3)\n                    ishr r0.w, r5.x, l(1)\n                    ishr r2.z, r5.x, l(2)\n                    and r0.y, r0.y, l(1)\n                    iadd r0.y, r0.y, r3.w\n                    iadd r0.y, r7.z, r0.y\n                    ishl r7.x, r0.w, l(2)\n                    ishl r7.y, r2.z, l(3)\n                    ishl r7.z, r0.z, l(4)\n                    and r7.xyz, r7.xyzx, l(4, 8, 16, 0)\n                    iadd r0.y, r0.y, r7.x\n                    iadd r0.y, r7.y, r0.y\n                    iadd r0.y, r7.z, r0.y\n                    ishr r0.z, r5.x, l(4)\n                    ishr r0.w, r5.w, l(1)\n                    ishr r2.z, r5.w, l(2)\n                    ishr r2.w, r5.w, l(3)\n                    ishl r8.x, r0.z, l(5)\n                    ishl r8.y, r0.w, l(8)\n                    ishl r8.z, r2.z, l(9)\n                    ishl r8.w, r2.w, l(10)\n                    and r8.xyzw, r8.xyzw, l(32, 256, 512, 1024)\n                    iadd r0.y, r0.y, r8.x\n                    iadd r0.y, r10.w, r0.y\n                    iadd r0.y, r7.w, r0.y\n                    iadd r0.y, r8.y, r0.y\n                    iadd r0.y, r8.z, r0.y\n                    iadd r0.y, r8.w, r0.y\n                    ishr r0.z, r5.w, l(4)\n                    ishl r0.z, r0.z, l(11)\n                    and r0.z, r0.z, l(2048)\n                    iadd r0.y, r0.z, r0.y\n                    ishr r0.z, r6.y, l(3)\n                    ishl r0.z, r0.z, l(12)\n                    and r0.z, r0.z, l(4096)\n                    iadd r0.y, r0.z, r0.y\n                    ishl r0.z, r2.y, l(13)\n                    and r0.z, r0.z, l(8192)\n                    iadd r0.y, r0.z, r0.y\n                    ushr r0.z, r2.y, l(1)\n                    ushr r0.w, r2.y, l(2)\n                    ushr r2.z, r2.y, l(3)\n                    ushr r2.w, r2.y, l(4)\n                    ishl r7.x, r0.z, l(14)\n                    ishl r7.y, r0.w, l(15)\n                    ishl r7.z, r2.z, l(16)\n                    ishl r7.w, r2.w, l(17)\n                    and r7.xyzw, r7.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n                    iadd r0.y, r0.y, r7.x\n                    iadd r0.y, r7.y, r0.y\n                    iadd r0.y, r7.z, r0.y\n                    iadd r3.w, r7.w, r0.y\n                  else \n                    ieq r0.y, r2.x, l(9)\n                    if_nz r0.y\n                      ishl r7.x, r1.x, l(5)\n                      ishl r7.y, r1.y, l(15)\n                      ishl r7.z, r1.z, l(25)\n                      ishl r7.w, r1.w, l(3)\n                      and r7.xyzw, r7.xyzw, l(32, 0x00008000, 0x02000000, 8)\n                      iadd r0.y, r7.x, l(26)\n                      ishr r0.z, r1.x, l(1)\n                      ishr r0.w, r1.x, l(2)\n                      ishr r2.z, r1.x, l(3)\n                      ishr r2.w, r1.x, l(4)\n                      ishl r8.x, r0.z, l(6)\n                      ishl r8.y, r0.w, l(7)\n                      ishl r8.z, r2.z, l(8)\n                      ishl r8.w, r2.w, l(9)\n                      and r8.xyzw, r8.xyzw, l(64, 128, 256, 512)\n                      iadd r0.y, r0.y, r8.x\n                      iadd r0.y, r8.y, r0.y\n                      iadd r0.y, r8.z, r0.y\n                      iadd r0.y, r8.w, r0.y\n                      ishr r0.z, r1.x, l(5)\n                      ishr r0.w, r1.x, l(6)\n                      ishr r2.z, r1.x, l(7)\n                      ishr r2.w, r1.y, l(1)\n                      ishl r8.x, r0.z, l(10)\n                      ishl r8.y, r0.w, l(11)\n                      ishl r8.z, r2.z, l(12)\n                      ishl r8.w, r2.w, l(16)\n                      and r8.xyzw, r8.xyzw, l(1024, 2048, 4096, 0x00010000)\n                      iadd r0.y, r0.y, r8.x\n                      iadd r0.y, r8.y, r0.y\n                      iadd r0.y, r8.z, r0.y\n                      ishr r0.z, r6.y, l(1)\n                      ishr r0.w, r6.y, l(5)\n                      ishr r2.zw, r6.yyyx, l(4)\n                      ishl r9.x, r0.z, l(13)\n                      ishl r9.y, r0.w, l(1)\n                      ishl r9.z, r2.z, l(2)\n                      ishl r9.w, r2.w, l(8)\n                      and r9.xyzw, r9.xyzw, l(8192, 2, 4, 256)\n                      iadd r0.y, r0.y, r9.x\n                      ishr r0.zw, r5.zzzy, l(4)\n                      ishr r2.z, r5.z, l(5)\n                      ishr r2.w, r5.y, l(1)\n                      ishl r10.x, r0.z, l(14)\n                      ishl r10.y, r2.z, l(23)\n                      ishl r10.z, r0.w, l(24)\n                      ishl r10.w, r2.w, l(10)\n                      and r10.xyzw, r10.xyzw, l(0x00004000, 0x00800000, 0x01000000, 1024)\n                      iadd r0.y, r0.y, r10.x\n                      iadd r0.y, r7.y, r0.y\n                      iadd r0.y, r8.w, r0.y\n                      ishr r0.z, r1.y, l(2)\n                      ishr r0.w, r1.y, l(3)\n                      ishr r2.z, r1.y, l(4)\n                      ishr r2.w, r1.y, l(5)\n                      ishl r8.x, r0.z, l(17)\n                      ishl r8.y, r0.w, l(18)\n                      ishl r8.z, r2.z, l(19)\n                      ishl r8.w, r2.w, l(20)\n                      and r8.xyzw, r8.xyzw, l(0x00020000, 0x00040000, 0x00080000, 0x00100000)\n                      iadd r0.y, r0.y, r8.x\n                      iadd r0.y, r8.y, r0.y\n                      iadd r0.y, r8.z, r0.y\n                      iadd r0.y, r8.w, r0.y\n                      ishr r0.z, r1.y, l(6)\n                      ishr r0.w, r1.y, l(7)\n                      ishr r2.z, r1.z, l(1)\n                      ishr r2.w, r1.z, l(2)\n                      ishl r8.x, r0.z, l(21)\n                      ishl r8.y, r0.w, l(22)\n                      ishl r8.z, r2.z, l(26)\n                      ishl r8.w, r2.w, l(27)\n                      and r8.xyzw, r8.xyzw, l(0x00200000, 0x00400000, 0x04000000, 0x08000000)\n                      iadd r0.y, r0.y, r8.x\n                      iadd r0.y, r8.y, r0.y\n                      iadd r0.y, r10.y, r0.y\n                      iadd r0.y, r10.z, r0.y\n                      iadd r0.y, r7.z, r0.y\n                      iadd r0.y, r8.z, r0.y\n                      iadd r0.y, r8.w, r0.y\n                      ishr r0.z, r1.z, l(3)\n                      ishr r0.w, r1.z, l(4)\n                      ishr r2.z, r1.z, l(5)\n                      ishr r2.w, r1.z, l(6)\n                      ishl r7.x, r0.z, l(28)\n                      ishl r7.y, r0.w, l(29)\n                      ishl r7.z, r2.z, l(30)\n                      ishl r0.z, r2.w, l(31)\n                      and r7.xyz, r7.xyzx, l(0x10000000, 0x20000000, 0x40000000, 0)\n                      iadd r0.y, r0.y, r7.x\n                      iadd r0.y, r7.y, r0.y\n                      iadd r0.y, r7.z, r0.y\n                      iadd r3.x, r0.z, r0.y\n                      ishr r0.y, r1.z, l(7)\n                      ishr r0.z, r1.w, l(1)\n                      ishr r0.w, r1.w, l(2)\n                      ishr r2.z, r1.w, l(3)\n                      and r0.y, r0.y, l(1)\n                      iadd r0.y, r9.y, r0.y\n                      iadd r0.y, r9.z, r0.y\n                      iadd r0.y, r7.w, r0.y\n                      ishl r7.x, r0.z, l(4)\n                      ishl r7.y, r0.w, l(5)\n                      ishl r7.z, r2.z, l(6)\n                      and r7.xyz, r7.xyzx, l(16, 32, 64, 0)\n                      iadd r0.y, r0.y, r7.x\n                      iadd r0.y, r7.y, r0.y\n                      iadd r0.y, r7.z, r0.y\n                      ishr r0.z, r1.w, l(4)\n                      ishl r0.z, r0.z, l(7)\n                      and r0.z, r0.z, l(128)\n                      iadd r0.y, r0.z, r0.y\n                      iadd r0.y, r9.w, r0.y\n                      ishl r7.x, r5.y, l(9)\n                      ishl r7.y, r5.z, l(29)\n                      ishl r7.z, r5.x, l(1)\n                      ishl r7.w, r5.w, l(7)\n                      and r7.xyzw, r7.xyzw, l(512, 0x20000000, 2, 128)\n                      iadd r0.y, r0.y, r7.x\n                      iadd r0.y, r10.w, r0.y\n                      ishr r0.zw, r5.yyyz, l(2)\n                      ishr r2.z, r5.y, l(3)\n                      ishr r2.w, r5.z, l(1)\n                      ishl r8.x, r0.z, l(11)\n                      ishl r8.y, r2.z, l(12)\n                      ishl r8.z, r2.w, l(30)\n                      ishl r0.z, r0.w, l(31)\n                      and r8.xyz, r8.xyzx, l(2048, 4096, 0x40000000, 0)\n                      iadd r0.y, r0.y, r8.x\n                      iadd r0.y, r8.y, r0.y\n                      ishl r8.x, r4.x, l(13)\n                      ishl r8.y, r4.y, l(23)\n                      and r2.zw, r8.xxxy, l(0, 0, 8192, 0x00800000)\n                      iadd r0.y, r0.y, r2.z\n                      ishr r0.w, r4.x, l(1)\n                      ishr r2.z, r4.x, l(2)\n                      ishr r4.z, r4.x, l(3)\n                      ishr r4.w, r4.x, l(4)\n                      ishl r9.x, r0.w, l(14)\n                      ishl r9.y, r2.z, l(15)\n                      ishl r9.z, r4.z, l(16)\n                      ishl r9.w, r4.w, l(17)\n                      and r9.xyzw, r9.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n                      iadd r0.y, r0.y, r9.x\n                      iadd r0.y, r9.y, r0.y\n                      iadd r0.y, r9.z, r0.y\n                      iadd r0.y, r9.w, r0.y\n                      ishl r8.x, r6.y, l(18)\n                      ishl r8.y, r6.x, l(19)\n                      and r4.zw, r8.xxxy, l(0, 0, 0x00040000, 0x00080000)\n                      iadd r0.y, r0.y, r4.z\n                      iadd r0.y, r4.w, r0.y\n                      ishr r0.w, r6.x, l(1)\n                      ishr r4.zw, r6.xxxy, l(2)\n                      ishr r2.z, r6.x, l(3)\n                      ishl r9.x, r0.w, l(20)\n                      ishl r9.y, r4.z, l(21)\n                      ishl r9.z, r2.z, l(22)\n                      ishl r9.w, r4.w, l(6)\n                      and r9.xyzw, r9.xyzw, l(0x00100000, 0x00200000, 0x00400000, 64)\n                      iadd r0.y, r0.y, r9.x\n                      iadd r0.y, r9.y, r0.y\n                      iadd r0.y, r9.z, r0.y\n                      iadd r0.y, r2.w, r0.y\n                      ishr r0.w, r4.y, l(1)\n                      ishr r2.z, r4.y, l(2)\n                      ishr r2.w, r4.y, l(3)\n                      ishr r4.z, r4.y, l(4)\n                      ishl r10.x, r0.w, l(24)\n                      ishl r10.y, r2.z, l(25)\n                      ishl r10.z, r2.w, l(26)\n                      ishl r10.w, r4.z, l(27)\n                      and r10.xyzw, r10.xyzw, l(0x01000000, 0x02000000, 0x04000000, 0x08000000)\n                      iadd r0.y, r0.y, r10.x\n                      iadd r0.y, r10.y, r0.y\n                      iadd r0.y, r10.z, r0.y\n                      iadd r0.y, r10.w, r0.y\n                      ishr r0.w, r4.y, l(5)\n                      ishl r0.w, r0.w, l(28)\n                      and r0.w, r0.w, l(0x10000000)\n                      iadd r0.y, r0.w, r0.y\n                      iadd r0.y, r7.y, r0.y\n                      iadd r0.y, r8.z, r0.y\n                      iadd r3.z, r0.z, r0.y\n                      ishr r0.yz, r5.zzxz, l(3)\n                      ishr r0.w, r5.x, l(1)\n                      ishr r2.z, r5.x, l(2)\n                      and r0.y, r0.y, l(1)\n                      iadd r0.y, r0.y, r3.w\n                      iadd r0.y, r7.z, r0.y\n                      ishl r7.x, r0.w, l(2)\n                      ishl r7.y, r2.z, l(3)\n                      ishl r7.z, r0.z, l(4)\n                      and r7.xyz, r7.xyzx, l(4, 8, 16, 0)\n                      iadd r0.y, r0.y, r7.x\n                      iadd r0.y, r7.y, r0.y\n                      iadd r0.y, r7.z, r0.y\n                      ishr r0.z, r5.x, l(4)\n                      ishr r0.w, r5.w, l(1)\n                      ishr r2.z, r5.w, l(2)\n                      ishr r2.w, r5.w, l(3)\n                      ishl r8.x, r0.z, l(5)\n                      ishl r8.y, r0.w, l(8)\n                      ishl r8.z, r2.z, l(9)\n                      ishl r8.w, r2.w, l(10)\n                      and r8.xyzw, r8.xyzw, l(32, 256, 512, 1024)\n                      iadd r0.y, r0.y, r8.x\n                      iadd r0.y, r9.w, r0.y\n                      iadd r0.y, r7.w, r0.y\n                      iadd r0.y, r8.y, r0.y\n                      iadd r0.y, r8.z, r0.y\n                      iadd r0.y, r8.w, r0.y\n                      ishr r0.z, r5.w, l(4)\n                      ishl r0.z, r0.z, l(11)\n                      and r0.z, r0.z, l(2048)\n                      iadd r0.y, r0.z, r0.y\n                      ishr r0.z, r6.y, l(3)\n                      ishl r0.z, r0.z, l(12)\n                      and r0.z, r0.z, l(4096)\n                      iadd r0.y, r0.z, r0.y\n                      ishl r0.z, r2.y, l(13)\n                      and r0.z, r0.z, l(8192)\n                      iadd r0.y, r0.z, r0.y\n                      ushr r0.z, r2.y, l(1)\n                      ushr r0.w, r2.y, l(2)\n                      ushr r2.z, r2.y, l(3)\n                      ushr r2.w, r2.y, l(4)\n                      ishl r7.x, r0.z, l(14)\n                      ishl r7.y, r0.w, l(15)\n                      ishl r7.z, r2.z, l(16)\n                      ishl r7.w, r2.w, l(17)\n                      and r7.xyzw, r7.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n                      iadd r0.y, r0.y, r7.x\n                      iadd r0.y, r7.y, r0.y\n                      iadd r0.y, r7.z, r0.y\n                      iadd r3.w, r7.w, r0.y\n                    else \n                      ieq r0.y, r2.x, l(10)\n                      if_nz r0.y\n                        ishl r7.x, r1.x, l(5)\n                        ishl r7.y, r1.y, l(15)\n                        ishl r7.z, r1.z, l(25)\n                        ishl r7.w, r1.w, l(3)\n                        and r7.xyzw, r7.xyzw, l(32, 0x00008000, 0x02000000, 8)\n                        iadd r0.y, r7.x, l(30)\n                        ishr r0.z, r1.x, l(1)\n                        ishr r0.w, r1.x, l(2)\n                        ishr r2.x, r1.x, l(3)\n                        ishr r2.z, r1.x, l(4)\n                        ishl r8.x, r0.z, l(6)\n                        ishl r8.y, r0.w, l(7)\n                        ishl r8.z, r2.x, l(8)\n                        ishl r8.w, r2.z, l(9)\n                        and r8.xyzw, r8.xyzw, l(64, 128, 256, 512)\n                        iadd r0.y, r0.y, r8.x\n                        iadd r0.y, r8.y, r0.y\n                        iadd r0.y, r8.z, r0.y\n                        iadd r0.y, r8.w, r0.y\n                        ishr r0.z, r1.x, l(5)\n                        ishr r0.w, r1.y, l(1)\n                        ishr r1.x, r1.y, l(2)\n                        ishr r2.x, r1.y, l(3)\n                        ishl r8.x, r0.z, l(10)\n                        ishl r8.y, r0.w, l(16)\n                        ishl r8.z, r1.x, l(17)\n                        ishl r8.w, r2.x, l(18)\n                        and r8.xyzw, r8.xyzw, l(1024, 0x00010000, 0x00020000, 0x00040000)\n                        iadd r0.y, r0.y, r8.x\n                        ishr r0.z, r6.x, l(4)\n                        ishr r0.w, r6.y, l(1)\n                        ishr r1.x, r6.y, l(2)\n                        ishr r2.x, r6.x, l(5)\n                        ishl r9.x, r0.z, l(11)\n                        ishl r9.y, r0.w, l(13)\n                        ishl r9.z, r1.x, l(23)\n                        ishl r0.z, r2.x, l(31)\n                        and r2.xzw, r9.xxyz, l(2048, 0, 8192, 0x00800000)\n                        iadd r0.y, r0.y, r2.x\n                        ishl r9.x, r6.y, l(12)\n                        ishl r9.y, r6.x, l(19)\n                        and r4.zw, r9.xxxy, l(0, 0, 4096, 0x00080000)\n                        iadd r0.y, r0.y, r4.z\n                        iadd r0.y, r2.z, r0.y\n                        ishr r2.xz, r5.zzyz, l(4)\n                        ishr r6.zw, r5.yyyz, l(5)\n                        ishl r9.x, r2.x, l(14)\n                        ishl r9.y, r6.z, l(21)\n                        ishl r9.z, r6.w, l(22)\n                        ishl r9.w, r2.z, l(24)\n                        and r9.xyzw, r9.xyzw, l(0x00004000, 0x00200000, 0x00400000, 0x01000000)\n                        iadd r0.y, r0.y, r9.x\n                        iadd r0.y, r7.y, r0.y\n                        iadd r0.y, r8.y, r0.y\n                        iadd r0.y, r8.z, r0.y\n                        iadd r0.y, r8.w, r0.y\n                        ishr r0.w, r1.y, l(4)\n                        ishr r1.x, r1.y, l(5)\n                        ishr r1.y, r1.z, l(1)\n                        ishr r2.x, r1.z, l(2)\n                        ishl r8.x, r0.w, l(19)\n                        ishl r8.y, r1.x, l(20)\n                        ishl r8.z, r1.y, l(26)\n                        ishl r8.w, r2.x, l(27)\n                        and r8.xyzw, r8.xyzw, l(0x00080000, 0x00100000, 0x04000000, 0x08000000)\n                        iadd r0.y, r0.y, r8.x\n                        iadd r0.y, r8.y, r0.y\n                        iadd r0.y, r9.y, r0.y\n                        iadd r0.y, r9.z, r0.y\n                        iadd r0.y, r2.w, r0.y\n                        iadd r0.y, r9.w, r0.y\n                        iadd r0.y, r7.z, r0.y\n                        iadd r0.y, r8.z, r0.y\n                        iadd r0.y, r8.w, r0.y\n                        ishr r0.w, r1.z, l(3)\n                        ishr r1.x, r1.z, l(4)\n                        ishr r1.y, r1.z, l(5)\n                        ishr r1.z, r1.w, l(1)\n                        ishl r8.x, r0.w, l(28)\n                        ishl r8.y, r1.x, l(29)\n                        ishl r8.z, r1.y, l(30)\n                        ishl r8.w, r1.z, l(4)\n                        and r8.xyzw, r8.xyzw, l(0x10000000, 0x20000000, 0x40000000, 16)\n                        iadd r0.y, r0.y, r8.x\n                        iadd r0.y, r8.y, r0.y\n                        iadd r0.y, r8.z, r0.y\n                        iadd r3.x, r0.z, r0.y\n                        ishr r0.y, r6.y, l(3)\n                        ishr r0.z, r6.y, l(5)\n                        ishr r0.w, r6.y, l(4)\n                        ishr r1.x, r6.x, l(1)\n                        and r0.y, r0.y, l(1)\n                        ishl r7.x, r0.z, l(1)\n                        ishl r7.y, r0.w, l(2)\n                        ishl r7.z, r1.x, l(20)\n                        and r1.xyz, r7.xyzx, l(2, 4, 0x00100000, 0)\n                        iadd r0.y, r0.y, r1.x\n                        iadd r0.y, r1.y, r0.y\n                        iadd r0.y, r7.w, r0.y\n                        iadd r0.y, r8.w, r0.y\n                        ishr r0.z, r1.w, l(2)\n                        ishr r0.w, r1.w, l(3)\n                        ishr r1.x, r1.w, l(4)\n                        ishr r1.y, r1.w, l(5)\n                        ishl r7.x, r0.z, l(5)\n                        ishl r7.y, r0.w, l(6)\n                        ishl r7.z, r1.x, l(7)\n                        ishl r7.w, r1.y, l(8)\n                        and r7.xyzw, r7.xyzw, l(32, 64, 128, 256)\n                        iadd r0.y, r0.y, r7.x\n                        iadd r0.y, r7.y, r0.y\n                        iadd r0.y, r7.z, r0.y\n                        iadd r0.y, r7.w, r0.y\n                        ishl r7.x, r5.y, l(9)\n                        ishl r7.y, r5.z, l(29)\n                        ishl r7.z, r5.x, l(1)\n                        ishl r7.w, r5.w, l(7)\n                        and r7.xyzw, r7.xyzw, l(512, 0x20000000, 2, 128)\n                        iadd r0.y, r0.y, r7.x\n                        ishr r0.zw, r5.yyyz, l(1)\n                        ishr r1.x, r5.y, l(2)\n                        ishr r1.y, r5.y, l(3)\n                        ishl r8.x, r0.z, l(10)\n                        ishl r8.y, r1.x, l(11)\n                        ishl r8.z, r1.y, l(12)\n                        ishl r8.w, r0.w, l(30)\n                        and r8.xyzw, r8.xyzw, l(1024, 2048, 4096, 0x40000000)\n                        iadd r0.y, r0.y, r8.x\n                        iadd r0.y, r8.y, r0.y\n                        iadd r0.y, r8.z, r0.y\n                        ishl r1.x, r4.x, l(13)\n                        ishl r1.y, r4.y, l(23)\n                        and r0.zw, r1.xxxy, l(0, 0, 8192, 0x00800000)\n                        iadd r0.y, r0.z, r0.y\n                        ishr r0.z, r4.x, l(1)\n                        ishr r1.x, r4.x, l(2)\n                        ishr r1.y, r4.x, l(3)\n                        ishr r1.w, r4.x, l(4)\n                        ishl r9.x, r0.z, l(14)\n                        ishl r9.y, r1.x, l(15)\n                        ishl r9.z, r1.y, l(16)\n                        ishl r9.w, r1.w, l(17)\n                        and r9.xyzw, r9.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n                        iadd r0.y, r0.y, r9.x\n                        iadd r0.y, r9.y, r0.y\n                        iadd r0.y, r9.z, r0.y\n                        iadd r0.y, r9.w, r0.y\n                        ishr r0.z, r4.x, l(5)\n                        ishr r1.x, r4.y, l(1)\n                        ishr r1.y, r4.y, l(2)\n                        ishr r1.w, r4.y, l(3)\n                        ishl r9.x, r0.z, l(18)\n                        ishl r9.y, r1.x, l(24)\n                        ishl r9.z, r1.y, l(25)\n                        ishl r9.w, r1.w, l(26)\n                        and r9.xyzw, r9.xyzw, l(0x00040000, 0x01000000, 0x02000000, 0x04000000)\n                        iadd r0.y, r0.y, r9.x\n                        iadd r0.y, r4.w, r0.y\n                        iadd r0.y, r1.z, r0.y\n                        ishr r0.z, r6.x, l(2)\n                        ishr r1.x, r6.x, l(3)\n                        ishl r6.x, r0.z, l(21)\n                        ishl r6.y, r1.x, l(22)\n                        and r1.xy, r6.xyxx, l(0x00200000, 0x00400000, 0, 0)\n                        iadd r0.y, r0.y, r1.x\n                        iadd r0.y, r1.y, r0.y\n                        iadd r0.y, r0.w, r0.y\n                        iadd r0.y, r9.y, r0.y\n                        iadd r0.y, r9.z, r0.y\n                        iadd r0.y, r9.w, r0.y\n                        ishr r0.z, r4.y, l(4)\n                        ishr r0.w, r4.y, l(5)\n                        ishl r1.x, r0.z, l(27)\n                        ishl r1.y, r0.w, l(28)\n                        and r0.zw, r1.xxxy, l(0, 0, 0x08000000, 0x10000000)\n                        iadd r0.y, r0.z, r0.y\n                        iadd r0.y, r0.w, r0.y\n                        iadd r0.y, r7.y, r0.y\n                        iadd r0.y, r8.w, r0.y\n                        ishr r0.zw, r5.zzzx, l(2)\n                        ishr r1.x, r5.z, l(3)\n                        ishr r1.y, r5.x, l(1)\n                        ishl r4.x, r0.z, l(31)\n                        ishl r4.y, r1.y, l(2)\n                        ishl r4.z, r0.w, l(3)\n                        iadd r3.z, r0.y, r4.x\n                        and r0.y, r1.x, l(1)\n                        iadd r0.y, r0.y, r3.w\n                        iadd r0.y, r7.z, r0.y\n                        and r0.zw, r4.yyyz, l(0, 0, 4, 8)\n                        iadd r0.y, r0.z, r0.y\n                        iadd r0.y, r0.w, r0.y\n                        ishr r0.z, r5.x, l(3)\n                        ishr r0.w, r5.x, l(4)\n                        ishr r1.x, r5.x, l(5)\n                        ishr r1.y, r5.w, l(1)\n                        ishl r4.x, r0.z, l(4)\n                        ishl r4.y, r0.w, l(5)\n                        ishl r4.z, r1.x, l(6)\n                        ishl r4.w, r1.y, l(8)\n                        and r1.xyzw, r4.xyzw, l(16, 32, 64, 256)\n                        iadd r0.y, r0.y, r1.x\n                        iadd r0.y, r1.y, r0.y\n                        iadd r0.y, r1.z, r0.y\n                        iadd r0.y, r7.w, r0.y\n                        iadd r0.y, r1.w, r0.y\n                        ishr r0.z, r5.w, l(2)\n                        ishr r0.w, r5.w, l(3)\n                        ishr r1.x, r5.w, l(4)\n                        ishr r1.y, r5.w, l(5)\n                        ishl r4.x, r0.z, l(9)\n                        ishl r4.y, r0.w, l(10)\n                        ishl r4.z, r1.x, l(11)\n                        ishl r4.w, r1.y, l(12)\n                        and r1.xyzw, r4.xyzw, l(512, 1024, 2048, 4096)\n                        iadd r0.y, r0.y, r1.x\n                        iadd r0.y, r1.y, r0.y\n                        iadd r0.y, r1.z, r0.y\n                        iadd r0.y, r1.w, r0.y\n                        ishl r0.z, r2.y, l(13)\n                        and r0.z, r0.z, l(8192)\n                        iadd r0.y, r0.z, r0.y\n                        ushr r0.z, r2.y, l(1)\n                        ushr r0.w, r2.y, l(2)\n                        ushr r1.x, r2.y, l(3)\n                        ushr r1.y, r2.y, l(4)\n                        ishl r2.x, r0.z, l(14)\n                        ishl r2.y, r0.w, l(15)\n                        ishl r2.z, r1.x, l(16)\n                        ishl r2.w, r1.y, l(17)\n                        and r1.xyzw, r2.xyzw, l(0x00004000, 0x00008000, 0x00010000, 0x00020000)\n                        iadd r0.y, r0.y, r1.x\n                        iadd r0.y, r1.y, r0.y\n                        iadd r0.y, r1.z, r0.y\n                        iadd r3.w, r1.w, r0.y\n                      else \n                        mov r3.xz, l(0,0,0,0)\n                      endif \n                    endif \n                  endif \n                endif \n              endif \n            endif \n          endif \n        endif \n      endif \n    endif \n  endif \n  store_structured u0.xyzw, r0.x, l(0), r3.xzwy\nendif \nret \n// Approximately 0 instruction slots used\n#endif\n\nconst BYTE BC6HEncode_EncodeBlockCS[] =\n{\n     68,  88,  66,  67, 106, 242, \n     47,  44,  29, 251, 192, 175, \n    230,  64, 141,  23, 223, 196, \n     86,  63,   1,   0,   0,   0, \n     28, 173,   1,   0,   3,   0, \n      0,   0,  44,   0,   0,   0, \n     60,   0,   0,   0,  76,   0, \n      0,   0,  73,  83,  71,  78, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     79,  83,  71,  78,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  83,  72, \n     69,  88, 200, 172,   1,   0, \n     64,   0,   5,   0,  50, 107, \n      0,   0, 106,   8,   0,   1, \n     53,  24,   0,   0,  58,   1, \n      0,   0, 204, 204,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n    136, 136,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 238, 238, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 200, 236,   0,   0, \n     15,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n    128, 200,   0,   0,  15,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0, 236, 254, \n      0,   0,  15,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0, 200, 254,   0,   0, \n     15,   0,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n    128, 236,   0,   0,  15,   0, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   0,   0, 200, \n      0,   0,  15,   0,   0,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   0, 236, 255,   0,   0, \n     15,   0,   0,   0,   2,   0, \n      0,   0,   1,   0,   0,   0, \n    128, 254,   0,   0,  15,   0, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   0,   0, 232, \n      0,   0,  15,   0,   0,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   0, 232, 255,   0,   0, \n     15,   0,   0,   0,   3,   0, \n      0,   0,   1,   0,   0,   0, \n      0, 255,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n      1,   0,   0,   0, 240, 255, \n      0,   0,  15,   0,   0,   0, \n      3,   0,   0,   0,   2,   0, \n      0,   0,   0, 240,   0,   0, \n     15,   0,   0,   0,   3,   0, \n      0,   0,   2,   0,   0,   0, \n     16, 247,   0,   0,  15,   0, \n      0,   0,   4,   0,   0,   0, \n      2,   0,   0,   0, 142,   0, \n      0,   0,   2,   0,   0,   0, \n      4,   0,   0,   0,   2,   0, \n      0,   0,   0, 113,   0,   0, \n      8,   0,   0,   0,   4,   0, \n      0,   0,   2,   0,   0,   0, \n    206,   8,   0,   0,   2,   0, \n      0,   0,   4,   0,   0,   0, \n      2,   0,   0,   0, 140,   0, \n      0,   0,   2,   0,   0,   0, \n      5,   0,   0,   0,   2,   0, \n      0,   0,  16, 115,   0,   0, \n      8,   0,   0,   0,   5,   0, \n      0,   0,   2,   0,   0,   0, \n      0,  49,   0,   0,   8,   0, \n      0,   0,   5,   0,   0,   0, \n      2,   0,   0,   0, 206, 140, \n      0,   0,  15,   0,   0,   0, \n      5,   0,   0,   0,   3,   0, \n      0,   0, 140,   8,   0,   0, \n      2,   0,   0,   0,   6,   0, \n      0,   0,   3,   0,   0,   0, \n     16,  49,   0,   0,   8,   0, \n      0,   0,   6,   0,   0,   0, \n      3,   0,   0,   0, 102, 102, \n      0,   0,   2,   0,   0,   0, \n      6,   0,   0,   0,   3,   0, \n      0,   0, 108,  54,   0,   0, \n      2,   0,   0,   0,   6,   0, \n      0,   0,   3,   0,   0,   0, \n    232,  23,   0,   0,   8,   0, \n      0,   0,   6,   0,   0,   0, \n      3,   0,   0,   0, 240,  15, \n      0,   0,   8,   0,   0,   0, \n      7,   0,   0,   0,   3,   0, \n      0,   0, 142, 113,   0,   0, \n      2,   0,   0,   0,   7,   0, \n      0,   0,   3,   0,   0,   0, \n    156,  57,   0,   0,   2,   0, \n      0,   0,   7,   0,   0,   0, \n      3,   0,   0,   0, 255, 255, \n    255, 255,   0,   0,   0,   0, \n      7,   0,   0,   0,   3,   0, \n      0,   0, 255, 255, 255, 255, \n      0,   0,   0,   0,   8,   0, \n      0,   0,   4,   0,   0,   0, \n    255, 255, 255, 255,   0,   0, \n      0,   0,   8,   0,   0,   0, \n      4,   0,   0,   0, 255, 255, \n    255, 255,   0,   0,   0,   0, \n      8,   0,   0,   0,   4,   0, \n      0,   0, 255, 255, 255, 255, \n      0,   0,   0,   0,   8,   0, \n      0,   0,   4,   0,   0,   0, \n    255, 255, 255, 255,   0,   0, \n      0,   0,   9,   0,   0,   0, \n      4,   0,   0,   0, 255, 255, \n    255, 255,   0,   0,   0,   0, \n      9,   0,   0,   0,   4,   0, \n      0,   0, 255, 255, 255, 255, \n      0,   0,   0,   0,   9,   0, \n      0,   0,   4,   0,   0,   0, \n    255, 255, 255, 255,   0,   0, \n      0,   0,   9,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,   5,   0,   0,   0, \n    255, 255, 255, 255,   0,   0, \n      0,   0,  10,   0,   0,   0, \n      5,   0,   0,   0, 255, 255, \n    255, 255,   0,   0,   0,   0, \n     10,   0,   0,   0,   5,   0, \n      0,   0, 255, 255, 255, 255, \n      0,   0,   0,   0,  10,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  11,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     11,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  11,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  11,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     12,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  12,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  12,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     12,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  13,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  13,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     13,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  13,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  14,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     14,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  14,   0, \n      0,   0,   7,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  14,   0,   0,   0, \n      7,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,   7,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,   7,   0,   0,   0, \n     10,   0,   0,   0,   5,   0, \n      0,   0,   5,   0,   0,   0, \n      5,   0,   0,   0,   7,   0, \n      0,   0,   6,   0,   0,   0, \n      6,   0,   0,   0,   6,   0, \n      0,   0,  11,   0,   0,   0, \n      5,   0,   0,   0,   4,   0, \n      0,   0,   4,   0,   0,   0, \n     11,   0,   0,   0,   4,   0, \n      0,   0,   5,   0,   0,   0, \n      4,   0,   0,   0,  11,   0, \n      0,   0,   4,   0,   0,   0, \n      4,   0,   0,   0,   5,   0, \n      0,   0,   9,   0,   0,   0, \n      5,   0,   0,   0,   5,   0, \n      0,   0,   5,   0,   0,   0, \n      8,   0,   0,   0,   6,   0, \n      0,   0,   5,   0,   0,   0, \n      5,   0,   0,   0,   8,   0, \n      0,   0,   5,   0,   0,   0, \n      6,   0,   0,   0,   5,   0, \n      0,   0,   8,   0,   0,   0, \n      5,   0,   0,   0,   5,   0, \n      0,   0,   6,   0,   0,   0, \n      6,   0,   0,   0,   6,   0, \n      0,   0,   6,   0,   0,   0, \n      6,   0,   0,   0,  10,   0, \n      0,   0,  10,   0,   0,   0, \n     10,   0,   0,   0,  10,   0, \n      0,   0,  11,   0,   0,   0, \n      9,   0,   0,   0,   9,   0, \n      0,   0,   9,   0,   0,   0, \n     12,   0,   0,   0,   8,   0, \n      0,   0,   8,   0,   0,   0, \n      8,   0,   0,   0,  16,   0, \n      0,   0,   4,   0,   0,   0, \n      4,   0,   0,   0,   4,   0, \n      0,   0,  89,   0,   0,   4, \n     70, 142,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     88,  24,   0,   4,   0, 112, \n     16,   0,   0,   0,   0,   0, \n     85,  85,   0,   0, 162,   0, \n      0,   4,   0, 112,  16,   0, \n      1,   0,   0,   0,  16,   0, \n      0,   0, 158,   0,   0,   4, \n      0, 224,  17,   0,   0,   0, \n      0,   0,  16,   0,   0,   0, \n     95,   0,   0,   2,   0,  64, \n      2,   0,  95,   0,   0,   2, \n     18,  16,   2,   0, 104,   0, \n      0,   2,  18,   0,   0,   0, \n    160,   0,   0,   5,   0, 240, \n     17,   0,   0,   0,   0,   0, \n     84,   0,   0,   0,  64,   0, \n      0,   0, 155,   0,   0,   4, \n     64,   0,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n     85,   0,   0,   6,  18,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     41,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  16,   2,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   8,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10, 128,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  32,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16, 128,  65,   0, \n      0,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,  79,   0, \n      0,  10, 242,   0,  16,   0, \n      1,   0,   0,   0, 166,  10, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,  16,   0, \n      0,   0,  32,   0,   0,   0, \n      2,   0,   0,   0,   8,   0, \n      0,   0,  31,   0,   4,   3, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  78,   0,   0,   9, \n    130,   0,  16,   0,   0,   0, \n      0,   0,   0, 208,   0,   0, \n     10,   0,  16,   0,   0,   0, \n      0,   0,  26, 128,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  35,   0,   0,  11, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16, 128, \n     65,   0,   0,   0,   0,   0, \n      0,   0,  26, 128,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  85,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   8, 194,   0,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     45,   0,   0,   7, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   2,   0, \n      0,   0,  70, 126,  16,   0, \n      0,   0,   0,   0,  16,   0, \n      0,  10, 130,   0,  16,   0, \n      0,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n      2,  64,   0,   0, 208, 179, \n     89,  62,  89,  23,  55,  63, \n    152, 221, 147,  61,   0,   0, \n      0,   0, 168,   0,   0,   8, \n     18, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   4,   0,   0,   0, \n      6,   5,  16,   0,   2,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255, 255, 127, 255, 255, \n    127,   0, 255, 255, 255, 127, \n    255, 255, 127,   0,  79,   0, \n      0,  10,  50,   0,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0, 255, 239, 255,  71, \n    255, 239, 255,  71,   0,   0, \n      0,   0,   0,   0,   0,   0, \n    134,   0,  16,   0,   4,   0, \n      0,   0,  79,   0,   0,  10, \n     50,   0,  16,   0,   5,   0, \n      0,   0, 134,   0,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,   0,   0, 128,  56, \n      0,   0, 128,  56,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     85,   0,   0,   7, 194,   0, \n     16,   0,   5,   0,   0,   0, \n      6,   8,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,  30,   0, \n      0,  11, 194,   0,  16,   0, \n      5,   0,   0,   0, 166,  14, \n     16, 128,  65,   0,   0,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 113,   0, \n      0,   0, 113,   0,   0,   0, \n     30,   0,   0,  10, 162,   0, \n     16,   0,   4,   0,   0,   0, \n     86,  13,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n    128,   0,   0,   0,   0,   0, \n      0,   0, 128,   0,  85,   0, \n      0,   7,  18,   0,  16,   0, \n      6,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  85,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     30,   0,   0,  10,  50,   0, \n     16,   0,   4,   0,   0,   0, \n    134,   0,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0, 200,   0,   0, \n      0, 200,   0,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,   9,  50,   0,  16,   0, \n      4,   0,   0,   0,  70,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   0,  16,   0,   6,   0, \n      0,   0,  70,   0,  16,   0, \n      4,   0,   0,   0,  30,   0, \n      0,  10, 194,   0,  16,   0, \n      4,   0,   0,   0,   6,   4, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n    255,  15,   0,   0, 255,  15, \n      0,   0,  85,   0,   0,   7, \n     50,   0,  16,   0,   4,   0, \n      0,   0,  70,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n      1,   0,   0,  10,  50,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   0,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  50,   0,  16,   0, \n      4,   0,   0,   0,  70,   0, \n     16,   0,   4,   0,   0,   0, \n    230,  10,  16,   0,   4,   0, \n      0,   0,  85,   0,   0,   7, \n     50,   0,  16,   0,   4,   0, \n      0,   0,  70,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n      1,   0,   0,  10,  50,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   0,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,  12,  50,   0,  16,   0, \n      2,   0,   0,   0,  70,   0, \n     16,   0,   2,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  70,   0,  16,   0, \n      4,   0,   0,   0,  30,   0, \n      0,   7,  50,   0,  16,   0, \n      4,   0,   0,   0,  70,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   0,  16,   0,   2,   0, \n      0,   0,   1,   0,   0,  10, \n     50,   0,  16,   0,   2,   0, \n      0,   0, 166,  10,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0, 255, 255, 255, 127, \n    255, 255, 127,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     79,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0, 255, 239, \n    255,  71,  10,   0,  16,   0, \n      2,   0,   0,   0,  79,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n    128,  56,  85,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n     30,   0,   0,   8, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16, 128,  65,   0, \n      0,   0,   2,   0,   0,   0, \n      1,  64,   0,   0, 113,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0, 128,   0, \n     85,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0, 200,  55,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0, 255,  15,   0,   0, \n     85,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,   1,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     85,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,   1,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0, 255, 127, \n      0,   0,  55,   0,   0,   9, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0, 255, 127,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     32,   0,   0,   8, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42, 128,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  95,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     78,   0,   0,  11, 114,   0, \n     16,   0,   2,   0,   0,   0, \n      0, 208,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n      2,  64,   0,   0,  31,   0, \n      0,   0,  31,   0,   0,   0, \n     31,   0,   0,   0,   0,   0, \n      0,   0,  79,   0,   0,  10, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     32,   0,   0,  10, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 123,   0,   0, 255, 123, \n      0,   0, 255, 123,   0,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  78,   0,   0,  11, \n    114,   0,  16,   0,   6,   0, \n      0,   0,   0, 208,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n     31,   0,   0,   0,  31,   0, \n      0,   0,  31,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,  12, 114,   0,  16,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0, 224, 255, \n     15,   0, 224, 255,  15,   0, \n    224, 255,  15,   0,   0,   0, \n      0,   0,  78,   0,   0,  11, \n    114,   0,  16,   0,   4,   0, \n      0,   0,   0, 208,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n     31,   0,   0,   0,  31,   0, \n      0,   0,  31,   0,   0,   0, \n      0,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      1, 128, 255, 255,   1, 128, \n    255, 255,   1, 128, 255, 255, \n      0,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   2,   0,   0,   0, \n    246,  15,  16,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n    168,   0,   0,   8, 114, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1, 167,   0, \n      0,   9,  50,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  70, 112,  16,   0, \n      1,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9, 130,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     31,   0,   4,   3,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     79,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5, 242,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   5, 242,   0, \n     16,   0,   5,   0,   0,   0, \n    150,  15,  16,   0,   3,   0, \n      0,   0,  18,   0,   0,   1, \n     85,   0,   0,   8,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     10, 144, 144,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     55,   0,   0,  12, 242,   0, \n     16,   0,   4,   0,   0,   0, \n     86,   5,  16,   0,   1,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255, 255, 127, 255, 255, \n    255, 127, 255, 255, 255, 127, \n      0,   0,   0, 128,  70,   2, \n     16,   0,   3,   0,   0,   0, \n     55,   0,   0,  12, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     86,   5,  16,   0,   1,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0, 128,   0,   0, \n      0, 128, 255, 255, 127, 127, \n    255, 255, 127, 255, 150,  15, \n     16,   0,   3,   0,   0,   0, \n     21,   0,   0,   1,  18,   0, \n      0,   1,  80,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     85,   0,   0,   8, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10, 144, 144,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     32,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  55,   0, \n      0,  12, 242,   0,  16,   0, \n      4,   0,   0,   0, 246,  15, \n     16,   0,   0,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255, 255, 127, 255, 255, \n    255, 127, 255, 255, 255, 127, \n      0,   0,   0, 128,  55,   0, \n      0,  12, 242,   0,  16,   0, \n      5,   0,   0,   0, 246,  15, \n     16,   0,   0,   0,   0,   0, \n    150,  15,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0, 128,   0,   0, \n      0, 128, 255, 255, 127, 127, \n    255, 255, 127, 255,  18,   0, \n      0,   1,  54,   0,   0,   8, \n    242,   0,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255, 255, 127, 255, 255, \n    255, 127, 255, 255, 255, 127, \n      0,   0,   0, 128,  54,   0, \n      0,   8, 242,   0,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0, 128, \n      0,   0,   0, 128, 255, 255, \n    127, 127, 255, 255, 127, 255, \n     21,   0,   0,   1,  21,   0, \n      0,   1, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      4,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     68,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n     21,   0,   0,   1, 190,  24, \n      0,   1,   1,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     79,   0,   0,  10, 242,   0, \n     16,   0,   3,   0,   0,   0, \n    246,  15,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      8,   0,   0,   0,   4,   0, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   0,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      3,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      4,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     76,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     76,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     49,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8, 114, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  76,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  21,   0,   0,   1, \n    167,   0,   0,   8,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  80,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  80,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  49,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     64,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n    168,   0,   0,   8, 114, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  64,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0, 168,   0,   0,   8, \n     18, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  80,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      3,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      4,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     76,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     76,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     49,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8, 114, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  76,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  21,   0,   0,   1, \n    167,   0,   0,   8,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  80,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  80,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  49,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     64,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n    168,   0,   0,   8, 114, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  64,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0, 168,   0,   0,   8, \n     18, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  80,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      3,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      4,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     76,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     76,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     49,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8, 114, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  76,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  21,   0,   0,   1, \n    167,   0,   0,   8,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  80,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  80,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  49,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     64,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n    168,   0,   0,   8, 114, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  64,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0, 168,   0,   0,   8, \n     18, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  80,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  58,   0,  16,   0, \n      3,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      3,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     76,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     76,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     49,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8, 114, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n     21,   0,   0,   1, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      3,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     80,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     80,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     49,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  64,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8, 114, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     64,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n     21,   0,   0,   1,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   1,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  64,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  32,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     80,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,  31,   0,   4,   3, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26, 144, 144,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  18,   0,   0,   1, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  21,   0,   0,   1, \n     30,   0,   0,   8, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16, 128,  65,   0, \n      0,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,  43,   0,   0,   5, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,  16,   0, \n      0,   7,  34,   0,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   8, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16, 128,  65,   0, \n      0,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,  43,   0,   0,   5, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  16,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,  49,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     29,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  56,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0, 253, 255, 125,  66, \n     14,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  28,   0, \n      0,   5, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     79,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n     55,   0,   0,   9, 242,   0, \n     16,   0,   5,   0,   0,   0, \n    246,  15,  16,   0,   0,   0, \n      0,   0,  70,  14,  16,   0, \n      4,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     55,   0,   0,   9, 194,   0, \n     16,   0,   2,   0,   0,   0, \n    246,  15,  16,   0,   0,   0, \n      0,   0,  86,   9,  16,   0, \n      3,   0,   0,   0,  86,   9, \n     16,   0,   4,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0, 168,   0,   0,   8, \n     50, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  68,   0, \n      0,   0, 230,  10,  16,   0, \n      2,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     79,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  31,   0, \n      4,   3,  58,   0,  16,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   5,  18,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     18,   0,   0,   1,  54,   0, \n      0,   6,  18,   0,  16,   0, \n      1,   0,   0,   0,  10, 144, \n    144,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  21,   0, \n      0,   1,  85,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  64,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   8, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16, 128,  65,   0,   0,   0, \n      4,   0,   0,   0,  43,   0, \n      0,   5, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n    167,   0,   0,   8, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   8, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  70,   2,  16, 128, \n     65,   0,   0,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,  43,   0, \n      0,   5, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     16,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,  18,   0, \n      0,   1, 167,   0,   0,   9, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  64,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   8, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16, 128,  65,   0,   0,   0, \n      5,   0,   0,   0,  43,   0, \n      0,   5, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n    167,   0,   0,   8, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   8, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  70,   2,  16, 128, \n     65,   0,   0,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,  43,   0, \n      0,   5, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     16,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,  21,   0, \n      0,   1,  16,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     29,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  29,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  60,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     49,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  56,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0, 253, 255, \n    125,  66,  14,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     28,   0,   0,   5, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  55,   0,   0,  10, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  42, 144, \n    144,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     55,   0,   0,   9, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  79,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0, 224, 255, \n    255, 255,  41,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     54,   0,   0,   8,  98,   0, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  55,   0,   0,   9, \n    194,   0,  16,   0,   2,   0, \n      0,   0, 166,  10,  16,   0, \n      2,   0,   0,   0,   6,   4, \n     16,   0,   4,   0,   0,   0, \n    166,  14,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   5, \n     34,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,   9,  50,   0,  16,   0, \n      3,   0,   0,   0, 166,  10, \n     16,   0,   0,   0,   0,   0, \n    230,  10,  16,   0,   2,   0, \n      0,   0,  70,   0,  16,   0, \n      3,   0,   0,   0,  18,   0, \n      0,   1,  29,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     29,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  60,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  49,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     56,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    253, 255, 125,  66,  14,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,  28,   0,   0,   5, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  55,   0, \n      0,  10,  18,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     58, 144, 144,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  55,   0,   0,   9, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  31,   0,   0,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  18,   0,   0,   0, \n     54,   0,   0,   5,  34,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  18,   0,   0,   1, \n     79,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      1,   0,   0,   0,  35,   0, \n      0,   9,  18,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  54,   0,   0,   5, \n     34,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  18,   0, \n      0,   1,  39,   0,   0,   8, \n     18,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  26, 144, \n    144,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  32,   0, \n      0,   8,  34,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     26, 144, 144,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   2,   0,   0,   0, \n      6,   4,  16,   0,   1,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,  79,   0, \n      0,   7,  34,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   1,   0, \n      0,   0,  35,   0,   0,   9, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     18,   0,   0,   1,  32,   0, \n      0,   7,  34,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  55,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   7, \n     34,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,  55,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,  79,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  35,   0,   0,  12, \n    194,   0,  16,   0,   2,   0, \n      0,   0, 166,  10,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   3,   0,   0,   0, \n    166,  14,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,  10, \n    194,   0,  16,   0,   2,   0, \n      0,   0, 166,  14,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 240, 255, \n    255, 255, 240, 255, 255, 255, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  55,   0,   0,   9, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  54,   0,   0,   5, \n     18,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,   9,  50,   0,  16,   0, \n      3,   0,   0,   0,  86,   5, \n     16,   0,   1,   0,   0,   0, \n     70,   0,  16,   0,   4,   0, \n      0,   0,  70,   0,  16,   0, \n      5,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     21,   0,   0,   1,  21,   0, \n      0,   1, 168,   0,   0,   8, \n     50, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  70,   0,  16,   0, \n      3,   0,   0,   0,  18,   0, \n      0,   1,  54,   0,   0,   8, \n     50,   0,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   8,  50,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     50,   0,  16,   0,   1,   0, \n      0,   0,  70,   0,  16,   0, \n      4,   0,   0,   0,  70,   0, \n     16,   0,   5,   0,   0,   0, \n    168,   0,   0,   8,  50, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     70,   0,  16,   0,   1,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  79,   0, \n      0,  10,  50,   0,  16,   0, \n      1,   0,   0,   0, 166,  10, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   4,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  31,   0,   4,   3, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   8, \n     50,   0,  16,   0,   4,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      4,   0,   0,   0, 167,   0, \n      0,   9,  50,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7, 146,   0,  16,   0, \n      1,   0,   0,   0,   6,   4, \n     16,   0,   4,   0,   0,   0, \n      6,   4,  16,   0,   5,   0, \n      0,   0, 168,   0,   0,   8, \n     50, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0, 198,   0,  16,   0, \n      1,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   8,  50,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n    146,   0,  16,   0,   1,   0, \n      0,   0,   6,   4,  16,   0, \n      4,   0,   0,   0,   6,   4, \n     16,   0,   5,   0,   0,   0, \n    168,   0,   0,   8,  50, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n    198,   0,  16,   0,   1,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   8,  50,   0,  16,   0, \n      4,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  50,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   0,  16,   0,   4,   0, \n      0,   0,  70,   0,  16,   0, \n      5,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  32,   0, \n      0,  10,  50,   0,  16,   0, \n      1,   0,   0,   0, 166,  10, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   2,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  31,   0,   4,   3, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  64,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  32,   0,   0,   8, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  42, 128,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     95,   0,   0,   0,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      1,   0,   0,   0,  33,   0, \n      0,   9,  18,   0,  16,   0, \n      1,   0,   0,   0,  10, 144, \n    208,   0,  64,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,   1,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  55,   0,   0,  15, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  55,   0,   0,  15, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,   6,   0, \n      0,   0,   6,   0,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,   7,   0,   0,   0, \n      6,   0,  16,   0,   1,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  32,   0, \n      0,  10, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n      0,   0, 255, 255,   0,   0, \n    255, 255,   0,   0,   0,   0, \n      0,   0,  32,   0,   0,  10, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0, 255, 255,   0,   0, \n    255, 255,   0,   0, 255, 255, \n      0,   0,   0,   0,   0,   0, \n     41,   0,   0,   9,  18,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  10, 144, 208,   0, \n     64,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  41,   0, \n      0,   9, 114,   0,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     10, 144, 208,   0,  64,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   9, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     10, 144, 208,   0,  64,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,  10,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,   6,   0,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,  10,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,   6,   0,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     18,   0,   0,   1,  33,   0, \n      0,   9,  18,   0,  16,   0, \n      1,   0,   0,   0,  10, 144, \n    208,   0,  64,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  55,   0,   0,  15, \n    114,   0,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  55,   0,   0,  15, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,   8,   0, \n      0,   0,   6,   0,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,   9,   0,   0,   0, \n      6,   0,  16,   0,   1,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  33,   0, \n      0,  10, 114,   0,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  33,   0,   0,  10, \n    114,   0,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     32,   0,   0,  10, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,  32,   0, \n      0,  10, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   9, \n     18,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  10, 144, \n    208,   0,  64,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,   0,   7, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0, 166,  10, \n     16,   0,   2,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,  13,   0, \n      0,   0,  70,   2,  16,   0, \n     13,   0,   0,   0, 166,  10, \n     16,   0,   2,   0,   0,   0, \n     70,   2,  16,   0,  15,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     32,   0,   0,  10, 114,   0, \n     16,   0,  16,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,  32,   0, \n      0,  10, 114,   0,  16,   0, \n     17,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   8, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16, 128, \n     65,   0,   0,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,   0,   7, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,  16,   0, \n      0,   0, 246,  15,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,  17,   0, \n      0,   0, 246,  15,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  10,   0,   0,   0, \n     70,   2,  16,   0,  10,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,  10,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     21,   0,   0,   1,  30,   0, \n      0,   8, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16, 128,  65,   0,   0,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n     55,   0,   0,  11, 114,   0, \n     16,   0,   4,   0,   0,   0, \n      6, 144, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n    168,   0,   0,   8,  50, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n    150,   5,  16,   0,   4,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      1,   0,   0,   0,  30,   0, \n      0,  10,  50,   0,  16,   0, \n      1,   0,   0,   0,  86,   5, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   2,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  64,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  80,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     31,   0,   4,   3,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     32,   0,   0,   8,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     42, 128,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  95,   0, \n      0,   0,  31,   0,   4,   3, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  33,   0,   0,   9, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10, 144, 208,   0, \n     64,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,   1,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     55,   0,   0,  15, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,  15, 114,   0, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,   7,   0,   0,   0, \n      6,   0,  16,   0,   1,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  60,   0, \n      0,   7, 178,   0,  16,   0, \n      1,   0,   0,   0,   6,   0, \n     16,   0,   1,   0,   0,   0, \n     70,   8,  16,   0,   8,   0, \n      0,   0,  32,   0,   0,  10, \n    114,   0,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0, 255, 255,   0,   0, \n    255, 255,   0,   0, 255, 255, \n      0,   0,   0,   0,   0,   0, \n     32,   0,   0,  10, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255,   0,   0, 255, 255, \n      0,   0, 255, 255,   0,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   9,  66,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     10, 144, 208,   0,  64,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0, 255, 255, \n    255, 255,  41,   0,   0,   9, \n    114,   0,  16,   0,  10,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,  10, 144, \n    208,   0,  64,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   9, \n    114,   0,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  10, 144, \n    208,   0,  64,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,  10,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     42,   0,   0,   7, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n    166,  10,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n    166,  10,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,  55,   0, \n      0,   9, 178,   0,  16,   0, \n      1,   0,   0,   0,  70,  12, \n     16,   0,   1,   0,   0,   0, \n     70,   8,  16,   0,   6,   0, \n      0,   0,  70,   8,  16,   0, \n      9,   0,   0,   0,  18,   0, \n      0,   1,  33,   0,   0,   9, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10, 144, 208,   0, \n     64,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     55,   0,   0,  15, 114,   0, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,  15, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,   8,   0,   0,   0, \n    166,  10,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n      9,   0,   0,   0, 166,  10, \n     16,   0,   2,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  33,   0,   0,  10, \n    114,   0,  16,   0,  10,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     33,   0,   0,  10, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  32,   0, \n      0,  10, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0,   0,   0, \n      0,   0,  32,   0,   0,  10, \n    114,   0,  16,   0,  13,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   9,  66,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0, 255, 255, \n    255, 255,  10, 144, 208,   0, \n     64,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0, 255, 255, \n    255, 255,  41,   0,   0,   7, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0, 246,  15,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0, 246,  15,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     40,   0,   0,   5, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  32,   0, \n      0,  10, 114,   0,  16,   0, \n     16,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0,   0,   0, \n      0,   0,  32,   0,   0,  10, \n    114,   0,  16,   0,  17,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,   2,  64, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   8, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16, 128,  65,   0, \n      0,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,  15,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     40,   0,   0,   5, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  16,   0,   0,   0, \n    246,  15,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  17,   0,   0,   0, \n    246,  15,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,  10,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,  55,   0, \n      0,   9, 178,   0,  16,   0, \n      1,   0,   0,   0,  70,   8, \n     16,   0,   9,   0,   0,   0, \n     70,   8,  16,   0,   6,   0, \n      0,   0,  70,   8,  16,   0, \n     11,   0,   0,   0,  21,   0, \n      0,   1,  30,   0,   0,   8, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  70,   2,  16, 128, \n     65,   0,   0,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   8, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16, 128,  65,   0,   0,   0, \n      4,   0,   0,   0,  70,   3, \n     16,   0,   1,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   5,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  55,   0, \n      0,  11, 242,   0,  16,   0, \n      5,   0,   0,   0,   6, 144, \n    208,   0,  32,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n     55,   0,   0,  11,  50,   0, \n     16,   0,   1,   0,   0,   0, \n      6, 144, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0, 150,   5, \n     16,   0,   4,   0,   0,   0, \n    214,   5,  16,   0,   1,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0, 168,   0, \n      0,   8,  50, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     68,   0,   0,   0,  70,   0, \n     16,   0,   1,   0,   0,   0, \n     21,   0,   0,   1,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   6,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     64,   0,   0,   0, 150, 240, \n     17,   0,   0,   0,   0,   0, \n     31,   0,   0,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     79,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  31,   0, \n      4,   3,  58,   0,  16,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   9,  18,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     10, 144, 208,   0,  64,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   9,  34,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     26, 144, 208,   0,  64,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   9,  66,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42, 144, 208,   0,  64,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   9, 130,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     58, 144, 208,   0,  64,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  33,   0, \n      0,  10, 114,   0,  16,   0, \n      6,   0,   0,   0,  38,   9, \n     16,   0,   1,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,  12, \n    114,   0,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n      0,   0,   0,   0, 150, 151, \n    208,   0,  64,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  33,   0,   0,   7, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  38,   9,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,  10, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n      0,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  38,   9,  16,   0, \n      1,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n      9,   0,   0,   0,  38,   9, \n     16,   0,   1,   0,   0,   0, \n     34,   0,   0,   7, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  30,   0, \n      0,  10, 242,   0,  16,   0, \n      5,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255,   1,   0,   0,   7, \n    226,   0,  16,   0,   5,   0, \n      0,   0, 166,   4,  16,   0, \n      1,   0,   0,   0,  86,  14, \n     16,   0,   5,   0,   0,   0, \n     55,   0,   0,   9, 226,   0, \n     16,   0,   5,   0,   0,   0, \n      6,   9,  16,   0,   9,   0, \n      0,   0,   6,   9,  16,   0, \n      8,   0,   0,   0,  86,  14, \n     16,   0,   5,   0,   0,   0, \n     55,   0,   0,   9, 226,   0, \n     16,   0,   5,   0,   0,   0, \n      6,   9,  16,   0,   6,   0, \n      0,   0,   6,   9,  16,   0, \n      7,   0,   0,   0,  86,  14, \n     16,   0,   5,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,   0,   0,   7, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      4,   0,   0,   0,   6,   0, \n     16,   0,   5,   0,   0,   0, \n      1,   0,   0,   7, 194,   0, \n     16,   0,   2,   0,   0,   0, \n      6,   4,  16,   0,   1,   0, \n      0,   0,   6,   0,  16,   0, \n      5,   0,   0,   0,  54,   0, \n      0,   5, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  55,   0,   0,  11, \n    242,   0,  16,   0,   4,   0, \n      0,   0,   6, 144, 208,   0, \n     32,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     70,  14,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  55,   0, \n      0,  11,  50,   0,  16,   0, \n      1,   0,   0,   0,   6, 144, \n    208,   0,  32,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0, 230,  10,  16,   0, \n      5,   0,   0,   0, 230,  10, \n     16,   0,   2,   0,   0,   0, \n     18,   0,   0,   1,  31,   0, \n      4,   5,  10, 144, 208,   0, \n     32,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   9,  18,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  10, 144, 208,   0, \n     64,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   9,  34,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  26, 144, 208,   0, \n     64,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   9,  66,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42, 144, 208,   0, \n     64,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   9, 130,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  58, 144, 208,   0, \n     64,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,  10, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255,   1,   0, \n      0,   7, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n      6,   0,  16,   0,   5,   0, \n      0,   0,  33,   0,   0,  10, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  38,   9,  16,   0, \n      1,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,  12, 114,   0, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255,   0,   0, \n      0,   0, 150, 151, 208,   0, \n     64,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     33,   0,   0,   7, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     38,   9,  16,   0,   1,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,  10, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255,   0,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     38,   9,  16,   0,   1,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  38,   9,  16,   0, \n      1,   0,   0,   0,  34,   0, \n      0,   7, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,   1,   0,   0,   7, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  38,   9,  16,   0, \n      1,   0,   0,   0, 150,   7, \n     16,   0,   5,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   1,   0,   0,   0, \n    150,   4,  16,   0,   6,   0, \n      0,   0, 150,   4,  16,   0, \n      7,   0,   0,   0, 150,   4, \n     16,   0,   5,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,  18,   0,   0,   1, \n     41,   0,   0,   9, 130,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  10, 144, 208,   0, \n     64,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,   0,   0,   7, 242,   0, \n     16,   0,   4,   0,   0,   0, \n    246,  15,  16,   0,   1,   0, \n      0,   0,  70,  14,  16,   0, \n      4,   0,   0,   0,   1,   0, \n      0,   7,  50,   0,  16,   0, \n      1,   0,   0,   0, 246,  15, \n     16,   0,   1,   0,   0,   0, \n     70,   0,  16,   0,   1,   0, \n      0,   0,  21,   0,   0,   1, \n     21,   0,   0,   1,  18,   0, \n      0,   1,  80,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     31,   0,   4,   5,  10, 144, \n    208,   0,  32,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  33,   0,   0,  10, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,  12, 114,   0, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255,   0,   0, \n      0,   0, 150, 151, 208,   0, \n     64,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n     33,   0,   0,   7, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,  10, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255,   0,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,  34,   0, \n      0,   7, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  41,   0,   0,   9, \n     18,   0,  16,   0,  10,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  26, 144, \n    208,   0,  64,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   9, \n     34,   0,  16,   0,  10,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42, 144, \n    208,   0,  64,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   9, \n     66,   0,  16,   0,  10,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  58, 144, \n    208,   0,  64,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,  10, \n    114,   0,  16,   0,  10,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,   2,  64, \n      0,   0, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255,   0,   0,   0,   0, \n      1,   0,   0,   7, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  33,   0, \n      0,  10, 114,   0,  16,   0, \n      5,   0,   0,   0,  38,   9, \n     16,   0,   1,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  33,   0,   0,   7, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  38,   9,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,  38,   9, \n     16,   0,   1,   0,   0,   0, \n     40,   0,   0,   5, 114,   0, \n     16,   0,   8,   0,   0,   0, \n     38,   9,  16,   0,   1,   0, \n      0,   0,  34,   0,   0,   7, \n    114,   0,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n      1,   0,   0,   7, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     38,   9,  16,   0,   1,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      1,   0,   0,   0, 150,   4, \n     16,   0,   5,   0,   0,   0, \n    150,   4,  16,   0,   6,   0, \n      0,   0, 150,   4,  16,   0, \n      7,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n     18,   0,   0,   1,  41,   0, \n      0,   9, 130,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     10, 144, 208,   0,  64,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0, 255, 255, \n    255, 255,  54,   0,   0,   5, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   7, 242,   0,  16,   0, \n      4,   0,   0,   0, 246,  15, \n     16,   0,   0,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0,   1,   0,   0,   7, \n     50,   0,  16,   0,   1,   0, \n      0,   0, 246,  15,  16,   0, \n      0,   0,   0,   0,  70,   0, \n     16,   0,   1,   0,   0,   0, \n     21,   0,   0,   1,  18,   0, \n      0,   1,  54,   0,   0,   5, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0, 168,   0,   0,   8, \n     50, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  68,   0, \n      0,   0,  70,   0,  16,   0, \n      1,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   0,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     68,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     79,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0, 254, 255, \n    255, 255,  32,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      5,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,  32,   0, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   2,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,  64,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   0,   0,   2,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   4,   0,   0,   0,   8, \n      0,   0,   0,  16,   0,   0, \n      0,  32,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     18,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0,   0,  64, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   2,   0,   0,   0, \n      4,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  22,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     16,   0,   0,   0,  32,   0, \n      0,   0,  64,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  26,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   0,   0,   4,   0,   0, \n      0,   8,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     29,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  30,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,  16,   0,   0, \n      0,  32,   0,   0,   0,  64, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,   2,   0, \n      0,   0,   4,   0,   0,   0, \n     16,   0,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   5,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,  32,   0,   0,   0, \n     64,   0,   0,   0, 128,   0, \n      0,   0,   0,   1,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   2,   0,   0,   0,   4, \n      0,   0,   0,   8,   0,   0, \n      0,  16,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n      2,   0,   0,   0,   6,   4, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,  32,   0,   0,   0,   0, \n    128,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   5,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      1,   0,   0,   0,   2,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  18,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     19,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  21,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      8,   0,   0,   0,  16,   0, \n      0,   0,  32,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     22,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      5,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n     64,   0,   0,   0,   0,   1, \n      0,   0,   0,   2,   0,   0, \n      0,   4,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  27,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     28,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  30,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   8,   0,   0, \n      0,  16,   0,   0,   0,  32, \n      0,   0,   0,  64,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  18,   0,   0,   1, \n     32,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      5,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     25,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   5,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,  32,   0,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   2,   8,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n     64,   0,   0,   0, 128,   0, \n      0,   0,   0,   1,   0,   0, \n      0,   2,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0,   0,   4, \n      0,   0,   0,   8,   0,   0, \n      0,  16,   0,   0,   0,  32, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      2,   0,   0,   0,   4,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     19,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  21,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     22,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      8,   0,   0,   0,  16,   0, \n      0,   0,  32,   0,   0,   0, \n     64,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  27,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,   0,   0, 128,   0, \n      0,   0,   0,   1,   0,   0, \n      0,   4,   0,   0,   0,   8, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     28,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  30,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,  16,   0,   0,   0,  32, \n      0,   0,   0,  64,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   2,   0,   0,   0, \n      4,   0,   0,   0,  16,   0, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n     32,   0,   0,   0,  64,   0, \n      0,   0, 128,   0,   0,   0, \n      0,   1,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      5,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,   0,   2, \n      0,   0,   0,   4,   0,   0, \n      0,   8,   0,   0,   0,  16, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   2,   0, \n      0,   0,   6,   4,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,  32, \n      0,   0,   0,   0, 128,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  64,   0,   0,   0, 128, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   2,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     18,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  19,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  20,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     21,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      5,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      4,   0,   0,   0,   8,   0, \n      0,   0,  16,   0,   0,   0, \n     32,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 194,   0, \n     16,   0,   4,   0,   0,   0, \n     86,   9,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  22,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,  64,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  25,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  26,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      5,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   1,   0,   0,   0,   2, \n      0,   0,   0,   4,   0,   0, \n      0,   8,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  29,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     30,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,  16, \n      0,   0,   0,  32,   0,   0, \n      0,  64,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     18,   0,   0,   1,  32,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  31,   0,   4,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  25,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n     32,   0,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   2, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0,  64,   0, \n      0,   0, 128,   0,   0,   0, \n      0,   1,   0,   0,   0,   2, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,   0,   4,   0,   0, \n      0,   8,   0,   0,   0,  16, \n      0,   0,   0,  32,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  18,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  64,   0,   0,   0,   0, \n      1,   0,   0,   0,   2,   0, \n      0,   0,   4,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  19,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  20,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     21,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  22,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   8,   0, \n      0,   0,  16,   0,   0,   0, \n     32,   0,   0,   0,  64,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  26,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  27,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0, 128,   0,   0,   0, \n      0,   1,   0,   0,   0,   4, \n      0,   0,   0,   8,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  29,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     30,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,  16, \n      0,   0,   0,  32,   0,   0, \n      0,  64,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      2,   0,   0,   0,   4,   0, \n      0,   0,  16,   0,   0,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      5,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,  32,   0, \n      0,   0,  64,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   5,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   2,   0,   0, \n      0,   4,   0,   0,   0,  16, \n      0,   0,   0,   0,  32,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   0,   8,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n      2,   0,   0,   0,   6,   4, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,  32,   0,   0,   0,   0, \n    128,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      1,   0,   0,   0,   2,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  18,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     19,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      8,   0,   0,   0,  16,   0, \n      0,   0,   0,   1,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    194,   0,  16,   0,   4,   0, \n      0,   0,  86,   9,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  22,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,  64,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  18,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  27,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   2,   0,   0, \n      0,   4,   0,   0,   0,   8, \n      0,   0,   0,  16,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  30,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   2,   0,   0,   0, \n      6,   4,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,  32, \n      0,   0,   0,  64,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     18,   0,   0,   1,  32,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  31,   0,   4,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  25,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n     32,   0,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   2, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0,  64,   0, \n      0,   0, 128,   0,   0,   0, \n      0,   1,   0,   0,   0,   2, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,   0,   4,   0,   0, \n      0,   8,   0,   0,   0,  16, \n      0,   0,   0,  32,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  18,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  64,   0,   0,   0,   0, \n      1,   0,   0,   0,   2,   0, \n      0,   0,   4,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  19,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  20,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     21,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  22,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   8,   0, \n      0,   0,  16,   0,   0,   0, \n     32,   0,   0,   0,  64,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  26,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  27,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0, 128,   0,   0,   0, \n      0,   1,   0,   0,   0,   4, \n      0,   0,   0,   8,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  29,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     30,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,  16, \n      0,   0,   0,  32,   0,   0, \n      0,  64,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      2,   0,   0,   0,   4,   0, \n      0,   0,  16,   0,   0,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      5,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,  32,   0, \n      0,   0,  64,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   5,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   2,   0,   0, \n      0,   4,   0,   0,   0,  16, \n      0,   0,   0,   0,   2,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   0,   8,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n      2,   0,   0,   0,   6,   4, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,  32,   0,   0,   0,   0, \n    128,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 194,   0, \n     16,   0,   4,   0,   0,   0, \n      6,   4,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0,   0,  64, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   1,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   5,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   8,   0,   0,   0, \n     16,   0,   0,   0,  32,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  22,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  29,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,  64,   0,   0,   0, \n      0,   8,   0,   0,   0,  16, \n      0,   0,   0,  32,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     25,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  26,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   2,   0, \n      0,   0,   6,   4,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   2,   0,   0,   0,   4, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  30,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,  64,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     18,   0,   0,   1,  54,   0, \n      0,   8,  82,   0,  16,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     21,   0,   0,   1,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     21,   0,   0,   1,  18,   0, \n      0,   1,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   6,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     68,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0, 252, 255,  32,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     98,   0,  16,   0,   0,   0, \n      0,   0,  86,   6,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      4,   0,   0,   0,   8,   0, \n      0,   0,   0,   4,   0,   0, \n      0,   8,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     25,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,  32,   0,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   2,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n     64,   0,   0,   0, 128,   0, \n      0,   0,   0,   1,   0,   0, \n      0,   2,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   9,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   4, \n      0,   0,   0,   8,   0,   0, \n      0,  16,   0,   0,   0,  32, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  70,  14,  16,   0, \n      9,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      2,   0,   0,   0,   4,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      9,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     19,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  21,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     22,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      8,   0,   0,   0,  16,   0, \n      0,   0,  32,   0,   0,   0, \n     64,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  27,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  70,  14,  16,   0, \n      9,   0,   0,   0,   2,  64, \n      0,   0,   0,   0, 128,   0, \n      0,   0,   0,   1,   0,   0, \n      0,   4,   0,   0,   0,   8, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      9,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     28,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  30,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,  16,   0,   0,   0,  32, \n      0,   0,   0,  64,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   2,   0,   0,   0, \n      4,   0,   0,   0,  16,   0, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,  32,   0, \n      0,   0,  64,   0,   0,   0, \n    128,   0,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  21,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     22,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   1, \n      0,   0,   0,   0,  16,   0, \n      0,   0,  32,   0,   0,   0, \n     64,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   2, \n      0,   0,   0,   0,   0,  32, \n      2,   0,   0,   0, 128,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    194,   0,  16,   0,   0,   0, \n      0,   0,  86,   9,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     30,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   2,   0, \n      0,   0,   6,   4,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,  16, \n      0,   0,   0,   0,   0,  64, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   4,   0,   0,   0, \n      6,   4,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,  32,   0,   0, \n      0,   0, 128,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,  64, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      2,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     18,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  19,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   6,   0, \n      0,   0,   6,   4,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,   8,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  27,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   1, \n      0,   0,   0,   2,   0,   0, \n      0,   4,   0,   0,   0,   8, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,  16,  64,   0,   0,   0, \n      0,  16,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   4,   0,   0,   0, \n      8,   0,   0,   0,  16,   0, \n      0,   0,  32,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   1,   0,   0, \n      0,   2,   0,   0,   0,   4, \n      0,   0,   0,   8,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,  32,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     85,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  85,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,  64, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      2,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     18,   0,   0,   1,  32,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     98,   0,  16,   0,   0,   0, \n      0,   0,  86,   6,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7, 194,   0, \n     16,   0,   2,   0,   0,   0, \n    166,   6,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     22,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   4,   0,   0,   0, \n      0,  64,   0,   0,   0,   0, \n     64,   0,   0,   0,   0,   1, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      8,   0,   0,   0,  16,   0, \n      0,   0,   0,  32,   0,   0, \n      0,   0, 128,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,  32,   0, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   2,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,  10,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n     10,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,  10,   0, \n      0,   0,  70,  14,  16,   0, \n     10,   0,   0,   0,   2,  64, \n      0,   0,  64,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   0,   0,   2,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n     10,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,  10,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n     10,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,  10,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,  10,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,  10,   0,   0,   0, \n     70,  14,  16,   0,  10,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   4,   0,   0,   0,   8, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   2,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,  10,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n     10,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  19,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   0,   0, \n      0,   0,   6,   4,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,  16, \n      0,   0,   0,   0,   8,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,  10,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,  10,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,  10,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,  10,   0, \n      0,   0,  70,  14,  16,   0, \n     10,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   8,   0,   0,   0, \n     16,   0,   0,   0,  32,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n     10,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,  10,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n     10,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  27,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     29,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   4,   0,   0,   0,   8, \n      0,   0,   0,  16,   0,   0, \n      0,  32,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  30,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   7,   0, \n      0,   0, 134,   3,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,  64, \n     16,   0,   0,   0,  32,   0, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   2,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,  64,   0, \n      0,   0, 128,   0,   0,   0, \n      0,   1,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     29,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   2,   0,   0,   0,   0, \n      0,  32,   2,   0,   0,   0, \n    128,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,   0,   7, \n    194,   0,  16,   0,   2,   0, \n      0,   0,  86,   9,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  30,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   4,   0,   0,   0,   8, \n      0,   0,   0,  16,   0,   0, \n      0,   0,   0,  64,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   9,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   2,   0,   0,   0, \n      6,   4,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,  32,   0,   0, \n      0,   0, 128,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,  10,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,  10,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,  10,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n     10,   0,   0,   0,  70,  14, \n     16,   0,  10,   0,   0,   0, \n      2,  64,   0,   0,   0,  64, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      2,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,  10,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,  10,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,  10,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,  10,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,  10,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     25,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n     10,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  26,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,  10,   0, \n      0,   0,  70,  14,  16,   0, \n     10,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0,   1,   0,   0, \n      0,   2,   0,   0,   0,   4, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n     10,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  21,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     22,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n      0,   0,   0,   0,   6,   4, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  32,   0,   0,   0, \n     64,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n     10,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,  10,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,  10,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  27,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   0,   0,   0,   0, \n      6,   4,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   8, \n      0,   0,   0,  16,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    194,   0,  16,   0,   0,   0, \n      0,   0, 166,   2,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n      1,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   0,   0,   0,   0, \n     86,   9,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,  16,   0,   0,   0, \n     32,   0,   0,   0,  64,   0, \n      0,   0,   0,   1,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   2, \n      0,   0,   0,   4,   0,   0, \n      0,   8,   0,   0,   0,  16, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,  32, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  85,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     85,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      1,   0,   0,   0,   2,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  18,   0, \n      0,   1,  32,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,  32,   0, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   2,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,  64,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   0,   0,   2,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   4,   0,   0,   0,   8, \n      0,   0,   0,  16,   0,   0, \n      0,  32,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     18,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,  64, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   2,   0,   0,   0, \n      4,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  22,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     16,   0,   0,   0,  32,   0, \n      0,   0,  64,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  26,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   0,   0,   4,   0,   0, \n      0,   8,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     29,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  30,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,  16,   0,   0, \n      0,  32,   0,   0,   0,  64, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   2,   0, \n      0,   0,   4,   0,   0,   0, \n     16,   0,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,  32,   0,   0,   0, \n     64,   0,   0,   0, 128,   0, \n      0,   0,   0,   1,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,  29,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   2,   0,   0, \n      0,   0,   0,  32,   2,   0, \n      0,   0, 128,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      0,   0,   0,   0,  86,   9, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  30,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   4,   0,   0, \n      0,   8,   0,   0,   0,  16, \n      0,   0,   0,   0,   0,  64, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   0,   0, \n      0,   0,   6,   4,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,  32, \n      0,   0,   0,   0, 128,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      2,   0,   0,   0,   6,   4, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  70,  14,  16,   0, \n      9,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   1, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      9,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 194,   0, \n     16,   0,   2,   0,   0,   0, \n     86,   9,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  27,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   2,   0,   0,   0, \n      6,   4,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   8,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  18,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     19,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n      4,   0,   0,   0,   6,   4, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      8,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      4,   0,   0,   0,   6,   4, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,  10,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  21,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,  10,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     22,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n     10,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,  10,   0, \n      0,   0,  70,  14,  16,   0, \n     10,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,  16,   0, \n      0,   0,  32,   0,   0,   0, \n     64,   0,   0,   0,   0,  16, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n     10,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,  10,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n     10,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  25,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  26,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   0,   0,   0,   0, \n      6,   4,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   2, \n      0,   0,   0,   4,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,  10,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      0,   0,   0,   0, 166,   2, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,   1,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   0,   0, \n      0,   0,  86,   9,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,  16,   0, \n      0,   0,  32,   0,   0,   0, \n      0,   1,   0,   0,   0,   2, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   0,   0, \n      0,   0,   6,   4,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  64,   0, \n      0,   0,   0,  16,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   2,   0, \n      0,   0,   6,   4,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   4, \n      0,   0,   0,   8,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,  32, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  85,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     85,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      1,   0,   0,   0,   2,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  18,   0, \n      0,   1,  32,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,  32,   0, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   2,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,  64,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   0,   0,   2,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   4,   0,   0,   0,   8, \n      0,   0,   0,  16,   0,   0, \n      0,  32,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     18,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,  64, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   2,   0,   0,   0, \n      4,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  22,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     16,   0,   0,   0,  32,   0, \n      0,   0,  64,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  26,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   0,   0,   4,   0,   0, \n      0,   8,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     29,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  30,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,  16,   0,   0, \n      0,  32,   0,   0,   0,  64, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   2,   0, \n      0,   0,   4,   0,   0,   0, \n     16,   0,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n    194,   0,  16,   0,   2,   0, \n      0,   0,   6,   4,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     18,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,  32,   0, \n      0,   0,  64,   0,   0,   0, \n    128,   0,   0,   0,   0,   0, \n      4,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  21,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     22,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   1, \n      0,   0,   0,   0,  16,   0, \n      0,   0,  32,   0,   0,   0, \n     64,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   2, \n      0,   0,   0,   0,   0,  32, \n      2,   0,   0,   0, 128,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,   0,   7, 194,   0, \n     16,   0,   0,   0,   0,   0, \n     86,   9,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,  10,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,  10,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     30,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n     10,   0,   0,   0,  70,  14, \n     16,   0,  10,   0,   0,   0, \n      2,  64,   0,   0,   0,   4, \n      0,   0,   0,   8,   0,   0, \n      0,  16,   0,   0,   0,   0, \n      0,  64,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,  10,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,  10,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,  10,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n      0,   0,   0,   0,   6,   4, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,  32,   0,   0,   0,   0, \n    128,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n     11,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,  11,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,  11,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n     11,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,  11,   0, \n      0,   0,  70,  14,  16,   0, \n     11,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      1,   0,   0,   0,   2,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n     11,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,  11,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n     11,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  11,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n      2,   0,   0,   0,   6,   4, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,  32,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   1,   0,   0,   0,   2, \n      0,   0,   0,   4,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   8,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     28,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,  16,  64,   0, \n      0,   0,   0,  16,   0,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      0,   0,   0,   0, 166,   2, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,   1,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   0,   0, \n      0,   0,  86,   9,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    194,   0,  16,   0,   0,   0, \n      0,   0,   6,  12,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n     16,   0,   0,   0,   0,   1, \n      0,   0,   0,   2,   0,   0, \n      0,   4,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   8, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,  32,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  85,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  64,   0,   0,   0, 128, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   2,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  18,   0,   0,   1, \n     32,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     25,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,  32,   0,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   2,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n     64,   0,   0,   0, 128,   0, \n      0,   0,   0,   1,   0,   0, \n      0,   2,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   4, \n      0,   0,   0,   8,   0,   0, \n      0,  16,   0,   0,   0,  32, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      2,   0,   0,   0,   4,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     19,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  21,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     22,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      8,   0,   0,   0,  16,   0, \n      0,   0,  32,   0,   0,   0, \n     64,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  27,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   0, 128,   0, \n      0,   0,   0,   1,   0,   0, \n      0,   4,   0,   0,   0,   8, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     28,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  30,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,  16,   0,   0,   0,  32, \n      0,   0,   0,  64,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   2,   0,   0,   0, \n      4,   0,   0,   0,  16,   0, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 194,   0, \n     16,   0,   2,   0,   0,   0, \n      6,   4,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,  32,   0,   0,   0, \n     64,   0,   0,   0, 128,   0, \n      0,   0,   0,   0,   2,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   1,   0,   0, \n      0,   4,   0,   0,   0,   8, \n      0,   0,   0,  16,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,  29,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   9,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  70,  14,  16,   0, \n      9,   0,   0,   0,   2,  64, \n      0,   0,   0,   2,   0,   0, \n      0,   0,   0,  32,   2,   0, \n      0,   0, 128,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      9,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   0,   0,   0,   0, \n      6,   4,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,  32,   0,   0, \n      0,   0, 128,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    194,   0,  16,   0,   2,   0, \n      0,   0,   6,   4,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  64,   0,   0,   0, 128, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   1,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  18,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     19,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n      2,   0,   0,   0,   6,   4, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      8,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      2,   0,   0,   0,   6,   4, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  21,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     22,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,  16,   0, \n      0,   0,  32,   0,   0,   0, \n     64,   0,  32,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  27,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   2, \n      0,   0,   0,   4,   0,   0, \n      0,   8,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,  16, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    194,   0,  16,   0,   0,   0, \n      0,   0, 166,   2,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  30,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   4,   0, \n      0,   0,   6,   8,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,  64,   4,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 194,   0, \n     16,   0,   0,   0,   0,   0, \n      6,  12,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   8,   0, \n      0,   0,  16,   0,   0,   0, \n      0,   1,   0,   0,   0,   2, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,  64,   0,   0,   0, \n      0,   8,   0,   0,   0,  16, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   4,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,  32,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  85,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  64,   0,   0,   0, 128, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   2,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  18,   0,   0,   1, \n     32,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     25,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,  32,   0,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   2,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n     64,   0,   0,   0, 128,   0, \n      0,   0,   0,   1,   0,   0, \n      0,   2,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   4, \n      0,   0,   0,   8,   0,   0, \n      0,  16,   0,   0,   0,  32, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 194,   0, \n     16,   0,   0,   0,   0,   0, \n    166,   6,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,  64, \n      0,   0,   0,   0,   0,   1, \n      0,   4,   0,   0,   0,   8, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      2,   0,   0,   0,   4,   0, \n      0,   0,   8,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   9,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  22,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n     16,   0,   0,   0,  32,   0, \n      0,   0,  64,   0,   0,   0, \n    128,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  27,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     29,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   4,   0,   0,   0,   8, \n      0,   0,   0,  16,   0,   0, \n      0,  32,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  30,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n      4,   0,   0,   0,   6,   8, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,  64,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 194,   0, \n     16,   0,   0,   0,   0,   0, \n     86,   1,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  20,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     21,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   4,   0, \n      0,   0,   0,   1,   0,   0, \n      0,   0,  16,   0,   0,   0, \n     32,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n     16,   0,   0,   0,  32,   0, \n      0,   0,  64,   0,   0,   0, \n    128,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   2, \n      0,   0,   0,   0,   0,  32, \n      2,   0,   0,   0, 128,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    194,   0,  16,   0,   0,   0, \n      0,   0,  86,   9,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     30,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   2,   0, \n      0,   0,   6,   4,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,  16, \n      0,   0,   0,   0,   0,  64, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   4,   0,   0,   0, \n      6,   4,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,  32,   0,   0, \n      0,   0, 128,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,  64, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      2,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     18,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  19,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   6,   0, \n      0,   0,   6,   4,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,   8,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      6,   0,   0,   0,   6,   4, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  22,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,  64,   0, \n      0,   0,   0,  16,  64,   0, \n      0,   0,   0,  16,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  25,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  26,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   1,   0,   0,   0,   2, \n      0,   0,   0,   4,   0,   0, \n      0,   8,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n      4,   0,   0,   0,   8,   0, \n      0,   0,  16,   0,   0,   0, \n     32,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   9,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   1,   0,   0,   0,   2, \n      0,   0,   0,   4,   0,   0, \n      0,   8,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,  32, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  85,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     85,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      1,   0,   0,   0,   2,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  18,   0, \n      0,   1,  32,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,  32,   0, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   2,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,  18,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,  64,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   0,   0,   2,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   4,   0,   0,   0,   8, \n      0,   0,   0,  16,   0,   0, \n      0,   0,   1,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      0,   0,   0,   0,   6,   4, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  70,  14,  16,   0, \n      9,   0,   0,   0,   2,  64, \n      0,   0,   0,  32,   0,   0, \n      0,   0, 128,   0,   2,   0, \n      0,   0,   4,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      0,   0,   0,   0, 166,   6, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,  10,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n     10,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,  10,   0, \n      0,   0,  70,  14,  16,   0, \n     10,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0,   0,   0,   1,   0,   4, \n      0,   0,   0,   8,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n     10,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  18,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     19,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   4,   0,   0,   0, \n      8,   0,   0,   0,  16,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  21,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     22,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  26,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  27,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,  32,   0,   0,   0, \n     64,   0,   0,   0,   0,   4, \n      0,   0,   0,   8,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,  10,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     28,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  30,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,  16,   0,   0,   0,  32, \n      0,   0,   0,  64,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,   1,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,  16,   0,   0,   0, \n     32,   0,   0,   0,  64,   0, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n      0,   0,   0,   0,   6,   4, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,  29,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   2,   0,   0, \n      0,   0,   0,  32,   2,   0, \n      0,   0, 128,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,  10,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 194,   0, \n     16,   0,   0,   0,   0,   0, \n     86,   9,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  30,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   2,   0,   0,   0, \n      6,   4,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,  16,   0,   0, \n      0,   0,   0,  64,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n      4,   0,   0,   0,   6,   4, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,  32,   0,   0,   0,   0, \n    128,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      1,   0,   0,   0,   2,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   6,   0,   0,   0, \n      6,   4,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   8,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 194,   0, \n     16,   0,   6,   0,   0,   0, \n      6,   4,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  22,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     28,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n     16,   0,   0,   0,  32,   0, \n      0,   0,  64,   0,   0,   0, \n      0,  16,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  27,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  70,  14,  16,   0, \n      9,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   1, \n      0,   0,   0,   2,   0,   0, \n      0,   4,   0,   0,   0,   8, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      9,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   4,   0, \n      0,   0,   8,   0,   0,   0, \n     16,   0,   0,   0,  32,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,  64,   0,   0,   0, \n      0,   1,   0,   0,   0,   2, \n      0,   0,   0,   4,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   0,   0,   0,   0, \n      6,   4,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   8,   0,   0, \n      0,  16,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,  32, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  85,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     85,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      1,   0,   0,   0,   2,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  18,   0, \n      0,   1,  32,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,  32,   0, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   2,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,  22,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,  64,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   0,   0,   2,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   4,   0,   0,   0,   8, \n      0,   0,   0,  16,   0,   0, \n      0,   0,   1,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   0,   0,   0,   0, \n      6,   4,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,  32,   0,   0, \n      0,   0,   8,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    194,   0,  16,   0,   2,   0, \n      0,   0, 166,   6,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  64,   0,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   4,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   9,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     18,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  19,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  20,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      4,   0,   0,   0,   8,   0, \n      0,   0,  16,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     21,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  22,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  26,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n     32,   0,   0,   0,  64,   0, \n      0,   0,   0,   4,   0,   0, \n      0,   8,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  29,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     30,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,  16, \n      0,   0,   0,  32,   0,   0, \n      0,  64,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,   1,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      6,   0,   0,   0,  86,   1, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   2,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   1,   0,   0,   0,   0, \n     16,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,  16,   0,   0,   0, \n     32,   0,   0,   0,  64,   0, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0, 128,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     29,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   2,   0,   0,   0,   0, \n      0,  32,   2,   0,   0,   0, \n    128,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 194,   0, \n     16,   0,   2,   0,   0,   0, \n     86,   9,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  30,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   8, \n      0,   0,   0,  16,   0,   0, \n      0,   0,   0,  64,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   2,   0,   0,   0, \n      6,   4,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,  32,   0,   0, \n      0,   0, 128,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,  64, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      2,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     25,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  26,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  70,  14,  16,   0, \n      9,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0,   1,   0,   0, \n      0,   2,   0,   0,   0,   4, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      9,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 194,   0, \n     16,   0,   4,   0,   0,   0, \n      6,   4,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,  10,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     21,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n     10,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  22,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,  10,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,  10,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n     10,   0,   0,   0,  70,  14, \n     16,   0,  10,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n     32,   0,   0,   0,  64,   0, \n      0,   0,   0,  16,  64,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,  10,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,  10,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   8,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,  10,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  98,   0,  16,   0, \n      0,   0,   0,   0, 166,   8, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   4,   0, \n      0,   0,   8,   0,   0,   0, \n     16,   0,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,  32,   0, \n      0,   0,   0,   1,   0,   0, \n      0,   2,   0,   0,   0,   4, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   8, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,  16,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,  32,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  85,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  64,   0,   0,   0, 128, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   2,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  18,   0,   0,   1, \n     32,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     25,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,  32,   0,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   2,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n     64,   0,   0,   0, 128,   0, \n      0,   0,   0,   1,   0,   0, \n      0,   2,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   4, \n      0,   0,   0,   8,   0,   0, \n      0,  16,   0,   0,   0,   0, \n      1,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      2,   0,   0,   0,  86,   1, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  32,   0,   0,   2,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   1,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,   0,   7, \n    194,   0,  16,   0,   0,   0, \n      0,   0, 166,   6,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,  10,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,  10,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n     10,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,  10,   0,   0,   0, \n     70,  14,  16,   0,  10,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  64,   0,   0,   0,   0, \n    128,   0,   0,   0,   0,   1, \n      0,   4,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,  10,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     18,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  19,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  20,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      4,   0,   0,   0,   8,   0, \n      0,   0,  16,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     21,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  22,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  26,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n     32,   0,   0,   0,  64,   0, \n      0,   0,   0,   4,   0,   0, \n      0,   8,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,  10,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n     10,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  29,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     30,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,  16, \n      0,   0,   0,  32,   0,   0, \n      0,  64,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,   1,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n     16,   0,   0,   0,  32,   0, \n      0,   0,  64,   0,   0,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    128,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   2, \n      0,   0,   0,   0,   0,  32, \n      2,   0,   0,   0, 128,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      0,   0,   0,   0,  86,   9, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     30,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   8,   0,   0, \n      0,  16,   0,   0,   0,   0, \n      0,  64,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n      2,   0,   0,   0,   6,   4, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,  32,   0,   0,   0,   0, \n    128,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  70,  14,  16,   0, \n      9,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      1,   0,   0,   0,   2,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      9,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   4,   0,   0,   0, \n      6,   4,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   8,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      4,   0,   0,   0,   6,   4, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  22,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n     16,   0,   0,   0,  32,   0, \n      0,   0,  64,   0,  64,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n     10,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,  10,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,  10,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  27,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,  10,   0, \n      0,   0,  70,  14,  16,   0, \n     10,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   1, \n      0,   0,   0,   2,   0,   0, \n      0,   4,   0,   0,   0,   8, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n     10,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,  10,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n     10,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,  16,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     98,   0,  16,   0,   0,   0, \n      0,   0, 166,   8,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,   1,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   4,   0,   0,   0, \n      8,   0,   0,   0,  16,   0, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,  32,   0,   0,   0, \n      0,   1,   0,   0,   0,   2, \n      0,   0,   0,   4,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   8,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,  16,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,  32,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     85,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  85,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,  64, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      2,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     18,   0,   0,   1,  32,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  25,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n     32,   0,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   2, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,  30,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,  64,   0, \n      0,   0, 128,   0,   0,   0, \n      0,   1,   0,   0,   0,   2, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   4,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      2,   0,   0,   0,   4,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      9,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n      1,   0,   0,  10, 210,   0, \n     16,   0,   2,   0,   0,   0, \n      6,   9,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   8,   0,   0,   0,   0, \n      0,   0,   0,  32,   0,   0, \n      0,   0, 128,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   9,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     19,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n      4,   0,   0,   0,   6,   4, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,  16,   0,   0,   0,   0, \n      8,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  82,   0,  16,   0, \n      2,   0,   0,   0, 166,   9, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n    194,   0,  16,   0,   6,   0, \n      0,   0,  86,   9,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  22,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,  64, \n      0,   0,   0,   0,  32,   0, \n      0,   0,  64,   0,   0,   0, \n      0,   1,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  26,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  27,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     16,   0,   0,   0,   0,   4, \n      0,   0,   0,   8,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     29,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  30,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,  16,   0,   0, \n      0,  32,   0,   0,   0,  64, \n     16,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   2,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  42,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     42,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,  32,   0,   0,   0, \n     64,   0,   0,   0, 128,   0, \n      0,   0,   0,   1,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,  29,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   2,   0,   0, \n      0,   0,   0,  32,   2,   0, \n      0,   0, 128,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      0,   0,   0,   0,  86,   9, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  30,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   4,   0,   0, \n      0,   8,   0,   0,   0,  16, \n      0,   0,   0,   0,   0,  64, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   0,   0, \n      0,   0,   6,   4,  16,   0, \n      1,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,  32, \n      0,   0,   0,   0, 128,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  42,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   9,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  64,   0,   0,   0, 128, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   2,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   9,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     42,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7,  34,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     18,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      4,   0,   0,   0,   0,   1, \n      0,   0,   0,   2,   0,   0, \n      0,   4,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     42,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  22,   0,   0,   0, \n      1,   0,   0,  10,  50,   0, \n     16,   0,   1,   0,   0,   0, \n     70,   0,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,  32,   0,   0,   0, \n     64,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   0,   0, \n      0,   0,   6,   4,  16,   0, \n      1,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   8,   0,   0,   0,  16, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 194,   0,  16,   0, \n      0,   0,   0,   0, 166,   2, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   0,   0, \n      0,   0,  86,   9,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      1,   0,   0,   0,  70,  14, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0,  16,   0, \n      0,   0,  32,   0,   0,   0, \n     64,   0,   0,   0,   0,   1, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  42,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     42,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  42,   0, \n      0,   7,  34,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   1,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   2,   0,   0,   0,   4, \n      0,   0,   0,   8,   0,   0, \n      0,  16,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,  32,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     85,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  85,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  85,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      1,   0,   0,   0,  70,  14, \n     16,   0,   2,   0,   0,   0, \n      2,  64,   0,   0,   0,  64, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      2,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     18,   0,   0,   1,  54,   0, \n      0,   8,  82,   0,  16,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     21,   0,   0,   1,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     21,   0,   0,   1,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     21,   0,   0,   1,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     21,   0,   0,   1,  21,   0, \n      0,   1, 168,   0,   0,   9, \n    242, 224,  17,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n    134,   7,  16,   0,   3,   0, \n      0,   0,  21,   0,   0,   1, \n     62,   0,   0,   1\n};\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/Shaders/Compiled/BC6HEncode_TryModeG10CS.inc",
    "content": "#if 0\n//\n// Generated by Microsoft (R) D3D Shader Disassembler\n//\n//\n// Input signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Input\n//\n// Output signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Output\ncs_4_0\ndcl_globalFlags refactoringAllowed\ndcl_immediateConstantBuffer { { 10, 5, 5, 5},\n                              { 7, 6, 6, 6},\n                              { 11, 5, 4, 4},\n                              { 11, 4, 5, 4},\n                              { 11, 4, 4, 5},\n                              { 9, 5, 5, 5},\n                              { 8, 6, 5, 5},\n                              { 8, 5, 6, 5},\n                              { 8, 5, 5, 6},\n                              { 6, 6, 6, 6},\n                              { 10, 10, 10, 10},\n                              { 11, 9, 9, 9},\n                              { 12, 8, 8, 8},\n                              { 16, 4, 4, 4},\n                              { -1, 0, 0, 0},\n                              { -1, 0, 4, 0},\n                              { -1, 0, 9, 0},\n                              { -1, 1, 13, 0},\n                              { -1, 1, 17, 0},\n                              { -1, 1, 21, 0},\n                              { -1, 1, 26, 0},\n                              { -1, 2, 30, 0},\n                              { -1, 2, 34, 0},\n                              { 0, 2, 38, 0},\n                              { 0, 2, 43, 0},\n                              { -1, 2, 47, 0},\n                              { -1, 3, 51, 0},\n                              { -1, 3, 55, 0},\n                              { 0, 3, 60, 0},\n                              { 0, 3, 64, 0},\n                              { 0, 4, 0, 0},\n                              { 0, 4, 0, 0},\n                              { 0, 4, 0, 0},\n                              { 0, 4, 0, 0},\n                              { 0, 5, 0, 0},\n                              { 0, 5, 0, 0},\n                              { 0, 5, 0, 0},\n                              { 0, 5, 0, 0},\n                              { 0, 6, 0, 0},\n                              { 0, 6, 0, 0},\n                              { 0, 6, 0, 0},\n                              { 0, 6, 0, 0},\n                              { 0, 6, 0, 0},\n                              { 0, 7, 0, 0},\n                              { 0, 7, 0, 0},\n                              { 0, 7, 0, 0},\n                              { 0, 7, 0, 0},\n                              { 0, 8, 0, 0},\n                              { 0, 8, 0, 0},\n                              { 0, 8, 0, 0},\n                              { 0, 8, 0, 0},\n                              { 0, 9, 0, 0},\n                              { 0, 9, 0, 0},\n                              { 0, 9, 0, 0},\n                              { 0, 9, 0, 0},\n                              { 0, 10, 0, 0},\n                              { 0, 10, 0, 0},\n                              { 0, 10, 0, 0},\n                              { 0, 10, 0, 0},\n                              { 0, 10, 0, 0},\n                              { 0, 11, 0, 0},\n                              { 0, 11, 0, 0},\n                              { 0, 11, 0, 0},\n                              { 0, 11, 0, 0},\n                              { 0, 12, 0, 0},\n                              { 0, 12, 0, 0},\n                              { 0, 12, 0, 0},\n                              { 0, 12, 0, 0},\n                              { 0, 13, 0, 0},\n                              { 0, 13, 0, 0},\n                              { 0, 13, 0, 0},\n                              { 0, 13, 0, 0},\n                              { 0, 14, 0, 0},\n                              { 0, 14, 0, 0},\n                              { 0, 14, 0, 0},\n                              { 0, 14, 0, 0},\n                              { 0, 15, 0, 0},\n                              { 0, 15, 0, 0} }\ndcl_constantbuffer CB0[2], immediateIndexed\ndcl_resource_texture2d (float,float,float,float) t0\ndcl_uav_structured u0, 16\ndcl_input vThreadIDInGroupFlattened\ndcl_input vThreadGroupID.x\ndcl_temps 19\ndcl_tgsm_structured g0, 84, 64\ndcl_thread_group 64, 1, 1\nushr r0.x, vThreadIDInGroupFlattened.x, l(4)\nishl r0.y, vThreadGroupID.x, l(2)\niadd r0.y, r0.y, cb0[1].x\niadd r0.x, r0.x, r0.y\nand r0.y, vThreadIDInGroupFlattened.x, l(48)\niadd r0.z, -r0.y, vThreadIDInGroupFlattened.x\nult r1.xyzw, r0.zzzz, l(16, 8, 4, 2)\nif_nz r1.x\n  udiv r0.w, null, r0.x, cb0[0].y\n  imad r1.x, -r0.w, cb0[0].y, r0.x\n  ishl r1.x, r1.x, l(2)\n  ishl r0.w, r0.w, l(2)\n  and r2.x, r0.z, l(3)\n  iadd r2.x, r1.x, r2.x\n  ushr r1.x, r0.z, l(2)\n  iadd r2.y, r0.w, r1.x\n  mov r2.zw, l(0,0,0,0)\n  ld r2.xyzw, r2.xyzw, t0.xyzw\n  ushr r3.xyz, r2.xyzx, l(16)\n  and r3.xyz, r3.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n  and r4.xyzw, r2.xxyy, l(0x7fffffff, 0x007fffff, 0x7fffffff, 0x007fffff)\n  ult r2.xy, l(0x47ffefff, 0x47ffefff, 0, 0), r4.xzxx\n  ult r5.xy, r4.xzxx, l(0x38800000, 0x38800000, 0, 0)\n  ushr r5.zw, r4.xxxz, l(23)\n  iadd r5.zw, -r5.zzzw, l(0, 0, 113, 113)\n  iadd r4.yw, r4.yyyw, l(0, 0x00800000, 0, 0x00800000)\n  ushr r6.x, r4.y, r5.z\n  ushr r6.y, r4.w, r5.w\n  iadd r4.xy, r4.xzxx, l(0xc8000000, 0xc8000000, 0, 0)\n  movc r4.xy, r5.xyxx, r6.xyxx, r4.xyxx\n  iadd r4.zw, r4.xxxy, l(0, 0, 4095, 4095)\n  ushr r4.xy, r4.xyxx, l(13)\n  and r4.xy, r4.xyxx, l(1, 1, 0, 0)\n  iadd r4.xy, r4.xyxx, r4.zwzz\n  ushr r4.xy, r4.xyxx, l(13)\n  and r4.xy, r4.xyxx, l(0x00007fff, 0x00007fff, 0, 0)\n  movc r2.xy, r2.xyxx, l(0x00007fff,0x00007fff,0,0), r4.xyxx\n  iadd r4.xy, r3.xyxx, r2.xyxx\n  and r2.xy, r2.zzzz, l(0x7fffffff, 0x007fffff, 0, 0)\n  ult r0.w, l(0x47ffefff), r2.x\n  ult r1.x, r2.x, l(0x38800000)\n  ushr r2.z, r2.x, l(23)\n  iadd r2.z, -r2.z, l(113)\n  iadd r2.y, r2.y, l(0x00800000)\n  ushr r2.y, r2.y, r2.z\n  iadd r2.x, r2.x, l(0xc8000000)\n  movc r1.x, r1.x, r2.y, r2.x\n  iadd r2.x, r1.x, l(4095)\n  ushr r1.x, r1.x, l(13)\n  and r1.x, r1.x, l(1)\n  iadd r1.x, r1.x, r2.x\n  ushr r1.x, r1.x, l(13)\n  and r1.x, r1.x, l(0x00007fff)\n  movc r0.w, r0.w, l(0x00007fff), r1.x\n  iadd r4.z, r3.z, r0.w\n  and r2.xyzw, r4.xxyy, l(1023, 0x00007c00, 1023, 0x00007c00)\n  if_nz r2.y\n    ushr r0.w, r4.x, l(10)\n    and r0.w, r0.w, l(31)\n  else \n    if_nz r2.x\n      ishl r1.x, r2.x, l(1)\n      mov r2.y, r1.x\n      mov r0.w, l(0)\n      loop \n        and r3.x, r2.y, l(1024)\n        breakc_nz r3.x\n        iadd r0.w, r0.w, l(-1)\n        ishl r2.y, r2.y, l(1)\n      endloop \n      and r2.x, r2.y, l(1022)\n    else \n      mov r2.x, l(0)\n      mov r0.w, l(-112)\n    endif \n  endif \n  ishl r3.xyz, r4.xyzx, l(16)\n  and r3.xyz, r3.xyzx, l(0x80000000, 0x80000000, 0x80000000, 0)\n  ishl r0.w, r0.w, l(23)\n  iadd r0.w, r0.w, l(0x38000000)\n  or r0.w, r0.w, r3.x\n  ishl r1.x, r2.x, l(13)\n  iadd r5.x, r0.w, r1.x\n  if_nz r2.w\n    ushr r0.w, r4.y, l(10)\n    and r0.w, r0.w, l(31)\n  else \n    if_nz r2.z\n      ishl r1.x, r2.z, l(1)\n      mov r2.x, r1.x\n      mov r0.w, l(0)\n      loop \n        and r2.y, r2.x, l(1024)\n        breakc_nz r2.y\n        iadd r0.w, r0.w, l(-1)\n        ishl r2.x, r2.x, l(1)\n      endloop \n      and r2.z, r2.x, l(1022)\n    else \n      mov r2.z, l(0)\n      mov r0.w, l(-112)\n    endif \n  endif \n  ishl r0.w, r0.w, l(23)\n  iadd r0.w, r0.w, l(0x38000000)\n  or r0.w, r0.w, r3.y\n  ishl r1.x, r2.z, l(13)\n  iadd r5.y, r0.w, r1.x\n  and r2.xy, r4.zzzz, l(1023, 0x00007c00, 0, 0)\n  if_nz r2.y\n    ushr r0.w, r4.z, l(10)\n    and r0.w, r0.w, l(31)\n  else \n    if_nz r2.x\n      ishl r1.x, r2.x, l(1)\n      mov r2.y, r1.x\n      mov r0.w, l(0)\n      loop \n        and r2.z, r2.y, l(1024)\n        breakc_nz r2.z\n        iadd r0.w, r0.w, l(-1)\n        ishl r2.y, r2.y, l(1)\n      endloop \n      and r2.x, r2.y, l(1022)\n    else \n      mov r2.x, l(0)\n      mov r0.w, l(-112)\n    endif \n  endif \n  ishl r0.w, r0.w, l(23)\n  iadd r0.w, r0.w, l(0x38000000)\n  or r0.w, r0.w, r3.z\n  ishl r1.x, r2.x, l(13)\n  iadd r5.z, r0.w, r1.x\n  store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(24), r5.xyzx\n  dp3 r2.w, r5.xyzx, l(0.212600, 0.715200, 0.072200, 0.000000)\n  ieq r0.w, cb0[0].z, l(95)\n  ishl r3.xyz, r4.xyzx, l(6)\n  udiv r3.xyz, null, r3.xyzx, l(31, 31, 31, 0)\n  ult r5.xyz, r4.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n  ieq r6.xyz, r4.xyzx, l(0x00007bff, 0x00007bff, 0x00007bff, 0)\n  ishl r4.xyz, r4.xyzx, l(5)\n  udiv r7.xyz, null, r4.xyzx, l(31, 31, 31, 0)\n  movc r7.xyz, r6.xyzx, l(0x00007fff,0x00007fff,0x00007fff,0), r7.xyzx\n  and r4.xyz, r4.xyzx, l(0x000fffe0, 0x000fffe0, 0x000fffe0, 0)\n  udiv r4.xyz, null, r4.xyzx, l(31, 31, 31, 0)\n  ineg r4.xyz, r4.xyzx\n  movc r4.xyz, r6.xyzx, l(0xffff8001,0xffff8001,0xffff8001,0), r4.xyzx\n  movc r4.xyz, r5.xyzx, r7.xyzx, r4.xyzx\n  movc r2.xyz, r0.wwww, r3.xyzx, r4.xyzx\n  store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(12), r2.xyzx\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r2.xyzx\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(68), r2.yzww\nendif \nsync_g_t\nif_nz r1.y\n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(76), g0.xxxx\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(8)\n  ld_structured r3.x, r0.w, l(76), g0.xxxx\n  lt r1.x, r3.x, r2.x\n  if_nz r1.x\n    ld_structured r2.xyz, r0.w, l(52), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(52), r2.xyzx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(76), r3.x\n  endif \n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(80), g0.xxxx\n  ld_structured r3.x, r0.w, l(80), g0.xxxx\n  lt r1.x, r2.x, r3.x\n  if_nz r1.x\n    ld_structured r2.xyz, r0.w, l(64), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(64), r2.xyzx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(80), r3.x\n  endif \nendif \nsync_g_t\nif_nz r1.z\n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(76), g0.xxxx\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(4)\n  ld_structured r3.x, r0.w, l(76), g0.xxxx\n  lt r1.x, r3.x, r2.x\n  if_nz r1.x\n    ld_structured r2.xyz, r0.w, l(52), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(52), r2.xyzx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(76), r3.x\n  endif \n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(80), g0.xxxx\n  ld_structured r3.x, r0.w, l(80), g0.xxxx\n  lt r1.x, r2.x, r3.x\n  if_nz r1.x\n    ld_structured r2.xyz, r0.w, l(64), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(64), r2.xyzx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(80), r3.x\n  endif \nendif \nsync_g_t\nif_nz r1.w\n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(76), g0.xxxx\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(2)\n  ld_structured r3.x, r0.w, l(76), g0.xxxx\n  lt r1.x, r3.x, r2.x\n  if_nz r1.x\n    ld_structured r2.xyz, r0.w, l(52), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(52), r2.xyzx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(76), r3.x\n  endif \n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(80), g0.xxxx\n  ld_structured r3.x, r0.w, l(80), g0.xxxx\n  lt r1.x, r2.x, r3.x\n  if_nz r1.x\n    ld_structured r2.xyz, r0.w, l(64), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(64), r2.xyzx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(80), r3.x\n  endif \nendif \nsync_g_t\nult r0.w, r0.z, l(1)\nif_nz r0.w\n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(76), g0.xxxx\n  iadd r1.x, vThreadIDInGroupFlattened.x, l(1)\n  ld_structured r3.x, r1.x, l(76), g0.xxxx\n  lt r1.y, r3.x, r2.x\n  if_nz r1.y\n    ld_structured r2.xyz, r1.x, l(52), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(52), r2.xyzx\n  endif \n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(80), g0.xxxx\n  ld_structured r3.x, r1.x, l(80), g0.xxxx\n  lt r1.y, r2.x, r3.x\n  if_nz r1.y\n    ld_structured r2.xyz, r1.x, l(64), g0.xyzx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(64), r2.xyzx\n  endif \nendif \nsync_g_t\nif_z r0.z\n  ld_structured r2.xyz, r0.y, l(52), g0.xyzx\n  ld_structured r3.xyz, r0.y, l(64), g0.xyzx\n  iadd r4.xyz, -r2.xyzx, r3.xyzx\n  itof r4.xyz, r4.xyzx\n  dp3 r1.x, r4.xyzx, r4.xyzx\n  ld_structured r5.xyz, r0.y, l(12), g0.xyzx\n  iadd r5.xyz, -r2.xyzx, r5.xyzx\n  itof r5.xyz, r5.xyzx\n  dp3 r1.y, r4.xyzx, r5.xyzx\n  lt r2.w, l(0.000000), r1.x\n  ge r4.x, r1.y, l(0.000000)\n  and r2.w, r2.w, r4.x\n  mul r1.y, r1.y, l(63.499989)\n  div r1.x, r1.y, r1.x\n  ftou r1.x, r1.x\n  ult r1.x, l(32), r1.x\n  and r1.x, r1.x, r2.w\n  if_nz r1.x\n    mov r3.w, r2.x\n    store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r3.xyzw\n    store_structured g0.xy, vThreadIDInGroupFlattened.x, l(68), r2.yzyy\n  endif \nendif \nsync_g_t\nif_nz r1.z\n  ld_structured r2.xyz, r0.y, l(52), g0.xyzx\n  ld_structured r3.xyz, r0.y, l(64), g0.xyzx\n  ineg r1.xyz, r2.xyzx\n  iadd r4.xyz, r1.xyzx, r3.xyzx\n  itof r4.xyz, r4.xyzx\n  dp3 r2.w, r4.xyzx, r4.xyzx\n  iadd r5.yz, r0.zzzz, l(0, 10, 11, 0)\n  ieq r6.xy, cb0[0].zzzz, l(95, 96, 0, 0)\n  if_nz r6.x\n    ige r0.z, icb[r5.y + 0].x, l(15)\n    and r0.z, r0.z, l(1)\n    movc r7.xyz, r2.xyzx, l(0,0,0,0), l(1,1,1,0)\n    movc r8.xyz, r3.xyzx, l(0,0,0,0), l(1,1,1,0)\n    or r7.xyz, r0.zzzz, r7.xyzx\n    or r8.xyz, r0.zzzz, r8.xyzx\n    ieq r9.xyz, r2.xyzx, l(0x0000ffff, 0x0000ffff, 0x0000ffff, 0)\n    ieq r10.xyz, r3.xyzx, l(0x0000ffff, 0x0000ffff, 0x0000ffff, 0)\n    ishl r0.z, l(1), icb[r5.y + 0].x\n    iadd r0.z, r0.z, l(-1)\n    ishl r11.xyz, r2.xyzx, icb[r5.y + 0].x\n    ishl r12.xyz, r3.xyzx, icb[r5.y + 0].x\n    ishr r11.xyz, r11.xyzx, l(16)\n    ishr r12.xyz, r12.xyzx, l(16)\n    movc r9.xyz, r9.xyzx, r0.zzzz, r11.xyzx\n    movc r10.xyz, r10.xyzx, r0.zzzz, r12.xyzx\n    movc r7.xyz, r7.xyzx, r2.xyzx, r9.xyzx\n    movc r8.xyz, r8.xyzx, r3.xyzx, r10.xyzx\n  else \n    ige r0.z, icb[r5.y + 0].x, l(16)\n    and r0.z, r0.z, l(1)\n    movc r9.xyz, r2.xyzx, l(0,0,0,0), l(1,1,1,0)\n    movc r10.xyz, r3.xyzx, l(0,0,0,0), l(1,1,1,0)\n    or r9.xyz, r0.zzzz, r9.xyzx\n    or r10.xyz, r0.zzzz, r10.xyzx\n    ige r11.xyz, r2.xyzx, l(0, 0, 0, 0)\n    ige r12.xyz, r3.xyzx, l(0, 0, 0, 0)\n    ieq r13.xyz, r2.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    ieq r14.xyz, r3.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    iadd r0.z, l(-1), icb[r5.y + 0].x\n    ishl r3.w, l(1), r0.z\n    iadd r4.w, r3.w, l(-1)\n    ishl r15.xyz, r2.xyzx, r0.z\n    ishl r16.xyz, r3.xyzx, r0.z\n    ishr r15.xyz, r15.xyzx, l(15)\n    ishr r16.xyz, r16.xyzx, l(15)\n    movc r13.xyz, r13.xyzx, r4.wwww, r15.xyzx\n    movc r14.xyz, r14.xyzx, r4.wwww, r16.xyzx\n    ineg r15.xyz, r3.xyzx\n    ieq r16.xyz, r1.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    ieq r17.xyz, r15.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    iadd r3.w, -r3.w, l(1)\n    ishl r18.xyz, r1.xyzx, r0.z\n    ishl r15.xyz, r15.xyzx, r0.z\n    ishr r18.xyz, r18.xyzx, l(15)\n    ishr r15.xyz, r15.xyzx, l(15)\n    ineg r18.xyz, r18.xyzx\n    ineg r15.xyz, r15.xyzx\n    movc r16.xyz, r16.xyzx, r3.wwww, r18.xyzx\n    movc r15.xyz, r17.xyzx, r3.wwww, r15.xyzx\n    movc r11.xyz, r11.xyzx, r13.xyzx, r16.xyzx\n    movc r12.xyz, r12.xyzx, r14.xyzx, r15.xyzx\n    movc r7.xyz, r9.xyzx, r2.xyzx, r11.xyzx\n    movc r8.xyz, r10.xyzx, r3.xyzx, r12.xyzx\n  endif \n  iadd r2.xyz, -r7.xyzx, r8.xyzx\n  movc r2.xyz, icb[r5.y + 14].xxxx, r2.xyzx, r8.xyzx\n  ige r3.xyz, r2.xyzx, l(0, 0, 0, 0)\n  iadd r8.xyzw, l(-1, -1, -1, -1), icb[r5.y + 0].xyzw\n  ishl r9.x, l(1), r8.x\n  ishl r9.y, l(1), r8.y\n  ishl r9.z, l(1), r8.z\n  ishl r9.w, l(1), r8.w\n  ige r8.yzw, r2.xxyz, r9.yyzw\n  ineg r10.xyz, r2.xyzx\n  ilt r10.xyz, r9.yzwy, r10.xyzx\n  movc r11.xyz, r3.xyzx, r8.yzwy, r10.xyzx\n  or r0.z, r11.y, r11.x\n  or r11.x, r11.z, r0.z\n  ishl r12.x, l(1), icb[r5.y + 0].x\n  ishl r12.y, l(1), icb[r5.y + 0].y\n  ishl r12.z, l(1), icb[r5.y + 0].z\n  ishl r12.w, l(1), icb[r5.y + 0].w\n  iadd r12.xyzw, r12.xyzw, l(-1, -1, -1, -1)\n  and r7.xyz, r7.xyzx, r12.xxxx\n  iadd r13.xyzw, r9.yzwx, l(-1, -1, -1, -1)\n  movc r8.yzw, r8.yyzw, r13.xxyz, r2.xxyz\n  and r12.yzw, r2.xxyz, r12.yyzw\n  movc r10.xyz, r10.xyzx, r9.yzwy, r12.yzwy\n  movc r11.yzw, r3.xxyz, r8.yyzw, r10.xxyz\n  and r3.yzw, r2.xxyz, r12.xxxx\n  mov r3.x, l(0)\n  movc r3.xyzw, icb[r5.y + 14].xxxx, r11.xyzw, r3.xyzw\n  and r2.xyz, r9.xxxx, r7.xyzx\n  and r8.yzw, r7.xxyz, r13.wwww\n  iadd r8.yzw, -r9.xxxx, r8.yyzw\n  movc r2.xyz, r2.xyzx, r8.yzwy, r7.xyzx\n  movc r2.xyz, r6.yyyy, r2.xyzx, r7.xyzx\n  or r0.z, r6.y, icb[r5.y + 14].x\n  and r6.yzw, r9.yyzw, r3.yyzw\n  and r7.xyz, r13.xyzx, r3.yzwy\n  iadd r7.xyz, -r9.yzwy, r7.xyzx\n  movc r6.yzw, r6.yyzw, r7.xxyz, r3.yyzw\n  movc r3.yzw, r0.zzzz, r6.yyzw, r3.yyzw\n  iadd r6.yzw, r2.xxyz, r3.yyzw\n  movc r3.yzw, icb[r5.y + 14].xxxx, r6.yyzw, r3.yyzw\n  ult r6.yz, icb[r5.y + 0].xxxx, l(0, 15, 16, 0)\n  ieq r7.xyz, r12.xxxx, r2.xyzx\n  ieq r8.yzw, r12.xxxx, r3.yyzw\n  ishl r9.xyz, r2.xyzx, l(16)\n  ishl r10.xyz, r3.yzwy, l(16)\n  iadd r9.xyz, r9.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n  iadd r10.xyz, r10.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n  ushr r9.xyz, r9.xyzx, icb[r5.y + 0].x\n  ushr r10.xyz, r10.xyzx, icb[r5.y + 0].x\n  movc r7.xyz, r7.xyzx, l(0x0000ffff,0x0000ffff,0x0000ffff,0), r9.xyzx\n  movc r8.yzw, r8.yyzw, l(0,0x0000ffff,0x0000ffff,0x0000ffff), r10.xxyz\n  movc r7.xyz, r2.xyzx, r7.xyzx, l(0,0,0,0)\n  movc r8.yzw, r3.yyzw, r8.yyzw, l(0,0,0,0)\n  movc r7.xyz, r6.yyyy, r7.xyzx, r2.xyzx\n  movc r8.yzw, r6.yyyy, r8.yyzw, r3.yyzw\n  ige r9.xyz, r2.xyzx, l(0, 0, 0, 0)\n  ige r10.xyz, r3.yzwy, l(0, 0, 0, 0)\n  imax r11.xyz, -r2.xyzx, r2.xyzx\n  imax r12.xyz, -r3.yzwy, r3.yzwy\n  ige r13.xyz, r11.xyzx, r13.wwww\n  ige r14.xyz, r12.xyzx, r13.wwww\n  ishl r15.xyz, r11.xyzx, l(15)\n  ishl r16.xyz, r12.xyzx, l(15)\n  iadd r15.xyz, r15.xyzx, l(0x00004000, 0x00004000, 0x00004000, 0)\n  iadd r16.xyz, r16.xyzx, l(0x00004000, 0x00004000, 0x00004000, 0)\n  ushr r15.xyz, r15.xyzx, r8.x\n  ushr r16.xyz, r16.xyzx, r8.x\n  movc r13.xyz, r13.xyzx, l(0x00007fff,0x00007fff,0x00007fff,0), r15.xyzx\n  movc r14.xyz, r14.xyzx, l(0x00007fff,0x00007fff,0x00007fff,0), r16.xyzx\n  movc r11.xyz, r11.xyzx, r13.xyzx, l(0,0,0,0)\n  movc r12.xyz, r12.xyzx, r14.xyzx, l(0,0,0,0)\n  ineg r13.xyz, r11.xyzx\n  ineg r14.xyz, r12.xyzx\n  movc r9.xyz, r9.xyzx, r11.xyzx, r13.xyzx\n  movc r10.xyz, r10.xyzx, r12.xyzx, r14.xyzx\n  movc r2.xyz, r6.zzzz, r9.xyzx, r2.xyzx\n  movc r3.yzw, r6.zzzz, r10.xxyz, r3.yyzw\n  movc r2.xyz, r6.xxxx, r7.xyzx, r2.xyzx\n  movc r3.yzw, r6.xxxx, r8.yyzw, r3.yyzw\n  ge r0.z, l(0.000000), r2.w\n  mov r4.w, l(0)\n  mov r5.y, l(0)\n  loop \n    uge r5.w, r5.y, l(16)\n    breakc_nz r5.w\n    iadd r5.w, r0.y, r5.y\n    ld_structured r7.xyz, r5.w, l(12), g0.xyzx\n    iadd r6.yzw, r1.xxyz, r7.xxyz\n    itof r6.yzw, r6.yyzw\n    dp3 r6.y, r4.xyzx, r6.yzwy\n    ge r6.z, l(0.000000), r6.y\n    or r6.z, r0.z, r6.z\n    lt r6.w, r6.y, r2.w\n    mul r6.y, r6.y, l(63.499989)\n    div r6.y, r6.y, r2.w\n    ftou r6.y, r6.y\n    movc r6.y, r6.w, icb[r6.y + 14].y, l(15)\n    movc r6.y, r6.z, l(0), r6.y\n    iadd r6.z, l(64), -icb[r6.y + 14].z\n    imul null, r7.xyz, r3.yzwy, icb[r6.y + 14].zzzz\n    imad r6.yzw, r2.xxyz, r6.zzzz, r7.xxyz\n    iadd r6.yzw, r6.yyzw, l(0, 32, 32, 32)\n    ishr r6.yzw, r6.yyzw, l(6)\n    imul null, r7.xyz, r6.yzwy, l(31, 31, 31, 0)\n    ishr r8.xyz, r7.xyzx, l(6)\n    ilt r9.xyz, r6.yzwy, l(0, 0, 0, 0)\n    imul null, r6.yzw, r6.yyzw, l(0, -31, -31, -31)\n    ishr r6.yzw, r6.yyzw, l(5)\n    ineg r6.yzw, r6.yyzw\n    ishr r7.xyz, r7.xyzx, l(5)\n    movc r6.yzw, r9.xxyz, r6.yyzw, r7.xxyz\n    ilt r7.xyz, r6.yzwy, l(0, 0, 0, 0)\n    ineg r9.xyz, r6.yzwy\n    or r9.xyz, r9.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n    movc r6.yzw, r7.xxyz, r9.xxyz, r6.yyzw\n    movc r6.yzw, r6.xxxx, r8.xxyz, r6.yyzw\n    and r7.xyzw, r6.yyzz, l(1023, 0x00007c00, 1023, 0x00007c00)\n    if_nz r7.y\n      ushr r7.y, r6.y, l(10)\n      and r7.y, r7.y, l(31)\n    else \n      if_nz r7.x\n        ishl r8.x, r7.x, l(1)\n        mov r8.y, r8.x\n        mov r7.y, l(0)\n        loop \n          and r8.z, r8.y, l(1024)\n          breakc_nz r8.z\n          iadd r7.y, r7.y, l(-1)\n          ishl r8.y, r8.y, l(1)\n        endloop \n        and r7.x, r8.y, l(1022)\n      else \n        mov r7.xy, l(0,-112,0,0)\n      endif \n    endif \n    ishl r8.xzw, r6.yyzw, l(16)\n    and r8.xzw, r8.xxzw, l(0x80000000, 0, 0x80000000, 0x80000000)\n    ishl r6.y, r7.y, l(23)\n    iadd r6.y, r6.y, l(0x38000000)\n    or r6.y, r6.y, r8.x\n    ishl r7.x, r7.x, l(13)\n    iadd r9.x, r6.y, r7.x\n    if_nz r7.w\n      ushr r6.y, r6.z, l(10)\n      and r6.y, r6.y, l(31)\n    else \n      if_nz r7.z\n        ishl r6.z, r7.z, l(1)\n        mov r7.x, r6.z\n        mov r6.y, l(0)\n        loop \n          and r7.w, r7.x, l(1024)\n          breakc_nz r7.w\n          iadd r6.y, r6.y, l(-1)\n          ishl r7.x, r7.x, l(1)\n        endloop \n        and r7.z, r7.x, l(1022)\n      else \n        mov r7.z, l(0)\n        mov r6.y, l(-112)\n      endif \n    endif \n    ishl r6.z, r6.y, l(23)\n    iadd r6.z, r6.z, l(0x38000000)\n    or r6.z, r6.z, r8.z\n    ishl r7.z, r7.z, l(13)\n    iadd r9.y, r6.z, r7.z\n    and r7.zw, r6.wwww, l(0, 0, 1023, 0x00007c00)\n    if_nz r7.w\n      ushr r6.z, r6.w, l(10)\n      and r6.z, r6.z, l(31)\n    else \n      if_nz r7.z\n        ishl r6.w, r7.z, l(1)\n        mov r7.w, r6.w\n        mov r6.z, l(0)\n        loop \n          and r8.x, r7.w, l(1024)\n          breakc_nz r8.x\n          iadd r6.z, r6.z, l(-1)\n          ishl r7.w, r7.w, l(1)\n        endloop \n        and r7.z, r7.w, l(1022)\n      else \n        mov r7.z, l(0)\n        mov r6.z, l(-112)\n      endif \n    endif \n    ishl r6.w, r6.z, l(23)\n    iadd r6.w, r6.w, l(0x38000000)\n    or r6.w, r6.w, r8.w\n    ishl r7.z, r7.z, l(13)\n    iadd r9.z, r6.w, r7.z\n    ld_structured r10.xyz, r5.w, l(24), g0.xyzx\n    add r8.xzw, r9.xxyz, -r10.xxyz\n    dp3 r5.w, r8.xzwx, r8.xzwx\n    add r4.w, r4.w, r5.w\n    iadd r5.y, r5.y, l(1)\n  endloop \n  movc r5.x, r3.x, l(100000002004087734272.000000), r4.w\n  store_structured g0.xy, vThreadIDInGroupFlattened.x, l(40), r5.xzxx\nendif \nsync_g_t\nif_nz r1.w\n  ld_structured r1.x, vThreadIDInGroupFlattened.x, l(40), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(2)\n  ld_structured r2.yz, r0.y, l(40), g0.xxyx\n  lt r0.z, r2.y, r1.x\n  if_nz r0.z\n    ld_structured r2.x, r0.y, l(40), g0.xxxx\n    store_structured g0.xy, vThreadIDInGroupFlattened.x, l(40), r2.xzxx\n  endif \nendif \nsync_g_t\nif_nz r0.w\n  ld_structured r1.x, vThreadIDInGroupFlattened.x, l(40), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(1)\n  ld_structured r2.yz, r0.y, l(40), g0.xxyx\n  lt r0.z, r2.y, r1.x\n  if_nz r0.z\n    ld_structured r2.x, r0.y, l(40), g0.xxxx\n    store_structured g0.xy, vThreadIDInGroupFlattened.x, l(40), r2.xzxx\n  endif \n  ld_structured r1.xy, vThreadIDInGroupFlattened.x, l(40), g0.xyxx\n  mov r1.zw, l(0,0,0,0)\n  store_structured u0.xyzw, r0.x, l(0), r1.xyzw\nendif \nret \n// Approximately 0 instruction slots used\n#endif\n\nconst BYTE BC6HEncode_TryModeG10CS[] =\n{\n     68,  88,  66,  67, 117, 150, \n     86, 154,  76,  44,  62, 174, \n    101,  82,  50,  59,  75, 244, \n     89,  47,   1,   0,   0,   0, \n     84,  63,   0,   0,   3,   0, \n      0,   0,  44,   0,   0,   0, \n     60,   0,   0,   0,  76,   0, \n      0,   0,  73,  83,  71,  78, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     79,  83,  71,  78,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  83,  72, \n     69,  88,   0,  63,   0,   0, \n     64,   0,   5,   0, 192,  15, \n      0,   0, 106,   8,   0,   1, \n     53,  24,   0,   0,  58,   1, \n      0,   0,  10,   0,   0,   0, \n      5,   0,   0,   0,   5,   0, \n      0,   0,   5,   0,   0,   0, \n      7,   0,   0,   0,   6,   0, \n      0,   0,   6,   0,   0,   0, \n      6,   0,   0,   0,  11,   0, \n      0,   0,   5,   0,   0,   0, \n      4,   0,   0,   0,   4,   0, \n      0,   0,  11,   0,   0,   0, \n      4,   0,   0,   0,   5,   0, \n      0,   0,   4,   0,   0,   0, \n     11,   0,   0,   0,   4,   0, \n      0,   0,   4,   0,   0,   0, \n      5,   0,   0,   0,   9,   0, \n      0,   0,   5,   0,   0,   0, \n      5,   0,   0,   0,   5,   0, \n      0,   0,   8,   0,   0,   0, \n      6,   0,   0,   0,   5,   0, \n      0,   0,   5,   0,   0,   0, \n      8,   0,   0,   0,   5,   0, \n      0,   0,   6,   0,   0,   0, \n      5,   0,   0,   0,   8,   0, \n      0,   0,   5,   0,   0,   0, \n      5,   0,   0,   0,   6,   0, \n      0,   0,   6,   0,   0,   0, \n      6,   0,   0,   0,   6,   0, \n      0,   0,   6,   0,   0,   0, \n     10,   0,   0,   0,  10,   0, \n      0,   0,  10,   0,   0,   0, \n     10,   0,   0,   0,  11,   0, \n      0,   0,   9,   0,   0,   0, \n      9,   0,   0,   0,   9,   0, \n      0,   0,  12,   0,   0,   0, \n      8,   0,   0,   0,   8,   0, \n      0,   0,   8,   0,   0,   0, \n     16,   0,   0,   0,   4,   0, \n      0,   0,   4,   0,   0,   0, \n      4,   0,   0,   0, 255, 255, \n    255, 255,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 255, 255, 255, 255, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n    255, 255, 255, 255,   0,   0, \n      0,   0,   9,   0,   0,   0, \n      0,   0,   0,   0, 255, 255, \n    255, 255,   1,   0,   0,   0, \n     13,   0,   0,   0,   0,   0, \n      0,   0, 255, 255, 255, 255, \n      1,   0,   0,   0,  17,   0, \n      0,   0,   0,   0,   0,   0, \n    255, 255, 255, 255,   1,   0, \n      0,   0,  21,   0,   0,   0, \n      0,   0,   0,   0, 255, 255, \n    255, 255,   1,   0,   0,   0, \n     26,   0,   0,   0,   0,   0, \n      0,   0, 255, 255, 255, 255, \n      2,   0,   0,   0,  30,   0, \n      0,   0,   0,   0,   0,   0, \n    255, 255, 255, 255,   2,   0, \n      0,   0,  34,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     38,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  43,   0, \n      0,   0,   0,   0,   0,   0, \n    255, 255, 255, 255,   2,   0, \n      0,   0,  47,   0,   0,   0, \n      0,   0,   0,   0, 255, 255, \n    255, 255,   3,   0,   0,   0, \n     51,   0,   0,   0,   0,   0, \n      0,   0, 255, 255, 255, 255, \n      3,   0,   0,   0,  55,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  60,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     64,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      9,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   9,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   9,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      9,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     11,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  11,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  11,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     11,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  12,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  12,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     12,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  12,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  13,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     13,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  13,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  13,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     14,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  14,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  14,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     14,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  89,   0,   0,   4, \n     70, 142,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     88,  24,   0,   4,   0, 112, \n     16,   0,   0,   0,   0,   0, \n     85,  85,   0,   0, 158,   0, \n      0,   4,   0, 224,  17,   0, \n      0,   0,   0,   0,  16,   0, \n      0,   0,  95,   0,   0,   2, \n      0,  64,   2,   0,  95,   0, \n      0,   2,  18,  16,   2,   0, \n    104,   0,   0,   2,  19,   0, \n      0,   0, 160,   0,   0,   5, \n      0, 240,  17,   0,   0,   0, \n      0,   0,  84,   0,   0,   0, \n     64,   0,   0,   0, 155,   0, \n      0,   4,  64,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   6, \n     18,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   6, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,  16,   2,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  30,   0,   0,   8, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10, 128, \n     32,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,   6, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  48,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16, 128, \n     65,   0,   0,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n     79,   0,   0,  10, 242,   0, \n     16,   0,   1,   0,   0,   0, \n    166,  10,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n     16,   0,   0,   0,   8,   0, \n      0,   0,   4,   0,   0,   0, \n      2,   0,   0,   0,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      1,   0,   0,   0,  78,   0, \n      0,   9, 130,   0,  16,   0, \n      0,   0,   0,   0,   0, 208, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,  26, 128, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  35,   0, \n      0,  11,  18,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16, 128,  65,   0,   0,   0, \n      0,   0,   0,   0,  26, 128, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,   1,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  85,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     54,   0,   0,   8, 194,   0, \n     16,   0,   2,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  45,   0,   0,   7, \n    242,   0,  16,   0,   2,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,  70, 126, \n     16,   0,   0,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   4,   0, \n      0,   0,   6,   5,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0, 255, 255, 255, 127, \n    255, 255, 127,   0, 255, 255, \n    255, 127, 255, 255, 127,   0, \n     79,   0,   0,  10,  50,   0, \n     16,   0,   2,   0,   0,   0, \n      2,  64,   0,   0, 255, 239, \n    255,  71, 255, 239, 255,  71, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 134,   0,  16,   0, \n      4,   0,   0,   0,  79,   0, \n      0,  10,  50,   0,  16,   0, \n      5,   0,   0,   0, 134,   0, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n    128,  56,   0,   0, 128,  56, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n    194,   0,  16,   0,   5,   0, \n      0,   0,   6,   8,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n     30,   0,   0,  11, 194,   0, \n     16,   0,   5,   0,   0,   0, \n    166,  14,  16, 128,  65,   0, \n      0,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n    113,   0,   0,   0, 113,   0, \n      0,   0,  30,   0,   0,  10, \n    162,   0,  16,   0,   4,   0, \n      0,   0,  86,  13,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 128,   0,   0,   0, \n      0,   0,   0,   0, 128,   0, \n     85,   0,   0,   7,  18,   0, \n     16,   0,   6,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  85,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,  10, \n     50,   0,  16,   0,   4,   0, \n      0,   0, 134,   0,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0, 200, \n      0,   0,   0, 200,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,   9,  50,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   0,  16,   0,   5,   0, \n      0,   0,  70,   0,  16,   0, \n      6,   0,   0,   0,  70,   0, \n     16,   0,   4,   0,   0,   0, \n     30,   0,   0,  10, 194,   0, \n     16,   0,   4,   0,   0,   0, \n      6,   4,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 255,  15,   0,   0, \n    255,  15,   0,   0,  85,   0, \n      0,   7,  50,   0,  16,   0, \n      4,   0,   0,   0,  70,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,   1,   0,   0,  10, \n     50,   0,  16,   0,   4,   0, \n      0,   0,  70,   0,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  50,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   0,  16,   0,   4,   0, \n      0,   0, 230,  10,  16,   0, \n      4,   0,   0,   0,  85,   0, \n      0,   7,  50,   0,  16,   0, \n      4,   0,   0,   0,  70,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,   1,   0,   0,  10, \n     50,   0,  16,   0,   4,   0, \n      0,   0,  70,   0,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,  12,  50,   0, \n     16,   0,   2,   0,   0,   0, \n     70,   0,  16,   0,   2,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  70,   0, \n     16,   0,   4,   0,   0,   0, \n     30,   0,   0,   7,  50,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   0,  16,   0,   3,   0, \n      0,   0,  70,   0,  16,   0, \n      2,   0,   0,   0,   1,   0, \n      0,  10,  50,   0,  16,   0, \n      2,   0,   0,   0, 166,  10, \n     16,   0,   2,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n    255, 127, 255, 255, 127,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  79,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 239, 255,  71,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     79,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0, 128,  56,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  30,   0,   0,   8, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16, 128, \n     65,   0,   0,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n    113,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n    128,   0,  85,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0, 200,  55,   0, \n      0,   9,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0, 255,  15, \n      0,   0,  85,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n      1,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  85,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n      1,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 127,   0,   0,  55,   0, \n      0,   9, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0, 255, 127, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   2,   0, \n      0,   0,   6,   5,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0, 255,   3,   0,   0, \n      0, 124,   0,   0, 255,   3, \n      0,   0,   0, 124,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     85,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,  18,   0,   0,   1, \n     31,   0,   4,   3,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  48,   0,   0,   1, \n      1,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   4,   0,   0,   3,   0, \n      4,   3,  10,   0,  16,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0, 255, 255, \n    255, 255,  41,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     22,   0,   0,   1,   1,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0, 254,   3, \n      0,   0,  18,   0,   0,   1, \n     54,   0,   0,   5,  18,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    144, 255, 255, 255,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     41,   0,   0,   7, 114,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,  56,  60,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  31,   0, \n      4,   3,  58,   0,  16,   0, \n      2,   0,   0,   0,  85,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n     18,   0,   0,   1,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  54,   0,   0,   5, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     48,   0,   0,   1,   1,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   4, \n      0,   0,   3,   0,   4,   3, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0, 255, 255, 255, 255, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,   1,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0, 254,   3,   0,   0, \n     18,   0,   0,   1,  54,   0, \n      0,   5,  66,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0, 144, 255, \n    255, 255,  21,   0,   0,   1, \n     21,   0,   0,   1,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,  56, \n     60,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,   0,   0,  10,  50,   0, \n     16,   0,   2,   0,   0,   0, \n    166,  10,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n    255,   3,   0,   0,   0, 124, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      2,   0,   0,   0,  85,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n     18,   0,   0,   1,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  54,   0,   0,   5, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     48,   0,   0,   1,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   4, \n      0,   0,   3,   0,   4,   3, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0, 255, 255, 255, 255, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,   1,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0, 254,   3,   0,   0, \n     18,   0,   0,   1,  54,   0, \n      0,   5,  18,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0, 144, 255, \n    255, 255,  21,   0,   0,   1, \n     21,   0,   0,   1,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,  56, \n     60,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n    168,   0,   0,   8, 114, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,  16,   0,   0,  10, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0, 208, 179,  89,  62, \n     89,  23,  55,  63, 152, 221, \n    147,  61,   0,   0,   0,   0, \n     32,   0,   0,   8, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42, 128,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  95,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     78,   0,   0,  11, 114,   0, \n     16,   0,   3,   0,   0,   0, \n      0, 208,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0,  31,   0, \n      0,   0,  31,   0,   0,   0, \n     31,   0,   0,   0,   0,   0, \n      0,   0,  79,   0,   0,  10, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     32,   0,   0,  10, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 123,   0,   0, 255, 123, \n      0,   0, 255, 123,   0,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  78,   0,   0,  11, \n    114,   0,  16,   0,   7,   0, \n      0,   0,   0, 208,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n     31,   0,   0,   0,  31,   0, \n      0,   0,  31,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,  12, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0, 224, 255, \n     15,   0, 224, 255,  15,   0, \n    224, 255,  15,   0,   0,   0, \n      0,   0,  78,   0,   0,  11, \n    114,   0,  16,   0,   4,   0, \n      0,   0,   0, 208,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n     31,   0,   0,   0,  31,   0, \n      0,   0,  31,   0,   0,   0, \n      0,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      1, 128, 255, 255,   1, 128, \n    255, 255,   1, 128, 255, 255, \n      0,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   2,   0,   0,   0, \n    246,  15,  16,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n    168,   0,   0,   8, 114, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     68,   0,   0,   0, 150,  15, \n     16,   0,   2,   0,   0,   0, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  31,   0,   4,   3, \n     26,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   8, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  76,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      8,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  76,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  49,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  31,   0,   4,   3, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0, 168,   0,   0,   8, \n    114, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0, 168,   0, \n      0,   8,  18, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     76,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     21,   0,   0,   1, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     80,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     80,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     49,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  64,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8, 114, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     64,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  80,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  21,   0,   0,   1, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  31,   0,   4,   3, \n     42,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   8, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  76,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      4,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  76,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  49,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  31,   0,   4,   3, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0, 168,   0,   0,   8, \n    114, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0, 168,   0, \n      0,   8,  18, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     76,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     21,   0,   0,   1, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     80,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     80,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     49,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  64,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8, 114, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     64,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  80,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  21,   0,   0,   1, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  31,   0,   4,   3, \n     58,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   8, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  76,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  76,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  49,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  31,   0,   4,   3, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0, 168,   0,   0,   8, \n    114, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0, 168,   0, \n      0,   8,  18, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     76,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     21,   0,   0,   1, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     80,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     80,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     49,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  64,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8, 114, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     64,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  80,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  21,   0,   0,   1, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  79,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   8,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  76,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  76,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  49,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n    168,   0,   0,   8, 114, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,  21,   0,   0,   1, \n    167,   0,   0,   8,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  80,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  80,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  49,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     64,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n    168,   0,   0,   8, 114, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  64,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,  21,   0,   0,   1, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  31,   0,   0,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  64,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   8, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  70,   2,  16, 128, \n     65,   0,   0,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  43,   0, \n      0,   5, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     16,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   8, 114,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16, 128,  65,   0,   0,   0, \n      2,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     43,   0,   0,   5, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,  16,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     49,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  29,   0, \n      0,   7,  18,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n     56,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    253, 255, 125,  66,  14,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  28,   0,   0,   5, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  79,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  32,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     31,   0,   4,   3,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      3,   0,   0,   0, 168,   0, \n      0,   8,  50, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     68,   0,   0,   0, 150,   5, \n     16,   0,   2,   0,   0,   0, \n     21,   0,   0,   1,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     64,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n     40,   0,   0,   5, 114,   0, \n     16,   0,   1,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n     43,   0,   0,   5, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,  16,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     30,   0,   0,  10,  98,   0, \n     16,   0,   5,   0,   0,   0, \n    166,  10,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,  11,   0,   0,   0, \n      0,   0,   0,   0,  32,   0, \n      0,  11,  50,   0,  16,   0, \n      6,   0,   0,   0, 166, 138, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,  95,   0,   0,   0, \n     96,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     31,   0,   4,   3,  10,   0, \n     16,   0,   6,   0,   0,   0, \n     33,   0,   0,   8,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10, 144, 144,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     55,   0,   0,  15, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,  15, 114,   0, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,   7,   0,   0,   0, \n    166,  10,  16,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n      8,   0,   0,   0, 166,  10, \n     16,   0,   0,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,  32,   0,   0,  10, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0, 255, 255,   0,   0, \n    255, 255,   0,   0, 255, 255, \n      0,   0,   0,   0,   0,   0, \n     32,   0,   0,  10, 114,   0, \n     16,   0,  10,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255,   0,   0, 255, 255, \n      0,   0, 255, 255,   0,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   8,  66,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     10, 144, 144,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  41,   0, \n      0,   8, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n     10, 144, 144,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     41,   0,   0,   8, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  10, 144, 144,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     42,   0,   0,   7, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n    166,  10,  16,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,  10,   0,   0,   0, \n    166,  10,  16,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,  18,   0, \n      0,   1,  33,   0,   0,   8, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10, 144, 144,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  55,   0,   0,  15, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  55,   0,   0,  15, \n    114,   0,  16,   0,  10,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,   9,   0, \n      0,   0, 166,  10,  16,   0, \n      0,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,  10,   0,   0,   0, \n    166,  10,  16,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,  33,   0, \n      0,  10, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  33,   0,   0,  10, \n    114,   0,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     32,   0,   0,  10, 114,   0, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,  32,   0, \n      0,  10, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   8, \n     66,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  10, 144, \n    144,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0, 255, 255, 255, 255, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     16,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     42,   0,   0,   7, 114,   0, \n     16,   0,  16,   0,   0,   0, \n     70,   2,  16,   0,  16,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n    246,  15,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n    246,  15,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n     16,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n     32,   0,   0,  10, 114,   0, \n     16,   0,  16,   0,   0,   0, \n     70,   2,  16,   0,   1,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,  32,   0, \n      0,  10, 114,   0,  16,   0, \n     17,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   8, \n    130,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16, 128, \n     65,   0,   0,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     18,   0,   0,   0,  70,   2, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 114,   0, \n     16,   0,  18,   0,   0,   0, \n     70,   2,  16,   0,  18,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  18,   0, \n      0,   0,  70,   2,  16,   0, \n     18,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  16,   0,   0,   0, \n     70,   2,  16,   0,  16,   0, \n      0,   0, 246,  15,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,  18,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,  17,   0, \n      0,   0, 246,  15,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  16,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,  10,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     21,   0,   0,   1,  30,   0, \n      0,   8, 114,   0,  16,   0, \n      2,   0,   0,   0,  70,   2, \n     16, 128,  65,   0,   0,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     55,   0,   0,  11, 114,   0, \n     16,   0,   2,   0,   0,   0, \n      6, 144, 208,   0,  14,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,  33,   0,   0,  10, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,  11, 242,   0, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255,  70, 158, 144,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   9,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     33,   0,   0,   7, 226,   0, \n     16,   0,   8,   0,   0,   0, \n      6,   9,  16,   0,   2,   0, \n      0,   0,  86,  14,  16,   0, \n      9,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n     34,   0,   0,   7, 114,   0, \n     16,   0,  10,   0,   0,   0, \n    150,   7,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n    150,   7,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,  11,   0,   0,   0, \n     10,   0,  16,   0,  11,   0, \n      0,   0,  60,   0,   0,   7, \n     18,   0,  16,   0,  11,   0, \n      0,   0,  42,   0,  16,   0, \n     11,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   8,  18,   0, \n     16,   0,  12,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  10, 144, 144,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  41,   0,   0,   8, \n     34,   0,  16,   0,  12,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  26, 144, \n    144,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   8,  66,   0,  16,   0, \n     12,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42, 144, 144,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     41,   0,   0,   8, 130,   0, \n     16,   0,  12,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  58, 144, 144,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,  10, \n    242,   0,  16,   0,  12,   0, \n      0,   0,  70,  14,  16,   0, \n     12,   0,   0,   0,   2,  64, \n      0,   0, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n      1,   0,   0,   7, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,   6,   0,  16,   0, \n     12,   0,   0,   0,  30,   0, \n      0,  10, 242,   0,  16,   0, \n     13,   0,   0,   0, 150,   3, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255,  55,   0,   0,   9, \n    226,   0,  16,   0,   8,   0, \n      0,   0,  86,  14,  16,   0, \n      8,   0,   0,   0,   6,   9, \n     16,   0,  13,   0,   0,   0, \n      6,   9,  16,   0,   2,   0, \n      0,   0,   1,   0,   0,   7, \n    226,   0,  16,   0,  12,   0, \n      0,   0,   6,   9,  16,   0, \n      2,   0,   0,   0,  86,  14, \n     16,   0,  12,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  10,   0,   0,   0, \n     70,   2,  16,   0,  10,   0, \n      0,   0, 150,   7,  16,   0, \n      9,   0,   0,   0, 150,   7, \n     16,   0,  12,   0,   0,   0, \n     55,   0,   0,   9, 226,   0, \n     16,   0,  11,   0,   0,   0, \n      6,   9,  16,   0,   3,   0, \n      0,   0,  86,  14,  16,   0, \n      8,   0,   0,   0,   6,   9, \n     16,   0,  10,   0,   0,   0, \n      1,   0,   0,   7, 226,   0, \n     16,   0,   3,   0,   0,   0, \n      6,   9,  16,   0,   2,   0, \n      0,   0,   6,   0,  16,   0, \n     12,   0,   0,   0,  54,   0, \n      0,   5,  18,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,  11, 242,   0, \n     16,   0,   3,   0,   0,   0, \n      6, 144, 208,   0,  14,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  70,  14, \n     16,   0,  11,   0,   0,   0, \n     70,  14,  16,   0,   3,   0, \n      0,   0,   1,   0,   0,   7, \n    114,   0,  16,   0,   2,   0, \n      0,   0,   6,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      1,   0,   0,   7, 226,   0, \n     16,   0,   8,   0,   0,   0, \n      6,   9,  16,   0,   7,   0, \n      0,   0, 246,  15,  16,   0, \n     13,   0,   0,   0,  30,   0, \n      0,   8, 226,   0,  16,   0, \n      8,   0,   0,   0,   6,   0, \n     16, 128,  65,   0,   0,   0, \n      9,   0,   0,   0,  86,  14, \n     16,   0,   8,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   2,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0, 150,   7,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   2,   0,   0,   0, \n     86,   5,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n     60,   0,   0,   9,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  10, 144, 208,   0, \n     14,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,   0,   0,   7, 226,   0, \n     16,   0,   6,   0,   0,   0, \n     86,  14,  16,   0,   9,   0, \n      0,   0,  86,  14,  16,   0, \n      3,   0,   0,   0,   1,   0, \n      0,   7, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n    150,   7,  16,   0,   3,   0, \n      0,   0,  30,   0,   0,   8, \n    114,   0,  16,   0,   7,   0, \n      0,   0, 150,   7,  16, 128, \n     65,   0,   0,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n      6,   0,   0,   0,  86,  14, \n     16,   0,   6,   0,   0,   0, \n      6,   9,  16,   0,   7,   0, \n      0,   0,  86,  14,  16,   0, \n      3,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n      3,   0,   0,   0, 166,  10, \n     16,   0,   0,   0,   0,   0, \n     86,  14,  16,   0,   6,   0, \n      0,   0,  86,  14,  16,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7, 226,   0,  16,   0, \n      6,   0,   0,   0,   6,   9, \n     16,   0,   2,   0,   0,   0, \n     86,  14,  16,   0,   3,   0, \n      0,   0,  55,   0,   0,  11, \n    226,   0,  16,   0,   3,   0, \n      0,   0,   6, 144, 208,   0, \n     14,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     86,  14,  16,   0,   6,   0, \n      0,   0,  86,  14,  16,   0, \n      3,   0,   0,   0,  79,   0, \n      0,  11,  98,   0,  16,   0, \n      6,   0,   0,   0,   6, 144, \n    144,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,  16,   0, \n      0,   0,   0,   0,   0,   0, \n     32,   0,   0,   7, 114,   0, \n     16,   0,   7,   0,   0,   0, \n      6,   0,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,  32,   0, \n      0,   7, 226,   0,  16,   0, \n      8,   0,   0,   0,   6,   0, \n     16,   0,  12,   0,   0,   0, \n     86,  14,  16,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  10,   0,   0,   0, \n    150,   7,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  30,   0, \n      0,  10, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,  10, \n    114,   0,  16,   0,  10,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     85,   0,   0,   8, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  10, 144, 144,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  85,   0,   0,   8, \n    114,   0,  16,   0,  10,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,  10, 144, \n    144,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  55,   0, \n      0,  12, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n      0,   0, 255, 255,   0,   0, \n    255, 255,   0,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  55,   0, \n      0,  12, 226,   0,  16,   0, \n      8,   0,   0,   0,  86,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0, 255, 255,   0,   0, \n    255, 255,   0,   0, 255, 255, \n      0,   0,   6,   9,  16,   0, \n     10,   0,   0,   0,  55,   0, \n      0,  12, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,  12, 226,   0,  16,   0, \n      8,   0,   0,   0,  86,  14, \n     16,   0,   3,   0,   0,   0, \n     86,  14,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      7,   0,   0,   0,  86,   5, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n      8,   0,   0,   0,  86,   5, \n     16,   0,   6,   0,   0,   0, \n     86,  14,  16,   0,   8,   0, \n      0,   0,  86,  14,  16,   0, \n      3,   0,   0,   0,  33,   0, \n      0,  10, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  33,   0,   0,  10, \n    114,   0,  16,   0,  10,   0, \n      0,   0, 150,   7,  16,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     36,   0,   0,   8, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16, 128,  65,   0, \n      0,   0,   2,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,  36,   0,   0,   8, \n    114,   0,  16,   0,  12,   0, \n      0,   0, 150,   7,  16, 128, \n     65,   0,   0,   0,   3,   0, \n      0,   0, 150,   7,  16,   0, \n      3,   0,   0,   0,  33,   0, \n      0,   7, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n    246,  15,  16,   0,  13,   0, \n      0,   0,  33,   0,   0,   7, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0, 246,  15, \n     16,   0,  13,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     16,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  30,   0,   0,  10, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0,  64,   0,   0,   0,  64, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,  10, 114,   0, \n     16,   0,  16,   0,   0,   0, \n     70,   2,  16,   0,  16,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  64,   0,   0,   0,  64, \n      0,   0,   0,  64,   0,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,  16,   0, \n      0,   0,  70,   2,  16,   0, \n     16,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,  70,   2, \n     16,   0,  16,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n     13,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     40,   0,   0,   5, 114,   0, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n     13,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,  10,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      2,   0,   0,   0, 166,  10, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n      3,   0,   0,   0, 166,  10, \n     16,   0,   6,   0,   0,   0, \n      6,   9,  16,   0,  10,   0, \n      0,   0,  86,  14,  16,   0, \n      3,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      2,   0,   0,   0,   6,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n      3,   0,   0,   0,   6,   0, \n     16,   0,   6,   0,   0,   0, \n     86,  14,  16,   0,   8,   0, \n      0,   0,  86,  14,  16,   0, \n      3,   0,   0,   0,  29,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     48,   0,   0,   1,  80,   0, \n      0,   7, 130,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   3,   0,   4,   3, \n     58,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   7, 226,   0, \n     16,   0,   6,   0,   0,   0, \n      6,   9,  16,   0,   1,   0, \n      0,   0,   6,   9,  16,   0, \n      7,   0,   0,   0,  43,   0, \n      0,   5, 226,   0,  16,   0, \n      6,   0,   0,   0,  86,  14, \n     16,   0,   6,   0,   0,   0, \n     16,   0,   0,   7,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0, 150,   7,  16,   0, \n      6,   0,   0,   0,  29,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n     49,   0,   0,   7, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  56,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0, 253, 255, \n    125,  66,  14,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     28,   0,   0,   5,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  55,   0,   0,  11, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  26, 144, \n    208,   0,  14,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  55,   0, \n      0,   9,  34,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  30,   0, \n      0,  10,  66,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  64,   0,   0,   0, \n     42, 144, 208, 128,  65,   0, \n      0,   0,  14,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  38,   0,   0,  10, \n      0, 208,   0,   0, 114,   0, \n     16,   0,   7,   0,   0,   0, \n    150,   7,  16,   0,   3,   0, \n      0,   0, 166, 154, 208,   0, \n     14,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n     35,   0,   0,   9, 226,   0, \n     16,   0,   6,   0,   0,   0, \n      6,   9,  16,   0,   2,   0, \n      0,   0, 166,  10,  16,   0, \n      6,   0,   0,   0,   6,   9, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,  10, 226,   0, \n     16,   0,   6,   0,   0,   0, \n     86,  14,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,  32,   0, \n      0,   0,  32,   0,   0,   0, \n     32,   0,   0,   0,  42,   0, \n      0,   7, 226,   0,  16,   0, \n      6,   0,   0,   0,  86,  14, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  38,   0,   0,  11, \n      0, 208,   0,   0, 114,   0, \n     16,   0,   7,   0,   0,   0, \n    150,   7,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n     31,   0,   0,   0,  31,   0, \n      0,   0,  31,   0,   0,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  34,   0,   0,  10, \n    114,   0,  16,   0,   9,   0, \n      0,   0, 150,   7,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     38,   0,   0,  11,   0, 208, \n      0,   0, 226,   0,  16,   0, \n      6,   0,   0,   0,  86,  14, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0, 225, 255, 255, 255, \n    225, 255, 255, 255, 225, 255, \n    255, 255,  42,   0,   0,   7, \n    226,   0,  16,   0,   6,   0, \n      0,   0,  86,  14,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     40,   0,   0,   5, 226,   0, \n     16,   0,   6,   0,   0,   0, \n     86,  14,  16,   0,   6,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     55,   0,   0,   9, 226,   0, \n     16,   0,   6,   0,   0,   0, \n      6,   9,  16,   0,   9,   0, \n      0,   0,  86,  14,  16,   0, \n      6,   0,   0,   0,   6,   9, \n     16,   0,   7,   0,   0,   0, \n     34,   0,   0,  10, 114,   0, \n     16,   0,   7,   0,   0,   0, \n    150,   7,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n      9,   0,   0,   0, 150,   7, \n     16,   0,   6,   0,   0,   0, \n     60,   0,   0,  10, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n      6,   0,   0,   0,   6,   9, \n     16,   0,   7,   0,   0,   0, \n      6,   9,  16,   0,   9,   0, \n      0,   0,  86,  14,  16,   0, \n      6,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n      6,   0,   0,   0,   6,   0, \n     16,   0,   6,   0,   0,   0, \n      6,   9,  16,   0,   8,   0, \n      0,   0,  86,  14,  16,   0, \n      6,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      7,   0,   0,   0,  86,  10, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0, 255,   3, \n      0,   0,   0, 124,   0,   0, \n    255,   3,   0,   0,   0, 124, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   7,   0, \n      0,   0,  85,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n      1,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,  18,   0, \n      0,   1,  31,   0,   4,   3, \n     10,   0,  16,   0,   7,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   8,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     54,   0,   0,   5,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  54,   0,   0,   5, \n     34,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  48,   0, \n      0,   1,   1,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,   0,   4,   0,   0, \n      3,   0,   4,   3,  42,   0, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  22,   0,   0,   1, \n      1,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n    254,   3,   0,   0,  18,   0, \n      0,   1,  54,   0,   0,   8, \n     50,   0,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0, 144, 255, \n    255, 255,   0,   0,   0,   0, \n      0,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     41,   0,   0,   7, 210,   0, \n     16,   0,   8,   0,   0,   0, \n     86,  14,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,   0, \n      0,  10, 210,   0,  16,   0, \n      8,   0,   0,   0,   6,  14, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,   0, 128,   0,   0, \n      0, 128,  41,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,  56,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  31,   0, \n      4,   3,  58,   0,  16,   0, \n      7,   0,   0,   0,  85,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,   1,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n     18,   0,   0,   1,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  54,   0,   0,   5, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     48,   0,   0,   1,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   0,   4, \n      0,   0,   3,   0,   4,   3, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0, 255, 255, 255, 255, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,   1,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0, 254,   3,   0,   0, \n     18,   0,   0,   1,  54,   0, \n      0,   5,  66,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   5,  34,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0, 144, 255, \n    255, 255,  21,   0,   0,   1, \n     21,   0,   0,   1,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,  56, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   7,   0,   0,   0, \n    246,  15,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 255,   3,   0,   0, \n      0, 124,   0,   0,  31,   0, \n      4,   3,  58,   0,  16,   0, \n      7,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n     18,   0,   0,   1,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   5,  66,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     48,   0,   0,   1,   1,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   0,   4, \n      0,   0,   3,   0,   4,   3, \n     10,   0,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0, 255, 255, 255, 255, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,   1,   0,   0,   7, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0, 254,   3,   0,   0, \n     18,   0,   0,   1,  54,   0, \n      0,   5,  66,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   5,  66,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0, 144, 255, \n    255, 255,  21,   0,   0,   1, \n     21,   0,   0,   1,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,  56, \n     60,   0,   0,   7, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,  10,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n      0,   0,   0,   8, 210,   0, \n     16,   0,   8,   0,   0,   0, \n      6,   9,  16,   0,   9,   0, \n      0,   0,   6,   9,  16, 128, \n     65,   0,   0,   0,  10,   0, \n      0,   0,  16,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0, 134,   3,  16,   0, \n      8,   0,   0,   0, 134,   3, \n     16,   0,   8,   0,   0,   0, \n      0,   0,   0,   7, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  22,   0,   0,   1, \n     55,   0,   0,   9,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n    236, 120, 173,  96,  58,   0, \n     16,   0,   4,   0,   0,   0, \n    168,   0,   0,   8,  50, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  40,   0,   0,   0, \n    134,   0,  16,   0,   5,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  58,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     40,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  98,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     40,   0,   0,   0,   6, 241, \n     17,   0,   0,   0,   0,   0, \n     49,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  40,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8,  50, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     40,   0,   0,   0, 134,   0, \n     16,   0,   2,   0,   0,   0, \n     21,   0,   0,   1,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   8,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  40,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     98,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  40,   0,   0,   0, \n      6, 241,  17,   0,   0,   0, \n      0,   0,  49,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     40,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    168,   0,   0,   8,  50, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  40,   0,   0,   0, \n    134,   0,  16,   0,   2,   0, \n      0,   0,  21,   0,   0,   1, \n    167,   0,   0,   8,  50,   0, \n     16,   0,   1,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  40,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  54,   0,   0,   8, \n    194,   0,  16,   0,   1,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   9, 242, 224,  17,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  70,  14,  16,   0, \n      1,   0,   0,   0,  21,   0, \n      0,   1,  62,   0,   0,   1\n};\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/Shaders/Compiled/BC6HEncode_TryModeLE10CS.inc",
    "content": "#if 0\n//\n// Generated by Microsoft (R) D3D Shader Disassembler\n//\n//\n// Input signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Input\n//\n// Output signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Output\ncs_4_0\ndcl_globalFlags refactoringAllowed\ndcl_immediateConstantBuffer { { 0x0000cccc, 15, -1, 0},\n                              { 0x00008888, 15, -1, 9},\n                              { 0x0000eeee, 15, -1, 18},\n                              { 0x0000ecc8, 15, -1, 27},\n                              { 0x0000c880, 15, -1, 37},\n                              { 0x0000feec, 15, -1, 46},\n                              { 0x0000fec8, 15, -1, 55},\n                              { 0x0000ec80, 15, -1, 64},\n                              { 0x0000c800, 15, -1, 0},\n                              { 0x0000ffec, 15, 0, 0},\n                              { 0x0000fe80, 15, 0, 0},\n                              { 0x0000e800, 15, -1, 0},\n                              { 0x0000ffe8, 15, -1, 0},\n                              { 0x0000ff00, 15, -1, 0},\n                              { 0x0000fff0, 15, 0, 0},\n                              { 0x0000f000, 15, 0, 0},\n                              { 0x0000f710, 15, 0, 0},\n                              { 142, 2, 0, 0},\n                              { 0x00007100, 8, 0, 0},\n                              { 2254, 2, 0, 0},\n                              { 140, 2, 0, 0},\n                              { 0x00007310, 8, 0, 0},\n                              { 0x00003100, 8, 0, 0},\n                              { 0x00008cce, 15, 0, 0},\n                              { 2188, 2, 0, 0},\n                              { 0x00003110, 8, 0, 0},\n                              { 0x00006666, 2, 0, 0},\n                              { 0x0000366c, 2, 0, 0},\n                              { 6120, 8, 0, 0},\n                              { 4080, 8, 0, 0},\n                              { 0x0000718e, 2, 0, 0},\n                              { 0x0000399c, 2, 0, 0},\n                              { 10, 5, 5, 5},\n                              { 7, 6, 6, 6},\n                              { 11, 5, 4, 4},\n                              { 11, 4, 5, 4},\n                              { 11, 4, 4, 5},\n                              { 9, 5, 5, 5},\n                              { 8, 6, 5, 5},\n                              { 8, 5, 6, 5},\n                              { 8, 5, 5, 6},\n                              { 6, 6, 6, 6},\n                              { 10, 10, 10, 10},\n                              { 11, 9, 9, 9},\n                              { 12, 8, 8, 8},\n                              { 16, 4, 4, 4},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 7, 0, 0, 0},\n                              { 7, 0, 0, 0},\n                              { 7, 0, 0, 0},\n                              { 7, 0, 0, 0} }\ndcl_constantbuffer CB0[2], immediateIndexed\ndcl_resource_texture2d (float,float,float,float) t0\ndcl_resource_structured t1, 16\ndcl_uav_structured u0, 16\ndcl_input vThreadIDInGroupFlattened\ndcl_input vThreadGroupID.x\ndcl_temps 24\ndcl_indexableTemp x0[6], 4\ndcl_indexableTemp x1[2], 4\ndcl_tgsm_structured g0, 84, 64\ndcl_thread_group 64, 1, 1\nushr r0.x, vThreadIDInGroupFlattened.x, l(5)\nishl r0.y, vThreadGroupID.x, l(1)\niadd r0.y, r0.y, cb0[1].x\niadd r0.x, r0.x, r0.y\nand r0.y, vThreadIDInGroupFlattened.x, l(32)\niadd r1.z, -r0.y, vThreadIDInGroupFlattened.x\nult r2.xyzw, r1.zzzz, l(16, 32, 8, 4)\nif_nz r2.x\n  udiv r0.z, null, r0.x, cb0[0].y\n  imad r0.w, -r0.z, cb0[0].y, r0.x\n  ishl r0.w, r0.w, l(2)\n  ishl r0.z, r0.z, l(2)\n  and r1.w, r1.z, l(3)\n  iadd r3.x, r0.w, r1.w\n  ushr r0.w, r1.z, l(2)\n  iadd r3.y, r0.w, r0.z\n  mov r3.zw, l(0,0,0,0)\n  ld r3.xyzw, r3.xyzw, t0.xyzw\n  ushr r4.xyz, r3.xyzx, l(16)\n  and r4.xyz, r4.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n  and r5.xyzw, r3.xxyy, l(0x7fffffff, 0x007fffff, 0x7fffffff, 0x007fffff)\n  ult r0.zw, l(0, 0, 0x47ffefff, 0x47ffefff), r5.xxxz\n  ult r3.xy, r5.xzxx, l(0x38800000, 0x38800000, 0, 0)\n  ushr r6.xy, r5.xzxx, l(23)\n  iadd r6.xy, -r6.xyxx, l(113, 113, 0, 0)\n  iadd r5.yw, r5.yyyw, l(0, 0x00800000, 0, 0x00800000)\n  ushr r7.x, r5.y, r6.x\n  ushr r7.y, r5.w, r6.y\n  iadd r5.xy, r5.xzxx, l(0xc8000000, 0xc8000000, 0, 0)\n  movc r3.xy, r3.xyxx, r7.xyxx, r5.xyxx\n  iadd r5.xy, r3.xyxx, l(4095, 4095, 0, 0)\n  ushr r3.xy, r3.xyxx, l(13)\n  and r3.xy, r3.xyxx, l(1, 1, 0, 0)\n  iadd r3.xy, r3.xyxx, r5.xyxx\n  ushr r3.xy, r3.xyxx, l(13)\n  and r3.xy, r3.xyxx, l(0x00007fff, 0x00007fff, 0, 0)\n  movc r0.zw, r0.zzzw, l(0,0,0x00007fff,0x00007fff), r3.xxxy\n  iadd r5.xy, r4.xyxx, r0.zwzz\n  and r0.zw, r3.zzzz, l(0, 0, 0x7fffffff, 0x007fffff)\n  ult r1.w, l(0x47ffefff), r0.z\n  ult r3.x, r0.z, l(0x38800000)\n  ushr r3.y, r0.z, l(23)\n  iadd r3.y, -r3.y, l(113)\n  iadd r0.w, r0.w, l(0x00800000)\n  ushr r0.w, r0.w, r3.y\n  iadd r0.z, r0.z, l(0xc8000000)\n  movc r0.z, r3.x, r0.w, r0.z\n  iadd r0.w, r0.z, l(4095)\n  ushr r0.z, r0.z, l(13)\n  and r0.z, r0.z, l(1)\n  iadd r0.z, r0.z, r0.w\n  ushr r0.z, r0.z, l(13)\n  and r0.z, r0.z, l(0x00007fff)\n  movc r0.z, r1.w, l(0x00007fff), r0.z\n  iadd r5.z, r4.z, r0.z\n  and r3.xyzw, r5.xxyy, l(1023, 0x00007c00, 1023, 0x00007c00)\n  if_nz r3.y\n    ushr r0.z, r5.x, l(10)\n    and r0.z, r0.z, l(31)\n  else \n    if_nz r3.x\n      ishl r0.w, r3.x, l(1)\n      mov r1.w, r0.w\n      mov r0.z, l(0)\n      loop \n        and r3.y, r1.w, l(1024)\n        breakc_nz r3.y\n        iadd r0.z, r0.z, l(-1)\n        ishl r1.w, r1.w, l(1)\n      endloop \n      and r3.x, r1.w, l(1022)\n    else \n      mov r3.x, l(0)\n      mov r0.z, l(-112)\n    endif \n  endif \n  ishl r4.xyz, r5.xyzx, l(16)\n  and r4.xyz, r4.xyzx, l(0x80000000, 0x80000000, 0x80000000, 0)\n  ishl r0.z, r0.z, l(23)\n  iadd r0.z, r0.z, l(0x38000000)\n  or r0.z, r0.z, r4.x\n  ishl r0.w, r3.x, l(13)\n  iadd r6.x, r0.w, r0.z\n  if_nz r3.w\n    ushr r0.z, r5.y, l(10)\n    and r0.z, r0.z, l(31)\n  else \n    if_nz r3.z\n      ishl r0.w, r3.z, l(1)\n      mov r1.w, r0.w\n      mov r0.z, l(0)\n      loop \n        and r3.x, r1.w, l(1024)\n        breakc_nz r3.x\n        iadd r0.z, r0.z, l(-1)\n        ishl r1.w, r1.w, l(1)\n      endloop \n      and r3.z, r1.w, l(1022)\n    else \n      mov r3.z, l(0)\n      mov r0.z, l(-112)\n    endif \n  endif \n  ishl r0.z, r0.z, l(23)\n  iadd r0.z, r0.z, l(0x38000000)\n  or r0.z, r0.z, r4.y\n  ishl r0.w, r3.z, l(13)\n  iadd r6.y, r0.w, r0.z\n  and r0.zw, r5.zzzz, l(0, 0, 1023, 0x00007c00)\n  if_nz r0.w\n    ushr r0.w, r5.z, l(10)\n    and r0.w, r0.w, l(31)\n  else \n    if_nz r0.z\n      ishl r1.w, r0.z, l(1)\n      mov r3.x, r1.w\n      mov r0.w, l(0)\n      loop \n        and r3.y, r3.x, l(1024)\n        breakc_nz r3.y\n        iadd r0.w, r0.w, l(-1)\n        ishl r3.x, r3.x, l(1)\n      endloop \n      and r0.z, r3.x, l(1022)\n    else \n      mov r0.zw, l(0,0,0,-112)\n    endif \n  endif \n  ishl r0.w, r0.w, l(23)\n  iadd r0.w, r0.w, l(0x38000000)\n  or r0.w, r0.w, r4.z\n  ishl r0.z, r0.z, l(13)\n  iadd r6.z, r0.z, r0.w\n  dp3 r6.w, r6.xyzx, l(0.212600, 0.715200, 0.072200, 0.000000)\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(24), r6.xyzw\n  ieq r0.z, cb0[0].z, l(95)\n  ishl r3.xyz, r5.xyzx, l(6)\n  udiv r3.xyz, null, r3.xyzx, l(31, 31, 31, 0)\n  ult r4.xyz, r5.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n  ieq r6.xyz, r5.xyzx, l(0x00007bff, 0x00007bff, 0x00007bff, 0)\n  ishl r5.xyz, r5.xyzx, l(5)\n  udiv r7.xyz, null, r5.xyzx, l(31, 31, 31, 0)\n  movc r7.xyz, r6.xyzx, l(0x00007fff,0x00007fff,0x00007fff,0), r7.xyzx\n  and r5.xyz, r5.xyzx, l(0x000fffe0, 0x000fffe0, 0x000fffe0, 0)\n  udiv r5.xyz, null, r5.xyzx, l(31, 31, 31, 0)\n  ineg r5.xyz, r5.xyzx\n  movc r5.xyz, r6.xyzx, l(0xffff8001,0xffff8001,0xffff8001,0), r5.xyzx\n  movc r4.xyz, r4.xyzx, r7.xyzx, r5.xyzx\n  movc r3.xyz, r0.zzzz, r3.xyzx, r4.xyzx\n  store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(12), r3.xyzx\nendif \nsync_g_t\nif_nz r2.y\n  mov x0[0].x, l(0x7fffffff)\n  mov x0[1].x, l(0x7fffffff)\n  mov x0[2].x, l(0x7fffffff)\n  mov x0[0].y, l(-0.000000)\n  mov x0[1].y, l(-0.000000)\n  mov x0[2].y, l(-0.000000)\n  mov x0[3].x, l(0x7fffffff)\n  mov x0[4].x, l(0x7fffffff)\n  mov x0[5].x, l(0x7fffffff)\n  mov x0[3].y, l(-0.000000)\n  mov x0[4].y, l(-0.000000)\n  mov x0[5].y, l(-0.000000)\n  mov x1[0].x, l(340282346638528859811704183484516925440.000000)\n  mov x1[0].y, l(-340282346638528859811704183484516925440.000000)\n  mov x1[1].x, l(340282346638528859811704183484516925440.000000)\n  mov x1[1].y, l(-340282346638528859811704183484516925440.000000)\n  mov r0.z, l(0)\n  loop \n    uge r0.w, r0.z, l(16)\n    breakc_nz r0.w\n    iadd r0.w, r0.z, r0.y\n    ld_structured r3.xyz, r0.w, l(12), g0.xyzx\n    ld_structured r4.x, r0.w, l(36), g0.xxxx\n    ushr r0.w, icb[r1.z + 0].x, r0.z\n    and r0.w, r0.w, l(1)\n    if_nz r0.w\n      mov r0.w, x1[1].x\n      lt r1.w, r4.x, r0.w\n      mov r2.y, x0[3].x\n      movc r2.y, r1.w, r3.x, r2.y\n      mov x0[3].x, r2.y\n      mov r2.y, x0[4].x\n      movc r2.y, r1.w, r3.y, r2.y\n      mov x0[4].x, r2.y\n      mov r2.y, x0[5].x\n      movc r2.y, r1.w, r3.z, r2.y\n      mov x0[5].x, r2.y\n      movc r0.w, r1.w, r4.x, r0.w\n      mov x1[1].x, r0.w\n      mov r0.w, x1[1].y\n      lt r1.w, r0.w, r4.x\n      mov r2.y, x0[3].y\n      movc r2.y, r1.w, r3.x, r2.y\n      mov x0[3].y, r2.y\n      mov r2.y, x0[4].y\n      movc r2.y, r1.w, r3.y, r2.y\n      mov x0[4].y, r2.y\n      mov r2.y, x0[5].y\n      movc r2.y, r1.w, r3.z, r2.y\n      mov x0[5].y, r2.y\n      movc r0.w, r1.w, r4.x, r0.w\n      mov x1[1].y, r0.w\n    else \n      mov r0.w, x1[0].x\n      lt r1.w, r4.x, r0.w\n      mov r2.y, x0[0].x\n      movc r2.y, r1.w, r3.x, r2.y\n      mov x0[0].x, r2.y\n      mov r2.y, x0[1].x\n      movc r2.y, r1.w, r3.y, r2.y\n      mov x0[1].x, r2.y\n      mov r2.y, x0[2].x\n      movc r2.y, r1.w, r3.z, r2.y\n      mov x0[2].x, r2.y\n      movc r0.w, r1.w, r4.x, r0.w\n      mov x1[0].x, r0.w\n      mov r0.w, x1[0].y\n      lt r1.w, r0.w, r4.x\n      mov r2.y, x0[0].y\n      movc r2.y, r1.w, r3.x, r2.y\n      mov x0[0].y, r2.y\n      mov r2.y, x0[1].y\n      movc r2.y, r1.w, r3.y, r2.y\n      mov x0[1].y, r2.y\n      mov r2.y, x0[2].y\n      movc r2.y, r1.w, r3.z, r2.y\n      mov x0[2].y, r2.y\n      movc r0.w, r1.w, r4.x, r0.w\n      mov x1[0].y, r0.w\n    endif \n    iadd r0.z, r0.z, l(1)\n  endloop \n  mov r3.x, x0[0].y\n  mov r3.y, x0[1].y\n  mov r3.z, x0[2].y\n  mov r0.z, x0[0].x\n  mov r0.w, x0[1].x\n  mov r1.w, x0[2].x\n  ineg r4.xy, r0.zwzz\n  ineg r4.z, r1.w\n  iadd r5.xyz, r3.xyzx, r4.xyzx\n  itof r5.xyz, r5.xyzx\n  dp3 r2.y, r5.xyzx, r5.xyzx\n  ld_structured r6.xyz, r0.y, l(12), g0.xyzx\n  iadd r4.xyz, r4.xyzx, r6.xyzx\n  itof r4.xyz, r4.xyzx\n  dp3 r3.w, r5.xyzx, r4.xyzx\n  lt r4.x, l(0.000000), r2.y\n  ge r4.y, r3.w, l(0.000000)\n  and r4.x, r4.y, r4.x\n  mul r3.w, r3.w, l(63.499989)\n  div r3.w, r3.w, r2.y\n  ftou r3.w, r3.w\n  ult r3.w, l(32), r3.w\n  and r3.w, r3.w, r4.x\n  movc r4.xyz, r3.wwww, -r5.xyzx, r5.xyzx\n  movc r5.xy, r3.wwww, r3.xyxx, r0.zwzz\n  movc r5.z, r3.w, r3.z, r1.w\n  movc r6.xy, r3.wwww, r0.zwzz, r3.xyxx\n  movc r6.z, r3.w, r1.w, r3.z\n  mov r3.x, x0[3].y\n  mov r3.y, x0[4].y\n  mov r3.z, x0[5].y\n  mov r0.z, x0[3].x\n  mov r0.w, x0[4].x\n  mov r1.w, x0[5].x\n  ineg r7.xy, r0.zwzz\n  ineg r7.z, r1.w\n  iadd r8.xyz, r3.xyzx, r7.xyzx\n  itof r8.xyz, r8.xyzx\n  dp3 r3.w, r8.xyzx, r8.xyzx\n  iadd r4.w, r0.y, icb[r1.z + 0].y\n  ld_structured r9.xyz, r4.w, l(12), g0.xyzx\n  iadd r7.xyz, r7.xyzx, r9.xyzx\n  itof r7.xyz, r7.xyzx\n  dp3 r4.w, r8.xyzx, r7.xyzx\n  lt r5.w, l(0.000000), r3.w\n  ge r6.w, r4.w, l(0.000000)\n  and r5.w, r5.w, r6.w\n  mul r4.w, r4.w, l(63.499989)\n  div r4.w, r4.w, r3.w\n  ftou r4.w, r4.w\n  ult r4.w, l(32), r4.w\n  and r4.w, r4.w, r5.w\n  movc r7.xyz, r4.wwww, -r8.xyzx, r8.xyzx\n  movc r8.xy, r4.wwww, r3.xyxx, r0.zwzz\n  movc r8.z, r4.w, r3.z, r1.w\n  movc r9.xy, r4.wwww, r0.zwzz, r3.xyxx\n  movc r9.z, r4.w, r1.w, r3.z\n  ieq r0.zw, cb0[0].zzzz, l(0, 0, 95, 96)\n  if_nz r0.z\n    mov r1.w, cb0[0].w\n    ige r3.x, icb[r1.w + 32].x, l(15)\n    and r3.x, r3.x, l(1)\n    movc r10.xyz, r5.xyzx, l(0,0,0,0), l(1,1,1,0)\n    movc r11.xyz, r6.xyzx, l(0,0,0,0), l(1,1,1,0)\n    or r10.xyz, r3.xxxx, r10.xyzx\n    or r11.xyz, r3.xxxx, r11.xyzx\n    ieq r12.xyz, r5.xyzx, l(0x0000ffff, 0x0000ffff, 0x0000ffff, 0)\n    ieq r13.xyz, r6.xyzx, l(0x0000ffff, 0x0000ffff, 0x0000ffff, 0)\n    ishl r3.y, l(1), icb[r1.w + 32].x\n    iadd r3.y, r3.y, l(-1)\n    ishl r14.xyz, r5.xyzx, icb[r1.w + 32].x\n    ishl r15.xyz, r6.xyzx, icb[r1.w + 32].x\n    ishr r14.xyz, r14.xyzx, l(16)\n    ishr r15.xyz, r15.xyzx, l(16)\n    movc r12.xyz, r12.xyzx, r3.yyyy, r14.xyzx\n    movc r13.xyz, r13.xyzx, r3.yyyy, r15.xyzx\n    movc r10.xyz, r10.xyzx, r5.xyzx, r12.xyzx\n    movc r11.xyz, r11.xyzx, r6.xyzx, r13.xyzx\n    movc r12.xyz, r8.xyzx, l(0,0,0,0), l(1,1,1,0)\n    movc r13.xyz, r9.xyzx, l(0,0,0,0), l(1,1,1,0)\n    or r12.xyz, r3.xxxx, r12.xyzx\n    or r13.xyz, r3.xxxx, r13.xyzx\n    ieq r14.xyz, r8.xyzx, l(0x0000ffff, 0x0000ffff, 0x0000ffff, 0)\n    ieq r15.xyz, r9.xyzx, l(0x0000ffff, 0x0000ffff, 0x0000ffff, 0)\n    mov r1.w, cb0[0].w\n    ishl r16.xyz, r8.xyzx, icb[r1.w + 32].x\n    ishl r17.xyz, r9.xyzx, icb[r1.w + 32].x\n    ishr r16.xyz, r16.xyzx, l(16)\n    ishr r17.xyz, r17.xyzx, l(16)\n    movc r14.xyz, r14.xyzx, r3.yyyy, r16.xyzx\n    movc r3.xyz, r15.xyzx, r3.yyyy, r17.xyzx\n    movc r12.xyz, r12.xyzx, r8.xyzx, r14.xyzx\n    movc r3.xyz, r13.xyzx, r9.xyzx, r3.xyzx\n  else \n    mov r1.w, cb0[0].w\n    ige r4.w, icb[r1.w + 32].x, l(16)\n    and r4.w, r4.w, l(1)\n    movc r13.xyz, r5.xyzx, l(0,0,0,0), l(1,1,1,0)\n    movc r14.xyz, r6.xyzx, l(0,0,0,0), l(1,1,1,0)\n    or r13.xyz, r4.wwww, r13.xyzx\n    or r14.xyz, r4.wwww, r14.xyzx\n    ige r15.xyz, r5.xyzx, l(0, 0, 0, 0)\n    ige r16.xyz, r6.xyzx, l(0, 0, 0, 0)\n    ieq r17.xyz, r5.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    ieq r18.xyz, r6.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    iadd r1.w, l(-1), icb[r1.w + 32].x\n    ishl r5.w, l(1), r1.w\n    iadd r6.w, r5.w, l(-1)\n    ishl r19.xyz, r5.xyzx, r1.w\n    ishl r20.xyz, r6.xyzx, r1.w\n    ishr r19.xyz, r19.xyzx, l(15)\n    ishr r20.xyz, r20.xyzx, l(15)\n    movc r17.xyz, r17.xyzx, r6.wwww, r19.xyzx\n    movc r18.xyz, r18.xyzx, r6.wwww, r20.xyzx\n    ineg r19.xyz, r5.xyzx\n    ineg r20.xyz, r6.xyzx\n    ieq r21.xyz, r19.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    ieq r22.xyz, r20.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    iadd r5.w, -r5.w, l(1)\n    ishl r19.xyz, r19.xyzx, r1.w\n    ishl r20.xyz, r20.xyzx, r1.w\n    ishr r19.xyz, r19.xyzx, l(15)\n    ishr r20.xyz, r20.xyzx, l(15)\n    ineg r19.xyz, r19.xyzx\n    ineg r20.xyz, r20.xyzx\n    movc r19.xyz, r21.xyzx, r5.wwww, r19.xyzx\n    movc r20.xyz, r22.xyzx, r5.wwww, r20.xyzx\n    movc r15.xyz, r15.xyzx, r17.xyzx, r19.xyzx\n    movc r16.xyz, r16.xyzx, r18.xyzx, r20.xyzx\n    movc r10.xyz, r13.xyzx, r5.xyzx, r15.xyzx\n    movc r11.xyz, r14.xyzx, r6.xyzx, r16.xyzx\n    movc r6.xyz, r8.xyzx, l(0,0,0,0), l(1,1,1,0)\n    movc r13.xyz, r9.xyzx, l(0,0,0,0), l(1,1,1,0)\n    or r6.xyz, r4.wwww, r6.xyzx\n    or r13.xyz, r4.wwww, r13.xyzx\n    ige r14.xyz, r8.xyzx, l(0, 0, 0, 0)\n    ige r15.xyz, r9.xyzx, l(0, 0, 0, 0)\n    ieq r16.xyz, r8.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    ieq r17.xyz, r9.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    ishl r18.xyz, r8.xyzx, r1.w\n    ishl r19.xyz, r9.xyzx, r1.w\n    ishr r18.xyz, r18.xyzx, l(15)\n    ishr r19.xyz, r19.xyzx, l(15)\n    movc r16.xyz, r16.xyzx, r6.wwww, r18.xyzx\n    movc r17.xyz, r17.xyzx, r6.wwww, r19.xyzx\n    ineg r18.xyz, r8.xyzx\n    ineg r19.xyz, r9.xyzx\n    ieq r20.xyz, r18.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    ieq r21.xyz, r19.xyzx, l(0x00007fff, 0x00007fff, 0x00007fff, 0)\n    ishl r18.xyz, r18.xyzx, r1.w\n    ishl r19.xyz, r19.xyzx, r1.w\n    ishr r18.xyz, r18.xyzx, l(15)\n    ishr r19.xyz, r19.xyzx, l(15)\n    ineg r18.xyz, r18.xyzx\n    ineg r19.xyz, r19.xyzx\n    movc r18.xyz, r20.xyzx, r5.wwww, r18.xyzx\n    movc r19.xyz, r21.xyzx, r5.wwww, r19.xyzx\n    movc r14.xyz, r14.xyzx, r16.xyzx, r18.xyzx\n    movc r15.xyz, r15.xyzx, r17.xyzx, r19.xyzx\n    movc r12.xyz, r6.xyzx, r8.xyzx, r14.xyzx\n    movc r3.xyz, r13.xyzx, r9.xyzx, r15.xyzx\n  endif \n  iadd r6.xyz, -r10.xyzx, r11.xyzx\n  mov r1.w, cb0[0].w\n  movc r6.xyz, icb[r1.w + 0].zzzz, r6.xyzx, r11.xyzx\n  iadd r9.xyz, -r10.xyzx, r12.xyzx\n  movc r9.xyz, icb[r1.w + 0].zzzz, r9.xyzx, r12.xyzx\n  iadd r11.xyz, -r10.xyzx, r3.xyzx\n  movc r3.xyz, icb[r1.w + 0].zzzz, r11.xyzx, r3.xyzx\n  if_nz icb[r1.w + 0].z\n    ige r11.xyz, r6.xyzx, l(0, 0, 0, 0)\n    iadd r12.xyz, l(-1, -1, -1, 0), icb[r1.w + 32].yzwy\n    ishl r13.x, l(1), r12.x\n    ishl r13.y, l(1), r12.y\n    ishl r13.z, l(1), r12.z\n    ige r12.xyz, r6.xyzx, r13.xyzx\n    ineg r14.xyz, r6.xyzx\n    ilt r14.xyz, r13.xyzx, r14.xyzx\n    movc r15.xyz, r11.xyzx, r12.xyzx, r14.xyzx\n    or r4.w, r15.y, r15.x\n    or r4.w, r15.z, r4.w\n    ishl r15.x, l(1), icb[r1.w + 32].x\n    ishl r15.y, l(1), icb[r1.w + 32].y\n    ishl r15.z, l(1), icb[r1.w + 32].z\n    ishl r15.w, l(1), icb[r1.w + 32].w\n    iadd r15.xyzw, r15.xyzw, l(-1, -1, -1, -1)\n    and r16.xyz, r10.xyzx, r15.xxxx\n    iadd r17.xyz, r13.xyzx, l(-1, -1, -1, 0)\n    movc r12.xyz, r12.xyzx, r17.xyzx, r6.xyzx\n    and r18.xyz, r6.xyzx, r15.yzwy\n    movc r14.xyz, r14.xyzx, r13.xyzx, r18.xyzx\n    movc r11.xyz, r11.xyzx, r12.xyzx, r14.xyzx\n    ige r12.xyz, r9.xyzx, l(0, 0, 0, 0)\n    ige r14.xyz, r9.xyzx, r13.xyzx\n    ineg r18.xyz, r9.xyzx\n    ilt r18.xyz, r13.xyzx, r18.xyzx\n    movc r19.xyz, r12.xyzx, r14.xyzx, r18.xyzx\n    ige r20.xyz, r3.xyzx, l(0, 0, 0, 0)\n    ige r21.xyz, r3.xyzx, r13.xyzx\n    ineg r22.xyz, r3.xyzx\n    ilt r22.xyz, r13.xyzx, r22.xyzx\n    movc r23.xyz, r20.xyzx, r21.xyzx, r22.xyzx\n    or r19.xyz, r19.xyzx, r23.xyzx\n    or r5.w, r19.y, r19.x\n    or r5.w, r19.z, r5.w\n    or r4.w, r4.w, r5.w\n    and r4.w, r4.w, l(1)\n    movc r14.xyz, r14.xyzx, r17.xyzx, r9.xyzx\n    and r19.xyz, r9.xyzx, r15.yzwy\n    movc r18.xyz, r18.xyzx, r13.xyzx, r19.xyzx\n    movc r12.xyz, r12.xyzx, r14.xyzx, r18.xyzx\n    movc r14.xyz, r21.xyzx, r17.xyzx, r3.xyzx\n    and r15.xyz, r3.xyzx, r15.yzwy\n    movc r13.xyz, r22.xyzx, r13.xyzx, r15.xyzx\n    movc r13.xyz, r20.xyzx, r14.xyzx, r13.xyzx\n  else \n    ishl r5.w, l(1), icb[r1.w + 32].x\n    iadd r5.w, r5.w, l(-1)\n    and r16.xyz, r5.wwww, r10.xyzx\n    and r11.xyz, r5.wwww, r6.xyzx\n    and r12.xyz, r5.wwww, r9.xyzx\n    and r13.xyz, r3.xyzx, r5.wwww\n    mov r4.w, l(0)\n  endif \n  iadd r6.xyzw, l(-1, -1, -1, -1), icb[r1.w + 32].xyzw\n  ishl r9.x, l(1), r6.x\n  ishl r9.y, l(1), r6.y\n  ishl r9.z, l(1), r6.z\n  ishl r9.w, l(1), r6.w\n  and r3.xyz, r9.xxxx, r16.xyzx\n  iadd r10.xyzw, r9.xyzw, l(-1, -1, -1, -1)\n  and r6.yzw, r10.xxxx, r16.xxyz\n  iadd r6.yzw, -r9.xxxx, r6.yyzw\n  movc r3.xyz, r3.xyzx, r6.yzwy, r16.xyzx\n  movc r3.xyz, r0.wwww, r3.xyzx, r16.xyzx\n  or r0.w, r0.w, icb[r1.w + 0].z\n  and r6.yzw, r9.yyzw, r11.xxyz\n  and r14.xyz, r10.yzwy, r11.xyzx\n  iadd r14.xyz, -r9.yzwy, r14.xyzx\n  movc r6.yzw, r6.yyzw, r14.xxyz, r11.xxyz\n  movc r6.yzw, r0.wwww, r6.yyzw, r11.xxyz\n  and r11.xyz, r9.yzwy, r12.xyzx\n  and r14.xyz, r10.yzwy, r12.xyzx\n  iadd r14.xyz, -r9.yzwy, r14.xyzx\n  movc r11.xyz, r11.xyzx, r14.xyzx, r12.xyzx\n  movc r11.xyz, r0.wwww, r11.xyzx, r12.xyzx\n  and r12.xyz, r9.yzwy, r13.xyzx\n  and r10.yzw, r10.yyzw, r13.xxyz\n  iadd r9.xyz, -r9.yzwy, r10.yzwy\n  movc r9.xyz, r12.xyzx, r9.xyzx, r13.xyzx\n  movc r9.xyz, r0.wwww, r9.xyzx, r13.xyzx\n  iadd r10.yzw, r3.xxyz, r6.yyzw\n  movc r6.yzw, icb[r1.w + 0].zzzz, r10.yyzw, r6.yyzw\n  iadd r10.yzw, r3.xxyz, r11.xxyz\n  movc r10.yzw, icb[r1.w + 0].zzzz, r10.yyzw, r11.xxyz\n  iadd r11.xyz, r3.xyzx, r9.xyzx\n  movc r9.xyz, icb[r1.w + 0].zzzz, r11.xyzx, r9.xyzx\n  ult r11.xy, icb[r1.w + 32].xxxx, l(15, 16, 0, 0)\n  ishl r0.w, l(1), icb[r1.w + 32].x\n  iadd r0.w, r0.w, l(-1)\n  ieq r12.xyz, r0.wwww, r3.xyzx\n  ieq r13.xyz, r0.wwww, r6.yzwy\n  ishl r14.xyz, r3.xyzx, l(16)\n  ishl r15.xyz, r6.yzwy, l(16)\n  iadd r14.xyz, r14.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n  iadd r15.xyz, r15.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n  ushr r14.xyz, r14.xyzx, icb[r1.w + 32].x\n  ushr r15.xyz, r15.xyzx, icb[r1.w + 32].x\n  movc r12.xyz, r12.xyzx, l(0x0000ffff,0x0000ffff,0x0000ffff,0), r14.xyzx\n  movc r13.xyz, r13.xyzx, l(0x0000ffff,0x0000ffff,0x0000ffff,0), r15.xyzx\n  movc r12.xyz, r3.xyzx, r12.xyzx, l(0,0,0,0)\n  movc r13.xyz, r6.yzwy, r13.xyzx, l(0,0,0,0)\n  movc r12.xyz, r11.xxxx, r12.xyzx, r3.xyzx\n  movc r13.xyz, r11.xxxx, r13.xyzx, r6.yzwy\n  ige r14.xyz, r3.xyzx, l(0, 0, 0, 0)\n  ige r15.xyz, r6.yzwy, l(0, 0, 0, 0)\n  imax r16.xyz, -r3.xyzx, r3.xyzx\n  imax r17.xyz, -r6.yzwy, r6.yzwy\n  ige r18.xyz, r16.xyzx, r10.xxxx\n  ige r19.xyz, r17.xyzx, r10.xxxx\n  ishl r20.xyz, r16.xyzx, l(15)\n  ishl r21.xyz, r17.xyzx, l(15)\n  iadd r20.xyz, r20.xyzx, l(0x00004000, 0x00004000, 0x00004000, 0)\n  iadd r21.xyz, r21.xyzx, l(0x00004000, 0x00004000, 0x00004000, 0)\n  ushr r20.xyz, r20.xyzx, r6.x\n  ushr r21.xyz, r21.xyzx, r6.x\n  movc r18.xyz, r18.xyzx, l(0x00007fff,0x00007fff,0x00007fff,0), r20.xyzx\n  movc r19.xyz, r19.xyzx, l(0x00007fff,0x00007fff,0x00007fff,0), r21.xyzx\n  movc r16.xyz, r16.xyzx, r18.xyzx, l(0,0,0,0)\n  movc r17.xyz, r17.xyzx, r19.xyzx, l(0,0,0,0)\n  ineg r18.xyz, r16.xyzx\n  ineg r19.xyz, r17.xyzx\n  movc r14.xyz, r14.xyzx, r16.xyzx, r18.xyzx\n  movc r15.xyz, r15.xyzx, r17.xyzx, r19.xyzx\n  movc r3.xyz, r11.yyyy, r14.xyzx, r3.xyzx\n  movc r6.yzw, r11.yyyy, r15.xxyz, r6.yyzw\n  movc r3.xyz, r0.zzzz, r12.xyzx, r3.xyzx\n  movc r6.yzw, r0.zzzz, r13.xxyz, r6.yyzw\n  ieq r12.xyz, r0.wwww, r10.yzwy\n  ieq r13.xyz, r0.wwww, r9.xyzx\n  ishl r14.xyz, r10.yzwy, l(16)\n  ishl r15.xyz, r9.xyzx, l(16)\n  iadd r14.xyz, r14.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n  iadd r15.xyz, r15.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n  ushr r14.xyz, r14.xyzx, icb[r1.w + 32].x\n  ushr r15.xyz, r15.xyzx, icb[r1.w + 32].x\n  movc r12.xyz, r12.xyzx, l(0x0000ffff,0x0000ffff,0x0000ffff,0), r14.xyzx\n  movc r13.xyz, r13.xyzx, l(0x0000ffff,0x0000ffff,0x0000ffff,0), r15.xyzx\n  movc r12.xyz, r10.yzwy, r12.xyzx, l(0,0,0,0)\n  movc r13.xyz, r9.xyzx, r13.xyzx, l(0,0,0,0)\n  movc r12.xyz, r11.xxxx, r12.xyzx, r10.yzwy\n  movc r11.xzw, r11.xxxx, r13.xxyz, r9.xxyz\n  ige r13.xyz, r10.yzwy, l(0, 0, 0, 0)\n  ige r14.xyz, r9.xyzx, l(0, 0, 0, 0)\n  imax r15.xyz, -r10.yzwy, r10.yzwy\n  imax r16.xyz, -r9.xyzx, r9.xyzx\n  ige r17.xyz, r15.xyzx, r10.xxxx\n  ige r18.xyz, r16.xyzx, r10.xxxx\n  ishl r19.xyz, r15.xyzx, l(15)\n  ishl r20.xyz, r16.xyzx, l(15)\n  iadd r19.xyz, r19.xyzx, l(0x00004000, 0x00004000, 0x00004000, 0)\n  iadd r20.xyz, r20.xyzx, l(0x00004000, 0x00004000, 0x00004000, 0)\n  ushr r19.xyz, r19.xyzx, r6.x\n  ushr r20.xyz, r20.xyzx, r6.x\n  movc r17.xyz, r17.xyzx, l(0x00007fff,0x00007fff,0x00007fff,0), r19.xyzx\n  movc r18.xyz, r18.xyzx, l(0x00007fff,0x00007fff,0x00007fff,0), r20.xyzx\n  movc r15.xyz, r15.xyzx, r17.xyzx, l(0,0,0,0)\n  movc r16.xyz, r16.xyzx, r18.xyzx, l(0,0,0,0)\n  ineg r17.xyz, r15.xyzx\n  ineg r18.xyz, r16.xyzx\n  movc r13.xyz, r13.xyzx, r15.xyzx, r17.xyzx\n  movc r14.xyz, r14.xyzx, r16.xyzx, r18.xyzx\n  movc r10.xyz, r11.yyyy, r13.xyzx, r10.yzwy\n  movc r9.xyz, r11.yyyy, r14.xyzx, r9.xyzx\n  movc r10.xyz, r0.zzzz, r12.xyzx, r10.xyzx\n  movc r9.xyz, r0.zzzz, r11.xzwx, r9.xyzx\n  ge r0.w, l(0.000000), r3.w\n  ge r1.w, l(0.000000), r2.y\n  mov r5.w, l(0)\n  mov r6.x, l(0)\n  loop \n    uge r7.w, r6.x, l(16)\n    breakc_nz r7.w\n    ushr r7.w, icb[r1.z + 0].x, r6.x\n    and r7.w, r7.w, l(1)\n    if_nz r7.w\n      iadd r7.w, r0.y, r6.x\n      ld_structured r11.xyz, r7.w, l(12), g0.xyzx\n      iadd r11.xyz, -r8.xyzx, r11.xyzx\n      itof r11.xyz, r11.xyzx\n      dp3 r7.w, r7.xyzx, r11.xyzx\n      ge r8.w, l(0.000000), r7.w\n      or r8.w, r0.w, r8.w\n      lt r9.w, r7.w, r3.w\n      mul r7.w, r7.w, l(63.499989)\n      div r7.w, r7.w, r3.w\n      ftou r7.w, r7.w\n      movc r7.w, r9.w, icb[r7.w + 46].x, l(7)\n      movc r7.w, r8.w, l(0), r7.w\n      iadd r8.w, l(64), -icb[r7.w + 0].w\n      imul null, r11.xyz, r9.xyzx, icb[r7.w + 0].wwww\n      imad r11.xyz, r10.xyzx, r8.wwww, r11.xyzx\n      iadd r11.xyz, r11.xyzx, l(32, 32, 32, 0)\n      ishr r11.xyz, r11.xyzx, l(6)\n      imul null, r12.xyz, r11.xyzx, l(31, 31, 31, 0)\n      ishr r13.xyz, r12.xyzx, l(6)\n      ilt r14.xyz, r11.xyzx, l(0, 0, 0, 0)\n      imul null, r11.xyz, r11.xyzx, l(-31, -31, -31, 0)\n      ishr r11.xyz, r11.xyzx, l(5)\n      ineg r11.xyz, r11.xyzx\n      ishr r12.xyz, r12.xyzx, l(5)\n      movc r11.xyz, r14.xyzx, r11.xyzx, r12.xyzx\n      ilt r12.xyz, r11.xyzx, l(0, 0, 0, 0)\n      ineg r14.xyz, r11.xyzx\n      or r14.xyz, r14.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n      movc r11.xyz, r12.xyzx, r14.xyzx, r11.xyzx\n      movc r11.xyz, r0.zzzz, r13.xyzx, r11.xyzx\n    else \n      iadd r7.w, r0.y, r6.x\n      ld_structured r12.xyz, r7.w, l(12), g0.xyzx\n      iadd r12.xyz, -r5.xyzx, r12.xyzx\n      itof r12.xyz, r12.xyzx\n      dp3 r7.w, r4.xyzx, r12.xyzx\n      ge r8.w, l(0.000000), r7.w\n      or r8.w, r1.w, r8.w\n      lt r9.w, r7.w, r2.y\n      mul r7.w, r7.w, l(63.499989)\n      div r7.w, r7.w, r2.y\n      ftou r7.w, r7.w\n      movc r7.w, r9.w, icb[r7.w + 46].x, l(7)\n      movc r7.w, r8.w, l(0), r7.w\n      iadd r8.w, l(64), -icb[r7.w + 0].w\n      imul null, r12.xyz, r6.yzwy, icb[r7.w + 0].wwww\n      imad r12.xyz, r3.xyzx, r8.wwww, r12.xyzx\n      iadd r12.xyz, r12.xyzx, l(32, 32, 32, 0)\n      ishr r12.xyz, r12.xyzx, l(6)\n      imul null, r13.xyz, r12.xyzx, l(31, 31, 31, 0)\n      ishr r14.xyz, r13.xyzx, l(6)\n      ilt r15.xyz, r12.xyzx, l(0, 0, 0, 0)\n      imul null, r12.xyz, r12.xyzx, l(-31, -31, -31, 0)\n      ishr r12.xyz, r12.xyzx, l(5)\n      ineg r12.xyz, r12.xyzx\n      ishr r13.xyz, r13.xyzx, l(5)\n      movc r12.xyz, r15.xyzx, r12.xyzx, r13.xyzx\n      ilt r13.xyz, r12.xyzx, l(0, 0, 0, 0)\n      ineg r15.xyz, r12.xyzx\n      or r15.xyz, r15.xyzx, l(0x00008000, 0x00008000, 0x00008000, 0)\n      movc r12.xyz, r13.xyzx, r15.xyzx, r12.xyzx\n      movc r11.xyz, r0.zzzz, r14.xyzx, r12.xyzx\n    endif \n    and r12.xy, r11.xxxx, l(1023, 0x00007c00, 0, 0)\n    if_nz r12.y\n      ushr r7.w, r11.x, l(10)\n      and r7.w, r7.w, l(31)\n    else \n      if_nz r12.x\n        ishl r8.w, r12.x, l(1)\n        mov r9.w, r8.w\n        mov r7.w, l(0)\n        loop \n          and r10.w, r9.w, l(1024)\n          breakc_nz r10.w\n          iadd r7.w, r7.w, l(-1)\n          ishl r9.w, r9.w, l(1)\n        endloop \n        and r12.x, r9.w, l(1022)\n      else \n        mov r12.x, l(0)\n        mov r7.w, l(-112)\n      endif \n    endif \n    ishl r8.w, r11.x, l(16)\n    and r8.w, r8.w, l(0x80000000)\n    ishl r10.w, r7.w, l(23)\n    iadd r10.w, r10.w, l(0x38000000)\n    or r8.w, r8.w, r10.w\n    ishl r10.w, r12.x, l(13)\n    iadd r12.x, r8.w, r10.w\n    and r11.xw, r11.yyyy, l(1023, 0, 0, 0x00007c00)\n    if_nz r11.w\n      ushr r8.w, r11.y, l(10)\n      and r8.w, r8.w, l(31)\n    else \n      if_nz r11.x\n        ishl r10.w, r11.x, l(1)\n        mov r11.w, r10.w\n        mov r8.w, l(0)\n        loop \n          and r12.w, r11.w, l(1024)\n          breakc_nz r12.w\n          iadd r8.w, r8.w, l(-1)\n          ishl r11.w, r11.w, l(1)\n        endloop \n        and r11.x, r11.w, l(1022)\n      else \n        mov r11.x, l(0)\n        mov r8.w, l(-112)\n      endif \n    endif \n    ishl r10.w, r11.y, l(16)\n    and r10.w, r10.w, l(0x80000000)\n    ishl r11.y, r8.w, l(23)\n    iadd r11.y, r11.y, l(0x38000000)\n    or r10.w, r10.w, r11.y\n    ishl r11.x, r11.x, l(13)\n    iadd r12.y, r10.w, r11.x\n    and r11.xy, r11.zzzz, l(1023, 0x00007c00, 0, 0)\n    if_nz r11.y\n      ushr r10.w, r11.z, l(10)\n      and r10.w, r10.w, l(31)\n    else \n      if_nz r11.x\n        ishl r11.y, r11.x, l(1)\n        mov r12.w, r11.y\n        mov r10.w, l(0)\n        loop \n          and r13.x, r12.w, l(1024)\n          breakc_nz r13.x\n          iadd r10.w, r10.w, l(-1)\n          ishl r12.w, r12.w, l(1)\n        endloop \n        and r11.x, r12.w, l(1022)\n      else \n        mov r11.x, l(0)\n        mov r10.w, l(-112)\n      endif \n    endif \n    ishl r11.y, r11.z, l(16)\n    and r11.y, r11.y, l(0x80000000)\n    ishl r11.z, r10.w, l(23)\n    iadd r11.z, r11.z, l(0x38000000)\n    or r11.y, r11.z, r11.y\n    ishl r11.x, r11.x, l(13)\n    iadd r12.z, r11.x, r11.y\n    iadd r11.x, r0.y, r6.x\n    ld_structured r13.xyz, r11.x, l(24), g0.xyzx\n    add r11.xyz, r12.xyzx, -r13.xyzx\n    dp3 r11.x, r11.xyzx, r11.xyzx\n    add r5.w, r5.w, r11.x\n    iadd r6.x, r6.x, l(1)\n  endloop \n  movc r1.x, r4.w, l(100000002004087734272.000000), r5.w\n  iadd r1.y, cb0[0].w, l(1)\n  store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(40), r1.xyzx\nendif \nsync_g_t\nif_nz r2.x\n  ld_structured r3.x, vThreadIDInGroupFlattened.x, l(40), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(16)\n  ld_structured r4.yzw, r0.y, l(40), g0.xxyz\n  lt r0.z, r4.y, r3.x\n  if_nz r0.z\n    ld_structured r4.x, r0.y, l(40), g0.xxxx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(40), r4.xzwx\n  endif \nendif \nsync_g_t\nif_nz r2.z\n  ld_structured r3.x, vThreadIDInGroupFlattened.x, l(40), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(8)\n  ld_structured r4.yzw, r0.y, l(40), g0.xxyz\n  lt r0.z, r4.y, r3.x\n  if_nz r0.z\n    ld_structured r4.x, r0.y, l(40), g0.xxxx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(40), r4.xzwx\n  endif \nendif \nsync_g_t\nif_nz r2.w\n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(40), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(4)\n  ld_structured r3.yzw, r0.y, l(40), g0.xxyz\n  lt r0.z, r3.y, r2.x\n  if_nz r0.z\n    ld_structured r3.x, r0.y, l(40), g0.xxxx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(40), r3.xzwx\n  endif \nendif \nsync_g_t\nult r0.yz, r1.zzzz, l(0, 2, 1, 0)\nif_nz r0.y\n  ld_structured r1.x, vThreadIDInGroupFlattened.x, l(40), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(2)\n  ld_structured r2.yzw, r0.y, l(40), g0.xxyz\n  lt r0.w, r2.y, r1.x\n  if_nz r0.w\n    ld_structured r2.x, r0.y, l(40), g0.xxxx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(40), r2.xzwx\n  endif \nendif \nsync_g_t\nif_nz r0.z\n  ld_structured r1.x, vThreadIDInGroupFlattened.x, l(40), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(1)\n  ld_structured r2.yzw, r0.y, l(40), g0.xxyz\n  lt r0.z, r2.y, r1.x\n  if_nz r0.z\n    ld_structured r2.x, r0.y, l(40), g0.xxxx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(40), r2.xzwx\n  endif \n  ld_structured r1.x, r0.x, l(0), t1.xxxx\n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(40), g0.xxxx\n  lt r0.y, r2.x, r1.x\n  if_nz r0.y\n    ld_structured r1.xyz, vThreadIDInGroupFlattened.x, l(40), g0.xyzx\n    mov r1.w, l(0)\n  else \n    ld_structured r1.xyzw, r0.x, l(0), t1.xyzw\n  endif \n  store_structured u0.xyzw, r0.x, l(0), r1.xyzw\nendif \nret \n// Approximately 0 instruction slots used\n#endif\n\nconst BYTE BC6HEncode_TryModeLE10CS[] =\n{\n     68,  88,  66,  67, 161,   2, \n    137, 126,  42,  47, 246, 175, \n    125,  91,  68,  30, 201,  32, \n    221, 116,   1,   0,   0,   0, \n     76,  96,   0,   0,   3,   0, \n      0,   0,  44,   0,   0,   0, \n     60,   0,   0,   0,  76,   0, \n      0,   0,  73,  83,  71,  78, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     79,  83,  71,  78,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  83,  72, \n     69,  88, 248,  95,   0,   0, \n     64,   0,   5,   0, 254,  23, \n      0,   0, 106,   8,   0,   1, \n     53,  24,   0,   0, 186,   1, \n      0,   0, 204, 204,   0,   0, \n     15,   0,   0,   0, 255, 255, \n    255, 255,   0,   0,   0,   0, \n    136, 136,   0,   0,  15,   0, \n      0,   0, 255, 255, 255, 255, \n      9,   0,   0,   0, 238, 238, \n      0,   0,  15,   0,   0,   0, \n    255, 255, 255, 255,  18,   0, \n      0,   0, 200, 236,   0,   0, \n     15,   0,   0,   0, 255, 255, \n    255, 255,  27,   0,   0,   0, \n    128, 200,   0,   0,  15,   0, \n      0,   0, 255, 255, 255, 255, \n     37,   0,   0,   0, 236, 254, \n      0,   0,  15,   0,   0,   0, \n    255, 255, 255, 255,  46,   0, \n      0,   0, 200, 254,   0,   0, \n     15,   0,   0,   0, 255, 255, \n    255, 255,  55,   0,   0,   0, \n    128, 236,   0,   0,  15,   0, \n      0,   0, 255, 255, 255, 255, \n     64,   0,   0,   0,   0, 200, \n      0,   0,  15,   0,   0,   0, \n    255, 255, 255, 255,   0,   0, \n      0,   0, 236, 255,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n    128, 254,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0, 232, \n      0,   0,  15,   0,   0,   0, \n    255, 255, 255, 255,   0,   0, \n      0,   0, 232, 255,   0,   0, \n     15,   0,   0,   0, 255, 255, \n    255, 255,   0,   0,   0,   0, \n      0, 255,   0,   0,  15,   0, \n      0,   0, 255, 255, 255, 255, \n      0,   0,   0,   0, 240, 255, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0, 240,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     16, 247,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 142,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0, 113,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n    206,   8,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 140,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  16, 115,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,  49,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 206, 140, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 140,   8,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     16,  49,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 102, 102, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 108,  54,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n    232,  23,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 240,  15, \n      0,   0,   8,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 142, 113,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n    156,  57,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,   5,   0,   0,   0, \n      5,   0,   0,   0,   5,   0, \n      0,   0,   7,   0,   0,   0, \n      6,   0,   0,   0,   6,   0, \n      0,   0,   6,   0,   0,   0, \n     11,   0,   0,   0,   5,   0, \n      0,   0,   4,   0,   0,   0, \n      4,   0,   0,   0,  11,   0, \n      0,   0,   4,   0,   0,   0, \n      5,   0,   0,   0,   4,   0, \n      0,   0,  11,   0,   0,   0, \n      4,   0,   0,   0,   4,   0, \n      0,   0,   5,   0,   0,   0, \n      9,   0,   0,   0,   5,   0, \n      0,   0,   5,   0,   0,   0, \n      5,   0,   0,   0,   8,   0, \n      0,   0,   6,   0,   0,   0, \n      5,   0,   0,   0,   5,   0, \n      0,   0,   8,   0,   0,   0, \n      5,   0,   0,   0,   6,   0, \n      0,   0,   5,   0,   0,   0, \n      8,   0,   0,   0,   5,   0, \n      0,   0,   5,   0,   0,   0, \n      6,   0,   0,   0,   6,   0, \n      0,   0,   6,   0,   0,   0, \n      6,   0,   0,   0,   6,   0, \n      0,   0,  10,   0,   0,   0, \n     10,   0,   0,   0,  10,   0, \n      0,   0,  10,   0,   0,   0, \n     11,   0,   0,   0,   9,   0, \n      0,   0,   9,   0,   0,   0, \n      9,   0,   0,   0,  12,   0, \n      0,   0,   8,   0,   0,   0, \n      8,   0,   0,   0,   8,   0, \n      0,   0,  16,   0,   0,   0, \n      4,   0,   0,   0,   4,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  89,   0, \n      0,   4,  70, 142,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  88,  24,   0,   4, \n      0, 112,  16,   0,   0,   0, \n      0,   0,  85,  85,   0,   0, \n    162,   0,   0,   4,   0, 112, \n     16,   0,   1,   0,   0,   0, \n     16,   0,   0,   0, 158,   0, \n      0,   4,   0, 224,  17,   0, \n      0,   0,   0,   0,  16,   0, \n      0,   0,  95,   0,   0,   2, \n      0,  64,   2,   0,  95,   0, \n      0,   2,  18,  16,   2,   0, \n    104,   0,   0,   2,  24,   0, \n      0,   0, 105,   0,   0,   4, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   4,   0,   0,   0, \n    105,   0,   0,   4,   1,   0, \n      0,   0,   2,   0,   0,   0, \n      4,   0,   0,   0, 160,   0, \n      0,   5,   0, 240,  17,   0, \n      0,   0,   0,   0,  84,   0, \n      0,   0,  64,   0,   0,   0, \n    155,   0,   0,   4,  64,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   6,  18,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   6,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,  16, \n      2,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   8,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10, 128,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   6,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16, 128,  65,   0,   0,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,  79,   0,   0,  10, \n    242,   0,  16,   0,   2,   0, \n      0,   0, 166,  10,  16,   0, \n      1,   0,   0,   0,   2,  64, \n      0,   0,  16,   0,   0,   0, \n     32,   0,   0,   0,   8,   0, \n      0,   0,   4,   0,   0,   0, \n     31,   0,   4,   3,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     78,   0,   0,   9,  66,   0, \n     16,   0,   0,   0,   0,   0, \n      0, 208,   0,   0,  10,   0, \n     16,   0,   0,   0,   0,   0, \n     26, 128,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     35,   0,   0,  11, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16, 128,  65,   0, \n      0,   0,   0,   0,   0,   0, \n     26, 128,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     85,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  54,   0,   0,   8, \n    194,   0,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  45,   0, \n      0,   7, 242,   0,  16,   0, \n      3,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     70, 126,  16,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      5,   0,   0,   0,   6,   5, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n    255, 127, 255, 255, 127,   0, \n    255, 255, 255, 127, 255, 255, \n    127,   0,  79,   0,   0,  10, \n    194,   0,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 255, 239, 255,  71, \n    255, 239, 255,  71,   6,   8, \n     16,   0,   5,   0,   0,   0, \n     79,   0,   0,  10,  50,   0, \n     16,   0,   3,   0,   0,   0, \n    134,   0,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0, 128,  56,   0,   0, \n    128,  56,   0,   0,   0,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7,  50,   0,  16,   0, \n      6,   0,   0,   0, 134,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  30,   0,   0,  11, \n     50,   0,  16,   0,   6,   0, \n      0,   0,  70,   0,  16, 128, \n     65,   0,   0,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n    113,   0,   0,   0, 113,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  30,   0, \n      0,  10, 162,   0,  16,   0, \n      5,   0,   0,   0,  86,  13, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0, 128,   0, \n      0,   0,   0,   0,   0,   0, \n    128,   0,  85,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n     85,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  30,   0, \n      0,  10,  50,   0,  16,   0, \n      5,   0,   0,   0, 134,   0, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0, 200,   0,   0,   0, 200, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  55,   0,   0,   9, \n     50,   0,  16,   0,   3,   0, \n      0,   0,  70,   0,  16,   0, \n      3,   0,   0,   0,  70,   0, \n     16,   0,   7,   0,   0,   0, \n     70,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,  10, \n     50,   0,  16,   0,   5,   0, \n      0,   0,  70,   0,  16,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0, 255,  15,   0,   0, \n    255,  15,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     85,   0,   0,   7,  50,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,   1,   0, \n      0,  10,  50,   0,  16,   0, \n      3,   0,   0,   0,  70,   0, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     50,   0,  16,   0,   3,   0, \n      0,   0,  70,   0,  16,   0, \n      3,   0,   0,   0,  70,   0, \n     16,   0,   5,   0,   0,   0, \n     85,   0,   0,   7,  50,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,   1,   0, \n      0,  10,  50,   0,  16,   0, \n      3,   0,   0,   0,  70,   0, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  55,   0,   0,  12, \n    194,   0,  16,   0,   0,   0, \n      0,   0, 166,  14,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      6,   4,  16,   0,   3,   0, \n      0,   0,  30,   0,   0,   7, \n     50,   0,  16,   0,   5,   0, \n      0,   0,  70,   0,  16,   0, \n      4,   0,   0,   0, 230,  10, \n     16,   0,   0,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,   0,   0,   0,   0, \n    166,  10,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 255, 255, 255, 127, \n    255, 255, 127,   0,  79,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0, 255, 239, 255,  71, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  79,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0, 128,  56, \n     85,   0,   0,   7,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,  30,   0, \n      0,   8,  34,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16, 128,  65,   0,   0,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0, 113,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0, 128,   0,  85,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0, 200, \n     55,   0,   0,   9,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    255,  15,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0, 255, 127,   0,   0, \n     55,   0,   0,   9,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 127,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      3,   0,   0,   0,   6,   5, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0, 255,   3, \n      0,   0,   0, 124,   0,   0, \n    255,   3,   0,   0,   0, 124, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  85,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,  18,   0, \n      0,   1,  31,   0,   4,   3, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  54,   0,   0,   5, \n     66,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  48,   0, \n      0,   1,   1,   0,   0,   7, \n     34,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   0,   4,   0,   0, \n      3,   0,   4,   3,  26,   0, \n     16,   0,   3,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  22,   0,   0,   1, \n      1,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    254,   3,   0,   0,  18,   0, \n      0,   1,  54,   0,   0,   5, \n     18,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   5,  66,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0, 144, 255, 255, 255, \n     21,   0,   0,   1,  21,   0, \n      0,   1,  41,   0,   0,   7, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,  56, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,  18,   0,   0,   1, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   5,  66,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  48,   0,   0,   1, \n      1,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   4,   0,   0,   3,   0, \n      4,   3,  10,   0,  16,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0, 255, 255, \n    255, 255,  41,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     22,   0,   0,   1,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0, 254,   3, \n      0,   0,  18,   0,   0,   1, \n     54,   0,   0,   5,  66,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   5, \n     66,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    144, 255, 255, 255,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,  56,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   0,   0, \n      0,   0, 166,  10,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 255,   3, \n      0,   0,   0, 124,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     85,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,  18,   0,   0,   1, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  48,   0,   0,   1, \n      1,   0,   0,   7,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   4,   0,   0,   3,   0, \n      4,   3,  26,   0,  16,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0, 255, 255, \n    255, 255,  41,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     22,   0,   0,   1,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0, 254,   3, \n      0,   0,  18,   0,   0,   1, \n     54,   0,   0,   8, 194,   0, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 144, 255, \n    255, 255,  21,   0,   0,   1, \n     21,   0,   0,   1,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,  56, \n     60,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     16,   0,   0,  10, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n    208, 179,  89,  62,  89,  23, \n     55,  63, 152, 221, 147,  61, \n      0,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n     32,   0,   0,   8,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42, 128,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  95,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     78,   0,   0,  11, 114,   0, \n     16,   0,   3,   0,   0,   0, \n      0, 208,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0,  31,   0, \n      0,   0,  31,   0,   0,   0, \n     31,   0,   0,   0,   0,   0, \n      0,   0,  79,   0,   0,  10, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     32,   0,   0,  10, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 123,   0,   0, 255, 123, \n      0,   0, 255, 123,   0,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  78,   0,   0,  11, \n    114,   0,  16,   0,   7,   0, \n      0,   0,   0, 208,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n     31,   0,   0,   0,  31,   0, \n      0,   0,  31,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,  12, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0, 224, 255, \n     15,   0, 224, 255,  15,   0, \n    224, 255,  15,   0,   0,   0, \n      0,   0,  78,   0,   0,  11, \n    114,   0,  16,   0,   5,   0, \n      0,   0,   0, 208,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n     31,   0,   0,   0,  31,   0, \n      0,   0,  31,   0,   0,   0, \n      0,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      1, 128, 255, 255,   1, 128, \n    255, 255,   1, 128, 255, 255, \n      0,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   3,   0,   0,   0, \n    166,  10,  16,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n    168,   0,   0,   8, 114, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 127,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 127,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 127,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0, 128,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0, 128,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0, 128,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 127,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 127,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 127,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0, 128,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0, 128,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0, 128,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 127, 127,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 127, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 127, 127,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 127, 255,  54,   0, \n      0,   5,  66,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     48,   0,   0,   1,  80,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   3,   0,   4,   3, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     85,   0,   0,   8, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10, 144, 144,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  48,  32,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n     49,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  55,   0, \n      0,   9,  34,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,  55,   0, \n      0,   9,  34,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  55,   0, \n      0,   9,  34,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  55,   0, \n      0,   9, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,  48, \n     32,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,  49,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   6, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  55,   0,   0,   9, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  55,   0,   0,   9, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  55,   0,   0,   9, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  55,   0,   0,   9, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  18,   0,   0,   1, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  48,  32,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     49,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,   9,  34,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  55,   0, \n      0,   9,  34,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  55,   0, \n      0,   9,  34,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  55,   0, \n      0,   9, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,  48, \n     32,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,  49,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   6, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  55,   0,   0,   9, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  55,   0,   0,   9, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  55,   0,   0,   9, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  55,   0,   0,   9, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  21,   0,   0,   1, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,  54,   0,   0,   6, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n     34,   0,  16,   0,   3,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  54,   0,   0,   6, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  40,   0,   0,   5, \n     50,   0,  16,   0,   4,   0, \n      0,   0, 230,  10,  16,   0, \n      0,   0,   0,   0,  40,   0, \n      0,   5,  66,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   7, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,  43,   0, \n      0,   5, 114,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     16,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      6,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7, 114,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,  43,   0,   0,   5, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,  16,   0, \n      0,   7, 130,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,  49,   0,   0,   7, \n     18,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     29,   0,   0,   7,  34,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   7,  18,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  56,   0,   0,   7, \n    130,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0, 253, 255, 125,  66, \n     14,   0,   0,   7, 130,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  28,   0, \n      0,   5, 130,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     79,   0,   0,   7, 130,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  55,   0,   0,  10, \n    114,   0,  16,   0,   4,   0, \n      0,   0, 246,  15,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16, 128,  65,   0,   0,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     55,   0,   0,   9,  50,   0, \n     16,   0,   5,   0,   0,   0, \n    246,  15,  16,   0,   3,   0, \n      0,   0,  70,   0,  16,   0, \n      3,   0,   0,   0, 230,  10, \n     16,   0,   0,   0,   0,   0, \n     55,   0,   0,   9,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     55,   0,   0,   9,  50,   0, \n     16,   0,   6,   0,   0,   0, \n    246,  15,  16,   0,   3,   0, \n      0,   0, 230,  10,  16,   0, \n      0,   0,   0,   0,  70,   0, \n     16,   0,   3,   0,   0,   0, \n     55,   0,   0,   9,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     40,   0,   0,   5,  50,   0, \n     16,   0,   7,   0,   0,   0, \n    230,  10,  16,   0,   0,   0, \n      0,   0,  40,   0,   0,   5, \n     66,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,  43,   0,   0,   5, \n    114,   0,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,  16,   0, \n      0,   7, 130,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   8, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  26, 144, \n    144,   0,  42,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  43,   0,   0,   5, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  16,   0, \n      0,   7, 130,   0,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,  49,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     29,   0,   0,   7, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  56,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0, 253, 255, 125,  66, \n     14,   0,   0,   7, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,  28,   0, \n      0,   5, 130,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n     79,   0,   0,   7, 130,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,  55,   0,   0,  10, \n    114,   0,  16,   0,   7,   0, \n      0,   0, 246,  15,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16, 128,  65,   0,   0,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     55,   0,   0,   9,  50,   0, \n     16,   0,   8,   0,   0,   0, \n    246,  15,  16,   0,   4,   0, \n      0,   0,  70,   0,  16,   0, \n      3,   0,   0,   0, 230,  10, \n     16,   0,   0,   0,   0,   0, \n     55,   0,   0,   9,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     55,   0,   0,   9,  50,   0, \n     16,   0,   9,   0,   0,   0, \n    246,  15,  16,   0,   4,   0, \n      0,   0, 230,  10,  16,   0, \n      0,   0,   0,   0,  70,   0, \n     16,   0,   3,   0,   0,   0, \n     55,   0,   0,   9,  66,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     32,   0,   0,  11, 194,   0, \n     16,   0,   0,   0,   0,   0, \n    166, 138,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     95,   0,   0,   0,  96,   0, \n      0,   0,  31,   0,   4,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  58, 128,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  33,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10, 144, 208,   0, \n     32,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,   1,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     55,   0,   0,  15, 114,   0, \n     16,   0,  10,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,  15, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,  10,   0,   0,   0, \n      6,   0,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n     11,   0,   0,   0,   6,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,  32,   0,   0,  10, \n    114,   0,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0, 255, 255,   0,   0, \n    255, 255,   0,   0, 255, 255, \n      0,   0,   0,   0,   0,   0, \n     32,   0,   0,  10, 114,   0, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255,   0,   0, 255, 255, \n      0,   0, 255, 255,   0,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   9,  34,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     10, 144, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0, 255, 255, \n    255, 255,  41,   0,   0,   9, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,  10, 144, \n    208,   0,  32,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  41,   0,   0,   9, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  10, 144, \n    208,   0,  32,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     42,   0,   0,   7, 114,   0, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,  15,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     86,   5,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n     86,   5,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,  10,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n     13,   0,   0,   0,  55,   0, \n      0,  15, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,  15, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n     12,   0,   0,   0,   6,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,  13,   0, \n      0,   0,   6,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n     32,   0,   0,  10, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255,   0,   0, 255, 255, \n      0,   0, 255, 255,   0,   0, \n      0,   0,   0,   0,  32,   0, \n      0,  10, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n      0,   0, 255, 255,   0,   0, \n    255, 255,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  58, 128,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  41,   0,   0,   9, \n    114,   0,  16,   0,  16,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,  10, 144, \n    208,   0,  32,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  41,   0,   0,   9, \n    114,   0,  16,   0,  17,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  10, 144, \n    208,   0,  32,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,  16,   0, \n      0,   0,  70,   2,  16,   0, \n     16,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     42,   0,   0,   7, 114,   0, \n     16,   0,  17,   0,   0,   0, \n     70,   2,  16,   0,  17,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     86,   5,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n     16,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     86,   5,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n     17,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  18,   0, \n      0,   1,  54,   0,   0,   6, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  58, 128,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  33,   0,   0,   9, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  10, 144, 208,   0, \n     32,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     55,   0,   0,  15, 114,   0, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,  15, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,  13,   0,   0,   0, \n    246,  15,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n     13,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n     14,   0,   0,   0, 246,  15, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,  33,   0,   0,  10, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     33,   0,   0,  10, 114,   0, \n     16,   0,  16,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  32,   0, \n      0,  10, 114,   0,  16,   0, \n     17,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0,   0,   0, \n      0,   0,  32,   0,   0,  10, \n    114,   0,  16,   0,  18,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   9, 130,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0, 255, 255, \n    255, 255,  10, 144, 208,   0, \n     32,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0, 255, 255, \n    255, 255,  41,   0,   0,   7, \n    114,   0,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  20,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     19,   0,   0,   0,  70,   2, \n     16,   0,  19,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,  20,   0, \n      0,   0,  70,   2,  16,   0, \n     20,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  17,   0,   0,   0, \n     70,   2,  16,   0,  17,   0, \n      0,   0, 246,  15,  16,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,  19,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  18,   0,   0,   0, \n     70,   2,  16,   0,  18,   0, \n      0,   0, 246,  15,  16,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,  20,   0,   0,   0, \n     40,   0,   0,   5, 114,   0, \n     16,   0,  19,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  20,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  32,   0, \n      0,  10, 114,   0,  16,   0, \n     21,   0,   0,   0,  70,   2, \n     16,   0,  19,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0,   0,   0, \n      0,   0,  32,   0,   0,  10, \n    114,   0,  16,   0,  22,   0, \n      0,   0,  70,   2,  16,   0, \n     20,   0,   0,   0,   2,  64, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   8, 130,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16, 128,  65,   0, \n      0,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n     19,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  20,   0,   0,   0, \n     70,   2,  16,   0,  20,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     19,   0,   0,   0,  70,   2, \n     16,   0,  19,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,  20,   0, \n      0,   0,  70,   2,  16,   0, \n     20,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     40,   0,   0,   5, 114,   0, \n     16,   0,  19,   0,   0,   0, \n     70,   2,  16,   0,  19,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  20,   0, \n      0,   0,  70,   2,  16,   0, \n     20,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     19,   0,   0,   0,  70,   2, \n     16,   0,  21,   0,   0,   0, \n    246,  15,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n     19,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     20,   0,   0,   0,  70,   2, \n     16,   0,  22,   0,   0,   0, \n    246,  15,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n     20,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,  17,   0, \n      0,   0,  70,   2,  16,   0, \n     19,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     16,   0,   0,   0,  70,   2, \n     16,   0,  16,   0,   0,   0, \n     70,   2,  16,   0,  18,   0, \n      0,   0,  70,   2,  16,   0, \n     20,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n     16,   0,   0,   0,  55,   0, \n      0,  15, 114,   0,  16,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,  15, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n      6,   0,   0,   0, 246,  15, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,  13,   0, \n      0,   0, 246,  15,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n     33,   0,   0,  10, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  33,   0, \n      0,  10, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  32,   0,   0,  10, \n    114,   0,  16,   0,  16,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0,   0,   0,   0,   0, \n     32,   0,   0,  10, 114,   0, \n     16,   0,  17,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     18,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,   0,   7, 114,   0, \n     16,   0,  18,   0,   0,   0, \n     70,   2,  16,   0,  18,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     19,   0,   0,   0,  70,   2, \n     16,   0,  19,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,  16,   0, \n      0,   0,  70,   2,  16,   0, \n     16,   0,   0,   0, 246,  15, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,  18,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,  17,   0, \n      0,   0,  70,   2,  16,   0, \n     17,   0,   0,   0, 246,  15, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,  19,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  18,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n     19,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     32,   0,   0,  10, 114,   0, \n     16,   0,  20,   0,   0,   0, \n     70,   2,  16,   0,  18,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,  32,   0, \n      0,  10, 114,   0,  16,   0, \n     21,   0,   0,   0,  70,   2, \n     16,   0,  19,   0,   0,   0, \n      2,  64,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n    255, 127,   0,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,  18,   0, \n      0,   0,  70,   2,  16,   0, \n     18,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  19,   0,   0,   0, \n     70,   2,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     18,   0,   0,   0,  70,   2, \n     16,   0,  18,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n     19,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     40,   0,   0,   5, 114,   0, \n     16,   0,  18,   0,   0,   0, \n     70,   2,  16,   0,  18,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n     19,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     18,   0,   0,   0,  70,   2, \n     16,   0,  20,   0,   0,   0, \n    246,  15,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n     18,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     19,   0,   0,   0,  70,   2, \n     16,   0,  21,   0,   0,   0, \n    246,  15,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n     19,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,  16,   0, \n      0,   0,  70,   2,  16,   0, \n     18,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,  17,   0, \n      0,   0,  70,   2,  16,   0, \n     19,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  21,   0, \n      0,   1,  30,   0,   0,   8, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  70,   2,  16, 128, \n     65,   0,   0,   0,  10,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      1,   0,   0,   0,  58, 128, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,  10, 114,   0,  16,   0, \n      6,   0,   0,   0, 166, 154, \n    144,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,  30,   0,   0,   8, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16, 128, \n     65,   0,   0,   0,  10,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,  55,   0, \n      0,  10, 114,   0,  16,   0, \n      9,   0,   0,   0, 166, 154, \n    144,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  30,   0,   0,   8, \n    114,   0,  16,   0,  11,   0, \n      0,   0,  70,   2,  16, 128, \n     65,   0,   0,   0,  10,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  55,   0, \n      0,  10, 114,   0,  16,   0, \n      3,   0,   0,   0, 166, 154, \n    144,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  31,   0,   4,   4, \n     42, 144, 144,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     33,   0,   0,  10, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  30,   0, \n      0,  12, 114,   0,  16,   0, \n     12,   0,   0,   0,   2,  64, \n      0,   0, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255,   0,   0,   0,   0, \n    150, 151, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n     13,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,  12,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,  13,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,  12,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,  13,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n     12,   0,   0,   0,  33,   0, \n      0,   7, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  34,   0, \n      0,   7, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,  60,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n     15,   0,   0,   0,  10,   0, \n     16,   0,  15,   0,   0,   0, \n     60,   0,   0,   7, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,  15,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   9,  18,   0,  16,   0, \n     15,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     10, 144, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   9,  34,   0,  16,   0, \n     15,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     26, 144, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   9,  66,   0,  16,   0, \n     15,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     42, 144, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   9, 130,   0,  16,   0, \n     15,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     58, 144, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  30,   0, \n      0,  10, 242,   0,  16,   0, \n     15,   0,   0,   0,  70,  14, \n     16,   0,  15,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255,   1,   0,   0,   7, \n    114,   0,  16,   0,  16,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,   6,   0, \n     16,   0,  15,   0,   0,   0, \n     30,   0,   0,  10, 114,   0, \n     16,   0,  17,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n      0,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  17,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,   1,   0, \n      0,   7, 114,   0,  16,   0, \n     18,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n    150,   7,  16,   0,  15,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,  18,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,  33,   0,   0,  10, \n    114,   0,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     33,   0,   0,   7, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n     13,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n     18,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     34,   0,   0,   7, 114,   0, \n     16,   0,  18,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,  70,   2,  16,   0, \n     18,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     19,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     18,   0,   0,   0,  33,   0, \n      0,  10, 114,   0,  16,   0, \n     20,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  33,   0,   0,   7, \n    114,   0,  16,   0,  21,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n     40,   0,   0,   5, 114,   0, \n     16,   0,  22,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  34,   0,   0,   7, \n    114,   0,  16,   0,  22,   0, \n      0,   0,  70,   2,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  22,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  23,   0,   0,   0, \n     70,   2,  16,   0,  20,   0, \n      0,   0,  70,   2,  16,   0, \n     21,   0,   0,   0,  70,   2, \n     16,   0,  22,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,  19,   0,   0,   0, \n     70,   2,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n     23,   0,   0,   0,  60,   0, \n      0,   7, 130,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,  19,   0,   0,   0, \n     10,   0,  16,   0,  19,   0, \n      0,   0,  60,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n     19,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     60,   0,   0,   7, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  17,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,   1,   0,   0,   7, \n    114,   0,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0, 150,   7, \n     16,   0,  15,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  18,   0,   0,   0, \n     70,   2,  16,   0,  18,   0, \n      0,   0,  70,   2,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  19,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  18,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,  21,   0, \n      0,   0,  70,   2,  16,   0, \n     17,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n      1,   0,   0,   7, 114,   0, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0, 150,   7,  16,   0, \n     15,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  22,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  20,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     13,   0,   0,   0,  18,   0, \n      0,   1,  41,   0,   0,   9, \n    130,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  10, 144, \n    208,   0,  32,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0, 255, 255, 255, 255, \n      1,   0,   0,   7, 114,   0, \n     16,   0,  16,   0,   0,   0, \n    246,  15,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,   1,   0, \n      0,   7, 114,   0,  16,   0, \n     11,   0,   0,   0, 246,  15, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   1,   0,   0,   7, \n    114,   0,  16,   0,  12,   0, \n      0,   0, 246,  15,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n      1,   0,   0,   7, 114,   0, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0, 246,  15,  16,   0, \n      5,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     21,   0,   0,   1,  30,   0, \n      0,  12, 242,   0,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n     70, 158, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   9,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,   1,   0,   0,   7, \n    114,   0,  16,   0,   3,   0, \n      0,   0,   6,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,  16,   0,   0,   0, \n     30,   0,   0,  10, 242,   0, \n     16,   0,  10,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255,   1,   0, \n      0,   7, 226,   0,  16,   0, \n      6,   0,   0,   0,   6,   0, \n     16,   0,  10,   0,   0,   0, \n      6,   9,  16,   0,  16,   0, \n      0,   0,  30,   0,   0,   8, \n    226,   0,  16,   0,   6,   0, \n      0,   0,   6,   0,  16, 128, \n     65,   0,   0,   0,   9,   0, \n      0,   0,  86,  14,  16,   0, \n      6,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n    150,   7,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n     16,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      3,   0,   0,   0, 246,  15, \n     16,   0,   0,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n     16,   0,   0,   0,  60,   0, \n      0,   8, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     42, 144, 144,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,   0,   0,   7, 226,   0, \n     16,   0,   6,   0,   0,   0, \n     86,  14,  16,   0,   9,   0, \n      0,   0,   6,   9,  16,   0, \n     11,   0,   0,   0,   1,   0, \n      0,   7, 114,   0,  16,   0, \n     14,   0,   0,   0, 150,   7, \n     16,   0,  10,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,  30,   0,   0,   8, \n    114,   0,  16,   0,  14,   0, \n      0,   0, 150,   7,  16, 128, \n     65,   0,   0,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n      6,   0,   0,   0,  86,  14, \n     16,   0,   6,   0,   0,   0, \n      6,   9,  16,   0,  14,   0, \n      0,   0,   6,   9,  16,   0, \n     11,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n      6,   0,   0,   0, 246,  15, \n     16,   0,   0,   0,   0,   0, \n     86,  14,  16,   0,   6,   0, \n      0,   0,   6,   9,  16,   0, \n     11,   0,   0,   0,   1,   0, \n      0,   7, 114,   0,  16,   0, \n     11,   0,   0,   0, 150,   7, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,   1,   0,   0,   7, \n    114,   0,  16,   0,  14,   0, \n      0,   0, 150,   7,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     30,   0,   0,   8, 114,   0, \n     16,   0,  14,   0,   0,   0, \n    150,   7,  16, 128,  65,   0, \n      0,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,  11,   0, \n      0,   0, 246,  15,  16,   0, \n      0,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,   1,   0,   0,   7, \n    114,   0,  16,   0,  12,   0, \n      0,   0, 150,   7,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n      1,   0,   0,   7, 226,   0, \n     16,   0,  10,   0,   0,   0, \n     86,  14,  16,   0,  10,   0, \n      0,   0,   6,   9,  16,   0, \n     13,   0,   0,   0,  30,   0, \n      0,   8, 114,   0,  16,   0, \n      9,   0,   0,   0, 150,   7, \n     16, 128,  65,   0,   0,   0, \n      9,   0,   0,   0, 150,   7, \n     16,   0,  10,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   9,   0,   0,   0, \n    246,  15,  16,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n     30,   0,   0,   7, 226,   0, \n     16,   0,  10,   0,   0,   0, \n      6,   9,  16,   0,   3,   0, \n      0,   0,  86,  14,  16,   0, \n      6,   0,   0,   0,  55,   0, \n      0,  10, 226,   0,  16,   0, \n      6,   0,   0,   0, 166, 154, \n    144,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  86,  14, \n     16,   0,  10,   0,   0,   0, \n     86,  14,  16,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n    226,   0,  16,   0,  10,   0, \n      0,   0,   6,   9,  16,   0, \n      3,   0,   0,   0,   6,   9, \n     16,   0,  11,   0,   0,   0, \n     55,   0,   0,  10, 226,   0, \n     16,   0,  10,   0,   0,   0, \n    166, 154, 144,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     86,  14,  16,   0,  10,   0, \n      0,   0,   6,   9,  16,   0, \n     11,   0,   0,   0,  30,   0, \n      0,   7, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  55,   0,   0,  10, \n    114,   0,  16,   0,   9,   0, \n      0,   0, 166, 154, 144,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     79,   0,   0,  12,  50,   0, \n     16,   0,  11,   0,   0,   0, \n      6, 144, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   2,  64, \n      0,   0,  15,   0,   0,   0, \n     16,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     41,   0,   0,   9, 130,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  10, 144, 208,   0, \n     32,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  32,   0, \n      0,   7, 114,   0,  16,   0, \n     12,   0,   0,   0, 246,  15, \n     16,   0,   0,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  32,   0,   0,   7, \n    114,   0,  16,   0,  13,   0, \n      0,   0, 246,  15,  16,   0, \n      0,   0,   0,   0, 150,   7, \n     16,   0,   6,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     15,   0,   0,   0, 150,   7, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  30,   0,   0,  10, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,  10, 114,   0, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,  15,   0, \n      0,   0,   2,  64,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   9, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     10, 144, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   9, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     10, 144, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  55,   0, \n      0,  12, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n      0,   0, 255, 255,   0,   0, \n    255, 255,   0,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  55,   0, \n      0,  12, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n      0,   0, 255, 255,   0,   0, \n    255, 255,   0,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  55,   0, \n      0,  12, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,  12, 114,   0,  16,   0, \n     13,   0,   0,   0, 150,   7, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     12,   0,   0,   0,   6,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     13,   0,   0,   0,   6,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0, 150,   7,  16,   0, \n      6,   0,   0,   0,  33,   0, \n      0,  10, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  33,   0,   0,  10, \n    114,   0,  16,   0,  15,   0, \n      0,   0, 150,   7,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     36,   0,   0,   8, 114,   0, \n     16,   0,  16,   0,   0,   0, \n     70,   2,  16, 128,  65,   0, \n      0,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  36,   0,   0,   8, \n    114,   0,  16,   0,  17,   0, \n      0,   0, 150,   7,  16, 128, \n     65,   0,   0,   0,   6,   0, \n      0,   0, 150,   7,  16,   0, \n      6,   0,   0,   0,  33,   0, \n      0,   7, 114,   0,  16,   0, \n     18,   0,   0,   0,  70,   2, \n     16,   0,  16,   0,   0,   0, \n      6,   0,  16,   0,  10,   0, \n      0,   0,  33,   0,   0,   7, \n    114,   0,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n     17,   0,   0,   0,   6,   0, \n     16,   0,  10,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  20,   0,   0,   0, \n     70,   2,  16,   0,  16,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     21,   0,   0,   0,  70,   2, \n     16,   0,  17,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  30,   0,   0,  10, \n    114,   0,  16,   0,  20,   0, \n      0,   0,  70,   2,  16,   0, \n     20,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0,  64,   0,   0,   0,  64, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,  10, 114,   0, \n     16,   0,  21,   0,   0,   0, \n     70,   2,  16,   0,  21,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  64,   0,   0,   0,  64, \n      0,   0,   0,  64,   0,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n     20,   0,   0,   0,  70,   2, \n     16,   0,  20,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,  21,   0, \n      0,   0,  70,   2,  16,   0, \n     21,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,  18,   0,   0,   0, \n     70,   2,  16,   0,  18,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,  70,   2, \n     16,   0,  20,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,  19,   0,   0,   0, \n     70,   2,  16,   0,  19,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,  70,   2, \n     16,   0,  21,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,  16,   0,   0,   0, \n     70,   2,  16,   0,  16,   0, \n      0,   0,  70,   2,  16,   0, \n     18,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,  17,   0,   0,   0, \n     70,   2,  16,   0,  17,   0, \n      0,   0,  70,   2,  16,   0, \n     19,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     40,   0,   0,   5, 114,   0, \n     16,   0,  18,   0,   0,   0, \n     70,   2,  16,   0,  16,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n     17,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,  16,   0, \n      0,   0,  70,   2,  16,   0, \n     18,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,  17,   0, \n      0,   0,  70,   2,  16,   0, \n     19,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      3,   0,   0,   0,  86,   5, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n      6,   0,   0,   0,  86,   5, \n     16,   0,  11,   0,   0,   0, \n      6,   9,  16,   0,  15,   0, \n      0,   0,  86,  14,  16,   0, \n      6,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      3,   0,   0,   0, 166,  10, \n     16,   0,   0,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n      6,   0,   0,   0, 166,  10, \n     16,   0,   0,   0,   0,   0, \n      6,   9,  16,   0,  13,   0, \n      0,   0,  86,  14,  16,   0, \n      6,   0,   0,   0,  32,   0, \n      0,   7, 114,   0,  16,   0, \n     12,   0,   0,   0, 246,  15, \n     16,   0,   0,   0,   0,   0, \n    150,   7,  16,   0,  10,   0, \n      0,   0,  32,   0,   0,   7, \n    114,   0,  16,   0,  13,   0, \n      0,   0, 246,  15,  16,   0, \n      0,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  14,   0,   0,   0, \n    150,   7,  16,   0,  10,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  30,   0,   0,  10, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,  10, 114,   0, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,  15,   0, \n      0,   0,   2,  64,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   9, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     10, 144, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   9, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n     10, 144, 208,   0,  32,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  55,   0, \n      0,  12, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n      0,   0, 255, 255,   0,   0, \n    255, 255,   0,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  55,   0, \n      0,  12, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n      0,   0, 255, 255,   0,   0, \n    255, 255,   0,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  55,   0, \n      0,  12, 114,   0,  16,   0, \n     12,   0,   0,   0, 150,   7, \n     16,   0,  10,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,  12, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     12,   0,   0,   0,   6,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0, 150,   7,  16,   0, \n     10,   0,   0,   0,  55,   0, \n      0,   9, 210,   0,  16,   0, \n     11,   0,   0,   0,   6,   0, \n     16,   0,  11,   0,   0,   0, \n      6,   9,  16,   0,  13,   0, \n      0,   0,   6,   9,  16,   0, \n      9,   0,   0,   0,  33,   0, \n      0,  10, 114,   0,  16,   0, \n     13,   0,   0,   0, 150,   7, \n     16,   0,  10,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  33,   0,   0,  10, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     36,   0,   0,   8, 114,   0, \n     16,   0,  15,   0,   0,   0, \n    150,   7,  16, 128,  65,   0, \n      0,   0,  10,   0,   0,   0, \n    150,   7,  16,   0,  10,   0, \n      0,   0,  36,   0,   0,   8, \n    114,   0,  16,   0,  16,   0, \n      0,   0,  70,   2,  16, 128, \n     65,   0,   0,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  33,   0, \n      0,   7, 114,   0,  16,   0, \n     17,   0,   0,   0,  70,   2, \n     16,   0,  15,   0,   0,   0, \n      6,   0,  16,   0,  10,   0, \n      0,   0,  33,   0,   0,   7, \n    114,   0,  16,   0,  18,   0, \n      0,   0,  70,   2,  16,   0, \n     16,   0,   0,   0,   6,   0, \n     16,   0,  10,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  19,   0,   0,   0, \n     70,   2,  16,   0,  15,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     20,   0,   0,   0,  70,   2, \n     16,   0,  16,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  30,   0,   0,  10, \n    114,   0,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n     19,   0,   0,   0,   2,  64, \n      0,   0,   0,  64,   0,   0, \n      0,  64,   0,   0,   0,  64, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,  10, 114,   0, \n     16,   0,  20,   0,   0,   0, \n     70,   2,  16,   0,  20,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  64,   0,   0,   0,  64, \n      0,   0,   0,  64,   0,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n     19,   0,   0,   0,  70,   2, \n     16,   0,  19,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,  20,   0, \n      0,   0,  70,   2,  16,   0, \n     20,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,  17,   0,   0,   0, \n     70,   2,  16,   0,  17,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,  70,   2, \n     16,   0,  19,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,  18,   0,   0,   0, \n     70,   2,  16,   0,  18,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 127,   0,   0, 255, 127, \n      0,   0, 255, 127,   0,   0, \n      0,   0,   0,   0,  70,   2, \n     16,   0,  20,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n     17,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,  12, 114,   0, \n     16,   0,  16,   0,   0,   0, \n     70,   2,  16,   0,  16,   0, \n      0,   0,  70,   2,  16,   0, \n     18,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     40,   0,   0,   5, 114,   0, \n     16,   0,  17,   0,   0,   0, \n     70,   2,  16,   0,  15,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  18,   0, \n      0,   0,  70,   2,  16,   0, \n     16,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n     17,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,  16,   0, \n      0,   0,  70,   2,  16,   0, \n     18,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     10,   0,   0,   0,  86,   5, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0, 150,   7,  16,   0, \n     10,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      9,   0,   0,   0,  86,   5, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     10,   0,   0,   0, 166,  10, \n     16,   0,   0,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      9,   0,   0,   0, 166,  10, \n     16,   0,   0,   0,   0,   0, \n    134,   3,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  29,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  29,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   5, \n     18,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  48,   0, \n      0,   1,  80,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      3,   0,   4,   3,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     85,   0,   0,   8, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     10, 144, 144,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n     11,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   8, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16, 128,  65,   0,   0,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     43,   0,   0,   5, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,  16,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     29,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  60,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  49,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     56,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n    253, 255, 125,  66,  14,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  28,   0,   0,   5, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  55,   0, \n      0,  11, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     10, 144, 208,   0,  46,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     55,   0,   0,   9, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     30,   0,   0,   9, 130,   0, \n     16,   0,   8,   0,   0,   0, \n      1,  64,   0,   0,  64,   0, \n      0,   0,  58, 144, 144, 128, \n     65,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     38,   0,   0,   9,   0, 208, \n      0,   0, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n    246, 159, 144,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     35,   0,   0,   9, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  10,   0, \n      0,   0, 246,  15,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     30,   0,   0,  10, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,   2,  64,   0,   0, \n     32,   0,   0,   0,  32,   0, \n      0,   0,  32,   0,   0,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  38,   0,   0,  11, \n      0, 208,   0,   0, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,   2,  64,   0,   0, \n     31,   0,   0,   0,  31,   0, \n      0,   0,  31,   0,   0,   0, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  34,   0,   0,  10, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     38,   0,   0,  11,   0, 208, \n      0,   0, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n      2,  64,   0,   0, 225, 255, \n    255, 255, 225, 255, 255, 255, \n    225, 255, 255, 255,   0,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     40,   0,   0,   5, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,  42,   0,   0,   7, \n    114,   0,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     34,   0,   0,  10, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     60,   0,   0,  10, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,   2,  64,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n     11,   0,   0,   0, 166,  10, \n     16,   0,   0,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  18,   0, \n      0,   1,  30,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   8, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16, 128,  65,   0, \n      0,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  43,   0,   0,   5, \n    114,   0,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,  16,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  29,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     60,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  49,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  56,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0, 253, 255, 125,  66, \n     14,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  28,   0, \n      0,   5, 130,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     55,   0,   0,  11, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  10, 144, 208,   0, \n     46,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  55,   0,   0,   9, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  30,   0,   0,   9, \n    130,   0,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n     64,   0,   0,   0,  58, 144, \n    144, 128,  65,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  38,   0,   0,   9, \n      0, 208,   0,   0, 114,   0, \n     16,   0,  12,   0,   0,   0, \n    150,   7,  16,   0,   6,   0, \n      0,   0, 246, 159, 144,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  35,   0,   0,   9, \n    114,   0,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0, 246,  15, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  30,   0,   0,  10, \n    114,   0,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,   2,  64, \n      0,   0,  32,   0,   0,   0, \n     32,   0,   0,   0,  32,   0, \n      0,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  38,   0, \n      0,  11,   0, 208,   0,   0, \n    114,   0,  16,   0,  13,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,   2,  64, \n      0,   0,  31,   0,   0,   0, \n     31,   0,   0,   0,  31,   0, \n      0,   0,   0,   0,   0,   0, \n     42,   0,   0,   7, 114,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  34,   0, \n      0,  10, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  38,   0,   0,  11, \n      0, 208,   0,   0, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,   2,  64,   0,   0, \n    225, 255, 255, 255, 225, 255, \n    255, 255, 225, 255, 255, 255, \n      0,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  40,   0,   0,   5, \n    114,   0,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,  42,   0, \n      0,   7, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,  34,   0,   0,  10, \n    114,   0,  16,   0,  13,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     40,   0,   0,   5, 114,   0, \n     16,   0,  15,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,  60,   0,   0,  10, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,  70,   2,  16,   0, \n     15,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  11,   0,   0,   0, \n    166,  10,  16,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     21,   0,   0,   1,   1,   0, \n      0,  10,  50,   0,  16,   0, \n     12,   0,   0,   0,   6,   0, \n     16,   0,  11,   0,   0,   0, \n      2,  64,   0,   0, 255,   3, \n      0,   0,   0, 124,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,  12,   0, \n      0,   0,  85,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  10,   0,  16,   0, \n     11,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,  18,   0, \n      0,   1,  31,   0,   4,   3, \n     10,   0,  16,   0,  12,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  10,   0,  16,   0, \n     12,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  48,   0, \n      0,   1,   1,   0,   0,   7, \n    130,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,   0,   4,   0,   0, \n      3,   0,   4,   3,  58,   0, \n     16,   0,  10,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  22,   0,   0,   1, \n      1,   0,   0,   7,  18,   0, \n     16,   0,  12,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n    254,   3,   0,   0,  18,   0, \n      0,   1,  54,   0,   0,   5, \n     18,   0,  16,   0,  12,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0, 144, 255, 255, 255, \n     21,   0,   0,   1,  21,   0, \n      0,   1,  41,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  10,   0,  16,   0, \n     11,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0, 128,  41,   0, \n      0,   7, 130,   0,  16,   0, \n     10,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,  56, \n     60,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n     10,   0,   0,   0,  10,   0, \n     16,   0,  12,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,  12,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,  10,   0,   0,   0, \n      1,   0,   0,  10, 146,   0, \n     16,   0,  11,   0,   0,   0, \n     86,   5,  16,   0,  11,   0, \n      0,   0,   2,  64,   0,   0, \n    255,   3,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0, 124,   0,   0,  31,   0, \n      4,   3,  58,   0,  16,   0, \n     11,   0,   0,   0,  85,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,  11,   0,   0,   0, \n      1,  64,   0,   0,  10,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n     18,   0,   0,   1,  31,   0, \n      4,   3,  10,   0,  16,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n     10,   0,   0,   0,  10,   0, \n     16,   0,  11,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,  11,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     48,   0,   0,   1,   1,   0, \n      0,   7, 130,   0,  16,   0, \n     12,   0,   0,   0,  58,   0, \n     16,   0,  11,   0,   0,   0, \n      1,  64,   0,   0,   0,   4, \n      0,   0,   3,   0,   4,   3, \n     58,   0,  16,   0,  12,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0, 255, 255, 255, 255, \n     41,   0,   0,   7, 130,   0, \n     16,   0,  11,   0,   0,   0, \n     58,   0,  16,   0,  11,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,   1,   0,   0,   7, \n     18,   0,  16,   0,  11,   0, \n      0,   0,  58,   0,  16,   0, \n     11,   0,   0,   0,   1,  64, \n      0,   0, 254,   3,   0,   0, \n     18,   0,   0,   1,  54,   0, \n      0,   5,  18,   0,  16,   0, \n     11,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   8,   0,   0,   0, \n      1,  64,   0,   0, 144, 255, \n    255, 255,  21,   0,   0,   1, \n     21,   0,   0,   1,  41,   0, \n      0,   7, 130,   0,  16,   0, \n     10,   0,   0,   0,  26,   0, \n     16,   0,  11,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0, 128, \n     41,   0,   0,   7,  34,   0, \n     16,   0,  11,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n     11,   0,   0,   0,  26,   0, \n     16,   0,  11,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,  56,  60,   0,   0,   7, \n    130,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,  26,   0, \n     16,   0,  11,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,  11,   0,   0,   0, \n     10,   0,  16,   0,  11,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n     12,   0,   0,   0,  58,   0, \n     16,   0,  10,   0,   0,   0, \n     10,   0,  16,   0,  11,   0, \n      0,   0,   1,   0,   0,  10, \n     50,   0,  16,   0,  11,   0, \n      0,   0, 166,  10,  16,   0, \n     11,   0,   0,   0,   2,  64, \n      0,   0, 255,   3,   0,   0, \n      0, 124,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,  11,   0,   0,   0, \n     85,   0,   0,   7, 130,   0, \n     16,   0,  10,   0,   0,   0, \n     42,   0,  16,   0,  11,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n     10,   0,   0,   0,  58,   0, \n     16,   0,  10,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,  18,   0,   0,   1, \n     31,   0,   4,   3,  10,   0, \n     16,   0,  11,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,  11,   0,   0,   0, \n     10,   0,  16,   0,  11,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n     12,   0,   0,   0,  26,   0, \n     16,   0,  11,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,  10,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  48,   0,   0,   1, \n      1,   0,   0,   7,  18,   0, \n     16,   0,  13,   0,   0,   0, \n     58,   0,  16,   0,  12,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   4,   0,   0,   3,   0, \n      4,   3,  10,   0,  16,   0, \n     13,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n     10,   0,   0,   0,  58,   0, \n     16,   0,  10,   0,   0,   0, \n      1,  64,   0,   0, 255, 255, \n    255, 255,  41,   0,   0,   7, \n    130,   0,  16,   0,  12,   0, \n      0,   0,  58,   0,  16,   0, \n     12,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     22,   0,   0,   1,   1,   0, \n      0,   7,  18,   0,  16,   0, \n     11,   0,   0,   0,  58,   0, \n     16,   0,  12,   0,   0,   0, \n      1,  64,   0,   0, 254,   3, \n      0,   0,  18,   0,   0,   1, \n     54,   0,   0,   5,  18,   0, \n     16,   0,  11,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,  10,   0, \n      0,   0,   1,  64,   0,   0, \n    144, 255, 255, 255,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     41,   0,   0,   7,  34,   0, \n     16,   0,  11,   0,   0,   0, \n     42,   0,  16,   0,  11,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,   0, \n      0,   7,  34,   0,  16,   0, \n     11,   0,   0,   0,  26,   0, \n     16,   0,  11,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0, 128,  41,   0,   0,   7, \n     66,   0,  16,   0,  11,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,  11,   0,   0,   0, \n     42,   0,  16,   0,  11,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,  56,  60,   0, \n      0,   7,  34,   0,  16,   0, \n     11,   0,   0,   0,  42,   0, \n     16,   0,  11,   0,   0,   0, \n     26,   0,  16,   0,  11,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,  11,   0, \n      0,   0,  10,   0,  16,   0, \n     11,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,  12,   0,   0,   0, \n     10,   0,  16,   0,  11,   0, \n      0,   0,  26,   0,  16,   0, \n     11,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n     11,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,  13,   0, \n      0,   0,  10,   0,  16,   0, \n     11,   0,   0,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,   0,   0,   0,   8, \n    114,   0,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16, 128,  65,   0,   0,   0, \n     13,   0,   0,   0,  16,   0, \n      0,   7,  18,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,   0,   0,   0,   7, \n    130,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,  10,   0, \n     16,   0,  11,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   6,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,  55,   0,   0,   9, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0, 236, 120, 173,  96, \n     58,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   8, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  58, 128,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0, 168,   0, \n      0,   8, 114, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     40,   0,   0,   0,  70,   2, \n     16,   0,   1,   0,   0,   0, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  31,   0,   4,   3, \n     10,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   8, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  40,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0, 167,   0, \n      0,   9, 226,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  40,   0, \n      0,   0,   6, 249,  17,   0, \n      0,   0,   0,   0,  49,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  31,   0,   4,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  40,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0, 168,   0,   0,   8, \n    114, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  40,   0, \n      0,   0, 134,   3,  16,   0, \n      4,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      3,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     40,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n    167,   0,   0,   9, 226,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     40,   0,   0,   0,   6, 249, \n     17,   0,   0,   0,   0,   0, \n     49,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  40,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8, 114, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     40,   0,   0,   0, 134,   3, \n     16,   0,   4,   0,   0,   0, \n     21,   0,   0,   1,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   8,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  40,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0, 167,   0,   0,   9, \n    226,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  40,   0,   0,   0, \n      6, 249,  17,   0,   0,   0, \n      0,   0,  49,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     40,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    168,   0,   0,   8, 114, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  40,   0,   0,   0, \n    134,   3,  16,   0,   3,   0, \n      0,   0,  21,   0,   0,   1, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  79,   0,   0,  10, \n     98,   0,  16,   0,   0,   0, \n      0,   0, 166,  10,  16,   0, \n      1,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   8,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  40,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n    226,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  40,   0,   0,   0, \n      6, 249,  17,   0,   0,   0, \n      0,   0,  49,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     40,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    168,   0,   0,   8, 114, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  40,   0,   0,   0, \n    134,   3,  16,   0,   2,   0, \n      0,   0,  21,   0,   0,   1, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  31,   0,   4,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   8, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  40,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 226,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  40,   0, \n      0,   0,   6, 249,  17,   0, \n      0,   0,   0,   0,  49,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  31,   0,   4,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  40,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0, 168,   0,   0,   8, \n    114, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  40,   0, \n      0,   0, 134,   3,  16,   0, \n      2,   0,   0,   0,  21,   0, \n      0,   1, 167,   0,   0,   9, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n      6, 112,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   8, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  40,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  49,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   8, \n    114,   0,  16,   0,   1,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  40,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     18,   0,   0,   1, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  70, 126,  16,   0, \n      1,   0,   0,   0,  21,   0, \n      0,   1, 168,   0,   0,   9, \n    242, 224,  17,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70,  14,  16,   0,   1,   0, \n      0,   0,  21,   0,   0,   1, \n     62,   0,   0,   1\n};\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/Shaders/Compiled/BC7Encode_EncodeBlockCS.inc",
    "content": "#if 0\n//\n// Generated by Microsoft (R) D3D Shader Disassembler\n//\n//\n// Input signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Input\n//\n// Output signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Output\ncs_4_0\ndcl_globalFlags refactoringAllowed\ndcl_immediateConstantBuffer { { 0x0000cccc, -0.000000, 15, 0},\n                              { 0x00008888, 65981199646559862278586368.000000, 15, 0},\n                              { 0x0000eeee, 15358528172589056.000000, 15, 0},\n                              { 0x0000ecc8, 3584194248704.000000, 15, 0},\n                              { 0x0000c880, -0.000000, 15, 0},\n                              { 0x0000feec, -0.000000, 15, 0},\n                              { 0x0000fec8, 14680365989888.000000, 15, 0},\n                              { 0x0000ec80, 15362462362632192.000000, 15, 0},\n                              { 0x0000c800, -0.000000, 15, 0},\n                              { 0x0000ffec, -0.000000, 15, 0},\n                              { 0x0000fe80, -0.000000, 15, 0},\n                              { 0x0000e800, -0.000000, 15, 0},\n                              { 0x0000ffe8, -0.000000, 15, 0},\n                              { 0x0000ff00, -0.000000, 15, 0},\n                              { 0x0000fff0, -0.000000, 15, 0},\n                              { 0x0000f000, 0.000000, 15, 0},\n                              { 0x0000f710, -0.000000, 15, 0},\n                              { 142, 0.000000, 2, 0},\n                              { 0x00007100, -0.000000, 8, 0},\n                              { 2254, 22076467445760.000000, 2, 0},\n                              { 140, -0.000000, 2, 0},\n                              { 0x00007310, 70798013459086900396556288.000000, 8, 0},\n                              { 0x00003100, -0.000000, 8, 0},\n                              { 0x00008cce, 0.000000, 15, 0},\n                              { 2188, 0x0050a4a4, 2, 0},\n                              { 0x00003110, -0.000000, 8, 0},\n                              { 0x00006666, 0.000000, 2, 0},\n                              { 0x0000366c, 17610885206241624413175808.000000, 2, 0},\n                              { 6120, -0.000000, 8, 0},\n                              { 4080, -0.000000, 8, 0},\n                              { 0x0000718e, 22097854464.000000, 2, 0},\n                              { 0x0000399c, 65888818352238724844093440.000000, 2, 0},\n                              { 0x0000aaaa, -0.000000, 15, 0},\n                              { 0x0000f0f0, 19411582976.000000, 15, 0},\n                              { 0x00005a5a, -0.000000, 6, 0},\n                              { 0x000033cc, 0.000000, 8, 0},\n                              { 0x00003c3c, 0.000000, 2, 0},\n                              { 0x000055aa, 0.000000, 8, 0},\n                              { 0x00009696, 0.000000, 15, 0},\n                              { 0x0000a55a, 22151331840.000000, 15, 0},\n                              { 0x000073ce, 9304358912.000000, 2, 0},\n                              { 5064, -0.000000, 8, 0},\n                              { 0x0000324c, 271536072765004599787520.000000, 2, 0},\n                              { 0x00003bdc, -0.000000, 2, 0},\n                              { 0x00006996, 21517107200.000000, 2, 0},\n                              { 0x0000c33c, 12724757752857622655008768.000000, 15, 0},\n                              { 0x00009966, 1365.320801, 15, 0},\n                              { 1632, 272006464738884193353728.000000, 6, 0},\n                              { 626, -0.000000, 6, 0},\n                              { 1252, 5783798415360.000000, 2, 0},\n                              { 0x00004e40, -0.000000, 6, 0},\n                              { 0x00002720, -0.000000, 8, 0},\n                              { 0x0000c936, -0.000000, 15, 0},\n                              { 0x0000936c, -0.000000, 15, 0},\n                              { 0x000039c6, -0.000000, 2, 0},\n                              { 0x0000639c, -0.000000, 2, 0},\n                              { 0x00009336, -0.000000, 15, 0},\n                              { 0x00009cc6, -0.000000, 15, 0},\n                              { 0x0000817e, -0.000000, 15, 0},\n                              { 0x0000e718, -0.000000, 15, 0},\n                              { 0x0000ccf0, 4.007874, 15, 0},\n                              { 4044, -0.000000, 2, 0},\n                              { 0x00007744, -0.000000, 2, 0},\n                              { 0x0000ee22, 0.000000, 15, 0},\n                              { 0, 0, 3, 15},\n                              { 0, 0, 3, 8},\n                              { 0, 0, 15, 8},\n                              { 1, 0, 15, 3},\n                              { 1, 0, 8, 15},\n                              { 1, 0, 3, 15},\n                              { 1, 0, 15, 3},\n                              { 2, 0, 15, 8},\n                              { 2, 0, 8, 15},\n                              { 2, 0, 8, 15},\n                              { 2, 0, 6, 15},\n                              { 2, 0, 6, 15},\n                              { 3, 0, 6, 15},\n                              { 3, 0, 5, 15},\n                              { 3, 0, 3, 15},\n                              { 3, 0, 3, 8},\n                              { 4, 0, 3, 15},\n                              { 4, 0, 3, 8},\n                              { 4, 0, 8, 15},\n                              { 4, 0, 15, 3},\n                              { 5, 0, 3, 15},\n                              { 5, 0, 3, 8},\n                              { 5, 0, 6, 15},\n                              { 5, 0, 10, 8},\n                              { 6, 0, 5, 3},\n                              { 6, 0, 8, 15},\n                              { 6, 0, 8, 6},\n                              { 6, 0, 6, 10},\n                              { 6, 0, 8, 15},\n                              { 7, 0, 5, 15},\n                              { 7, 0, 15, 10},\n                              { 7, 0, 15, 8},\n                              { 7, 0, 8, 15},\n                              { 8, 0, 15, 3},\n                              { 8, 0, 3, 15},\n                              { 8, 0, 5, 10},\n                              { 8, 0, 6, 10},\n                              { 9, 0, 10, 8},\n                              { 9, 0, 8, 9},\n                              { 9, 0, 15, 10},\n                              { 9, 0, 15, 6},\n                              { 10, 0, 3, 15},\n                              { 10, 0, 15, 8},\n                              { 10, 0, 5, 15},\n                              { 10, 0, 15, 3},\n                              { 10, 0, 15, 6},\n                              { 11, 0, 15, 6},\n                              { 11, 0, 15, 8},\n                              { 11, 0, 3, 15},\n                              { 11, 0, 15, 3},\n                              { 12, 0, 5, 15},\n                              { 12, 0, 5, 15},\n                              { 12, 0, 5, 15},\n                              { 12, 0, 8, 15},\n                              { 13, 0, 5, 15},\n                              { 13, 0, 10, 15},\n                              { 13, 0, 5, 15},\n                              { 13, 0, 10, 15},\n                              { 14, 0, 8, 15},\n                              { 14, 0, 13, 15},\n                              { 14, 0, 15, 3},\n                              { 14, 0, 12, 15},\n                              { 15, 0, 3, 15},\n                              { 15, 0, 3, 8},\n                              { 0, 15, 0, 0},\n                              { 0, 15, 0, 0},\n                              { 0, 15, 0, 0},\n                              { 0, 15, 0, 0},\n                              { 0, 15, 0, 0},\n                              { 1, 15, 0, 0},\n                              { 1, 15, 0, 0},\n                              { 1, 15, 0, 0},\n                              { 1, 15, 0, 0},\n                              { 1, 15, 0, 0},\n                              { 1, 15, 0, 0},\n                              { 1, 15, 0, 0},\n                              { 1, 15, 0, 0},\n                              { 1, 15, 0, 0},\n                              { 2, 15, 0, 0},\n                              { 2, 15, 0, 0},\n                              { 2, 15, 0, 0},\n                              { 2, 2, 0, 0},\n                              { 2, 8, 0, 0},\n                              { 2, 2, 0, 0},\n                              { 2, 2, 0, 0},\n                              { 2, 8, 0, 0},\n                              { 2, 8, 0, 0},\n                              { 3, 15, 0, 0},\n                              { 3, 2, 0, 0},\n                              { 3, 8, 0, 0},\n                              { 3, 2, 0, 0},\n                              { 3, 2, 0, 0},\n                              { 3, 8, 0, 0},\n                              { 3, 8, 0, 0},\n                              { 3, 2, 0, 0},\n                              { 3, 2, 0, 0},\n                              { 3, 15, 0, 0},\n                              { 4, 15, 0, 0},\n                              { 4, 6, 0, 0},\n                              { 4, 8, 0, 0},\n                              { 4, 2, 0, 0},\n                              { 4, 8, 0, 0},\n                              { 4, 15, 0, 0},\n                              { 4, 15, 0, 0},\n                              { 4, 2, 0, 0},\n                              { 4, 8, 0, 0},\n                              { 5, 2, 0, 0},\n                              { 5, 2, 0, 0},\n                              { 5, 2, 0, 0},\n                              { 5, 15, 0, 0},\n                              { 5, 15, 0, 0},\n                              { 5, 6, 0, 0},\n                              { 5, 6, 0, 0},\n                              { 5, 2, 0, 0},\n                              { 5, 6, 0, 0},\n                              { 6, 8, 0, 0},\n                              { 6, 15, 0, 0},\n                              { 6, 15, 0, 0},\n                              { 6, 2, 0, 0},\n                              { 6, 2, 0, 0},\n                              { 6, 15, 0, 0},\n                              { 6, 15, 0, 0},\n                              { 6, 15, 0, 0},\n                              { 6, 15, 0, 0},\n                              { 7, 15, 0, 0},\n                              { 7, 2, 0, 0},\n                              { 7, 2, 0, 0},\n                              { 7, 15, 0, 0},\n                              { 0, 3, 15, 0},\n                              { 0, 3, 8, 0},\n                              { 0, 8, 15, 0},\n                              { 0, 3, 15, 0},\n                              { 0, 8, 15, 0},\n                              { 0, 3, 15, 0},\n                              { 0, 3, 15, 0},\n                              { 0, 8, 15, 0},\n                              { 0, 8, 15, 0},\n                              { 0, 8, 15, 0},\n                              { 0, 6, 15, 0},\n                              { 1, 6, 15, 0},\n                              { 1, 6, 15, 0},\n                              { 1, 5, 15, 0},\n                              { 1, 3, 15, 0},\n                              { 1, 3, 8, 0},\n                              { 1, 3, 15, 0},\n                              { 1, 3, 8, 0},\n                              { 1, 8, 15, 0},\n                              { 1, 3, 15, 0},\n                              { 1, 3, 15, 0},\n                              { 1, 3, 8, 0},\n                              { 1, 6, 15, 0},\n                              { 1, 8, 10, 0},\n                              { 1, 3, 5, 0},\n                              { 1, 8, 15, 0},\n                              { 1, 6, 8, 0},\n                              { 1, 6, 10, 0},\n                              { 1, 8, 15, 0},\n                              { 1, 5, 15, 0},\n                              { 1, 10, 15, 0},\n                              { 1, 8, 15, 0},\n                              { 1, 8, 15, 0},\n                              { 2, 3, 15, 0},\n                              { 2, 3, 15, 0},\n                              { 2, 5, 10, 0},\n                              { 2, 6, 10, 0},\n                              { 2, 8, 10, 0},\n                              { 2, 8, 9, 0},\n                              { 2, 10, 15, 0},\n                              { 2, 6, 15, 0},\n                              { 2, 3, 15, 0},\n                              { 2, 8, 15, 0},\n                              { 2, 5, 15, 0},\n                              { 2, 3, 15, 0},\n                              { 2, 6, 15, 0},\n                              { 2, 6, 15, 0},\n                              { 2, 8, 15, 0},\n                              { 2, 3, 15, 0},\n                              { 2, 3, 15, 0},\n                              { 2, 5, 15, 0},\n                              { 2, 5, 15, 0},\n                              { 2, 5, 15, 0},\n                              { 2, 8, 15, 0},\n                              { 3, 5, 15, 0},\n                              { 3, 10, 15, 0},\n                              { 3, 5, 15, 0},\n                              { 3, 10, 15, 0},\n                              { 3, 8, 15, 0},\n                              { 3, 13, 15, 0},\n                              { 3, 3, 15, 0},\n                              { 3, 12, 15, 0},\n                              { 3, 3, 15, 0},\n                              { 3, 3, 8, 0} }\ndcl_constantbuffer CB0[2], immediateIndexed\ndcl_resource_texture2d (float,float,float,float) t0\ndcl_resource_structured t1, 16\ndcl_uav_structured u0, 16\ndcl_input vThreadIDInGroupFlattened\ndcl_input vThreadGroupID.x\ndcl_temps 15\ndcl_tgsm_structured g0, 100, 64\ndcl_thread_group 64, 1, 1\nushr r0.x, vThreadIDInGroupFlattened.x, l(4)\nishl r0.y, vThreadGroupID.x, l(2)\niadd r0.y, r0.y, cb0[1].x\niadd r0.x, r0.x, r0.y\nand r0.y, vThreadIDInGroupFlattened.x, l(48)\niadd r0.z, -r0.y, vThreadIDInGroupFlattened.x\nld_structured r1.xyz, r0.x, l(4), t1.xyzx\nand r0.w, r1.x, l(0x7fffffff)\nld_structured r2.x, r0.x, l(4), t1.xxxx\nushr r1.x, r2.x, l(31)\nult r2.xyzw, r0.zzzz, l(16, 8, 4, 2)\nif_nz r2.x\n  udiv r1.w, null, r0.x, cb0[0].y\n  imad r3.x, -r1.w, cb0[0].y, r0.x\n  ishl r3.x, r3.x, l(2)\n  ishl r1.w, r1.w, l(2)\n  and r3.y, r0.z, l(3)\n  iadd r3.x, r3.y, r3.x\n  ushr r4.x, r0.z, l(2)\n  iadd r3.y, r1.w, r4.x\n  mov r3.zw, l(0,0,0,0)\n  ld r3.xyzw, r3.xyzw, t0.xyzw\n  mul r3.xyzw, r3.xyzw, l(255.000000, 255.000000, 255.000000, 255.000000)\n  ftou r3.xyzw, r3.xyzw\n  umin r3.xyzw, r3.xyzw, l(255, 255, 255, 255)\n  ieq r4.xy, r0.wwww, l(4, 5, 0, 0)\n  or r1.w, r4.y, r4.x\n  ieq r4.xyz, r1.zzzz, l(1, 2, 3, 0)\n  movc r5.zw, r4.zzzz, r3.wwwz, r3.zzzw\n  mov r5.xy, r3.xyxx\n  movc r5.yzw, r4.yyyy, r3.wwzy, r5.yyzw\n  movc r4.xyzw, r4.xxxx, r3.wyzx, r5.xyzw\n  movc r3.xyzw, r1.wwww, r4.xyzw, r3.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(0), r3.xyzw\nendif \nsync_g_t\niadd r1.w, r1.y, l(-64)\nif_nz r2.x\n  ld_structured r3.xyzw, vThreadIDInGroupFlattened.x, l(0), g0.xyzw\n  ishl r4.x, r0.z, l(1)\n  ushr r4.x, icb[r1.w + 0].y, r4.x\n  and r4.x, r4.x, l(3)\n  ieq r4.yz, r0.wwww, l(0, 0, 2, 0)\n  or r4.y, r4.z, r4.y\n  ieq r4.x, r4.x, l(2)\n  movc r5.xyzw, r4.xxxx, r3.xyzw, l(-1,-1,-1,-1)\n  and r3.xyzw, r3.xyzw, r4.xxxx\n  movc r5.xyzw, r4.yyyy, r5.xyzw, l(-1,-1,-1,-1)\n  and r3.xyzw, r3.xyzw, r4.yyyy\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r5.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r3.xyzw\nendif \nsync_g_t\nif_nz r2.y\n  ld_structured r3.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r4.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r5.x, vThreadIDInGroupFlattened.x, l(8)\n  ld_structured r6.xyzw, r5.x, l(36), g0.xyzw\n  ld_structured r5.xyzw, r5.x, l(52), g0.xyzw\n  umin r3.xyzw, r3.xyzw, r6.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r3.xyzw\n  umax r3.xyzw, r4.xyzw, r5.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r3.xyzw\nendif \nsync_g_t\nif_nz r2.z\n  ld_structured r3.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r4.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r5.x, vThreadIDInGroupFlattened.x, l(4)\n  ld_structured r6.xyzw, r5.x, l(36), g0.xyzw\n  ld_structured r5.xyzw, r5.x, l(52), g0.xyzw\n  umin r3.xyzw, r3.xyzw, r6.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r3.xyzw\n  umax r3.xyzw, r4.xyzw, r5.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r3.xyzw\nendif \nsync_g_t\nif_nz r2.w\n  ld_structured r3.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r4.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r5.x, vThreadIDInGroupFlattened.x, l(2)\n  ld_structured r6.xyzw, r5.x, l(36), g0.xyzw\n  ld_structured r5.xyzw, r5.x, l(52), g0.xyzw\n  umin r3.xyzw, r3.xyzw, r6.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r3.xyzw\n  umax r3.xyzw, r4.xyzw, r5.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r3.xyzw\nendif \nsync_g_t\nult r3.xy, r0.zzzz, l(1, 3, 0, 0)\nif_nz r3.x\n  ld_structured r4.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r5.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r3.z, vThreadIDInGroupFlattened.x, l(1)\n  ld_structured r6.xyzw, r3.z, l(36), g0.xyzw\n  ld_structured r7.xyzw, r3.z, l(52), g0.xyzw\n  umin r4.xyzw, r4.xyzw, r6.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r4.xyzw\n  umax r4.xyzw, r5.xyzw, r7.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r4.xyzw\nendif \nsync_g_t\nieq r3.zw, r0.zzzz, l(0, 0, 2, 1)\nif_nz r3.z\n  ld_structured r4.xyzw, r0.y, l(36), g0.xyzw\n  ld_structured r5.xyzw, r0.y, l(52), g0.xyzw\nelse \n  mov r4.xyzw, l(-1,-1,-1,-1)\n  mov r5.xyzw, l(0,0,0,0)\nendif \nif_nz r2.x\n  ld_structured r6.xyzw, vThreadIDInGroupFlattened.x, l(0), g0.xyzw\n  ushr r3.z, icb[r1.y + 0].x, r0.z\n  and r3.z, r3.z, l(1)\n  ishl r7.x, r0.z, l(1)\n  ushr r7.x, icb[r1.w + 0].y, r7.x\n  and r7.x, r7.x, l(3)\n  ieq r8.xyzw, r0.wwww, l(0, 2, 1, 3)\n  ieq r7.x, r7.x, l(1)\n  movc r9.xyzw, r7.xxxx, r6.xyzw, l(-1,-1,-1,-1)\n  and r7.xyzw, r6.xyzw, r7.xxxx\n  or r8.xy, r8.ywyy, r8.xzxx\n  ieq r8.z, r0.w, l(7)\n  or r8.y, r8.z, r8.y\n  ieq r3.z, r3.z, l(1)\n  movc r10.xyzw, r3.zzzz, r6.xyzw, l(-1,-1,-1,-1)\n  and r6.xyzw, r6.xyzw, r3.zzzz\n  movc r10.xyzw, r8.yyyy, r10.xyzw, l(-1,-1,-1,-1)\n  and r6.xyzw, r6.xyzw, r8.yyyy\n  movc r9.xyzw, r8.xxxx, r9.xyzw, r10.xyzw\n  movc r6.xyzw, r8.xxxx, r7.xyzw, r6.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r9.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r6.xyzw\nendif \nsync_g_t\nif_nz r2.y\n  ld_structured r6.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r7.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r3.z, vThreadIDInGroupFlattened.x, l(8)\n  ld_structured r8.xyzw, r3.z, l(36), g0.xyzw\n  ld_structured r9.xyzw, r3.z, l(52), g0.xyzw\n  umin r6.xyzw, r6.xyzw, r8.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r6.xyzw\n  umax r6.xyzw, r7.xyzw, r9.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r6.xyzw\nendif \nsync_g_t\nif_nz r2.z\n  ld_structured r6.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r7.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r3.z, vThreadIDInGroupFlattened.x, l(4)\n  ld_structured r8.xyzw, r3.z, l(36), g0.xyzw\n  ld_structured r9.xyzw, r3.z, l(52), g0.xyzw\n  umin r6.xyzw, r6.xyzw, r8.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r6.xyzw\n  umax r6.xyzw, r7.xyzw, r9.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r6.xyzw\nendif \nsync_g_t\nif_nz r2.w\n  ld_structured r6.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r7.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r3.z, vThreadIDInGroupFlattened.x, l(2)\n  ld_structured r8.xyzw, r3.z, l(36), g0.xyzw\n  ld_structured r9.xyzw, r3.z, l(52), g0.xyzw\n  umin r6.xyzw, r6.xyzw, r8.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r6.xyzw\n  umax r6.xyzw, r7.xyzw, r9.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r6.xyzw\nendif \nsync_g_t\nif_nz r3.x\n  ld_structured r6.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r7.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r3.z, vThreadIDInGroupFlattened.x, l(1)\n  ld_structured r8.xyzw, r3.z, l(36), g0.xyzw\n  ld_structured r9.xyzw, r3.z, l(52), g0.xyzw\n  umin r6.xyzw, r6.xyzw, r8.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r6.xyzw\n  umax r6.xyzw, r7.xyzw, r9.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r6.xyzw\nendif \nsync_g_t\nif_nz r3.w\n  ld_structured r4.xyzw, r0.y, l(36), g0.xyzw\n  ld_structured r5.xyzw, r0.y, l(52), g0.xyzw\nendif \nif_nz r2.x\n  ld_structured r6.xyzw, vThreadIDInGroupFlattened.x, l(0), g0.xyzw\n  ushr r3.z, icb[r1.y + 0].x, r0.z\n  and r3.z, r3.z, l(1)\n  ishl r7.x, r0.z, l(1)\n  ushr r7.x, icb[r1.w + 0].y, r7.x\n  and r7.x, r7.x, l(3)\n  ieq r8.xyzw, r0.wwww, l(0, 2, 1, 3)\n  movc r9.xyzw, r7.xxxx, l(-1,-1,-1,-1), r6.xyzw\n  movc r7.xyzw, r7.xxxx, l(0,0,0,0), r6.xyzw\n  or r8.xy, r8.ywyy, r8.xzxx\n  ieq r10.xyzw, r0.wwww, l(7, 4, 5, 6)\n  or r8.y, r8.y, r10.x\n  movc r11.xyzw, r3.zzzz, l(-1,-1,-1,-1), r6.xyzw\n  movc r12.xyzw, r3.zzzz, l(0,0,0,0), r6.xyzw\n  or r3.z, r10.z, r10.y\n  or r3.z, r10.w, r3.z\n  movc r10.xyzw, r3.zzzz, r6.xyzw, l(-1,-1,-1,-1)\n  and r6.xyzw, r6.xyzw, r3.zzzz\n  movc r10.xyzw, r8.yyyy, r11.xyzw, r10.xyzw\n  movc r6.xyzw, r8.yyyy, r12.xyzw, r6.xyzw\n  movc r9.xyzw, r8.xxxx, r9.xyzw, r10.xyzw\n  movc r6.xyzw, r8.xxxx, r7.xyzw, r6.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r9.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r6.xyzw\nendif \nsync_g_t\nif_nz r2.y\n  ld_structured r6.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r7.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r2.y, vThreadIDInGroupFlattened.x, l(8)\n  ld_structured r8.xyzw, r2.y, l(36), g0.xyzw\n  ld_structured r9.xyzw, r2.y, l(52), g0.xyzw\n  umin r6.xyzw, r6.xyzw, r8.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r6.xyzw\n  umax r6.xyzw, r7.xyzw, r9.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r6.xyzw\nendif \nsync_g_t\nif_nz r2.z\n  ld_structured r6.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r7.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r2.y, vThreadIDInGroupFlattened.x, l(4)\n  ld_structured r8.xyzw, r2.y, l(36), g0.xyzw\n  ld_structured r9.xyzw, r2.y, l(52), g0.xyzw\n  umin r6.xyzw, r6.xyzw, r8.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r6.xyzw\n  umax r6.xyzw, r7.xyzw, r9.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r6.xyzw\nendif \nsync_g_t\nif_nz r2.w\n  ld_structured r6.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r7.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r2.y, vThreadIDInGroupFlattened.x, l(2)\n  ld_structured r8.xyzw, r2.y, l(36), g0.xyzw\n  ld_structured r9.xyzw, r2.y, l(52), g0.xyzw\n  umin r6.xyzw, r6.xyzw, r8.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r6.xyzw\n  umax r6.xyzw, r7.xyzw, r9.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r6.xyzw\nendif \nsync_g_t\nif_nz r3.x\n  ld_structured r6.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r7.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r2.y, vThreadIDInGroupFlattened.x, l(1)\n  ld_structured r8.xyzw, r2.y, l(36), g0.xyzw\n  ld_structured r9.xyzw, r2.y, l(52), g0.xyzw\n  umin r6.xyzw, r6.xyzw, r8.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r6.xyzw\n  umax r6.xyzw, r7.xyzw, r9.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r6.xyzw\nendif \nsync_g_t\nif_z r0.z\n  ld_structured r4.xyzw, r0.y, l(36), g0.xyzw\n  ld_structured r5.xyzw, r0.y, l(52), g0.xyzw\nendif \nif_nz r3.y\n  ieq r2.yzw, r0.wwww, l(0, 1, 4, 5)\n  ushr r3.x, r1.z, r0.z\n  and r3.x, r3.x, l(1)\n  ishl r3.y, r0.z, l(1)\n  ushr r6.x, r1.z, r3.y\n  iadd r3.y, r3.y, l(1)\n  ushr r6.y, r1.z, r3.y\n  and r3.yz, r6.xxyx, l(0, 1, 1, 0)\n  movc r3.xy, r2.yyyy, r3.xxxx, r3.yzyy\n  if_z r0.w\n    imad r6.xyz, r4.xyzx, l(7967, 7967, 7967, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n    ushr r6.xyz, r6.xyzx, l(16)\n    and r6.xyz, r6.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\n    iadd r6.xyz, r3.xxxx, r6.xyzx\n    ishl r6.xyz, r6.xyzx, l(3)\n    ushr r7.xyz, r6.xyzx, l(5)\n    or r7.xyz, r6.xyzx, r7.xyzx\n    imad r8.xyz, r5.xyzx, l(7967, 7967, 7967, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n    ushr r8.xyz, r8.xyzx, l(16)\n    and r8.xyz, r8.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\n    iadd r8.xyz, r3.yyyy, r8.xyzx\n    ishl r8.xyz, r8.xyzx, l(3)\n    ushr r9.xyz, r8.xyzx, l(5)\n    or r5.xyz, r8.xyzx, r9.xyzx\n    mov r5.w, l(255)\n    mov r4.xyw, l(255,2040,0,2040)\n  else \n    if_nz r2.y\n      imad r9.xyz, r4.xyzx, l(0x00007f7f, 0x00007f7f, 0x00007f7f, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n      ushr r9.xyz, r9.xyzx, l(16)\n      and r9.xyz, r9.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\n      iadd r9.xyz, r3.xxxx, r9.xyzx\n      ishl r6.xyz, r9.xyzx, l(1)\n      ushr r9.xyz, r6.xyzx, l(7)\n      or r7.xyz, r6.xyzx, r9.xyzx\n      imad r9.xyz, r5.xyzx, l(0x00007f7f, 0x00007f7f, 0x00007f7f, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n      ushr r9.xyz, r9.xyzx, l(16)\n      and r9.xyz, r9.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\n      iadd r9.xyz, r3.yyyy, r9.xyzx\n      ishl r8.xyz, r9.xyzx, l(1)\n      ushr r9.xyz, r8.xyzx, l(7)\n      or r5.xyz, r8.xyzx, r9.xyzx\n      mov r5.w, l(255)\n      mov r4.xyw, l(255,510,0,510)\n    else \n      ieq r2.y, r0.w, l(2)\n      if_nz r2.y\n        imad r9.xyz, r4.xyzx, l(7967, 7967, 7967, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n        ushr r9.xyz, r9.xyzx, l(16)\n        ishl r6.xyz, r9.xyzx, l(3)\n        ushr r9.xyz, r6.xyzx, l(5)\n        or r7.xyz, r6.xyzx, r9.xyzx\n        imad r9.xyz, r5.xyzx, l(7967, 7967, 7967, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n        ushr r9.xyz, r9.xyzx, l(16)\n        ishl r8.xyz, r9.xyzx, l(3)\n        ushr r9.xyz, r8.xyzx, l(5)\n        or r5.xyz, r8.xyzx, r9.xyzx\n        mov r5.w, l(255)\n        mov r4.xyw, l(255,2040,0,2040)\n      else \n        ieq r2.y, r0.w, l(3)\n        if_nz r2.y\n          and r9.xyz, r4.xyzx, l(-2, -2, -2, 0)\n          iadd r6.xyz, r3.xxxx, r9.xyzx\n          and r9.xyz, r5.xyzx, l(-2, -2, -2, 0)\n          iadd r8.xyz, r3.yyyy, r9.xyzx\n          mov r7.xyz, r6.xyzx\n          mov r5.xyz, r8.xyzx\n          mov r5.w, l(255)\n          mov r4.xyw, l(255,255,0,255)\n        else \n          ieq r2.y, r0.w, l(4)\n          if_nz r2.y\n            imad r9.xyzw, r4.xyzw, l(7967, 7967, 7967, 0x00003f3f), l(0x00008000, 0x00008000, 0x00008000, 0x00008000)\n            ushr r9.xyzw, r9.xyzw, l(16)\n            ishl r6.xyz, r9.xyzx, l(3)\n            ishl r6.w, r9.w, l(2)\n            ushr r9.xyz, r6.xyzx, l(5)\n            ushr r9.w, r6.w, l(6)\n            or r7.xyzw, r6.xyzw, r9.xyzw\n            imad r9.xyzw, r5.xyzw, l(7967, 7967, 7967, 0x00003f3f), l(0x00008000, 0x00008000, 0x00008000, 0x00008000)\n            ushr r9.xyzw, r9.xyzw, l(16)\n            ishl r4.xzw, r9.xxzy, l(3)\n            ishl r4.y, r9.w, l(2)\n            ushr r9.xyz, r4.xwzx, l(5)\n            ushr r9.w, r4.y, l(6)\n            or r5.xyzw, r4.xwzy, r9.xyzw\n            mov r8.xyz, r4.xwzx\n            mov r4.x, r7.w\n            mov r4.w, r6.w\n          else \n            ieq r2.y, r0.w, l(5)\n            if_nz r2.y\n              imad r9.xyz, r4.xyzx, l(0x00007f7f, 0x00007f7f, 0x00007f7f, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n              ushr r9.xyz, r9.xyzx, l(16)\n              ishl r6.xyz, r9.xyzx, l(1)\n              ushr r9.xyz, r6.xyzx, l(7)\n              or r7.xyz, r6.xyzx, r9.xyzx\n              imad r9.xyz, r5.xyzx, l(0x00007f7f, 0x00007f7f, 0x00007f7f, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n              ushr r9.xyz, r9.xyzx, l(16)\n              ishl r8.xyz, r9.xyzx, l(1)\n              ushr r9.xyz, r8.xyzx, l(7)\n              or r5.xyz, r8.xyzx, r9.xyzx\n              mov r4.x, r4.w\n              mov r4.y, r5.w\n            else \n              ieq r2.y, r0.w, l(6)\n              if_nz r2.y\n                and r9.xyzw, r4.xyzw, l(-2, -2, -2, -2)\n                iadd r6.xyzw, r3.xxxx, r9.xyzw\n                and r9.xyzw, r5.xyzw, l(-2, -2, -2, -2)\n                iadd r4.xyzw, r3.yyyy, r9.xwzy\n                mov r7.xyz, r6.xyzx\n                mov r5.xyzw, r4.xwzy\n                mov r8.xyz, r4.xwzx\n                mov r4.xw, r6.wwww\n              else \n                imad r9.xyzw, r4.xyzw, l(0x00003f3f, 0x00003f3f, 0x00003f3f, 0x00003f3f), l(0x00008000, 0x00008000, 0x00008000, 0x00008000)\n                ushr r9.xyzw, r9.xyzw, l(16)\n                and r9.xyzw, r9.xyzw, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0x0000fffe)\n                iadd r9.xyzw, r3.xxxx, r9.xyzw\n                ishl r6.xyzw, r9.xyzw, l(2)\n                ushr r10.xyzw, r6.xyzw, l(6)\n                or r4.xyzw, r6.wxzy, r10.wxzy\n                imad r10.xyzw, r5.xyzw, l(0x00003f3f, 0x00003f3f, 0x00003f3f, 0x00003f3f), l(0x00008000, 0x00008000, 0x00008000, 0x00008000)\n                ushr r10.xyzw, r10.xyzw, l(16)\n                and r10.xyzw, r10.xyzw, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0x0000fffe)\n                iadd r10.xyzw, r3.yyyy, r10.xwyz\n                ishl r8.xyzw, r10.xzwy, l(2)\n                ushr r11.xyzw, r8.xyzw, l(6)\n                or r5.xyzw, r8.xyzw, r11.xyzw\n                mov r10.x, r9.w\n                ishl r3.xy, r10.xyxx, l(2)\n                mov r7.xyz, r4.ywzy\n                mov r4.yw, r3.yyyx\n              endif \n            endif \n          endif \n        endif \n      endif \n    endif \n  endif \n  ineg r9.xyz, r7.xyzx\n  ineg r9.w, r4.x\n  iadd r10.xyzw, r5.xyzw, r9.xyzw\n  ult r2.y, r0.w, l(4)\n  movc r2.y, r2.y, l(0), r10.w\n  or r2.z, r2.w, r2.z\n  if_nz r2.z\n    if_z r0.z\n      imul null, r2.zw, r10.xxxy, r10.xxxy\n      iadd r2.z, r2.w, r2.z\n      imad r2.z, r10.z, r10.z, r2.z\n      imul null, r2.w, r2.y, r2.y\n      ld_structured r11.xyzw, r0.y, l(0), g0.xyzw\n      iadd r3.xyz, -r7.xyzx, r11.xyzx\n      imul null, r3.xy, r3.xyxx, r10.xyxx\n      iadd r3.x, r3.y, r3.x\n      imad r3.x, r10.z, r3.z, r3.x\n      iadd r3.y, -r4.x, r11.w\n      imul null, r3.y, r2.y, r3.y\n      ilt r3.z, l(0), r2.z\n      ilt r10.w, l(0), r3.x\n      and r3.z, r3.z, r10.w\n      itof r3.x, r3.x\n      mul r3.x, r3.x, l(63.499989)\n      ftou r3.x, r3.x\n      ishl r2.z, r2.z, l(5)\n      ult r2.z, r2.z, r3.x\n      and r2.z, r2.z, r3.z\n      movc r11.xyz, r2.zzzz, r5.xyzx, r7.xyzx\n      movc r5.xyz, r2.zzzz, r7.xyzx, r5.xyzx\n      movc r12.xyz, r2.zzzz, r8.xyzx, r6.xyzx\n      movc r8.xyz, r2.zzzz, r6.xyzx, r8.xyzx\n      ilt r2.z, l(0), r2.w\n      ilt r3.x, l(0), r3.y\n      and r2.z, r2.z, r3.x\n      itof r3.x, r3.y\n      mul r3.x, r3.x, l(63.499989)\n      ftou r3.x, r3.x\n      ishl r2.w, r2.w, l(5)\n      ult r2.w, r2.w, r3.x\n      and r2.z, r2.w, r2.z\n      mov r4.z, r5.w\n      movc r13.xyzw, r2.zzzz, r4.zxyw, r4.xzwy\n      mov r11.w, r13.x\n      mov r5.w, r13.y\n      mov r12.w, r13.z\n      mov r6.xyzw, r12.xyzw\n      mov r8.w, r13.w\n    else \n      mov r7.w, r4.x\n      mov r11.xyzw, r7.xyzw\n      mov r6.w, r4.w\n      mov r8.w, r4.y\n    endif \n  else \n    if_z r0.z\n      mov r2.z, l(0)\n    else \n      if_nz r3.w\n        mov r2.z, icb[r1.y + 0].z\n      else \n        mov r2.z, icb[r1.y + 0].w\n      endif \n    endif \n    imul null, r3.xy, r10.xyxx, r10.xyxx\n    iadd r2.w, r3.y, r3.x\n    imad r2.w, r10.z, r10.z, r2.w\n    imad r2.w, r2.y, r2.y, r2.w\n    iadd r2.z, r0.y, r2.z\n    ld_structured r3.xyzw, r2.z, l(0), g0.xyzw\n    iadd r3.xyzw, r9.xyzw, r3.xyzw\n    imul null, r3.xy, r3.xyxx, r10.xyxx\n    iadd r2.z, r3.y, r3.x\n    imad r2.z, r10.z, r3.z, r2.z\n    imad r2.y, r2.y, r3.w, r2.z\n    ilt r2.z, l(0), r2.w\n    ilt r3.x, l(0), r2.y\n    and r2.z, r2.z, r3.x\n    itof r2.y, r2.y\n    mul r2.y, r2.y, l(63.499989)\n    ftou r2.y, r2.y\n    ishl r2.w, r2.w, l(5)\n    ult r2.y, r2.w, r2.y\n    and r2.y, r2.y, r2.z\n    mov r7.w, r4.x\n    movc r11.xyzw, r2.yyyy, r5.xyzw, r7.xyzw\n    movc r5.xyzw, r2.yyyy, r7.xyzw, r5.xyzw\n    mov r8.w, r4.y\n    mov r4.xyz, r6.xyzx\n    movc r6.xyzw, r2.yyyy, r8.xyzw, r4.xyzw\n    movc r8.xyzw, r2.yyyy, r4.xyzw, r8.xyzw\n  endif \n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r11.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r5.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(68), r6.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(84), r8.xyzw\nendif \nsync_g_t\nif_nz r2.x\n  ieq r2.xyzw, r0.wwww, l(0, 1, 6, 4)\n  or r3.x, r2.y, r2.x\n  movc r3.yz, r1.xxxx, l(0,1,2,0), l(0,2,1,0)\n  movc r3.yz, r2.wwww, r3.yyzy, l(0,2,2,0)\n  movc r3.yz, r2.zzzz, l(0,0,0,0), r3.yyzy\n  movc r3.xy, r3.xxxx, l(1,1,0,0), r3.yzyy\n  ieq r4.xyzw, r0.wwww, l(2, 3, 7, 5)\n  ishl r2.z, r0.z, l(1)\n  ushr r1.w, icb[r1.w + 0].y, r2.z\n  and r1.w, r1.w, l(3)\n  or r2.xyz, r2.xywx, r4.xywx\n  or r2.y, r4.z, r2.y\n  ushr r2.w, icb[r1.y + 0].x, r0.z\n  and r2.y, r2.y, r2.w\n  and r2.y, r2.y, l(1)\n  movc r1.w, r2.x, r1.w, r2.y\n  iadd r1.w, r0.y, r1.w\n  ld_structured r4.xyzw, r1.w, l(36), g0.xyzw\n  ld_structured r5.xyzw, r1.w, l(52), g0.xyzw\n  iadd r5.xyzw, -r4.xyzw, r5.xyzw\n  ult r1.w, r0.w, l(4)\n  movc r1.w, r1.w, l(0), r5.w\n  if_nz r2.z\n    imul null, r2.xy, r5.xyxx, r5.xyxx\n    iadd r2.x, r2.y, r2.x\n    imad r2.x, r5.z, r5.z, r2.x\n    imul null, r2.y, r1.w, r1.w\n    ld_structured r6.xyzw, vThreadIDInGroupFlattened.x, l(0), g0.xyzw\n    iadd r7.xyzw, -r4.xyzw, r6.xyzw\n    imul null, r2.zw, r5.xxxy, r7.xxxy\n    iadd r2.z, r2.w, r2.z\n    imad r2.z, r5.z, r7.z, r2.z\n    ige r2.w, l(0), r2.x\n    ige r3.z, l(0), r2.z\n    or r2.w, r2.w, r3.z\n    ilt r3.z, r2.z, r2.x\n    itof r2.xz, r2.xxzx\n    mul r2.z, r2.z, l(63.499989)\n    div r2.x, r2.z, r2.x\n    ftou r2.x, r2.x\n    ishl r3.yw, r3.xxxy, l(6)\n    iadd r2.x, r2.x, r3.y\n    iadd r6.xy, r3.ywyy, l(11, 11, 0, 0)\n    udiv null, r6.xy, r6.xyxx, l(68, 68, 0, 0)\n    ult r7.xy, r3.ywyy, l(1, 1, 0, 0)\n    movc r6.xy, r7.xyxx, l(15,15,0,0), r6.xyxx\n    movc r2.x, r3.z, icb[r2.x + 64].x, r6.x\n    movc r7.y, r2.w, l(0), r2.x\n    imul null, r2.x, r1.w, r7.w\n    ige r2.zw, l(0, 0, 0, 0), r2.yyyx\n    or r2.z, r2.w, r2.z\n    ilt r2.w, r2.x, r2.y\n    itof r2.xy, r2.xyxx\n    mul r2.x, r2.x, l(63.499989)\n    div r2.x, r2.x, r2.y\n    ftou r2.x, r2.x\n    iadd r2.x, r2.x, r3.w\n    movc r2.x, r2.w, icb[r2.x + 64].x, r6.y\n    movc r7.x, r2.z, l(0), r2.x\n    movc r2.xy, r1.xxxx, r7.xyxx, r7.yxyy\n  else \n    imul null, r2.zw, r5.xxxy, r5.xxxy\n    iadd r2.z, r2.w, r2.z\n    imad r2.z, r5.z, r5.z, r2.z\n    imad r2.z, r1.w, r1.w, r2.z\n    ld_structured r6.xyzw, vThreadIDInGroupFlattened.x, l(0), g0.xyzw\n    iadd r4.xyzw, -r4.xyzw, r6.xyzw\n    imul null, r3.yz, r4.xxyx, r5.xxyx\n    iadd r2.w, r3.z, r3.y\n    imad r2.w, r5.z, r4.z, r2.w\n    imad r1.w, r1.w, r4.w, r2.w\n    ige r2.w, l(0), r2.z\n    ige r3.y, l(0), r1.w\n    or r2.w, r2.w, r3.y\n    ilt r3.y, r1.w, r2.z\n    itof r1.w, r1.w\n    mul r1.w, r1.w, l(63.499989)\n    itof r2.z, r2.z\n    div r1.w, r1.w, r2.z\n    ftou r1.w, r1.w\n    ishl r2.z, r3.x, l(6)\n    iadd r1.w, r1.w, r2.z\n    iadd r3.x, r2.z, l(11)\n    udiv null, r3.x, r3.x, l(68)\n    ult r2.z, r2.z, l(1)\n    movc r2.z, r2.z, l(15), r3.x\n    movc r1.w, r3.y, icb[r1.w + 64].x, r2.z\n    movc r2.x, r2.w, l(0), r1.w\n    mov r2.y, l(0)\n  endif \n  store_structured g0.xy, vThreadIDInGroupFlattened.x, l(16), r2.xyxx\nendif \nsync_g_t\nif_z r0.z\n  if_z r0.w\n    ishl r0.z, r1.y, l(1)\n    iadd r0.z, r0.z, l(-128)\n    iadd r0.z, r0.z, l(1)\n    ld_structured r2.xyz, r0.y, l(68), g0.xyzx\n    ishl r3.x, r2.x, l(1)\n    ishl r3.y, r2.y, l(25)\n    ishl r3.z, r2.z, l(17)\n    and r3.xyz, r3.xyzx, l(480, 0xe0000000, 0x01e00000, 0)\n    or r0.z, r0.z, r3.x\n    ld_structured r4.xyz, r0.y, l(84), g0.xyzx\n    ishl r5.x, r4.x, l(5)\n    ishl r5.y, r4.z, l(21)\n    and r2.xw, r5.xxxy, l(7680, 0, 0, 0x1e000000)\n    or r0.z, r0.z, r2.x\n    iadd r3.xw, r0.yyyy, l(1, 0, 0, 2)\n    ld_structured r5.xyz, r3.x, l(68), g0.xyzx\n    ishl r6.x, r5.x, l(9)\n    ishl r6.y, r5.y, l(1)\n    ishl r6.z, r5.z, l(25)\n    and r6.xyz, r6.xyzx, l(0x0001e000, 480, 0xe0000000, 0)\n    or r0.z, r0.z, r6.x\n    ld_structured r7.xyz, r3.x, l(84), g0.xyzx\n    ishl r8.x, r7.x, l(13)\n    ishl r8.y, r7.y, l(5)\n    and r4.xw, r8.xxxy, l(0x001e0000, 0, 0, 7680)\n    or r0.z, r0.z, r4.x\n    ld_structured r8.xyz, r3.w, l(68), g0.xyzx\n    ishl r9.x, r8.x, l(17)\n    ishl r9.y, r8.y, l(9)\n    ishl r9.z, r8.z, l(1)\n    and r9.xyz, r9.xyzx, l(0x01e00000, 0x0001e000, 480, 0)\n    or r0.z, r0.z, r9.x\n    ld_structured r10.xyz, r3.w, l(84), g0.xyzx\n    ishl r11.x, r10.x, l(21)\n    ishl r11.y, r10.y, l(13)\n    ishl r11.z, r10.z, l(5)\n    and r11.xyz, r11.xyzx, l(0x1e000000, 0x001e0000, 7680, 0)\n    or r0.z, r0.z, r11.x\n    or r12.x, r3.y, r0.z\n    ld_structured r13.xy, r0.y, l(68), g0.xyxx\n    ushr r0.z, r13.y, l(7)\n    and r0.z, r0.z, l(1)\n    ushr r1.w, r4.y, l(3)\n    and r1.w, r1.w, l(30)\n    iadd r0.z, r0.z, r1.w\n    iadd r0.z, r6.y, r0.z\n    iadd r0.z, r4.w, r0.z\n    iadd r0.z, r9.y, r0.z\n    iadd r0.z, r11.y, r0.z\n    iadd r0.z, r3.z, r0.z\n    iadd r0.z, r2.w, r0.z\n    iadd r12.y, r6.z, r0.z\n    ld_structured r2.x, r3.x, l(76), g0.xxxx\n    ushr r0.z, r2.x, l(7)\n    and r0.z, r0.z, l(1)\n    ushr r1.w, r7.z, l(3)\n    and r1.w, r1.w, l(30)\n    iadd r0.z, r0.z, r1.w\n    iadd r0.z, r9.z, r0.z\n    iadd r0.z, r11.z, r0.z\n    ishl r1.w, r13.x, l(10)\n    and r1.w, r1.w, l(8192)\n    iadd r0.z, r0.z, r1.w\n    ld_structured r2.x, r0.y, l(84), g0.xxxx\n    ishl r1.w, r2.x, l(11)\n    and r1.w, r1.w, l(0x00004000)\n    iadd r0.z, r0.z, r1.w\n    ld_structured r2.x, r3.x, l(68), g0.xxxx\n    ishl r1.w, r2.x, l(12)\n    and r1.w, r1.w, l(0x00008000)\n    iadd r0.z, r0.z, r1.w\n    ld_structured r2.x, r3.x, l(84), g0.xxxx\n    ishl r1.w, r2.x, l(13)\n    and r1.w, r1.w, l(0x00010000)\n    iadd r0.z, r0.z, r1.w\n    ld_structured r2.x, r3.w, l(68), g0.xxxx\n    ishl r1.w, r2.x, l(14)\n    and r1.w, r1.w, l(0x00020000)\n    iadd r0.z, r0.z, r1.w\n    ld_structured r2.x, r3.w, l(84), g0.xxxx\n    ishl r1.w, r2.x, l(15)\n    and r1.w, r1.w, l(0x00040000)\n    iadd r0.z, r0.z, r1.w\n    ld_structured r2.x, r0.y, l(16), g0.xxxx\n    ishl r1.w, r2.x, l(19)\n    iadd r0.z, r0.z, r1.w\n    umin r1.w, l(4), icb[r1.y + 128].y\n    mov r12.z, r0.z\n    mov r2.x, l(1)\n    loop \n      ult r2.y, r1.w, r2.x\n      breakc_nz r2.y\n      iadd r2.y, r0.y, r2.x\n      ld_structured r3.x, r2.y, l(16), g0.xxxx\n      imad r2.y, r2.x, l(3), l(18)\n      ishl r2.y, r3.x, r2.y\n      or r12.z, r2.y, r12.z\n      iadd r2.x, r2.x, l(1)\n    endloop \n    ult r0.z, icb[r1.y + 128].y, l(4)\n    if_nz r0.z\n      iadd r0.z, r0.y, l(4)\n      ld_structured r3.x, r0.z, l(16), g0.xxxx\n      ishl r0.z, r3.x, l(29)\n      or r12.z, r0.z, r12.z\n      iadd r2.z, r2.x, l(1)\n      mov r2.y, l(0)\n    else \n      iadd r0.z, r0.y, l(4)\n      ld_structured r3.x, r0.z, l(16), g0.xxxx\n      ushr r0.z, r3.x, l(2)\n      and r0.z, r0.z, l(1)\n      mov r2.y, r0.z\n      mov r2.z, r2.x\n      loop \n        ult r1.w, icb[r1.y + 128].y, r2.z\n        breakc_nz r1.w\n        iadd r1.w, r0.y, r2.z\n        ld_structured r3.x, r1.w, l(16), g0.xxxx\n        imad r1.w, r2.z, l(3), l(-14)\n        ishl r1.w, r3.x, r1.w\n        or r2.y, r1.w, r2.y\n        iadd r2.z, r2.z, l(1)\n      endloop \n    endif \n    mov r0.z, r2.y\n    mov r1.w, r2.z\n    loop \n      ult r2.x, icb[r1.y + 128].z, r1.w\n      breakc_nz r2.x\n      iadd r2.x, r0.y, r1.w\n      ld_structured r3.x, r2.x, l(16), g0.xxxx\n      imad r2.x, r1.w, l(3), l(-15)\n      ishl r2.x, r3.x, r2.x\n      or r0.z, r0.z, r2.x\n      iadd r1.w, r1.w, l(1)\n    endloop \n    mov r12.w, r0.z\n    mov r2.x, r1.w\n    loop \n      uge r2.y, r2.x, l(16)\n      breakc_nz r2.y\n      iadd r2.y, r0.y, r2.x\n      ld_structured r3.x, r2.y, l(16), g0.xxxx\n      imad r2.y, r2.x, l(3), l(-16)\n      ishl r2.y, r3.x, r2.y\n      or r12.w, r2.y, r12.w\n      iadd r2.x, r2.x, l(1)\n    endloop \n  else \n    ieq r0.z, r0.w, l(1)\n    if_nz r0.z\n      ishl r0.z, r1.y, l(2)\n      iadd r0.z, r0.z, l(2)\n      ld_structured r2.xyz, r0.y, l(68), g0.xyzx\n      ishl r3.x, r2.x, l(6)\n      ishl r3.y, r2.z, l(22)\n      and r2.xz, r3.xxyx, l(0x00003f00, 0, 0x3f000000, 0)\n      or r0.z, r0.z, r2.x\n      ld_structured r3.xyz, r0.y, l(84), g0.xyzx\n      ishl r4.x, r3.x, l(12)\n      ishl r4.y, r3.y, l(4)\n      ishl r4.z, r3.z, l(28)\n      and r3.xyz, r4.xyzx, l(0x000fc000, 4032, 0xc0000000, 0)\n      or r0.z, r0.z, r3.x\n      iadd r1.w, r0.y, l(1)\n      ld_structured r4.xyz, r1.w, l(68), g0.xyzx\n      ishl r5.x, r4.x, l(18)\n      ishl r5.y, r4.y, l(10)\n      ishl r5.z, r4.z, l(2)\n      and r4.xyz, r5.xyzx, l(0x03f00000, 0x0003f000, 1008, 0)\n      or r0.z, r0.z, r4.x\n      ld_structured r5.xyz, r1.w, l(84), g0.xyzx\n      ishl r6.x, r5.x, l(24)\n      ishl r6.y, r5.y, l(16)\n      ishl r6.z, r5.z, l(8)\n      and r5.xyz, r6.xyzx, l(0xfc000000, 0x00fc0000, 0x0000fc00, 0)\n      or r12.x, r0.z, r5.x\n      ushr r0.z, r2.y, l(2)\n      and r0.z, r0.z, l(63)\n      iadd r0.z, r3.y, r0.z\n      iadd r0.z, r4.y, r0.z\n      iadd r0.z, r5.y, r0.z\n      iadd r0.z, r2.z, r0.z\n      iadd r12.y, r3.z, r0.z\n      ld_structured r2.x, r0.y, l(92), g0.xxxx\n      ushr r0.z, r2.x, l(4)\n      and r0.z, r0.z, l(15)\n      iadd r0.z, r4.z, r0.z\n      iadd r0.z, r5.z, r0.z\n      ld_structured r2.x, r0.y, l(68), g0.xxxx\n      ishl r2.x, r2.x, l(15)\n      and r2.x, r2.x, l(0x00010000)\n      iadd r0.z, r0.z, r2.x\n      ld_structured r2.x, r1.w, l(68), g0.xxxx\n      ishl r2.x, r2.x, l(16)\n      and r2.x, r2.x, l(0x00020000)\n      iadd r0.z, r0.z, r2.x\n      ld_structured r2.x, r0.y, l(16), g0.xxxx\n      ishl r2.x, r2.x, l(18)\n      iadd r0.z, r0.z, r2.x\n      ieq r2.y, l(15), icb[r1.y + 128].y\n      if_nz r2.y\n        iadd r3.xyzw, r0.yyyy, l(15, 14, 13, 12)\n        ld_structured r4.x, r3.x, l(16), g0.xxxx\n        ishl r2.y, r4.x, l(30)\n        ld_structured r4.x, r3.y, l(16), g0.xxxx\n        ishl r2.z, r4.x, l(27)\n        or r2.y, r2.z, r2.y\n        ld_structured r4.x, r3.z, l(16), g0.xxxx\n        ishl r2.z, r4.x, l(24)\n        or r2.y, r2.z, r2.y\n        ld_structured r3.x, r3.w, l(16), g0.xxxx\n        ishl r2.z, r3.x, l(21)\n        or r2.y, r2.z, r2.y\n        iadd r3.xyzw, r0.yyyy, l(11, 10, 9, 8)\n        ld_structured r4.x, r3.x, l(16), g0.xxxx\n        ishl r2.z, r4.x, l(18)\n        or r2.y, r2.z, r2.y\n        ld_structured r4.x, r3.y, l(16), g0.xxxx\n        ishl r2.z, r4.x, l(15)\n        or r2.y, r2.z, r2.y\n        ld_structured r4.x, r3.z, l(16), g0.xxxx\n        ishl r2.z, r4.x, l(12)\n        or r2.y, r2.z, r2.y\n        ld_structured r3.x, r3.w, l(16), g0.xxxx\n        ishl r2.z, r3.x, l(9)\n        or r2.y, r2.z, r2.y\n        iadd r3.xyzw, r0.yyyy, l(7, 6, 5, 4)\n        ld_structured r4.x, r3.x, l(16), g0.xxxx\n        ishl r2.z, r4.x, l(6)\n        or r2.y, r2.z, r2.y\n        ld_structured r4.x, r3.y, l(16), g0.xxxx\n        ishl r2.z, r4.x, l(3)\n        or r2.y, r2.z, r2.y\n        ld_structured r4.x, r3.z, l(16), g0.xxxx\n        or r12.w, r2.y, r4.x\n        ld_structured r3.x, r3.w, l(16), g0.xxxx\n        ishl r2.y, r3.x, l(29)\n        iadd r2.zw, r0.yyyy, l(0, 0, 3, 2)\n        ld_structured r3.x, r2.z, l(16), g0.xxxx\n        ishl r2.z, r3.x, l(26)\n        or r2.y, r2.z, r2.y\n        ld_structured r3.x, r2.w, l(16), g0.xxxx\n        ishl r2.z, r3.x, l(23)\n        or r2.y, r2.z, r2.y\n        ld_structured r3.x, r1.w, l(16), g0.xxxx\n        ishl r2.z, r3.x, l(20)\n        or r2.y, r2.z, r2.y\n        or r2.y, r2.x, r2.y\n        or r12.z, r0.z, r2.y\n      else \n        ieq r2.y, l(2), icb[r1.y + 128].y\n        if_nz r2.y\n          iadd r3.xyzw, r0.yyyy, l(15, 14, 13, 12)\n          ld_structured r4.x, r3.x, l(16), g0.xxxx\n          ishl r2.y, r4.x, l(29)\n          ld_structured r4.x, r3.y, l(16), g0.xxxx\n          ishl r2.z, r4.x, l(26)\n          or r2.y, r2.z, r2.y\n          ld_structured r4.x, r3.z, l(16), g0.xxxx\n          ishl r2.z, r4.x, l(23)\n          or r2.y, r2.z, r2.y\n          ld_structured r3.x, r3.w, l(16), g0.xxxx\n          ishl r2.z, r3.x, l(20)\n          or r2.y, r2.z, r2.y\n          iadd r3.xyzw, r0.yyyy, l(11, 10, 9, 8)\n          ld_structured r4.x, r3.x, l(16), g0.xxxx\n          ishl r2.z, r4.x, l(17)\n          or r2.y, r2.z, r2.y\n          ld_structured r4.x, r3.y, l(16), g0.xxxx\n          ishl r2.z, r4.x, l(14)\n          or r2.y, r2.z, r2.y\n          ld_structured r4.x, r3.z, l(16), g0.xxxx\n          ishl r2.z, r4.x, l(11)\n          or r2.y, r2.z, r2.y\n          ld_structured r3.x, r3.w, l(16), g0.xxxx\n          ishl r2.z, r3.x, l(8)\n          or r2.y, r2.z, r2.y\n          iadd r3.xyzw, r0.yyyy, l(7, 6, 5, 4)\n          ld_structured r4.x, r3.x, l(16), g0.xxxx\n          ishl r2.z, r4.x, l(5)\n          or r2.y, r2.z, r2.y\n          ld_structured r4.x, r3.y, l(16), g0.xxxx\n          ishl r2.z, r4.x, l(2)\n          or r2.y, r2.z, r2.y\n          ld_structured r4.x, r3.z, l(16), g0.xxxx\n          ushr r2.z, r4.x, l(1)\n          or r12.w, r2.z, r2.y\n          ishl r2.y, r4.x, l(31)\n          ld_structured r3.x, r3.w, l(16), g0.xxxx\n          ishl r2.z, r3.x, l(28)\n          or r2.y, r2.z, r2.y\n          iadd r2.zw, r0.yyyy, l(0, 0, 3, 2)\n          ld_structured r3.x, r2.z, l(16), g0.xxxx\n          ishl r2.z, r3.x, l(25)\n          or r2.y, r2.z, r2.y\n          ld_structured r3.x, r2.w, l(16), g0.xxxx\n          ishl r2.z, r3.x, l(23)\n          or r2.y, r2.z, r2.y\n          ld_structured r3.x, r1.w, l(16), g0.xxxx\n          ishl r2.z, r3.x, l(20)\n          or r2.y, r2.z, r2.y\n          or r2.y, r2.x, r2.y\n          or r12.z, r0.z, r2.y\n        else \n          ieq r2.y, l(8), icb[r1.y + 128].y\n          if_nz r2.y\n            iadd r3.xyzw, r0.yyyy, l(15, 14, 13, 12)\n            ld_structured r4.x, r3.x, l(16), g0.xxxx\n            ishl r2.y, r4.x, l(29)\n            ld_structured r4.x, r3.y, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(26)\n            or r2.y, r2.z, r2.y\n            ld_structured r4.x, r3.z, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(23)\n            or r2.y, r2.z, r2.y\n            ld_structured r3.x, r3.w, l(16), g0.xxxx\n            ishl r2.z, r3.x, l(20)\n            or r2.y, r2.z, r2.y\n            iadd r3.xyzw, r0.yyyy, l(11, 10, 9, 8)\n            ld_structured r4.x, r3.x, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(17)\n            or r2.y, r2.z, r2.y\n            ld_structured r4.x, r3.y, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(14)\n            or r2.y, r2.z, r2.y\n            ld_structured r4.x, r3.z, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(11)\n            or r2.y, r2.z, r2.y\n            ld_structured r3.x, r3.w, l(16), g0.xxxx\n            ishl r2.z, r3.x, l(9)\n            or r2.y, r2.z, r2.y\n            iadd r3.xyzw, r0.yyyy, l(7, 6, 5, 4)\n            ld_structured r4.x, r3.x, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(6)\n            or r2.y, r2.z, r2.y\n            ld_structured r4.x, r3.y, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(3)\n            or r2.y, r2.z, r2.y\n            ld_structured r4.x, r3.z, l(16), g0.xxxx\n            or r12.w, r2.y, r4.x\n            ld_structured r3.x, r3.w, l(16), g0.xxxx\n            ishl r2.y, r3.x, l(29)\n            iadd r2.zw, r0.yyyy, l(0, 0, 3, 2)\n            ld_structured r3.x, r2.z, l(16), g0.xxxx\n            ishl r2.z, r3.x, l(26)\n            or r2.y, r2.z, r2.y\n            ld_structured r3.x, r2.w, l(16), g0.xxxx\n            ishl r2.z, r3.x, l(23)\n            or r2.y, r2.z, r2.y\n            ld_structured r3.x, r1.w, l(16), g0.xxxx\n            ishl r2.z, r3.x, l(20)\n            or r2.y, r2.z, r2.y\n            or r2.y, r2.x, r2.y\n            or r12.z, r0.z, r2.y\n          else \n            iadd r3.xyzw, r0.yyyy, l(15, 14, 13, 12)\n            ld_structured r4.x, r3.x, l(16), g0.xxxx\n            ishl r2.y, r4.x, l(29)\n            ld_structured r4.x, r3.y, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(26)\n            or r2.y, r2.z, r2.y\n            ld_structured r4.x, r3.z, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(23)\n            or r2.y, r2.z, r2.y\n            ld_structured r3.x, r3.w, l(16), g0.xxxx\n            ishl r2.z, r3.x, l(20)\n            or r2.y, r2.z, r2.y\n            iadd r3.xyzw, r0.yyyy, l(11, 10, 9, 8)\n            ld_structured r4.x, r3.x, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(17)\n            or r2.y, r2.z, r2.y\n            ld_structured r4.x, r3.y, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(14)\n            or r2.y, r2.z, r2.y\n            ld_structured r4.x, r3.z, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(11)\n            or r2.y, r2.z, r2.y\n            ld_structured r3.x, r3.w, l(16), g0.xxxx\n            ishl r2.z, r3.x, l(8)\n            or r2.y, r2.z, r2.y\n            iadd r3.xyzw, r0.yyyy, l(7, 6, 5, 4)\n            ld_structured r4.x, r3.x, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(5)\n            or r2.y, r2.z, r2.y\n            ld_structured r4.x, r3.y, l(16), g0.xxxx\n            ishl r2.z, r4.x, l(3)\n            or r2.y, r2.z, r2.y\n            ld_structured r4.x, r3.z, l(16), g0.xxxx\n            or r12.w, r2.y, r4.x\n            ld_structured r3.x, r3.w, l(16), g0.xxxx\n            ishl r2.y, r3.x, l(29)\n            iadd r2.zw, r0.yyyy, l(0, 0, 3, 2)\n            ld_structured r3.x, r2.z, l(16), g0.xxxx\n            ishl r2.z, r3.x, l(26)\n            or r2.y, r2.z, r2.y\n            ld_structured r3.x, r2.w, l(16), g0.xxxx\n            ishl r2.z, r3.x, l(23)\n            or r2.y, r2.z, r2.y\n            ld_structured r3.x, r1.w, l(16), g0.xxxx\n            ishl r1.w, r3.x, l(20)\n            or r1.w, r1.w, r2.y\n            or r1.w, r2.x, r1.w\n            or r12.z, r0.z, r1.w\n          endif \n        endif \n      endif \n    else \n      ieq r0.z, r0.w, l(2)\n      if_nz r0.z\n        ishl r0.z, r1.y, l(3)\n        iadd r0.z, r0.z, l(-512)\n        iadd r0.z, r0.z, l(4)\n        ld_structured r2.xyz, r0.y, l(68), g0.xyzx\n        ishl r3.x, r2.x, l(6)\n        ishl r3.y, r2.y, l(4)\n        ishl r3.z, r2.z, l(2)\n        and r3.xyz, r3.xyzx, l(0x00003e00, 3968, 992, 0)\n        or r0.z, r0.z, r3.x\n        ld_structured r4.xyz, r0.y, l(84), g0.xyzx\n        ishl r5.x, r4.x, l(11)\n        ishl r5.y, r4.y, l(9)\n        ishl r5.z, r4.z, l(7)\n        and r5.xyz, r5.xyzx, l(0x0007c000, 0x0001f000, 0x00007c00, 0)\n        or r0.z, r0.z, r5.x\n        iadd r2.xw, r0.yyyy, l(1, 0, 0, 2)\n        ld_structured r6.xyz, r2.x, l(68), g0.xyzx\n        ishl r7.x, r6.x, l(16)\n        ishl r7.y, r6.y, l(14)\n        ishl r7.z, r6.z, l(12)\n        and r7.xyz, r7.xyzx, l(0x00f80000, 0x003e0000, 0x000f8000, 0)\n        or r0.z, r0.z, r7.x\n        ld_structured r8.xyz, r2.x, l(84), g0.xyzx\n        ishl r9.x, r8.x, l(21)\n        ishl r9.y, r8.y, l(19)\n        ishl r9.z, r8.z, l(17)\n        and r9.xyz, r9.xyzx, l(0x1f000000, 0x07c00000, 0x01f00000, 0)\n        or r0.z, r0.z, r9.x\n        ld_structured r10.xyz, r2.w, l(68), g0.xyzx\n        ishl r11.x, r10.x, l(26)\n        ishl r11.y, r10.y, l(24)\n        ishl r11.z, r10.z, l(22)\n        and r11.xyz, r11.xyzx, l(0xe0000000, 0xf8000000, 0x3e000000, 0)\n        or r12.x, r0.z, r11.x\n        ld_structured r13.x, r2.w, l(68), g0.xxxx\n        ushr r0.z, r13.x, l(6)\n        and r0.z, r0.z, l(3)\n        ld_structured r13.xyz, r2.w, l(84), g0.xyzx\n        ushr r14.x, r13.x, l(1)\n        ushr r14.y, r13.y, l(3)\n        and r3.xw, r14.xxxy, l(124, 0, 0, 31)\n        iadd r0.z, r0.z, r3.x\n        iadd r0.z, r3.y, r0.z\n        iadd r0.z, r5.y, r0.z\n        iadd r0.z, r7.y, r0.z\n        iadd r0.z, r9.y, r0.z\n        iadd r12.y, r11.y, r0.z\n        iadd r0.z, r3.z, r3.w\n        iadd r0.z, r5.z, r0.z\n        iadd r0.z, r7.z, r0.z\n        iadd r0.z, r9.z, r0.z\n        iadd r0.z, r11.z, r0.z\n        ishl r1.w, r13.z, l(27)\n        and r1.w, r1.w, l(0xc0000000)\n        iadd r12.z, r0.z, r1.w\n        ld_structured r2.x, r2.w, l(92), g0.xxxx\n        ushr r0.z, r2.x, l(5)\n        and r0.z, r0.z, l(7)\n        ld_structured r2.x, r0.y, l(16), g0.xxxx\n        ishl r1.w, r2.x, l(3)\n        iadd r0.z, r0.z, r1.w\n        mov r1.w, r0.z\n        mov r2.x, l(1)\n        loop \n          ult r2.y, icb[r1.y + 128].y, r2.x\n          breakc_nz r2.y\n          iadd r2.y, r0.y, r2.x\n          ld_structured r3.x, r2.y, l(16), g0.xxxx\n          ishl r2.y, r2.x, l(1)\n          iadd r2.y, r2.y, l(2)\n          ishl r2.y, r3.x, r2.y\n          or r1.w, r1.w, r2.y\n          iadd r2.x, r2.x, l(1)\n        endloop \n        mov r0.z, r1.w\n        mov r2.y, r2.x\n        loop \n          ult r2.z, icb[r1.y + 128].z, r2.y\n          breakc_nz r2.z\n          iadd r2.z, r0.y, r2.y\n          ld_structured r3.x, r2.z, l(16), g0.xxxx\n          ishl r2.z, r2.y, l(1)\n          iadd r2.z, r2.z, l(1)\n          ishl r2.z, r3.x, r2.z\n          or r0.z, r0.z, r2.z\n          iadd r2.y, r2.y, l(1)\n        endloop \n        mov r12.w, r0.z\n        mov r1.w, r2.y\n        loop \n          uge r2.x, r1.w, l(16)\n          breakc_nz r2.x\n          iadd r2.x, r0.y, r1.w\n          ld_structured r3.x, r2.x, l(16), g0.xxxx\n          ishl r2.x, r1.w, l(1)\n          ishl r2.x, r3.x, r2.x\n          or r12.w, r2.x, r12.w\n          iadd r1.w, r1.w, l(1)\n        endloop \n      else \n        ieq r0.z, r0.w, l(3)\n        if_nz r0.z\n          ishl r0.z, r1.y, l(4)\n          iadd r0.z, r0.z, l(8)\n          ld_structured r2.xyz, r0.y, l(68), g0.xyzx\n          ishl r3.x, r2.x, l(9)\n          ishl r3.y, r2.y, l(5)\n          ishl r3.z, r2.z, l(1)\n          and r3.xyz, r3.xyzx, l(0x0001fc00, 8128, 508, 0)\n          or r0.z, r0.z, r3.x\n          ld_structured r4.xyz, r0.y, l(84), g0.xyzx\n          ishl r5.x, r4.x, l(16)\n          ishl r5.y, r4.y, l(12)\n          ishl r5.z, r4.z, l(8)\n          and r5.xyz, r5.xyzx, l(0x00fe0000, 0x000fe000, 0x0000fe00, 0)\n          or r0.z, r0.z, r5.x\n          iadd r1.w, r0.y, l(1)\n          ld_structured r6.xyz, r1.w, l(68), g0.xyzx\n          ishl r7.x, r6.x, l(23)\n          ishl r7.y, r6.y, l(19)\n          ishl r7.z, r6.z, l(15)\n          and r7.xyz, r7.xyzx, l(0x7f000000, 0x07f00000, 0x007f0000, 0)\n          or r0.z, r0.z, r7.x\n          ld_structured r8.xyz, r1.w, l(84), g0.xyzx\n          ishl r9.x, r8.x, l(30)\n          ishl r9.y, r8.y, l(26)\n          ishl r9.z, r8.z, l(22)\n          and r9.xyz, r9.xyzx, l(0x80000000, 0xf8000000, 0x3f800000, 0)\n          or r12.x, r0.z, r9.x\n          ld_structured r10.xy, r1.w, l(84), g0.xyxx\n          ushr r11.x, r10.x, l(2)\n          ushr r11.y, r10.y, l(6)\n          and r2.xw, r11.xxxy, l(63, 0, 0, 3)\n          iadd r2.xy, r3.yzyy, r2.xwxx\n          iadd r2.xy, r5.yzyy, r2.xyxx\n          iadd r2.xy, r7.yzyy, r2.xyxx\n          iadd r2.xy, r9.yzyy, r2.xyxx\n          ld_structured r3.x, r0.y, l(68), g0.xxxx\n          ishl r0.z, r3.x, l(30)\n          and r0.z, r0.z, l(0x40000000)\n          iadd r0.z, r0.z, r2.y\n          ld_structured r3.x, r0.y, l(84), g0.xxxx\n          ishl r2.y, r3.x, l(31)\n          iadd r12.z, r0.z, r2.y\n          ld_structured r3.x, r1.w, l(68), g0.xxxx\n          and r0.z, r3.x, l(1)\n          ld_structured r3.x, r1.w, l(84), g0.xxxx\n          ishl r1.w, r3.x, l(1)\n          and r1.w, r1.w, l(2)\n          iadd r0.z, r0.z, r1.w\n          ld_structured r3.x, r0.y, l(16), g0.xxxx\n          ishl r1.w, r3.x, l(2)\n          iadd r0.z, r0.z, r1.w\n          mov r1.w, r0.z\n          mov r2.y, l(1)\n          loop \n            ult r2.z, icb[r1.y + 128].y, r2.y\n            breakc_nz r2.z\n            iadd r2.z, r0.y, r2.y\n            ld_structured r3.x, r2.z, l(16), g0.xxxx\n            ishl r2.z, r2.y, l(1)\n            iadd r2.z, r2.z, l(1)\n            ishl r2.z, r3.x, r2.z\n            or r1.w, r1.w, r2.z\n            iadd r2.y, r2.y, l(1)\n          endloop \n          mov r12.w, r1.w\n          mov r0.z, r2.y\n          loop \n            uge r2.z, r0.z, l(16)\n            breakc_nz r2.z\n            iadd r2.z, r0.z, r0.y\n            ld_structured r3.x, r2.z, l(16), g0.xxxx\n            ishl r2.z, r0.z, l(1)\n            ishl r2.z, r3.x, r2.z\n            or r12.w, r2.z, r12.w\n            iadd r0.z, r0.z, l(1)\n          endloop \n          mov r12.y, r2.x\n        else \n          ieq r0.z, r0.w, l(4)\n          if_nz r0.z\n            ishl r0.z, r1.z, l(5)\n            and r0.z, r0.z, l(96)\n            iadd r0.z, r0.z, l(16)\n            ishl r1.x, r1.x, l(7)\n            iadd r0.z, r0.z, r1.x\n            ld_structured r2.xyzw, r0.y, l(68), g0.xyzw\n            ishl r3.x, r2.x, l(5)\n            ishl r3.y, r2.y, l(15)\n            ishl r3.z, r2.z, l(25)\n            ishl r3.w, r2.w, l(4)\n            and r2.xyzw, r3.xyzw, l(7936, 0x007c0000, 0xf0000000, 4032)\n            iadd r0.z, r0.z, r2.x\n            ld_structured r3.xyzw, r0.y, l(84), g0.xyzw\n            ishl r4.xz, r3.xxwx, l(10)\n            ishl r4.y, r3.y, l(20)\n            and r3.xyw, r4.xyxz, l(0x0003e000, 0x0f800000, 0, 0x0003f000)\n            iadd r0.z, r0.z, r3.x\n            iadd r0.z, r2.y, r0.z\n            iadd r0.z, r3.y, r0.z\n            iadd r12.x, r2.z, r0.z\n            ld_structured r4.x, r0.y, l(76), g0.xxxx\n            ushr r0.z, r4.x, l(7)\n            and r0.z, r0.z, l(1)\n            ushr r1.x, r3.z, l(2)\n            and r1.x, r1.x, l(62)\n            iadd r0.z, r0.z, r1.x\n            iadd r0.z, r2.w, r0.z\n            iadd r0.z, r3.w, r0.z\n            ld_structured r2.xy, r0.y, l(16), g0.xyxx\n            ishl r3.x, r2.x, l(18)\n            ishl r3.y, r2.y, l(17)\n            and r1.xw, r3.xxxy, l(0x00040000, 0, 0, 0x00060000)\n            iadd r0.z, r0.z, r1.x\n            iadd r2.xyzw, r0.yyyy, l(1, 2, 3, 4)\n            ld_structured r3.xy, r2.x, l(16), g0.xyxx\n            ishl r3.xy, r3.xyxx, l(19)\n            iadd r0.z, r0.z, r3.x\n            ld_structured r4.xy, r2.y, l(16), g0.xyxx\n            ishl r1.x, r4.x, l(21)\n            ishl r2.x, r4.y, l(22)\n            or r0.z, r0.z, r1.x\n            ld_structured r4.xy, r2.z, l(16), g0.xyxx\n            ishl r1.x, r4.x, l(23)\n            ishl r2.y, r4.y, l(25)\n            or r0.z, r0.z, r1.x\n            ld_structured r4.xy, r2.w, l(16), g0.xyxx\n            ishl r1.x, r4.x, l(25)\n            ishl r2.z, r4.y, l(28)\n            or r0.z, r0.z, r1.x\n            iadd r4.xyzw, r0.yyyy, l(5, 6, 7, 8)\n            ld_structured r5.xy, r4.x, l(16), g0.xyxx\n            ishl r1.x, r5.x, l(27)\n            ishl r2.w, r5.y, l(31)\n            or r0.z, r0.z, r1.x\n            ld_structured r5.xy, r4.y, l(16), g0.xyxx\n            ishl r1.x, r5.x, l(29)\n            ishl r3.x, r5.y, l(2)\n            or r0.z, r0.z, r1.x\n            ld_structured r5.xy, r4.z, l(16), g0.xyxx\n            ishl r1.x, r5.x, l(31)\n            ishl r3.z, r5.y, l(5)\n            or r12.y, r0.z, r1.x\n            ld_structured r5.x, r4.z, l(16), g0.xxxx\n            ushr r0.z, r5.x, l(1)\n            ld_structured r5.xy, r4.w, l(16), g0.xyxx\n            ishl r1.x, r5.x, l(1)\n            ishl r3.w, r5.y, l(8)\n            or r0.z, r0.z, r1.x\n            iadd r5.xyzw, r0.yyyy, l(9, 10, 11, 12)\n            ld_structured r6.xy, r5.x, l(16), g0.xyxx\n            ishl r1.x, r6.x, l(3)\n            ishl r4.y, r6.y, l(11)\n            or r0.z, r0.z, r1.x\n            ld_structured r6.xy, r5.y, l(16), g0.xyxx\n            ishl r1.x, r6.x, l(5)\n            ishl r4.z, r6.y, l(14)\n            or r0.z, r0.z, r1.x\n            ld_structured r6.xy, r5.z, l(16), g0.xyxx\n            ishl r1.x, r6.x, l(7)\n            ishl r4.w, r6.y, l(17)\n            or r0.z, r0.z, r1.x\n            ld_structured r5.xy, r5.w, l(16), g0.xyxx\n            ishl r1.x, r5.x, l(9)\n            ishl r5.x, r5.y, l(20)\n            or r0.z, r0.z, r1.x\n            iadd r5.yzw, r0.yyyy, l(0, 13, 14, 15)\n            ld_structured r6.xy, r5.y, l(16), g0.xyxx\n            ishl r1.x, r6.x, l(11)\n            ishl r5.y, r6.y, l(23)\n            or r0.z, r0.z, r1.x\n            ld_structured r6.xy, r5.z, l(16), g0.xyxx\n            ishl r1.x, r6.x, l(13)\n            ishl r5.z, r6.y, l(26)\n            or r0.z, r0.z, r1.x\n            ld_structured r6.xy, r5.w, l(16), g0.xyxx\n            ishl r1.x, r6.x, l(15)\n            ishl r5.w, r6.y, l(29)\n            or r0.z, r0.z, r1.x\n            or r0.z, r1.w, r0.z\n            or r0.z, r3.y, r0.z\n            or r0.z, r2.x, r0.z\n            or r0.z, r2.y, r0.z\n            or r0.z, r2.z, r0.z\n            or r12.z, r2.w, r0.z\n            ld_structured r2.x, r4.x, l(20), g0.xxxx\n            ushr r0.z, r2.x, l(1)\n            or r0.z, r3.x, r0.z\n            or r0.z, r3.z, r0.z\n            or r0.z, r3.w, r0.z\n            or r0.z, r4.y, r0.z\n            or r0.z, r4.z, r0.z\n            or r0.z, r4.w, r0.z\n            or r0.z, r5.x, r0.z\n            or r0.z, r5.y, r0.z\n            or r0.z, r5.z, r0.z\n            or r12.w, r5.w, r0.z\n          else \n            ieq r0.z, r0.w, l(5)\n            if_nz r0.z\n              ishl r0.z, r1.z, l(6)\n              iadd r0.z, r0.z, l(32)\n              ld_structured r2.xyzw, r0.y, l(68), g0.xyzw\n              ishl r3.x, r2.x, l(7)\n              ishl r3.y, r2.y, l(21)\n              ishl r3.z, r2.z, l(3)\n              ishl r1.x, r2.w, l(18)\n              and r2.xyz, r3.xyzx, l(0x00007f00, 0x1fc00000, 2032, 0)\n              or r0.z, r0.z, r2.x\n              ld_structured r3.xyzw, r0.y, l(84), g0.xyzw\n              ishl r4.x, r3.x, l(14)\n              ishl r4.y, r3.y, l(28)\n              ishl r4.z, r3.z, l(10)\n              ishl r1.z, r3.w, l(26)\n              and r3.xyz, r4.xyzx, l(0x003f8000, 0xe0000000, 0x0003f800, 0)\n              or r0.z, r0.z, r3.x\n              or r0.z, r2.y, r0.z\n              or r12.x, r3.y, r0.z\n              ld_structured r4.x, r0.y, l(88), g0.xxxx\n              ushr r0.z, r4.x, l(4)\n              and r0.z, r0.z, l(15)\n              iadd r0.z, r2.z, r0.z\n              iadd r0.z, r3.z, r0.z\n              iadd r0.z, r1.x, r0.z\n              or r12.y, r1.z, r0.z\n              ld_structured r2.x, r0.y, l(96), g0.xxxx\n              ushr r0.z, r2.x, l(6)\n              ld_structured r2.xy, r0.y, l(16), g0.xyxx\n              ishl r1.x, r2.x, l(2)\n              ishl r1.z, r2.y, l(1)\n              or r0.z, r0.z, r1.x\n              iadd r2.xyzw, r0.yyyy, l(1, 2, 3, 4)\n              ld_structured r3.xy, r2.x, l(16), g0.xyxx\n              ishl r1.x, r3.x, l(3)\n              ishl r1.w, r3.y, l(2)\n              or r0.z, r0.z, r1.x\n              ld_structured r3.xy, r2.y, l(16), g0.xyxx\n              ishl r1.x, r3.x, l(5)\n              ishl r2.x, r3.y, l(4)\n              or r0.z, r0.z, r1.x\n              ld_structured r3.xy, r2.z, l(16), g0.xyxx\n              ishl r1.x, r3.x, l(7)\n              ishl r2.y, r3.y, l(6)\n              or r0.z, r0.z, r1.x\n              ld_structured r3.xy, r2.w, l(16), g0.xyxx\n              ishl r1.x, r3.x, l(9)\n              ishl r2.z, r3.y, l(8)\n              or r0.z, r0.z, r1.x\n              iadd r3.xyzw, r0.yyyy, l(5, 6, 7, 8)\n              ld_structured r4.xy, r3.x, l(16), g0.xyxx\n              ishl r1.x, r4.x, l(11)\n              ishl r2.w, r4.y, l(10)\n              or r0.z, r0.z, r1.x\n              ld_structured r4.xy, r3.y, l(16), g0.xyxx\n              ishl r1.x, r4.x, l(13)\n              ishl r3.x, r4.y, l(12)\n              or r0.z, r0.z, r1.x\n              ld_structured r4.xy, r3.z, l(16), g0.xyxx\n              ishl r1.x, r4.x, l(15)\n              ishl r3.y, r4.y, l(14)\n              or r0.z, r0.z, r1.x\n              ld_structured r4.xy, r3.w, l(16), g0.xyxx\n              ishl r1.x, r4.x, l(17)\n              ishl r3.z, r4.y, l(16)\n              or r0.z, r0.z, r1.x\n              iadd r4.xyzw, r0.yyyy, l(9, 10, 11, 12)\n              ld_structured r5.xy, r4.x, l(16), g0.xyxx\n              ishl r1.x, r5.x, l(19)\n              ishl r3.w, r5.y, l(18)\n              or r0.z, r0.z, r1.x\n              ld_structured r5.xy, r4.y, l(16), g0.xyxx\n              ishl r1.x, r5.x, l(21)\n              ishl r4.x, r5.y, l(20)\n              or r0.z, r0.z, r1.x\n              ld_structured r5.xy, r4.z, l(16), g0.xyxx\n              ishl r1.x, r5.x, l(23)\n              ishl r4.y, r5.y, l(22)\n              or r0.z, r0.z, r1.x\n              ld_structured r5.xy, r4.w, l(16), g0.xyxx\n              ishl r1.x, r5.x, l(25)\n              ishl r4.z, r5.y, l(24)\n              or r0.z, r0.z, r1.x\n              iadd r5.xyz, r0.yyyy, l(13, 14, 15, 0)\n              ld_structured r6.xy, r5.x, l(16), g0.xyxx\n              ishl r1.x, r6.x, l(27)\n              ishl r4.w, r6.y, l(26)\n              or r0.z, r0.z, r1.x\n              ld_structured r6.xy, r5.y, l(16), g0.xyxx\n              ishl r1.x, r6.x, l(29)\n              ishl r5.x, r6.y, l(28)\n              or r0.z, r0.z, r1.x\n              ld_structured r6.xy, r5.z, l(16), g0.xyxx\n              ishl r1.x, r6.x, l(31)\n              ishl r5.y, r6.y, l(30)\n              or r12.z, r0.z, r1.x\n              ld_structured r6.x, r5.z, l(16), g0.xxxx\n              ushr r0.z, r6.x, l(1)\n              or r0.z, r1.z, r0.z\n              or r0.z, r1.w, r0.z\n              or r0.z, r2.x, r0.z\n              or r0.z, r2.y, r0.z\n              or r0.z, r2.z, r0.z\n              or r0.z, r2.w, r0.z\n              or r0.z, r3.x, r0.z\n              or r0.z, r3.y, r0.z\n              or r0.z, r3.z, r0.z\n              or r0.z, r3.w, r0.z\n              or r0.z, r4.x, r0.z\n              or r0.z, r4.y, r0.z\n              or r0.z, r4.z, r0.z\n              or r0.z, r4.w, r0.z\n              or r0.z, r5.x, r0.z\n              or r12.w, r5.y, r0.z\n            else \n              ieq r0.z, r0.w, l(6)\n              if_nz r0.z\n                ld_structured r2.xyzw, r0.y, l(68), g0.xyzw\n                ishl r3.x, r2.x, l(6)\n                ishl r3.y, r2.y, l(20)\n                ishl r3.z, r2.z, l(2)\n                ishl r3.w, r2.w, l(16)\n                and r2.xyzw, r3.xyzw, l(0x00003f80, 0x0fe00000, 1016, 0x00fe0000)\n                iadd r0.z, r2.x, l(64)\n                ld_structured r3.xyzw, r0.y, l(84), g0.xyzw\n                ishl r4.x, r3.x, l(13)\n                ishl r4.y, r3.y, l(27)\n                ishl r4.z, r3.z, l(9)\n                ishl r4.w, r3.w, l(23)\n                and r3.xyzw, r4.xyzw, l(0x001fc000, 0xf0000000, 0x0001fc00, 0x7f000000)\n                iadd r0.z, r0.z, r3.x\n                iadd r0.z, r2.y, r0.z\n                iadd r12.x, r3.y, r0.z\n                ld_structured r4.xy, r0.y, l(84), g0.xyxx\n                ushr r0.z, r4.y, l(5)\n                and r0.z, r0.z, l(7)\n                iadd r0.z, r2.z, r0.z\n                iadd r0.z, r3.z, r0.z\n                iadd r0.z, r2.w, r0.z\n                iadd r0.z, r3.w, r0.z\n                ld_structured r2.x, r0.y, l(68), g0.xxxx\n                ishl r0.w, r2.x, l(31)\n                iadd r12.y, r0.w, r0.z\n                and r0.z, r4.x, l(1)\n                ld_structured r2.x, r0.y, l(16), g0.xxxx\n                ishl r0.w, r2.x, l(1)\n                iadd r0.z, r0.w, r0.z\n                iadd r2.xyzw, r0.yyyy, l(1, 2, 3, 4)\n                ld_structured r3.x, r2.x, l(16), g0.xxxx\n                ishl r0.w, r3.x, l(4)\n                or r0.z, r0.w, r0.z\n                ld_structured r3.x, r2.y, l(16), g0.xxxx\n                ishl r0.w, r3.x, l(8)\n                or r0.z, r0.w, r0.z\n                ld_structured r3.x, r2.z, l(16), g0.xxxx\n                ishl r0.w, r3.x, l(12)\n                or r0.z, r0.w, r0.z\n                ld_structured r2.x, r2.w, l(16), g0.xxxx\n                ishl r0.w, r2.x, l(16)\n                or r0.z, r0.w, r0.z\n                iadd r2.xyzw, r0.yyyy, l(5, 6, 7, 8)\n                ld_structured r3.x, r2.x, l(16), g0.xxxx\n                ishl r0.w, r3.x, l(20)\n                or r0.z, r0.w, r0.z\n                ld_structured r3.x, r2.y, l(16), g0.xxxx\n                ishl r0.w, r3.x, l(24)\n                or r0.z, r0.w, r0.z\n                ld_structured r3.x, r2.z, l(16), g0.xxxx\n                ishl r0.w, r3.x, l(28)\n                or r12.z, r0.w, r0.z\n                ld_structured r2.x, r2.w, l(16), g0.xxxx\n                iadd r3.xyzw, r0.yyyy, l(9, 10, 11, 12)\n                ld_structured r4.x, r3.x, l(16), g0.xxxx\n                ishl r0.z, r4.x, l(4)\n                or r0.z, r0.z, r2.x\n                ld_structured r2.x, r3.y, l(16), g0.xxxx\n                ishl r0.w, r2.x, l(8)\n                or r0.z, r0.w, r0.z\n                ld_structured r2.x, r3.z, l(16), g0.xxxx\n                ishl r0.w, r2.x, l(12)\n                or r0.z, r0.w, r0.z\n                ld_structured r2.x, r3.w, l(16), g0.xxxx\n                ishl r0.w, r2.x, l(16)\n                or r0.z, r0.w, r0.z\n                iadd r1.xzw, r0.yyyy, l(13, 0, 14, 15)\n                ld_structured r2.x, r1.x, l(16), g0.xxxx\n                ishl r0.w, r2.x, l(20)\n                or r0.z, r0.w, r0.z\n                ld_structured r2.x, r1.z, l(16), g0.xxxx\n                ishl r0.w, r2.x, l(24)\n                or r0.z, r0.w, r0.z\n                ld_structured r2.x, r1.w, l(16), g0.xxxx\n                ishl r0.w, r2.x, l(28)\n                or r12.w, r0.w, r0.z\n              else \n                ishl r0.z, r1.y, l(8)\n                iadd r0.z, r0.z, l(128)\n                ld_structured r2.xyzw, r0.y, l(68), g0.xyzw\n                ishl r3.x, r2.x, l(11)\n                ishl r3.y, r2.z, l(19)\n                ishl r3.z, r2.w, l(7)\n                and r1.xzw, r3.xxyz, l(0x0007c000, 0, 0x07c00000, 0x00007c00)\n                or r0.z, r0.z, r1.x\n                ld_structured r3.xyzw, r0.y, l(84), g0.xyzw\n                ishl r4.x, r3.x, l(16)\n                ishl r4.y, r3.y, l(4)\n                ishl r4.z, r3.z, l(24)\n                ishl r4.w, r3.w, l(12)\n                and r4.xyzw, r4.xyzw, l(0x00f80000, 3968, 0xf8000000, 0x000f8000)\n                or r0.z, r0.z, r4.x\n                iadd r0.w, r0.y, l(1)\n                ld_structured r5.xyzw, r0.w, l(68), g0.xyzw\n                ishl r6.x, r5.x, l(21)\n                ishl r6.y, r5.y, l(9)\n                ishl r6.z, r5.w, l(17)\n                and r6.xyz, r6.xyzx, l(0x1f000000, 0x0001f000, 0x01f00000, 0)\n                or r0.z, r0.z, r6.x\n                ld_structured r7.xyzw, r0.w, l(84), g0.xyzw\n                ishl r8.x, r7.x, l(26)\n                ishl r8.y, r7.y, l(14)\n                ishl r8.z, r7.z, l(2)\n                ishl r8.w, r7.w, l(22)\n                and r8.xyzw, r8.xyzw, l(0xe0000000, 0x003e0000, 992, 0x3e000000)\n                or r12.x, r0.z, r8.x\n                ld_structured r9.x, r0.w, l(84), g0.xxxx\n                ushr r10.x, r9.x, l(6)\n                ushr r10.y, r9.x, l(1)\n                and r6.xw, r10.xxxy, l(3, 0, 0, 2)\n                ushr r0.z, r2.y, l(1)\n                and r0.z, r0.z, l(124)\n                iadd r0.z, r0.z, r6.x\n                iadd r0.z, r4.y, r0.z\n                iadd r0.z, r6.y, r0.z\n                iadd r0.z, r8.y, r0.z\n                iadd r0.z, r1.z, r0.z\n                iadd r12.y, r4.z, r0.z\n                ushr r0.z, r5.z, l(3)\n                and r0.z, r0.z, l(31)\n                iadd r0.z, r8.z, r0.z\n                iadd r0.z, r1.w, r0.z\n                iadd r0.z, r4.w, r0.z\n                iadd r0.z, r6.z, r0.z\n                iadd r0.z, r8.w, r0.z\n                ld_structured r2.x, r0.y, l(68), g0.xxxx\n                ishl r1.x, r2.x, l(28)\n                and r1.x, r1.x, l(0x40000000)\n                iadd r0.z, r0.z, r1.x\n                ld_structured r2.x, r0.y, l(84), g0.xxxx\n                ishl r1.x, r2.x, l(29)\n                and r1.x, r1.x, l(0x80000000)\n                iadd r12.z, r0.z, r1.x\n                ld_structured r2.x, r0.w, l(68), g0.xxxx\n                ushr r0.z, r2.x, l(2)\n                and r0.z, r0.z, l(1)\n                iadd r0.z, r6.w, r0.z\n                ld_structured r2.x, r0.y, l(16), g0.xxxx\n                ishl r0.w, r2.x, l(2)\n                iadd r0.z, r0.w, r0.z\n                mov r0.w, r0.z\n                mov r1.x, l(1)\n                loop \n                  ult r1.z, icb[r1.y + 128].y, r1.x\n                  breakc_nz r1.z\n                  iadd r1.z, r0.y, r1.x\n                  ld_structured r2.x, r1.z, l(16), g0.xxxx\n                  ishl r1.z, r1.x, l(1)\n                  iadd r1.z, r1.z, l(1)\n                  ishl r1.z, r2.x, r1.z\n                  or r0.w, r0.w, r1.z\n                  iadd r1.x, r1.x, l(1)\n                endloop \n                mov r12.w, r0.w\n                mov r0.z, r1.x\n                loop \n                  uge r1.y, r0.z, l(16)\n                  breakc_nz r1.y\n                  iadd r1.y, r0.z, r0.y\n                  ld_structured r2.x, r1.y, l(16), g0.xxxx\n                  ishl r1.y, r0.z, l(1)\n                  ishl r1.y, r2.x, r1.y\n                  or r12.w, r1.y, r12.w\n                  iadd r0.z, r0.z, l(1)\n                endloop \n              endif \n            endif \n          endif \n        endif \n      endif \n    endif \n  endif \n  store_structured u0.xyzw, r0.x, l(0), r12.xyzw\nendif \nret \n// Approximately 0 instruction slots used\n#endif\n\nconst BYTE BC7Encode_EncodeBlockCS[] =\n{\n     68,  88,  66,  67,  33, 143, \n     96, 195, 201,  25,   5,  15, \n     19,  60,  35, 103, 143, 233, \n    183,  96,   1,   0,   0,   0, \n    200, 193,   0,   0,   3,   0, \n      0,   0,  44,   0,   0,   0, \n     60,   0,   0,   0,  76,   0, \n      0,   0,  73,  83,  71,  78, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     79,  83,  71,  78,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  83,  72, \n     69,  88, 116, 193,   0,   0, \n     64,   0,   5,   0,  93,  48, \n      0,   0, 106,   8,   0,   1, \n     53,  24,   0,   0,   2,   4, \n      0,   0, 204, 204,   0,   0, \n     80,  80, 104, 170,  15,   0, \n      0,   0,   0,   0,   0,   0, \n    136, 136,   0,   0,  64,  80, \n     90, 106,  15,   0,   0,   0, \n      0,   0,   0,   0, 238, 238, \n      0,   0,   0,  66,  90,  90, \n     15,   0,   0,   0,   0,   0, \n      0,   0, 200, 236,   0,   0, \n    168, 160,  80,  84,  15,   0, \n      0,   0,   0,   0,   0,   0, \n    128, 200,   0,   0,   0,   0, \n    165, 165,  15,   0,   0,   0, \n      0,   0,   0,   0, 236, 254, \n      0,   0,  80,  80, 160, 160, \n     15,   0,   0,   0,   0,   0, \n      0,   0, 200, 254,   0,   0, \n    160, 160,  85,  85,  15,   0, \n      0,   0,   0,   0,   0,   0, \n    128, 236,   0,   0,  80,  80, \n     90,  90,  15,   0,   0,   0, \n      0,   0,   0,   0,   0, 200, \n      0,   0,   0,   0,  85, 170, \n     15,   0,   0,   0,   0,   0, \n      0,   0, 236, 255,   0,   0, \n      0,  85,  85, 170,  15,   0, \n      0,   0,   0,   0,   0,   0, \n    128, 254,   0,   0,   0,  85, \n    170, 170,  15,   0,   0,   0, \n      0,   0,   0,   0,   0, 232, \n      0,   0, 144, 144, 144, 144, \n     15,   0,   0,   0,   0,   0, \n      0,   0, 232, 255,   0,   0, \n    148, 148, 148, 148,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0, 255,   0,   0, 164, 164, \n    164, 164,  15,   0,   0,   0, \n      0,   0,   0,   0, 240, 255, \n      0,   0,  80, 148, 165, 169, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0, 240,   0,   0, \n     80,  66,  10,  42,  15,   0, \n      0,   0,   0,   0,   0,   0, \n     16, 247,   0,   0,  64,  80, \n    148, 165,  15,   0,   0,   0, \n      0,   0,   0,   0, 142,   0, \n      0,   0,  84,  80,  66,  10, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0, 113,   0,   0, \n      0, 165, 165, 165,   8,   0, \n      0,   0,   0,   0,   0,   0, \n    206,   8,   0,   0, 160, 160, \n    160,  85,   2,   0,   0,   0, \n      0,   0,   0,   0, 140,   0, \n      0,   0,  84,  84, 168, 168, \n      2,   0,   0,   0,   0,   0, \n      0,   0,  16, 115,   0,   0, \n     64,  64, 106, 106,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      0,  49,   0,   0,   0,  80, \n    164, 164,   8,   0,   0,   0, \n      0,   0,   0,   0, 206, 140, \n      0,   0,   0,   5,  26,  26, \n     15,   0,   0,   0,   0,   0, \n      0,   0, 140,   8,   0,   0, \n    164, 164,  80,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n     16,  49,   0,   0, 144, 144, \n    165, 170,   8,   0,   0,   0, \n      0,   0,   0,   0, 102, 102, \n      0,   0,  20, 105, 105,  20, \n      2,   0,   0,   0,   0,   0, \n      0,   0, 108,  54,   0,   0, \n      0,  20, 105, 105,   2,   0, \n      0,   0,   0,   0,   0,   0, \n    232,  23,   0,   0, 160, 133, \n    133, 160,   8,   0,   0,   0, \n      0,   0,   0,   0, 240,  15, \n      0,   0,  20,  20, 130, 170, \n      8,   0,   0,   0,   0,   0, \n      0,   0, 142, 113,   0,   0, \n     80, 164, 164,  80,   2,   0, \n      0,   0,   0,   0,   0,   0, \n    156,  57,   0,   0,   0,   2, \n     90, 106,   2,   0,   0,   0, \n      0,   0,   0,   0, 170, 170, \n      0,   0,   0, 128, 165, 169, \n     15,   0,   0,   0,   0,   0, \n      0,   0, 240, 240,   0,   0, \n    168, 160, 144,  80,  15,   0, \n      0,   0,   0,   0,   0,   0, \n     90,  90,   0,   0,  80, 144, \n    160, 168,   6,   0,   0,   0, \n      0,   0,   0,   0, 204,  51, \n      0,   0,  36,  36,  36,  36, \n      8,   0,   0,   0,   0,   0, \n      0,   0,  60,  60,   0,   0, \n      0,  85, 170,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n    170,  85,   0,   0,  36,  73, \n    146,  36,   8,   0,   0,   0, \n      0,   0,   0,   0, 150, 150, \n      0,   0,  36, 146,  73,  36, \n     15,   0,   0,   0,   0,   0, \n      0,   0,  90, 165,   0,   0, \n     80,  10, 165,  80,  15,   0, \n      0,   0,   0,   0,   0,   0, \n    206, 115,   0,   0,  80, 165, \n     10,  80,   2,   0,   0,   0, \n      0,   0,   0,   0, 200,  19, \n      0,   0,  68,  68, 170, 170, \n      8,   0,   0,   0,   0,   0, \n      0,   0,  76,  50,   0,   0, \n      0,   0, 102, 102,   2,   0, \n      0,   0,   0,   0,   0,   0, \n    220,  59,   0,   0, 160, 165, \n    160, 165,   2,   0,   0,   0, \n      0,   0,   0,   0, 150, 105, \n      0,   0, 160,  80, 160,  80, \n      2,   0,   0,   0,   0,   0, \n      0,   0,  60, 195,   0,   0, \n     40, 105,  40, 105,  15,   0, \n      0,   0,   0,   0,   0,   0, \n    102, 153,   0,   0,  68, 170, \n    170,  68,  15,   0,   0,   0, \n      0,   0,   0,   0,  96,   6, \n      0,   0,   0, 102, 102, 102, \n      6,   0,   0,   0,   0,   0, \n      0,   0, 114,   2,   0,   0, \n     68,  68,  68, 170,   6,   0, \n      0,   0,   0,   0,   0,   0, \n    228,   4,   0,   0, 168,  84, \n    168,  84,   2,   0,   0,   0, \n      0,   0,   0,   0,  64,  78, \n      0,   0, 128, 149, 128, 149, \n      6,   0,   0,   0,   0,   0, \n      0,   0,  32,  39,   0,   0, \n      0, 150, 150, 150,   8,   0, \n      0,   0,   0,   0,   0,   0, \n     54, 201,   0,   0, 168,  84, \n     84, 168,  15,   0,   0,   0, \n      0,   0,   0,   0, 108, 147, \n      0,   0, 128, 149, 149, 128, \n     15,   0,   0,   0,   0,   0, \n      0,   0, 198,  57,   0,   0, \n     20,  20,  20, 170,   2,   0, \n      0,   0,   0,   0,   0,   0, \n    156,  99,   0,   0,   0,   0, \n    150, 150,   2,   0,   0,   0, \n      0,   0,   0,   0,  54, 147, \n      0,   0,  20,  20, 170, 170, \n     15,   0,   0,   0,   0,   0, \n      0,   0, 198, 156,   0,   0, \n    160,  80,  80, 160,  15,   0, \n      0,   0,   0,   0,   0,   0, \n    126, 129,   0,   0, 160, 165, \n    165, 160,  15,   0,   0,   0, \n      0,   0,   0,   0,  24, 231, \n      0,   0,   0,   0,   0, 150, \n     15,   0,   0,   0,   0,   0, \n      0,   0, 240, 204,   0,   0, \n    128,  64, 128,  64,  15,   0, \n      0,   0,   0,   0,   0,   0, \n    204,  15,   0,   0, 168, 169, \n    168, 169,   2,   0,   0,   0, \n      0,   0,   0,   0,  68, 119, \n      0,   0,  68, 170, 170, 170, \n      2,   0,   0,   0,   0,   0, \n      0,   0,  34, 238,   0,   0, \n     84,  82,  74,  42,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,   8,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      3,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  15,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  15,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      3,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,   8,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,  15,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  15,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  15,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     15,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  15,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      8,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   8,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,   3,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  15,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      8,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  15,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,   8,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n      3,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  15,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,   6,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     10,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  15,   0, \n      0,   0,   7,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  15,   0,   0,   0, \n      7,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n     10,   0,   0,   0,   7,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,   8,   0, \n      0,   0,   7,   0,   0,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,  15,   0,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      3,   0,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   8,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  10,   0,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     10,   0,   0,   0,   9,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,   0,   0,   8,   0, \n      0,   0,   9,   0,   0,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,   9,   0,   0,   0, \n      9,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n     10,   0,   0,   0,   9,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,   6,   0, \n      0,   0,  10,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  15,   0,   0,   0, \n     10,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      8,   0,   0,   0,  10,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  15,   0, \n      0,   0,  10,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n     10,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      6,   0,   0,   0,  11,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,   6,   0, \n      0,   0,  11,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,   8,   0,   0,   0, \n     11,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     15,   0,   0,   0,  11,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,   3,   0, \n      0,   0,  12,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  15,   0,   0,   0, \n     12,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     15,   0,   0,   0,  12,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  15,   0, \n      0,   0,  12,   0,   0,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,  15,   0,   0,   0, \n     13,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     15,   0,   0,   0,  13,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,   0,   0,  15,   0, \n      0,   0,  13,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  15,   0,   0,   0, \n     13,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n     15,   0,   0,   0,  14,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  15,   0, \n      0,   0,  14,   0,   0,   0, \n      0,   0,   0,   0,  13,   0, \n      0,   0,  15,   0,   0,   0, \n     14,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      3,   0,   0,   0,  14,   0, \n      0,   0,   0,   0,   0,   0, \n     12,   0,   0,   0,  15,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  15,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   8,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   8,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   8,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   8,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   6,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      6,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   5,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   3,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      3,   0,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   3,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   3,   0,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      8,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   3,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   3,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      3,   0,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   6,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   8,   0,   0,   0, \n     10,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      3,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   8,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   6,   0,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      6,   0,   0,   0,  10,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   8,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   5,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     10,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   8,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   3,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   5,   0,   0,   0, \n     10,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      6,   0,   0,   0,  10,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   8,   0, \n      0,   0,  10,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   8,   0,   0,   0, \n      9,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     10,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   6,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   3,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      8,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   5,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   3,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      6,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   6,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   3,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   5,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      5,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   5,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      5,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  10,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   5,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     10,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   8,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  13,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  12,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   3,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      3,   0,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n     89,   0,   0,   4,  70, 142, \n     32,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  88,  24, \n      0,   4,   0, 112,  16,   0, \n      0,   0,   0,   0,  85,  85, \n      0,   0, 162,   0,   0,   4, \n      0, 112,  16,   0,   1,   0, \n      0,   0,  16,   0,   0,   0, \n    158,   0,   0,   4,   0, 224, \n     17,   0,   0,   0,   0,   0, \n     16,   0,   0,   0,  95,   0, \n      0,   2,   0,  64,   2,   0, \n     95,   0,   0,   2,  18,  16, \n      2,   0, 104,   0,   0,   2, \n     15,   0,   0,   0, 160,   0, \n      0,   5,   0, 240,  17,   0, \n      0,   0,   0,   0, 100,   0, \n      0,   0,  64,   0,   0,   0, \n    155,   0,   0,   4,  64,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   6,  18,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   6,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,  16, \n      2,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   8,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10, 128,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   6,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     48,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16, 128,  65,   0,   0,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     70, 114,  16,   0,   1,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0, 255, 255, 255, 127, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,   6, 112, \n     16,   0,   1,   0,   0,   0, \n     85,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,  79,   0, \n      0,  10, 242,   0,  16,   0, \n      2,   0,   0,   0, 166,  10, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,  16,   0, \n      0,   0,   8,   0,   0,   0, \n      4,   0,   0,   0,   2,   0, \n      0,   0,  31,   0,   4,   3, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  78,   0,   0,   9, \n    130,   0,  16,   0,   1,   0, \n      0,   0,   0, 208,   0,   0, \n     10,   0,  16,   0,   0,   0, \n      0,   0,  26, 128,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  35,   0,   0,  11, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16, 128, \n     65,   0,   0,   0,   1,   0, \n      0,   0,  26, 128,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   7,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  85,   0,   0,   7, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  54,   0, \n      0,   8, 194,   0,  16,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     45,   0,   0,   7, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   3,   0, \n      0,   0,  70, 126,  16,   0, \n      0,   0,   0,   0,  56,   0, \n      0,  10, 242,   0,  16,   0, \n      3,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n    127,  67,   0,   0, 127,  67, \n      0,   0, 127,  67,   0,   0, \n    127,  67,  28,   0,   0,   5, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  70,  14,  16,   0, \n      3,   0,   0,   0,  84,   0, \n      0,  10, 242,   0,  16,   0, \n      3,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0, 255,   0, \n      0,   0, 255,   0,   0,   0, \n    255,   0,   0,   0, 255,   0, \n      0,   0,  32,   0,   0,  10, \n     50,   0,  16,   0,   4,   0, \n      0,   0, 246,  15,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   4,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     60,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  32,   0, \n      0,  10, 114,   0,  16,   0, \n      4,   0,   0,   0, 166,  10, \n     16,   0,   1,   0,   0,   0, \n      2,  64,   0,   0,   1,   0, \n      0,   0,   2,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,  55,   0,   0,   9, \n    194,   0,  16,   0,   5,   0, \n      0,   0, 166,  10,  16,   0, \n      4,   0,   0,   0, 246,  11, \n     16,   0,   3,   0,   0,   0, \n    166,  14,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   5, \n     50,   0,  16,   0,   5,   0, \n      0,   0,  70,   0,  16,   0, \n      3,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n      5,   0,   0,   0,  86,   5, \n     16,   0,   4,   0,   0,   0, \n    246,   6,  16,   0,   3,   0, \n      0,   0,  86,  14,  16,   0, \n      5,   0,   0,   0,  55,   0, \n      0,   9, 242,   0,  16,   0, \n      4,   0,   0,   0,   6,   0, \n     16,   0,   4,   0,   0,   0, \n    118,   2,  16,   0,   3,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,  55,   0, \n      0,   9, 242,   0,  16,   0, \n      3,   0,   0,   0, 246,  15, \n     16,   0,   1,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0,  70,  14,  16,   0, \n      3,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  30,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0, 192, 255, 255, 255, \n     31,   0,   4,   3,  10,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     85,   0,   0,   8,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26, 144, 144,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,   0,   0,   7, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     32,   0,   0,  10,  98,   0, \n     16,   0,   4,   0,   0,   0, \n    246,  15,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,  32,   0,   0,   7, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     55,   0,   0,  12, 242,   0, \n     16,   0,   5,   0,   0,   0, \n      6,   0,  16,   0,   4,   0, \n      0,   0,  70,  14,  16,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n      1,   0,   0,   7, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   3,   0, \n      0,   0,   6,   0,  16,   0, \n      4,   0,   0,   0,  55,   0, \n      0,  12, 242,   0,  16,   0, \n      5,   0,   0,   0,  86,   5, \n     16,   0,   4,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255,   1,   0, \n      0,   7, 242,   0,  16,   0, \n      3,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     86,   5,  16,   0,   4,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  31,   0,   4,   3, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   8, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   8, 242,   0,  16,   0, \n      4,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     84,   0,   0,   7, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   3,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     83,   0,   0,   7, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  31,   0,   4,   3, \n     42,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   8, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   8, 242,   0,  16,   0, \n      4,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     84,   0,   0,   7, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   3,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     83,   0,   0,   7, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  31,   0,   4,   3, \n     58,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   8, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   8, 242,   0,  16,   0, \n      4,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     84,   0,   0,   7, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   3,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     83,   0,   0,   7, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  79,   0,   0,  10, \n     50,   0,  16,   0,   3,   0, \n      0,   0, 166,  10,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     31,   0,   4,   3,  10,   0, \n     16,   0,   3,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   8, \n    242,   0,  16,   0,   5,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6,  66,   0,  16,   0, \n      3,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  84,   0, \n      0,   7, 242,   0,  16,   0, \n      4,   0,   0,   0,  70,  14, \n     16,   0,   4,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70,  14,  16,   0, \n      4,   0,   0,   0,  83,   0, \n      0,   7, 242,   0,  16,   0, \n      4,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n     70,  14,  16,   0,   7,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      4,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     32,   0,   0,  10, 194,   0, \n     16,   0,   3,   0,   0,   0, \n    166,  10,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   0,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      3,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  18,   0, \n      0,   1,  54,   0,   0,   8, \n    242,   0,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255,  54,   0, \n      0,   8, 242,   0,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     21,   0,   0,   1,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   8, 242,   0,  16,   0, \n      6,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     85,   0,   0,   8,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     10, 144, 144,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   8,  18,   0,  16,   0, \n      7,   0,   0,   0,  26, 144, \n    144,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n      1,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  32,   0, \n      0,  10, 242,   0,  16,   0, \n      8,   0,   0,   0, 246,  15, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   0,   3,   0, \n      0,   0,  32,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     55,   0,   0,  12, 242,   0, \n     16,   0,   9,   0,   0,   0, \n      6,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n      1,   0,   0,   7, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,   6,   0,  16,   0, \n      7,   0,   0,   0,  60,   0, \n      0,   7,  50,   0,  16,   0, \n      8,   0,   0,   0, 214,   5, \n     16,   0,   8,   0,   0,   0, \n    134,   0,  16,   0,   8,   0, \n      0,   0,  32,   0,   0,   7, \n     66,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  32,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  55,   0,   0,  12, \n    242,   0,  16,   0,  10,   0, \n      0,   0, 166,  10,  16,   0, \n      3,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255,   1,   0,   0,   7, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0, 166,  10, \n     16,   0,   3,   0,   0,   0, \n     55,   0,   0,  12, 242,   0, \n     16,   0,  10,   0,   0,   0, \n     86,   5,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n     10,   0,   0,   0,   2,  64, \n      0,   0, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n      1,   0,   0,   7, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,  86,   5,  16,   0, \n      8,   0,   0,   0,  55,   0, \n      0,   9, 242,   0,  16,   0, \n      9,   0,   0,   0,   6,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0,  70,  14,  16,   0, \n     10,   0,   0,   0,  55,   0, \n      0,   9, 242,   0,  16,   0, \n      6,   0,   0,   0,   6,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   8, 242,   0,  16,   0, \n      6,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  84,   0,   0,   7, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,  83,   0,   0,   7, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   8, 242,   0,  16,   0, \n      6,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  84,   0,   0,   7, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,  83,   0,   0,   7, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  58,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   8, 242,   0,  16,   0, \n      6,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  84,   0,   0,   7, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,  83,   0,   0,   7, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      3,   0,   0,   0, 167,   0, \n      0,   8, 242,   0,  16,   0, \n      6,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   7,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  84,   0,   0,   7, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,  83,   0,   0,   7, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  58,   0,  16,   0, \n      3,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  21,   0, \n      0,   1,  31,   0,   4,   3, \n     10,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   8, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   8,  66,   0,  16,   0, \n      3,   0,   0,   0,  10, 144, \n    144,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   8, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  26, 144, 144,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,   1,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  32,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0, 246,  15,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   0,   3,   0,   0,   0, \n     55,   0,   0,  12, 242,   0, \n     16,   0,   9,   0,   0,   0, \n      6,   0,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255,  70,  14, \n     16,   0,   6,   0,   0,   0, \n     55,   0,   0,  12, 242,   0, \n     16,   0,   7,   0,   0,   0, \n      6,   0,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n     60,   0,   0,   7,  50,   0, \n     16,   0,   8,   0,   0,   0, \n    214,   5,  16,   0,   8,   0, \n      0,   0, 134,   0,  16,   0, \n      8,   0,   0,   0,  32,   0, \n      0,  10, 242,   0,  16,   0, \n     10,   0,   0,   0, 246,  15, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   7,   0, \n      0,   0,   4,   0,   0,   0, \n      5,   0,   0,   0,   6,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,  10,   0, \n     16,   0,  10,   0,   0,   0, \n     55,   0,   0,  12, 242,   0, \n     16,   0,  11,   0,   0,   0, \n    166,  10,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255,  70,  14, \n     16,   0,   6,   0,   0,   0, \n     55,   0,   0,  12, 242,   0, \n     16,   0,  12,   0,   0,   0, \n    166,  10,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,  10,   0, \n      0,   0,  26,   0,  16,   0, \n     10,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,  10,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  55,   0,   0,  12, \n    242,   0,  16,   0,  10,   0, \n      0,   0, 166,  10,  16,   0, \n      3,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255, 255, 255, 255, 255, \n    255, 255,   1,   0,   0,   7, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0, 166,  10, \n     16,   0,   3,   0,   0,   0, \n     55,   0,   0,   9, 242,   0, \n     16,   0,  10,   0,   0,   0, \n     86,   5,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n     11,   0,   0,   0,  70,  14, \n     16,   0,  10,   0,   0,   0, \n     55,   0,   0,   9, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     86,   5,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n     12,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n     55,   0,   0,   9, 242,   0, \n     16,   0,   9,   0,   0,   0, \n      6,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,  10,   0,   0,   0, \n     55,   0,   0,   9, 242,   0, \n     16,   0,   6,   0,   0,   0, \n      6,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   8, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      8,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  84,   0, \n      0,   7, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  83,   0, \n      0,   7, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   8, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      4,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  84,   0, \n      0,   7, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  83,   0, \n      0,   7, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   8, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  84,   0, \n      0,   7, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  83,   0, \n      0,   7, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  10,   0, \n     16,   0,   3,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   8, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  84,   0, \n      0,   7, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  83,   0, \n      0,   7, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   7,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   0,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     21,   0,   0,   1,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      3,   0,   0,   0,  32,   0, \n      0,  10, 226,   0,  16,   0, \n      2,   0,   0,   0, 246,  15, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      4,   0,   0,   0,   5,   0, \n      0,   0,  85,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   7, \n     18,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,   1,   0,   0,  10, \n     98,   0,  16,   0,   3,   0, \n      0,   0,   6,   1,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,   9,  50,   0, \n     16,   0,   3,   0,   0,   0, \n     86,   5,  16,   0,   2,   0, \n      0,   0,   6,   0,  16,   0, \n      3,   0,   0,   0, 150,   5, \n     16,   0,   3,   0,   0,   0, \n     31,   0,   0,   3,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     35,   0,   0,  15, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n     31,  31,   0,   0,  31,  31, \n      0,   0,  31,  31,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n    114,   0,  16,   0,   6,   0, \n      0,   0,   6,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n     35,   0,   0,  15, 114,   0, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n     31,  31,   0,   0,  31,  31, \n      0,   0,  31,  31,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n      2,  64,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n    114,   0,  16,   0,   8,   0, \n      0,   0,  86,   5,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0, 255,   0, \n      0,   0,  54,   0,   0,   8, \n    178,   0,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n    255,   0,   0,   0, 248,   7, \n      0,   0,   0,   0,   0,   0, \n    248,   7,   0,   0,  18,   0, \n      0,   1,  31,   0,   4,   3, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  35,   0,   0,  15, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0, 127, 127,   0,   0, \n    127, 127,   0,   0, 127, 127, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7, 114,   0,  16,   0, \n      9,   0,   0,   0,   6,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  35,   0,   0,  15, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0, 127, 127,   0,   0, \n    127, 127,   0,   0, 127, 127, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7, 114,   0,  16,   0, \n      9,   0,   0,   0,  86,   5, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n    255,   0,   0,   0,  54,   0, \n      0,   8, 178,   0,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0, 255,   0,   0,   0, \n    254,   1,   0,   0,   0,   0, \n      0,   0, 254,   1,   0,   0, \n     18,   0,   0,   1,  32,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  35,   0,   0,  15, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,  31,  31,   0,   0, \n     31,  31,   0,   0,  31,  31, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     35,   0,   0,  15, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n     31,  31,   0,   0,  31,  31, \n      0,   0,  31,  31,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0, 255,   0,   0,   0, \n     54,   0,   0,   8, 178,   0, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0, 255,   0, \n      0,   0, 248,   7,   0,   0, \n      0,   0,   0,   0, 248,   7, \n      0,   0,  18,   0,   0,   1, \n     32,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0, 254, 255, \n    255, 255, 254, 255, 255, 255, \n    254, 255, 255, 255,   0,   0, \n      0,   0,  30,   0,   0,   7, \n    114,   0,  16,   0,   6,   0, \n      0,   0,   6,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255, 255, 255, 254, 255, \n    255, 255, 254, 255, 255, 255, \n      0,   0,   0,   0,  30,   0, \n      0,   7, 114,   0,  16,   0, \n      8,   0,   0,   0,  86,   5, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,  54,   0,   0,   5, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   5, 114,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0, 255,   0, \n      0,   0,  54,   0,   0,   8, \n    178,   0,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n    255,   0,   0,   0, 255,   0, \n      0,   0,   0,   0,   0,   0, \n    255,   0,   0,   0,  18,   0, \n      0,   1,  32,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     35,   0,   0,  15, 242,   0, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n     31,  31,   0,   0,  31,  31, \n      0,   0,  31,  31,   0,   0, \n     63,  63,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n     85,   0,   0,   7, 242,   0, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  85,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  60,   0,   0,   7, \n    242,   0,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n     35,   0,   0,  15, 242,   0, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n     31,  31,   0,   0,  31,  31, \n      0,   0,  31,  31,   0,   0, \n     63,  63,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n     85,   0,   0,   7, 242,   0, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 210,   0,  16,   0, \n      4,   0,   0,   0,   6,   6, \n     16,   0,   9,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,   9,   0,   0,   0, \n    198,   2,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  85,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  60,   0,   0,   7, \n    242,   0,  16,   0,   5,   0, \n      0,   0, 198,   6,  16,   0, \n      4,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n     54,   0,   0,   5, 114,   0, \n     16,   0,   8,   0,   0,   0, \n    198,   2,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   5, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     18,   0,   0,   1,  32,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  35,   0,   0,  15, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0, 127, 127,   0,   0, \n    127, 127,   0,   0, 127, 127, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     35,   0,   0,  15, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n    127, 127,   0,   0, 127, 127, \n      0,   0, 127, 127,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,  54,   0, \n      0,   5,  18,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n     54,   0,   0,   5,  34,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,  18,   0,   0,   1, \n     32,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0, 254, 255, \n    255, 255, 254, 255, 255, 255, \n    254, 255, 255, 255, 254, 255, \n    255, 255,  30,   0,   0,   7, \n    242,   0,  16,   0,   6,   0, \n      0,   0,   6,   0,  16,   0, \n      3,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255, 255, 255, 254, 255, \n    255, 255, 254, 255, 255, 255, \n    254, 255, 255, 255,  30,   0, \n      0,   7, 242,   0,  16,   0, \n      4,   0,   0,   0,  86,   5, \n     16,   0,   3,   0,   0,   0, \n    198,   6,  16,   0,   9,   0, \n      0,   0,  54,   0,   0,   5, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   5, 242,   0,  16,   0, \n      5,   0,   0,   0, 198,   6, \n     16,   0,   4,   0,   0,   0, \n     54,   0,   0,   5, 114,   0, \n     16,   0,   8,   0,   0,   0, \n    198,   2,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   5, \n    146,   0,  16,   0,   4,   0, \n      0,   0, 246,  15,  16,   0, \n      6,   0,   0,   0,  18,   0, \n      0,   1,  35,   0,   0,  15, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  70,  14,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,  63,  63,   0,   0, \n     63,  63,   0,   0,  63,  63, \n      0,   0,  63,  63,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,  85,   0,   0,   7, \n    242,   0,  16,   0,   9,   0, \n      0,   0,  70,  14,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0,  30,   0, \n      0,   7, 242,   0,  16,   0, \n      9,   0,   0,   0,   6,   0, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   9,   0, \n      0,   0,  41,   0,   0,   7, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  70,  14,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     85,   0,   0,   7, 242,   0, \n     16,   0,  10,   0,   0,   0, \n     70,  14,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  60,   0, \n      0,   7, 242,   0,  16,   0, \n      4,   0,   0,   0,  54,   6, \n     16,   0,   6,   0,   0,   0, \n     54,   6,  16,   0,  10,   0, \n      0,   0,  35,   0,   0,  15, \n    242,   0,  16,   0,  10,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,  63,  63,   0,   0, \n     63,  63,   0,   0,  63,  63, \n      0,   0,  63,  63,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,  85,   0,   0,   7, \n    242,   0,  16,   0,  10,   0, \n      0,   0,  70,  14,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,  10,   0,   0,   0, \n     70,  14,  16,   0,  10,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0,  30,   0, \n      0,   7, 242,   0,  16,   0, \n     10,   0,   0,   0,  86,   5, \n     16,   0,   3,   0,   0,   0, \n    198,   9,  16,   0,  10,   0, \n      0,   0,  41,   0,   0,   7, \n    242,   0,  16,   0,   8,   0, \n      0,   0, 134,   7,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     85,   0,   0,   7, 242,   0, \n     16,   0,  11,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  60,   0, \n      0,   7, 242,   0,  16,   0, \n      5,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,  11,   0, \n      0,   0,  54,   0,   0,   5, \n     18,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7,  50,   0,  16,   0, \n      3,   0,   0,   0,  70,   0, \n     16,   0,  10,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  54,   0,   0,   5, \n    114,   0,  16,   0,   7,   0, \n      0,   0, 214,   6,  16,   0, \n      4,   0,   0,   0,  54,   0, \n      0,   5, 162,   0,  16,   0, \n      4,   0,   0,   0,  86,   1, \n     16,   0,   3,   0,   0,   0, \n     21,   0,   0,   1,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     21,   0,   0,   1,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     21,   0,   0,   1,  40,   0, \n      0,   5, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n     40,   0,   0,   5, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  30,   0,   0,   7, \n    242,   0,  16,   0,  10,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n     79,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  55,   0, \n      0,   9,  34,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  31,   0,   4,   3, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  31,   0,   0,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  38,   0,   0,   8, \n      0, 208,   0,   0, 194,   0, \n     16,   0,   2,   0,   0,   0, \n      6,   4,  16,   0,  10,   0, \n      0,   0,   6,   4,  16,   0, \n     10,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  35,   0,   0,   9, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,  10,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  38,   0,   0,   8, \n      0, 208,   0,   0, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n     11,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   8, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16, 128,  65,   0,   0,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0,  50,   0,  16,   0, \n      3,   0,   0,   0,  70,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   0,  16,   0,  10,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     35,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,  10,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     30,   0,   0,   8,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16, 128,  65,   0, \n      0,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,  11,   0, \n      0,   0,  38,   0,   0,   8, \n      0, 208,   0,   0,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  34,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  34,   0,   0,   7, \n    130,   0,  16,   0,  10,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,  43,   0, \n      0,   5,  18,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     56,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n    253, 255, 125,  66,  28,   0, \n      0,   5,  18,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  79,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  11,   0,   0,   0, \n    166,  10,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   5,   0,   0,   0, \n    166,  10,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  12,   0,   0,   0, \n    166,  10,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   8,   0,   0,   0, \n    166,  10,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     34,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  34,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     43,   0,   0,   5,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  56,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0, 253, 255, 125,  66, \n     28,   0,   0,   5,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     79,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   5, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,  55,   0, \n      0,   9, 242,   0,  16,   0, \n     13,   0,   0,   0, 166,  10, \n     16,   0,   2,   0,   0,   0, \n     38,  13,  16,   0,   4,   0, \n      0,   0, 134,   7,  16,   0, \n      4,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n     11,   0,   0,   0,  10,   0, \n     16,   0,  13,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,  13,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,  12,   0, \n      0,   0,  42,   0,  16,   0, \n     13,   0,   0,   0,  54,   0, \n      0,   5, 242,   0,  16,   0, \n      6,   0,   0,   0,  70,  14, \n     16,   0,  12,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,  13,   0, \n      0,   0,  18,   0,   0,   1, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   5, \n    242,   0,  16,   0,  11,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,  21,   0,   0,   1, \n     18,   0,   0,   1,  31,   0, \n      0,   3,  42,   0,  16,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   5,  66,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     18,   0,   0,   1,  31,   0, \n      4,   3,  58,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  66,   0,  16,   0, \n      2,   0,   0,   0,  42, 144, \n    144,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  18,   0, \n      0,   1,  54,   0,   0,   6, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58, 144, 144,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,  21,   0,   0,   1, \n     21,   0,   0,   1,  38,   0, \n      0,   8,   0, 208,   0,   0, \n     50,   0,  16,   0,   3,   0, \n      0,   0,  70,   0,  16,   0, \n     10,   0,   0,   0,  70,   0, \n     16,   0,  10,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  35,   0, \n      0,   9, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,  10,   0,   0,   0, \n     42,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  35,   0, \n      0,   9, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  70,  14,  16,   0, \n      9,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0,  50,   0,  16,   0, \n      3,   0,   0,   0,  70,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   0,  16,   0,  10,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     35,   0,   0,   9,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,  10,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     35,   0,   0,   9,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     34,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  34,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     43,   0,   0,   5,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  56,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0, 253, 255, 125,  66, \n     28,   0,   0,   5,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     79,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  55,   0, \n      0,   9, 242,   0,  16,   0, \n     11,   0,   0,   0,  86,   5, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,  70,  14,  16,   0, \n      7,   0,   0,   0,  55,   0, \n      0,   9, 242,   0,  16,   0, \n      5,   0,   0,   0,  86,   5, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   7,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      8,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n     54,   0,   0,   5, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,  55,   0,   0,   9, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  86,   5,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0,  55,   0,   0,   9, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  86,   5,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   4,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,  21,   0,   0,   1, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70,  14,  16,   0,  11,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     68,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  84,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      2,   0,   0,   0,  32,   0, \n      0,  10, 242,   0,  16,   0, \n      2,   0,   0,   0, 246,  15, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      6,   0,   0,   0,   4,   0, \n      0,   0,  60,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     55,   0,   0,  15,  98,   0, \n     16,   0,   3,   0,   0,   0, \n      6,   0,  16,   0,   1,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,  12,  98,   0, \n     16,   0,   3,   0,   0,   0, \n    246,  15,  16,   0,   2,   0, \n      0,   0,  86,   6,  16,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,  12,  98,   0, \n     16,   0,   3,   0,   0,   0, \n    166,  10,  16,   0,   2,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  86,   6, \n     16,   0,   3,   0,   0,   0, \n     55,   0,   0,  12,  50,   0, \n     16,   0,   3,   0,   0,   0, \n      6,   0,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 150,   5, \n     16,   0,   3,   0,   0,   0, \n     32,   0,   0,  10, 242,   0, \n     16,   0,   4,   0,   0,   0, \n    246,  15,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      2,   0,   0,   0,   3,   0, \n      0,   0,   7,   0,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   8, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  26, 144, 144,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,   2,   0, \n      0,   0,  70,   3,  16,   0, \n      2,   0,   0,   0,  70,   3, \n     16,   0,   4,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  85,   0, \n      0,   8, 130,   0,  16,   0, \n      2,   0,   0,   0,  10, 144, \n    144,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  55,   0,   0,   9, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   4,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     52,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   8, 242,   0, \n     16,   0,   5,   0,   0,   0, \n     70,  14,  16, 128,  65,   0, \n      0,   0,   4,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,  79,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     55,   0,   0,   9, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0,  50,   0,  16,   0, \n      2,   0,   0,   0,  70,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   0,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     35,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0,  34,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   8, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   8, 242,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16, 128,  65,   0,   0,   0, \n      4,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0, 194,   0,  16,   0, \n      2,   0,   0,   0,   6,   4, \n     16,   0,   5,   0,   0,   0, \n      6,   4,  16,   0,   7,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     35,   0,   0,   9,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     33,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  33,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  60,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     34,   0,   0,   7,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  43,   0, \n      0,   5,  82,   0,  16,   0, \n      2,   0,   0,   0,   6,   2, \n     16,   0,   2,   0,   0,   0, \n     56,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n    253, 255, 125,  66,  14,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  28,   0,   0,   5, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7, 162,   0,  16,   0, \n      3,   0,   0,   0,   6,   4, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n     30,   0,   0,  10,  50,   0, \n     16,   0,   6,   0,   0,   0, \n    214,   5,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n     11,   0,   0,   0,  11,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  78,   0, \n      0,  11,   0, 208,   0,   0, \n     50,   0,  16,   0,   6,   0, \n      0,   0,  70,   0,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,  68,   0,   0,   0, \n     68,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     79,   0,   0,  10,  50,   0, \n     16,   0,   7,   0,   0,   0, \n    214,   5,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,  12,  50,   0,  16,   0, \n      6,   0,   0,   0,  70,   0, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,  15,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  70,   0,  16,   0, \n      6,   0,   0,   0,  55,   0, \n      0,  11,  18,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     10, 144, 208,   0,  64,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n     55,   0,   0,   9,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0,  18,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  33,   0,   0,  10, \n    194,   0,  16,   0,   2,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  86,   1, \n     16,   0,   2,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  34,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  43,   0,   0,   5, \n     50,   0,  16,   0,   2,   0, \n      0,   0,  70,   0,  16,   0, \n      2,   0,   0,   0,  56,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0, 253, 255, \n    125,  66,  14,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     28,   0,   0,   5,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     55,   0,   0,  11,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  10, 144, 208,   0, \n     64,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  55,   0,   0,   9, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  55,   0,   0,   9, \n     50,   0,  16,   0,   2,   0, \n      0,   0,   6,   0,  16,   0, \n      1,   0,   0,   0,  70,   0, \n     16,   0,   7,   0,   0,   0, \n     22,   5,  16,   0,   7,   0, \n      0,   0,  18,   0,   0,   1, \n     38,   0,   0,   8,   0, 208, \n      0,   0, 194,   0,  16,   0, \n      2,   0,   0,   0,   6,   4, \n     16,   0,   5,   0,   0,   0, \n      6,   4,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     35,   0,   0,   9,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     35,   0,   0,   9,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   6,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   8, \n    242,   0,  16,   0,   4,   0, \n      0,   0,  70,  14,  16, 128, \n     65,   0,   0,   0,   4,   0, \n      0,   0,  70,  14,  16,   0, \n      6,   0,   0,   0,  38,   0, \n      0,   8,   0, 208,   0,   0, \n     98,   0,  16,   0,   3,   0, \n      0,   0,   6,   1,  16,   0, \n      4,   0,   0,   0,   6,   1, \n     16,   0,   5,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  35,   0, \n      0,   9, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  35,   0, \n      0,   9, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  33,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  33,   0,   0,   7, \n     34,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     60,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  34,   0, \n      0,   7,  34,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  43,   0,   0,   5, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  56,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0, 253, 255, \n    125,  66,  43,   0,   0,   5, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  14,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  28,   0,   0,   5, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  78,   0, \n      0,   8,   0, 208,   0,   0, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n     79,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  55,   0, \n      0,   9,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  55,   0, \n      0,  11, 130,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n     10, 144, 208,   0,  64,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     55,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     54,   0,   0,   5,  34,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  21,   0,   0,   1, \n    168,   0,   0,   8,  50, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     70,   0,  16,   0,   2,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      0,   3,  42,   0,  16,   0, \n      0,   0,   0,   0,  31,   0, \n      0,   3,  58,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0, 128, 255, 255, 255, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  68,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0, 224,   1, \n      0,   0,   0,   0,   0, 224, \n      0,   0, 224,   1,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     84,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,   1,   0,   0,  10, \n    146,   0,  16,   0,   2,   0, \n      0,   0,   6,   4,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,  30,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,  30, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,  10, 146,   0,  16,   0, \n      3,   0,   0,   0,  86,   5, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   6,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  25,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,   0, 224,   1,   0, \n    224,   1,   0,   0,   0,   0, \n      0, 224,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      7,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  84,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,  13,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n      1,   0,   0,  10, 146,   0, \n     16,   0,   4,   0,   0,   0, \n      6,   4,  16,   0,   8,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,  30,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,  30,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   9,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   8,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   9,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0,   2,  64, \n      0,   0,   0,   0, 224,   1, \n      0, 224,   1,   0, 224,   1, \n      0,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      9,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n     10,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  84,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n     11,   0,   0,   0,  10,   0, \n     16,   0,  10,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,  11,   0, \n      0,   0,  26,   0,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,  11,   0,   0,   0, \n     42,   0,  16,   0,  10,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,  30,   0,   0,  30,   0, \n      0,  30,   0,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,  11,   0,   0,   0, \n     60,   0,   0,   7,  18,   0, \n     16,   0,  12,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  50,   0,  16,   0, \n     13,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  68,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,  13,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     85,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  30,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,  11,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,  12,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  76,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     85,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  30,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,  11,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n     13,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0,  32,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  84,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0,  64,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0, 128,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  84,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   1,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   2,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  84,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   4,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  84,   0, \n      0,   9, 130,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     26, 144, 208,   0, 128,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5,  66,   0,  16,   0, \n     12,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   5,  18,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  48,   0,   0,   1, \n     79,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   3,   0, \n      4,   3,  26,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  35,   0,   0,   9, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,  12,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n     12,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  22,   0,   0,   1, \n     79,   0,   0,   9,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26, 144, 208,   0, 128,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,  12,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,  12,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     18,   0,   0,   1,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   5,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  48,   0,   0,   1, \n     79,   0,   0,   9, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     26, 144, 208,   0, 128,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      3,   0,   4,   3,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  35,   0, \n      0,   9, 130,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n    242, 255, 255, 255,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,  21,   0,   0,   1, \n     54,   0,   0,   5,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  48,   0, \n      0,   1,  79,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  42, 144, 208,   0, \n    128,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   3,   0,   4,   3, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     35,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0, 241, 255, 255, 255, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     22,   0,   0,   1,  54,   0, \n      0,   5, 130,   0,  16,   0, \n     12,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   5,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  48,   0,   0,   1, \n     80,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   3,   0, \n      4,   3,  26,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  35,   0,   0,   9, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n      1,  64,   0,   0, 240, 255, \n    255, 255,  41,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     60,   0,   0,   7, 130,   0, \n     16,   0,  12,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n     12,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  22,   0,   0,   1, \n     18,   0,   0,   1,  32,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  31,   0,   4,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  68,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  22,   0,   0,   0, \n      1,   0,   0,  10,  82,   0, \n     16,   0,   2,   0,   0,   0, \n      6,   1,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  63,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,  63, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  84,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,   0, 192,  15,   0, \n    192,  15,   0,   0,   0,   0, \n      0, 192,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  18,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0,   0, 240,   3, \n      0, 240,   3,   0, 240,   3, \n      0,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  84,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      6,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0, 252,   0,   0, 252,   0, \n      0, 252,   0,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     18,   0,  16,   0,  12,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  63,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,  12,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  92,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n      1,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   1,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   2,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  18,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  32,   0, \n      0,   9,  34,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     26, 144, 208,   0, 128,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,  10, 242,   0,  16,   0, \n      3,   0,   0,   0,  86,   5, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,  15,   0, \n      0,   0,  14,   0,   0,   0, \n     13,   0,   0,   0,  12,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  30,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,  10, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     86,   5,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n     11,   0,   0,   0,  10,   0, \n      0,   0,   9,   0,   0,   0, \n      8,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,  10, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     86,   5,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      7,   0,   0,   0,   6,   0, \n      0,   0,   5,   0,   0,   0, \n      4,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n    130,   0,  16,   0,  12,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     29,   0,   0,   0,  30,   0, \n      0,  10, 194,   0,  16,   0, \n      2,   0,   0,   0,  86,   5, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  26,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,  12,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  18,   0, \n      0,   1,  32,   0,   0,   9, \n     34,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  26, 144, \n    208,   0, 128,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,  10, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  86,   5,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,  15,   0,   0,   0, \n     14,   0,   0,   0,  13,   0, \n      0,   0,  12,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     29,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  26,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  20,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,  10, 242,   0,  16,   0, \n      3,   0,   0,   0,  86,   5, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,  11,   0, \n      0,   0,  10,   0,   0,   0, \n      9,   0,   0,   0,   8,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  14,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,  10, 242,   0,  16,   0, \n      3,   0,   0,   0,  86,   5, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   7,   0, \n      0,   0,   6,   0,   0,   0, \n      5,   0,   0,   0,   4,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  60,   0, \n      0,   7, 130,   0,  16,   0, \n     12,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     28,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,  10, \n    194,   0,  16,   0,   2,   0, \n      0,   0,  86,   5,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     25,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n     12,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  18,   0,   0,   1, \n     32,   0,   0,   9,  34,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  26, 144, 208,   0, \n    128,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,  10, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     86,   5,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n     15,   0,   0,   0,  14,   0, \n      0,   0,  13,   0,   0,   0, \n     12,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  26,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,  10, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  86,   5,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,  11,   0,   0,   0, \n     10,   0,   0,   0,   9,   0, \n      0,   0,   8,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  11,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,  10, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  86,   5,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   7,   0,   0,   0, \n      6,   0,   0,   0,   5,   0, \n      0,   0,   4,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7, 130,   0,  16,   0, \n     12,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  29,   0,   0,   0, \n     30,   0,   0,  10, 194,   0, \n     16,   0,   2,   0,   0,   0, \n     86,   5,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  26,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  20,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,  12,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     18,   0,   0,   1,  30,   0, \n      0,  10, 242,   0,  16,   0, \n      3,   0,   0,   0,  86,   5, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,  15,   0, \n      0,   0,  14,   0,   0,   0, \n     13,   0,   0,   0,  12,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  29,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,  10, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     86,   5,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n     11,   0,   0,   0,  10,   0, \n      0,   0,   9,   0,   0,   0, \n      8,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,  10, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     86,   5,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      7,   0,   0,   0,   6,   0, \n      0,   0,   5,   0,   0,   0, \n      4,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n    130,   0,  16,   0,  12,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     29,   0,   0,   0,  30,   0, \n      0,  10, 194,   0,  16,   0, \n      2,   0,   0,   0,  86,   5, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  26,   0,   0,   0, \n     60,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  60,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  60,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,  12,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     21,   0,   0,   1,  18,   0, \n      0,   1,  32,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0, 254, \n    255, 255,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     68,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  62,   0,   0, 128,  15, \n      0,   0, 224,   3,   0,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  84,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,   0, 192,   7,   0, \n      0, 240,   1,   0,   0, 124, \n      0,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  30,   0, \n      0,  10, 146,   0,  16,   0, \n      2,   0,   0,   0,  86,   5, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   7,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   0, 248,   0, \n      0,   0,  62,   0,   0, 128, \n     15,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      8,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  84,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      9,   0,   0,   0,  10,   0, \n     16,   0,   8,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,  31,   0,   0, 192,   7, \n      0,   0, 240,   1,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,  10,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     68,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,  11,   0,   0,   0, \n     10,   0,  16,   0,  10,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n     11,   0,   0,   0,  26,   0, \n     16,   0,  10,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,  11,   0, \n      0,   0,  42,   0,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0,  22,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0, 224,   0,   0, \n      0, 248,   0,   0,   0,  62, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  18,   0,  16,   0, \n     12,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,  11,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,  13,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n     13,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n     13,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  84,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7,  18,   0,  16,   0, \n     14,   0,   0,   0,  10,   0, \n     16,   0,  13,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   7, \n     34,   0,  16,   0,  14,   0, \n      0,   0,  26,   0,  16,   0, \n     13,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n      1,   0,   0,  10, 146,   0, \n     16,   0,   3,   0,   0,   0, \n      6,   4,  16,   0,  14,   0, \n      0,   0,   2,  64,   0,   0, \n    124,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     31,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      9,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,  12,   0,   0,   0, \n     26,   0,  16,   0,  11,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n     11,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,  13,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0, 192,  30,   0,   0,   7, \n     66,   0,  16,   0,  12,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     92,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   5,  18,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  48,   0,   0,   1, \n     79,   0,   0,   9,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26, 144, 208,   0, 128,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      3,   0,   4,   3,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  60,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     22,   0,   0,   1,  54,   0, \n      0,   5,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n     54,   0,   0,   5,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  48,   0,   0,   1, \n     79,   0,   0,   9,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42, 144, 208,   0, 128,   0, \n      0,   0,  26,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      3,   0,   4,   3,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     22,   0,   0,   1,  54,   0, \n      0,   5, 130,   0,  16,   0, \n     12,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  48,   0,   0,   1, \n     80,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   3,   0, \n      4,   3,  10,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  60,   0, \n      0,   7, 130,   0,  16,   0, \n     12,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,  12,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     22,   0,   0,   1,  18,   0, \n      0,   1,  32,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0, 167,   0,   0,   9, \n    114,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n     70, 242,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0,   0, 252,   1,   0, \n    192,  31,   0,   0, 252,   1, \n      0,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  84,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      5,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n    254,   0,   0, 224,  15,   0, \n      0, 254,   0,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 114,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  68,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      7,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  19,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0, 127,   0,   0, 240,   7, \n      0,   0, 127,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     84,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     10,   0,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n     30,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   8,   0,   0,   0, \n      1,  64,   0,   0,  26,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,  22,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0, 128,   0,   0, \n      0, 248,   0,   0, 128,  63, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  18,   0,  16,   0, \n     12,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   9,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  84,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n     18,   0,  16,   0,  11,   0, \n      0,   0,  10,   0,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     85,   0,   0,   7,  34,   0, \n     16,   0,  11,   0,   0,   0, \n     26,   0,  16,   0,  10,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,   1,   0, \n      0,  10, 146,   0,  16,   0, \n      2,   0,   0,   0,   6,   4, \n     16,   0,  11,   0,   0,   0, \n      2,  64,   0,   0,  63,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  30,   0,   0,   7, \n     50,   0,  16,   0,   2,   0, \n      0,   0, 150,   5,  16,   0, \n      3,   0,   0,   0, 198,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  50,   0, \n     16,   0,   2,   0,   0,   0, \n    150,   5,  16,   0,   5,   0, \n      0,   0,  70,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  50,   0,  16,   0, \n      2,   0,   0,   0, 150,   5, \n     16,   0,   7,   0,   0,   0, \n     70,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     50,   0,  16,   0,   2,   0, \n      0,   0, 150,   5,  16,   0, \n      9,   0,   0,   0,  70,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     68,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     30,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,  64,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     84,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n     12,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     84,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     48,   0,   0,   1,  79,   0, \n      0,   9,  66,   0,  16,   0, \n      2,   0,   0,   0,  26, 144, \n    208,   0, 128,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   3,   0, \n      4,   3,  42,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  60,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,  54,   0,   0,   5, \n    130,   0,  16,   0,  12,   0, \n      0,   0,  58,   0,  16,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     48,   0,   0,   1,  80,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   3,   0,   4,   3, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  60,   0,   0,   7, \n    130,   0,  16,   0,  12,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,  12,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,  54,   0,   0,   5, \n     34,   0,  16,   0,  12,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  18,   0, \n      0,   1,  32,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  96,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  25,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n      0,  31,   0,   0,   0,   0, \n    124,   0,   0,   0,   0, 240, \n    192,  15,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  84,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     82,   0,  16,   0,   4,   0, \n      0,   0,   6,   3,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,   1,   0, \n      0,  10, 178,   0,  16,   0, \n      3,   0,   0,   0,  70,   8, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0,   0, 224, \n      3,   0,   0,   0, 128,  15, \n      0,   0,   0,   0,   0, 240, \n      3,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,  12,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     76,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     62,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  50,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n      1,   0,   0,  10, 146,   0, \n     16,   0,   1,   0,   0,   0, \n      6,   4,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  30,   0,   0,  10, \n    242,   0,  16,   0,   2,   0, \n      0,   0,  86,   5,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      2,   0,   0,   0,   3,   0, \n      0,   0,   4,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  50,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     19,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  21,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     22,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     25,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  25,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     28,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  30,   0,   0,  10, \n    242,   0,  16,   0,   4,   0, \n      0,   0,  86,   5,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   5,   0,   0,   0, \n      6,   0,   0,   0,   7,   0, \n      0,   0,   8,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   5,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     29,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     31,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,  12,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9,  50,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  30,   0, \n      0,  10, 242,   0,  16,   0, \n      5,   0,   0,   0,  86,   5, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   9,   0, \n      0,   0,  10,   0,   0,   0, \n     11,   0,   0,   0,  12,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   6,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   6,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     17,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,   9,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  30,   0,   0,  10, \n    226,   0,  16,   0,   5,   0, \n      0,   0,  86,   5,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n     13,   0,   0,   0,  14,   0, \n      0,   0,  15,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   6,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  23,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     13,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  26,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,  12,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7, 130,   0,  16,   0, \n     12,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  18,   0,   0,   1, \n     32,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  32,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     68,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  21,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     18,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      2,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0,   0, 127, \n      0,   0,   0,   0, 192,  31, \n    240,   7,   0,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     84,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  10,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     26,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0,   0, 128, \n     63,   0,   0,   0,   0, 224, \n      0, 248,   3,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  18,   0,  16,   0, \n     12,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  88,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     15,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n     12,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  96,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,  10, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     86,   5,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      1,   0,   0,   0,   2,   0, \n      0,   0,   3,   0,   0,   0, \n      4,   0,   0,   0, 167,   0, \n      0,   9,  50,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9,  50,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9,  50,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9,  50,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  30,   0, \n      0,  10, 242,   0,  16,   0, \n      3,   0,   0,   0,  86,   5, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   5,   0, \n      0,   0,   6,   0,   0,   0, \n      7,   0,   0,   0,   8,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     10,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  15,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     14,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  17,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  30,   0,   0,  10, \n    242,   0,  16,   0,   4,   0, \n      0,   0,  86,   5,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   9,   0,   0,   0, \n     10,   0,   0,   0,  11,   0, \n      0,   0,  12,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   5,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     19,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  18,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     21,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     23,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  22,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   5,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n     25,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,  10, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     86,   5,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n     13,   0,   0,   0,  14,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  50,   0,  16,   0, \n      6,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  27,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  26,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9,  50,   0,  16,   0, \n      6,   0,   0,   0,  26,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9,  50,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  30,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,  12,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n    130,   0,  16,   0,  12,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     18,   0,   0,   1,  32,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  31,   0,   4,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     20,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n    128,  63,   0,   0,   0,   0, \n    224,  15, 248,   3,   0,   0, \n      0,   0, 254,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  64,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  84,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  13,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     27,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   9,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  23,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n      0, 192,  31,   0,   0,   0, \n      0, 240,   0, 252,   1,   0, \n      0,   0,   0, 127,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,  12,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  50,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  84,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  68,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,  12,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,  10, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     86,   5,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      1,   0,   0,   0,   2,   0, \n      0,   0,   3,   0,   0,   0, \n      4,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  12,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,  10, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     86,   5,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      5,   0,   0,   0,   6,   0, \n      0,   0,   7,   0,   0,   0, \n      8,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  20,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,  12,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,  10, 242,   0,  16,   0, \n      3,   0,   0,   0,  86,   5, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   9,   0, \n      0,   0,  10,   0,   0,   0, \n     11,   0,   0,   0,  12,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     12,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,  10, 210,   0,  16,   0, \n      1,   0,   0,   0,  86,   5, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,  13,   0, \n      0,   0,   0,   0,   0,   0, \n     14,   0,   0,   0,  15,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  20,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     28,   0,   0,   0,  60,   0, \n      0,   7, 130,   0,  16,   0, \n     12,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  18,   0,   0,   1, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0, 128,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,  11,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     19,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,   1,   0,   0,  10, \n    210,   0,  16,   0,   1,   0, \n      0,   0,   6,   9,  16,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0,   0, 192,   7,   0, \n      0,   0,   0,   0,   0,   0, \n    192,   7,   0, 124,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  84,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n      1,  64,   0,   0,  12,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   4,   0, \n      0,   0,  70,  14,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,   0,   0, 248,   0, \n    128,  15,   0,   0,   0,   0, \n      0, 248,   0, 128,  15,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  68,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     18,   0,  16,   0,   6,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,   1,  64, \n      0,   0,  21,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      9,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  17,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,  31, \n      0, 240,   1,   0,   0,   0, \n    240,   1,   0,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  84,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      8,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,  26,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,  14,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   8,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,  22,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0, 224, \n      0,   0,  62,   0, 224,   3, \n      0,   0,   0,   0,   0,  62, \n     60,   0,   0,   7,  18,   0, \n     16,   0,  12,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      8,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  84,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7,  18,   0,  16,   0, \n     10,   0,   0,   0,  10,   0, \n     16,   0,   9,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  85,   0,   0,   7, \n     34,   0,  16,   0,  10,   0, \n      0,   0,  10,   0,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,  10, 146,   0, \n     16,   0,   6,   0,   0,   0, \n      6,   4,  16,   0,  10,   0, \n      0,   0,   2,  64,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0, 124,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      6,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,  12,   0, \n      0,   0,  42,   0,  16,   0, \n      4,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     85,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  31,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   4,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  68,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,   1,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,  64, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  84,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  29,   0, \n      0,   0,   1,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0, 128, \n     30,   0,   0,   7,  66,   0, \n     16,   0,  12,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  68,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  54,   0,   0,   5, \n     18,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  48,   0, \n      0,   1,  79,   0,   0,   9, \n     66,   0,  16,   0,   1,   0, \n      0,   0,  26, 144, 208,   0, \n    128,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   3,   0,   4,   3, \n     42,   0,  16,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     66,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   1,   0,   0,   0, \n     60,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  22,   0,   0,   1, \n     54,   0,   0,   5, 130,   0, \n     16,   0,  12,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  54,   0,   0,   5, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  48,   0, \n      0,   1,  80,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      3,   0,   4,   3,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     60,   0,   0,   7, 130,   0, \n     16,   0,  12,   0,   0,   0, \n     26,   0,  16,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n     12,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  22,   0,   0,   1, \n     21,   0,   0,   1,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     21,   0,   0,   1,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     21,   0,   0,   1, 168,   0, \n      0,   9, 242, 224,  17,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  70,  14,  16,   0, \n     12,   0,   0,   0,  21,   0, \n      0,   1,  62,   0,   0,   1\n};\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/Shaders/Compiled/BC7Encode_TryMode02CS.inc",
    "content": "#if 0\n//\n// Generated by Microsoft (R) D3D Shader Disassembler\n//\n//\n// Input signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Input\n//\n// Output signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Output\ncs_4_0\ndcl_globalFlags refactoringAllowed\ndcl_immediateConstantBuffer { { -0.000000, 15, 0, 0},\n                              { 65981199646559862278586368.000000, 15, 0, 0},\n                              { 15358528172589056.000000, 15, 0, 0},\n                              { 3584194248704.000000, 15, 0, 1},\n                              { -0.000000, 15, 0, 1},\n                              { -0.000000, 15, 0, 1},\n                              { 14680365989888.000000, 15, 0, 1},\n                              { 15362462362632192.000000, 15, 0, 2},\n                              { -0.000000, 15, 0, 2},\n                              { -0.000000, 15, 0, 2},\n                              { -0.000000, 15, 0, 2},\n                              { -0.000000, 15, 0, 2},\n                              { -0.000000, 15, 0, 3},\n                              { -0.000000, 15, 0, 3},\n                              { -0.000000, 15, 0, 3},\n                              { 0.000000, 15, 0, 3},\n                              { -0.000000, 15, 0, 4},\n                              { 0.000000, 2, 0, 4},\n                              { -0.000000, 8, 0, 4},\n                              { 22076467445760.000000, 2, 0, 4},\n                              { -0.000000, 2, 0, 5},\n                              { 70798013459086900396556288.000000, 8, 0, 5},\n                              { -0.000000, 8, 0, 5},\n                              { 0.000000, 15, 0, 5},\n                              { 0x0050a4a4, 2, 0, 6},\n                              { -0.000000, 8, 0, 6},\n                              { 0.000000, 2, 0, 6},\n                              { 17610885206241624413175808.000000, 2, 0, 6},\n                              { -0.000000, 8, 0, 6},\n                              { -0.000000, 8, 0, 7},\n                              { 22097854464.000000, 2, 0, 7},\n                              { 65888818352238724844093440.000000, 2, 0, 7},\n                              { -0.000000, 15, 0, 7},\n                              { 19411582976.000000, 15, 0, 8},\n                              { -0.000000, 6, 0, 8},\n                              { 0.000000, 8, 0, 8},\n                              { 0.000000, 2, 0, 8},\n                              { 0.000000, 8, 0, 9},\n                              { 0.000000, 15, 0, 9},\n                              { 22151331840.000000, 15, 0, 9},\n                              { 9304358912.000000, 2, 0, 9},\n                              { -0.000000, 8, 0, 10},\n                              { 271536072765004599787520.000000, 2, 0, 10},\n                              { -0.000000, 2, 0, 10},\n                              { 21517107200.000000, 2, 0, 10},\n                              { 12724757752857622655008768.000000, 15, 0, 10},\n                              { 1365.320801, 15, 0, 11},\n                              { 272006464738884193353728.000000, 6, 0, 11},\n                              { -0.000000, 6, 0, 11},\n                              { 5783798415360.000000, 2, 0, 11},\n                              { -0.000000, 6, 0, 12},\n                              { -0.000000, 8, 0, 12},\n                              { -0.000000, 15, 0, 12},\n                              { -0.000000, 15, 0, 12},\n                              { -0.000000, 2, 0, 13},\n                              { -0.000000, 2, 0, 13},\n                              { -0.000000, 15, 0, 13},\n                              { -0.000000, 15, 0, 13},\n                              { -0.000000, 15, 0, 14},\n                              { -0.000000, 15, 0, 14},\n                              { 4.007874, 15, 0, 14},\n                              { -0.000000, 2, 0, 14},\n                              { -0.000000, 2, 0, 15},\n                              { 0.000000, 15, 0, 15},\n                              { 0, 3, 15, 0},\n                              { 4, 3, 8, 0},\n                              { 9, 15, 8, 0},\n                              { 13, 15, 3, 0},\n                              { 17, 8, 15, 0},\n                              { 21, 3, 15, 1},\n                              { 26, 15, 3, 1},\n                              { 30, 15, 8, 1},\n                              { 34, 8, 15, 1},\n                              { 38, 8, 15, 1},\n                              { 43, 6, 15, 1},\n                              { 47, 6, 15, 1},\n                              { 51, 6, 15, 1},\n                              { 55, 5, 15, 1},\n                              { 60, 3, 15, 2},\n                              { 64, 3, 8, 2},\n                              { 0, 3, 15, 2},\n                              { 9, 3, 8, 2},\n                              { 18, 8, 15, 2},\n                              { 27, 15, 3, 2},\n                              { 37, 3, 15, 2},\n                              { 46, 3, 8, 2},\n                              { 55, 6, 15, 2},\n                              { 64, 10, 8, 3},\n                              { 0, 5, 3, 3},\n                              { 0, 8, 15, 3},\n                              { 0, 8, 6, 3},\n                              { 0, 6, 10, 3},\n                              { 0, 8, 15, 3},\n                              { 0, 5, 15, 3},\n                              { 0, 15, 10, 3},\n                              { 0, 15, 8, 3},\n                              { 0, 8, 15, 3},\n                              { 21, 15, 3, 4},\n                              { 43, 3, 15, 4},\n                              { 64, 5, 10, 4},\n                              { 0, 6, 10, 4},\n                              { 0, 10, 8, 4},\n                              { 0, 8, 9, 4},\n                              { 0, 15, 10, 4},\n                              { 0, 15, 6, 4},\n                              { 0, 3, 15, 4},\n                              { 0, 15, 8, 5},\n                              { 0, 5, 15, 5},\n                              { 0, 15, 3, 5},\n                              { 0, 15, 6, 5},\n                              { 0, 15, 6, 5},\n                              { 0, 15, 8, 5},\n                              { 0, 3, 15, 5},\n                              { 0, 15, 3, 5},\n                              { 0, 5, 15, 5},\n                              { 0, 5, 15, 6},\n                              { 0, 5, 15, 6},\n                              { 0, 8, 15, 6},\n                              { 0, 5, 15, 6},\n                              { 0, 10, 15, 6},\n                              { 0, 5, 15, 6},\n                              { 0, 10, 15, 6},\n                              { 0, 8, 15, 6},\n                              { 0, 13, 15, 6},\n                              { 0, 15, 3, 7},\n                              { 0, 12, 15, 7},\n                              { 0, 3, 15, 7},\n                              { 0, 3, 8, 7},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3} }\ndcl_constantbuffer CB0[2], immediateIndexed\ndcl_resource_texture2d (float,float,float,float) t0\ndcl_resource_structured t1, 16\ndcl_uav_structured u0, 16\ndcl_input vThreadIDInGroupFlattened\ndcl_input vThreadGroupID.x\ndcl_temps 29\ndcl_indexableTemp x0[12], 4\ndcl_indexableTemp x1[3], 4\ndcl_indexableTemp x2[3], 4\ndcl_indexableTemp x3[3], 4\ndcl_indexableTemp x4[3], 4\ndcl_indexableTemp x5[3], 4\ndcl_indexableTemp x6[3], 4\ndcl_tgsm_structured g0, 100, 64\ndcl_thread_group 64, 1, 1\niadd r0.x, vThreadGroupID.x, cb0[1].x\nult r1.xyzw, vThreadIDInGroupFlattened.xxxx, l(16, 32, 8, 4)\nif_nz r1.x\n  udiv r0.y, null, r0.x, cb0[0].y\n  imad r0.z, -r0.y, cb0[0].y, r0.x\n  ishl r0.z, r0.z, l(2)\n  ishl r0.y, r0.y, l(2)\n  and r0.w, vThreadIDInGroupFlattened.x, l(3)\n  iadd r2.x, r0.w, r0.z\n  ushr r0.z, vThreadIDInGroupFlattened.x, l(2)\n  iadd r2.y, r0.z, r0.y\n  mov r2.zw, l(0,0,0,0)\n  ld r2.xyzw, r2.xyzw, t0.xyzw\n  mul r2.xyzw, r2.xyzw, l(255.000000, 255.000000, 255.000000, 255.000000)\n  ftou r2.xyzw, r2.xyzw\n  umin r2.xyzw, r2.xyzw, l(255, 255, 255, 255)\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(0), r2.xyzw\nendif \nsync_g_t\nstore_structured g0.x, vThreadIDInGroupFlattened.x, l(16), l(-1)\nmovc r0.y, cb0[0].w, l(64), l(16)\nult r0.y, vThreadIDInGroupFlattened.x, r0.y\nif_nz r0.y\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(64)\n  mov x0[0].x, l(-1)\n  mov x0[1].x, l(-1)\n  mov x0[2].x, l(-1)\n  mov x0[0].y, l(0)\n  mov x0[1].y, l(0)\n  mov x0[2].y, l(0)\n  mov x0[4].x, l(-1)\n  mov x0[5].x, l(-1)\n  mov x0[6].x, l(-1)\n  mov x0[4].y, l(0)\n  mov x0[5].y, l(0)\n  mov x0[6].y, l(0)\n  mov x0[8].x, l(-1)\n  mov x0[9].x, l(-1)\n  mov x0[10].x, l(-1)\n  mov x0[8].y, l(0)\n  mov x0[9].y, l(0)\n  mov x0[10].y, l(0)\n  iadd r0.z, r0.y, l(-64)\n  mov r0.w, l(0)\n  loop \n    uge r2.x, r0.w, l(16)\n    breakc_nz r2.x\n    ld_structured r2.xyz, r0.w, l(0), g0.xyzx\n    ishl r2.w, r0.w, l(1)\n    ushr r2.w, icb[r0.z + 0].x, r2.w\n    and r2.w, r2.w, l(3)\n    ieq r3.x, r2.w, l(2)\n    if_nz r3.x\n      mov r3.x, x0[8].x\n      mov r3.y, x0[9].x\n      mov r3.z, x0[10].x\n      umin r3.xyz, r2.xyzx, r3.xyzx\n      mov x0[8].x, r3.x\n      mov x0[9].x, r3.y\n      mov x0[10].x, r3.z\n      mov r3.x, x0[8].y\n      mov r3.y, x0[9].y\n      mov r3.z, x0[10].y\n      umax r3.xyz, r2.xyzx, r3.xyzx\n      mov x0[8].y, r3.x\n      mov x0[9].y, r3.y\n      mov x0[10].y, r3.z\n    else \n      ieq r2.w, r2.w, l(1)\n      if_nz r2.w\n        mov r3.x, x0[4].x\n        mov r3.y, x0[5].x\n        mov r3.z, x0[6].x\n        umin r3.xyz, r2.xyzx, r3.xyzx\n        mov x0[4].x, r3.x\n        mov x0[5].x, r3.y\n        mov x0[6].x, r3.z\n        mov r3.x, x0[4].y\n        mov r3.y, x0[5].y\n        mov r3.z, x0[6].y\n        umax r3.xyz, r2.xyzx, r3.xyzx\n        mov x0[4].y, r3.x\n        mov x0[5].y, r3.y\n        mov x0[6].y, r3.z\n      else \n        mov r3.x, x0[0].x\n        mov r3.y, x0[1].x\n        mov r3.z, x0[2].x\n        umin r3.xyz, r2.xyzx, r3.xyzx\n        mov x0[0].x, r3.x\n        mov x0[1].x, r3.y\n        mov x0[2].x, r3.z\n        mov r3.x, x0[0].y\n        mov r3.y, x0[1].y\n        mov r3.z, x0[2].y\n        umax r2.xyz, r2.xyzx, r3.xyzx\n        mov x0[0].y, r2.x\n        mov x0[1].y, r2.y\n        mov x0[2].y, r2.z\n      endif \n    endif \n    iadd r0.w, r0.w, l(1)\n  endloop \n  mov r2.x, x0[0].x\n  mov r2.y, x0[1].x\n  mov r2.z, x0[2].x\n  mov r3.x, x0[0].y\n  mov r3.y, x0[1].y\n  mov r3.z, x0[2].y\n  mov r4.x, x0[4].x\n  mov r4.y, x0[5].x\n  mov r4.z, x0[6].x\n  mov r5.x, x0[4].y\n  mov r5.y, x0[5].y\n  mov r5.z, x0[6].y\n  mov r6.x, x0[8].x\n  mov r6.y, x0[9].x\n  mov r6.z, x0[10].x\n  mov r7.x, x0[8].y\n  mov r7.y, x0[9].y\n  mov r7.z, x0[10].y\n  movc r0.w, cb0[0].w, l(1), l(4)\n  mov x1[0].x, l(0)\n  mov x1[1].x, l(0)\n  mov x1[2].x, l(0)\n  mov x2[0].x, l(-1)\n  mov x2[1].x, l(-1)\n  mov x2[2].x, l(-1)\n  imad r2.xyz, r2.xyzx, l(7967, 7967, 7967, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n  ushr r2.xyz, r2.xyzx, l(16)\n  and r8.xyz, r2.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\n  imad r3.xyz, r3.xyzx, l(7967, 7967, 7967, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n  ushr r3.xyz, r3.xyzx, l(16)\n  and r9.xyz, r3.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\n  ishl r2.xyz, r2.xyzx, l(3)\n  ushr r10.xyz, r2.xyzx, l(5)\n  or r2.xyz, r2.xyzx, r10.xyzx\n  ishl r3.xyz, r3.xyzx, l(3)\n  ushr r10.xyz, r3.xyzx, l(5)\n  or r3.xyz, r3.xyzx, r10.xyzx\n  imad r4.xyz, r4.xyzx, l(7967, 7967, 7967, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n  ushr r4.xyz, r4.xyzx, l(16)\n  and r10.xyz, r4.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\n  imad r5.xyz, r5.xyzx, l(7967, 7967, 7967, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n  ushr r5.xyz, r5.xyzx, l(16)\n  and r11.xyz, r5.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\n  ishl r4.xyz, r4.xyzx, l(3)\n  ushr r12.xyz, r4.xyzx, l(5)\n  or r4.xyz, r4.xyzx, r12.xyzx\n  ishl r5.xyz, r5.xyzx, l(3)\n  ushr r12.xyz, r5.xyzx, l(5)\n  or r5.xyz, r5.xyzx, r12.xyzx\n  imad r6.xyz, r6.xyzx, l(7967, 7967, 7967, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n  ushr r6.xyz, r6.xyzx, l(16)\n  and r12.xyz, r6.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\n  imad r7.xyz, r7.xyzx, l(7967, 7967, 7967, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n  ushr r7.xyz, r7.xyzx, l(16)\n  and r13.xyz, r7.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\n  ishl r6.xyz, r6.xyzx, l(3)\n  ushr r14.xyz, r6.xyzx, l(5)\n  or r6.xyz, r6.xyzx, r14.xyzx\n  ishl r7.xyz, r7.xyzx, l(3)\n  ushr r14.xyz, r7.xyzx, l(5)\n  or r7.xyz, r7.xyzx, r14.xyzx\n  mov r2.w, r3.z\n  mov r3.w, r2.y\n  mov r4.w, r5.z\n  mov r5.w, r4.y\n  mov r6.w, r7.z\n  mov r7.w, r6.y\n  mov r14.y, l(255)\n  mov r2.y, cb0[0].w\n  mov r15.x, l(0)\n  loop \n    uge r3.z, r15.x, r0.w\n    breakc_nz r3.z\n    ieq r3.z, r2.y, l(2)\n    if_z r2.y\n      ushr r15.y, r15.x, l(1)\n      and r14.zw, r15.xxxy, l(0, 0, 1, 1)\n      iadd r16.xyz, r8.xyzx, r14.zzzz\n      ishl r16.xyz, r16.xyzx, l(3)\n      ushr r17.xyz, r16.xyzx, l(5)\n      or r16.xzw, r16.zzxy, r17.zzxy\n      iadd r17.xyz, r9.xyzx, r14.wwww\n      ishl r17.xyz, r17.xyzx, l(3)\n      ushr r18.xyz, r17.xyzx, l(5)\n      or r17.xyz, r17.yxzy, r18.yxzy\n      mov r16.y, r17.z\n      mov r17.w, r16.w\n      mov r14.zw, r17.wwwx\n      mov r17.x, r16.z\n    else \n      mov r16.xy, r2.zwzz\n      mov r14.zw, r3.wwwy\n      mov r17.x, r2.x\n      mov r17.y, r3.x\n    endif \n    mov x0[3].xy, l(255,255,0,0)\n    mov x0[2].xy, r16.xyxx\n    mov x0[1].xy, r14.zwzz\n    mov x0[0].xy, r17.xyxx\n    if_z r2.y\n      ushr r15.y, r15.x, l(1)\n      and r15.zw, r15.xxxy, l(0, 0, 1, 1)\n      iadd r18.xyz, r10.xyzx, r15.zzzz\n      ishl r18.xyz, r18.xyzx, l(3)\n      ushr r19.xyz, r18.xyzx, l(5)\n      or r18.xzw, r18.zzxy, r19.zzxy\n      iadd r19.xyz, r11.xyzx, r15.wwww\n      ishl r19.xyz, r19.xyzx, l(3)\n      ushr r20.xyz, r19.xyzx, l(5)\n      or r19.xyz, r19.yxzy, r20.yxzy\n      mov r18.y, r19.z\n      mov r19.w, r18.w\n      mov r15.zw, r19.wwwx\n      mov r19.x, r18.z\n    else \n      mov r18.xy, r4.zwzz\n      mov r15.zw, r5.wwwy\n      mov r19.x, r4.x\n      mov r19.y, r5.x\n    endif \n    mov x0[7].xy, l(255,255,0,0)\n    mov x0[6].xy, r18.xyxx\n    mov x0[5].xy, r15.zwzz\n    mov x0[4].xy, r19.xyxx\n    if_z r2.y\n      ushr r15.y, r15.x, l(1)\n      and r16.zw, r15.xxxy, l(0, 0, 1, 1)\n      iadd r20.xyz, r12.xyzx, r16.zzzz\n      ishl r20.xyz, r20.xyzx, l(3)\n      ushr r21.xyz, r20.xyzx, l(5)\n      or r20.xzw, r20.zzxy, r21.zzxy\n      iadd r21.xyz, r13.xyzx, r16.wwww\n      ishl r21.xyz, r21.xyzx, l(3)\n      ushr r22.xyz, r21.xyzx, l(5)\n      or r21.xyz, r21.yxzy, r22.yxzy\n      mov r20.y, r21.z\n      mov r21.w, r20.w\n      mov r16.zw, r21.wwwx\n      mov r21.x, r20.z\n    else \n      mov r20.xy, r6.zwzz\n      mov r16.zw, r7.wwwy\n      mov r21.x, r6.x\n      mov r21.y, r7.x\n    endif \n    mov x0[11].xy, l(255,255,0,0)\n    mov x0[10].xy, r20.xyxx\n    mov x0[9].xy, r16.zwzz\n    mov x0[8].xy, r21.xyxx\n    ineg r22.x, r17.x\n    ineg r22.y, r14.z\n    ineg r22.z, r16.x\n    mov r17.z, r14.w\n    mov r17.w, r16.y\n    iadd r17.xyz, r17.yzwy, r22.xyzx\n    mov x3[0].xyz, r17.xyzx\n    ineg r22.x, r19.x\n    ineg r22.y, r15.z\n    ineg r22.z, r18.x\n    mov r19.z, r15.w\n    mov r19.w, r18.y\n    iadd r15.yzw, r19.yyzw, r22.xxyz\n    mov x3[1].xyz, r15.yzwy\n    ineg r18.x, r21.x\n    ineg r18.y, r16.z\n    ineg r18.z, r20.x\n    mov r21.z, r16.w\n    mov r21.w, r20.y\n    iadd r16.xyz, r18.xyzx, r21.yzwy\n    mov x3[2].xyz, r16.xyzx\n    mov x3[2].w, l(0)\n    mov x3[1].w, l(0)\n    mov x3[0].w, l(0)\n    imul null, r14.zw, r17.xxxy, r17.xxxy\n    iadd r4.y, r14.w, r14.z\n    imad r4.y, r17.z, r17.z, r4.y\n    mov x4[0].x, r4.y\n    imul null, r14.zw, r15.yyyz, r15.yyyz\n    iadd r5.z, r14.w, r14.z\n    imad r5.z, r15.w, r15.w, r5.z\n    mov x4[1].x, r5.z\n    imul null, r14.zw, r16.xxxy, r16.xxxy\n    iadd r6.y, r14.w, r14.z\n    imad r6.y, r16.z, r16.z, r6.y\n    mov x4[2].x, r6.y\n    mov x5[0].x, l(0)\n    mov x5[1].x, icb[r0.y + 0].y\n    mov x5[2].x, icb[r0.y + 0].z\n    mov r7.z, l(0)\n    loop \n      uge r8.w, r7.z, l(3)\n      breakc_nz r8.w\n      mov r16.xyzw, x3[r7.z + 0].xyzw\n      mov r8.w, x5[r7.z + 0].x\n      ld_structured r17.xyzw, r8.w, l(0), g0.xyzw\n      ishl r8.w, r7.z, l(2)\n      mov r9.w, x0[r8.w + 0].x\n      mov r10.w, x0[r8.w + 1].x\n      mov r11.w, x0[r8.w + 2].x\n      mov r12.w, x0[r8.w + 3].x\n      ineg r18.x, r9.w\n      ineg r18.y, r10.w\n      ineg r18.z, r11.w\n      ineg r18.w, r12.w\n      iadd r17.xyzw, r17.xyzw, r18.xyzw\n      imul null, r14.zw, r16.xxxy, r17.xxxy\n      iadd r13.w, r14.w, r14.z\n      imad r13.w, r16.z, r17.z, r13.w\n      imad r13.w, r16.w, r17.w, r13.w\n      mov r14.z, x4[r7.z + 0].x\n      ilt r14.w, l(0), r14.z\n      ilt r15.y, l(0), r13.w\n      and r14.w, r14.w, r15.y\n      itof r13.w, r13.w\n      mul r13.w, r13.w, l(63.499989)\n      ftou r13.w, r13.w\n      ishl r14.z, r14.z, l(5)\n      ult r13.w, r14.z, r13.w\n      and r13.w, r13.w, r14.w\n      if_nz r13.w\n        ineg r16.xyzw, r16.xyzw\n        mov x3[r7.z + 0].xyzw, r16.xyzw\n        mov r13.w, x0[r8.w + 0].y\n        mov r14.z, x0[r8.w + 1].y\n        mov r14.w, x0[r8.w + 2].y\n        mov r15.y, x0[r8.w + 3].y\n        mov x0[r8.w + 0].x, r13.w\n        mov x0[r8.w + 1].x, r14.z\n        mov x0[r8.w + 2].x, r14.w\n        mov x0[r8.w + 3].x, r15.y\n        mov x0[r8.w + 0].y, r9.w\n        mov x0[r8.w + 1].y, r10.w\n        mov x0[r8.w + 2].y, r11.w\n        mov x0[r8.w + 3].y, r12.w\n      endif \n      iadd r7.z, r7.z, l(1)\n    endloop \n    mov x6[0].x, l(0)\n    mov x6[1].x, l(0)\n    mov x6[2].x, l(0)\n    mov r16.xyzw, x3[2].xyzw\n    mov r7.z, x0[8].x\n    mov r8.w, x0[9].x\n    mov r9.w, x0[10].x\n    mov r10.w, x0[11].x\n    ineg r17.x, r7.z\n    ineg r17.y, r8.w\n    ineg r17.z, r9.w\n    ineg r17.w, r10.w\n    ige r11.w, l(0), r6.y\n    itof r12.w, r6.y\n    movc r15.yzw, r3.zzzz, l(0,128,3,32), l(0,64,7,16)\n    mov r18.xyzw, x3[1].xyzw\n    mov r3.z, x0[4].x\n    mov r13.w, x0[5].x\n    mov r14.z, x0[6].x\n    mov r14.w, x0[7].x\n    ineg r19.x, r3.z\n    ineg r19.y, r13.w\n    ineg r19.zw, r14.zzzw\n    ige r20.x, l(0), r5.z\n    itof r20.y, r5.z\n    mov r21.xyzw, x3[0].xyzw\n    mov r20.z, x0[0].x\n    mov r20.w, x0[1].x\n    mov r22.x, x0[2].x\n    mov r22.y, x0[3].x\n    ineg r23.xy, r20.zwzz\n    ineg r23.zw, r22.xxxy\n    ige r22.z, l(0), r4.y\n    itof r22.w, r4.y\n    mov r24.x, l(0)\n    loop \n      uge r24.y, r24.x, l(16)\n      breakc_nz r24.y\n      ishl r24.y, r24.x, l(1)\n      ushr r24.y, icb[r0.z + 0].x, r24.y\n      and r24.y, r24.y, l(3)\n      ieq r24.zw, r24.yyyy, l(0, 0, 2, 1)\n      if_nz r24.z\n        ld_structured r25.xyzw, r24.x, l(0), g0.xyzw\n        iadd r25.xyzw, r17.xyzw, r25.xyzw\n        imul null, r25.xy, r16.xyxx, r25.xyxx\n        iadd r25.x, r25.y, r25.x\n        imad r25.x, r16.z, r25.z, r25.x\n        imad r25.x, r16.w, r25.w, r25.x\n        ige r25.y, l(0), r25.x\n        or r25.y, r11.w, r25.y\n        ilt r25.z, r25.x, r6.y\n        itof r25.x, r25.x\n        mul r25.x, r25.x, l(63.499989)\n        div r25.x, r25.x, r12.w\n        ftou r25.x, r25.x\n        iadd r25.x, r15.y, r25.x\n        movc r25.x, r25.z, icb[r25.x + 0].w, r15.z\n        movc r25.x, r25.y, l(0), r25.x\n      else \n        ieq r25.y, r24.y, l(1)\n        if_nz r25.y\n          ld_structured r26.xyzw, r24.x, l(0), g0.xyzw\n          iadd r26.xyzw, r19.xyzw, r26.xyzw\n          imul null, r25.yz, r18.xxyx, r26.xxyx\n          iadd r25.y, r25.z, r25.y\n          imad r25.y, r18.z, r26.z, r25.y\n          imad r25.y, r18.w, r26.w, r25.y\n          ige r25.z, l(0), r25.y\n          or r25.z, r20.x, r25.z\n          ilt r25.w, r25.y, r5.z\n          itof r25.y, r25.y\n          mul r25.y, r25.y, l(63.499989)\n          div r25.y, r25.y, r20.y\n          ftou r25.y, r25.y\n          iadd r25.y, r15.y, r25.y\n          movc r25.y, r25.w, icb[r25.y + 0].w, r15.z\n          movc r25.x, r25.z, l(0), r25.y\n        else \n          ld_structured r26.xyzw, r24.x, l(0), g0.xyzw\n          iadd r26.xyzw, r23.xyzw, r26.xyzw\n          imul null, r25.yz, r21.xxyx, r26.xxyx\n          iadd r25.y, r25.z, r25.y\n          imad r25.y, r21.z, r26.z, r25.y\n          imad r25.y, r21.w, r26.w, r25.y\n          ige r25.z, l(0), r25.y\n          or r25.z, r22.z, r25.z\n          ilt r25.w, r25.y, r4.y\n          itof r25.y, r25.y\n          mul r25.y, r25.y, l(63.499989)\n          div r25.y, r25.y, r22.w\n          ftou r25.y, r25.y\n          iadd r25.y, r15.y, r25.y\n          movc r25.y, r25.w, icb[r25.y + 0].w, r15.z\n          movc r25.x, r25.z, l(0), r25.y\n        endif \n      endif \n      iadd r25.x, r15.w, r25.x\n      iadd r25.y, l(64), -icb[r25.x + 64].x\n      ishl r24.y, r24.y, l(2)\n      mov r26.x, x0[r24.y + 0].x\n      mov r26.y, x0[r24.y + 1].x\n      mov r26.z, x0[r24.y + 2].x\n      mov r27.x, x0[r24.y + 0].y\n      mov r27.y, x0[r24.y + 1].y\n      mov r27.z, x0[r24.y + 2].y\n      imul null, r25.xzw, r27.xxyz, icb[r25.x + 64].xxxx\n      imad r25.xyz, r25.yyyy, r26.xyzx, r25.xzwx\n      iadd r25.xyz, r25.xyzx, l(32, 32, 32, 0)\n      ushr r25.xyw, r25.xyxz, l(6)\n      ld_structured r26.xyzw, r24.x, l(0), g0.xyzw\n      ult r27.xyz, r25.xywx, r26.xyzx\n      mov r25.z, r26.x\n      movc r27.xw, r27.xxxx, r25.zzzx, r25.xxxz\n      mov r25.xz, r26.yyzy\n      movc r25.xyzw, r27.yyzz, r25.xyzw, r25.yxwz\n      ult r24.y, l(255), r26.w\n      mov r14.x, r26.w\n      movc r26.xw, r24.yyyy, r14.yyyx, r14.xxxy\n      ineg r28.x, r27.w\n      ineg r28.yz, r25.yywy\n      ineg r28.w, r26.x\n      mov r26.x, r27.x\n      mov r26.yz, r25.xxzx\n      iadd r25.xyzw, r28.xyzw, r26.xyzw\n      imul null, r25.xy, r25.xyxx, r25.xyxx\n      iadd r14.x, r25.y, r25.x\n      imad r14.x, r25.z, r25.z, r14.x\n      utof r14.x, r14.x\n      utof r24.y, r25.w\n      mul r24.y, r24.y, r24.y\n      mad r14.x, r24.y, cb0[1].z, r14.x\n      ftou r14.x, r14.x\n      mov r24.y, x6[2].x\n      iadd r25.x, r14.x, r24.y\n      movc r24.y, r24.z, r25.x, r24.y\n      mov x6[2].x, r24.y\n      not r24.yz, r24.zzwz\n      and r24.w, r24.w, r24.y\n      mov r25.x, x6[1].x\n      iadd r25.y, r14.x, r25.x\n      movc r24.w, r24.w, r25.y, r25.x\n      mov x6[1].x, r24.w\n      and r24.y, r24.z, r24.y\n      mov r24.z, x6[0].x\n      iadd r14.x, r14.x, r24.z\n      movc r14.x, r24.y, r14.x, r24.z\n      mov x6[0].x, r14.x\n      iadd r24.x, r24.x, l(1)\n    endloop \n    mov r3.z, x6[0].x\n    mov r4.y, x2[0].x\n    ult r5.z, r3.z, r4.y\n    umin r3.z, r3.z, r4.y\n    mov x2[0].x, r3.z\n    mov r3.z, x1[0].x\n    movc r3.z, r5.z, r15.x, r3.z\n    mov x1[0].x, r3.z\n    mov r3.z, x6[1].x\n    mov r4.y, x2[1].x\n    ult r5.z, r3.z, r4.y\n    umin r3.z, r3.z, r4.y\n    mov x2[1].x, r3.z\n    mov r3.z, x1[1].x\n    movc r3.z, r5.z, r15.x, r3.z\n    mov x1[1].x, r3.z\n    mov r3.z, x6[2].x\n    mov r4.y, x2[2].x\n    ult r5.z, r3.z, r4.y\n    umin r3.z, r3.z, r4.y\n    mov x2[2].x, r3.z\n    mov r3.z, x1[2].x\n    movc r3.z, r5.z, r15.x, r3.z\n    mov x1[2].x, r3.z\n    iadd r15.x, r15.x, l(1)\n  endloop \n  mov r0.z, x2[0].x\n  mov r0.w, x2[1].x\n  iadd r0.z, r0.w, r0.z\n  mov r0.w, x2[2].x\n  iadd r0.z, r0.w, r0.z\n  store_structured g0.x, vThreadIDInGroupFlattened.x, l(16), r0.z\n  store_structured g0.x, vThreadIDInGroupFlattened.x, l(24), r0.y\n  mov r0.y, x1[2].x\n  ishl r0.y, r0.y, l(4)\n  mov r0.z, x1[1].x\n  ishl r0.z, r0.z, l(2)\n  or r0.y, r0.z, r0.y\n  mov r0.z, x1[0].x\n  or r0.y, r0.z, r0.y\n  store_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r0.y\nendif \nsync_g_t\nif_nz r1.y\n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(32)\n  ld_structured r3.x, r0.y, l(16), g0.xxxx\n  ld_structured r4.x, r0.y, l(24), g0.xxxx\n  ld_structured r5.x, r0.y, l(32), g0.xxxx\n  ult r0.y, r3.x, r2.x\n  if_nz r0.y\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(16), r3.x\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(24), r4.x\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r5.x\n  endif \nendif \nsync_g_t\nif_nz r1.x\n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(16)\n  ld_structured r3.x, r0.y, l(16), g0.xxxx\n  ld_structured r4.x, r0.y, l(24), g0.xxxx\n  ld_structured r5.x, r0.y, l(32), g0.xxxx\n  ult r0.y, r3.x, r2.x\n  if_nz r0.y\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(16), r3.x\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(24), r4.x\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r5.x\n  endif \nendif \nsync_g_t\nif_nz r1.z\n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(8)\n  ld_structured r3.x, r0.y, l(16), g0.xxxx\n  ld_structured r4.x, r0.y, l(24), g0.xxxx\n  ld_structured r5.x, r0.y, l(32), g0.xxxx\n  ult r0.y, r3.x, r2.x\n  if_nz r0.y\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(16), r3.x\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(24), r4.x\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r5.x\n  endif \nendif \nsync_g_t\nif_nz r1.w\n  ld_structured r1.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(4)\n  ld_structured r2.x, r0.y, l(16), g0.xxxx\n  ld_structured r3.x, r0.y, l(24), g0.xxxx\n  ld_structured r4.x, r0.y, l(32), g0.xxxx\n  ult r0.y, r2.x, r1.x\n  if_nz r0.y\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(16), r2.x\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(24), r3.x\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r4.x\n  endif \nendif \nsync_g_t\nult r0.yz, vThreadIDInGroupFlattened.xxxx, l(0, 2, 1, 0)\nif_nz r0.y\n  ld_structured r1.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(2)\n  ld_structured r2.x, r0.y, l(16), g0.xxxx\n  ld_structured r3.x, r0.y, l(24), g0.xxxx\n  ld_structured r4.x, r0.y, l(32), g0.xxxx\n  ult r0.y, r2.x, r1.x\n  if_nz r0.y\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(16), r2.x\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(24), r3.x\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r4.x\n  endif \nendif \nsync_g_t\nif_nz r0.z\n  ld_structured r1.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(1)\n  ld_structured r2.x, r0.y, l(16), g0.xxxx\n  ld_structured r3.x, r0.y, l(24), g0.xxxx\n  ld_structured r4.x, r0.y, l(32), g0.xxxx\n  ult r0.y, r2.x, r1.x\n  if_nz r0.y\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(16), r2.x\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(24), r3.x\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r4.x\n  endif \n  ld_structured r1.x, r0.x, l(0), t1.xxxx\n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  ult r0.y, r2.x, r1.x\n  if_nz r0.y\n    ld_structured r2.z, vThreadIDInGroupFlattened.x, l(24), g0.xxxx\n    ld_structured r2.w, vThreadIDInGroupFlattened.x, l(32), g0.xxxx\n    mov r2.y, cb0[0].w\n  else \n    ld_structured r2.xyzw, r0.x, l(0), t1.xyzw\n  endif \n  store_structured u0.xyzw, r0.x, l(0), r2.xyzw\nendif \nret \n// Approximately 0 instruction slots used\n#endif\n\nconst BYTE BC7Encode_TryMode02CS[] =\n{\n     68,  88,  66,  67, 145, 232, \n    246,  57,  30, 232,  55,  85, \n    166, 107, 154, 101, 228,  76, \n     33,  91,   1,   0,   0,   0, \n    136,  75,   0,   0,   3,   0, \n      0,   0,  44,   0,   0,   0, \n     60,   0,   0,   0,  76,   0, \n      0,   0,  73,  83,  71,  78, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     79,  83,  71,  78,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  83,  72, \n     69,  88,  52,  75,   0,   0, \n     64,   0,   5,   0, 205,  18, \n      0,   0, 106,   8,   0,   1, \n     53,  24,   0,   0,   2,   3, \n      0,   0,  80,  80, 104, 170, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     64,  80,  90, 106,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,  66, \n     90,  90,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 168, 160,  80,  84, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0, 165, 165,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  80,  80, \n    160, 160,  15,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0, 160, 160,  85,  85, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     80,  80,  90,  90,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n     85, 170,  15,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,  85,  85, 170, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,  85, 170, 170,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0, 144, 144, \n    144, 144,  15,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0, 148, 148, 148, 148, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n    164, 164, 164, 164,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  80, 148, \n    165, 169,  15,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  80,  66,  10,  42, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     64,  80, 148, 165,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,  84,  80, \n     66,  10,   2,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0, 165, 165, 165, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n    160, 160, 160,  85,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,  84,  84, \n    168, 168,   2,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  64,  64, 106, 106, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n      0,  80, 164, 164,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,   0,   5, \n     26,  26,  15,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0, 164, 164,  80,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n    144, 144, 165, 170,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  20, 105, \n    105,  20,   2,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   0,  20, 105, 105, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n    160, 133, 133, 160,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  20,  20, \n    130, 170,   8,   0,   0,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,  80, 164, 164,  80, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n      0,   2,  90, 106,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,   0, 128, \n    165, 169,  15,   0,   0,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0, 168, 160, 144,  80, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     80, 144, 160, 168,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  36,  36, \n     36,  36,   8,   0,   0,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,   0,  85, 170,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     36,  73, 146,  36,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      9,   0,   0,   0,  36, 146, \n     73,  36,  15,   0,   0,   0, \n      0,   0,   0,   0,   9,   0, \n      0,   0,  80,  10, 165,  80, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   9,   0,   0,   0, \n     80, 165,  10,  80,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      9,   0,   0,   0,  68,  68, \n    170, 170,   8,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,   0,   0, 102, 102, \n      2,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n    160, 165, 160, 165,   2,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,   0,   0, 160,  80, \n    160,  80,   2,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,  40, 105,  40, 105, \n     15,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n     68, 170, 170,  68,  15,   0, \n      0,   0,   0,   0,   0,   0, \n     11,   0,   0,   0,   0, 102, \n    102, 102,   6,   0,   0,   0, \n      0,   0,   0,   0,  11,   0, \n      0,   0,  68,  68,  68, 170, \n      6,   0,   0,   0,   0,   0, \n      0,   0,  11,   0,   0,   0, \n    168,  84, 168,  84,   2,   0, \n      0,   0,   0,   0,   0,   0, \n     11,   0,   0,   0, 128, 149, \n    128, 149,   6,   0,   0,   0, \n      0,   0,   0,   0,  12,   0, \n      0,   0,   0, 150, 150, 150, \n      8,   0,   0,   0,   0,   0, \n      0,   0,  12,   0,   0,   0, \n    168,  84,  84, 168,  15,   0, \n      0,   0,   0,   0,   0,   0, \n     12,   0,   0,   0, 128, 149, \n    149, 128,  15,   0,   0,   0, \n      0,   0,   0,   0,  12,   0, \n      0,   0,  20,  20,  20, 170, \n      2,   0,   0,   0,   0,   0, \n      0,   0,  13,   0,   0,   0, \n      0,   0, 150, 150,   2,   0, \n      0,   0,   0,   0,   0,   0, \n     13,   0,   0,   0,  20,  20, \n    170, 170,  15,   0,   0,   0, \n      0,   0,   0,   0,  13,   0, \n      0,   0, 160,  80,  80, 160, \n     15,   0,   0,   0,   0,   0, \n      0,   0,  13,   0,   0,   0, \n    160, 165, 165, 160,  15,   0, \n      0,   0,   0,   0,   0,   0, \n     14,   0,   0,   0,   0,   0, \n      0, 150,  15,   0,   0,   0, \n      0,   0,   0,   0,  14,   0, \n      0,   0, 128,  64, 128,  64, \n     15,   0,   0,   0,   0,   0, \n      0,   0,  14,   0,   0,   0, \n    168, 169, 168, 169,   2,   0, \n      0,   0,   0,   0,   0,   0, \n     14,   0,   0,   0,  68, 170, \n    170, 170,   2,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,  84,  82,  74,  42, \n     15,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   3,   0,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   9,   0,   0,   0, \n     15,   0,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n     13,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,  17,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,  21,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   1,   0,   0,   0, \n     26,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   0,  15,   0,   0,   0, \n      8,   0,   0,   0,   1,   0, \n      0,   0,  34,   0,   0,   0, \n      8,   0,   0,   0,  15,   0, \n      0,   0,   1,   0,   0,   0, \n     38,   0,   0,   0,   8,   0, \n      0,   0,  15,   0,   0,   0, \n      1,   0,   0,   0,  43,   0, \n      0,   0,   6,   0,   0,   0, \n     15,   0,   0,   0,   1,   0, \n      0,   0,  47,   0,   0,   0, \n      6,   0,   0,   0,  15,   0, \n      0,   0,   1,   0,   0,   0, \n     51,   0,   0,   0,   6,   0, \n      0,   0,  15,   0,   0,   0, \n      1,   0,   0,   0,  55,   0, \n      0,   0,   5,   0,   0,   0, \n     15,   0,   0,   0,   1,   0, \n      0,   0,  60,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   2,   0,   0,   0, \n     64,   0,   0,   0,   3,   0, \n      0,   0,   8,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     15,   0,   0,   0,   2,   0, \n      0,   0,   9,   0,   0,   0, \n      3,   0,   0,   0,   8,   0, \n      0,   0,   2,   0,   0,   0, \n     18,   0,   0,   0,   8,   0, \n      0,   0,  15,   0,   0,   0, \n      2,   0,   0,   0,  27,   0, \n      0,   0,  15,   0,   0,   0, \n      3,   0,   0,   0,   2,   0, \n      0,   0,  37,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   2,   0,   0,   0, \n     46,   0,   0,   0,   3,   0, \n      0,   0,   8,   0,   0,   0, \n      2,   0,   0,   0,  55,   0, \n      0,   0,   6,   0,   0,   0, \n     15,   0,   0,   0,   2,   0, \n      0,   0,  64,   0,   0,   0, \n     10,   0,   0,   0,   8,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   3,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,   6,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  10,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,  10,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      8,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n     21,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n      4,   0,   0,   0,  43,   0, \n      0,   0,   3,   0,   0,   0, \n     15,   0,   0,   0,   4,   0, \n      0,   0,  64,   0,   0,   0, \n      5,   0,   0,   0,  10,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  10,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n      8,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,   9,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,  10,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      6,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,   8,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     15,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,   3,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,   6,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      6,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,   8,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  15,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      3,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  15,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  15,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     15,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  15,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  15,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n     15,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  15,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,  15,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n     13,   0,   0,   0,  15,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n      7,   0,   0,   0,   0,   0, \n      0,   0,  12,   0,   0,   0, \n     15,   0,   0,   0,   7,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   7,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   8,   0,   0,   0, \n      7,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  89,   0,   0,   4, \n     70, 142,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     88,  24,   0,   4,   0, 112, \n     16,   0,   0,   0,   0,   0, \n     85,  85,   0,   0, 162,   0, \n      0,   4,   0, 112,  16,   0, \n      1,   0,   0,   0,  16,   0, \n      0,   0, 158,   0,   0,   4, \n      0, 224,  17,   0,   0,   0, \n      0,   0,  16,   0,   0,   0, \n     95,   0,   0,   2,   0,  64, \n      2,   0,  95,   0,   0,   2, \n     18,  16,   2,   0, 104,   0, \n      0,   2,  29,   0,   0,   0, \n    105,   0,   0,   4,   0,   0, \n      0,   0,  12,   0,   0,   0, \n      4,   0,   0,   0, 105,   0, \n      0,   4,   1,   0,   0,   0, \n      3,   0,   0,   0,   4,   0, \n      0,   0, 105,   0,   0,   4, \n      2,   0,   0,   0,   3,   0, \n      0,   0,   4,   0,   0,   0, \n    105,   0,   0,   4,   3,   0, \n      0,   0,   3,   0,   0,   0, \n      4,   0,   0,   0, 105,   0, \n      0,   4,   4,   0,   0,   0, \n      3,   0,   0,   0,   4,   0, \n      0,   0, 105,   0,   0,   4, \n      5,   0,   0,   0,   3,   0, \n      0,   0,   4,   0,   0,   0, \n    105,   0,   0,   4,   6,   0, \n      0,   0,   3,   0,   0,   0, \n      4,   0,   0,   0, 160,   0, \n      0,   5,   0, 240,  17,   0, \n      0,   0,   0,   0, 100,   0, \n      0,   0,  64,   0,   0,   0, \n    155,   0,   0,   4,  64,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      0,   0,   0,   0,  10,  16, \n      2,   0,  10, 128,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  79,   0,   0,   9, \n    242,   0,  16,   0,   1,   0, \n      0,   0,   6,  64,   2,   0, \n      2,  64,   0,   0,  16,   0, \n      0,   0,  32,   0,   0,   0, \n      8,   0,   0,   0,   4,   0, \n      0,   0,  31,   0,   4,   3, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  78,   0,   0,   9, \n     34,   0,  16,   0,   0,   0, \n      0,   0,   0, 208,   0,   0, \n     10,   0,  16,   0,   0,   0, \n      0,   0,  26, 128,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  35,   0,   0,  11, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16, 128, \n     65,   0,   0,   0,   0,   0, \n      0,   0,  26, 128,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   6, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   6,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  54,   0,   0,   8, \n    194,   0,  16,   0,   2,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  45,   0, \n      0,   7, 242,   0,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   2,   0,   0,   0, \n     70, 126,  16,   0,   0,   0, \n      0,   0,  56,   0,   0,  10, \n    242,   0,  16,   0,   2,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0,   0,   0, 127,  67, \n      0,   0, 127,  67,   0,   0, \n    127,  67,   0,   0, 127,  67, \n     28,   0,   0,   5, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   2,   0, \n      0,   0,  84,   0,   0,  10, \n    242,   0,  16,   0,   2,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0, 255,   0,   0,   0, \n    255,   0,   0,   0, 255,   0, \n      0,   0, 255,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70,  14,  16,   0,   2,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1, 168,   0, \n      0,   8,  18, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,  64, \n      0,   0, 255, 255, 255, 255, \n     55,   0,   0,  10,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58, 128,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  64,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  79,   0, \n      0,   6,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     64,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0, 192, 255, \n    255, 255,  54,   0,   0,   5, \n    130,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  48,   0, \n      0,   1,  80,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      3,   0,   4,   3,  10,   0, \n     16,   0,   2,   0,   0,   0, \n    167,   0,   0,   9, 114,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  70, 242, \n     17,   0,   0,   0,   0,   0, \n     41,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   8, 130,   0,  16,   0, \n      2,   0,   0,   0,  10, 144, \n    144,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  32,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  31,   0,   4,   3, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,  54,   0,   0,   6, \n     34,   0,  16,   0,   3,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   9,   0, \n      0,   0,  54,   0,   0,   6, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,  84,   0,   0,   7, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   0,   0,   0,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   0,   0,   0,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   9,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n     83,   0,   0,   7, 114,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  18,   0, \n      0,   1,  32,   0,   0,   7, \n    130,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     84,   0,   0,   7, 114,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  18,   0,  16,   0, \n      3,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n      3,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  54,   0, \n      0,   6,  66,   0,  16,   0, \n      3,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  83,   0, \n      0,   7, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  18,   0,   0,   1, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     84,   0,   0,   7, 114,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  18,   0,  16,   0, \n      3,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n      3,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   6,  66,   0,  16,   0, \n      3,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  83,   0, \n      0,   7, 114,   0,  16,   0, \n      2,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  21,   0,   0,   1, \n     21,   0,   0,   1,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  22,   0,   0,   1, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   6,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   6,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   9,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   6,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   9,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n     55,   0,   0,  10, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58, 128,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      4,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      1,   0,   0,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      2,   0,   0,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  35,   0, \n      0,  15, 114,   0,  16,   0, \n      2,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n      2,  64,   0,   0,  31,  31, \n      0,   0,  31,  31,   0,   0, \n     31,  31,   0,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n      2,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0,   0,   0,   0,   0, \n     35,   0,   0,  15, 114,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n     31,  31,   0,   0,  31,  31, \n      0,   0,  31,  31,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,  10,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n      2,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n     70,   2,  16,   0,  10,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,   3,   0, \n      0,   0,  70,   2,  16,   0, \n      3,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,  10,   0,   0,   0, \n     70,   2,  16,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n      3,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n     70,   2,  16,   0,  10,   0, \n      0,   0,  35,   0,   0,  15, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,   2,  64, \n      0,   0,  31,  31,   0,   0, \n     31,  31,   0,   0,  31,  31, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,  10,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n      0,   0,   0,   0,  35,   0, \n      0,  15, 114,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n      2,  64,   0,   0,  31,  31, \n      0,   0,  31,  31,   0,   0, \n     31,  31,   0,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0,   0,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,   4,   0, \n      0,   0,  70,   2,  16,   0, \n      4,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,   5,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n     35,   0,   0,  15, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n     31,  31,   0,   0,  31,  31, \n      0,   0,  31,  31,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0,   0,   0, \n      0,   0,  35,   0,   0,  15, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,  31,  31,   0,   0, \n     31,  31,   0,   0,  31,  31, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n      6,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,  14,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n     14,   0,   0,   0,   1,  64, \n      0,   0, 255,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     58, 128,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   5,  18,   0, \n     16,   0,  15,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  48,   0,   0,   1, \n     80,   0,   0,   7,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,  15,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   3,   0, \n      4,   3,  42,   0,  16,   0, \n      3,   0,   0,   0,  32,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  31,   0,   0,   3, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  85,   0,   0,   7, \n     34,   0,  16,   0,  15,   0, \n      0,   0,  10,   0,  16,   0, \n     15,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,  10, 194,   0, \n     16,   0,  14,   0,   0,   0, \n      6,   4,  16,   0,  15,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7, 114,   0,  16,   0, \n     16,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n    166,  10,  16,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,  16,   0, \n      0,   0,  70,   2,  16,   0, \n     16,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,  17,   0,   0,   0, \n     70,   2,  16,   0,  16,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  60,   0, \n      0,   7, 210,   0,  16,   0, \n     16,   0,   0,   0, 166,   4, \n     16,   0,  16,   0,   0,   0, \n    166,   4,  16,   0,  17,   0, \n      0,   0,  30,   0,   0,   7, \n    114,   0,  16,   0,  17,   0, \n      0,   0,  70,   2,  16,   0, \n      9,   0,   0,   0, 246,  15, \n     16,   0,  14,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  17,   0,   0,   0, \n     70,   2,  16,   0,  17,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n     18,   0,   0,   0,  70,   2, \n     16,   0,  17,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,  17,   0, \n      0,   0,  22,   6,  16,   0, \n     17,   0,   0,   0,  22,   6, \n     16,   0,  18,   0,   0,   0, \n     54,   0,   0,   5,  34,   0, \n     16,   0,  16,   0,   0,   0, \n     42,   0,  16,   0,  17,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,  17,   0, \n      0,   0,  58,   0,  16,   0, \n     16,   0,   0,   0,  54,   0, \n      0,   5, 194,   0,  16,   0, \n     14,   0,   0,   0, 246,   3, \n     16,   0,  17,   0,   0,   0, \n     54,   0,   0,   5,  18,   0, \n     16,   0,  17,   0,   0,   0, \n     42,   0,  16,   0,  16,   0, \n      0,   0,  18,   0,   0,   1, \n     54,   0,   0,   5,  50,   0, \n     16,   0,  16,   0,   0,   0, \n    230,  10,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   5, \n    194,   0,  16,   0,  14,   0, \n      0,   0, 246,   7,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   5,  18,   0,  16,   0, \n     17,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     54,   0,   0,   5,  34,   0, \n     16,   0,  17,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  21,   0,   0,   1, \n     54,   0,   0,   9,  50,  48, \n     32,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0, 255,   0,   0,   0, \n    255,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   6,  50,  48, \n     32,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  70,   0, \n     16,   0,  16,   0,   0,   0, \n     54,   0,   0,   6,  50,  48, \n     32,   0,   0,   0,   0,   0, \n      1,   0,   0,   0, 230,  10, \n     16,   0,  14,   0,   0,   0, \n     54,   0,   0,   6,  50,  48, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  70,   0, \n     16,   0,  17,   0,   0,   0, \n     31,   0,   0,   3,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     85,   0,   0,   7,  34,   0, \n     16,   0,  15,   0,   0,   0, \n     10,   0,  16,   0,  15,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n     15,   0,   0,   0,   6,   4, \n     16,   0,  15,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n    114,   0,  16,   0,  18,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0, 166,  10, \n     16,   0,  15,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  18,   0,   0,   0, \n     70,   2,  16,   0,  18,   0, \n      0,   0,   1,  64,   0,   0, \n      3,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n     19,   0,   0,   0,  70,   2, \n     16,   0,  18,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  60,   0,   0,   7, \n    210,   0,  16,   0,  18,   0, \n      0,   0, 166,   4,  16,   0, \n     18,   0,   0,   0, 166,   4, \n     16,   0,  19,   0,   0,   0, \n     30,   0,   0,   7, 114,   0, \n     16,   0,  19,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0, 246,  15,  16,   0, \n     15,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     19,   0,   0,   0,  70,   2, \n     16,   0,  19,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,  20,   0, \n      0,   0,  70,   2,  16,   0, \n     19,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,  19,   0,   0,   0, \n     22,   6,  16,   0,  19,   0, \n      0,   0,  22,   6,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n     18,   0,   0,   0,  42,   0, \n     16,   0,  19,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,  19,   0,   0,   0, \n     58,   0,  16,   0,  18,   0, \n      0,   0,  54,   0,   0,   5, \n    194,   0,  16,   0,  15,   0, \n      0,   0, 246,   3,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   5,  18,   0,  16,   0, \n     19,   0,   0,   0,  42,   0, \n     16,   0,  18,   0,   0,   0, \n     18,   0,   0,   1,  54,   0, \n      0,   5,  50,   0,  16,   0, \n     18,   0,   0,   0, 230,  10, \n     16,   0,   4,   0,   0,   0, \n     54,   0,   0,   5, 194,   0, \n     16,   0,  15,   0,   0,   0, \n    246,   7,  16,   0,   5,   0, \n      0,   0,  54,   0,   0,   5, \n     18,   0,  16,   0,  19,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n     19,   0,   0,   0,  10,   0, \n     16,   0,   5,   0,   0,   0, \n     21,   0,   0,   1,  54,   0, \n      0,   9,  50,  48,  32,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n    255,   0,   0,   0, 255,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  50,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  70,   0,  16,   0, \n     18,   0,   0,   0,  54,   0, \n      0,   6,  50,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0, 230,  10,  16,   0, \n     15,   0,   0,   0,  54,   0, \n      0,   6,  50,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  70,   0,  16,   0, \n     19,   0,   0,   0,  31,   0, \n      0,   3,  26,   0,  16,   0, \n      2,   0,   0,   0,  85,   0, \n      0,   7,  34,   0,  16,   0, \n     15,   0,   0,   0,  10,   0, \n     16,   0,  15,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,  16,   0, \n      0,   0,   6,   4,  16,   0, \n     15,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n     30,   0,   0,   7, 114,   0, \n     16,   0,  20,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0, 166,  10,  16,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     20,   0,   0,   0,  70,   2, \n     16,   0,  20,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,  21,   0, \n      0,   0,  70,   2,  16,   0, \n     20,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     60,   0,   0,   7, 210,   0, \n     16,   0,  20,   0,   0,   0, \n    166,   4,  16,   0,  20,   0, \n      0,   0, 166,   4,  16,   0, \n     21,   0,   0,   0,  30,   0, \n      0,   7, 114,   0,  16,   0, \n     21,   0,   0,   0,  70,   2, \n     16,   0,  13,   0,   0,   0, \n    246,  15,  16,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,  21,   0, \n      0,   0,  70,   2,  16,   0, \n     21,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,  22,   0,   0,   0, \n     70,   2,  16,   0,  21,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n     21,   0,   0,   0,  22,   6, \n     16,   0,  21,   0,   0,   0, \n     22,   6,  16,   0,  22,   0, \n      0,   0,  54,   0,   0,   5, \n     34,   0,  16,   0,  20,   0, \n      0,   0,  42,   0,  16,   0, \n     21,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n     21,   0,   0,   0,  58,   0, \n     16,   0,  20,   0,   0,   0, \n     54,   0,   0,   5, 194,   0, \n     16,   0,  16,   0,   0,   0, \n    246,   3,  16,   0,  21,   0, \n      0,   0,  54,   0,   0,   5, \n     18,   0,  16,   0,  21,   0, \n      0,   0,  42,   0,  16,   0, \n     20,   0,   0,   0,  18,   0, \n      0,   1,  54,   0,   0,   5, \n     50,   0,  16,   0,  20,   0, \n      0,   0, 230,  10,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   5, 194,   0,  16,   0, \n     16,   0,   0,   0, 246,   7, \n     16,   0,   7,   0,   0,   0, \n     54,   0,   0,   5,  18,   0, \n     16,   0,  21,   0,   0,   0, \n     10,   0,  16,   0,   6,   0, \n      0,   0,  54,   0,   0,   5, \n     34,   0,  16,   0,  21,   0, \n      0,   0,  10,   0,  16,   0, \n      7,   0,   0,   0,  21,   0, \n      0,   1,  54,   0,   0,   9, \n     50,  48,  32,   0,   0,   0, \n      0,   0,  11,   0,   0,   0, \n      2,  64,   0,   0, 255,   0, \n      0,   0, 255,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n     50,  48,  32,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n     70,   0,  16,   0,  20,   0, \n      0,   0,  54,   0,   0,   6, \n     50,  48,  32,   0,   0,   0, \n      0,   0,   9,   0,   0,   0, \n    230,  10,  16,   0,  16,   0, \n      0,   0,  54,   0,   0,   6, \n     50,  48,  32,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     70,   0,  16,   0,  21,   0, \n      0,   0,  40,   0,   0,   5, \n     18,   0,  16,   0,  22,   0, \n      0,   0,  10,   0,  16,   0, \n     17,   0,   0,   0,  40,   0, \n      0,   5,  34,   0,  16,   0, \n     22,   0,   0,   0,  42,   0, \n     16,   0,  14,   0,   0,   0, \n     40,   0,   0,   5,  66,   0, \n     16,   0,  22,   0,   0,   0, \n     10,   0,  16,   0,  16,   0, \n      0,   0,  54,   0,   0,   5, \n     66,   0,  16,   0,  17,   0, \n      0,   0,  58,   0,  16,   0, \n     14,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n     17,   0,   0,   0,  26,   0, \n     16,   0,  16,   0,   0,   0, \n     30,   0,   0,   7, 114,   0, \n     16,   0,  17,   0,   0,   0, \n    150,   7,  16,   0,  17,   0, \n      0,   0,  70,   2,  16,   0, \n     22,   0,   0,   0,  54,   0, \n      0,   6, 114,  48,  32,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n     17,   0,   0,   0,  40,   0, \n      0,   5,  18,   0,  16,   0, \n     22,   0,   0,   0,  10,   0, \n     16,   0,  19,   0,   0,   0, \n     40,   0,   0,   5,  34,   0, \n     16,   0,  22,   0,   0,   0, \n     42,   0,  16,   0,  15,   0, \n      0,   0,  40,   0,   0,   5, \n     66,   0,  16,   0,  22,   0, \n      0,   0,  10,   0,  16,   0, \n     18,   0,   0,   0,  54,   0, \n      0,   5,  66,   0,  16,   0, \n     19,   0,   0,   0,  58,   0, \n     16,   0,  15,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,  19,   0,   0,   0, \n     26,   0,  16,   0,  18,   0, \n      0,   0,  30,   0,   0,   7, \n    226,   0,  16,   0,  15,   0, \n      0,   0,  86,  14,  16,   0, \n     19,   0,   0,   0,   6,   9, \n     16,   0,  22,   0,   0,   0, \n     54,   0,   0,   6, 114,  48, \n     32,   0,   3,   0,   0,   0, \n      1,   0,   0,   0, 150,   7, \n     16,   0,  15,   0,   0,   0, \n     40,   0,   0,   5,  18,   0, \n     16,   0,  18,   0,   0,   0, \n     10,   0,  16,   0,  21,   0, \n      0,   0,  40,   0,   0,   5, \n     34,   0,  16,   0,  18,   0, \n      0,   0,  42,   0,  16,   0, \n     16,   0,   0,   0,  40,   0, \n      0,   5,  66,   0,  16,   0, \n     18,   0,   0,   0,  10,   0, \n     16,   0,  20,   0,   0,   0, \n     54,   0,   0,   5,  66,   0, \n     16,   0,  21,   0,   0,   0, \n     58,   0,  16,   0,  16,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,  21,   0, \n      0,   0,  26,   0,  16,   0, \n     20,   0,   0,   0,  30,   0, \n      0,   7, 114,   0,  16,   0, \n     16,   0,   0,   0,  70,   2, \n     16,   0,  18,   0,   0,   0, \n    150,   7,  16,   0,  21,   0, \n      0,   0,  54,   0,   0,   6, \n    114,  48,  32,   0,   3,   0, \n      0,   0,   2,   0,   0,   0, \n     70,   2,  16,   0,  16,   0, \n      0,   0,  54,   0,   0,   6, \n    130,  48,  32,   0,   3,   0, \n      0,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n    130,  48,  32,   0,   3,   0, \n      0,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n    130,  48,  32,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  38,   0,   0,   8, \n      0, 208,   0,   0, 194,   0, \n     16,   0,  14,   0,   0,   0, \n      6,   4,  16,   0,  17,   0, \n      0,   0,   6,   4,  16,   0, \n     17,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     42,   0,  16,   0,  14,   0, \n      0,   0,  35,   0,   0,   9, \n     34,   0,  16,   0,   4,   0, \n      0,   0,  42,   0,  16,   0, \n     17,   0,   0,   0,  42,   0, \n     16,   0,  17,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,  38,   0,   0,   8, \n      0, 208,   0,   0, 194,   0, \n     16,   0,  14,   0,   0,   0, \n     86,   9,  16,   0,  15,   0, \n      0,   0,  86,   9,  16,   0, \n     15,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     42,   0,  16,   0,  14,   0, \n      0,   0,  35,   0,   0,   9, \n     66,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n     15,   0,   0,   0,  58,   0, \n     16,   0,  15,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   4,   0, \n      0,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  38,   0,   0,   8, \n      0, 208,   0,   0, 194,   0, \n     16,   0,  14,   0,   0,   0, \n      6,   4,  16,   0,  16,   0, \n      0,   0,   6,   4,  16,   0, \n     16,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     42,   0,  16,   0,  14,   0, \n      0,   0,  35,   0,   0,   9, \n     34,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n     16,   0,   0,   0,  42,   0, \n     16,   0,  16,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   4,   0, \n      0,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   7, \n     18,  48,  32,   0,   5,   0, \n      0,   0,   1,   0,   0,   0, \n     26, 144, 144,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   7,  18,  48, \n     32,   0,   5,   0,   0,   0, \n      2,   0,   0,   0,  42, 144, \n    144,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   5,  66,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     48,   0,   0,   1,  80,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,   3,   0,   4,   3, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  54,   0,   0,   7, \n    242,   0,  16,   0,  16,   0, \n      0,   0,  70,  62,  32,   4, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     54,   0,   0,   7, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     10,  48,  32,   4,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n     17,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  54,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  10,  48,  32,   4, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     54,   0,   0,   8, 130,   0, \n     16,   0,  10,   0,   0,   0, \n     10,  48,  32,   6,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  54,   0,   0,   8, \n    130,   0,  16,   0,  11,   0, \n      0,   0,  10,  48,  32,   6, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  54,   0, \n      0,   8, 130,   0,  16,   0, \n     12,   0,   0,   0,  10,  48, \n     32,   6,   0,   0,   0,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     40,   0,   0,   5,  18,   0, \n     16,   0,  18,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  40,   0,   0,   5, \n     34,   0,  16,   0,  18,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,  40,   0, \n      0,   5,  66,   0,  16,   0, \n     18,   0,   0,   0,  58,   0, \n     16,   0,  11,   0,   0,   0, \n     40,   0,   0,   5, 130,   0, \n     16,   0,  18,   0,   0,   0, \n     58,   0,  16,   0,  12,   0, \n      0,   0,  30,   0,   0,   7, \n    242,   0,  16,   0,  17,   0, \n      0,   0,  70,  14,  16,   0, \n     17,   0,   0,   0,  70,  14, \n     16,   0,  18,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0, 194,   0,  16,   0, \n     14,   0,   0,   0,   6,   4, \n     16,   0,  16,   0,   0,   0, \n      6,   4,  16,   0,  17,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,  13,   0, \n      0,   0,  58,   0,  16,   0, \n     14,   0,   0,   0,  42,   0, \n     16,   0,  14,   0,   0,   0, \n     35,   0,   0,   9, 130,   0, \n     16,   0,  13,   0,   0,   0, \n     42,   0,  16,   0,  16,   0, \n      0,   0,  42,   0,  16,   0, \n     17,   0,   0,   0,  58,   0, \n     16,   0,  13,   0,   0,   0, \n     35,   0,   0,   9, 130,   0, \n     16,   0,  13,   0,   0,   0, \n     58,   0,  16,   0,  16,   0, \n      0,   0,  58,   0,  16,   0, \n     17,   0,   0,   0,  58,   0, \n     16,   0,  13,   0,   0,   0, \n     54,   0,   0,   7,  66,   0, \n     16,   0,  14,   0,   0,   0, \n     10,  48,  32,   4,   4,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  34,   0, \n      0,   7, 130,   0,  16,   0, \n     14,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,  14,   0, \n      0,   0,  34,   0,   0,   7, \n     34,   0,  16,   0,  15,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,  13,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,  14,   0, \n      0,   0,  26,   0,  16,   0, \n     15,   0,   0,   0,  43,   0, \n      0,   5, 130,   0,  16,   0, \n     13,   0,   0,   0,  58,   0, \n     16,   0,  13,   0,   0,   0, \n     56,   0,   0,   7, 130,   0, \n     16,   0,  13,   0,   0,   0, \n     58,   0,  16,   0,  13,   0, \n      0,   0,   1,  64,   0,   0, \n    253, 255, 125,  66,  28,   0, \n      0,   5, 130,   0,  16,   0, \n     13,   0,   0,   0,  58,   0, \n     16,   0,  13,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,  14,   0,   0,   0, \n     42,   0,  16,   0,  14,   0, \n      0,   0,   1,  64,   0,   0, \n      5,   0,   0,   0,  79,   0, \n      0,   7, 130,   0,  16,   0, \n     13,   0,   0,   0,  42,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,  13,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,  13,   0, \n      0,   0,  58,   0,  16,   0, \n     13,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,  13,   0,   0,   0, \n     40,   0,   0,   5, 242,   0, \n     16,   0,  16,   0,   0,   0, \n     70,  14,  16,   0,  16,   0, \n      0,   0,  54,   0,   0,   7, \n    242,  48,  32,   4,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,  16,   0,   0,   0, \n     54,   0,   0,   7, 130,   0, \n     16,   0,  13,   0,   0,   0, \n     26,  48,  32,   4,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  54,   0, \n      0,   8,  66,   0,  16,   0, \n     14,   0,   0,   0,  26,  48, \n     32,   6,   0,   0,   0,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     54,   0,   0,   8, 130,   0, \n     16,   0,  14,   0,   0,   0, \n     26,  48,  32,   6,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  54,   0,   0,   8, \n     34,   0,  16,   0,  15,   0, \n      0,   0,  26,  48,  32,   6, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  54,   0, \n      0,   7,  18,  48,  32,   4, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,  13,   0, \n      0,   0,  54,   0,   0,   8, \n     18,  48,  32,   6,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n     14,   0,   0,   0,  54,   0, \n      0,   8,  18,  48,  32,   6, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     54,   0,   0,   8,  18,  48, \n     32,   6,   0,   0,   0,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     26,   0,  16,   0,  15,   0, \n      0,   0,  54,   0,   0,   7, \n     34,  48,  32,   4,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     54,   0,   0,   8,  34,  48, \n     32,   6,   0,   0,   0,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  54,   0,   0,   8, \n     34,  48,  32,   6,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n     11,   0,   0,   0,  54,   0, \n      0,   8,  34,  48,  32,   6, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,  12,   0,   0,   0, \n     21,   0,   0,   1,  30,   0, \n      0,   7,  66,   0,  16,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  22,   0,   0,   1, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   6,   0,   0,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   6,   0,   0,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   6, 242,   0, \n     16,   0,  16,   0,   0,   0, \n     70,  62,  32,   0,   3,   0, \n      0,   0,   2,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   7,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   8,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   9,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,  10,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,  11,   0,   0,   0, \n     40,   0,   0,   5,  18,   0, \n     16,   0,  17,   0,   0,   0, \n     42,   0,  16,   0,   7,   0, \n      0,   0,  40,   0,   0,   5, \n     34,   0,  16,   0,  17,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  40,   0, \n      0,   5,  66,   0,  16,   0, \n     17,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     40,   0,   0,   5, 130,   0, \n     16,   0,  17,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  33,   0,   0,   7, \n    130,   0,  16,   0,  11,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   6,   0,   0,   0, \n     43,   0,   0,   5, 130,   0, \n     16,   0,  12,   0,   0,   0, \n     26,   0,  16,   0,   6,   0, \n      0,   0,  55,   0,   0,  15, \n    226,   0,  16,   0,  15,   0, \n      0,   0, 166,  10,  16,   0, \n      3,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n    128,   0,   0,   0,   3,   0, \n      0,   0,  32,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,  64,   0,   0,   0, \n      7,   0,   0,   0,  16,   0, \n      0,   0,  54,   0,   0,   6, \n    242,   0,  16,   0,  18,   0, \n      0,   0,  70,  62,  32,   0, \n      3,   0,   0,   0,   1,   0, \n      0,   0,  54,   0,   0,   6, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,  13,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  54,   0,   0,   6, \n     66,   0,  16,   0,  14,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,  14,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,  40,   0,   0,   5, \n     18,   0,  16,   0,  19,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  40,   0, \n      0,   5,  34,   0,  16,   0, \n     19,   0,   0,   0,  58,   0, \n     16,   0,  13,   0,   0,   0, \n     40,   0,   0,   5, 194,   0, \n     16,   0,  19,   0,   0,   0, \n    166,  14,  16,   0,  14,   0, \n      0,   0,  33,   0,   0,   7, \n     18,   0,  16,   0,  20,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     43,   0,   0,   5,  34,   0, \n     16,   0,  20,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  54,   0,   0,   6, \n    242,   0,  16,   0,  21,   0, \n      0,   0,  70,  62,  32,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n     66,   0,  16,   0,  20,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,  20,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  54,   0,   0,   6, \n     18,   0,  16,   0,  22,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,   0,  16,   0,  22,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  40,   0,   0,   5, \n     50,   0,  16,   0,  23,   0, \n      0,   0, 230,  10,  16,   0, \n     20,   0,   0,   0,  40,   0, \n      0,   5, 194,   0,  16,   0, \n     23,   0,   0,   0,   6,   4, \n     16,   0,  22,   0,   0,   0, \n     33,   0,   0,   7,  66,   0, \n     16,   0,  22,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,  43,   0, \n      0,   5, 130,   0,  16,   0, \n     22,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n     54,   0,   0,   5,  18,   0, \n     16,   0,  24,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  48,   0,   0,   1, \n     80,   0,   0,   7,  34,   0, \n     16,   0,  24,   0,   0,   0, \n     10,   0,  16,   0,  24,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   3,   0, \n      4,   3,  26,   0,  16,   0, \n     24,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n     24,   0,   0,   0,  10,   0, \n     16,   0,  24,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   8, \n     34,   0,  16,   0,  24,   0, \n      0,   0,  10, 144, 144,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n     24,   0,   0,   0,   1,   0, \n      0,   7,  34,   0,  16,   0, \n     24,   0,   0,   0,  26,   0, \n     16,   0,  24,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  32,   0,   0,  10, \n    194,   0,  16,   0,  24,   0, \n      0,   0,  86,   5,  16,   0, \n     24,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   1,   0,   0,   0, \n     31,   0,   4,   3,  42,   0, \n     16,   0,  24,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,  25,   0,   0,   0, \n     10,   0,  16,   0,  24,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   7, 242,   0, \n     16,   0,  25,   0,   0,   0, \n     70,  14,  16,   0,  17,   0, \n      0,   0,  70,  14,  16,   0, \n     25,   0,   0,   0,  38,   0, \n      0,   8,   0, 208,   0,   0, \n     50,   0,  16,   0,  25,   0, \n      0,   0,  70,   0,  16,   0, \n     16,   0,   0,   0,  70,   0, \n     16,   0,  25,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,  25,   0,   0,   0, \n     26,   0,  16,   0,  25,   0, \n      0,   0,  10,   0,  16,   0, \n     25,   0,   0,   0,  35,   0, \n      0,   9,  18,   0,  16,   0, \n     25,   0,   0,   0,  42,   0, \n     16,   0,  16,   0,   0,   0, \n     42,   0,  16,   0,  25,   0, \n      0,   0,  10,   0,  16,   0, \n     25,   0,   0,   0,  35,   0, \n      0,   9,  18,   0,  16,   0, \n     25,   0,   0,   0,  58,   0, \n     16,   0,  16,   0,   0,   0, \n     58,   0,  16,   0,  25,   0, \n      0,   0,  10,   0,  16,   0, \n     25,   0,   0,   0,  33,   0, \n      0,   7,  34,   0,  16,   0, \n     25,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,  25,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,  25,   0, \n      0,   0,  58,   0,  16,   0, \n     11,   0,   0,   0,  26,   0, \n     16,   0,  25,   0,   0,   0, \n     34,   0,   0,   7,  66,   0, \n     16,   0,  25,   0,   0,   0, \n     10,   0,  16,   0,  25,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  43,   0, \n      0,   5,  18,   0,  16,   0, \n     25,   0,   0,   0,  10,   0, \n     16,   0,  25,   0,   0,   0, \n     56,   0,   0,   7,  18,   0, \n     16,   0,  25,   0,   0,   0, \n     10,   0,  16,   0,  25,   0, \n      0,   0,   1,  64,   0,   0, \n    253, 255, 125,  66,  14,   0, \n      0,   7,  18,   0,  16,   0, \n     25,   0,   0,   0,  10,   0, \n     16,   0,  25,   0,   0,   0, \n     58,   0,  16,   0,  12,   0, \n      0,   0,  28,   0,   0,   5, \n     18,   0,  16,   0,  25,   0, \n      0,   0,  10,   0,  16,   0, \n     25,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n     25,   0,   0,   0,  26,   0, \n     16,   0,  15,   0,   0,   0, \n     10,   0,  16,   0,  25,   0, \n      0,   0,  55,   0,   0,  10, \n     18,   0,  16,   0,  25,   0, \n      0,   0,  42,   0,  16,   0, \n     25,   0,   0,   0,  58, 144, \n    144,   0,  10,   0,  16,   0, \n     25,   0,   0,   0,  42,   0, \n     16,   0,  15,   0,   0,   0, \n     55,   0,   0,   9,  18,   0, \n     16,   0,  25,   0,   0,   0, \n     26,   0,  16,   0,  25,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,  25,   0,   0,   0, \n     18,   0,   0,   1,  32,   0, \n      0,   7,  34,   0,  16,   0, \n     25,   0,   0,   0,  26,   0, \n     16,   0,  24,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,  25,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,  26,   0, \n      0,   0,  10,   0,  16,   0, \n     24,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n    242,   0,  16,   0,  26,   0, \n      0,   0,  70,  14,  16,   0, \n     19,   0,   0,   0,  70,  14, \n     16,   0,  26,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0,  98,   0,  16,   0, \n     25,   0,   0,   0,   6,   1, \n     16,   0,  18,   0,   0,   0, \n      6,   1,  16,   0,  26,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,  25,   0, \n      0,   0,  42,   0,  16,   0, \n     25,   0,   0,   0,  26,   0, \n     16,   0,  25,   0,   0,   0, \n     35,   0,   0,   9,  34,   0, \n     16,   0,  25,   0,   0,   0, \n     42,   0,  16,   0,  18,   0, \n      0,   0,  42,   0,  16,   0, \n     26,   0,   0,   0,  26,   0, \n     16,   0,  25,   0,   0,   0, \n     35,   0,   0,   9,  34,   0, \n     16,   0,  25,   0,   0,   0, \n     58,   0,  16,   0,  18,   0, \n      0,   0,  58,   0,  16,   0, \n     26,   0,   0,   0,  26,   0, \n     16,   0,  25,   0,   0,   0, \n     33,   0,   0,   7,  66,   0, \n     16,   0,  25,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n     25,   0,   0,   0,  60,   0, \n      0,   7,  66,   0,  16,   0, \n     25,   0,   0,   0,  10,   0, \n     16,   0,  20,   0,   0,   0, \n     42,   0,  16,   0,  25,   0, \n      0,   0,  34,   0,   0,   7, \n    130,   0,  16,   0,  25,   0, \n      0,   0,  26,   0,  16,   0, \n     25,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     43,   0,   0,   5,  34,   0, \n     16,   0,  25,   0,   0,   0, \n     26,   0,  16,   0,  25,   0, \n      0,   0,  56,   0,   0,   7, \n     34,   0,  16,   0,  25,   0, \n      0,   0,  26,   0,  16,   0, \n     25,   0,   0,   0,   1,  64, \n      0,   0, 253, 255, 125,  66, \n     14,   0,   0,   7,  34,   0, \n     16,   0,  25,   0,   0,   0, \n     26,   0,  16,   0,  25,   0, \n      0,   0,  26,   0,  16,   0, \n     20,   0,   0,   0,  28,   0, \n      0,   5,  34,   0,  16,   0, \n     25,   0,   0,   0,  26,   0, \n     16,   0,  25,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,  25,   0,   0,   0, \n     26,   0,  16,   0,  15,   0, \n      0,   0,  26,   0,  16,   0, \n     25,   0,   0,   0,  55,   0, \n      0,  10,  34,   0,  16,   0, \n     25,   0,   0,   0,  58,   0, \n     16,   0,  25,   0,   0,   0, \n     58, 144, 144,   0,  26,   0, \n     16,   0,  25,   0,   0,   0, \n     42,   0,  16,   0,  15,   0, \n      0,   0,  55,   0,   0,   9, \n     18,   0,  16,   0,  25,   0, \n      0,   0,  42,   0,  16,   0, \n     25,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,  25,   0, \n      0,   0,  18,   0,   0,   1, \n    167,   0,   0,   9, 242,   0, \n     16,   0,  26,   0,   0,   0, \n     10,   0,  16,   0,  24,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   7, 242,   0, \n     16,   0,  26,   0,   0,   0, \n     70,  14,  16,   0,  23,   0, \n      0,   0,  70,  14,  16,   0, \n     26,   0,   0,   0,  38,   0, \n      0,   8,   0, 208,   0,   0, \n     98,   0,  16,   0,  25,   0, \n      0,   0,   6,   1,  16,   0, \n     21,   0,   0,   0,   6,   1, \n     16,   0,  26,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,  25,   0,   0,   0, \n     42,   0,  16,   0,  25,   0, \n      0,   0,  26,   0,  16,   0, \n     25,   0,   0,   0,  35,   0, \n      0,   9,  34,   0,  16,   0, \n     25,   0,   0,   0,  42,   0, \n     16,   0,  21,   0,   0,   0, \n     42,   0,  16,   0,  26,   0, \n      0,   0,  26,   0,  16,   0, \n     25,   0,   0,   0,  35,   0, \n      0,   9,  34,   0,  16,   0, \n     25,   0,   0,   0,  58,   0, \n     16,   0,  21,   0,   0,   0, \n     58,   0,  16,   0,  26,   0, \n      0,   0,  26,   0,  16,   0, \n     25,   0,   0,   0,  33,   0, \n      0,   7,  66,   0,  16,   0, \n     25,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,  25,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,  25,   0, \n      0,   0,  42,   0,  16,   0, \n     22,   0,   0,   0,  42,   0, \n     16,   0,  25,   0,   0,   0, \n     34,   0,   0,   7, 130,   0, \n     16,   0,  25,   0,   0,   0, \n     26,   0,  16,   0,  25,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,  43,   0, \n      0,   5,  34,   0,  16,   0, \n     25,   0,   0,   0,  26,   0, \n     16,   0,  25,   0,   0,   0, \n     56,   0,   0,   7,  34,   0, \n     16,   0,  25,   0,   0,   0, \n     26,   0,  16,   0,  25,   0, \n      0,   0,   1,  64,   0,   0, \n    253, 255, 125,  66,  14,   0, \n      0,   7,  34,   0,  16,   0, \n     25,   0,   0,   0,  26,   0, \n     16,   0,  25,   0,   0,   0, \n     58,   0,  16,   0,  22,   0, \n      0,   0,  28,   0,   0,   5, \n     34,   0,  16,   0,  25,   0, \n      0,   0,  26,   0,  16,   0, \n     25,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n     25,   0,   0,   0,  26,   0, \n     16,   0,  15,   0,   0,   0, \n     26,   0,  16,   0,  25,   0, \n      0,   0,  55,   0,   0,  10, \n     34,   0,  16,   0,  25,   0, \n      0,   0,  58,   0,  16,   0, \n     25,   0,   0,   0,  58, 144, \n    144,   0,  26,   0,  16,   0, \n     25,   0,   0,   0,  42,   0, \n     16,   0,  15,   0,   0,   0, \n     55,   0,   0,   9,  18,   0, \n     16,   0,  25,   0,   0,   0, \n     42,   0,  16,   0,  25,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,  25,   0,   0,   0, \n     21,   0,   0,   1,  21,   0, \n      0,   1,  30,   0,   0,   7, \n     18,   0,  16,   0,  25,   0, \n      0,   0,  58,   0,  16,   0, \n     15,   0,   0,   0,  10,   0, \n     16,   0,  25,   0,   0,   0, \n     30,   0,   0,  10,  34,   0, \n     16,   0,  25,   0,   0,   0, \n      1,  64,   0,   0,  64,   0, \n      0,   0,  10, 144, 208, 128, \n     65,   0,   0,   0,  64,   0, \n      0,   0,  10,   0,  16,   0, \n     25,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n     24,   0,   0,   0,  26,   0, \n     16,   0,  24,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  54,   0,   0,   7, \n     18,   0,  16,   0,  26,   0, \n      0,   0,  10,  48,  32,   4, \n      0,   0,   0,   0,  26,   0, \n     16,   0,  24,   0,   0,   0, \n     54,   0,   0,   8,  34,   0, \n     16,   0,  26,   0,   0,   0, \n     10,  48,  32,   6,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,  24,   0, \n      0,   0,  54,   0,   0,   8, \n     66,   0,  16,   0,  26,   0, \n      0,   0,  10,  48,  32,   6, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n     24,   0,   0,   0,  54,   0, \n      0,   7,  18,   0,  16,   0, \n     27,   0,   0,   0,  26,  48, \n     32,   4,   0,   0,   0,   0, \n     26,   0,  16,   0,  24,   0, \n      0,   0,  54,   0,   0,   8, \n     34,   0,  16,   0,  27,   0, \n      0,   0,  26,  48,  32,   6, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n     24,   0,   0,   0,  54,   0, \n      0,   8,  66,   0,  16,   0, \n     27,   0,   0,   0,  26,  48, \n     32,   6,   0,   0,   0,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,  24,   0,   0,   0, \n     38,   0,   0,  10,   0, 208, \n      0,   0, 210,   0,  16,   0, \n     25,   0,   0,   0,   6,   9, \n     16,   0,  27,   0,   0,   0, \n      6, 144, 208,   0,  64,   0, \n      0,   0,  10,   0,  16,   0, \n     25,   0,   0,   0,  35,   0, \n      0,   9, 114,   0,  16,   0, \n     25,   0,   0,   0,  86,   5, \n     16,   0,  25,   0,   0,   0, \n     70,   2,  16,   0,  26,   0, \n      0,   0, 134,   3,  16,   0, \n     25,   0,   0,   0,  30,   0, \n      0,  10, 114,   0,  16,   0, \n     25,   0,   0,   0,  70,   2, \n     16,   0,  25,   0,   0,   0, \n      2,  64,   0,   0,  32,   0, \n      0,   0,  32,   0,   0,   0, \n     32,   0,   0,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n    178,   0,  16,   0,  25,   0, \n      0,   0,  70,   8,  16,   0, \n     25,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,  26,   0,   0,   0, \n     10,   0,  16,   0,  24,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     79,   0,   0,   7, 114,   0, \n     16,   0,  27,   0,   0,   0, \n     70,   3,  16,   0,  25,   0, \n      0,   0,  70,   2,  16,   0, \n     26,   0,   0,   0,  54,   0, \n      0,   5,  66,   0,  16,   0, \n     25,   0,   0,   0,  10,   0, \n     16,   0,  26,   0,   0,   0, \n     55,   0,   0,   9, 146,   0, \n     16,   0,  27,   0,   0,   0, \n      6,   0,  16,   0,  27,   0, \n      0,   0, 166,   2,  16,   0, \n     25,   0,   0,   0,   6,   8, \n     16,   0,  25,   0,   0,   0, \n     54,   0,   0,   5,  82,   0, \n     16,   0,  25,   0,   0,   0, \n     86,   6,  16,   0,  26,   0, \n      0,   0,  55,   0,   0,   9, \n    242,   0,  16,   0,  25,   0, \n      0,   0,  86,  10,  16,   0, \n     27,   0,   0,   0,  70,  14, \n     16,   0,  25,   0,   0,   0, \n     22,  11,  16,   0,  25,   0, \n      0,   0,  79,   0,   0,   7, \n     34,   0,  16,   0,  24,   0, \n      0,   0,   1,  64,   0,   0, \n    255,   0,   0,   0,  58,   0, \n     16,   0,  26,   0,   0,   0, \n     54,   0,   0,   5,  18,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,  26,   0, \n      0,   0,  55,   0,   0,   9, \n    146,   0,  16,   0,  26,   0, \n      0,   0,  86,   5,  16,   0, \n     24,   0,   0,   0,  86,   1, \n     16,   0,  14,   0,   0,   0, \n      6,   4,  16,   0,  14,   0, \n      0,   0,  40,   0,   0,   5, \n     18,   0,  16,   0,  28,   0, \n      0,   0,  58,   0,  16,   0, \n     27,   0,   0,   0,  40,   0, \n      0,   5,  98,   0,  16,   0, \n     28,   0,   0,   0,  86,   7, \n     16,   0,  25,   0,   0,   0, \n     40,   0,   0,   5, 130,   0, \n     16,   0,  28,   0,   0,   0, \n     10,   0,  16,   0,  26,   0, \n      0,   0,  54,   0,   0,   5, \n     18,   0,  16,   0,  26,   0, \n      0,   0,  10,   0,  16,   0, \n     27,   0,   0,   0,  54,   0, \n      0,   5,  98,   0,  16,   0, \n     26,   0,   0,   0,   6,   2, \n     16,   0,  25,   0,   0,   0, \n     30,   0,   0,   7, 242,   0, \n     16,   0,  25,   0,   0,   0, \n     70,  14,  16,   0,  28,   0, \n      0,   0,  70,  14,  16,   0, \n     26,   0,   0,   0,  38,   0, \n      0,   8,   0, 208,   0,   0, \n     50,   0,  16,   0,  25,   0, \n      0,   0,  70,   0,  16,   0, \n     25,   0,   0,   0,  70,   0, \n     16,   0,  25,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,  14,   0,   0,   0, \n     26,   0,  16,   0,  25,   0, \n      0,   0,  10,   0,  16,   0, \n     25,   0,   0,   0,  35,   0, \n      0,   9,  18,   0,  16,   0, \n     14,   0,   0,   0,  42,   0, \n     16,   0,  25,   0,   0,   0, \n     42,   0,  16,   0,  25,   0, \n      0,   0,  10,   0,  16,   0, \n     14,   0,   0,   0,  86,   0, \n      0,   5,  18,   0,  16,   0, \n     14,   0,   0,   0,  10,   0, \n     16,   0,  14,   0,   0,   0, \n     86,   0,   0,   5,  34,   0, \n     16,   0,  24,   0,   0,   0, \n     58,   0,  16,   0,  25,   0, \n      0,   0,  56,   0,   0,   7, \n     34,   0,  16,   0,  24,   0, \n      0,   0,  26,   0,  16,   0, \n     24,   0,   0,   0,  26,   0, \n     16,   0,  24,   0,   0,   0, \n     50,   0,   0,  10,  18,   0, \n     16,   0,  14,   0,   0,   0, \n     26,   0,  16,   0,  24,   0, \n      0,   0,  42, 128,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n     14,   0,   0,   0,  28,   0, \n      0,   5,  18,   0,  16,   0, \n     14,   0,   0,   0,  10,   0, \n     16,   0,  14,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,  24,   0,   0,   0, \n     10,  48,  32,   0,   6,   0, \n      0,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,  25,   0,   0,   0, \n     10,   0,  16,   0,  14,   0, \n      0,   0,  26,   0,  16,   0, \n     24,   0,   0,   0,  55,   0, \n      0,   9,  34,   0,  16,   0, \n     24,   0,   0,   0,  42,   0, \n     16,   0,  24,   0,   0,   0, \n     10,   0,  16,   0,  25,   0, \n      0,   0,  26,   0,  16,   0, \n     24,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      6,   0,   0,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n     24,   0,   0,   0,  59,   0, \n      0,   5,  98,   0,  16,   0, \n     24,   0,   0,   0, 166,  11, \n     16,   0,  24,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,  24,   0,   0,   0, \n     58,   0,  16,   0,  24,   0, \n      0,   0,  26,   0,  16,   0, \n     24,   0,   0,   0,  54,   0, \n      0,   6,  18,   0,  16,   0, \n     25,   0,   0,   0,  10,  48, \n     32,   0,   6,   0,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n     25,   0,   0,   0,  10,   0, \n     16,   0,  14,   0,   0,   0, \n     10,   0,  16,   0,  25,   0, \n      0,   0,  55,   0,   0,   9, \n    130,   0,  16,   0,  24,   0, \n      0,   0,  58,   0,  16,   0, \n     24,   0,   0,   0,  26,   0, \n     16,   0,  25,   0,   0,   0, \n     10,   0,  16,   0,  25,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   6,   0, \n      0,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,  24,   0, \n      0,   0,   1,   0,   0,   7, \n     34,   0,  16,   0,  24,   0, \n      0,   0,  42,   0,  16,   0, \n     24,   0,   0,   0,  26,   0, \n     16,   0,  24,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,  24,   0,   0,   0, \n     10,  48,  32,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,  14,   0,   0,   0, \n     10,   0,  16,   0,  14,   0, \n      0,   0,  42,   0,  16,   0, \n     24,   0,   0,   0,  55,   0, \n      0,   9,  18,   0,  16,   0, \n     14,   0,   0,   0,  26,   0, \n     16,   0,  24,   0,   0,   0, \n     10,   0,  16,   0,  14,   0, \n      0,   0,  42,   0,  16,   0, \n     24,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n     14,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n     24,   0,   0,   0,  10,   0, \n     16,   0,  24,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  22,   0,   0,   1, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     10,  48,  32,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  48,  32,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n     79,   0,   0,   7,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,  84,   0, \n      0,   7,  66,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  10,  48,  32,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  55,   0,   0,   9, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  10,   0, \n     16,   0,  15,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  10,  48,  32,   0, \n      6,   0,   0,   0,   1,   0, \n      0,   0,  54,   0,   0,   6, \n     34,   0,  16,   0,   4,   0, \n      0,   0,  10,  48,  32,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   0,  79,   0,   0,   7, \n     66,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n     84,   0,   0,   7,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      4,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  66,   0,  16,   0, \n      3,   0,   0,   0,  10,  48, \n     32,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,  55,   0, \n      0,   9,  66,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   5,   0,   0,   0, \n     10,   0,  16,   0,  15,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6,  66,   0,  16,   0, \n      3,   0,   0,   0,  10,  48, \n     32,   0,   6,   0,   0,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n      4,   0,   0,   0,  10,  48, \n     32,   0,   2,   0,   0,   0, \n      2,   0,   0,   0,  79,   0, \n      0,   7,  66,   0,  16,   0, \n      5,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,  84,   0,   0,   7, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   2,   0,   0,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     10,  48,  32,   0,   1,   0, \n      0,   0,   2,   0,   0,   0, \n     55,   0,   0,   9,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  10,   0,  16,   0, \n     15,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   1,   0,   0,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,  15,   0,   0,   0, \n     10,   0,  16,   0,  15,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,  54,   0,   0,   6, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,  48,  32,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,  48,  32,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  48,  32,   0,   2,   0, \n      0,   0,   2,   0,   0,   0, \n     30,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8,  18, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,  48,  32,   0, \n      1,   0,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  48,  32,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,  48,  32,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  32,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  32,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     79,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8,  18, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0, 168,   0,   0,   8, \n     18, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  32,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     79,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8,  18, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0, 168,   0,   0,   8, \n     18, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  32,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      2,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     79,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8,  18, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0, 168,   0,   0,   8, \n     18, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  32,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  58,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     79,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8,  18, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0, 168,   0,   0,   8, \n     18, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  32,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n    190,  24,   0,   1,  79,   0, \n      0,   9,  98,   0,  16,   0, \n      0,   0,   0,   0,   6,  64, \n      2,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     79,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8,  18, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0, 168,   0,   0,   8, \n     18, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  32,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     24,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     79,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  31,   0, \n      4,   3,  26,   0,  16,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8,  18, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  24,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0, 168,   0,   0,   8, \n     18, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  32,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  21,   0, \n      0,   1, 167,   0,   0,   9, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n      6, 112,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   8, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  79,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   8, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  24,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   8, 130,   0,  16,   0, \n      2,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     58, 128,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     18,   0,   0,   1, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  70, 126,  16,   0, \n      1,   0,   0,   0,  21,   0, \n      0,   1, 168,   0,   0,   9, \n    242, 224,  17,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70,  14,  16,   0,   2,   0, \n      0,   0,  21,   0,   0,   1, \n     62,   0,   0,   1\n};\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/Shaders/Compiled/BC7Encode_TryMode137CS.inc",
    "content": "#if 0\n//\n// Generated by Microsoft (R) D3D Shader Disassembler\n//\n//\n// Input signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Input\n//\n// Output signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Output\ncs_4_0\ndcl_globalFlags refactoringAllowed\ndcl_immediateConstantBuffer { { 0x0000cccc, 15, 0, 0},\n                              { 0x00008888, 15, 0, 0},\n                              { 0x0000eeee, 15, 0, 0},\n                              { 0x0000ecc8, 15, 0, 1},\n                              { 0x0000c880, 15, 0, 1},\n                              { 0x0000feec, 15, 0, 1},\n                              { 0x0000fec8, 15, 0, 1},\n                              { 0x0000ec80, 15, 0, 2},\n                              { 0x0000c800, 15, 0, 2},\n                              { 0x0000ffec, 15, 0, 2},\n                              { 0x0000fe80, 15, 0, 2},\n                              { 0x0000e800, 15, 0, 2},\n                              { 0x0000ffe8, 15, 0, 3},\n                              { 0x0000ff00, 15, 0, 3},\n                              { 0x0000fff0, 15, 0, 3},\n                              { 0x0000f000, 15, 0, 3},\n                              { 0x0000f710, 15, 0, 4},\n                              { 142, 2, 0, 4},\n                              { 0x00007100, 8, 0, 4},\n                              { 2254, 2, 0, 4},\n                              { 140, 2, 0, 5},\n                              { 0x00007310, 8, 0, 5},\n                              { 0x00003100, 8, 0, 5},\n                              { 0x00008cce, 15, 0, 5},\n                              { 2188, 2, 0, 6},\n                              { 0x00003110, 8, 0, 6},\n                              { 0x00006666, 2, 0, 6},\n                              { 0x0000366c, 2, 0, 6},\n                              { 6120, 8, 0, 6},\n                              { 4080, 8, 0, 7},\n                              { 0x0000718e, 2, 0, 7},\n                              { 0x0000399c, 2, 0, 7},\n                              { 0x0000aaaa, 15, 0, 7},\n                              { 0x0000f0f0, 15, 0, 8},\n                              { 0x00005a5a, 6, 0, 8},\n                              { 0x000033cc, 8, 0, 8},\n                              { 0x00003c3c, 2, 0, 8},\n                              { 0x000055aa, 8, 0, 9},\n                              { 0x00009696, 15, 0, 9},\n                              { 0x0000a55a, 15, 0, 9},\n                              { 0x000073ce, 2, 0, 9},\n                              { 5064, 8, 0, 10},\n                              { 0x0000324c, 2, 0, 10},\n                              { 0x00003bdc, 2, 0, 10},\n                              { 0x00006996, 2, 0, 10},\n                              { 0x0000c33c, 15, 0, 10},\n                              { 0x00009966, 15, 0, 11},\n                              { 1632, 6, 0, 11},\n                              { 626, 6, 0, 11},\n                              { 1252, 2, 0, 11},\n                              { 0x00004e40, 6, 0, 12},\n                              { 0x00002720, 8, 0, 12},\n                              { 0x0000c936, 15, 0, 12},\n                              { 0x0000936c, 15, 0, 12},\n                              { 0x000039c6, 2, 0, 13},\n                              { 0x0000639c, 2, 0, 13},\n                              { 0x00009336, 15, 0, 13},\n                              { 0x00009cc6, 15, 0, 13},\n                              { 0x0000817e, 15, 0, 14},\n                              { 0x0000e718, 15, 0, 14},\n                              { 0x0000ccf0, 15, 0, 14},\n                              { 4044, 2, 0, 14},\n                              { 0x00007744, 2, 0, 15},\n                              { 0x0000ee22, 15, 0, 15},\n                              { 0, 3, 15, 0},\n                              { 4, 3, 8, 0},\n                              { 9, 15, 8, 0},\n                              { 13, 15, 3, 0},\n                              { 17, 8, 15, 0},\n                              { 21, 3, 15, 1},\n                              { 26, 15, 3, 1},\n                              { 30, 15, 8, 1},\n                              { 34, 8, 15, 1},\n                              { 38, 8, 15, 1},\n                              { 43, 6, 15, 1},\n                              { 47, 6, 15, 1},\n                              { 51, 6, 15, 1},\n                              { 55, 5, 15, 1},\n                              { 60, 3, 15, 2},\n                              { 64, 3, 8, 2},\n                              { 0, 3, 15, 2},\n                              { 9, 3, 8, 2},\n                              { 18, 8, 15, 2},\n                              { 27, 15, 3, 2},\n                              { 37, 3, 15, 2},\n                              { 46, 3, 8, 2},\n                              { 55, 6, 15, 2},\n                              { 64, 10, 8, 3},\n                              { 0, 5, 3, 3},\n                              { 0, 8, 15, 3},\n                              { 0, 8, 6, 3},\n                              { 0, 6, 10, 3},\n                              { 0, 8, 15, 3},\n                              { 0, 5, 15, 3},\n                              { 0, 15, 10, 3},\n                              { 0, 15, 8, 3},\n                              { 0, 8, 15, 3},\n                              { 21, 15, 3, 4},\n                              { 43, 3, 15, 4},\n                              { 64, 5, 10, 4},\n                              { 0, 6, 10, 4},\n                              { 0, 10, 8, 4},\n                              { 0, 8, 9, 4},\n                              { 0, 15, 10, 4},\n                              { 0, 15, 6, 4},\n                              { 0, 3, 15, 4},\n                              { 0, 15, 8, 5},\n                              { 0, 5, 15, 5},\n                              { 0, 15, 3, 5},\n                              { 0, 15, 6, 5},\n                              { 0, 15, 6, 5},\n                              { 0, 15, 8, 5},\n                              { 0, 3, 15, 5},\n                              { 0, 15, 3, 5},\n                              { 0, 5, 15, 5},\n                              { 0, 5, 15, 6},\n                              { 0, 5, 15, 6},\n                              { 0, 8, 15, 6},\n                              { 0, 5, 15, 6},\n                              { 0, 10, 15, 6},\n                              { 0, 5, 15, 6},\n                              { 0, 10, 15, 6},\n                              { 0, 8, 15, 6},\n                              { 0, 13, 15, 6},\n                              { 0, 15, 3, 7},\n                              { 0, 12, 15, 7},\n                              { 0, 3, 15, 7},\n                              { 0, 3, 8, 7},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 1},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 2},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3},\n                              { 0, 0, 0, 3} }\ndcl_constantbuffer CB0[2], immediateIndexed\ndcl_resource_texture2d (float,float,float,float) t0\ndcl_resource_structured t1, 16\ndcl_uav_structured u0, 16\ndcl_input vThreadIDInGroupFlattened\ndcl_input vThreadGroupID.x\ndcl_temps 28\ndcl_indexableTemp x0[8], 4\ndcl_indexableTemp x1[2], 4\ndcl_indexableTemp x2[2], 4\ndcl_indexableTemp x3[2], 4\ndcl_tgsm_structured g0, 100, 64\ndcl_thread_group 64, 1, 1\niadd r0.x, vThreadGroupID.x, cb0[1].x\nult r1.xyzw, vThreadIDInGroupFlattened.xxxx, l(16, 32, 8, 4)\nif_nz r1.x\n  udiv r0.y, null, r0.x, cb0[0].y\n  imad r0.z, -r0.y, cb0[0].y, r0.x\n  ishl r0.z, r0.z, l(2)\n  ishl r0.y, r0.y, l(2)\n  and r0.w, vThreadIDInGroupFlattened.x, l(3)\n  iadd r2.x, r0.w, r0.z\n  ushr r0.z, vThreadIDInGroupFlattened.x, l(2)\n  iadd r2.y, r0.z, r0.y\n  mov r2.zw, l(0,0,0,0)\n  ld r2.xyzw, r2.xyzw, t0.xyzw\n  mul r2.xyzw, r2.xyzw, l(255.000000, 255.000000, 255.000000, 255.000000)\n  ftou r2.xyzw, r2.xyzw\n  umin r2.xyzw, r2.xyzw, l(255, 255, 255, 255)\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(0), r2.xyzw\nendif \nsync_g_t\nmov x0[0].x, l(-1)\nmov x0[1].x, l(-1)\nmov x0[2].x, l(-1)\nmov x0[3].x, l(-1)\nmov x0[0].y, l(0)\nmov x0[1].y, l(0)\nmov x0[2].y, l(0)\nmov x0[3].y, l(0)\nmov x0[4].x, l(-1)\nmov x0[5].x, l(-1)\nmov x0[6].x, l(-1)\nmov x0[7].x, l(-1)\nmov x0[4].y, l(0)\nmov x0[5].y, l(0)\nmov x0[6].y, l(0)\nmov x0[7].y, l(0)\nmov r0.y, l(0)\nloop \n  uge r0.z, r0.y, l(16)\n  breakc_nz r0.z\n  ld_structured r2.xyzw, r0.y, l(0), g0.xyzw\n  mov r0.z, vThreadIDInGroupFlattened.x\n  ushr r0.z, icb[r0.z + 0].x, r0.y\n  and r0.z, r0.z, l(1)\n  ieq r0.z, r0.z, l(1)\n  if_nz r0.z\n    mov r3.x, x0[4].x\n    mov r3.y, x0[5].x\n    mov r3.z, x0[6].x\n    mov r3.w, x0[7].x\n    umin r3.xyzw, r2.xyzw, r3.xyzw\n    mov x0[4].x, r3.x\n    mov x0[5].x, r3.y\n    mov x0[6].x, r3.z\n    mov x0[7].x, r3.w\n    mov r3.x, x0[4].y\n    mov r3.y, x0[5].y\n    mov r3.z, x0[6].y\n    mov r3.w, x0[7].y\n    umax r3.xyzw, r2.xyzw, r3.xyzw\n    mov x0[4].y, r3.x\n    mov x0[5].y, r3.y\n    mov x0[6].y, r3.z\n    mov x0[7].y, r3.w\n  else \n    mov r3.x, x0[0].x\n    mov r3.y, x0[1].x\n    mov r3.z, x0[2].x\n    mov r3.w, x0[3].x\n    umin r3.xyzw, r2.xyzw, r3.xyzw\n    mov x0[0].x, r3.x\n    mov x0[1].x, r3.y\n    mov x0[2].x, r3.z\n    mov x0[3].x, r3.w\n    mov r3.x, x0[0].y\n    mov r3.y, x0[1].y\n    mov r3.z, x0[2].y\n    mov r3.w, x0[3].y\n    umax r2.xyzw, r2.xyzw, r3.xyzw\n    mov x0[0].y, r2.x\n    mov x0[1].y, r2.y\n    mov x0[2].y, r2.z\n    mov x0[3].y, r2.w\n  endif \n  iadd r0.y, r0.y, l(1)\nendloop \nmov r2.x, x0[0].x\nmov r2.y, x0[1].x\nmov r2.z, x0[2].x\nmov r2.w, x0[3].x\nmov r3.x, x0[0].y\nmov r3.y, x0[1].y\nmov r3.z, x0[2].y\nmov r3.w, x0[3].y\nmov r4.x, x0[4].x\nmov r4.y, x0[5].x\nmov r4.z, x0[6].x\nmov r4.w, x0[7].x\nmov r5.x, x0[4].y\nmov r5.y, x0[5].y\nmov r5.z, x0[6].y\nmov r5.w, x0[7].y\nieq r0.y, cb0[0].w, l(1)\nmovc r0.z, r0.y, l(2), l(4)\nmov x1[0].x, l(0)\nmov x1[1].x, l(0)\nmov x2[0].x, l(-1)\nmov x2[1].x, l(-1)\nimad r6.xyz, r2.xyzx, l(0x00007f7f, 0x00007f7f, 0x00007f7f, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\nushr r6.xyz, r6.xyzx, l(16)\nand r6.xyz, r6.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\nimad r7.xyz, r3.xyzx, l(0x00007f7f, 0x00007f7f, 0x00007f7f, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\nushr r7.xyz, r7.xyzx, l(16)\nand r7.xyz, r7.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\nand r8.xyz, r2.xyzx, l(-2, -2, -2, 0)\nand r9.xyz, r3.xyzx, l(-2, -2, -2, 0)\nimad r10.xyzw, r2.xyzw, l(0x00003f3f, 0x00003f3f, 0x00003f3f, 0x00003f3f), l(0x00008000, 0x00008000, 0x00008000, 0x00008000)\nushr r10.xyzw, r10.xyzw, l(16)\nand r10.xyzw, r10.xyzw, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0x0000fffe)\nimad r11.xyzw, r3.xyzw, l(0x00003f3f, 0x00003f3f, 0x00003f3f, 0x00003f3f), l(0x00008000, 0x00008000, 0x00008000, 0x00008000)\nushr r11.xyzw, r11.xyzw, l(16)\nand r11.xyzw, r11.xyzw, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0x0000fffe)\nimad r12.xyz, r4.xyzx, l(0x00007f7f, 0x00007f7f, 0x00007f7f, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\nushr r12.xyz, r12.xyzx, l(16)\nand r12.xyz, r12.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\nimad r13.xyz, r5.xyzx, l(0x00007f7f, 0x00007f7f, 0x00007f7f, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\nushr r13.xyz, r13.xyzx, l(16)\nand r13.xyz, r13.xyzx, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0)\nand r14.xyz, r4.xyzx, l(-2, -2, -2, 0)\nand r15.xyz, r5.xyzx, l(-2, -2, -2, 0)\nimad r16.xyzw, r4.xyzw, l(0x00003f3f, 0x00003f3f, 0x00003f3f, 0x00003f3f), l(0x00008000, 0x00008000, 0x00008000, 0x00008000)\nushr r16.xyzw, r16.xyzw, l(16)\nand r16.xyzw, r16.xyzw, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0x0000fffe)\nimad r17.xyzw, r5.xyzw, l(0x00003f3f, 0x00003f3f, 0x00003f3f, 0x00003f3f), l(0x00008000, 0x00008000, 0x00008000, 0x00008000)\nushr r17.xyzw, r17.xyzw, l(16)\nand r17.xyzw, r17.xyzw, l(0x0000fffe, 0x0000fffe, 0x0000fffe, 0x0000fffe)\nmov r0.w, cb0[0].w\nmov r18.x, l(0)\nloop \n  uge r6.w, r18.x, r0.z\n  breakc_nz r6.w\n  mov x0[0].x, r2.x\n  mov x0[1].x, r2.y\n  mov x0[2].x, r2.z\n  mov x0[3].x, r2.w\n  mov x0[0].y, r3.x\n  mov x0[1].y, r3.y\n  mov x0[2].y, r3.z\n  mov x0[3].y, r3.w\n  mov x0[4].x, r4.x\n  mov x0[5].x, r4.y\n  mov x0[6].x, r4.z\n  mov x0[7].x, r4.w\n  mov x0[4].y, r5.x\n  mov x0[5].y, r5.y\n  mov x0[6].y, r5.z\n  mov x0[7].y, r5.w\n  ieq r6.w, r0.w, l(1)\n  if_nz r6.w\n    or r19.xyz, r6.xyzx, r18.xxxx\n    ishl r19.xyz, r19.xyzx, l(1)\n    ushr r20.xyz, r19.xyzx, l(7)\n    or r19.xyz, r19.xyzx, r20.xyzx\n    or r20.xyz, r7.xyzx, r18.xxxx\n    ishl r20.xyz, r20.xyzx, l(1)\n    ushr r21.xyz, r20.xyzx, l(7)\n    or r20.xyz, r20.xyzx, r21.xyzx\n    mov x0[0].x, r19.x\n    mov x0[1].x, r19.y\n    mov x0[2].x, r19.z\n    mov x0[3].x, l(255)\n    mov x0[0].y, r20.x\n    mov x0[1].y, r20.y\n    mov x0[2].y, r20.z\n    mov x0[3].y, l(255)\n    or r19.xyz, r12.xyzx, r18.xxxx\n    ishl r19.xyz, r19.xyzx, l(1)\n    ushr r20.xyz, r19.xyzx, l(7)\n    or r19.xyz, r19.xyzx, r20.xyzx\n    or r20.xyz, r13.xyzx, r18.xxxx\n    ishl r20.xyz, r20.xyzx, l(1)\n    ushr r21.xyz, r20.xyzx, l(7)\n    or r20.xyz, r20.xyzx, r21.xyzx\n    mov x0[4].x, r19.x\n    mov x0[5].x, r19.y\n    mov x0[6].x, r19.z\n    mov x0[7].x, l(255)\n    mov x0[4].y, r20.x\n    mov x0[5].y, r20.y\n    mov x0[6].y, r20.z\n    mov x0[7].y, l(255)\n  else \n    ieq r6.w, r0.w, l(3)\n    if_nz r6.w\n      ushr r18.y, r18.x, l(1)\n      and r18.zw, r18.xxxy, l(0, 0, 1, 1)\n      iadd r19.xyz, r8.xyzx, r18.zzzz\n      iadd r20.xyz, r9.xyzx, r18.wwww\n      mov x0[0].x, r19.x\n      mov x0[1].x, r19.y\n      mov x0[2].x, r19.z\n      mov x0[3].x, l(255)\n      mov x0[0].y, r20.x\n      mov x0[1].y, r20.y\n      mov x0[2].y, r20.z\n      mov x0[3].y, l(255)\n    else \n      ieq r7.w, r0.w, l(7)\n      if_nz r7.w\n        ushr r18.y, r18.x, l(1)\n        and r18.zw, r18.xxxy, l(0, 0, 1, 1)\n        iadd r19.xyzw, r10.xyzw, r18.zzzz\n        ishl r19.xyzw, r19.xyzw, l(2)\n        ushr r20.xyzw, r19.xyzw, l(6)\n        or r19.xyzw, r19.xyzw, r20.xyzw\n        iadd r20.xyzw, r11.xyzw, r18.wwww\n        ishl r20.xyzw, r20.xyzw, l(2)\n        ushr r21.xyzw, r20.xyzw, l(6)\n        or r20.xyzw, r20.xyzw, r21.xyzw\n        mov x0[0].x, r19.x\n        mov x0[1].x, r19.y\n        mov x0[2].x, r19.z\n        mov x0[3].x, r19.w\n        mov x0[0].y, r20.x\n        mov x0[1].y, r20.y\n        mov x0[2].y, r20.z\n        mov x0[3].y, r20.w\n      endif \n    endif \n    if_nz r6.w\n      ushr r18.y, r18.x, l(1)\n      and r18.zw, r18.xxxy, l(0, 0, 1, 1)\n      iadd r19.xyz, r14.xyzx, r18.zzzz\n      iadd r20.xyz, r15.xyzx, r18.wwww\n      mov x0[4].x, r19.x\n      mov x0[5].x, r19.y\n      mov x0[6].x, r19.z\n      mov x0[7].x, l(255)\n      mov x0[4].y, r20.x\n      mov x0[5].y, r20.y\n      mov x0[6].y, r20.z\n      mov x0[7].y, l(255)\n    else \n      ieq r6.w, r0.w, l(7)\n      if_nz r6.w\n        ushr r18.y, r18.x, l(1)\n        and r18.yz, r18.xxyx, l(0, 1, 1, 0)\n        iadd r19.xyzw, r16.xyzw, r18.yyyy\n        ishl r19.xyzw, r19.xyzw, l(2)\n        ushr r20.xyzw, r19.xyzw, l(6)\n        or r19.xyzw, r19.xyzw, r20.xyzw\n        iadd r20.xyzw, r17.xyzw, r18.zzzz\n        ishl r20.xyzw, r20.xyzw, l(2)\n        ushr r21.xyzw, r20.xyzw, l(6)\n        or r20.xyzw, r20.xyzw, r21.xyzw\n        mov x0[4].x, r19.x\n        mov x0[5].x, r19.y\n        mov x0[6].x, r19.z\n        mov x0[7].x, r19.w\n        mov x0[4].y, r20.x\n        mov x0[5].y, r20.y\n        mov x0[6].y, r20.z\n        mov x0[7].y, r20.w\n      endif \n    endif \n  endif \n  mov r19.x, x0[0].y\n  mov r19.y, x0[1].y\n  mov r19.z, x0[2].y\n  mov r19.w, x0[3].y\n  mov r6.w, x0[0].x\n  mov r7.w, x0[1].x\n  mov r8.w, x0[2].x\n  mov r9.w, x0[3].x\n  ineg r20.x, r6.w\n  ineg r20.y, r7.w\n  ineg r20.z, r8.w\n  ineg r20.w, r9.w\n  iadd r21.xyzw, r19.xyzw, r20.xyzw\n  mov r22.x, x0[4].y\n  mov r22.y, x0[5].y\n  mov r22.z, x0[6].y\n  mov r22.w, x0[7].y\n  mov r12.w, x0[4].x\n  mov r13.w, x0[5].x\n  mov r14.w, x0[6].x\n  mov r15.w, x0[7].x\n  ineg r23.x, r12.w\n  ineg r23.y, r13.w\n  ineg r23.z, r14.w\n  ineg r23.w, r15.w\n  iadd r22.xyzw, r22.xyzw, r23.xyzw\n  ine r18.yz, r0.wwww, l(0, 7, 1, 0)\n  movc r22.w, r18.y, l(0), r22.w\n  movc r21.w, r18.y, l(0), r21.w\n  imul null, r23.xy, r21.xyxx, r21.xyxx\n  iadd r12.w, r23.y, r23.x\n  imad r12.w, r21.z, r21.z, r12.w\n  imad r12.w, r21.w, r21.w, r12.w\n  imul null, r23.xy, r22.xyxx, r22.xyxx\n  iadd r13.w, r23.y, r23.x\n  imad r13.w, r22.z, r22.z, r13.w\n  imad r13.w, r22.w, r22.w, r13.w\n  ld_structured r23.xyzw, l(0), l(0), g0.xyzw\n  iadd r20.xyzw, r20.xyzw, r23.xyzw\n  imul null, r20.xy, r20.xyxx, r21.xyxx\n  iadd r14.w, r20.y, r20.x\n  imad r14.w, r21.z, r20.z, r14.w\n  imad r14.w, r21.w, r20.w, r14.w\n  ilt r15.w, l(0), r12.w\n  ilt r18.w, l(0), r14.w\n  and r15.w, r15.w, r18.w\n  itof r14.w, r14.w\n  mul r14.w, r14.w, l(63.499989)\n  ftou r14.w, r14.w\n  ishl r18.w, r12.w, l(5)\n  ult r14.w, r18.w, r14.w\n  and r14.w, r14.w, r15.w\n  ineg r20.xyzw, r21.xyzw\n  movc r20.xyzw, r14.wwww, r20.xyzw, r21.xyzw\n  movc r15.w, r14.w, r19.x, r6.w\n  mov x0[0].x, r15.w\n  mov r18.w, x0[1].x\n  movc r18.w, r14.w, r19.y, r18.w\n  mov x0[1].x, r18.w\n  mov r19.x, x0[2].x\n  movc r19.x, r14.w, r19.z, r19.x\n  mov x0[2].x, r19.x\n  mov r19.y, x0[3].x\n  movc r19.y, r14.w, r19.w, r19.y\n  mov x0[3].x, r19.y\n  mov r19.z, x0[0].y\n  movc r6.w, r14.w, r6.w, r19.z\n  mov x0[0].y, r6.w\n  mov r6.w, x0[1].y\n  movc r6.w, r14.w, r7.w, r6.w\n  mov x0[1].y, r6.w\n  mov r6.w, x0[2].y\n  movc r6.w, r14.w, r8.w, r6.w\n  mov x0[2].y, r6.w\n  mov r6.w, x0[3].y\n  movc r6.w, r14.w, r9.w, r6.w\n  mov x0[3].y, r6.w\n  mov r6.w, vThreadIDInGroupFlattened.x\n  mov r7.w, icb[r6.w + 0].y\n  ld_structured r21.xyzw, r7.w, l(0), g0.xyzw\n  mov r7.w, x0[4].x\n  mov r8.w, x0[5].x\n  mov r9.w, x0[6].x\n  mov r14.w, x0[7].x\n  ineg r23.x, r7.w\n  ineg r23.y, r8.w\n  ineg r23.z, r9.w\n  ineg r23.w, r14.w\n  iadd r21.xyzw, r21.xyzw, r23.xyzw\n  imul null, r19.zw, r21.xxxy, r22.xxxy\n  iadd r19.z, r19.w, r19.z\n  imad r19.z, r22.z, r21.z, r19.z\n  imad r19.z, r22.w, r21.w, r19.z\n  ilt r19.w, l(0), r13.w\n  ilt r21.x, l(0), r19.z\n  and r19.w, r19.w, r21.x\n  itof r19.z, r19.z\n  mul r19.z, r19.z, l(63.499989)\n  ftou r19.z, r19.z\n  ishl r21.x, r13.w, l(5)\n  ult r19.z, r21.x, r19.z\n  and r19.z, r19.z, r19.w\n  ineg r21.xyzw, r22.xyzw\n  movc r21.xyzw, r19.zzzz, r21.xyzw, r22.xyzw\n  mov r19.w, x0[4].y\n  mov r22.x, x0[5].y\n  mov r22.y, x0[6].y\n  mov r22.z, x0[7].y\n  movc r19.w, r19.z, r19.w, r7.w\n  mov x0[4].x, r19.w\n  mov r22.w, x0[5].x\n  movc r22.x, r19.z, r22.x, r22.w\n  mov x0[5].x, r22.x\n  mov r22.w, x0[6].x\n  movc r22.y, r19.z, r22.y, r22.w\n  mov x0[6].x, r22.y\n  mov r22.w, x0[7].x\n  movc r22.z, r19.z, r22.z, r22.w\n  mov x0[7].x, r22.z\n  mov r22.w, x0[4].y\n  movc r7.w, r19.z, r7.w, r22.w\n  mov x0[4].y, r7.w\n  mov r7.w, x0[5].y\n  movc r7.w, r19.z, r8.w, r7.w\n  mov x0[5].y, r7.w\n  mov r7.w, x0[6].y\n  movc r7.w, r19.z, r9.w, r7.w\n  mov x0[6].y, r7.w\n  mov r7.w, x0[7].y\n  movc r7.w, r19.z, r14.w, r7.w\n  mov x0[7].y, r7.w\n  mov x3[0].x, l(0)\n  mov x3[1].x, l(0)\n  ineg r23.x, r19.w\n  ineg r23.yzw, r22.xxyz\n  ige r7.w, l(0), r13.w\n  itof r8.w, r13.w\n  movc r22.xyz, r18.zzzz, l(32,128,3,0), l(16,64,7,0)\n  ineg r24.x, r15.w\n  ineg r24.y, r18.w\n  ineg r24.zw, r19.xxxy\n  ige r9.w, l(0), r12.w\n  itof r14.w, r12.w\n  mov r15.w, l(0)\n  loop \n    uge r18.z, r15.w, l(16)\n    breakc_nz r18.z\n    ushr r18.z, icb[r6.w + 0].x, r15.w\n    and r18.z, r18.z, l(1)\n    ieq r18.w, r18.z, l(1)\n    if_nz r18.w\n      ld_structured r19.xyzw, r15.w, l(0), g0.xyzw\n      iadd r19.xyzw, r23.xyzw, r19.xyzw\n      imul null, r19.xy, r19.xyxx, r21.xyxx\n      iadd r19.x, r19.y, r19.x\n      imad r19.x, r21.z, r19.z, r19.x\n      imad r19.x, r21.w, r19.w, r19.x\n      ige r19.y, l(0), r19.x\n      or r19.y, r7.w, r19.y\n      ilt r19.z, r19.x, r13.w\n      itof r19.x, r19.x\n      mul r19.x, r19.x, l(63.499989)\n      div r19.x, r19.x, r8.w\n      ftou r19.x, r19.x\n      iadd r19.x, r19.x, r22.y\n      movc r19.x, r19.z, icb[r19.x + 0].w, r22.z\n      movc r19.x, r19.y, l(0), r19.x\n    else \n      ld_structured r25.xyzw, r15.w, l(0), g0.xyzw\n      iadd r25.xyzw, r24.xyzw, r25.xyzw\n      imul null, r19.yz, r20.xxyx, r25.xxyx\n      iadd r19.y, r19.z, r19.y\n      imad r19.y, r20.z, r25.z, r19.y\n      imad r19.y, r20.w, r25.w, r19.y\n      ige r19.z, l(0), r19.y\n      or r19.z, r9.w, r19.z\n      ilt r19.w, r19.y, r12.w\n      itof r19.y, r19.y\n      mul r19.y, r19.y, l(63.499989)\n      div r19.y, r19.y, r14.w\n      ftou r19.y, r19.y\n      iadd r19.y, r19.y, r22.y\n      movc r19.y, r19.w, icb[r19.y + 0].w, r22.z\n      movc r19.x, r19.z, l(0), r19.y\n    endif \n    iadd r19.x, r19.x, r22.x\n    iadd r19.y, l(64), -icb[r19.x + 64].x\n    ishl r18.z, r18.z, l(2)\n    mov r25.x, x0[r18.z + 0].x\n    mov r25.y, x0[r18.z + 1].x\n    mov r25.z, x0[r18.z + 2].x\n    mov r25.w, x0[r18.z + 3].x\n    mov r26.x, x0[r18.z + 0].y\n    mov r26.y, x0[r18.z + 1].y\n    mov r26.z, x0[r18.z + 2].y\n    mov r26.w, x0[r18.z + 3].y\n    imul null, r26.xyzw, r26.xyzw, icb[r19.x + 64].xxxx\n    imad r19.xyzw, r19.yyyy, r25.xyzw, r26.xyzw\n    iadd r19.xyzw, r19.xyzw, l(32, 32, 32, 32)\n    ushr r19.xyzw, r19.xzyw, l(6)\n    movc r19.w, r18.y, l(255), r19.w\n    ld_structured r25.xyzw, r15.w, l(0), g0.xyzw\n    ult r26.xyz, r19.xzyx, r25.xyzx\n    mov r27.xz, r25.xxyx\n    mov r27.yw, r19.xxxz\n    movc r27.xyzw, r26.xxyy, r27.xyzw, r27.yxwz\n    mov r19.xz, r25.zzwz\n    movc r19.xy, r26.zzzz, r19.xyxx, r19.yxyy\n    ult r18.z, r19.w, r25.w\n    movc r25.xw, r18.zzzz, r19.wwwz, r19.zzzw\n    ineg r26.xy, r27.ywyy\n    ineg r26.z, r19.y\n    ineg r26.w, r25.x\n    mov r25.xy, r27.xzxx\n    mov r25.z, r19.x\n    iadd r19.xyzw, r26.xyzw, r25.xyzw\n    imul null, r19.xy, r19.xyxx, r19.xyxx\n    iadd r18.z, r19.y, r19.x\n    imad r18.z, r19.z, r19.z, r18.z\n    utof r18.z, r18.z\n    utof r19.x, r19.w\n    mul r19.x, r19.x, r19.x\n    mad r18.z, r19.x, cb0[1].z, r18.z\n    ftou r18.z, r18.z\n    mov r19.x, x3[1].x\n    iadd r19.y, r18.z, r19.x\n    movc r19.x, r18.w, r19.y, r19.x\n    mov x3[1].x, r19.x\n    mov r19.x, x3[0].x\n    iadd r18.z, r18.z, r19.x\n    movc r18.z, r18.w, r19.x, r18.z\n    mov x3[0].x, r18.z\n    iadd r15.w, r15.w, l(1)\n  endloop \n  mov r6.w, x3[0].x\n  mov r7.w, x2[0].x\n  ult r8.w, r6.w, r7.w\n  umin r6.w, r6.w, r7.w\n  mov x2[0].x, r6.w\n  mov r6.w, x1[0].x\n  movc r6.w, r8.w, r18.x, r6.w\n  mov x1[0].x, r6.w\n  mov r6.w, x3[1].x\n  mov r7.w, x2[1].x\n  ult r8.w, r6.w, r7.w\n  umin r6.w, r6.w, r7.w\n  mov x2[1].x, r6.w\n  mov r6.w, x1[1].x\n  movc r6.w, r8.w, r18.x, r6.w\n  mov x1[1].x, r6.w\n  iadd r18.x, r18.x, l(1)\nendloop \nmov r0.z, x2[0].x\nmov r0.w, x2[1].x\niadd r2.x, r0.w, r0.z\nmov r2.y, cb0[0].w\nmov r2.z, vThreadIDInGroupFlattened.x\nstore_structured g0.xyz, vThreadIDInGroupFlattened.x, l(16), r2.xyzx\nif_nz r0.y\n  mov r0.y, x1[1].x\n  ishl r0.y, r0.y, l(1)\n  mov r0.z, x1[0].x\n  or r0.y, r0.z, r0.y\nelse \n  mov r0.z, x1[1].x\n  ishl r0.z, r0.z, l(2)\n  mov r0.w, x1[0].x\n  or r0.y, r0.w, r0.z\nendif \nstore_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r0.y\nsync_g_t\nif_nz r1.y\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(32)\n  ld_structured r3.yzw, r0.y, l(16), g0.xxyz\n  ld_structured r4.x, r0.y, l(32), g0.xxxx\n  ult r0.z, r3.y, r2.x\n  if_nz r0.z\n    ld_structured r3.x, r0.y, l(16), g0.xxxx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(16), r3.xzwx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r4.x\n  endif \nendif \nsync_g_t\nif_nz r1.x\n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(16)\n  ld_structured r3.yzw, r0.y, l(16), g0.xxyz\n  ld_structured r4.x, r0.y, l(32), g0.xxxx\n  ult r0.z, r3.y, r2.x\n  if_nz r0.z\n    ld_structured r3.x, r0.y, l(16), g0.xxxx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(16), r3.xzwx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r4.x\n  endif \nendif \nsync_g_t\nif_nz r1.z\n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(8)\n  ld_structured r3.yzw, r0.y, l(16), g0.xxyz\n  ld_structured r4.x, r0.y, l(32), g0.xxxx\n  ult r0.z, r3.y, r2.x\n  if_nz r0.z\n    ld_structured r3.x, r0.y, l(16), g0.xxxx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(16), r3.xzwx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r4.x\n  endif \nendif \nsync_g_t\nif_nz r1.w\n  ld_structured r1.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(4)\n  ld_structured r2.yzw, r0.y, l(16), g0.xxyz\n  ld_structured r3.x, r0.y, l(32), g0.xxxx\n  ult r0.z, r2.y, r1.x\n  if_nz r0.z\n    ld_structured r2.x, r0.y, l(16), g0.xxxx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(16), r2.xzwx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r3.x\n  endif \nendif \nsync_g_t\nult r0.yz, vThreadIDInGroupFlattened.xxxx, l(0, 2, 1, 0)\nif_nz r0.y\n  ld_structured r1.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(2)\n  ld_structured r2.yzw, r0.y, l(16), g0.xxyz\n  ld_structured r3.x, r0.y, l(32), g0.xxxx\n  ult r0.w, r2.y, r1.x\n  if_nz r0.w\n    ld_structured r2.x, r0.y, l(16), g0.xxxx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(16), r2.xzwx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r3.x\n  endif \nendif \nsync_g_t\nif_nz r0.z\n  ld_structured r1.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(1)\n  ld_structured r2.yzw, r0.y, l(16), g0.xxyz\n  ld_structured r3.x, r0.y, l(32), g0.xxxx\n  ult r0.z, r2.y, r1.x\n  if_nz r0.z\n    ld_structured r2.x, r0.y, l(16), g0.xxxx\n    store_structured g0.xyz, vThreadIDInGroupFlattened.x, l(16), r2.xzwx\n    store_structured g0.x, vThreadIDInGroupFlattened.x, l(32), r3.x\n  endif \n  ld_structured r1.x, r0.x, l(0), t1.xxxx\n  ld_structured r2.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  ult r0.y, r2.x, r1.x\n  if_nz r0.y\n    ld_structured r1.xyz, vThreadIDInGroupFlattened.x, l(16), g0.xyzx\n    ld_structured r1.w, vThreadIDInGroupFlattened.x, l(32), g0.xxxx\n  else \n    ld_structured r1.xyzw, r0.x, l(0), t1.xyzw\n  endif \n  store_structured u0.xyzw, r0.x, l(0), r1.xyzw\nendif \nret \n// Approximately 0 instruction slots used\n#endif\n\nconst BYTE BC7Encode_TryMode137CS[] =\n{\n     68,  88,  66,  67, 237,  85, \n    208, 125,   4,   8, 223, 249, \n    164, 254,  64,  15, 135,   5, \n    113, 116,   1,   0,   0,   0, \n     48,  76,   0,   0,   3,   0, \n      0,   0,  44,   0,   0,   0, \n     60,   0,   0,   0,  76,   0, \n      0,   0,  73,  83,  71,  78, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     79,  83,  71,  78,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  83,  72, \n     69,  88, 220,  75,   0,   0, \n     64,   0,   5,   0, 247,  18, \n      0,   0, 106,   8,   0,   1, \n     53,  24,   0,   0,   2,   3, \n      0,   0, 204, 204,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n    136, 136,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 238, 238, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0, 200, 236,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n    128, 200,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0, 236, 254, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0, 200, 254,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n    128, 236,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0, 200, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0, 236, 255,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n    128, 254,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0, 232, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0, 232, 255,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0, 255,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0, 240, 255, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0, 240,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     16, 247,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0, 142,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0, 113,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n    206,   8,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0, 140,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  16, 115,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n      0,  49,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0, 206, 140, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0, 140,   8,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     16,  49,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0, 102, 102, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0, 108,  54,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n    232,  23,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0, 240,  15, \n      0,   0,   8,   0,   0,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0, 142, 113,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n    156,  57,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      7,   0,   0,   0, 170, 170, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0, 240, 240,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     90,  90,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0, 204,  51, \n      0,   0,   8,   0,   0,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,  60,  60,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n    170,  85,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      9,   0,   0,   0, 150, 150, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   9,   0, \n      0,   0,  90, 165,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,   9,   0,   0,   0, \n    206, 115,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      9,   0,   0,   0, 200,  19, \n      0,   0,   8,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,  76,  50,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n    220,  59,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,   0,   0, 150, 105, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,  60, 195,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n    102, 153,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n     11,   0,   0,   0,  96,   6, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,  11,   0, \n      0,   0, 114,   2,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,  11,   0,   0,   0, \n    228,   4,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n     11,   0,   0,   0,  64,  78, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,  12,   0, \n      0,   0,  32,  39,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,  12,   0,   0,   0, \n     54, 201,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n     12,   0,   0,   0, 108, 147, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,  12,   0, \n      0,   0, 198,  57,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,  13,   0,   0,   0, \n    156,  99,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n     13,   0,   0,   0,  54, 147, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,  13,   0, \n      0,   0, 198, 156,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,  13,   0,   0,   0, \n    126, 129,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n     14,   0,   0,   0,  24, 231, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,  14,   0, \n      0,   0, 240, 204,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,  14,   0,   0,   0, \n    204,  15,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n     14,   0,   0,   0,  68, 119, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,  34, 238,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   3,   0,   0,   0, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   9,   0,   0,   0, \n     15,   0,   0,   0,   8,   0, \n      0,   0,   0,   0,   0,   0, \n     13,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,  17,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   0,   0, \n      0,   0,  21,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   1,   0,   0,   0, \n     26,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   0,  15,   0,   0,   0, \n      8,   0,   0,   0,   1,   0, \n      0,   0,  34,   0,   0,   0, \n      8,   0,   0,   0,  15,   0, \n      0,   0,   1,   0,   0,   0, \n     38,   0,   0,   0,   8,   0, \n      0,   0,  15,   0,   0,   0, \n      1,   0,   0,   0,  43,   0, \n      0,   0,   6,   0,   0,   0, \n     15,   0,   0,   0,   1,   0, \n      0,   0,  47,   0,   0,   0, \n      6,   0,   0,   0,  15,   0, \n      0,   0,   1,   0,   0,   0, \n     51,   0,   0,   0,   6,   0, \n      0,   0,  15,   0,   0,   0, \n      1,   0,   0,   0,  55,   0, \n      0,   0,   5,   0,   0,   0, \n     15,   0,   0,   0,   1,   0, \n      0,   0,  60,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   2,   0,   0,   0, \n     64,   0,   0,   0,   3,   0, \n      0,   0,   8,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     15,   0,   0,   0,   2,   0, \n      0,   0,   9,   0,   0,   0, \n      3,   0,   0,   0,   8,   0, \n      0,   0,   2,   0,   0,   0, \n     18,   0,   0,   0,   8,   0, \n      0,   0,  15,   0,   0,   0, \n      2,   0,   0,   0,  27,   0, \n      0,   0,  15,   0,   0,   0, \n      3,   0,   0,   0,   2,   0, \n      0,   0,  37,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   2,   0,   0,   0, \n     46,   0,   0,   0,   3,   0, \n      0,   0,   8,   0,   0,   0, \n      2,   0,   0,   0,  55,   0, \n      0,   0,   6,   0,   0,   0, \n     15,   0,   0,   0,   2,   0, \n      0,   0,  64,   0,   0,   0, \n     10,   0,   0,   0,   8,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   3,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,   6,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  10,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,  10,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      8,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n     21,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n      4,   0,   0,   0,  43,   0, \n      0,   0,   3,   0,   0,   0, \n     15,   0,   0,   0,   4,   0, \n      0,   0,  64,   0,   0,   0, \n      5,   0,   0,   0,  10,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  10,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n      8,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,   9,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,  10,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      6,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,   8,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     15,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,   3,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,   6,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      6,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,   8,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  15,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      3,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  15,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  15,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     15,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  15,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  15,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n     15,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  15,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,  15,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     15,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n     13,   0,   0,   0,  15,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,   3,   0,   0,   0, \n      7,   0,   0,   0,   0,   0, \n      0,   0,  12,   0,   0,   0, \n     15,   0,   0,   0,   7,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  15,   0, \n      0,   0,   7,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   8,   0,   0,   0, \n      7,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  89,   0,   0,   4, \n     70, 142,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     88,  24,   0,   4,   0, 112, \n     16,   0,   0,   0,   0,   0, \n     85,  85,   0,   0, 162,   0, \n      0,   4,   0, 112,  16,   0, \n      1,   0,   0,   0,  16,   0, \n      0,   0, 158,   0,   0,   4, \n      0, 224,  17,   0,   0,   0, \n      0,   0,  16,   0,   0,   0, \n     95,   0,   0,   2,   0,  64, \n      2,   0,  95,   0,   0,   2, \n     18,  16,   2,   0, 104,   0, \n      0,   2,  28,   0,   0,   0, \n    105,   0,   0,   4,   0,   0, \n      0,   0,   8,   0,   0,   0, \n      4,   0,   0,   0, 105,   0, \n      0,   4,   1,   0,   0,   0, \n      2,   0,   0,   0,   4,   0, \n      0,   0, 105,   0,   0,   4, \n      2,   0,   0,   0,   2,   0, \n      0,   0,   4,   0,   0,   0, \n    105,   0,   0,   4,   3,   0, \n      0,   0,   2,   0,   0,   0, \n      4,   0,   0,   0, 160,   0, \n      0,   5,   0, 240,  17,   0, \n      0,   0,   0,   0, 100,   0, \n      0,   0,  64,   0,   0,   0, \n    155,   0,   0,   4,  64,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      0,   0,   0,   0,  10,  16, \n      2,   0,  10, 128,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  79,   0,   0,   9, \n    242,   0,  16,   0,   1,   0, \n      0,   0,   6,  64,   2,   0, \n      2,  64,   0,   0,  16,   0, \n      0,   0,  32,   0,   0,   0, \n      8,   0,   0,   0,   4,   0, \n      0,   0,  31,   0,   4,   3, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  78,   0,   0,   9, \n     34,   0,  16,   0,   0,   0, \n      0,   0,   0, 208,   0,   0, \n     10,   0,  16,   0,   0,   0, \n      0,   0,  26, 128,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  35,   0,   0,  11, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16, 128, \n     65,   0,   0,   0,   0,   0, \n      0,   0,  26, 128,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   6, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   6,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  54,   0,   0,   8, \n    194,   0,  16,   0,   2,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  45,   0, \n      0,   7, 242,   0,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   2,   0,   0,   0, \n     70, 126,  16,   0,   0,   0, \n      0,   0,  56,   0,   0,  10, \n    242,   0,  16,   0,   2,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0,   0,   0, 127,  67, \n      0,   0, 127,  67,   0,   0, \n    127,  67,   0,   0, 127,  67, \n     28,   0,   0,   5, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   2,   0, \n      0,   0,  84,   0,   0,  10, \n    242,   0,  16,   0,   2,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0, 255,   0,   0,   0, \n    255,   0,   0,   0, 255,   0, \n      0,   0, 255,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70,  14,  16,   0,   2,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n    255, 255, 255, 255,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     48,   0,   0,   1,  80,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   3,   0,   4,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  54,   0,   0,   4, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n     85,   0,   0,   8,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10, 144, 144,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     32,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  18,   0,  16,   0, \n      3,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n      3,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  54,   0, \n      0,   6,  66,   0,  16,   0, \n      3,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      3,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,  84,   0, \n      0,   7, 242,   0,  16,   0, \n      3,   0,   0,   0,  70,  14, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  54,   0,   0,   6, \n     34,   0,  16,   0,   3,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  54,   0,   0,   6, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   3,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,  83,   0,   0,   7, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  34,  48, \n     32,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  34,  48, \n     32,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  34,  48, \n     32,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  34,  48, \n     32,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     18,   0,   0,   1,  54,   0, \n      0,   6,  18,   0,  16,   0, \n      3,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n      3,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   6,  66,   0,  16,   0, \n      3,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      3,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  84,   0, \n      0,   7, 242,   0,  16,   0, \n      3,   0,   0,   0,  70,  14, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n     34,   0,  16,   0,   3,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  54,   0,   0,   6, \n     66,   0,  16,   0,   3,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   3,   0, \n      0,   0,  26,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  83,   0,   0,   7, \n    242,   0,  16,   0,   2,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  34,  48, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     54,   0,   0,   6,  34,  48, \n     32,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     54,   0,   0,   6,  34,  48, \n     32,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     54,   0,   0,   6,  34,  48, \n     32,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     21,   0,   0,   1,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  22,   0,   0,   1, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   3,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   3,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   3,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n     54,   0,   0,   6,  18,   0, \n     16,   0,   5,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   5,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   5,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   5,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n     32,   0,   0,   8,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     58, 128,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  55,   0,   0,   9, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      1,  64,   0,   0, 255, 255, \n    255, 255,  54,   0,   0,   6, \n     18,  48,  32,   0,   2,   0, \n      0,   0,   1,   0,   0,   0, \n      1,  64,   0,   0, 255, 255, \n    255, 255,  35,   0,   0,  15, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0, 127, 127,   0,   0, \n    127, 127,   0,   0, 127, 127, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  70,   2,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   6,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n      0,   0,   0,   0,  35,   0, \n      0,  15, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0, 127, 127, \n      0,   0, 127, 127,   0,   0, \n    127, 127,   0,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   2,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255, 255, 255, 254, 255, \n    255, 255, 254, 255, 255, 255, \n      0,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n      9,   0,   0,   0,  70,   2, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0, 254, 255, \n    255, 255, 254, 255, 255, 255, \n    254, 255, 255, 255,   0,   0, \n      0,   0,  35,   0,   0,  15, \n    242,   0,  16,   0,  10,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0,  63,  63,   0,   0, \n     63,  63,   0,   0,  63,  63, \n      0,   0,  63,  63,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,  85,   0,   0,   7, \n    242,   0,  16,   0,  10,   0, \n      0,   0,  70,  14,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,  10,   0,   0,   0, \n     70,  14,  16,   0,  10,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0,  35,   0, \n      0,  15, 242,   0,  16,   0, \n     11,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n      2,  64,   0,   0,  63,  63, \n      0,   0,  63,  63,   0,   0, \n     63,  63,   0,   0,  63,  63, \n      0,   0,   2,  64,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,  85,   0, \n      0,   7, 242,   0,  16,   0, \n     11,   0,   0,   0,  70,  14, \n     16,   0,  11,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,  11,   0, \n      0,   0,  70,  14,  16,   0, \n     11,   0,   0,   0,   2,  64, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n     35,   0,   0,  15, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n    127, 127,   0,   0, 127, 127, \n      0,   0, 127, 127,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,  12,   0,   0,   0, \n     70,   2,  16,   0,  12,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n     12,   0,   0,   0,  70,   2, \n     16,   0,  12,   0,   0,   0, \n      2,  64,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0,   0,   0, \n      0,   0,  35,   0,   0,  15, \n    114,   0,  16,   0,  13,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0, 127, 127,   0,   0, \n    127, 127,   0,   0, 127, 127, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,  13,   0, \n      0,   0,  70,   2,  16,   0, \n     13,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 114,   0, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,  10, 114,   0,  16,   0, \n     14,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n      2,  64,   0,   0, 254, 255, \n    255, 255, 254, 255, 255, 255, \n    254, 255, 255, 255,   0,   0, \n      0,   0,   1,   0,   0,  10, \n    114,   0,  16,   0,  15,   0, \n      0,   0,  70,   2,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0, 254, 255, 255, 255, \n    254, 255, 255, 255, 254, 255, \n    255, 255,   0,   0,   0,   0, \n     35,   0,   0,  15, 242,   0, \n     16,   0,  16,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n     63,  63,   0,   0,  63,  63, \n      0,   0,  63,  63,   0,   0, \n     63,  63,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n     85,   0,   0,   7, 242,   0, \n     16,   0,  16,   0,   0,   0, \n     70,  14,  16,   0,  16,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   1,   0, \n      0,  10, 242,   0,  16,   0, \n     16,   0,   0,   0,  70,  14, \n     16,   0,  16,   0,   0,   0, \n      2,  64,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0,  35,   0,   0,  15, \n    242,   0,  16,   0,  17,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0,  63,  63,   0,   0, \n     63,  63,   0,   0,  63,  63, \n      0,   0,  63,  63,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,  85,   0,   0,   7, \n    242,   0,  16,   0,  17,   0, \n      0,   0,  70,  14,  16,   0, \n     17,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,  17,   0,   0,   0, \n     70,  14,  16,   0,  17,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255,   0,   0, 254, 255, \n      0,   0, 254, 255,   0,   0, \n    254, 255,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      0,   0,   0,   0,  58, 128, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   5,  18,   0,  16,   0, \n     18,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     48,   0,   0,   1,  80,   0, \n      0,   7, 130,   0,  16,   0, \n      6,   0,   0,   0,  10,   0, \n     16,   0,  18,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   3,   0,   4,   3, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   5,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     26,   0,  16,   0,   5,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   5,   0, \n      0,   0,  32,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,  19,   0,   0,   0, \n     70,   2,  16,   0,   6,   0, \n      0,   0,   6,   0,  16,   0, \n     18,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     19,   0,   0,   0,  70,   2, \n     16,   0,  19,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,  20,   0, \n      0,   0,  70,   2,  16,   0, \n     19,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,  19,   0,   0,   0, \n     70,   2,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n     20,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n     20,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      6,   0,  16,   0,  18,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,  20,   0, \n      0,   0,  70,   2,  16,   0, \n     20,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,  21,   0,   0,   0, \n     70,   2,  16,   0,  20,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n     20,   0,   0,   0,  70,   2, \n     16,   0,  20,   0,   0,   0, \n     70,   2,  16,   0,  21,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,  19,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,  19,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      1,  64,   0,   0, 255,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,  20,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,  20,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,  20,   0, \n      0,   0,  54,   0,   0,   6, \n     34,  48,  32,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      1,  64,   0,   0, 255,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,   6,   0, \n     16,   0,  18,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,  19,   0,   0,   0, \n     70,   2,  16,   0,  19,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n     20,   0,   0,   0,  70,   2, \n     16,   0,  19,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n     19,   0,   0,   0,  70,   2, \n     16,   0,  20,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,  20,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,   6,   0,  16,   0, \n     18,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     20,   0,   0,   0,  70,   2, \n     16,   0,  20,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,  21,   0, \n      0,   0,  70,   2,  16,   0, \n     20,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,  20,   0,   0,   0, \n     70,   2,  16,   0,  20,   0, \n      0,   0,  70,   2,  16,   0, \n     21,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n    255,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n    255,   0,   0,   0,  18,   0, \n      0,   1,  32,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     85,   0,   0,   7,  34,   0, \n     16,   0,  18,   0,   0,   0, \n     10,   0,  16,   0,  18,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n     18,   0,   0,   0,   6,   4, \n     16,   0,  18,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n    114,   0,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0, 166,  10, \n     16,   0,  18,   0,   0,   0, \n     30,   0,   0,   7, 114,   0, \n     16,   0,  20,   0,   0,   0, \n     70,   2,  16,   0,   9,   0, \n      0,   0, 246,  15,  16,   0, \n     18,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n    255,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   1,  64,   0,   0, \n    255,   0,   0,   0,  18,   0, \n      0,   1,  32,   0,   0,   7, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     85,   0,   0,   7,  34,   0, \n     16,   0,  18,   0,   0,   0, \n     10,   0,  16,   0,  18,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n     18,   0,   0,   0,   6,   4, \n     16,   0,  18,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n    242,   0,  16,   0,  19,   0, \n      0,   0,  70,  14,  16,   0, \n     10,   0,   0,   0, 166,  10, \n     16,   0,  18,   0,   0,   0, \n     41,   0,   0,   7, 242,   0, \n     16,   0,  19,   0,   0,   0, \n     70,  14,  16,   0,  19,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  85,   0, \n      0,   7, 242,   0,  16,   0, \n     20,   0,   0,   0,  70,  14, \n     16,   0,  19,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  60,   0,   0,   7, \n    242,   0,  16,   0,  19,   0, \n      0,   0,  70,  14,  16,   0, \n     19,   0,   0,   0,  70,  14, \n     16,   0,  20,   0,   0,   0, \n     30,   0,   0,   7, 242,   0, \n     16,   0,  20,   0,   0,   0, \n     70,  14,  16,   0,  11,   0, \n      0,   0, 246,  15,  16,   0, \n     18,   0,   0,   0,  41,   0, \n      0,   7, 242,   0,  16,   0, \n     20,   0,   0,   0,  70,  14, \n     16,   0,  20,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  85,   0,   0,   7, \n    242,   0,  16,   0,  21,   0, \n      0,   0,  70,  14,  16,   0, \n     20,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     60,   0,   0,   7, 242,   0, \n     16,   0,  20,   0,   0,   0, \n     70,  14,  16,   0,  20,   0, \n      0,   0,  70,  14,  16,   0, \n     21,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n     20,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     85,   0,   0,   7,  34,   0, \n     16,   0,  18,   0,   0,   0, \n     10,   0,  16,   0,  18,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,  10, 194,   0,  16,   0, \n     18,   0,   0,   0,   6,   4, \n     16,   0,  18,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n    114,   0,  16,   0,  19,   0, \n      0,   0,  70,   2,  16,   0, \n     14,   0,   0,   0, 166,  10, \n     16,   0,  18,   0,   0,   0, \n     30,   0,   0,   7, 114,   0, \n     16,   0,  20,   0,   0,   0, \n     70,   2,  16,   0,  15,   0, \n      0,   0, 246,  15,  16,   0, \n     18,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n    255,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n    255,   0,   0,   0,  18,   0, \n      0,   1,  32,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   7,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     85,   0,   0,   7,  34,   0, \n     16,   0,  18,   0,   0,   0, \n     10,   0,  16,   0,  18,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,  10,  98,   0,  16,   0, \n     18,   0,   0,   0,   6,   1, \n     16,   0,  18,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n    242,   0,  16,   0,  19,   0, \n      0,   0,  70,  14,  16,   0, \n     16,   0,   0,   0,  86,   5, \n     16,   0,  18,   0,   0,   0, \n     41,   0,   0,   7, 242,   0, \n     16,   0,  19,   0,   0,   0, \n     70,  14,  16,   0,  19,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  85,   0, \n      0,   7, 242,   0,  16,   0, \n     20,   0,   0,   0,  70,  14, \n     16,   0,  19,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  60,   0,   0,   7, \n    242,   0,  16,   0,  19,   0, \n      0,   0,  70,  14,  16,   0, \n     19,   0,   0,   0,  70,  14, \n     16,   0,  20,   0,   0,   0, \n     30,   0,   0,   7, 242,   0, \n     16,   0,  20,   0,   0,   0, \n     70,  14,  16,   0,  17,   0, \n      0,   0, 166,  10,  16,   0, \n     18,   0,   0,   0,  41,   0, \n      0,   7, 242,   0,  16,   0, \n     20,   0,   0,   0,  70,  14, \n     16,   0,  20,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  85,   0,   0,   7, \n    242,   0,  16,   0,  21,   0, \n      0,   0,  70,  14,  16,   0, \n     20,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     60,   0,   0,   7, 242,   0, \n     16,   0,  20,   0,   0,   0, \n     70,  14,  16,   0,  20,   0, \n      0,   0,  70,  14,  16,   0, \n     21,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  10,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n     20,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n     21,   0,   0,   1,  54,   0, \n      0,   6,  18,   0,  16,   0, \n     19,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n     19,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   6,  66,   0,  16,   0, \n     19,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n     19,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      6,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      7,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      8,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      9,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  40,   0, \n      0,   5,  18,   0,  16,   0, \n     20,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     40,   0,   0,   5,  34,   0, \n     16,   0,  20,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  40,   0,   0,   5, \n     66,   0,  16,   0,  20,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  40,   0, \n      0,   5, 130,   0,  16,   0, \n     20,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7, 242,   0, \n     16,   0,  21,   0,   0,   0, \n     70,  14,  16,   0,  19,   0, \n      0,   0,  70,  14,  16,   0, \n     20,   0,   0,   0,  54,   0, \n      0,   6,  18,   0,  16,   0, \n     22,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n     22,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  54,   0, \n      0,   6,  66,   0,  16,   0, \n     22,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n     22,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n     12,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n     13,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n     14,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n     15,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,  40,   0, \n      0,   5,  18,   0,  16,   0, \n     23,   0,   0,   0,  58,   0, \n     16,   0,  12,   0,   0,   0, \n     40,   0,   0,   5,  34,   0, \n     16,   0,  23,   0,   0,   0, \n     58,   0,  16,   0,  13,   0, \n      0,   0,  40,   0,   0,   5, \n     66,   0,  16,   0,  23,   0, \n      0,   0,  58,   0,  16,   0, \n     14,   0,   0,   0,  40,   0, \n      0,   5, 130,   0,  16,   0, \n     23,   0,   0,   0,  58,   0, \n     16,   0,  15,   0,   0,   0, \n     30,   0,   0,   7, 242,   0, \n     16,   0,  22,   0,   0,   0, \n     70,  14,  16,   0,  22,   0, \n      0,   0,  70,  14,  16,   0, \n     23,   0,   0,   0,  39,   0, \n      0,  10,  98,   0,  16,   0, \n     18,   0,   0,   0, 246,  15, \n     16,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  55,   0,   0,   9, \n    130,   0,  16,   0,  22,   0, \n      0,   0,  26,   0,  16,   0, \n     18,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  22,   0, \n      0,   0,  55,   0,   0,   9, \n    130,   0,  16,   0,  21,   0, \n      0,   0,  26,   0,  16,   0, \n     18,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  21,   0, \n      0,   0,  38,   0,   0,   8, \n      0, 208,   0,   0,  50,   0, \n     16,   0,  23,   0,   0,   0, \n     70,   0,  16,   0,  21,   0, \n      0,   0,  70,   0,  16,   0, \n     21,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n     12,   0,   0,   0,  26,   0, \n     16,   0,  23,   0,   0,   0, \n     10,   0,  16,   0,  23,   0, \n      0,   0,  35,   0,   0,   9, \n    130,   0,  16,   0,  12,   0, \n      0,   0,  42,   0,  16,   0, \n     21,   0,   0,   0,  42,   0, \n     16,   0,  21,   0,   0,   0, \n     58,   0,  16,   0,  12,   0, \n      0,   0,  35,   0,   0,   9, \n    130,   0,  16,   0,  12,   0, \n      0,   0,  58,   0,  16,   0, \n     21,   0,   0,   0,  58,   0, \n     16,   0,  21,   0,   0,   0, \n     58,   0,  16,   0,  12,   0, \n      0,   0,  38,   0,   0,   8, \n      0, 208,   0,   0,  50,   0, \n     16,   0,  23,   0,   0,   0, \n     70,   0,  16,   0,  22,   0, \n      0,   0,  70,   0,  16,   0, \n     22,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n     13,   0,   0,   0,  26,   0, \n     16,   0,  23,   0,   0,   0, \n     10,   0,  16,   0,  23,   0, \n      0,   0,  35,   0,   0,   9, \n    130,   0,  16,   0,  13,   0, \n      0,   0,  42,   0,  16,   0, \n     22,   0,   0,   0,  42,   0, \n     16,   0,  22,   0,   0,   0, \n     58,   0,  16,   0,  13,   0, \n      0,   0,  35,   0,   0,   9, \n    130,   0,  16,   0,  13,   0, \n      0,   0,  58,   0,  16,   0, \n     22,   0,   0,   0,  58,   0, \n     16,   0,  22,   0,   0,   0, \n     58,   0,  16,   0,  13,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,  23,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n    242,   0,  16,   0,  20,   0, \n      0,   0,  70,  14,  16,   0, \n     20,   0,   0,   0,  70,  14, \n     16,   0,  23,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0,  50,   0,  16,   0, \n     20,   0,   0,   0,  70,   0, \n     16,   0,  20,   0,   0,   0, \n     70,   0,  16,   0,  21,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,  14,   0, \n      0,   0,  26,   0,  16,   0, \n     20,   0,   0,   0,  10,   0, \n     16,   0,  20,   0,   0,   0, \n     35,   0,   0,   9, 130,   0, \n     16,   0,  14,   0,   0,   0, \n     42,   0,  16,   0,  21,   0, \n      0,   0,  42,   0,  16,   0, \n     20,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     35,   0,   0,   9, 130,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,  21,   0, \n      0,   0,  58,   0,  16,   0, \n     20,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     34,   0,   0,   7, 130,   0, \n     16,   0,  15,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n     12,   0,   0,   0,  34,   0, \n      0,   7, 130,   0,  16,   0, \n     18,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  14,   0, \n      0,   0,   1,   0,   0,   7, \n    130,   0,  16,   0,  15,   0, \n      0,   0,  58,   0,  16,   0, \n     15,   0,   0,   0,  58,   0, \n     16,   0,  18,   0,   0,   0, \n     43,   0,   0,   5, 130,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,  14,   0, \n      0,   0,  56,   0,   0,   7, \n    130,   0,  16,   0,  14,   0, \n      0,   0,  58,   0,  16,   0, \n     14,   0,   0,   0,   1,  64, \n      0,   0, 253, 255, 125,  66, \n     28,   0,   0,   5, 130,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,  14,   0, \n      0,   0,  41,   0,   0,   7, \n    130,   0,  16,   0,  18,   0, \n      0,   0,  58,   0,  16,   0, \n     12,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     79,   0,   0,   7, 130,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,  18,   0, \n      0,   0,  58,   0,  16,   0, \n     14,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n     14,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,  15,   0, \n      0,   0,  40,   0,   0,   5, \n    242,   0,  16,   0,  20,   0, \n      0,   0,  70,  14,  16,   0, \n     21,   0,   0,   0,  55,   0, \n      0,   9, 242,   0,  16,   0, \n     20,   0,   0,   0, 246,  15, \n     16,   0,  14,   0,   0,   0, \n     70,  14,  16,   0,  20,   0, \n      0,   0,  70,  14,  16,   0, \n     21,   0,   0,   0,  55,   0, \n      0,   9, 130,   0,  16,   0, \n     15,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     10,   0,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n     15,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n     18,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  55,   0, \n      0,   9, 130,   0,  16,   0, \n     18,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     26,   0,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n     18,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n     18,   0,   0,   0,  54,   0, \n      0,   6,  18,   0,  16,   0, \n     19,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  55,   0, \n      0,   9,  18,   0,  16,   0, \n     19,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  34,   0,  16,   0, \n     19,   0,   0,   0,  10,  48, \n     32,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  55,   0, \n      0,   9,  34,   0,  16,   0, \n     19,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,  19,   0, \n      0,   0,  26,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  66,   0,  16,   0, \n     19,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,   9, 130,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  42,   0,  16,   0, \n     19,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      6,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  55,   0, \n      0,   9, 130,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      6,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  55,   0, \n      0,   9, 130,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      6,   0,   0,   0,  26,  48, \n     32,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  55,   0, \n      0,   9, 130,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   6,  34,  48,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   4, 130,   0,  16,   0, \n      6,   0,   0,   0,  10,  64, \n      2,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  26, 144, 144,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,  21,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,  14,   0, \n      0,   0,  10,  48,  32,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,  40,   0,   0,   5, \n     18,   0,  16,   0,  23,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  40,   0, \n      0,   5,  34,   0,  16,   0, \n     23,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     40,   0,   0,   5,  66,   0, \n     16,   0,  23,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  40,   0,   0,   5, \n    130,   0,  16,   0,  23,   0, \n      0,   0,  58,   0,  16,   0, \n     14,   0,   0,   0,  30,   0, \n      0,   7, 242,   0,  16,   0, \n     21,   0,   0,   0,  70,  14, \n     16,   0,  21,   0,   0,   0, \n     70,  14,  16,   0,  23,   0, \n      0,   0,  38,   0,   0,   8, \n      0, 208,   0,   0, 194,   0, \n     16,   0,  19,   0,   0,   0, \n      6,   4,  16,   0,  21,   0, \n      0,   0,   6,   4,  16,   0, \n     22,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n     19,   0,   0,   0,  58,   0, \n     16,   0,  19,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  35,   0,   0,   9, \n     66,   0,  16,   0,  19,   0, \n      0,   0,  42,   0,  16,   0, \n     22,   0,   0,   0,  42,   0, \n     16,   0,  21,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  35,   0,   0,   9, \n     66,   0,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n     22,   0,   0,   0,  58,   0, \n     16,   0,  21,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  34,   0,   0,   7, \n    130,   0,  16,   0,  19,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,  13,   0,   0,   0, \n     34,   0,   0,   7,  18,   0, \n     16,   0,  21,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n     19,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n     19,   0,   0,   0,  58,   0, \n     16,   0,  19,   0,   0,   0, \n     10,   0,  16,   0,  21,   0, \n      0,   0,  43,   0,   0,   5, \n     66,   0,  16,   0,  19,   0, \n      0,   0,  42,   0,  16,   0, \n     19,   0,   0,   0,  56,   0, \n      0,   7,  66,   0,  16,   0, \n     19,   0,   0,   0,  42,   0, \n     16,   0,  19,   0,   0,   0, \n      1,  64,   0,   0, 253, 255, \n    125,  66,  28,   0,   0,   5, \n     66,   0,  16,   0,  19,   0, \n      0,   0,  42,   0,  16,   0, \n     19,   0,   0,   0,  41,   0, \n      0,   7,  18,   0,  16,   0, \n     21,   0,   0,   0,  58,   0, \n     16,   0,  13,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  79,   0,   0,   7, \n     66,   0,  16,   0,  19,   0, \n      0,   0,  10,   0,  16,   0, \n     21,   0,   0,   0,  42,   0, \n     16,   0,  19,   0,   0,   0, \n      1,   0,   0,   7,  66,   0, \n     16,   0,  19,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n     19,   0,   0,   0,  40,   0, \n      0,   5, 242,   0,  16,   0, \n     21,   0,   0,   0,  70,  14, \n     16,   0,  22,   0,   0,   0, \n     55,   0,   0,   9, 242,   0, \n     16,   0,  21,   0,   0,   0, \n    166,  10,  16,   0,  19,   0, \n      0,   0,  70,  14,  16,   0, \n     21,   0,   0,   0,  70,  14, \n     16,   0,  22,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,  19,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     54,   0,   0,   6,  18,   0, \n     16,   0,  22,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,  22,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     54,   0,   0,   6,  66,   0, \n     16,   0,  22,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n     55,   0,   0,   9, 130,   0, \n     16,   0,  19,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n     19,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,  19,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,  22,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     55,   0,   0,   9,  18,   0, \n     16,   0,  22,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  10,   0,  16,   0, \n     22,   0,   0,   0,  58,   0, \n     16,   0,  22,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  10,   0, \n     16,   0,  22,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,  22,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     55,   0,   0,   9,  34,   0, \n     16,   0,  22,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  26,   0,  16,   0, \n     22,   0,   0,   0,  58,   0, \n     16,   0,  22,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  26,   0, \n     16,   0,  22,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,  22,   0,   0,   0, \n     10,  48,  32,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n     55,   0,   0,   9,  66,   0, \n     16,   0,  22,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  42,   0,  16,   0, \n     22,   0,   0,   0,  58,   0, \n     16,   0,  22,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,  42,   0, \n     16,   0,  22,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,  22,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     55,   0,   0,   9, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,  22,   0,   0,   0, \n     54,   0,   0,   6,  34,  48, \n     32,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     55,   0,   0,   9, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     54,   0,   0,   6,  34,  48, \n     32,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n     55,   0,   0,   9, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     54,   0,   0,   6,  34,  48, \n     32,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     26,  48,  32,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n     55,   0,   0,   9, 130,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n     14,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     54,   0,   0,   6,  34,  48, \n     32,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   3,   0,   0,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     40,   0,   0,   5,  18,   0, \n     16,   0,  23,   0,   0,   0, \n     58,   0,  16,   0,  19,   0, \n      0,   0,  40,   0,   0,   5, \n    226,   0,  16,   0,  23,   0, \n      0,   0,   6,   9,  16,   0, \n     22,   0,   0,   0,  33,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  13,   0, \n      0,   0,  43,   0,   0,   5, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n     13,   0,   0,   0,  55,   0, \n      0,  15, 114,   0,  16,   0, \n     22,   0,   0,   0, 166,  10, \n     16,   0,  18,   0,   0,   0, \n      2,  64,   0,   0,  32,   0, \n      0,   0, 128,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n     16,   0,   0,   0,  64,   0, \n      0,   0,   7,   0,   0,   0, \n      0,   0,   0,   0,  40,   0, \n      0,   5,  18,   0,  16,   0, \n     24,   0,   0,   0,  58,   0, \n     16,   0,  15,   0,   0,   0, \n     40,   0,   0,   5,  34,   0, \n     16,   0,  24,   0,   0,   0, \n     58,   0,  16,   0,  18,   0, \n      0,   0,  40,   0,   0,   5, \n    194,   0,  16,   0,  24,   0, \n      0,   0,   6,   4,  16,   0, \n     19,   0,   0,   0,  33,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  12,   0, \n      0,   0,  43,   0,   0,   5, \n    130,   0,  16,   0,  14,   0, \n      0,   0,  58,   0,  16,   0, \n     12,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n     15,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     48,   0,   0,   1,  80,   0, \n      0,   7,  66,   0,  16,   0, \n     18,   0,   0,   0,  58,   0, \n     16,   0,  15,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   3,   0,   4,   3, \n     42,   0,  16,   0,  18,   0, \n      0,   0,  85,   0,   0,   8, \n     66,   0,  16,   0,  18,   0, \n      0,   0,  10, 144, 144,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n     15,   0,   0,   0,   1,   0, \n      0,   7,  66,   0,  16,   0, \n     18,   0,   0,   0,  42,   0, \n     16,   0,  18,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  32,   0,   0,   7, \n    130,   0,  16,   0,  18,   0, \n      0,   0,  42,   0,  16,   0, \n     18,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     31,   0,   4,   3,  58,   0, \n     16,   0,  18,   0,   0,   0, \n    167,   0,   0,   9, 242,   0, \n     16,   0,  19,   0,   0,   0, \n     58,   0,  16,   0,  15,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   7, 242,   0, \n     16,   0,  19,   0,   0,   0, \n     70,  14,  16,   0,  23,   0, \n      0,   0,  70,  14,  16,   0, \n     19,   0,   0,   0,  38,   0, \n      0,   8,   0, 208,   0,   0, \n     50,   0,  16,   0,  19,   0, \n      0,   0,  70,   0,  16,   0, \n     19,   0,   0,   0,  70,   0, \n     16,   0,  21,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,  19,   0,   0,   0, \n     26,   0,  16,   0,  19,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  35,   0, \n      0,   9,  18,   0,  16,   0, \n     19,   0,   0,   0,  42,   0, \n     16,   0,  21,   0,   0,   0, \n     42,   0,  16,   0,  19,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  35,   0, \n      0,   9,  18,   0,  16,   0, \n     19,   0,   0,   0,  58,   0, \n     16,   0,  21,   0,   0,   0, \n     58,   0,  16,   0,  19,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  33,   0, \n      0,   7,  34,   0,  16,   0, \n     19,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     10,   0,  16,   0,  19,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  26,   0, \n     16,   0,  19,   0,   0,   0, \n     34,   0,   0,   7,  66,   0, \n     16,   0,  19,   0,   0,   0, \n     10,   0,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n     13,   0,   0,   0,  43,   0, \n      0,   5,  18,   0,  16,   0, \n     19,   0,   0,   0,  10,   0, \n     16,   0,  19,   0,   0,   0, \n     56,   0,   0,   7,  18,   0, \n     16,   0,  19,   0,   0,   0, \n     10,   0,  16,   0,  19,   0, \n      0,   0,   1,  64,   0,   0, \n    253, 255, 125,  66,  14,   0, \n      0,   7,  18,   0,  16,   0, \n     19,   0,   0,   0,  10,   0, \n     16,   0,  19,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  28,   0,   0,   5, \n     18,   0,  16,   0,  19,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n     19,   0,   0,   0,  10,   0, \n     16,   0,  19,   0,   0,   0, \n     26,   0,  16,   0,  22,   0, \n      0,   0,  55,   0,   0,  10, \n     18,   0,  16,   0,  19,   0, \n      0,   0,  42,   0,  16,   0, \n     19,   0,   0,   0,  58, 144, \n    144,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  42,   0, \n     16,   0,  22,   0,   0,   0, \n     55,   0,   0,   9,  18,   0, \n     16,   0,  19,   0,   0,   0, \n     26,   0,  16,   0,  19,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,  19,   0,   0,   0, \n     18,   0,   0,   1, 167,   0, \n      0,   9, 242,   0,  16,   0, \n     25,   0,   0,   0,  58,   0, \n     16,   0,  15,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   7, 242,   0,  16,   0, \n     25,   0,   0,   0,  70,  14, \n     16,   0,  24,   0,   0,   0, \n     70,  14,  16,   0,  25,   0, \n      0,   0,  38,   0,   0,   8, \n      0, 208,   0,   0,  98,   0, \n     16,   0,  19,   0,   0,   0, \n      6,   1,  16,   0,  20,   0, \n      0,   0,   6,   1,  16,   0, \n     25,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n     19,   0,   0,   0,  42,   0, \n     16,   0,  19,   0,   0,   0, \n     26,   0,  16,   0,  19,   0, \n      0,   0,  35,   0,   0,   9, \n     34,   0,  16,   0,  19,   0, \n      0,   0,  42,   0,  16,   0, \n     20,   0,   0,   0,  42,   0, \n     16,   0,  25,   0,   0,   0, \n     26,   0,  16,   0,  19,   0, \n      0,   0,  35,   0,   0,   9, \n     34,   0,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n     20,   0,   0,   0,  58,   0, \n     16,   0,  25,   0,   0,   0, \n     26,   0,  16,   0,  19,   0, \n      0,   0,  33,   0,   0,   7, \n     66,   0,  16,   0,  19,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,  19,   0,   0,   0, \n     60,   0,   0,   7,  66,   0, \n     16,   0,  19,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n     19,   0,   0,   0,  34,   0, \n      0,   7, 130,   0,  16,   0, \n     19,   0,   0,   0,  26,   0, \n     16,   0,  19,   0,   0,   0, \n     58,   0,  16,   0,  12,   0, \n      0,   0,  43,   0,   0,   5, \n     34,   0,  16,   0,  19,   0, \n      0,   0,  26,   0,  16,   0, \n     19,   0,   0,   0,  56,   0, \n      0,   7,  34,   0,  16,   0, \n     19,   0,   0,   0,  26,   0, \n     16,   0,  19,   0,   0,   0, \n      1,  64,   0,   0, 253, 255, \n    125,  66,  14,   0,   0,   7, \n     34,   0,  16,   0,  19,   0, \n      0,   0,  26,   0,  16,   0, \n     19,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     28,   0,   0,   5,  34,   0, \n     16,   0,  19,   0,   0,   0, \n     26,   0,  16,   0,  19,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,  19,   0, \n      0,   0,  26,   0,  16,   0, \n     19,   0,   0,   0,  26,   0, \n     16,   0,  22,   0,   0,   0, \n     55,   0,   0,  10,  34,   0, \n     16,   0,  19,   0,   0,   0, \n     58,   0,  16,   0,  19,   0, \n      0,   0,  58, 144, 144,   0, \n     26,   0,  16,   0,  19,   0, \n      0,   0,  42,   0,  16,   0, \n     22,   0,   0,   0,  55,   0, \n      0,   9,  18,   0,  16,   0, \n     19,   0,   0,   0,  42,   0, \n     16,   0,  19,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n     19,   0,   0,   0,  21,   0, \n      0,   1,  30,   0,   0,   7, \n     18,   0,  16,   0,  19,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  10,   0, \n     16,   0,  22,   0,   0,   0, \n     30,   0,   0,  10,  34,   0, \n     16,   0,  19,   0,   0,   0, \n      1,  64,   0,   0,  64,   0, \n      0,   0,  10, 144, 208, 128, \n     65,   0,   0,   0,  64,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  41,   0, \n      0,   7,  66,   0,  16,   0, \n     18,   0,   0,   0,  42,   0, \n     16,   0,  18,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  54,   0,   0,   7, \n     18,   0,  16,   0,  25,   0, \n      0,   0,  10,  48,  32,   4, \n      0,   0,   0,   0,  42,   0, \n     16,   0,  18,   0,   0,   0, \n     54,   0,   0,   8,  34,   0, \n     16,   0,  25,   0,   0,   0, \n     10,  48,  32,   6,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,  18,   0, \n      0,   0,  54,   0,   0,   8, \n     66,   0,  16,   0,  25,   0, \n      0,   0,  10,  48,  32,   6, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n     18,   0,   0,   0,  54,   0, \n      0,   8, 130,   0,  16,   0, \n     25,   0,   0,   0,  10,  48, \n     32,   6,   0,   0,   0,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,  18,   0,   0,   0, \n     54,   0,   0,   7,  18,   0, \n     16,   0,  26,   0,   0,   0, \n     26,  48,  32,   4,   0,   0, \n      0,   0,  42,   0,  16,   0, \n     18,   0,   0,   0,  54,   0, \n      0,   8,  34,   0,  16,   0, \n     26,   0,   0,   0,  26,  48, \n     32,   6,   0,   0,   0,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,  18,   0,   0,   0, \n     54,   0,   0,   8,  66,   0, \n     16,   0,  26,   0,   0,   0, \n     26,  48,  32,   6,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,  18,   0, \n      0,   0,  54,   0,   0,   8, \n    130,   0,  16,   0,  26,   0, \n      0,   0,  26,  48,  32,   6, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  42,   0,  16,   0, \n     18,   0,   0,   0,  38,   0, \n      0,  10,   0, 208,   0,   0, \n    242,   0,  16,   0,  26,   0, \n      0,   0,  70,  14,  16,   0, \n     26,   0,   0,   0,   6, 144, \n    208,   0,  64,   0,   0,   0, \n     10,   0,  16,   0,  19,   0, \n      0,   0,  35,   0,   0,   9, \n    242,   0,  16,   0,  19,   0, \n      0,   0,  86,   5,  16,   0, \n     19,   0,   0,   0,  70,  14, \n     16,   0,  25,   0,   0,   0, \n     70,  14,  16,   0,  26,   0, \n      0,   0,  30,   0,   0,  10, \n    242,   0,  16,   0,  19,   0, \n      0,   0,  70,  14,  16,   0, \n     19,   0,   0,   0,   2,  64, \n      0,   0,  32,   0,   0,   0, \n     32,   0,   0,   0,  32,   0, \n      0,   0,  32,   0,   0,   0, \n     85,   0,   0,   7, 242,   0, \n     16,   0,  19,   0,   0,   0, \n    134,  13,  16,   0,  19,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  55,   0, \n      0,   9, 130,   0,  16,   0, \n     19,   0,   0,   0,  26,   0, \n     16,   0,  18,   0,   0,   0, \n      1,  64,   0,   0, 255,   0, \n      0,   0,  58,   0,  16,   0, \n     19,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n     25,   0,   0,   0,  58,   0, \n     16,   0,  15,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  79,   0, \n      0,   7, 114,   0,  16,   0, \n     26,   0,   0,   0, 134,   1, \n     16,   0,  19,   0,   0,   0, \n     70,   2,  16,   0,  25,   0, \n      0,   0,  54,   0,   0,   5, \n     82,   0,  16,   0,  27,   0, \n      0,   0,   6,   1,  16,   0, \n     25,   0,   0,   0,  54,   0, \n      0,   5, 162,   0,  16,   0, \n     27,   0,   0,   0,   6,   8, \n     16,   0,  19,   0,   0,   0, \n     55,   0,   0,   9, 242,   0, \n     16,   0,  27,   0,   0,   0, \n      6,   5,  16,   0,  26,   0, \n      0,   0,  70,  14,  16,   0, \n     27,   0,   0,   0,  22,  11, \n     16,   0,  27,   0,   0,   0, \n     54,   0,   0,   5,  82,   0, \n     16,   0,  19,   0,   0,   0, \n    166,  11,  16,   0,  25,   0, \n      0,   0,  55,   0,   0,   9, \n     50,   0,  16,   0,  19,   0, \n      0,   0, 166,  10,  16,   0, \n     26,   0,   0,   0,  70,   0, \n     16,   0,  19,   0,   0,   0, \n     22,   5,  16,   0,  19,   0, \n      0,   0,  79,   0,   0,   7, \n     66,   0,  16,   0,  18,   0, \n      0,   0,  58,   0,  16,   0, \n     19,   0,   0,   0,  58,   0, \n     16,   0,  25,   0,   0,   0, \n     55,   0,   0,   9, 146,   0, \n     16,   0,  25,   0,   0,   0, \n    166,  10,  16,   0,  18,   0, \n      0,   0, 246,  11,  16,   0, \n     19,   0,   0,   0, 166,  14, \n     16,   0,  19,   0,   0,   0, \n     40,   0,   0,   5,  50,   0, \n     16,   0,  26,   0,   0,   0, \n    214,   5,  16,   0,  27,   0, \n      0,   0,  40,   0,   0,   5, \n     66,   0,  16,   0,  26,   0, \n      0,   0,  26,   0,  16,   0, \n     19,   0,   0,   0,  40,   0, \n      0,   5, 130,   0,  16,   0, \n     26,   0,   0,   0,  10,   0, \n     16,   0,  25,   0,   0,   0, \n     54,   0,   0,   5,  50,   0, \n     16,   0,  25,   0,   0,   0, \n    134,   0,  16,   0,  27,   0, \n      0,   0,  54,   0,   0,   5, \n     66,   0,  16,   0,  25,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  30,   0, \n      0,   7, 242,   0,  16,   0, \n     19,   0,   0,   0,  70,  14, \n     16,   0,  26,   0,   0,   0, \n     70,  14,  16,   0,  25,   0, \n      0,   0,  38,   0,   0,   8, \n      0, 208,   0,   0,  50,   0, \n     16,   0,  19,   0,   0,   0, \n     70,   0,  16,   0,  19,   0, \n      0,   0,  70,   0,  16,   0, \n     19,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n     18,   0,   0,   0,  26,   0, \n     16,   0,  19,   0,   0,   0, \n     10,   0,  16,   0,  19,   0, \n      0,   0,  35,   0,   0,   9, \n     66,   0,  16,   0,  18,   0, \n      0,   0,  42,   0,  16,   0, \n     19,   0,   0,   0,  42,   0, \n     16,   0,  19,   0,   0,   0, \n     42,   0,  16,   0,  18,   0, \n      0,   0,  86,   0,   0,   5, \n     66,   0,  16,   0,  18,   0, \n      0,   0,  42,   0,  16,   0, \n     18,   0,   0,   0,  86,   0, \n      0,   5,  18,   0,  16,   0, \n     19,   0,   0,   0,  58,   0, \n     16,   0,  19,   0,   0,   0, \n     56,   0,   0,   7,  18,   0, \n     16,   0,  19,   0,   0,   0, \n     10,   0,  16,   0,  19,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  50,   0, \n      0,  10,  66,   0,  16,   0, \n     18,   0,   0,   0,  10,   0, \n     16,   0,  19,   0,   0,   0, \n     42, 128,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     42,   0,  16,   0,  18,   0, \n      0,   0,  28,   0,   0,   5, \n     66,   0,  16,   0,  18,   0, \n      0,   0,  42,   0,  16,   0, \n     18,   0,   0,   0,  54,   0, \n      0,   6,  18,   0,  16,   0, \n     19,   0,   0,   0,  10,  48, \n     32,   0,   3,   0,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n     19,   0,   0,   0,  42,   0, \n     16,   0,  18,   0,   0,   0, \n     10,   0,  16,   0,  19,   0, \n      0,   0,  55,   0,   0,   9, \n     18,   0,  16,   0,  19,   0, \n      0,   0,  58,   0,  16,   0, \n     18,   0,   0,   0,  26,   0, \n     16,   0,  19,   0,   0,   0, \n     10,   0,  16,   0,  19,   0, \n      0,   0,  54,   0,   0,   6, \n     18,  48,  32,   0,   3,   0, \n      0,   0,   1,   0,   0,   0, \n     10,   0,  16,   0,  19,   0, \n      0,   0,  54,   0,   0,   6, \n     18,   0,  16,   0,  19,   0, \n      0,   0,  10,  48,  32,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,  18,   0, \n      0,   0,  42,   0,  16,   0, \n     18,   0,   0,   0,  10,   0, \n     16,   0,  19,   0,   0,   0, \n     55,   0,   0,   9,  66,   0, \n     16,   0,  18,   0,   0,   0, \n     58,   0,  16,   0,  18,   0, \n      0,   0,  10,   0,  16,   0, \n     19,   0,   0,   0,  42,   0, \n     16,   0,  18,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,  18,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,  15,   0,   0,   0, \n     58,   0,  16,   0,  15,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,  54,   0,   0,   6, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  10,  48,  32,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  10,  48,  32,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,  79,   0,   0,   7, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     84,   0,   0,   7, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      7,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      6,   0,   0,   0,  10,  48, \n     32,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,  55,   0, \n      0,   9, 130,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   8,   0,   0,   0, \n     10,   0,  16,   0,  18,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   6,  18,  48,  32,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      6,   0,   0,   0,  10,  48, \n     32,   0,   3,   0,   0,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      7,   0,   0,   0,  10,  48, \n     32,   0,   2,   0,   0,   0, \n      1,   0,   0,   0,  79,   0, \n      0,   7, 130,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   7,   0, \n      0,   0,  84,   0,   0,   7, \n    130,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   2,   0,   0,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     54,   0,   0,   6, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     10,  48,  32,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n     55,   0,   0,   9, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  10,   0,  16,   0, \n     18,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     54,   0,   0,   6,  18,  48, \n     32,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,  58,   0, \n     16,   0,   6,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,  18,   0,   0,   0, \n     10,   0,  16,   0,  18,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,  54,   0,   0,   6, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  10,  48,  32,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,  54,   0,   0,   6, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,  48,  32,   0, \n      2,   0,   0,   0,   1,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     58, 128,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   4,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  64,   2,   0, 168,   0, \n      0,   8, 114, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70,   2, \n     16,   0,   2,   0,   0,   0, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  48,  32,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   6,  66,   0,  16,   0, \n      0,   0,   0,   0,  10,  48, \n     32,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,  18,   0,   0,   1, \n     54,   0,   0,   6,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  48,  32,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n     41,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   6, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,  48, \n     32,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,  60,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,  21,   0,   0,   1, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  32,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0, 190,  24,   0,   1, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  32,   0,   0,   0, \n    167,   0,   0,   9, 226,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 249, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     79,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8, 114, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0, 134,   3, \n     16,   0,   3,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  32,   0,   0,   0, \n     10,   0,  16,   0,   4,   0, \n      0,   0,  21,   0,   0,   1, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  31,   0,   4,   3, \n     10,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   8, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0, 167,   0, \n      0,   9, 226,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 249,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  32,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  79,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   3,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,  31,   0,   4,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0, 168,   0,   0,   8, \n    114, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0, 134,   3,  16,   0, \n      3,   0,   0,   0, 168,   0, \n      0,   8,  18, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n     21,   0,   0,   1,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   8,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   8,   0, \n      0,   0, 167,   0,   0,   9, \n    226,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 249,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  32,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  79,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    168,   0,   0,   8, 114, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n    134,   3,  16,   0,   3,   0, \n      0,   0, 168,   0,   0,   8, \n     18, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  32,   0, \n      0,   0,  10,   0,  16,   0, \n      4,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  58,   0,  16,   0, \n      1,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n    167,   0,   0,   9, 226,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 249, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     79,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8, 114, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0, 134,   3, \n     16,   0,   2,   0,   0,   0, \n    168,   0,   0,   8,  18, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  32,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  21,   0,   0,   1, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  79,   0,   0,   9, \n     98,   0,  16,   0,   0,   0, \n      0,   0,   6,  64,   2,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   8, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9, 226,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 249,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  32,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  79,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  31,   0,   4,   3, \n     58,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0, 168,   0,   0,   8, \n    114, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0, 134,   3,  16,   0, \n      2,   0,   0,   0, 168,   0, \n      0,   8,  18, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     21,   0,   0,   1,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   8,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n    226,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 249,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  32,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  79,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    168,   0,   0,   8, 114, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n    134,   3,  16,   0,   2,   0, \n      0,   0, 168,   0,   0,   8, \n     18, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  32,   0, \n      0,   0,  10,   0,  16,   0, \n      3,   0,   0,   0,  21,   0, \n      0,   1, 167,   0,   0,   9, \n     18,   0,  16,   0,   1,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n      6, 112,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   8, \n     18,   0,  16,   0,   2,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  79,   0, \n      0,   7,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   8, \n    114,   0,  16,   0,   1,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  70, 242,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   8, 130,   0,  16,   0, \n      1,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     18,   0,   0,   1, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  70, 126,  16,   0, \n      1,   0,   0,   0,  21,   0, \n      0,   1, 168,   0,   0,   9, \n    242, 224,  17,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70,  14,  16,   0,   1,   0, \n      0,   0,  21,   0,   0,   1, \n     62,   0,   0,   1\n};\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/Shaders/Compiled/BC7Encode_TryMode456CS.inc",
    "content": "#if 0\n//\n// Generated by Microsoft (R) D3D Shader Disassembler\n//\n//\n// Input signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Input\n//\n// Output signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// no Output\ncs_4_0\ndcl_globalFlags refactoringAllowed\ndcl_immediateConstantBuffer { { 0, 0, 0, 0},\n                              { 0, 4, 0, 0},\n                              { 0, 9, 0, 0},\n                              { 1, 13, 0, 0},\n                              { 1, 17, 0, 0},\n                              { 1, 21, 0, 0},\n                              { 1, 26, 0, 0},\n                              { 2, 30, 0, 0},\n                              { 2, 34, 0, 0},\n                              { 2, 38, 0, 0},\n                              { 2, 43, 0, 0},\n                              { 2, 47, 0, 0},\n                              { 3, 51, 0, 0},\n                              { 3, 55, 0, 0},\n                              { 3, 60, 0, 0},\n                              { 3, 64, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 9, 0, 0},\n                              { 4, 18, 0, 0},\n                              { 4, 27, 0, 0},\n                              { 5, 37, 0, 0},\n                              { 5, 46, 0, 0},\n                              { 5, 55, 0, 0},\n                              { 5, 64, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 7, 0, 0, 0},\n                              { 7, 0, 0, 0},\n                              { 7, 0, 0, 0},\n                              { 7, 0, 0, 0},\n                              { 8, 21, 0, 0},\n                              { 8, 43, 0, 0},\n                              { 8, 64, 0, 0},\n                              { 8, 0, 0, 0},\n                              { 9, 0, 0, 0},\n                              { 9, 0, 0, 0},\n                              { 9, 0, 0, 0},\n                              { 9, 0, 0, 0},\n                              { 10, 0, 0, 0},\n                              { 10, 0, 0, 0},\n                              { 10, 0, 0, 0},\n                              { 10, 0, 0, 0},\n                              { 10, 0, 0, 0},\n                              { 11, 0, 0, 0},\n                              { 11, 0, 0, 0},\n                              { 11, 0, 0, 0},\n                              { 11, 0, 0, 0},\n                              { 12, 0, 0, 0},\n                              { 12, 0, 0, 0},\n                              { 12, 0, 0, 0},\n                              { 12, 0, 0, 0},\n                              { 13, 0, 0, 0},\n                              { 13, 0, 0, 0},\n                              { 13, 0, 0, 0},\n                              { 13, 0, 0, 0},\n                              { 14, 0, 0, 0},\n                              { 14, 0, 0, 0},\n                              { 14, 0, 0, 0},\n                              { 14, 0, 0, 0},\n                              { 15, 0, 0, 0},\n                              { 15, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 4, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 5, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 6, 0, 0, 0},\n                              { 7, 0, 0, 0},\n                              { 7, 0, 0, 0},\n                              { 7, 0, 0, 0},\n                              { 7, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 0, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 1, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 2, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0},\n                              { 3, 0, 0, 0} }\ndcl_constantbuffer CB0[2], immediateIndexed\ndcl_resource_texture2d (float,float,float,float) t0\ndcl_uav_structured u0, 16\ndcl_input vThreadIDInGroupFlattened\ndcl_input vThreadGroupID.x\ndcl_temps 19\ndcl_tgsm_structured g0, 100, 64\ndcl_thread_group 64, 1, 1\nushr r0.x, vThreadIDInGroupFlattened.x, l(4)\nishl r0.y, vThreadGroupID.x, l(2)\niadd r0.y, r0.y, cb0[1].x\niadd r0.x, r0.x, r0.y\nand r0.y, vThreadIDInGroupFlattened.x, l(48)\niadd r0.z, -r0.y, vThreadIDInGroupFlattened.x\nult r1.xyzw, r0.zzzz, l(16, 8, 4, 2)\nif_nz r1.x\n  udiv r0.w, null, r0.x, cb0[0].y\n  imad r2.x, -r0.w, cb0[0].y, r0.x\n  ishl r2.x, r2.x, l(2)\n  ishl r0.w, r0.w, l(2)\n  and r2.y, r0.z, l(3)\n  iadd r2.x, r2.y, r2.x\n  ushr r3.x, r0.z, l(2)\n  iadd r2.y, r0.w, r3.x\n  mov r2.zw, l(0,0,0,0)\n  ld r2.xyzw, r2.xyzw, t0.xyzw\n  mul r2.xyzw, r2.xyzw, l(255.000000, 255.000000, 255.000000, 255.000000)\n  ftou r2.xyzw, r2.xyzw\n  umin r2.xyzw, r2.xyzw, l(255, 255, 255, 255)\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(0), r2.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r2.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r2.xyzw\nendif \nsync_g_t\nif_nz r1.y\n  ld_structured r2.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r3.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(8)\n  ld_structured r4.xyzw, r0.w, l(36), g0.xyzw\n  ld_structured r5.xyzw, r0.w, l(52), g0.xyzw\n  umin r2.xyzw, r2.xyzw, r4.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r2.xyzw\n  umax r2.xyzw, r3.xyzw, r5.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r2.xyzw\nendif \nsync_g_t\nif_nz r1.z\n  ld_structured r2.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r3.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(4)\n  ld_structured r4.xyzw, r0.w, l(36), g0.xyzw\n  ld_structured r5.xyzw, r0.w, l(52), g0.xyzw\n  umin r2.xyzw, r2.xyzw, r4.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r2.xyzw\n  umax r2.xyzw, r3.xyzw, r5.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r2.xyzw\nendif \nsync_g_t\nif_nz r1.w\n  ld_structured r2.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r3.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(2)\n  ld_structured r4.xyzw, r0.w, l(36), g0.xyzw\n  ld_structured r5.xyzw, r0.w, l(52), g0.xyzw\n  umin r2.xyzw, r2.xyzw, r4.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r2.xyzw\n  umax r2.xyzw, r3.xyzw, r5.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r2.xyzw\nendif \nsync_g_t\nult r2.xy, r0.zzzz, l(1, 12, 0, 0)\nif_nz r2.x\n  ld_structured r3.xyzw, vThreadIDInGroupFlattened.x, l(36), g0.xyzw\n  ld_structured r4.xyzw, vThreadIDInGroupFlattened.x, l(52), g0.xyzw\n  iadd r0.w, vThreadIDInGroupFlattened.x, l(1)\n  ld_structured r5.xyzw, r0.w, l(36), g0.xyzw\n  ld_structured r6.xyzw, r0.w, l(52), g0.xyzw\n  umin r3.xyzw, r3.xyzw, r5.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(36), r3.xyzw\n  umax r3.xyzw, r4.xyzw, r6.xyzw\n  store_structured g0.xyzw, vThreadIDInGroupFlattened.x, l(52), r3.xyzw\nendif \nsync_g_t\nld_structured r3.xyzw, r0.y, l(0), g0.xyzw\nld_structured r4.xyzw, r0.y, l(36), g0.xyzw\nld_structured r5.xyzw, r0.y, l(52), g0.xyzw\nand r0.w, r0.z, l(1)\nmovc r6.xyz, r0.wwww, l(1,1,2,0), l(0,2,1,0)\nmovc r6.xyz, r1.yyyy, r6.xyzx, l(0,2,2,0)\nif_nz r2.y\n  ieq r7.xyzw, r0.zzzz, l(8, 9, 10, 11)\n  ult r0.w, r0.z, l(6)\n  or r0.w, r7.z, r0.w\n  or r2.yzw, r1.wwzy, r7.xxyw\n  mov r7.y, r4.z\n  mov r7.w, r5.z\n  mov r7.x, l(3)\n  mov r8.x, r4.w\n  mov r8.y, r5.w\n  mov r8.z, l(0)\n  movc r9.xyz, r2.wwww, r7.ywxy, r8.xyzx\n  movc r10.yw, r2.wwww, r8.xxxy, r7.yyyw\n  mov r11.x, r4.y\n  mov r11.y, r5.y\n  mov r11.z, l(2)\n  movc r9.xyz, r0.wwww, r11.xyzx, r9.xyzx\n  mov r7.xz, r8.xxyx\n  mov r10.xz, r11.xxyx\n  movc r7.xyzw, r0.wwww, r7.xzwy, r10.xzwy\n  mov r10.x, r4.x\n  mov r10.yz, r7.xxwx\n  movc r11.xyz, r2.zzzz, r4.wyzw, r10.xyzx\n  mov r10.y, r5.x\n  mov r10.z, l(1)\n  movc r9.xyz, r2.zzzz, r10.xyzx, r9.xyzx\n  mov r7.x, r10.y\n  movc r7.xyz, r2.zzzz, r5.wyzw, r7.xyzx\n  movc r10.xyz, r2.yyyy, r4.xyzx, r11.xyzx\n  movc r7.xyz, r2.yyyy, r5.xyzx, r7.xyzx\n  movc r2.yzw, r2.yyyy, r8.xxyz, r9.xxyz\n  if_nz r1.y\n    imad r8.xyz, r10.xyzx, l(7967, 7967, 7967, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n    ushr r8.xyz, r8.xyzx, l(16)\n    imad r9.xy, r2.yzyy, l(0x00003f3f, 0x00003f3f, 0, 0), l(0x00008000, 0x00008000, 0, 0)\n    ushr r9.xy, r9.xyxx, l(16)\n    ishl r8.xyz, r8.xyzx, l(3)\n    ushr r11.xyz, r8.xyzx, l(5)\n    or r8.xyz, r8.xyzx, r11.xyzx\n    ishl r9.xy, r9.xyxx, l(2)\n    ushr r9.zw, r9.xxxy, l(6)\n    imad r11.xyz, r7.xyzx, l(7967, 7967, 7967, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n    ushr r11.xyz, r11.xyzx, l(16)\n    ishl r11.xyz, r11.xyzx, l(3)\n    ushr r12.xyz, r11.xyzx, l(5)\n    or r11.xyz, r11.xyzx, r12.xyzx\n    or r9.xy, r9.zwzz, r9.xyxx\n    mov r11.w, r9.y\n    mov r12.y, l(4)\n  else \n    imad r10.xyz, r10.xyzx, l(0x00007f7f, 0x00007f7f, 0x00007f7f, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n    ushr r10.xyz, r10.xyzx, l(16)\n    ishl r10.xyz, r10.xyzx, l(1)\n    ushr r13.xyz, r10.xyzx, l(7)\n    or r8.xyz, r10.xyzx, r13.xyzx\n    imad r7.xyz, r7.xyzx, l(0x00007f7f, 0x00007f7f, 0x00007f7f, 0), l(0x00008000, 0x00008000, 0x00008000, 0)\n    ushr r7.xyz, r7.xyzx, l(16)\n    ishl r7.xyz, r7.xyzx, l(1)\n    ushr r10.xyz, r7.xyzx, l(7)\n    or r11.xyz, r7.xyzx, r10.xyzx\n    mov r9.x, r2.y\n    mov r11.w, r2.z\n    mov r12.y, l(5)\n  endif \n  ieq r7.xyz, r2.wwww, l(1, 2, 3, 0)\n  movc r10.zw, r7.zzzz, r3.wwwz, r3.zzzw\n  mov r10.xy, r3.xyxx\n  movc r10.yzw, r7.yyyy, r3.wwzy, r10.yyzw\n  movc r10.xyzw, r7.xxxx, r3.wyzx, r10.xyzw\n  ineg r13.xyz, r8.xyzx\n  ineg r13.w, r9.x\n  iadd r14.xyzw, r11.xyzw, r13.xyzw\n  imul null, r15.xyz, r14.xywx, r14.xywx\n  iadd r0.w, r15.y, r15.x\n  imad r0.w, r14.z, r14.z, r0.w\n  iadd r13.xyzw, r10.xyzw, r13.xyzw\n  imul null, r13.xyw, r13.xyxw, r13.xyxw\n  iadd r2.y, r13.y, r13.x\n  imad r2.y, r13.z, r13.z, r2.y\n  iadd r10.xyzw, -r11.xyzw, r10.xyzw\n  imul null, r10.xyw, r10.xyxw, r10.xyxw\n  iadd r2.z, r10.y, r10.x\n  imad r2.z, r10.z, r10.z, r2.z\n  ilt r2.y, r2.z, r2.y\n  ineg r16.xyzw, r14.xyzw\n  movc r10.xyz, r2.yyyy, r11.xyzx, r8.xyzx\n  movc r8.xyz, r2.yyyy, r8.xyzx, r11.xyzx\n  movc r11.xyz, r2.yyyy, r16.xyzx, r14.xyzx\n  ilt r2.y, r10.w, r13.w\n  mov r9.y, r11.w\n  mov r9.z, r16.w\n  mov r9.w, r14.w\n  movc r9.xyz, r2.yyyy, r9.yxzy, r9.xywx\n  ige r2.y, l(0), r0.w\n  itof r2.z, r0.w\n  ishl r12.zw, r6.yyyz, l(6)\n  ishl r6.yz, r6.yyzy, l(4)\n  iadd r13.xy, r12.zwzz, l(11, 11, 0, 0)\n  ige r7.w, l(0), r15.z\n  itof r8.w, r15.z\n  udiv null, r13.xy, r13.xyxx, l(68, 68, 0, 0)\n  mov r13.zw, l(0,0,0,0)\n  loop \n    uge r9.w, r13.w, l(16)\n    breakc_nz r9.w\n    iadd r9.w, r0.y, r13.w\n    ld_structured r14.xyzw, r9.w, l(0), g0.xyzw\n    movc r16.zw, r7.zzzz, r14.wwwz, r14.zzzw\n    mov r16.xy, r14.xyxx\n    movc r16.yzw, r7.yyyy, r14.wwzy, r16.yyzw\n    movc r14.xyzw, r7.xxxx, r14.wyzx, r16.xyzw\n    iadd r15.xyw, -r10.xyxz, r14.xyxz\n    imul null, r15.xy, r11.xyxx, r15.xyxx\n    iadd r9.w, r15.y, r15.x\n    imad r9.w, r11.z, r15.w, r9.w\n    ige r10.w, l(0), r9.w\n    or r10.w, r2.y, r10.w\n    ilt r11.w, r9.w, r0.w\n    itof r9.w, r9.w\n    mul r9.w, r9.w, l(63.499989)\n    div r9.w, r9.w, r2.z\n    ftou r9.w, r9.w\n    iadd r9.w, r9.w, r12.z\n    movc r9.w, r11.w, icb[r9.w + 0].x, r13.x\n    movc r9.w, r10.w, l(0), r9.w\n    iadd r10.w, -r9.x, r14.w\n    imul null, r10.w, r9.z, r10.w\n    ige r11.w, l(0), r10.w\n    or r11.w, r7.w, r11.w\n    ilt r15.x, r10.w, r15.z\n    itof r10.w, r10.w\n    mul r10.w, r10.w, l(63.499989)\n    div r10.w, r10.w, r8.w\n    ftou r10.w, r10.w\n    iadd r10.w, r10.w, r12.w\n    movc r10.w, r15.x, icb[r10.w + 0].x, r13.y\n    movc r10.w, r11.w, l(0), r10.w\n    iadd r9.w, r6.y, r9.w\n    iadd r11.w, l(64), -icb[r9.w + 0].y\n    imul null, r15.xyw, r8.xyxz, icb[r9.w + 0].yyyy\n    imad r15.xyw, r11.wwww, r10.xyxz, r15.xyxw\n    iadd r15.xyw, r15.xyxw, l(32, 32, 0, 32)\n    ushr r16.xyw, r15.xyxw, l(6)\n    iadd r9.w, r6.z, r10.w\n    iadd r10.w, l(64), -icb[r9.w + 0].y\n    imul null, r9.w, r9.y, icb[r9.w + 0].y\n    imad r9.w, r10.w, r9.x, r9.w\n    iadd r9.w, r9.w, l(32)\n    ushr r15.y, r9.w, l(6)\n    ult r17.xyz, r16.xywx, r14.xyzx\n    mov r16.z, r14.x\n    movc r17.xw, r17.xxxx, r16.zzzx, r16.xxxz\n    mov r16.xz, r14.yyzy\n    movc r16.xyzw, r17.yyzz, r16.xyzw, r16.yxwz\n    ult r9.w, r15.y, r14.w\n    mov r15.x, r14.w\n    movc r14.xy, r9.wwww, r15.xyxx, r15.yxyy\n    ineg r18.w, r17.w\n    ineg r18.yz, r16.yywy\n    ineg r18.x, r14.y\n    mov r14.w, r17.x\n    mov r14.yz, r16.xxzx\n    iadd r14.xyzw, r18.xyzw, r14.xyzw\n    movc r16.zw, r7.zzzz, r14.xxxz, r14.zzzx\n    mov r16.xy, r14.wyww\n    movc r16.yzw, r7.yyyy, r14.xxzy, r16.yyzw\n    movc r14.xyzw, r7.xxxx, r14.xyzw, r16.xyzw\n    imul null, r14.xy, r14.xyxx, r14.xyxx\n    iadd r9.w, r14.y, r14.x\n    imad r9.w, r14.z, r14.z, r9.w\n    utof r9.w, r9.w\n    utof r10.w, r14.w\n    mul r10.w, r10.w, r10.w\n    mad r9.w, r10.w, cb0[1].z, r9.w\n    ftou r9.w, r9.w\n    iadd r13.z, r9.w, r13.z\n    iadd r13.w, r13.w, l(1)\n  endloop \n  mov r12.x, r13.z\n  mov r6.w, r2.w\nelse \n  if_nz r1.x\n    iadd r7.x, r0.z, l(-12)\n    ushr r7.y, r7.x, l(1)\n    and r0.zw, r7.xxxy, l(0, 0, 1, 1)\n    and r4.xyzw, r4.xyzw, l(-2, -2, -2, -2)\n    iadd r4.xyzw, r0.zzzz, r4.xyzw\n    and r5.xyzw, r5.xyzw, l(-2, -2, -2, -2)\n    iadd r5.xyzw, r0.wwww, r5.xyzw\n    iadd r8.xyzw, -r4.xyzw, r5.xyzw\n    imul null, r0.zw, r8.xxxy, r8.xxxy\n    iadd r0.z, r0.w, r0.z\n    imad r0.z, r8.z, r8.z, r0.z\n    imad r0.z, r8.w, r8.w, r0.z\n    iadd r3.xyzw, r3.xyzw, -r4.xyzw\n    imul null, r2.yz, r3.xxyx, r8.xxyx\n    iadd r0.w, r2.z, r2.y\n    imad r0.w, r8.z, r3.z, r0.w\n    imad r0.w, r8.w, r3.w, r0.w\n    ilt r1.x, l(0), r0.z\n    ige r2.y, r0.w, l(0)\n    and r1.x, r1.x, r2.y\n    itof r0.w, r0.w\n    mul r0.w, r0.w, l(63.499989)\n    ftou r0.w, r0.w\n    ishl r2.y, r0.z, l(5)\n    ult r0.w, r2.y, r0.w\n    and r0.w, r0.w, r1.x\n    ineg r3.xyzw, r8.xyzw\n    movc r9.xyzw, r0.wwww, r5.xyzw, r4.xyzw\n    movc r4.xyzw, r0.wwww, r4.xyzw, r5.xyzw\n    movc r3.xyzw, r0.wwww, r3.xyzw, r8.xyzw\n    ige r0.w, l(0), r0.z\n    itof r1.x, r0.z\n    mov r12.xy, l(0,0,0,0)\n    loop \n      uge r2.y, r12.y, l(16)\n      breakc_nz r2.y\n      iadd r2.y, r0.y, r12.y\n      ld_structured r5.xyzw, r2.y, l(0), g0.xyzw\n      iadd r8.xyzw, -r9.xyzw, r5.xyzw\n      imul null, r2.yz, r3.xxyx, r8.xxyx\n      iadd r2.y, r2.z, r2.y\n      imad r2.y, r3.z, r8.z, r2.y\n      imad r2.y, r3.w, r8.w, r2.y\n      ige r2.z, l(0), r2.y\n      or r2.z, r0.w, r2.z\n      ilt r2.w, r2.y, r0.z\n      itof r2.y, r2.y\n      mul r2.y, r2.y, l(63.499989)\n      div r2.y, r2.y, r1.x\n      ftou r2.y, r2.y\n      movc r2.y, r2.w, icb[r2.y + 0].x, l(15)\n      movc r2.y, r2.z, l(0), r2.y\n      iadd r2.z, l(64), -icb[r2.y + 0].y\n      imul null, r8.xyzw, r4.xyzw, icb[r2.y + 0].yyyy\n      imad r8.xyzw, r2.zzzz, r9.xyzw, r8.xyzw\n      iadd r8.xyzw, r8.xyzw, l(32, 32, 32, 32)\n      ushr r8.xyzw, r8.xzyw, l(6)\n      ult r10.xyzw, r8.xzyw, r5.xyzw\n      mov r11.xz, r5.xxyx\n      mov r11.yw, r8.xxxz\n      movc r11.xyzw, r10.xxyy, r11.xyzw, r11.yxwz\n      mov r8.xz, r5.zzwz\n      movc r5.xyzw, r10.zwzw, r8.ywxz, r8.xzyw\n      ineg r8.xy, r11.ywyy\n      ineg r8.zw, r5.xxxy\n      mov r5.xy, r11.xzxx\n      iadd r5.xyzw, r8.xyzw, r5.xyzw\n      imul null, r2.yz, r5.xxyx, r5.xxyx\n      iadd r2.y, r2.z, r2.y\n      imad r2.y, r5.z, r5.z, r2.y\n      utof r2.y, r2.y\n      utof r2.z, r5.w\n      mul r2.z, r2.z, r2.z\n      mad r2.y, r2.z, cb0[1].z, r2.y\n      ftou r2.y, r2.y\n      iadd r12.x, r2.y, r12.x\n      iadd r12.y, r12.y, l(1)\n    endloop \n    mov r12.y, l(6)\n    mov r6.w, r7.x\n  else \n    mov r12.xy, l(-1,0,0,0)\n    mov r6.w, l(0)\n  endif \nendif \nstore_structured g0.xy, vThreadIDInGroupFlattened.x, l(16), r12.xyxx\nstore_structured g0.xy, vThreadIDInGroupFlattened.x, l(28), r6.xwxx\nsync_g_t\nif_nz r1.y\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(8)\n  ld_structured r3.yz, r0.y, l(16), g0.xxyx\n  ld_structured r4.xy, r0.y, l(28), g0.xyxx\n  ult r0.z, r3.y, r12.x\n  if_nz r0.z\n    ld_structured r3.x, r0.y, l(16), g0.xxxx\n    store_structured g0.xy, vThreadIDInGroupFlattened.x, l(16), r3.xzxx\n    store_structured g0.xy, vThreadIDInGroupFlattened.x, l(28), r4.xyxx\n  endif \nendif \nsync_g_t\nif_nz r1.z\n  ld_structured r3.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(4)\n  ld_structured r4.yz, r0.y, l(16), g0.xxyx\n  ld_structured r5.xy, r0.y, l(28), g0.xyxx\n  ult r0.z, r4.y, r3.x\n  if_nz r0.z\n    ld_structured r4.x, r0.y, l(16), g0.xxxx\n    store_structured g0.xy, vThreadIDInGroupFlattened.x, l(16), r4.xzxx\n    store_structured g0.xy, vThreadIDInGroupFlattened.x, l(28), r5.xyxx\n  endif \nendif \nsync_g_t\nif_nz r1.w\n  ld_structured r1.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(2)\n  ld_structured r3.yz, r0.y, l(16), g0.xxyx\n  ld_structured r4.xy, r0.y, l(28), g0.xyxx\n  ult r0.z, r3.y, r1.x\n  if_nz r0.z\n    ld_structured r3.x, r0.y, l(16), g0.xxxx\n    store_structured g0.xy, vThreadIDInGroupFlattened.x, l(16), r3.xzxx\n    store_structured g0.xy, vThreadIDInGroupFlattened.x, l(28), r4.xyxx\n  endif \nendif \nsync_g_t\nif_nz r2.x\n  ld_structured r1.x, vThreadIDInGroupFlattened.x, l(16), g0.xxxx\n  iadd r0.y, vThreadIDInGroupFlattened.x, l(1)\n  ld_structured r2.yz, r0.y, l(16), g0.xxyx\n  ld_structured r3.xy, r0.y, l(28), g0.xyxx\n  ult r0.z, r2.y, r1.x\n  if_nz r0.z\n    ld_structured r2.x, r0.y, l(16), g0.xxxx\n    store_structured g0.xy, vThreadIDInGroupFlattened.x, l(16), r2.xzxx\n    store_structured g0.xy, vThreadIDInGroupFlattened.x, l(28), r3.xyxx\n  endif \n  ld_structured r1.xw, vThreadIDInGroupFlattened.x, l(28), g0.xxxy\n  ishl r0.y, r1.x, l(31)\n  ld_structured r1.xy, vThreadIDInGroupFlattened.x, l(16), g0.xyxx\n  or r1.y, r0.y, r1.y\n  mov r1.z, l(0)\n  store_structured u0.xyzw, r0.x, l(0), r1.xyzw\nendif \nret \n// Approximately 0 instruction slots used\n#endif\n\nconst BYTE BC7Encode_TryMode456CS[] =\n{\n     68,  88,  66,  67, 147, 174, \n    199, 189,  42,   5, 183, 145, \n    202, 210, 163, 191, 100,  29, \n      3, 141,   1,   0,   0,   0, \n     20,  56,   0,   0,   3,   0, \n      0,   0,  44,   0,   0,   0, \n     60,   0,   0,   0,  76,   0, \n      0,   0,  73,  83,  71,  78, \n      8,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     79,  83,  71,  78,   8,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  83,  72, \n     69,  88, 192,  55,   0,   0, \n     64,   0,   5,   0, 240,  13, \n      0,   0, 106,   8,   0,   1, \n     53,  24,   0,   0,   2,   3, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   9,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     13,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  17,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,  21,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     26,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  34,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     38,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,  43,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,  47,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     51,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,  55,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  60,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n     64,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   9,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n     18,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,  27,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  37,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n     46,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,  55,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,  64,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n     21,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      8,   0,   0,   0,  43,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   8,   0, \n      0,   0,  64,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   8,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      9,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   9,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   9,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      9,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     10,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  10,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     11,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  11,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  11,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     11,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  12,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  12,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     12,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  12,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  13,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     13,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  13,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  13,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     14,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  14,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  14,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     14,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      5,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   5,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   5,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      6,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   6,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   6,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   7,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   7,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      7,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  89,   0,   0,   4, \n     70, 142,  32,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n     88,  24,   0,   4,   0, 112, \n     16,   0,   0,   0,   0,   0, \n     85,  85,   0,   0, 158,   0, \n      0,   4,   0, 224,  17,   0, \n      0,   0,   0,   0,  16,   0, \n      0,   0,  95,   0,   0,   2, \n      0,  64,   2,   0,  95,   0, \n      0,   2,  18,  16,   2,   0, \n    104,   0,   0,   2,  19,   0, \n      0,   0, 160,   0,   0,   5, \n      0, 240,  17,   0,   0,   0, \n      0,   0, 100,   0,   0,   0, \n     64,   0,   0,   0, 155,   0, \n      0,   4,  64,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,  85,   0,   0,   6, \n     18,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   4,   0, \n      0,   0,  41,   0,   0,   6, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,  16,   2,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  30,   0,   0,   8, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  10, 128, \n     32,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  30,   0, \n      0,   7,  18,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,   0,   0,   6, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  48,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16, 128, \n     65,   0,   0,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n     79,   0,   0,  10, 242,   0, \n     16,   0,   1,   0,   0,   0, \n    166,  10,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n     16,   0,   0,   0,   8,   0, \n      0,   0,   4,   0,   0,   0, \n      2,   0,   0,   0,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      1,   0,   0,   0,  78,   0, \n      0,   9, 130,   0,  16,   0, \n      0,   0,   0,   0,   0, 208, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,  26, 128, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  35,   0, \n      0,  11,  18,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16, 128,  65,   0,   0,   0, \n      0,   0,   0,   0,  26, 128, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   0,   0,   0,   0, \n     41,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n      2,   0,   0,   0,  41,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,   1,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      2,   0,   0,   0,  85,   0, \n      0,   7,  18,   0,  16,   0, \n      3,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  10,   0, \n     16,   0,   3,   0,   0,   0, \n     54,   0,   0,   8, 194,   0, \n     16,   0,   2,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  45,   0,   0,   7, \n    242,   0,  16,   0,   2,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,  70, 126, \n     16,   0,   0,   0,   0,   0, \n     56,   0,   0,  10, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   2,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0, 127,  67,   0,   0, \n    127,  67,   0,   0, 127,  67, \n      0,   0, 127,  67,  28,   0, \n      0,   5, 242,   0,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   2,   0,   0,   0, \n     84,   0,   0,  10, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   2,   0, \n      0,   0,   2,  64,   0,   0, \n    255,   0,   0,   0, 255,   0, \n      0,   0, 255,   0,   0,   0, \n    255,   0,   0,   0, 168,   0, \n      0,   8, 242, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  70,  14, \n     16,   0,   2,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70,  14,  16,   0,   2,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   8, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      8,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  84,   0, \n      0,   7, 242,   0,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,  83,   0, \n      0,   7, 242,   0,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   8, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      4,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  84,   0, \n      0,   7, 242,   0,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,  83,   0, \n      0,   7, 242,   0,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   2,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   8, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6, 130,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      4,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      5,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,  84,   0, \n      0,   7, 242,   0,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   2,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,  83,   0, \n      0,   7, 242,   0,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0, 168,   0,   0,   8, \n    242, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70,  14,  16,   0, \n      2,   0,   0,   0,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     79,   0,   0,  10,  50,   0, \n     16,   0,   2,   0,   0,   0, \n    166,  10,  16,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      1,   0,   0,   0,  12,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   8, 242,   0,  16,   0, \n      3,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     36,   0,   0,   0,  70, 254, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   8, 242,   0, \n     16,   0,   4,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   5,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   6,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  84,   0,   0,   7, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  70,  14,  16,   0, \n      3,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  36,   0,   0,   0, \n     70,  14,  16,   0,   3,   0, \n      0,   0,  83,   0,   0,   7, \n    242,   0,  16,   0,   3,   0, \n      0,   0,  70,  14,  16,   0, \n      4,   0,   0,   0,  70,  14, \n     16,   0,   6,   0,   0,   0, \n    168,   0,   0,   8, 242, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  52,   0,   0,   0, \n     70,  14,  16,   0,   3,   0, \n      0,   0,  21,   0,   0,   1, \n    190,  24,   0,   1, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  36,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9, 242,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  52,   0, \n      0,   0,  70, 254,  17,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,  55,   0,   0,  15, \n    114,   0,  16,   0,   6,   0, \n      0,   0, 246,  15,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   2,   0, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,  55,   0,   0,  12, \n    114,   0,  16,   0,   6,   0, \n      0,   0,  86,   5,  16,   0, \n      1,   0,   0,   0,  70,   2, \n     16,   0,   6,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  32,   0,   0,  10, \n    242,   0,  16,   0,   7,   0, \n      0,   0, 166,  10,  16,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   8,   0,   0,   0, \n      9,   0,   0,   0,  10,   0, \n      0,   0,  11,   0,   0,   0, \n     79,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  60,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n    226,   0,  16,   0,   2,   0, \n      0,   0, 246,   6,  16,   0, \n      1,   0,   0,   0,   6,  13, \n     16,   0,   7,   0,   0,   0, \n     54,   0,   0,   5,  34,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   7,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  54,   0, \n      0,   5,  18,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   3,   0,   0,   0, \n     54,   0,   0,   5,  18,   0, \n     16,   0,   8,   0,   0,   0, \n     58,   0,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   5, \n     34,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,  54,   0, \n      0,   5,  66,   0,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   9,   0,   0,   0, \n    246,  15,  16,   0,   2,   0, \n      0,   0, 214,   4,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     55,   0,   0,   9, 162,   0, \n     16,   0,  10,   0,   0,   0, \n    246,  15,  16,   0,   2,   0, \n      0,   0,   6,   4,  16,   0, \n      8,   0,   0,   0,  86,  13, \n     16,   0,   7,   0,   0,   0, \n     54,   0,   0,   5,  18,   0, \n     16,   0,  11,   0,   0,   0, \n     26,   0,  16,   0,   4,   0, \n      0,   0,  54,   0,   0,   5, \n     34,   0,  16,   0,  11,   0, \n      0,   0,  26,   0,  16,   0, \n      5,   0,   0,   0,  54,   0, \n      0,   5,  66,   0,  16,   0, \n     11,   0,   0,   0,   1,  64, \n      0,   0,   2,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   9,   0,   0,   0, \n    246,  15,  16,   0,   0,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     54,   0,   0,   5,  82,   0, \n     16,   0,   7,   0,   0,   0, \n      6,   1,  16,   0,   8,   0, \n      0,   0,  54,   0,   0,   5, \n     82,   0,  16,   0,  10,   0, \n      0,   0,   6,   1,  16,   0, \n     11,   0,   0,   0,  55,   0, \n      0,   9, 242,   0,  16,   0, \n      7,   0,   0,   0, 246,  15, \n     16,   0,   0,   0,   0,   0, \n    134,   7,  16,   0,   7,   0, \n      0,   0, 134,   7,  16,   0, \n     10,   0,   0,   0,  54,   0, \n      0,   5,  18,   0,  16,   0, \n     10,   0,   0,   0,  10,   0, \n     16,   0,   4,   0,   0,   0, \n     54,   0,   0,   5,  98,   0, \n     16,   0,  10,   0,   0,   0, \n      6,   3,  16,   0,   7,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,  11,   0, \n      0,   0, 166,  10,  16,   0, \n      2,   0,   0,   0, 118,  14, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,  10,   0, \n      0,   0,  54,   0,   0,   5, \n     34,   0,  16,   0,  10,   0, \n      0,   0,  10,   0,  16,   0, \n      5,   0,   0,   0,  54,   0, \n      0,   5,  66,   0,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   9,   0,   0,   0, \n    166,  10,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,   9,   0,   0,   0, \n     54,   0,   0,   5,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     26,   0,  16,   0,  10,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,   7,   0, \n      0,   0, 166,  10,  16,   0, \n      2,   0,   0,   0, 118,  14, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,  10,   0, \n      0,   0,  86,   5,  16,   0, \n      2,   0,   0,   0,  70,   2, \n     16,   0,   4,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,  55,   0,   0,   9, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  86,   5,  16,   0, \n      2,   0,   0,   0,  70,   2, \n     16,   0,   5,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,  55,   0,   0,   9, \n    226,   0,  16,   0,   2,   0, \n      0,   0,  86,   5,  16,   0, \n      2,   0,   0,   0,   6,   9, \n     16,   0,   8,   0,   0,   0, \n      6,   9,  16,   0,   9,   0, \n      0,   0,  31,   0,   4,   3, \n     26,   0,  16,   0,   1,   0, \n      0,   0,  35,   0,   0,  15, \n    114,   0,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,   2,  64, \n      0,   0,  31,  31,   0,   0, \n     31,  31,   0,   0,  31,  31, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     35,   0,   0,  15,  50,   0, \n     16,   0,   9,   0,   0,   0, \n    150,   5,  16,   0,   2,   0, \n      0,   0,   2,  64,   0,   0, \n     63,  63,   0,   0,  63,  63, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     85,   0,   0,   7,  50,   0, \n     16,   0,   9,   0,   0,   0, \n     70,   0,  16,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,   8,   0,   0,   0, \n     70,   2,  16,   0,   8,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  41,   0, \n      0,   7,  50,   0,  16,   0, \n      9,   0,   0,   0,  70,   0, \n     16,   0,   9,   0,   0,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0,  85,   0,   0,   7, \n    194,   0,  16,   0,   9,   0, \n      0,   0,   6,   4,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,   6,   0,   0,   0, \n     35,   0,   0,  15, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,   2,  64,   0,   0, \n     31,  31,   0,   0,  31,  31, \n      0,   0,  31,  31,   0,   0, \n      0,   0,   0,   0,   2,  64, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  41,   0, \n      0,   7, 114,   0,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n      1,  64,   0,   0,   3,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,  12,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     60,   0,   0,   7, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   2,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n     12,   0,   0,   0,  60,   0, \n      0,   7,  50,   0,  16,   0, \n      9,   0,   0,   0, 230,  10, \n     16,   0,   9,   0,   0,   0, \n     70,   0,  16,   0,   9,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,  11,   0, \n      0,   0,  26,   0,  16,   0, \n      9,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n     12,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     18,   0,   0,   1,  35,   0, \n      0,  15, 114,   0,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,  10,   0,   0,   0, \n      2,  64,   0,   0, 127, 127, \n      0,   0, 127, 127,   0,   0, \n    127, 127,   0,   0,   0,   0, \n      0,   0,   2,  64,   0,   0, \n      0, 128,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,  10,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,  41,   0,   0,   7, \n    114,   0,  16,   0,  10,   0, \n      0,   0,  70,   2,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     85,   0,   0,   7, 114,   0, \n     16,   0,  13,   0,   0,   0, \n     70,   2,  16,   0,  10,   0, \n      0,   0,   1,  64,   0,   0, \n      7,   0,   0,   0,  60,   0, \n      0,   7, 114,   0,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,  10,   0,   0,   0, \n     70,   2,  16,   0,  13,   0, \n      0,   0,  35,   0,   0,  15, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0, 127, 127,   0,   0, \n    127, 127,   0,   0, 127, 127, \n      0,   0,   0,   0,   0,   0, \n      2,  64,   0,   0,   0, 128, \n      0,   0,   0, 128,   0,   0, \n      0, 128,   0,   0,   0,   0, \n      0,   0,  85,   0,   0,   7, \n    114,   0,  16,   0,   7,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     41,   0,   0,   7, 114,   0, \n     16,   0,   7,   0,   0,   0, \n     70,   2,  16,   0,   7,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  85,   0, \n      0,   7, 114,   0,  16,   0, \n     10,   0,   0,   0,  70,   2, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   7,   0, \n      0,   0,  60,   0,   0,   7, \n    114,   0,  16,   0,  11,   0, \n      0,   0,  70,   2,  16,   0, \n      7,   0,   0,   0,  70,   2, \n     16,   0,  10,   0,   0,   0, \n     54,   0,   0,   5,  18,   0, \n     16,   0,   9,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,  11,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n     12,   0,   0,   0,   1,  64, \n      0,   0,   5,   0,   0,   0, \n     21,   0,   0,   1,  32,   0, \n      0,  10, 114,   0,  16,   0, \n      7,   0,   0,   0, 246,  15, \n     16,   0,   2,   0,   0,   0, \n      2,  64,   0,   0,   1,   0, \n      0,   0,   2,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,  55,   0,   0,   9, \n    194,   0,  16,   0,  10,   0, \n      0,   0, 166,  10,  16,   0, \n      7,   0,   0,   0, 246,  11, \n     16,   0,   3,   0,   0,   0, \n    166,  14,  16,   0,   3,   0, \n      0,   0,  54,   0,   0,   5, \n     50,   0,  16,   0,  10,   0, \n      0,   0,  70,   0,  16,   0, \n      3,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n     10,   0,   0,   0,  86,   5, \n     16,   0,   7,   0,   0,   0, \n    246,   6,  16,   0,   3,   0, \n      0,   0,  86,  14,  16,   0, \n     10,   0,   0,   0,  55,   0, \n      0,   9, 242,   0,  16,   0, \n     10,   0,   0,   0,   6,   0, \n     16,   0,   7,   0,   0,   0, \n    118,   2,  16,   0,   3,   0, \n      0,   0,  70,  14,  16,   0, \n     10,   0,   0,   0,  40,   0, \n      0,   5, 114,   0,  16,   0, \n     13,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     40,   0,   0,   5, 130,   0, \n     16,   0,  13,   0,   0,   0, \n     10,   0,  16,   0,   9,   0, \n      0,   0,  30,   0,   0,   7, \n    242,   0,  16,   0,  14,   0, \n      0,   0,  70,  14,  16,   0, \n     11,   0,   0,   0,  70,  14, \n     16,   0,  13,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0, 114,   0,  16,   0, \n     15,   0,   0,   0,  70,   3, \n     16,   0,  14,   0,   0,   0, \n     70,   3,  16,   0,  14,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n     15,   0,   0,   0,  10,   0, \n     16,   0,  15,   0,   0,   0, \n     35,   0,   0,   9, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,  14,   0, \n      0,   0,  42,   0,  16,   0, \n     14,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   7, 242,   0, \n     16,   0,  13,   0,   0,   0, \n     70,  14,  16,   0,  10,   0, \n      0,   0,  70,  14,  16,   0, \n     13,   0,   0,   0,  38,   0, \n      0,   8,   0, 208,   0,   0, \n    178,   0,  16,   0,  13,   0, \n      0,   0,  70,  12,  16,   0, \n     13,   0,   0,   0,  70,  12, \n     16,   0,  13,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,  13,   0, \n      0,   0,  10,   0,  16,   0, \n     13,   0,   0,   0,  35,   0, \n      0,   9,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,  13,   0,   0,   0, \n     42,   0,  16,   0,  13,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   8, 242,   0,  16,   0, \n     10,   0,   0,   0,  70,  14, \n     16, 128,  65,   0,   0,   0, \n     11,   0,   0,   0,  70,  14, \n     16,   0,  10,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0, 178,   0,  16,   0, \n     10,   0,   0,   0,  70,  12, \n     16,   0,  10,   0,   0,   0, \n     70,  12,  16,   0,  10,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n     10,   0,   0,   0,  10,   0, \n     16,   0,  10,   0,   0,   0, \n     35,   0,   0,   9,  66,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,  10,   0, \n      0,   0,  42,   0,  16,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     34,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  40,   0, \n      0,   5, 242,   0,  16,   0, \n     16,   0,   0,   0,  70,  14, \n     16,   0,  14,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  10,   0,   0,   0, \n     86,   5,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n     11,   0,   0,   0,  70,   2, \n     16,   0,   8,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,   8,   0,   0,   0, \n     86,   5,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n      8,   0,   0,   0,  70,   2, \n     16,   0,  11,   0,   0,   0, \n     55,   0,   0,   9, 114,   0, \n     16,   0,  11,   0,   0,   0, \n     86,   5,  16,   0,   2,   0, \n      0,   0,  70,   2,  16,   0, \n     16,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     34,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n     13,   0,   0,   0,  54,   0, \n      0,   5,  34,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,  11,   0,   0,   0, \n     54,   0,   0,   5,  66,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,  16,   0, \n      0,   0,  54,   0,   0,   5, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n     14,   0,   0,   0,  55,   0, \n      0,   9, 114,   0,  16,   0, \n      9,   0,   0,   0,  86,   5, \n     16,   0,   2,   0,   0,   0, \n     22,   6,  16,   0,   9,   0, \n      0,   0,  70,   3,  16,   0, \n      9,   0,   0,   0,  33,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  43,   0,   0,   5, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7, 194,   0,  16,   0, \n     12,   0,   0,   0,  86,   9, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  41,   0,   0,   7, \n     98,   0,  16,   0,   6,   0, \n      0,   0,  86,   6,  16,   0, \n      6,   0,   0,   0,   1,  64, \n      0,   0,   4,   0,   0,   0, \n     30,   0,   0,  10,  50,   0, \n     16,   0,  13,   0,   0,   0, \n    230,  10,  16,   0,  12,   0, \n      0,   0,   2,  64,   0,   0, \n     11,   0,   0,   0,  11,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  33,   0, \n      0,   7, 130,   0,  16,   0, \n      7,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,  15,   0, \n      0,   0,  43,   0,   0,   5, \n    130,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n     15,   0,   0,   0,  78,   0, \n      0,  11,   0, 208,   0,   0, \n     50,   0,  16,   0,  13,   0, \n      0,   0,  70,   0,  16,   0, \n     13,   0,   0,   0,   2,  64, \n      0,   0,  68,   0,   0,   0, \n     68,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   8, 194,   0, \n     16,   0,  13,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  48,   0,   0,   1, \n     80,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,  13,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   3,   0, \n      4,   3,  58,   0,  16,   0, \n      9,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  13,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,  14,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  55,   0,   0,   9, \n    194,   0,  16,   0,  16,   0, \n      0,   0, 166,  10,  16,   0, \n      7,   0,   0,   0, 246,  11, \n     16,   0,  14,   0,   0,   0, \n    166,  14,  16,   0,  14,   0, \n      0,   0,  54,   0,   0,   5, \n     50,   0,  16,   0,  16,   0, \n      0,   0,  70,   0,  16,   0, \n     14,   0,   0,   0,  55,   0, \n      0,   9, 226,   0,  16,   0, \n     16,   0,   0,   0,  86,   5, \n     16,   0,   7,   0,   0,   0, \n    246,   6,  16,   0,  14,   0, \n      0,   0,  86,  14,  16,   0, \n     16,   0,   0,   0,  55,   0, \n      0,   9, 242,   0,  16,   0, \n     14,   0,   0,   0,   6,   0, \n     16,   0,   7,   0,   0,   0, \n    118,   2,  16,   0,  14,   0, \n      0,   0,  70,  14,  16,   0, \n     16,   0,   0,   0,  30,   0, \n      0,   8, 178,   0,  16,   0, \n     15,   0,   0,   0,  70,   8, \n     16, 128,  65,   0,   0,   0, \n     10,   0,   0,   0,  70,   8, \n     16,   0,  14,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0,  50,   0,  16,   0, \n     15,   0,   0,   0,  70,   0, \n     16,   0,  11,   0,   0,   0, \n     70,   0,  16,   0,  15,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n     15,   0,   0,   0,  10,   0, \n     16,   0,  15,   0,   0,   0, \n     35,   0,   0,   9, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,  11,   0, \n      0,   0,  58,   0,  16,   0, \n     15,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     33,   0,   0,   7, 130,   0, \n     16,   0,  10,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  60,   0, \n      0,   7, 130,   0,  16,   0, \n     10,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  34,   0,   0,   7, \n    130,   0,  16,   0,  11,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n     43,   0,   0,   5, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  56,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,   1,  64, \n      0,   0, 253, 255, 125,  66, \n     14,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  28,   0, \n      0,   5, 130,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n     12,   0,   0,   0,  55,   0, \n      0,  10, 130,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,  11,   0,   0,   0, \n     10, 144, 144,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     10,   0,  16,   0,  13,   0, \n      0,   0,  55,   0,   0,   9, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  30,   0,   0,   8, \n    130,   0,  16,   0,  10,   0, \n      0,   0,  10,   0,  16, 128, \n     65,   0,   0,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n     14,   0,   0,   0,  38,   0, \n      0,   8,   0, 208,   0,   0, \n    130,   0,  16,   0,  10,   0, \n      0,   0,  42,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,  10,   0,   0,   0, \n     33,   0,   0,   7, 130,   0, \n     16,   0,  11,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,  60,   0, \n      0,   7, 130,   0,  16,   0, \n     11,   0,   0,   0,  58,   0, \n     16,   0,   7,   0,   0,   0, \n     58,   0,  16,   0,  11,   0, \n      0,   0,  34,   0,   0,   7, \n     18,   0,  16,   0,  15,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,  42,   0, \n     16,   0,  15,   0,   0,   0, \n     43,   0,   0,   5, 130,   0, \n     16,   0,  10,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  56,   0,   0,   7, \n    130,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,   1,  64, \n      0,   0, 253, 255, 125,  66, \n     14,   0,   0,   7, 130,   0, \n     16,   0,  10,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  28,   0, \n      0,   5, 130,   0,  16,   0, \n     10,   0,   0,   0,  58,   0, \n     16,   0,  10,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,  10,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n     12,   0,   0,   0,  55,   0, \n      0,  10, 130,   0,  16,   0, \n     10,   0,   0,   0,  10,   0, \n     16,   0,  15,   0,   0,   0, \n     10, 144, 144,   0,  58,   0, \n     16,   0,  10,   0,   0,   0, \n     26,   0,  16,   0,  13,   0, \n      0,   0,  55,   0,   0,   9, \n    130,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n     11,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  26,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   9, 130,   0, \n     16,   0,  11,   0,   0,   0, \n      1,  64,   0,   0,  64,   0, \n      0,   0,  26, 144, 144, 128, \n     65,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     38,   0,   0,   9,   0, 208, \n      0,   0, 178,   0,  16,   0, \n     15,   0,   0,   0,  70,   8, \n     16,   0,   8,   0,   0,   0, \n     86, 149, 144,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     35,   0,   0,   9, 178,   0, \n     16,   0,  15,   0,   0,   0, \n    246,  15,  16,   0,  11,   0, \n      0,   0,  70,   8,  16,   0, \n     10,   0,   0,   0,  70,  12, \n     16,   0,  15,   0,   0,   0, \n     30,   0,   0,  10, 178,   0, \n     16,   0,  15,   0,   0,   0, \n     70,  12,  16,   0,  15,   0, \n      0,   0,   2,  64,   0,   0, \n     32,   0,   0,   0,  32,   0, \n      0,   0,   0,   0,   0,   0, \n     32,   0,   0,   0,  85,   0, \n      0,   7, 178,   0,  16,   0, \n     16,   0,   0,   0,  70,  12, \n     16,   0,  15,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n      6,   0,   0,   0,  58,   0, \n     16,   0,  10,   0,   0,   0, \n     30,   0,   0,   9, 130,   0, \n     16,   0,  10,   0,   0,   0, \n      1,  64,   0,   0,  64,   0, \n      0,   0,  26, 144, 144, 128, \n     65,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     38,   0,   0,   9,   0, 208, \n      0,   0, 130,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,   9,   0,   0,   0, \n     26, 144, 144,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     35,   0,   0,   9, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  10,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     30,   0,   0,   7, 130,   0, \n     16,   0,   9,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,   1,  64,   0,   0, \n     32,   0,   0,   0,  85,   0, \n      0,   7,  34,   0,  16,   0, \n     15,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n      1,  64,   0,   0,   6,   0, \n      0,   0,  79,   0,   0,   7, \n    114,   0,  16,   0,  17,   0, \n      0,   0,  70,   3,  16,   0, \n     16,   0,   0,   0,  70,   2, \n     16,   0,  14,   0,   0,   0, \n     54,   0,   0,   5,  66,   0, \n     16,   0,  16,   0,   0,   0, \n     10,   0,  16,   0,  14,   0, \n      0,   0,  55,   0,   0,   9, \n    146,   0,  16,   0,  17,   0, \n      0,   0,   6,   0,  16,   0, \n     17,   0,   0,   0, 166,   2, \n     16,   0,  16,   0,   0,   0, \n      6,   8,  16,   0,  16,   0, \n      0,   0,  54,   0,   0,   5, \n     82,   0,  16,   0,  16,   0, \n      0,   0,  86,   6,  16,   0, \n     14,   0,   0,   0,  55,   0, \n      0,   9, 242,   0,  16,   0, \n     16,   0,   0,   0,  86,  10, \n     16,   0,  17,   0,   0,   0, \n     70,  14,  16,   0,  16,   0, \n      0,   0,  22,  11,  16,   0, \n     16,   0,   0,   0,  79,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,  15,   0,   0,   0, \n     58,   0,  16,   0,  14,   0, \n      0,   0,  54,   0,   0,   5, \n     18,   0,  16,   0,  15,   0, \n      0,   0,  58,   0,  16,   0, \n     14,   0,   0,   0,  55,   0, \n      0,   9,  50,   0,  16,   0, \n     14,   0,   0,   0, 246,  15, \n     16,   0,   9,   0,   0,   0, \n     70,   0,  16,   0,  15,   0, \n      0,   0,  22,   5,  16,   0, \n     15,   0,   0,   0,  40,   0, \n      0,   5, 130,   0,  16,   0, \n     18,   0,   0,   0,  58,   0, \n     16,   0,  17,   0,   0,   0, \n     40,   0,   0,   5,  98,   0, \n     16,   0,  18,   0,   0,   0, \n     86,   7,  16,   0,  16,   0, \n      0,   0,  40,   0,   0,   5, \n     18,   0,  16,   0,  18,   0, \n      0,   0,  26,   0,  16,   0, \n     14,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n     14,   0,   0,   0,  10,   0, \n     16,   0,  17,   0,   0,   0, \n     54,   0,   0,   5,  98,   0, \n     16,   0,  14,   0,   0,   0, \n      6,   2,  16,   0,  16,   0, \n      0,   0,  30,   0,   0,   7, \n    242,   0,  16,   0,  14,   0, \n      0,   0,  70,  14,  16,   0, \n     18,   0,   0,   0,  70,  14, \n     16,   0,  14,   0,   0,   0, \n     55,   0,   0,   9, 194,   0, \n     16,   0,  16,   0,   0,   0, \n    166,  10,  16,   0,   7,   0, \n      0,   0,   6,   8,  16,   0, \n     14,   0,   0,   0, 166,   2, \n     16,   0,  14,   0,   0,   0, \n     54,   0,   0,   5,  50,   0, \n     16,   0,  16,   0,   0,   0, \n    118,  15,  16,   0,  14,   0, \n      0,   0,  55,   0,   0,   9, \n    226,   0,  16,   0,  16,   0, \n      0,   0,  86,   5,  16,   0, \n      7,   0,   0,   0,   6,   6, \n     16,   0,  14,   0,   0,   0, \n     86,  14,  16,   0,  16,   0, \n      0,   0,  55,   0,   0,   9, \n    242,   0,  16,   0,  14,   0, \n      0,   0,   6,   0,  16,   0, \n      7,   0,   0,   0,  70,  14, \n     16,   0,  14,   0,   0,   0, \n     70,  14,  16,   0,  16,   0, \n      0,   0,  38,   0,   0,   8, \n      0, 208,   0,   0,  50,   0, \n     16,   0,  14,   0,   0,   0, \n     70,   0,  16,   0,  14,   0, \n      0,   0,  70,   0,  16,   0, \n     14,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      9,   0,   0,   0,  26,   0, \n     16,   0,  14,   0,   0,   0, \n     10,   0,  16,   0,  14,   0, \n      0,   0,  35,   0,   0,   9, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  42,   0,  16,   0, \n     14,   0,   0,   0,  42,   0, \n     16,   0,  14,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  86,   0,   0,   5, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  86,   0, \n      0,   5, 130,   0,  16,   0, \n     10,   0,   0,   0,  58,   0, \n     16,   0,  14,   0,   0,   0, \n     56,   0,   0,   7, 130,   0, \n     16,   0,  10,   0,   0,   0, \n     58,   0,  16,   0,  10,   0, \n      0,   0,  58,   0,  16,   0, \n     10,   0,   0,   0,  50,   0, \n      0,  10, 130,   0,  16,   0, \n      9,   0,   0,   0,  58,   0, \n     16,   0,  10,   0,   0,   0, \n     42, 128,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     58,   0,  16,   0,   9,   0, \n      0,   0,  28,   0,   0,   5, \n    130,   0,  16,   0,   9,   0, \n      0,   0,  58,   0,  16,   0, \n      9,   0,   0,   0,  30,   0, \n      0,   7,  66,   0,  16,   0, \n     13,   0,   0,   0,  58,   0, \n     16,   0,   9,   0,   0,   0, \n     42,   0,  16,   0,  13,   0, \n      0,   0,  30,   0,   0,   7, \n    130,   0,  16,   0,  13,   0, \n      0,   0,  58,   0,  16,   0, \n     13,   0,   0,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n     22,   0,   0,   1,  54,   0, \n      0,   5,  18,   0,  16,   0, \n     12,   0,   0,   0,  42,   0, \n     16,   0,  13,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   6,   0,   0,   0, \n     58,   0,  16,   0,   2,   0, \n      0,   0,  18,   0,   0,   1, \n     31,   0,   4,   3,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   7,  18,   0, \n     16,   0,   7,   0,   0,   0, \n     42,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n    244, 255, 255, 255,  85,   0, \n      0,   7,  34,   0,  16,   0, \n      7,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n      1,  64,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,  10, \n    194,   0,  16,   0,   0,   0, \n      0,   0,   6,   4,  16,   0, \n      7,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,  10, 242,   0, \n     16,   0,   4,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0,   2,  64,   0,   0, \n    254, 255, 255, 255, 254, 255, \n    255, 255, 254, 255, 255, 255, \n    254, 255, 255, 255,  30,   0, \n      0,   7, 242,   0,  16,   0, \n      4,   0,   0,   0, 166,  10, \n     16,   0,   0,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0,   1,   0,   0,  10, \n    242,   0,  16,   0,   5,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,   2,  64, \n      0,   0, 254, 255, 255, 255, \n    254, 255, 255, 255, 254, 255, \n    255, 255, 254, 255, 255, 255, \n     30,   0,   0,   7, 242,   0, \n     16,   0,   5,   0,   0,   0, \n    246,  15,  16,   0,   0,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,  30,   0, \n      0,   8, 242,   0,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16, 128,  65,   0,   0,   0, \n      4,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0, 194,   0,  16,   0, \n      0,   0,   0,   0,   6,   4, \n     16,   0,   8,   0,   0,   0, \n      6,   4,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     35,   0,   0,   9,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     35,   0,   0,   9,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     30,   0,   0,   8, 242,   0, \n     16,   0,   3,   0,   0,   0, \n     70,  14,  16,   0,   3,   0, \n      0,   0,  70,  14,  16, 128, \n     65,   0,   0,   0,   4,   0, \n      0,   0,  38,   0,   0,   8, \n      0, 208,   0,   0,  98,   0, \n     16,   0,   2,   0,   0,   0, \n      6,   1,  16,   0,   3,   0, \n      0,   0,   6,   1,  16,   0, \n      8,   0,   0,   0,  30,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  35,   0,   0,   9, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      8,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  35,   0,   0,   9, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      8,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  34,   0,   0,   7, \n     18,   0,  16,   0,   1,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     33,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   7,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  43,   0,   0,   5, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  56,   0, \n      0,   7, 130,   0,  16,   0, \n      0,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0, 253, 255, \n    125,  66,  28,   0,   0,   5, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  41,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   5,   0, \n      0,   0,  79,   0,   0,   7, \n    130,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   0,   0,   0,   0, \n      1,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n     58,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  40,   0, \n      0,   5, 242,   0,  16,   0, \n      3,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n     55,   0,   0,   9, 242,   0, \n     16,   0,   9,   0,   0,   0, \n    246,  15,  16,   0,   0,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,  70,  14, \n     16,   0,   4,   0,   0,   0, \n     55,   0,   0,   9, 242,   0, \n     16,   0,   4,   0,   0,   0, \n    246,  15,  16,   0,   0,   0, \n      0,   0,  70,  14,  16,   0, \n      4,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n     55,   0,   0,   9, 242,   0, \n     16,   0,   3,   0,   0,   0, \n    246,  15,  16,   0,   0,   0, \n      0,   0,  70,  14,  16,   0, \n      3,   0,   0,   0,  70,  14, \n     16,   0,   8,   0,   0,   0, \n     33,   0,   0,   7, 130,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  43,   0, \n      0,   5,  18,   0,  16,   0, \n      1,   0,   0,   0,  42,   0, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   8,  50,   0, \n     16,   0,  12,   0,   0,   0, \n      2,  64,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  48,   0,   0,   1, \n     80,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,  12,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   3,   0, \n      4,   3,  26,   0,  16,   0, \n      2,   0,   0,   0,  30,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,  12,   0, \n      0,   0, 167,   0,   0,   9, \n    242,   0,  16,   0,   5,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70, 254,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   8, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16, 128, \n     65,   0,   0,   0,   9,   0, \n      0,   0,  70,  14,  16,   0, \n      5,   0,   0,   0,  38,   0, \n      0,   8,   0, 208,   0,   0, \n     98,   0,  16,   0,   2,   0, \n      0,   0,   6,   1,  16,   0, \n      3,   0,   0,   0,   6,   1, \n     16,   0,   8,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  35,   0, \n      0,   9,  34,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   3,   0,   0,   0, \n     42,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  35,   0, \n      0,   9,  34,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   3,   0,   0,   0, \n     58,   0,  16,   0,   8,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  33,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  60,   0,   0,   7, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      0,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     34,   0,   0,   7, 130,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      0,   0,   0,   0,  43,   0, \n      0,   5,  34,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     56,   0,   0,   7,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n    253, 255, 125,  66,  14,   0, \n      0,   7,  34,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     10,   0,  16,   0,   1,   0, \n      0,   0,  28,   0,   0,   5, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  55,   0, \n      0,  10,  34,   0,  16,   0, \n      2,   0,   0,   0,  58,   0, \n     16,   0,   2,   0,   0,   0, \n     10, 144, 144,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n      1,  64,   0,   0,  15,   0, \n      0,   0,  55,   0,   0,   9, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   9, \n     66,   0,  16,   0,   2,   0, \n      0,   0,   1,  64,   0,   0, \n     64,   0,   0,   0,  26, 144, \n    144, 128,  65,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  38,   0,   0,   9, \n      0, 208,   0,   0, 242,   0, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   4,   0, \n      0,   0,  86, 149, 144,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  35,   0,   0,   9, \n    242,   0,  16,   0,   8,   0, \n      0,   0, 166,  10,  16,   0, \n      2,   0,   0,   0,  70,  14, \n     16,   0,   9,   0,   0,   0, \n     70,  14,  16,   0,   8,   0, \n      0,   0,  30,   0,   0,  10, \n    242,   0,  16,   0,   8,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,   2,  64, \n      0,   0,  32,   0,   0,   0, \n     32,   0,   0,   0,  32,   0, \n      0,   0,  32,   0,   0,   0, \n     85,   0,   0,   7, 242,   0, \n     16,   0,   8,   0,   0,   0, \n    134,  13,  16,   0,   8,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  79,   0, \n      0,   7, 242,   0,  16,   0, \n     10,   0,   0,   0, 134,  13, \n     16,   0,   8,   0,   0,   0, \n     70,  14,  16,   0,   5,   0, \n      0,   0,  54,   0,   0,   5, \n     82,   0,  16,   0,  11,   0, \n      0,   0,   6,   1,  16,   0, \n      5,   0,   0,   0,  54,   0, \n      0,   5, 162,   0,  16,   0, \n     11,   0,   0,   0,   6,   8, \n     16,   0,   8,   0,   0,   0, \n     55,   0,   0,   9, 242,   0, \n     16,   0,  11,   0,   0,   0, \n      6,   5,  16,   0,  10,   0, \n      0,   0,  70,  14,  16,   0, \n     11,   0,   0,   0,  22,  11, \n     16,   0,  11,   0,   0,   0, \n     54,   0,   0,   5,  82,   0, \n     16,   0,   8,   0,   0,   0, \n    166,  11,  16,   0,   5,   0, \n      0,   0,  55,   0,   0,   9, \n    242,   0,  16,   0,   5,   0, \n      0,   0, 230,  14,  16,   0, \n     10,   0,   0,   0, 214,   8, \n     16,   0,   8,   0,   0,   0, \n    134,  13,  16,   0,   8,   0, \n      0,   0,  40,   0,   0,   5, \n     50,   0,  16,   0,   8,   0, \n      0,   0, 214,   5,  16,   0, \n     11,   0,   0,   0,  40,   0, \n      0,   5, 194,   0,  16,   0, \n      8,   0,   0,   0,   6,   4, \n     16,   0,   5,   0,   0,   0, \n     54,   0,   0,   5,  50,   0, \n     16,   0,   5,   0,   0,   0, \n    134,   0,  16,   0,  11,   0, \n      0,   0,  30,   0,   0,   7, \n    242,   0,  16,   0,   5,   0, \n      0,   0,  70,  14,  16,   0, \n      8,   0,   0,   0,  70,  14, \n     16,   0,   5,   0,   0,   0, \n     38,   0,   0,   8,   0, 208, \n      0,   0,  98,   0,  16,   0, \n      2,   0,   0,   0,   6,   1, \n     16,   0,   5,   0,   0,   0, \n      6,   1,  16,   0,   5,   0, \n      0,   0,  30,   0,   0,   7, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     35,   0,   0,   9,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   5,   0, \n      0,   0,  42,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     86,   0,   0,   5,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  86,   0,   0,   5, \n     66,   0,  16,   0,   2,   0, \n      0,   0,  58,   0,  16,   0, \n      5,   0,   0,   0,  56,   0, \n      0,   7,  66,   0,  16,   0, \n      2,   0,   0,   0,  42,   0, \n     16,   0,   2,   0,   0,   0, \n     42,   0,  16,   0,   2,   0, \n      0,   0,  50,   0,   0,  10, \n     34,   0,  16,   0,   2,   0, \n      0,   0,  42,   0,  16,   0, \n      2,   0,   0,   0,  42, 128, \n     32,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,  26,   0, \n     16,   0,   2,   0,   0,   0, \n     28,   0,   0,   5,  34,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  30,   0,   0,   7, \n     18,   0,  16,   0,  12,   0, \n      0,   0,  26,   0,  16,   0, \n      2,   0,   0,   0,  10,   0, \n     16,   0,  12,   0,   0,   0, \n     30,   0,   0,   7,  34,   0, \n     16,   0,  12,   0,   0,   0, \n     26,   0,  16,   0,  12,   0, \n      0,   0,   1,  64,   0,   0, \n      1,   0,   0,   0,  22,   0, \n      0,   1,  54,   0,   0,   5, \n     34,   0,  16,   0,  12,   0, \n      0,   0,   1,  64,   0,   0, \n      6,   0,   0,   0,  54,   0, \n      0,   5, 130,   0,  16,   0, \n      6,   0,   0,   0,  10,   0, \n     16,   0,   7,   0,   0,   0, \n     18,   0,   0,   1,  54,   0, \n      0,   8,  50,   0,  16,   0, \n     12,   0,   0,   0,   2,  64, \n      0,   0, 255, 255, 255, 255, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     54,   0,   0,   5, 130,   0, \n     16,   0,   6,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0,  21,   0,   0,   1, \n     21,   0,   0,   1, 168,   0, \n      0,   8,  50, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,  70,   0, \n     16,   0,  12,   0,   0,   0, \n    168,   0,   0,   8,  50, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n    198,   0,  16,   0,   6,   0, \n      0,   0, 190,  24,   0,   1, \n     31,   0,   4,   3,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     30,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   8,   0,   0,   0, \n    167,   0,   0,   9,  98,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 241, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   4,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     28,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     79,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   3,   0, \n      0,   0,  10,   0,  16,   0, \n     12,   0,   0,   0,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      3,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8,  50, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0, 134,   0, \n     16,   0,   3,   0,   0,   0, \n    168,   0,   0,   8,  50, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n     70,   0,  16,   0,   4,   0, \n      0,   0,  21,   0,   0,   1, \n     21,   0,   0,   1, 190,  24, \n      0,   1,  31,   0,   4,   3, \n     42,   0,  16,   0,   1,   0, \n      0,   0, 167,   0,   0,   8, \n     18,   0,  16,   0,   3,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0,  30,   0, \n      0,   6,  34,   0,  16,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n      4,   0,   0,   0, 167,   0, \n      0,   9,  98,   0,  16,   0, \n      4,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 241,  17,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  50,   0,  16,   0, \n      5,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,  70, 240,  17,   0, \n      0,   0,   0,   0,  79,   0, \n      0,   7,  66,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   4,   0,   0,   0, \n     10,   0,  16,   0,   3,   0, \n      0,   0,  31,   0,   4,   3, \n     42,   0,  16,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     18,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0, 168,   0,   0,   8, \n     50, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0, 134,   0,  16,   0, \n      4,   0,   0,   0, 168,   0, \n      0,   8,  50, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     28,   0,   0,   0,  70,   0, \n     16,   0,   5,   0,   0,   0, \n     21,   0,   0,   1,  21,   0, \n      0,   1, 190,  24,   0,   1, \n     31,   0,   4,   3,  58,   0, \n     16,   0,   1,   0,   0,   0, \n    167,   0,   0,   8,  18,   0, \n     16,   0,   1,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 240,  17,   0,   0,   0, \n      0,   0,  30,   0,   0,   6, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,   2,   0, \n      0,   0, 167,   0,   0,   9, \n     98,   0,  16,   0,   3,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n      6, 241,  17,   0,   0,   0, \n      0,   0, 167,   0,   0,   9, \n     50,   0,  16,   0,   4,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  79,   0,   0,   7, \n     66,   0,  16,   0,   0,   0, \n      0,   0,  26,   0,  16,   0, \n      3,   0,   0,   0,  10,   0, \n     16,   0,   1,   0,   0,   0, \n     31,   0,   4,   3,  42,   0, \n     16,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  18,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n    168,   0,   0,   8,  50, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n    134,   0,  16,   0,   3,   0, \n      0,   0, 168,   0,   0,   8, \n     50, 240,  17,   0,   0,   0, \n      0,   0,  10,  64,   2,   0, \n      1,  64,   0,   0,  28,   0, \n      0,   0,  70,   0,  16,   0, \n      4,   0,   0,   0,  21,   0, \n      0,   1,  21,   0,   0,   1, \n    190,  24,   0,   1,  31,   0, \n      4,   3,  10,   0,  16,   0, \n      2,   0,   0,   0, 167,   0, \n      0,   8,  18,   0,  16,   0, \n      1,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 240, \n     17,   0,   0,   0,   0,   0, \n     30,   0,   0,   6,  34,   0, \n     16,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,   1,   0,   0,   0, \n    167,   0,   0,   9,  98,   0, \n     16,   0,   2,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     16,   0,   0,   0,   6, 241, \n     17,   0,   0,   0,   0,   0, \n    167,   0,   0,   9,  50,   0, \n     16,   0,   3,   0,   0,   0, \n     26,   0,  16,   0,   0,   0, \n      0,   0,   1,  64,   0,   0, \n     28,   0,   0,   0,  70, 240, \n     17,   0,   0,   0,   0,   0, \n     79,   0,   0,   7,  66,   0, \n     16,   0,   0,   0,   0,   0, \n     26,   0,  16,   0,   2,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,  31,   0, \n      4,   3,  42,   0,  16,   0, \n      0,   0,   0,   0, 167,   0, \n      0,   9,  18,   0,  16,   0, \n      2,   0,   0,   0,  26,   0, \n     16,   0,   0,   0,   0,   0, \n      1,  64,   0,   0,  16,   0, \n      0,   0,   6, 240,  17,   0, \n      0,   0,   0,   0, 168,   0, \n      0,   8,  50, 240,  17,   0, \n      0,   0,   0,   0,  10,  64, \n      2,   0,   1,  64,   0,   0, \n     16,   0,   0,   0, 134,   0, \n     16,   0,   2,   0,   0,   0, \n    168,   0,   0,   8,  50, 240, \n     17,   0,   0,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n     70,   0,  16,   0,   3,   0, \n      0,   0,  21,   0,   0,   1, \n    167,   0,   0,   8, 146,   0, \n     16,   0,   1,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  28,   0,   0,   0, \n      6, 244,  17,   0,   0,   0, \n      0,   0,  41,   0,   0,   7, \n     34,   0,  16,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      1,   0,   0,   0,   1,  64, \n      0,   0,  31,   0,   0,   0, \n    167,   0,   0,   8,  50,   0, \n     16,   0,   1,   0,   0,   0, \n     10,  64,   2,   0,   1,  64, \n      0,   0,  16,   0,   0,   0, \n     70, 240,  17,   0,   0,   0, \n      0,   0,  60,   0,   0,   7, \n     34,   0,  16,   0,   1,   0, \n      0,   0,  26,   0,  16,   0, \n      0,   0,   0,   0,  26,   0, \n     16,   0,   1,   0,   0,   0, \n     54,   0,   0,   5,  66,   0, \n     16,   0,   1,   0,   0,   0, \n      1,  64,   0,   0,   0,   0, \n      0,   0, 168,   0,   0,   9, \n    242, 224,  17,   0,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,   1,  64, \n      0,   0,   0,   0,   0,   0, \n     70,  14,  16,   0,   1,   0, \n      0,   0,  21,   0,   0,   1, \n     62,   0,   0,   1\n};\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/filters.h",
    "content": "//-------------------------------------------------------------------------------------\n// filters.h\n//\n// Utility header with helpers for implementing image filters\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <DirectXMath.h>\n#include <DirectXPackedVector.h>\n\n#include <memory>\n\n#include \"scoped.h\"\n\n\nnamespace DirectX\n{\n    namespace Filters\n    {\n        //-------------------------------------------------------------------------------------\n        // Box filtering helpers\n        //-------------------------------------------------------------------------------------\n\n        XMGLOBALCONST XMVECTORF32 g_boxScale = { { { 0.25f, 0.25f, 0.25f, 0.25f } } };\n        XMGLOBALCONST XMVECTORF32 g_boxScale3D = { { { 0.125f, 0.125f, 0.125f, 0.125f } } };\n\n    #define AVERAGE4( res, p0, p1, p2, p3 ) \\\n{ \\\n    XMVECTOR v = XMVectorAdd((p0), (p1)); \\\n    v = XMVectorAdd(v, (p2)); \\\n    v = XMVectorAdd(v, (p3)); \\\n    res = XMVectorMultiply(v, g_boxScale); \\\n}\n\n    #define AVERAGE8( res, p0, p1, p2, p3, p4, p5, p6, p7) \\\n{ \\\n    XMVECTOR v = XMVectorAdd((p0), (p1)); \\\n    v = XMVectorAdd(v, (p2)); \\\n    v = XMVectorAdd(v, (p3)); \\\n    v = XMVectorAdd(v, (p4)); \\\n    v = XMVectorAdd(v, (p5)); \\\n    v = XMVectorAdd(v, (p6)); \\\n    v = XMVectorAdd(v, (p7)); \\\n    res = XMVectorMultiply(v, g_boxScale3D); \\\n}\n\n\n        //-------------------------------------------------------------------------------------\n        // Linear filtering helpers\n        //-------------------------------------------------------------------------------------\n\n        struct LinearFilter\n        {\n            size_t  u0;\n            float   weight0;\n            size_t  u1;\n            float   weight1;\n        };\n\n        inline void CreateLinearFilter(_In_ size_t source, _In_ size_t dest, _In_ bool wrap, _Out_writes_(dest) LinearFilter* lf) noexcept\n        {\n            assert(source > 0);\n            assert(dest > 0);\n            assert(lf != nullptr);\n\n            const float scale = float(source) / float(dest);\n\n            // Mirror is the same case as clamp for linear\n\n            for (size_t u = 0; u < dest; ++u)\n            {\n                const float srcB = (float(u) + 0.5f) * scale + 0.5f;\n\n                ptrdiff_t isrcB = ptrdiff_t(srcB);\n                ptrdiff_t isrcA = isrcB - 1;\n\n                const float weight = 1.0f + float(isrcB) - srcB;\n\n                if (isrcA < 0)\n                {\n                    isrcA = (wrap) ? (ptrdiff_t(source) - 1) : 0;\n                }\n\n                if (size_t(isrcB) >= source)\n                {\n                    isrcB = (wrap) ? 0 : (ptrdiff_t(source) - 1);\n                }\n\n                auto& entry = lf[u];\n                entry.u0 = size_t(isrcA);\n                entry.weight0 = weight;\n\n                entry.u1 = size_t(isrcB);\n                entry.weight1 = 1.0f - weight;\n            }\n        }\n\n    #define BILINEAR_INTERPOLATE( res, x, y, r0, r1 ) \\\n    res = XMVectorAdd(XMVectorScale(XMVectorAdd(XMVectorScale((r0)[ x.u0 ], x.weight0), XMVectorScale((r0)[ x.u1 ], x.weight1)), y.weight0), \\\n                      XMVectorScale(XMVectorAdd(XMVectorScale((r1)[ x.u0 ], x.weight0), XMVectorScale((r1)[ x.u1 ], x.weight1)), y.weight1) );\n\n    #define TRILINEAR_INTERPOLATE( res, x, y, z, r0, r1, r2, r3 ) \\\n{\\\n    const XMVECTOR a0 = XMVectorScale(XMVectorAdd(XMVectorScale((r0)[ x.u0 ], x.weight0 ), XMVectorScale((r0)[ x.u1 ], x.weight1)), y.weight0); \\\n    const XMVECTOR a1 = XMVectorScale(XMVectorAdd(XMVectorScale((r1)[ x.u0 ], x.weight0 ), XMVectorScale((r1)[ x.u1 ], x.weight1)), y.weight1); \\\n    const XMVECTOR a2 = XMVectorScale(XMVectorAdd(XMVectorScale((r2)[ x.u0 ], x.weight0 ), XMVectorScale((r2)[ x.u1 ], x.weight1)), y.weight0); \\\n    const XMVECTOR a3 = XMVectorScale(XMVectorAdd(XMVectorScale((r3)[ x.u0 ], x.weight0 ), XMVectorScale((r3)[ x.u1 ], x.weight1)), y.weight1); \\\n    res = XMVectorAdd(XMVectorScale(XMVectorAdd(a0, a1), z.weight0), XMVectorScale(XMVectorAdd(a2, a3), z.weight1)); \\\n}\n\n        //-------------------------------------------------------------------------------------\n        // Cubic filtering helpers\n        //-------------------------------------------------------------------------------------\n\n        XMGLOBALCONST XMVECTORF32 g_cubicThird = { { { 1.f / 3.f, 1.f / 3.f, 1.f / 3.f, 1.f / 3.f } } };\n        XMGLOBALCONST XMVECTORF32 g_cubicSixth = { { { 1.f / 6.f, 1.f / 6.f, 1.f / 6.f, 1.f / 6.f } } };\n        XMGLOBALCONST XMVECTORF32 g_cubicHalf = { { { 1.f / 2.f, 1.f / 2.f, 1.f / 2.f, 1.f / 2.f } } };\n\n        constexpr ptrdiff_t bounduvw(ptrdiff_t u, ptrdiff_t maxu, bool wrap, bool mirror) noexcept\n        {\n            if (wrap)\n            {\n                if (u < 0)\n                {\n                    u = maxu + u + 1;\n                }\n                else if (u > maxu)\n                {\n                    u = u - maxu - 1;\n                }\n            }\n            else if (mirror)\n            {\n                if (u < 0)\n                {\n                    u = (-u) - 1;\n                }\n                else if (u > maxu)\n                {\n                    u = maxu - (u - maxu - 1);\n                }\n            }\n\n            // Handles clamp, but also a safety factor for degenerate images for wrap/mirror\n            u = std::min<ptrdiff_t>(u, maxu);\n            u = std::max<ptrdiff_t>(u, 0);\n\n            return u;\n        }\n\n        struct CubicFilter\n        {\n            size_t  u0;\n            size_t  u1;\n            size_t  u2;\n            size_t  u3;\n            float   x;\n        };\n\n        inline void CreateCubicFilter(_In_ size_t source, _In_ size_t dest, _In_ bool wrap, _In_ bool mirror, _Out_writes_(dest) CubicFilter* cf) noexcept\n        {\n            assert(source > 0);\n            assert(dest > 0);\n            assert(cf != nullptr);\n\n            const float scale = float(source) / float(dest);\n\n            for (size_t u = 0; u < dest; ++u)\n            {\n                const float srcB = (float(u) + 0.5f) * scale - 0.5f;\n\n                const ptrdiff_t isrcB = bounduvw(ptrdiff_t(srcB), ptrdiff_t(source) - 1, wrap, mirror);\n                const ptrdiff_t isrcA = bounduvw(isrcB - 1, ptrdiff_t(source) - 1, wrap, mirror);\n                const ptrdiff_t isrcC = bounduvw(isrcB + 1, ptrdiff_t(source) - 1, wrap, mirror);\n                const ptrdiff_t isrcD = bounduvw(isrcB + 2, ptrdiff_t(source) - 1, wrap, mirror);\n\n                auto& entry = cf[u];\n                entry.u0 = size_t(isrcA);\n                entry.u1 = size_t(isrcB);\n                entry.u2 = size_t(isrcC);\n                entry.u3 = size_t(isrcD);\n\n                const float x = srcB - float(isrcB);\n                entry.x = x;\n            }\n        }\n\n    #define CUBIC_INTERPOLATE( res, dx, p0, p1, p2, p3 ) \\\n{ \\\n    const XMVECTOR a0 = (p1); \\\n    const XMVECTOR d0 = XMVectorSubtract(p0, a0); \\\n    const XMVECTOR d2 = XMVectorSubtract(p2, a0); \\\n    const XMVECTOR d3 = XMVectorSubtract(p3, a0); \\\n    XMVECTOR a1 = XMVectorSubtract(d2, XMVectorMultiply(g_cubicThird, d0)); \\\n    a1 = XMVectorSubtract(a1, XMVectorMultiply(g_cubicSixth, d3)); \\\n    const XMVECTOR a2 = XMVectorAdd(XMVectorMultiply(g_cubicHalf, d0), XMVectorMultiply(g_cubicHalf, d2)); \\\n    XMVECTOR a3 = XMVectorSubtract(XMVectorMultiply(g_cubicSixth, d3), XMVectorMultiply(g_cubicSixth, d0)); \\\n    a3 = XMVectorSubtract(a3, XMVectorMultiply(g_cubicHalf, d2)); \\\n    const XMVECTOR vdx = XMVectorReplicate(dx); \\\n    const XMVECTOR vdx2 = XMVectorMultiply(vdx, vdx); \\\n    const XMVECTOR vdx3 = XMVectorMultiply(vdx2, vdx); \\\n    res = XMVectorAdd(XMVectorAdd(XMVectorAdd(a0, XMVectorMultiply(a1, vdx)), XMVectorMultiply(a2, vdx2)), XMVectorMultiply(a3, vdx3)); \\\n}\n\n\n        //-------------------------------------------------------------------------------------\n        // Triangle filtering helpers\n        //-------------------------------------------------------------------------------------\n\n        struct FilterTo\n        {\n            size_t      u;\n            float       weight;\n        };\n\n        struct FilterFrom\n        {\n            size_t      count;\n            size_t      sizeInBytes;\n            FilterTo    to[1]; // variable-sized array\n        };\n\n        struct Filter\n        {\n            size_t      sizeInBytes;\n            size_t      totalSize;\n            FilterFrom  from[1]; // variable-sized array\n        };\n\n        struct TriangleRow\n        {\n            size_t                      remaining;\n            TriangleRow* next;\n            ScopedAlignedArrayXMVECTOR  scanline;\n\n            TriangleRow() noexcept : remaining(0), next(nullptr) {}\n        };\n\n        constexpr size_t TF_FILTER_SIZE = sizeof(Filter) - sizeof(FilterFrom);\n        constexpr size_t TF_FROM_SIZE = sizeof(FilterFrom) - sizeof(FilterTo);\n        constexpr size_t TF_TO_SIZE = sizeof(FilterTo);\n\n        constexpr float TF_EPSILON = 0.00001f;\n\n        inline HRESULT CreateTriangleFilter(_In_ size_t source, _In_ size_t dest, _In_ bool wrap, _Inout_ std::unique_ptr<Filter>& tf) noexcept\n        {\n            assert(source > 0);\n            assert(dest > 0);\n\n            const float scale = float(dest) / float(source);\n            const float scaleInv = 0.5f / scale;\n\n            // Determine storage required for filter and allocate memory if needed\n            size_t totalSize = TF_FILTER_SIZE + TF_FROM_SIZE + TF_TO_SIZE;\n            const float repeat = (wrap) ? 1.f : 0.f;\n\n            for (size_t u = 0; u < source; ++u)\n            {\n                const float src = float(u) - 0.5f;\n                const float destMin = src * scale;\n                const float destMax = destMin + scale;\n                const float t = destMax - destMin + repeat + 1.f;\n                totalSize += TF_FROM_SIZE + TF_TO_SIZE + size_t(t) * TF_TO_SIZE * 2;\n            }\n\n            uint8_t* pFilter = nullptr;\n\n            if (tf)\n            {\n                // See if existing filter memory block is large enough to reuse\n                if (tf->totalSize >= totalSize)\n                {\n                    pFilter = reinterpret_cast<uint8_t*>(tf.get());\n                }\n                else\n                {\n                    // Need to reallocate filter memory block\n                    tf.reset(nullptr);\n                }\n            }\n\n            if (!tf)\n            {\n                // Allocate filter memory block\n                pFilter = new (std::nothrow) uint8_t[totalSize];\n                if (!pFilter)\n                    return E_OUTOFMEMORY;\n\n                tf.reset(reinterpret_cast<Filter*>(pFilter));\n                tf->totalSize = totalSize;\n            }\n\n            assert(pFilter != nullptr);\n            _Analysis_assume_(pFilter != nullptr);\n\n            // Filter setup\n            size_t sizeInBytes = TF_FILTER_SIZE;\n            size_t accumU = 0;\n            float accumWeight = 0.f;\n\n            for (size_t u = 0; u < source; ++u)\n            {\n                // Setup from entry\n                const size_t sizeFrom = sizeInBytes;\n                auto pFrom = reinterpret_cast<FilterFrom*>(pFilter + sizeInBytes);\n                sizeInBytes += TF_FROM_SIZE;\n\n                if (sizeInBytes > totalSize)\n                    return E_FAIL;\n\n                size_t toCount = 0;\n\n                // Perform two passes to capture the influences from both sides\n                for (size_t j = 0; j < 2; ++j)\n                {\n                    const float src = float(u + j) - 0.5f;\n\n                    float destMin = src * scale;\n                    float destMax = destMin + scale;\n\n                    if (!wrap)\n                    {\n                        // Clamp\n                        if (destMin < 0.f)\n                            destMin = 0.f;\n                        if (destMax > float(dest))\n                            destMax = float(dest);\n                    }\n\n                    for (auto k = static_cast<ptrdiff_t>(floorf(destMin)); float(k) < destMax; ++k)\n                    {\n                        float d0 = float(k);\n                        float d1 = d0 + 1.f;\n\n                        size_t u0;\n                        if (k < 0)\n                        {\n                            // Handle wrap\n                            u0 = size_t(k + ptrdiff_t(dest));\n                        }\n                        else if (k >= ptrdiff_t(dest))\n                        {\n                            // Handle wrap\n                            u0 = size_t(k - ptrdiff_t(dest));\n                        }\n                        else\n                        {\n                            u0 = size_t(k);\n                        }\n\n                        // Save previous accumulated weight (if any)\n                        if (u0 != accumU)\n                        {\n                            if (accumWeight > TF_EPSILON)\n                            {\n                                auto pTo = reinterpret_cast<FilterTo*>(pFilter + sizeInBytes);\n                                sizeInBytes += TF_TO_SIZE;\n                                ++toCount;\n\n                                if (sizeInBytes > totalSize)\n                                    return E_FAIL;\n\n                                pTo->u = accumU;\n                                pTo->weight = accumWeight;\n                            }\n\n                            accumWeight = 0.f;\n                            accumU = u0;\n                        }\n\n                        // Clip destination\n                        if (d0 < destMin)\n                            d0 = destMin;\n                        if (d1 > destMax)\n                            d1 = destMax;\n\n                        // Calculate average weight over destination pixel\n\n                        float weight;\n                        if (!wrap && src < 0.f)\n                            weight = 1.f;\n                        else if (!wrap && ((src + 1.f) >= float(source)))\n                            weight = 0.f;\n                        else\n                            weight = (d0 + d1) * scaleInv - src;\n\n                        accumWeight += (d1 - d0) * (j ? (1.f - weight) : weight);\n                    }\n                }\n\n                // Store accumulated weight\n                if (accumWeight > TF_EPSILON)\n                {\n                    auto pTo = reinterpret_cast<FilterTo*>(pFilter + sizeInBytes);\n                    sizeInBytes += TF_TO_SIZE;\n                    ++toCount;\n\n                    if (sizeInBytes > totalSize)\n                        return E_FAIL;\n\n                    pTo->u = accumU;\n                    pTo->weight = accumWeight;\n                }\n\n                accumWeight = 0.f;\n\n                // Finalize from entry\n                pFrom->count = toCount;\n                pFrom->sizeInBytes = sizeInBytes - sizeFrom;\n            }\n\n            tf->sizeInBytes = sizeInBytes;\n\n            return S_OK;\n        }\n\n    } // namespace Filters\n} // namespace DirectX\n"
  },
  {
    "path": "Tools/BCnCompressglTF/DirectXTex/scoped.h",
    "content": "//-------------------------------------------------------------------------------------\n// scoped.h\n//\n// Utility header with helper classes for exception-safe handling of resources\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//-------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <cassert>\n#include <cstddef>\n#include <cstdint>\n#include <memory>\n#include <tuple>\n\n#ifndef _WIN32\n#include <cstdlib>\n\nstruct aligned_deleter { void operator()(void* p) noexcept { free(p); } };\n\nusing ScopedAlignedArrayFloat = std::unique_ptr<float[], aligned_deleter>;\n\ninline ScopedAlignedArrayFloat make_AlignedArrayFloat(uint64_t count)\n{\n    uint64_t size = sizeof(float) * count;\n    size = (size + 15u) & ~0xF;\n    if (size > static_cast<uint64_t>(UINT32_MAX))\n        return nullptr;\n\n    auto ptr = aligned_alloc(16, static_cast<size_t>(size));\n    return ScopedAlignedArrayFloat(static_cast<float*>(ptr));\n}\n\nusing ScopedAlignedArrayXMVECTOR = std::unique_ptr<DirectX::XMVECTOR[], aligned_deleter>;\n\ninline ScopedAlignedArrayXMVECTOR make_AlignedArrayXMVECTOR(uint64_t count)\n{\n    uint64_t size = sizeof(DirectX::XMVECTOR) * count;\n    if (size > static_cast<uint64_t>(UINT32_MAX))\n        return nullptr;\n    auto ptr = aligned_alloc(16, static_cast<size_t>(size));\n    return ScopedAlignedArrayXMVECTOR(static_cast<DirectX::XMVECTOR*>(ptr));\n}\n\n#else // WIN32\n//---------------------------------------------------------------------------------\n#include <malloc.h>\n\nstruct aligned_deleter { void operator()(void* p) noexcept { _aligned_free(p); } };\n\nusing ScopedAlignedArrayFloat = std::unique_ptr<float[], aligned_deleter>;\n\ninline ScopedAlignedArrayFloat make_AlignedArrayFloat(uint64_t count)\n{\n    const uint64_t size = sizeof(float) * count;\n    if (size > static_cast<uint64_t>(UINT32_MAX))\n        return nullptr;\n    auto ptr = _aligned_malloc(static_cast<size_t>(size), 16);\n    return ScopedAlignedArrayFloat(static_cast<float*>(ptr));\n}\n\nusing ScopedAlignedArrayXMVECTOR = std::unique_ptr<DirectX::XMVECTOR[], aligned_deleter>;\n\ninline ScopedAlignedArrayXMVECTOR make_AlignedArrayXMVECTOR(uint64_t count)\n{\n    const uint64_t size = sizeof(DirectX::XMVECTOR) * count;\n    if (size > static_cast<uint64_t>(UINT32_MAX))\n        return nullptr;\n    auto ptr = _aligned_malloc(static_cast<size_t>(size), 16);\n    return ScopedAlignedArrayXMVECTOR(static_cast<DirectX::XMVECTOR*>(ptr));\n}\n\n//---------------------------------------------------------------------------------\nstruct handle_closer { void operator()(HANDLE h) noexcept { assert(h != INVALID_HANDLE_VALUE); if (h) CloseHandle(h); } };\n\nusing ScopedHandle = std::unique_ptr<void, handle_closer>;\n\ninline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }\n\n//---------------------------------------------------------------------------------\nstruct find_closer { void operator()(HANDLE h) noexcept { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };\n\nusing ScopedFindHandle = std::unique_ptr<void, find_closer>;\n\n//---------------------------------------------------------------------------------\nclass auto_delete_file\n{\npublic:\n    auto_delete_file(HANDLE hFile) noexcept : m_handle(hFile) {}\n\n    auto_delete_file(const auto_delete_file&) = delete;\n    auto_delete_file& operator=(const auto_delete_file&) = delete;\n\n    ~auto_delete_file()\n    {\n        if (m_handle)\n        {\n            FILE_DISPOSITION_INFO info = {};\n            info.DeleteFile = TRUE;\n            std::ignore = SetFileInformationByHandle(m_handle, FileDispositionInfo, &info, sizeof(info));\n        }\n    }\n\n    void clear() noexcept { m_handle = nullptr; }\n\nprivate:\n    HANDLE m_handle;\n};\n\n#endif // WIN32\n"
  },
  {
    "path": "Tools/BCnCompressglTF/TexConv/texconv.cpp",
    "content": "//--------------------------------------------------------------------------------------\n// File: TexConv.cpp\n//\n// DirectX Texture Converter\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n//--------------------------------------------------------------------------------------\n\n#include <Utility/Error.h>\n#include \"texconv.h\"\n\n#include <ShlObj.h>\n\n#include <algorithm>\n#include <cstdlib>\n#include <cstring>\n#include <fstream>\n#include <set>\n\n#include <wrl\\client.h>\n\n#include <wincodec.h>\n\n#pragma warning(disable : 4619 4616 26812)\n\n#include \"../DirectXTex/DirectXTex.h\"\n\n#include \"DirectXPackedVector.h\"\n\nusing namespace DirectX;\nusing namespace DirectX::PackedVector;\nusing Microsoft::WRL::ComPtr;\n\nnamespace\n{\n    enum OPTIONS : uint64_t\n    {\n        OPT_RECURSIVE = 1,\n        OPT_FILELIST,\n        OPT_WIDTH,\n        OPT_HEIGHT,\n        OPT_MIPLEVELS,\n        OPT_FORMAT,\n        OPT_FILTER,\n        OPT_SRGBI,\n        OPT_SRGBO,\n        OPT_SRGB,\n        OPT_PREFIX,\n        OPT_SUFFIX,\n        OPT_OUTPUTDIR,\n        OPT_TOLOWER,\n        OPT_OVERWRITE,\n        OPT_FILETYPE,\n        OPT_HFLIP,\n        OPT_VFLIP,\n        OPT_DDS_DWORD_ALIGN,\n        OPT_DDS_BAD_DXTN_TAILS,\n        OPT_USE_DX10,\n        OPT_USE_DX9,\n        OPT_TGA20,\n        OPT_WIC_QUALITY,\n        OPT_WIC_LOSSLESS,\n        OPT_WIC_MULTIFRAME,\n        OPT_NOLOGO,\n        OPT_TIMING,\n        OPT_SEPALPHA,\n        OPT_NO_WIC,\n        OPT_TYPELESS_UNORM,\n        OPT_TYPELESS_FLOAT,\n        OPT_PREMUL_ALPHA,\n        OPT_DEMUL_ALPHA,\n        OPT_EXPAND_LUMINANCE,\n        OPT_TA_WRAP,\n        OPT_TA_MIRROR,\n        OPT_FORCE_SINGLEPROC,\n        OPT_GPU,\n        OPT_NOGPU,\n        OPT_FEATURE_LEVEL,\n        OPT_FIT_POWEROF2,\n        OPT_ALPHA_THRESHOLD,\n        OPT_ALPHA_WEIGHT,\n        OPT_NORMAL_MAP,\n        OPT_NORMAL_MAP_AMPLITUDE,\n        OPT_BC_COMPRESS,\n        OPT_COLORKEY,\n        OPT_TONEMAP,\n        OPT_X2_BIAS,\n        OPT_PRESERVE_ALPHA_COVERAGE,\n        OPT_INVERT_Y,\n        OPT_RECONSTRUCT_Z,\n        OPT_ROTATE_COLOR,\n        OPT_PAPER_WHITE_NITS,\n        OPT_BCNONMULT4FIX,\n        OPT_SWIZZLE,\n        OPT_MAX\n    };\n\n    enum\n    {\n        ROTATE_709_TO_HDR10 = 1,\n        ROTATE_HDR10_TO_709,\n        ROTATE_709_TO_2020,\n        ROTATE_2020_TO_709,\n        ROTATE_P3D65_TO_HDR10,\n        ROTATE_P3D65_TO_2020,\n        ROTATE_709_TO_P3D65,\n        ROTATE_P3D65_TO_709,\n    };\n\n    static_assert(OPT_MAX <= 64, \"dwOptions is a unsigned int bitfield\");\n\n    struct SConversion\n    {\n        wchar_t szSrc[MAX_PATH];\n        wchar_t szFolder[MAX_PATH];\n    };\n\n    template<typename T>\n    struct SValue\n    {\n        const wchar_t*  name;\n        T               value;\n    };\n\n    const SValue<uint64_t> g_pOptions[] =\n    {\n        { L\"r\",             OPT_RECURSIVE },\n        { L\"flist\",         OPT_FILELIST },\n        { L\"w\",             OPT_WIDTH },\n        { L\"h\",             OPT_HEIGHT },\n        { L\"m\",             OPT_MIPLEVELS },\n        { L\"f\",             OPT_FORMAT },\n        { L\"if\",            OPT_FILTER },\n        { L\"srgbi\",         OPT_SRGBI },\n        { L\"srgbo\",         OPT_SRGBO },\n        { L\"srgb\",          OPT_SRGB },\n        { L\"px\",            OPT_PREFIX },\n        { L\"sx\",            OPT_SUFFIX },\n        { L\"o\",             OPT_OUTPUTDIR },\n        { L\"l\",             OPT_TOLOWER },\n        { L\"y\",             OPT_OVERWRITE },\n        { L\"ft\",            OPT_FILETYPE },\n        { L\"hflip\",         OPT_HFLIP },\n        { L\"vflip\",         OPT_VFLIP },\n        { L\"dword\",         OPT_DDS_DWORD_ALIGN },\n        { L\"badtails\",      OPT_DDS_BAD_DXTN_TAILS },\n        { L\"dx10\",          OPT_USE_DX10 },\n        { L\"dx9\",           OPT_USE_DX9 },\n        { L\"tga20\",         OPT_TGA20 },\n        { L\"wicq\",          OPT_WIC_QUALITY },\n        { L\"wiclossless\",   OPT_WIC_LOSSLESS },\n        { L\"wicmulti\",      OPT_WIC_MULTIFRAME },\n        { L\"nologo\",        OPT_NOLOGO },\n        { L\"timing\",        OPT_TIMING },\n        { L\"sepalpha\",      OPT_SEPALPHA },\n        { L\"keepcoverage\",  OPT_PRESERVE_ALPHA_COVERAGE },\n        { L\"nowic\",         OPT_NO_WIC },\n        { L\"tu\",            OPT_TYPELESS_UNORM },\n        { L\"tf\",            OPT_TYPELESS_FLOAT },\n        { L\"pmalpha\",       OPT_PREMUL_ALPHA },\n        { L\"alpha\",         OPT_DEMUL_ALPHA },\n        { L\"xlum\",          OPT_EXPAND_LUMINANCE },\n        { L\"wrap\",          OPT_TA_WRAP },\n        { L\"mirror\",        OPT_TA_MIRROR },\n        { L\"singleproc\",    OPT_FORCE_SINGLEPROC },\n        { L\"gpu\",           OPT_GPU },\n        { L\"nogpu\",         OPT_NOGPU },\n        { L\"fl\",            OPT_FEATURE_LEVEL },\n        { L\"pow2\",          OPT_FIT_POWEROF2 },\n        { L\"at\",            OPT_ALPHA_THRESHOLD },\n        { L\"aw\",            OPT_ALPHA_WEIGHT },\n        { L\"nmap\",          OPT_NORMAL_MAP },\n        { L\"nmapamp\",       OPT_NORMAL_MAP_AMPLITUDE },\n        { L\"bc\",            OPT_BC_COMPRESS },\n        { L\"c\",             OPT_COLORKEY },\n        { L\"tonemap\",       OPT_TONEMAP },\n        { L\"x2bias\",        OPT_X2_BIAS },\n        { L\"inverty\",       OPT_INVERT_Y },\n        { L\"reconstructz\",  OPT_RECONSTRUCT_Z },\n        { L\"rotatecolor\",   OPT_ROTATE_COLOR },\n        { L\"nits\",          OPT_PAPER_WHITE_NITS },\n        { L\"fixbc4x4\",      OPT_BCNONMULT4FIX },\n        { L\"swizzle\",       OPT_SWIZZLE },\n        { nullptr,          0 }\n    };\n\n#define DEFFMT(fmt) { L## #fmt, DXGI_FORMAT_ ## fmt }\n\n    const SValue<uint32_t> g_pFormats[] =\n    {\n        // List does not include _TYPELESS or depth/stencil formats\n        DEFFMT(R32G32B32A32_FLOAT),\n        DEFFMT(R32G32B32A32_UINT),\n        DEFFMT(R32G32B32A32_SINT),\n        DEFFMT(R32G32B32_FLOAT),\n        DEFFMT(R32G32B32_UINT),\n        DEFFMT(R32G32B32_SINT),\n        DEFFMT(R16G16B16A16_FLOAT),\n        DEFFMT(R16G16B16A16_UNORM),\n        DEFFMT(R16G16B16A16_UINT),\n        DEFFMT(R16G16B16A16_SNORM),\n        DEFFMT(R16G16B16A16_SINT),\n        DEFFMT(R32G32_FLOAT),\n        DEFFMT(R32G32_UINT),\n        DEFFMT(R32G32_SINT),\n        DEFFMT(R10G10B10A2_UNORM),\n        DEFFMT(R10G10B10A2_UINT),\n        DEFFMT(R11G11B10_FLOAT),\n        DEFFMT(R8G8B8A8_UNORM),\n        DEFFMT(R8G8B8A8_UNORM_SRGB),\n        DEFFMT(R8G8B8A8_UINT),\n        DEFFMT(R8G8B8A8_SNORM),\n        DEFFMT(R8G8B8A8_SINT),\n        DEFFMT(R16G16_FLOAT),\n        DEFFMT(R16G16_UNORM),\n        DEFFMT(R16G16_UINT),\n        DEFFMT(R16G16_SNORM),\n        DEFFMT(R16G16_SINT),\n        DEFFMT(R32_FLOAT),\n        DEFFMT(R32_UINT),\n        DEFFMT(R32_SINT),\n        DEFFMT(R8G8_UNORM),\n        DEFFMT(R8G8_UINT),\n        DEFFMT(R8G8_SNORM),\n        DEFFMT(R8G8_SINT),\n        DEFFMT(R16_FLOAT),\n        DEFFMT(R16_UNORM),\n        DEFFMT(R16_UINT),\n        DEFFMT(R16_SNORM),\n        DEFFMT(R16_SINT),\n        DEFFMT(R8_UNORM),\n        DEFFMT(R8_UINT),\n        DEFFMT(R8_SNORM),\n        DEFFMT(R8_SINT),\n        DEFFMT(A8_UNORM),\n        DEFFMT(R9G9B9E5_SHAREDEXP),\n        DEFFMT(R8G8_B8G8_UNORM),\n        DEFFMT(G8R8_G8B8_UNORM),\n        DEFFMT(BC1_UNORM),\n        DEFFMT(BC1_UNORM_SRGB),\n        DEFFMT(BC2_UNORM),\n        DEFFMT(BC2_UNORM_SRGB),\n        DEFFMT(BC3_UNORM),\n        DEFFMT(BC3_UNORM_SRGB),\n        DEFFMT(BC4_UNORM),\n        DEFFMT(BC4_SNORM),\n        DEFFMT(BC5_UNORM),\n        DEFFMT(BC5_SNORM),\n        DEFFMT(B5G6R5_UNORM),\n        DEFFMT(B5G5R5A1_UNORM),\n\n        // DXGI 1.1 formats\n        DEFFMT(B8G8R8A8_UNORM),\n        DEFFMT(B8G8R8X8_UNORM),\n        DEFFMT(R10G10B10_XR_BIAS_A2_UNORM),\n        DEFFMT(B8G8R8A8_UNORM_SRGB),\n        DEFFMT(B8G8R8X8_UNORM_SRGB),\n        DEFFMT(BC6H_UF16),\n        DEFFMT(BC6H_SF16),\n        DEFFMT(BC7_UNORM),\n        DEFFMT(BC7_UNORM_SRGB),\n\n        // DXGI 1.2 formats\n        DEFFMT(AYUV),\n        DEFFMT(Y410),\n        DEFFMT(Y416),\n        DEFFMT(YUY2),\n        DEFFMT(Y210),\n        DEFFMT(Y216),\n        // No support for legacy paletted video formats (AI44, IA44, P8, A8P8)\n        DEFFMT(B4G4R4A4_UNORM),\n\n        { nullptr, DXGI_FORMAT_UNKNOWN }\n    };\n\n    const SValue<uint32_t> g_pFormatAliases[] =\n    {\n        { L\"DXT1\", DXGI_FORMAT_BC1_UNORM },\n        { L\"DXT2\", DXGI_FORMAT_BC2_UNORM },\n        { L\"DXT3\", DXGI_FORMAT_BC2_UNORM },\n        { L\"DXT4\", DXGI_FORMAT_BC3_UNORM },\n        { L\"DXT5\", DXGI_FORMAT_BC3_UNORM },\n\n        { L\"RGBA\", DXGI_FORMAT_R8G8B8A8_UNORM },\n        { L\"BGRA\", DXGI_FORMAT_B8G8R8A8_UNORM },\n        { L\"BGR\",  DXGI_FORMAT_B8G8R8X8_UNORM },\n\n        { L\"FP16\", DXGI_FORMAT_R16G16B16A16_FLOAT },\n        { L\"FP32\", DXGI_FORMAT_R32G32B32A32_FLOAT },\n\n        { L\"BPTC\", DXGI_FORMAT_BC7_UNORM },\n        { L\"BPTC_FLOAT\", DXGI_FORMAT_BC6H_UF16 },\n\n        { nullptr, DXGI_FORMAT_UNKNOWN }\n    };\n\n    const SValue<uint32_t> g_pReadOnlyFormats[] =\n    {\n        DEFFMT(R32G32B32A32_TYPELESS),\n        DEFFMT(R32G32B32_TYPELESS),\n        DEFFMT(R16G16B16A16_TYPELESS),\n        DEFFMT(R32G32_TYPELESS),\n        DEFFMT(R32G8X24_TYPELESS),\n        DEFFMT(D32_FLOAT_S8X24_UINT),\n        DEFFMT(R32_FLOAT_X8X24_TYPELESS),\n        DEFFMT(X32_TYPELESS_G8X24_UINT),\n        DEFFMT(R10G10B10A2_TYPELESS),\n        DEFFMT(R8G8B8A8_TYPELESS),\n        DEFFMT(R16G16_TYPELESS),\n        DEFFMT(R32_TYPELESS),\n        DEFFMT(D32_FLOAT),\n        DEFFMT(R24G8_TYPELESS),\n        DEFFMT(D24_UNORM_S8_UINT),\n        DEFFMT(R24_UNORM_X8_TYPELESS),\n        DEFFMT(X24_TYPELESS_G8_UINT),\n        DEFFMT(R8G8_TYPELESS),\n        DEFFMT(R16_TYPELESS),\n        DEFFMT(R8_TYPELESS),\n        DEFFMT(BC1_TYPELESS),\n        DEFFMT(BC2_TYPELESS),\n        DEFFMT(BC3_TYPELESS),\n        DEFFMT(BC4_TYPELESS),\n        DEFFMT(BC5_TYPELESS),\n\n        // DXGI 1.1 formats\n        DEFFMT(B8G8R8A8_TYPELESS),\n        DEFFMT(B8G8R8X8_TYPELESS),\n        DEFFMT(BC6H_TYPELESS),\n        DEFFMT(BC7_TYPELESS),\n\n        // DXGI 1.2 formats\n        DEFFMT(NV12),\n        DEFFMT(P010),\n        DEFFMT(P016),\n        DEFFMT(420_OPAQUE),\n        DEFFMT(NV11),\n\n        // DXGI 1.3 formats\n        { L\"P208\", DXGI_FORMAT(130) },\n        { L\"V208\", DXGI_FORMAT(131) },\n        { L\"V408\", DXGI_FORMAT(132) },\n\n        { nullptr, DXGI_FORMAT_UNKNOWN }\n    };\n\n    const SValue<uint32_t> g_pFilters[] =\n    {\n        { L\"POINT\",                     TEX_FILTER_POINT },\n        { L\"LINEAR\",                    TEX_FILTER_LINEAR },\n        { L\"CUBIC\",                     TEX_FILTER_CUBIC },\n        { L\"FANT\",                      TEX_FILTER_FANT },\n        { L\"BOX\",                       TEX_FILTER_BOX },\n        { L\"TRIANGLE\",                  TEX_FILTER_TRIANGLE },\n        { L\"POINT_DITHER\",              TEX_FILTER_POINT | TEX_FILTER_DITHER },\n        { L\"LINEAR_DITHER\",             TEX_FILTER_LINEAR | TEX_FILTER_DITHER },\n        { L\"CUBIC_DITHER\",              TEX_FILTER_CUBIC | TEX_FILTER_DITHER },\n        { L\"FANT_DITHER\",               TEX_FILTER_FANT | TEX_FILTER_DITHER },\n        { L\"BOX_DITHER\",                TEX_FILTER_BOX | TEX_FILTER_DITHER },\n        { L\"TRIANGLE_DITHER\",           TEX_FILTER_TRIANGLE | TEX_FILTER_DITHER },\n        { L\"POINT_DITHER_DIFFUSION\",    TEX_FILTER_POINT | TEX_FILTER_DITHER_DIFFUSION },\n        { L\"LINEAR_DITHER_DIFFUSION\",   TEX_FILTER_LINEAR | TEX_FILTER_DITHER_DIFFUSION },\n        { L\"CUBIC_DITHER_DIFFUSION\",    TEX_FILTER_CUBIC | TEX_FILTER_DITHER_DIFFUSION },\n        { L\"FANT_DITHER_DIFFUSION\",     TEX_FILTER_FANT | TEX_FILTER_DITHER_DIFFUSION },\n        { L\"BOX_DITHER_DIFFUSION\",      TEX_FILTER_BOX | TEX_FILTER_DITHER_DIFFUSION },\n        { L\"TRIANGLE_DITHER_DIFFUSION\", TEX_FILTER_TRIANGLE | TEX_FILTER_DITHER_DIFFUSION },\n        { nullptr,                      TEX_FILTER_DEFAULT                              }\n    };\n\n    const SValue<uint32_t> g_pRotateColor[] =\n    {\n        { L\"709to2020\",     ROTATE_709_TO_2020 },\n        { L\"2020to709\",     ROTATE_2020_TO_709 },\n        { L\"709toHDR10\",    ROTATE_709_TO_HDR10 },\n        { L\"HDR10to709\",    ROTATE_HDR10_TO_709 },\n        { L\"P3D65to2020\",   ROTATE_P3D65_TO_2020 },\n        { L\"P3D65toHDR10\",  ROTATE_P3D65_TO_HDR10 },\n        { L\"709toP3D65\",    ROTATE_709_TO_P3D65 },\n        { L\"P3D65to709\",    ROTATE_P3D65_TO_709 },\n        { nullptr, 0 },\n    };\n\n#define CODEC_DDS 0xFFFF0001\n#define CODEC_TGA 0xFFFF0002\n#define CODEC_HDP 0xFFFF0003\n#define CODEC_JXR 0xFFFF0004\n#define CODEC_HDR 0xFFFF0005\n#define CODEC_PPM 0xFFFF0006\n#define CODEC_PFM 0xFFFF0007\n\n#ifdef USE_OPENEXR\n#define CODEC_EXR 0xFFFF0008\n#endif\n\n    const SValue<uint32_t> g_pSaveFileTypes[] =   // valid formats to write to\n    {\n        { L\"bmp\",   WIC_CODEC_BMP  },\n        { L\"jpg\",   WIC_CODEC_JPEG },\n        { L\"jpeg\",  WIC_CODEC_JPEG },\n        { L\"png\",   WIC_CODEC_PNG  },\n        { L\"dds\",   CODEC_DDS      },\n        { L\"tga\",   CODEC_TGA      },\n        { L\"hdr\",   CODEC_HDR      },\n        { L\"tif\",   WIC_CODEC_TIFF },\n        { L\"tiff\",  WIC_CODEC_TIFF },\n        { L\"wdp\",   WIC_CODEC_WMP  },\n        { L\"hdp\",   CODEC_HDP      },\n        { L\"jxr\",   CODEC_JXR      },\n        { L\"ppm\",   CODEC_PPM      },\n        { L\"pfm\",   CODEC_PFM      },\n    #ifdef USE_OPENEXR\n        { L\"exr\",   CODEC_EXR      },\n    #endif\n        { L\"heic\",  WIC_CODEC_HEIF },\n        { L\"heif\",  WIC_CODEC_HEIF },\n        { nullptr,  CODEC_DDS      }\n    };\n\n    const SValue<uint32_t> g_pFeatureLevels[] =   // valid feature levels for -fl for maximimum size\n    {\n        { L\"9.1\",  2048 },\n        { L\"9.2\",  2048 },\n        { L\"9.3\",  4096 },\n        { L\"10.0\", 8192 },\n        { L\"10.1\", 8192 },\n        { L\"11.0\", 16384 },\n        { L\"11.1\", 16384 },\n        { L\"12.0\", 16384 },\n        { L\"12.1\", 16384 },\n        { L\"12.2\", 16384 },\n        { nullptr, 0 },\n    };\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////\n\n#pragma warning( disable : 4616 6211 )\n\nnamespace\n{\n    inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }\n\n    struct find_closer { void operator()(HANDLE h) noexcept { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };\n\n    using ScopedFindHandle = std::unique_ptr<void, find_closer>;\n\n    constexpr static bool ispow2(size_t x)\n    {\n        return ((x != 0) && !(x & (x - 1)));\n    }\n\n#ifdef _PREFAST_\n#pragma prefast(disable : 26018, \"Only used with static internal arrays\")\n#endif\n\n    template<typename T>\n    T LookupByName(const wchar_t *pName, const SValue<T> *pArray)\n    {\n        while (pArray->name)\n        {\n            if (!_wcsicmp(pName, pArray->name))\n                return pArray->value;\n\n            pArray++;\n        }\n\n        return 0;\n    }\n\n    template<typename T>\n    const wchar_t* LookupByValue(T value, const SValue<T> *pArray)\n    {\n        while (pArray->name)\n        {\n            if (value == pArray->value)\n                return pArray->name;\n\n            pArray++;\n        }\n\n        return L\"\";\n    }\n\n    void SearchForFiles(const wchar_t* path, std::list<SConversion>& files, bool recursive, const wchar_t* folder)\n    {\n        // Process files\n        WIN32_FIND_DATAW findData = {};\n        ScopedFindHandle hFile(safe_handle(FindFirstFileExW(path,\n            FindExInfoBasic, &findData,\n            FindExSearchNameMatch, nullptr,\n            FIND_FIRST_EX_LARGE_FETCH)));\n        if (hFile)\n        {\n            for (;;)\n            {\n                if (!(findData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)))\n                {\n                    wchar_t drive[_MAX_DRIVE] = {};\n                    wchar_t dir[_MAX_DIR] = {};\n                    _wsplitpath_s(path, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);\n\n                    SConversion conv = {};\n                    _wmakepath_s(conv.szSrc, drive, dir, findData.cFileName, nullptr);\n                    if (folder)\n                    {\n                        wcscpy_s(conv.szFolder, folder);\n                    }\n                    files.push_back(conv);\n                }\n\n                if (!FindNextFileW(hFile.get(), &findData))\n                    break;\n            }\n        }\n\n        // Process directories\n        if (recursive)\n        {\n            wchar_t searchDir[MAX_PATH] = {};\n            {\n                wchar_t drive[_MAX_DRIVE] = {};\n                wchar_t dir[_MAX_DIR] = {};\n                _wsplitpath_s(path, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);\n                _wmakepath_s(searchDir, drive, dir, L\"*\", nullptr);\n            }\n\n            hFile.reset(safe_handle(FindFirstFileExW(searchDir,\n                FindExInfoBasic, &findData,\n                FindExSearchLimitToDirectories, nullptr,\n                FIND_FIRST_EX_LARGE_FETCH)));\n            if (!hFile)\n                return;\n\n            for (;;)\n            {\n                if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n                {\n                    if (findData.cFileName[0] != L'.')\n                    {\n                        wchar_t subdir[MAX_PATH] = {};\n                        auto subfolder = (folder)\n                            ? (std::wstring(folder) + std::wstring(findData.cFileName) + L\"\\\\\")\n                            : (std::wstring(findData.cFileName) + L\"\\\\\");\n                        {\n                            wchar_t drive[_MAX_DRIVE] = {};\n                            wchar_t dir[_MAX_DIR] = {};\n                            wchar_t fname[_MAX_FNAME] = {};\n                            wchar_t ext[_MAX_FNAME] = {};\n                            _wsplitpath_s(path, drive, dir, fname, ext);\n                            wcscat_s(dir, findData.cFileName);\n                            _wmakepath_s(subdir, drive, dir, fname, ext);\n                        }\n\n                        SearchForFiles(subdir, files, recursive, subfolder.c_str());\n                    }\n                }\n\n                if (!FindNextFileW(hFile.get(), &findData))\n                    break;\n            }\n        }\n    }\n\n    void ProcessFileList(std::wifstream& inFile, std::list<SConversion>& files)\n    {\n        std::list<SConversion> flist;\n        std::set<std::wstring> excludes;\n        wchar_t fname[1024] = {};\n        for (;;)\n        {\n            inFile >> fname;\n            if (!inFile)\n                break;\n\n            if (*fname == L'#')\n            {\n                // Comment\n            }\n            else if (*fname == L'-')\n            {\n                if (flist.empty())\n                {\n                    wprintf(L\"WARNING: Ignoring the line '%ls' in -flist\\n\", fname);\n                }\n                else\n                {\n                    if (wcspbrk(fname, L\"?*\") != nullptr)\n                    {\n                        std::list<SConversion> removeFiles;\n                        SearchForFiles(&fname[1], removeFiles, false, nullptr);\n\n                        for (auto it : removeFiles)\n                        {\n                            _wcslwr_s(it.szSrc);\n                            excludes.insert(it.szSrc);\n                        }\n                    }\n                    else\n                    {\n                        std::wstring name = (fname + 1);\n                        std::transform(name.begin(), name.end(), name.begin(), towlower);\n                        excludes.insert(name);\n                    }\n                }\n            }\n            else if (wcspbrk(fname, L\"?*\") != nullptr)\n            {\n                SearchForFiles(fname, flist, false, nullptr);\n            }\n            else\n            {\n                SConversion conv = {};\n                wcscpy_s(conv.szSrc, MAX_PATH, fname);\n                flist.push_back(conv);\n            }\n\n            inFile.ignore(1000, '\\n');\n        }\n\n        inFile.close();\n\n        if (!excludes.empty())\n        {\n            // Remove any excluded files\n            for (auto it = flist.begin(); it != flist.end();)\n            {\n                std::wstring name = it->szSrc;\n                std::transform(name.begin(), name.end(), name.begin(), towlower);\n                auto item = it;\n                ++it;\n                if (excludes.find(name) != excludes.end())\n                {\n                    flist.erase(item);\n                }\n            }\n        }\n\n        if (flist.empty())\n        {\n            wprintf(L\"WARNING: No file names found in -flist\\n\");\n        }\n        else\n        {\n            files.splice(files.end(), flist);\n        }\n    }\n\n    void PrintFormat(DXGI_FORMAT Format)\n    {\n        for (auto pFormat = g_pFormats; pFormat->name; pFormat++)\n        {\n            if (static_cast<DXGI_FORMAT>(pFormat->value) == Format)\n            {\n                wprintf(L\"%ls\", pFormat->name);\n                return;\n            }\n        }\n\n        for (auto pFormat = g_pReadOnlyFormats; pFormat->name; pFormat++)\n        {\n            if (static_cast<DXGI_FORMAT>(pFormat->value) == Format)\n            {\n                wprintf(L\"%ls\", pFormat->name);\n                return;\n            }\n        }\n\n        wprintf(L\"*UNKNOWN*\");\n    }\n\n    void PrintInfo(const TexMetadata& info)\n    {\n        wprintf(L\" (%zux%zu\", info.width, info.height);\n\n        if (TEX_DIMENSION_TEXTURE3D == info.dimension)\n            wprintf(L\"x%zu\", info.depth);\n\n        if (info.mipLevels > 1)\n            wprintf(L\",%zu\", info.mipLevels);\n\n        if (info.arraySize > 1)\n            wprintf(L\",%zu\", info.arraySize);\n\n        wprintf(L\" \");\n        PrintFormat(info.format);\n\n        switch (info.dimension)\n        {\n        case TEX_DIMENSION_TEXTURE1D:\n            wprintf(L\"%ls\", (info.arraySize > 1) ? L\" 1DArray\" : L\" 1D\");\n            break;\n\n        case TEX_DIMENSION_TEXTURE2D:\n            if (info.IsCubemap())\n            {\n                wprintf(L\"%ls\", (info.arraySize > 6) ? L\" CubeArray\" : L\" Cube\");\n            }\n            else\n            {\n                wprintf(L\"%ls\", (info.arraySize > 1) ? L\" 2DArray\" : L\" 2D\");\n            }\n            break;\n\n        case TEX_DIMENSION_TEXTURE3D:\n            wprintf(L\" 3D\");\n            break;\n        }\n\n        switch (info.GetAlphaMode())\n        {\n        case TEX_ALPHA_MODE_OPAQUE:\n            wprintf(L\" \\x0e0:Opaque\");\n            break;\n        case TEX_ALPHA_MODE_PREMULTIPLIED:\n            wprintf(L\" \\x0e0:PM\");\n            break;\n        case TEX_ALPHA_MODE_STRAIGHT:\n            wprintf(L\" \\x0e0:NonPM\");\n            break;\n        case TEX_ALPHA_MODE_CUSTOM:\n            wprintf(L\" \\x0e0:Custom\");\n            break;\n        case TEX_ALPHA_MODE_UNKNOWN:\n            break;\n        }\n\n        wprintf(L\")\");\n    }\n\n    void PrintList(size_t cch, const SValue<uint32_t> *pValue)\n    {\n        while (pValue->name)\n        {\n            const size_t cchName = wcslen(pValue->name);\n\n            if (cch + cchName + 2 >= 80)\n            {\n                wprintf(L\"\\n      \");\n                cch = 6;\n            }\n\n            wprintf(L\"%ls \", pValue->name);\n            cch += cchName + 2;\n            pValue++;\n        }\n\n        wprintf(L\"\\n\");\n    }\n\n    void PrintLogo()\n    {\n        wchar_t version[32] = {};\n\n        wchar_t appName[_MAX_PATH] = {};\n        if (GetModuleFileNameW(nullptr, appName, static_cast<UINT>(std::size(appName))))\n        {\n            const DWORD size = GetFileVersionInfoSizeW(appName, nullptr);\n            if (size > 0)\n            {\n                auto verInfo = std::make_unique<uint8_t[]>(size);\n                if (GetFileVersionInfoW(appName, 0, size, verInfo.get()))\n                {\n                    LPVOID lpstr = nullptr;\n                    UINT strLen = 0;\n                    if (VerQueryValueW(verInfo.get(), L\"\\\\StringFileInfo\\\\040904B0\\\\ProductVersion\", &lpstr, &strLen))\n                    {\n                        wcsncpy_s(version, reinterpret_cast<const wchar_t*>(lpstr), strLen);\n                    }\n                }\n            }\n        }\n\n        if (!*version || wcscmp(version, L\"1.0.0.0\") == 0)\n        {\n            swprintf_s(version, L\"%03d (library)\", DIRECTX_TEX_VERSION);\n        }\n\n        wprintf(L\"Microsoft (R) DirectX Texture Converter [DirectXTex] Version %ls\\n\", version);\n        wprintf(L\"Copyright (C) Microsoft Corp.\\n\");\n    #ifdef _DEBUG\n        wprintf(L\"*** Debug build ***\\n\");\n    #endif\n        wprintf(L\"\\n\");\n    }\n\n    _Success_(return)\n        bool GetDXGIFactory(_Outptr_ IDXGIFactory1** pFactory)\n    {\n        if (!pFactory)\n            return false;\n\n        *pFactory = nullptr;\n\n        typedef HRESULT(WINAPI* pfn_CreateDXGIFactory1)(REFIID riid, _Out_ void **ppFactory);\n\n        static pfn_CreateDXGIFactory1 s_CreateDXGIFactory1 = nullptr;\n\n        if (!s_CreateDXGIFactory1)\n        {\n            HMODULE hModDXGI = LoadLibraryW(L\"dxgi.dll\");\n            if (!hModDXGI)\n                return false;\n\n            s_CreateDXGIFactory1 = reinterpret_cast<pfn_CreateDXGIFactory1>(reinterpret_cast<void*>(GetProcAddress(hModDXGI, \"CreateDXGIFactory1\")));\n            if (!s_CreateDXGIFactory1)\n                return false;\n        }\n\n        return SUCCEEDED(s_CreateDXGIFactory1(IID_PPV_ARGS(pFactory)));\n    }\n\n    void PrintUsage()\n    {\n        PrintLogo();\n\n        wprintf(L\"Usage: texconv <options> <files>\\n\\n\");\n        wprintf(L\"   -r                  wildcard filename search is recursive\\n\");\n        wprintf(L\"     -r:flatten        flatten the directory structure (default)\\n\");\n        wprintf(L\"     -r:keep           keep the directory structure\\n\");\n        wprintf(L\"   -flist <filename>   use text file with a list of input files (one per line)\\n\");\n        wprintf(L\"\\n   -w <n>              width\\n\");\n        wprintf(L\"   -h <n>              height\\n\");\n        wprintf(L\"   -m <n>              miplevels\\n\");\n        wprintf(L\"   -f <format>         format\\n\");\n        wprintf(L\"\\n   -if <filter>        image filtering\\n\");\n        wprintf(L\"   -srgb{i|o}          sRGB {input, output}\\n\");\n        wprintf(L\"\\n   -px <string>        name prefix\\n\");\n        wprintf(L\"   -sx <string>        name suffix\\n\");\n        wprintf(L\"   -o <directory>      output directory\\n\");\n        wprintf(L\"   -l                  force output filename to lower case\\n\");\n        wprintf(L\"   -y                  overwrite existing output file (if any)\\n\");\n        wprintf(L\"   -ft <filetype>      output file type\\n\");\n        wprintf(L\"\\n   -hflip              horizonal flip of source image\\n\");\n        wprintf(L\"   -vflip              vertical flip of source image\\n\");\n        wprintf(L\"\\n   -sepalpha           resize/generate mips alpha channel separately\\n\");\n        wprintf(L\"                       from color channels\\n\");\n        wprintf(L\"   -keepcoverage <ref> Preserve alpha coverage in mips for alpha test ref\\n\");\n        wprintf(L\"\\n   -nowic              Force non-WIC filtering\\n\");\n        wprintf(L\"   -wrap, -mirror      texture addressing mode (wrap, mirror, or clamp)\\n\");\n        wprintf(L\"   -pmalpha            convert final texture to use premultiplied alpha\\n\");\n        wprintf(L\"   -alpha              convert premultiplied alpha to straight alpha\\n\");\n        wprintf(\n            L\"   -at <threshold>     Alpha threshold used for BC1, RGBA5551, and WIC\\n\"\n            L\"                       (defaults to 0.5)\\n\");\n        wprintf(L\"\\n   -fl <feature-level> Set maximum feature level target (defaults to 11.0)\\n\");\n        wprintf(L\"   -pow2               resize to fit a power-of-2, respecting aspect ratio\\n\");\n        wprintf(\n            L\"\\n   -nmap <options>     converts height-map to normal-map\\n\"\n            L\"                       options must be one or more of\\n\"\n            L\"                          r, g, b, a, l, m, u, v, i, o\\n\");\n        wprintf(L\"   -nmapamp <weight>   normal map amplitude (defaults to 1.0)\\n\");\n        wprintf(L\"\\n                       (DDS input only)\\n\");\n        wprintf(L\"   -t{u|f}             TYPELESS format is treated as UNORM or FLOAT\\n\");\n        wprintf(L\"   -dword              Use DWORD instead of BYTE alignment\\n\");\n        wprintf(L\"   -badtails           Fix for older DXTn with bad mipchain tails\\n\");\n        wprintf(L\"   -fixbc4x4           Fix for odd-sized BC files that Direct3D can't load\\n\");\n        wprintf(L\"   -xlum               expand legacy L8, L16, and A8P8 formats\\n\");\n        wprintf(L\"\\n                       (DDS output only)\\n\");\n        wprintf(L\"   -dx10               Force use of 'DX10' extended header\\n\");\n        wprintf(L\"   -dx9                Force use of legacy DX9 header\\n\");\n        wprintf(L\"\\n                       (TGA output only)\\n\");\n        wprintf(L\"   -tga20              Write file including TGA 2.0 extension area\\n\");\n        wprintf(L\"\\n                       (BMP, PNG, JPG, TIF, WDP output only)\\n\");\n        wprintf(L\"   -wicq <quality>     When writing images with WIC use quality (0.0 to 1.0)\\n\");\n        wprintf(L\"   -wiclossless        When writing images with WIC use lossless mode\\n\");\n        wprintf(L\"   -wicmulti           When writing images with WIC encode multiframe images\\n\");\n        wprintf(L\"\\n   -nologo             suppress copyright message\\n\");\n        wprintf(L\"   -timing             Display elapsed processing time\\n\\n\");\n    #ifdef _OPENMP\n        wprintf(L\"   -singleproc         Do not use multi-threaded compression\\n\");\n    #endif\n        wprintf(L\"   -gpu <adapter>      Select GPU for DirectCompute-based codecs (0 is default)\\n\");\n        wprintf(L\"   -nogpu              Do not use DirectCompute-based codecs\\n\");\n        wprintf(\n            L\"\\n   -bc <options>       Sets options for BC compression\\n\"\n            L\"                       options must be one or more of\\n\"\n            L\"                          d, u, q, x\\n\");\n        wprintf(\n            L\"   -aw <weight>        BC7 GPU compressor weighting for alpha error metric\\n\"\n            L\"                       (defaults to 1.0)\\n\");\n        wprintf(L\"\\n   -c <hex-RGB>        colorkey (a.k.a. chromakey) transparency\\n\");\n        wprintf(L\"   -rotatecolor <rot>  rotates color primaries and/or applies a curve\\n\");\n        wprintf(L\"   -nits <value>       paper-white value in nits to use for HDR10 (def: 200.0)\\n\");\n        wprintf(L\"   -tonemap            Apply a tonemap operator based on maximum luminance\\n\");\n        wprintf(L\"   -x2bias             Enable *2 - 1 conversion cases for unorm/pos-only-float\\n\");\n        wprintf(L\"   -inverty            Invert Y (i.e. green) channel values\\n\");\n        wprintf(L\"   -reconstructz       Rebuild Z (blue) channel assuming X/Y are normals\\n\");\n        wprintf(L\"   -swizzle <rgba>     Swizzle image channels using HLSL-style mask\\n\");\n\n        wprintf(L\"\\n   <format>: \");\n        PrintList(13, g_pFormats);\n        wprintf(L\"      \");\n        PrintList(13, g_pFormatAliases);\n\n        wprintf(L\"\\n   <filter>: \");\n        PrintList(13, g_pFilters);\n\n        wprintf(L\"\\n   <rot>: \");\n        PrintList(13, g_pRotateColor);\n\n        wprintf(L\"\\n   <filetype>: \");\n        PrintList(15, g_pSaveFileTypes);\n\n        wprintf(L\"\\n   <feature-level>: \");\n        PrintList(13, g_pFeatureLevels);\n\n        ComPtr<IDXGIFactory1> dxgiFactory;\n        if (GetDXGIFactory(dxgiFactory.GetAddressOf()))\n        {\n            wprintf(L\"\\n   <adapter>:\\n\");\n\n            ComPtr<IDXGIAdapter> adapter;\n            for (UINT adapterIndex = 0;\n                SUCCEEDED(dxgiFactory->EnumAdapters(adapterIndex, adapter.ReleaseAndGetAddressOf()));\n                ++adapterIndex)\n            {\n                DXGI_ADAPTER_DESC desc;\n                if (SUCCEEDED(adapter->GetDesc(&desc)))\n                {\n                    wprintf(L\"      %u: VID:%04X, PID:%04X - %ls\\n\", adapterIndex, desc.VendorId, desc.DeviceId, desc.Description);\n                }\n            }\n        }\n    }\n\n    const wchar_t* GetErrorDesc(HRESULT hr)\n    {\n        static wchar_t desc[1024] = {};\n\n        LPWSTR errorText = nullptr;\n\n        const DWORD result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,\n            nullptr, static_cast<DWORD>(hr),\n            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&errorText), 0, nullptr);\n\n        *desc = 0;\n\n        if (result > 0 && errorText)\n        {\n            swprintf_s(desc, L\": %ls\", errorText);\n\n            size_t len = wcslen(desc);\n            if (len >= 1)\n            {\n                desc[len - 1] = 0;\n            }\n\n            if (errorText)\n                LocalFree(errorText);\n        }\n\n        return desc;\n    }\n\n    void FitPowerOf2(size_t origx, size_t origy, _Inout_ size_t& targetx, _Inout_ size_t& targety, size_t maxsize)\n    {\n        const float origAR = float(origx) / float(origy);\n\n        if (origx > origy)\n        {\n            size_t x;\n            for (x = maxsize; x > 1; x >>= 1) { if (x <= targetx) break; }\n            targetx = x;\n\n            float bestScore = FLT_MAX;\n            for (size_t y = maxsize; y > 0; y >>= 1)\n            {\n                const float score = fabsf((float(x) / float(y)) - origAR);\n                if (score < bestScore)\n                {\n                    bestScore = score;\n                    targety = y;\n                }\n            }\n        }\n        else\n        {\n            size_t y;\n            for (y = maxsize; y > 1; y >>= 1) { if (y <= targety) break; }\n            targety = y;\n\n            float bestScore = FLT_MAX;\n            for (size_t x = maxsize; x > 0; x >>= 1)\n            {\n                const float score = fabsf((float(x) / float(y)) - origAR);\n                if (score < bestScore)\n                {\n                    bestScore = score;\n                    targetx = x;\n                }\n            }\n        }\n    }\n\n    constexpr size_t CountMips(_In_ size_t width, _In_ size_t height) noexcept\n    {\n        size_t mipLevels = 1;\n\n        while (height > 1 || width > 1)\n        {\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n\n            ++mipLevels;\n        }\n\n        return mipLevels;\n    }\n\n    constexpr size_t CountMips3D(_In_ size_t width, _In_ size_t height, _In_ size_t depth) noexcept\n    {\n        size_t mipLevels = 1;\n\n        while (height > 1 || width > 1 || depth > 1)\n        {\n            if (height > 1)\n                height >>= 1;\n\n            if (width > 1)\n                width >>= 1;\n\n            if (depth > 1)\n                depth >>= 1;\n\n            ++mipLevels;\n        }\n\n        return mipLevels;\n    }\n\n    const XMVECTORF32 c_MaxNitsFor2084 = { { { 10000.0f, 10000.0f, 10000.0f, 1.f } } };\n\n    // HDTV to UHDTV (Rec.709 color primaries into Rec.2020)\n    const XMMATRIX c_from709to2020 =\n    {\n        0.6274040f, 0.0690970f, 0.0163916f, 0.f,\n        0.3292820f, 0.9195400f, 0.0880132f, 0.f,\n        0.0433136f, 0.0113612f, 0.8955950f, 0.f,\n        0.f,        0.f,        0.f,        1.f\n    };\n\n    // UHDTV to HDTV\n    const XMMATRIX c_from2020to709 =\n    {\n        1.6604910f,  -0.1245505f, -0.0181508f, 0.f,\n        -0.5876411f,  1.1328999f, -0.1005789f, 0.f,\n        -0.0728499f, -0.0083494f,  1.1187297f, 0.f,\n        0.f,          0.f,         0.f,        1.f\n    };\n\n    // DCI-P3-D65 https://en.wikipedia.org/wiki/DCI-P3 to UHDTV (DCI-P3-D65 color primaries into Rec.2020)\n    const XMMATRIX c_fromP3D65to2020 =\n    {\n        0.753845f, 0.0457456f, -0.00121055f, 0.f,\n        0.198593f, 0.941777f,   0.0176041f,  0.f,\n        0.047562f, 0.0124772f,  0.983607f,   0.f,\n        0.f,       0.f,         0.f,         1.f\n    };\n\n    // HDTV to DCI-P3-D65 (a.k.a. Display P3 or P3D65)\n    const XMMATRIX c_from709toP3D65 =\n    {\n        0.822461969f, 0.033194199f, 0.017082631f, 0.f,\n        0.1775380f,   0.9668058f,   0.0723974f,   0.f,\n        0.0000000f,   0.0000000f,   0.9105199f,   0.f,\n        0.f,          0.f,          0.f,          1.f\n    };\n\n    // DCI-P3-D65 to HDTV\n    const XMMATRIX c_fromP3D65to709 =\n    {\n        1.224940176f,  -0.042056955f, -0.019637555f, 0.f,\n        -0.224940176f,  1.042056955f, -0.078636046f, 0.f,\n        0.0000000f,     0.0000000f,    1.098273600f, 0.f,\n        0.f,            0.f,           0.f,          1.f\n    };\n\n    inline float LinearToST2084(float normalizedLinearValue)\n    {\n        const float ST2084 = pow((0.8359375f + 18.8515625f * pow(abs(normalizedLinearValue), 0.1593017578f)) / (1.0f + 18.6875f * pow(abs(normalizedLinearValue), 0.1593017578f)), 78.84375f);\n        return ST2084;  // Don't clamp between [0..1], so we can still perform operations on scene values higher than 10,000 nits\n    }\n\n    inline float ST2084ToLinear(float ST2084)\n    {\n        const float normalizedLinear = pow(std::max(pow(abs(ST2084), 1.0f / 78.84375f) - 0.8359375f, 0.0f) / (18.8515625f - 18.6875f * pow(abs(ST2084), 1.0f / 78.84375f)), 1.0f / 0.1593017578f);\n        return normalizedLinear;\n    }\n\n    bool ParseSwizzleMask(\n        _In_reads_(4) const wchar_t* mask,\n        _Out_writes_(4) uint32_t* swizzleElements,\n        _Out_writes_(4) uint32_t* zeroElements,\n        _Out_writes_(4) uint32_t* oneElements)\n    {\n        if (!mask || !swizzleElements || !zeroElements || !oneElements)\n            return false;\n\n        if (!mask[0])\n            return false;\n\n        for (uint32_t j = 0; j < 4; ++j)\n        {\n            if (!mask[j])\n                break;\n\n            switch (mask[j])\n            {\n            case L'R':\n            case L'X':\n            case L'r':\n            case L'x':\n                for (uint32_t k = j; k < 4; ++k)\n                {\n                    swizzleElements[k] = 0;\n                    zeroElements[k] = 0;\n                    oneElements[k] = 0;\n                }\n                break;\n\n            case L'G':\n            case L'Y':\n            case L'g':\n            case L'y':\n                for (uint32_t k = j; k < 4; ++k)\n                {\n                    swizzleElements[k] = 1;\n                    zeroElements[k] = 0;\n                    oneElements[k] = 0;\n                }\n                break;\n\n            case L'B':\n            case L'Z':\n            case L'b':\n            case L'z':\n                for (uint32_t k = j; k < 4; ++k)\n                {\n                    swizzleElements[k] = 2;\n                    zeroElements[k] = 0;\n                    oneElements[k] = 0;\n                }\n                break;\n\n            case L'A':\n            case L'W':\n            case L'a':\n            case L'w':\n                for (size_t k = j; k < 4; ++k)\n                {\n                    swizzleElements[k] = 3;\n                    zeroElements[k] = 0;\n                    oneElements[k] = 0;\n                }\n                break;\n\n            case L'0':\n                for (uint32_t k = j; k < 4; ++k)\n                {\n                    swizzleElements[k] = k;\n                    zeroElements[k] = 1;\n                    oneElements[k] = 0;\n                }\n                break;\n\n            case L'1':\n                for (uint32_t k = j; k < 4; ++k)\n                {\n                    swizzleElements[k] = k;\n                    zeroElements[k] = 0;\n                    oneElements[k] = 1;\n                }\n                break;\n\n            default:\n                return false;\n            }\n        }\n\n        return true;\n    }\n}\n\n//--------------------------------------------------------------------------------------\n// Entry-point\n//--------------------------------------------------------------------------------------\n#ifdef _PREFAST_\n#pragma prefast(disable : 28198, \"Command-line tool, frees all memory on exit\")\n#endif\n\n\nint TexConv(int argc, wchar_t* argv[], ID3D11Device* device)\n{\n    // Parameters and defaults\n    size_t width = 0;\n    size_t height = 0;\n    size_t mipLevels = 0;\n    DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;\n    TEX_FILTER_FLAGS dwFilter = TEX_FILTER_DEFAULT;\n    TEX_FILTER_FLAGS dwSRGB = TEX_FILTER_DEFAULT;\n    TEX_FILTER_FLAGS dwConvert = TEX_FILTER_DEFAULT;\n    TEX_COMPRESS_FLAGS dwCompress = TEX_COMPRESS_DEFAULT;\n    TEX_FILTER_FLAGS dwFilterOpts = TEX_FILTER_DEFAULT;\n    uint32_t FileType = CODEC_DDS;\n    uint32_t maxSize = 16384;\n    int adapter = -1;\n    float alphaThreshold = TEX_THRESHOLD_DEFAULT;\n    float alphaWeight = 1.f;\n    CNMAP_FLAGS dwNormalMap = CNMAP_DEFAULT;\n    float nmapAmplitude = 1.f;\n    float wicQuality = -1.f;\n    uint32_t colorKey = 0;\n    uint32_t dwRotateColor = 0;\n    float paperWhiteNits = 200.f;\n    float preserveAlphaCoverageRef = 0.0f;\n    bool keepRecursiveDirs = false;\n    uint32_t swizzleElements[4] = { 0, 1, 2, 3 };\n    uint32_t zeroElements[4] = {};\n    uint32_t oneElements[4] = {};\n\n    wchar_t szPrefix[MAX_PATH] = {};\n    wchar_t szSuffix[MAX_PATH] = {};\n    wchar_t szOutputDir[MAX_PATH] = {};\n\n    HRESULT hr = ERROR_SUCCESS;\n\n    // Process command line\n    uint64_t dwOptions = 0;\n    std::list<SConversion> conversion;\n\n    for (int iArg = 1; iArg < argc; iArg++)\n    {\n        PWSTR pArg = argv[iArg];\n\n        if (('-' == pArg[0]) || ('/' == pArg[0]))\n        {\n            pArg++;\n            PWSTR pValue;\n\n            for (pValue = pArg; *pValue && (':' != *pValue); pValue++);\n\n            if (*pValue)\n                *pValue++ = 0;\n\n            const uint64_t dwOption = LookupByName(pArg, g_pOptions);\n\n            if (!dwOption || (dwOptions & (uint64_t(1) << dwOption)))\n            {\n                wprintf(L\"Unknown option: %ls\\n\", pArg);\n                //PrintUsage();\n                return 1;\n            }\n\n            dwOptions |= (uint64_t(1) << dwOption);\n\n            // Handle options with additional value parameter\n            switch (dwOption)\n            {\n            case OPT_WIDTH:\n            case OPT_HEIGHT:\n            case OPT_MIPLEVELS:\n            case OPT_FORMAT:\n            case OPT_FILTER:\n            case OPT_PREFIX:\n            case OPT_SUFFIX:\n            case OPT_OUTPUTDIR:\n            case OPT_FILETYPE:\n            case OPT_GPU:\n            case OPT_FEATURE_LEVEL:\n            case OPT_ALPHA_THRESHOLD:\n            case OPT_ALPHA_WEIGHT:\n            case OPT_NORMAL_MAP:\n            case OPT_NORMAL_MAP_AMPLITUDE:\n            case OPT_WIC_QUALITY:\n            case OPT_BC_COMPRESS:\n            case OPT_COLORKEY:\n            case OPT_FILELIST:\n            case OPT_ROTATE_COLOR:\n            case OPT_PAPER_WHITE_NITS:\n            case OPT_PRESERVE_ALPHA_COVERAGE:\n            case OPT_SWIZZLE:\n                // These support either \"-arg:value\" or \"-arg value\"\n                if (!*pValue)\n                {\n                    if ((iArg + 1 >= argc))\n                    {\n                        printf(\"Invalid usage.\\n\");\n                        //PrintUsage();\n                        return 1;\n                    }\n\n                    iArg++;\n                    pValue = argv[iArg];\n                }\n                break;\n            }\n\n            switch (dwOption)\n            {\n            case OPT_WIDTH:\n                if (swscanf_s(pValue, L\"%zu\", &width) != 1)\n                {\n                    wprintf(L\"Invalid value specified with -w (%ls)\\n\", pValue);\n                    wprintf(L\"\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                break;\n\n            case OPT_HEIGHT:\n                if (swscanf_s(pValue, L\"%zu\", &height) != 1)\n                {\n                    wprintf(L\"Invalid value specified with -h (%ls)\\n\", pValue);\n                    printf(\"\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                break;\n\n            case OPT_MIPLEVELS:\n                if (swscanf_s(pValue, L\"%zu\", &mipLevels) != 1)\n                {\n                    wprintf(L\"Invalid value specified with -m (%ls)\\n\", pValue);\n                    wprintf(L\"\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                break;\n\n            case OPT_FORMAT:\n                format = static_cast<DXGI_FORMAT>(LookupByName(pValue, g_pFormats));\n                if (!format)\n                {\n                    format = static_cast<DXGI_FORMAT>(LookupByName(pValue, g_pFormatAliases));\n                    if (!format)\n                    {\n                        wprintf(L\"Invalid value specified with -f (%ls)\\n\", pValue);\n                        wprintf(L\"\\n\");\n                        //PrintUsage();\n                        return 1;\n                    }\n                }\n                break;\n\n            case OPT_FILTER:\n                dwFilter = static_cast<TEX_FILTER_FLAGS>(LookupByName(pValue, g_pFilters));\n                if (!dwFilter)\n                {\n                    wprintf(L\"Invalid value specified with -if (%ls)\\n\", pValue);\n                    wprintf(L\"\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                break;\n\n            case OPT_ROTATE_COLOR:\n                dwRotateColor = LookupByName(pValue, g_pRotateColor);\n                if (!dwRotateColor)\n                {\n                    wprintf(L\"Invalid value specified with -rotatecolor (%ls)\\n\", pValue);\n                    wprintf(L\"\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                break;\n\n            case OPT_SRGBI:\n                dwSRGB |= TEX_FILTER_SRGB_IN;\n                break;\n\n            case OPT_SRGBO:\n                dwSRGB |= TEX_FILTER_SRGB_OUT;\n                break;\n\n            case OPT_SRGB:\n                dwSRGB |= TEX_FILTER_SRGB;\n                break;\n\n            case OPT_SEPALPHA:\n                dwFilterOpts |= TEX_FILTER_SEPARATE_ALPHA;\n                break;\n\n            case OPT_NO_WIC:\n                dwFilterOpts |= TEX_FILTER_FORCE_NON_WIC;\n                break;\n\n            case OPT_PREFIX:\n                wcscpy_s(szPrefix, MAX_PATH, pValue);\n                break;\n\n            case OPT_SUFFIX:\n                wcscpy_s(szSuffix, MAX_PATH, pValue);\n                break;\n\n            case OPT_OUTPUTDIR:\n                wcscpy_s(szOutputDir, MAX_PATH, pValue);\n                break;\n\n            case OPT_FILETYPE:\n                FileType = LookupByName(pValue, g_pSaveFileTypes);\n                if (!FileType)\n                {\n                    wprintf(L\"Invalid value specified with -ft (%ls)\\n\", pValue);\n                    wprintf(L\"\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                break;\n\n            case OPT_PREMUL_ALPHA:\n                if (dwOptions & (uint64_t(1) << OPT_DEMUL_ALPHA))\n                {\n                    wprintf(L\"Can't use -pmalpha and -alpha at same time\\n\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                break;\n\n            case OPT_DEMUL_ALPHA:\n                if (dwOptions & (uint64_t(1) << OPT_PREMUL_ALPHA))\n                {\n                    wprintf(L\"Can't use -pmalpha and -alpha at same time\\n\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                break;\n\n            case OPT_TA_WRAP:\n                if (dwFilterOpts & TEX_FILTER_MIRROR)\n                {\n                    wprintf(L\"Can't use -wrap and -mirror at same time\\n\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                dwFilterOpts |= TEX_FILTER_WRAP;\n                break;\n\n            case OPT_TA_MIRROR:\n                if (dwFilterOpts & TEX_FILTER_WRAP)\n                {\n                    wprintf(L\"Can't use -wrap and -mirror at same time\\n\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                dwFilterOpts |= TEX_FILTER_MIRROR;\n                break;\n\n            case OPT_NORMAL_MAP:\n                {\n                    dwNormalMap = CNMAP_DEFAULT;\n\n                    if (wcschr(pValue, L'l'))\n                    {\n                        dwNormalMap |= CNMAP_CHANNEL_LUMINANCE;\n                    }\n                    else if (wcschr(pValue, L'r'))\n                    {\n                        dwNormalMap |= CNMAP_CHANNEL_RED;\n                    }\n                    else if (wcschr(pValue, L'g'))\n                    {\n                        dwNormalMap |= CNMAP_CHANNEL_GREEN;\n                    }\n                    else if (wcschr(pValue, L'b'))\n                    {\n                        dwNormalMap |= CNMAP_CHANNEL_BLUE;\n                    }\n                    else if (wcschr(pValue, L'a'))\n                    {\n                        dwNormalMap |= CNMAP_CHANNEL_ALPHA;\n                    }\n                    else\n                    {\n                        wprintf(L\"Invalid value specified for -nmap (%ls), missing l, r, g, b, or a\\n\\n\", pValue);\n                        return 1;\n                    }\n\n                    if (wcschr(pValue, L'm'))\n                    {\n                        dwNormalMap |= CNMAP_MIRROR;\n                    }\n                    else\n                    {\n                        if (wcschr(pValue, L'u'))\n                        {\n                            dwNormalMap |= CNMAP_MIRROR_U;\n                        }\n                        if (wcschr(pValue, L'v'))\n                        {\n                            dwNormalMap |= CNMAP_MIRROR_V;\n                        }\n                    }\n\n                    if (wcschr(pValue, L'i'))\n                    {\n                        dwNormalMap |= CNMAP_INVERT_SIGN;\n                    }\n\n                    if (wcschr(pValue, L'o'))\n                    {\n                        dwNormalMap |= CNMAP_COMPUTE_OCCLUSION;\n                    }\n                }\n                break;\n\n            case OPT_NORMAL_MAP_AMPLITUDE:\n                if (!dwNormalMap)\n                {\n                    wprintf(L\"-nmapamp requires -nmap\\n\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                else if (swscanf_s(pValue, L\"%f\", &nmapAmplitude) != 1)\n                {\n                    wprintf(L\"Invalid value specified with -nmapamp (%ls)\\n\\n\", pValue);\n                    //PrintUsage();\n                    return 1;\n                }\n                else if (nmapAmplitude < 0.f)\n                {\n                    wprintf(L\"Normal map amplitude must be positive (%ls)\\n\\n\", pValue);\n                    return 1;\n                }\n                break;\n\n            case OPT_GPU:\n                if (swscanf_s(pValue, L\"%d\", &adapter) != 1)\n                {\n                    wprintf(L\"Invalid value specified with -gpu (%ls)\\n\\n\", pValue);\n                    //PrintUsage();\n                    return 1;\n                }\n                else if (adapter < 0)\n                {\n                    wprintf(L\"Invalid adapter index (%ls)\\n\\n\", pValue);\n                    //PrintUsage();\n                    return 1;\n                }\n                break;\n\n            case OPT_FEATURE_LEVEL:\n                maxSize = LookupByName(pValue, g_pFeatureLevels);\n                if (!maxSize)\n                {\n                    wprintf(L\"Invalid value specified with -fl (%ls)\\n\", pValue);\n                    wprintf(L\"\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                break;\n\n            case OPT_ALPHA_THRESHOLD:\n                if (swscanf_s(pValue, L\"%f\", &alphaThreshold) != 1)\n                {\n                    wprintf(L\"Invalid value specified with -at (%ls)\\n\", pValue);\n                    wprintf(L\"\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                else if (alphaThreshold < 0.f)\n                {\n                    wprintf(L\"-at (%ls) parameter must be positive\\n\", pValue);\n                    wprintf(L\"\\n\");\n                    return 1;\n                }\n                break;\n\n            case OPT_ALPHA_WEIGHT:\n                if (swscanf_s(pValue, L\"%f\", &alphaWeight) != 1)\n                {\n                    wprintf(L\"Invalid value specified with -aw (%ls)\\n\", pValue);\n                    wprintf(L\"\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                else if (alphaWeight < 0.f)\n                {\n                    wprintf(L\"-aw (%ls) parameter must be positive\\n\", pValue);\n                    wprintf(L\"\\n\");\n                    return 1;\n                }\n                break;\n\n            case OPT_BC_COMPRESS:\n                {\n                    dwCompress = TEX_COMPRESS_DEFAULT;\n\n                    bool found = false;\n                    if (wcschr(pValue, L'u'))\n                    {\n                        dwCompress |= TEX_COMPRESS_UNIFORM;\n                        found = true;\n                    }\n\n                    if (wcschr(pValue, L'd'))\n                    {\n                        dwCompress |= TEX_COMPRESS_DITHER;\n                        found = true;\n                    }\n\n                    if (wcschr(pValue, L'q'))\n                    {\n                        dwCompress |= TEX_COMPRESS_BC7_QUICK;\n                        found = true;\n                    }\n\n                    if (wcschr(pValue, L'x'))\n                    {\n                        dwCompress |= TEX_COMPRESS_BC7_USE_3SUBSETS;\n                        found = true;\n                    }\n\n                    if ((dwCompress & (TEX_COMPRESS_BC7_QUICK | TEX_COMPRESS_BC7_USE_3SUBSETS)) == (TEX_COMPRESS_BC7_QUICK | TEX_COMPRESS_BC7_USE_3SUBSETS))\n                    {\n                        wprintf(L\"Can't use -bc x (max) and -bc q (quick) at same time\\n\\n\");\n                        //PrintUsage();\n                        return 1;\n                    }\n\n                    if (!found)\n                    {\n                        wprintf(L\"Invalid value specified for -bc (%ls), missing d, u, q, or x\\n\\n\", pValue);\n                        return 1;\n                    }\n                }\n                break;\n\n            case OPT_WIC_QUALITY:\n                if (swscanf_s(pValue, L\"%f\", &wicQuality) != 1\n                    || (wicQuality < 0.f)\n                    || (wicQuality > 1.f))\n                {\n                    wprintf(L\"Invalid value specified with -wicq (%ls)\\n\", pValue);\n                    printf(\"\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                break;\n\n            case OPT_COLORKEY:\n                if (swscanf_s(pValue, L\"%x\", &colorKey) != 1)\n                {\n                    printf(\"Invalid value specified with -c (%ls)\\n\", pValue);\n                    printf(\"\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                colorKey &= 0xFFFFFF;\n                break;\n\n            case OPT_X2_BIAS:\n                dwConvert |= TEX_FILTER_FLOAT_X2BIAS;\n                break;\n\n            case OPT_USE_DX10:\n                if (dwOptions & (uint64_t(1) << OPT_USE_DX9))\n                {\n                    wprintf(L\"Can't use -dx9 and -dx10 at same time\\n\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                break;\n\n            case OPT_USE_DX9:\n                if (dwOptions & (uint64_t(1) << OPT_USE_DX10))\n                {\n                    wprintf(L\"Can't use -dx9 and -dx10 at same time\\n\\n\");\n                    //PrintUsage();\n                    return 1;\n                }\n                break;\n\n            case OPT_RECURSIVE:\n                if (*pValue)\n                {\n                    // This option takes 'flatten' or 'keep' with ':' syntax\n                    if (!_wcsicmp(pValue, L\"keep\"))\n                    {\n                        keepRecursiveDirs = true;\n                    }\n                    else if (_wcsicmp(pValue, L\"flatten\") != 0)\n                    {\n                        wprintf(L\"For recursive use -r, -r:flatten, or -r:keep\\n\\n\");\n                        //PrintUsage();\n                        return 1;\n                    }\n                }\n                break;\n\n            case OPT_FILELIST:\n                {\n                    std::wifstream inFile(pValue);\n                    if (!inFile)\n                    {\n                        wprintf(L\"Error opening -flist file %ls\\n\", pValue);\n                        return 1;\n                    }\n\n                    inFile.imbue(std::locale::classic());\n\n                    ProcessFileList(inFile, conversion);\n                }\n                break;\n\n            case OPT_PAPER_WHITE_NITS:\n                if (swscanf_s(pValue, L\"%f\", &paperWhiteNits) != 1)\n                {\n                    wprintf(L\"Invalid value specified with -nits (%ls)\\n\\n\", pValue);\n                    //PrintUsage();\n                    return 1;\n                }\n                else if (paperWhiteNits > 10000.f || paperWhiteNits <= 0.f)\n                {\n                    wprintf(L\"-nits (%ls) parameter must be between 0 and 10000\\n\\n\", pValue);\n                    return 1;\n                }\n                break;\n\n            case OPT_PRESERVE_ALPHA_COVERAGE:\n                if (swscanf_s(pValue, L\"%f\", &preserveAlphaCoverageRef) != 1)\n                {\n                    wprintf(L\"Invalid value specified with -keepcoverage (%ls)\\n\\n\", pValue);\n                    //PrintUsage();\n                    return 1;\n                }\n                else if (preserveAlphaCoverageRef < 0.0f || preserveAlphaCoverageRef > 1.0f)\n                {\n                    wprintf(L\"-keepcoverage (%ls) parameter must be between 0.0 and 1.0\\n\\n\", pValue);\n                    return 1;\n                }\n                break;\n\n            case OPT_SWIZZLE:\n                if (!*pValue || wcslen(pValue) > 4)\n                {\n                    wprintf(L\"Invalid value specified with -swizzle (%ls)\\n\\n\", pValue);\n                    //PrintUsage();\n                    return 1;\n                }\n                else if (!ParseSwizzleMask(pValue, swizzleElements, zeroElements, oneElements))\n                {\n                    wprintf(L\"-swizzle requires a 1 to 4 character mask composed of these letters: r, g, b, a, x, y, w, z, 0, 1\\n\");\n                    return 1;\n                }\n                break;\n            }\n        }\n        else if (wcspbrk(pArg, L\"?*\") != nullptr)\n        {\n            const size_t count = conversion.size();\n            SearchForFiles(pArg, conversion, (dwOptions & (uint64_t(1) << OPT_RECURSIVE)) != 0, nullptr);\n            if (conversion.size() <= count)\n            {\n                wprintf(L\"No matching files found for %ls\\n\", pArg);\n                return 1;\n            }\n        }\n        else\n        {\n            SConversion conv = {};\n            wcscpy_s(conv.szSrc, MAX_PATH, pArg);\n\n            conversion.push_back(conv);\n        }\n    }\n\n    if (conversion.empty())\n    {\n        //PrintUsage();\n        printf(\"No input images specified.\\n\");\n        return 1;\n    }\n\n    if (~dwOptions & (uint64_t(1) << OPT_NOLOGO))\n        PrintLogo();\n\n    // Work out out filename prefix and suffix\n    if (szOutputDir[0] && (L'\\\\' != szOutputDir[wcslen(szOutputDir) - 1]))\n        wcscat_s(szOutputDir, MAX_PATH, L\"\\\\\");\n\n    auto fileTypeName = LookupByValue(FileType, g_pSaveFileTypes);\n\n    if (fileTypeName)\n    {\n        wcscat_s(szSuffix, MAX_PATH, L\".\");\n        wcscat_s(szSuffix, MAX_PATH, fileTypeName);\n    }\n    else\n    {\n        wcscat_s(szSuffix, MAX_PATH, L\".unknown\");\n    }\n\n    if (FileType != CODEC_DDS)\n    {\n        mipLevels = 1;\n    }\n\n    LARGE_INTEGER qpcFreq = {};\n    std::ignore = QueryPerformanceFrequency(&qpcFreq);\n\n    LARGE_INTEGER qpcStart = {};\n    std::ignore = QueryPerformanceCounter(&qpcStart);\n\n    // Convert images\n    bool sizewarn = false;\n    bool nonpow2warn = false;\n    bool non4bc = false;\n    bool preserveAlphaCoverage = false;\n\n    int retVal = 0;\n\n    for (auto pConv = conversion.begin(); pConv != conversion.end(); ++pConv)\n    {\n        if (pConv != conversion.begin())\n            wprintf(L\"\\n\");\n\n        // --- Load source image -------------------------------------------------------\n        wprintf(L\"reading %ls\", pConv->szSrc);\n        fflush(stdout);\n\n        wchar_t ext[_MAX_EXT] = {};\n        wchar_t fname[_MAX_FNAME] = {};\n        _wsplitpath_s(pConv->szSrc, nullptr, 0, nullptr, 0, fname, _MAX_FNAME, ext, _MAX_EXT);\n\n        TexMetadata info;\n        std::unique_ptr<ScratchImage> image(new (std::nothrow) ScratchImage);\n\n        if (!image)\n        {\n            wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n            return 1;\n        }\n\n        if (_wcsicmp(ext, L\".dds\") == 0)\n        {\n            DDS_FLAGS ddsFlags = DDS_FLAGS_ALLOW_LARGE_FILES;\n            if (dwOptions & (uint64_t(1) << OPT_DDS_DWORD_ALIGN))\n                ddsFlags |= DDS_FLAGS_LEGACY_DWORD;\n            if (dwOptions & (uint64_t(1) << OPT_EXPAND_LUMINANCE))\n                ddsFlags |= DDS_FLAGS_EXPAND_LUMINANCE;\n            if (dwOptions & (uint64_t(1) << OPT_DDS_BAD_DXTN_TAILS))\n                ddsFlags |= DDS_FLAGS_BAD_DXTN_TAILS;\n\n            hr = LoadFromDDSFile(pConv->szSrc, ddsFlags, &info, *image);\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                retVal = 1;\n                continue;\n            }\n\n            if (IsTypeless(info.format))\n            {\n                if (dwOptions & (uint64_t(1) << OPT_TYPELESS_UNORM))\n                {\n                    info.format = MakeTypelessUNORM(info.format);\n                }\n                else if (dwOptions & (uint64_t(1) << OPT_TYPELESS_FLOAT))\n                {\n                    info.format = MakeTypelessFLOAT(info.format);\n                }\n\n                if (IsTypeless(info.format))\n                {\n                    wprintf(L\" FAILED due to Typeless format %d\\n\", info.format);\n                    retVal = 1;\n                    continue;\n                }\n\n                image->OverrideFormat(info.format);\n            }\n        }\n        else if (_wcsicmp(ext, L\".bmp\") == 0)\n        {\n            Check(false, \"bmp is unsupported\");\n        }\n        else if (_wcsicmp(ext, L\".tga\") == 0)\n        {\n            Check(false, \"tga is unsupported\");\n        }\n        else if (_wcsicmp(ext, L\".hdr\") == 0)\n        {\n            Check(false, \"hdr is unsupported\");\n        }\n        else if (_wcsicmp(ext, L\".ppm\") == 0)\n        {\n            Check(false, \"ppm is unsupported\");\n        }\n        else if (_wcsicmp(ext, L\".pfm\") == 0)\n        {\n            Check(false, \"pfm is unsupported\");\n        }\n        else\n        {\n            // WIC shares the same filter values for mode and dither\n            static_assert(static_cast<int>(WIC_FLAGS_DITHER) == static_cast<int>(TEX_FILTER_DITHER), \"WIC_FLAGS_* & TEX_FILTER_* should match\");\n            static_assert(static_cast<int>(WIC_FLAGS_DITHER_DIFFUSION) == static_cast<int>(TEX_FILTER_DITHER_DIFFUSION), \"WIC_FLAGS_* & TEX_FILTER_* should match\");\n            static_assert(static_cast<int>(WIC_FLAGS_FILTER_POINT) == static_cast<int>(TEX_FILTER_POINT), \"WIC_FLAGS_* & TEX_FILTER_* should match\");\n            static_assert(static_cast<int>(WIC_FLAGS_FILTER_LINEAR) == static_cast<int>(TEX_FILTER_LINEAR), \"WIC_FLAGS_* & TEX_FILTER_* should match\");\n            static_assert(static_cast<int>(WIC_FLAGS_FILTER_CUBIC) == static_cast<int>(TEX_FILTER_CUBIC), \"WIC_FLAGS_* & TEX_FILTER_* should match\");\n            static_assert(static_cast<int>(WIC_FLAGS_FILTER_FANT) == static_cast<int>(TEX_FILTER_FANT), \"WIC_FLAGS_* & TEX_FILTER_* should match\");\n\n            WIC_FLAGS wicFlags = WIC_FLAGS_NONE | dwFilter;\n            if (FileType == CODEC_DDS)\n                wicFlags |= WIC_FLAGS_ALL_FRAMES;\n\n            hr = LoadFromWICFile(pConv->szSrc, wicFlags, &info, *image);\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                retVal = 1;\n                if (hr == static_cast<HRESULT>(0xc00d5212) /* MF_E_TOPO_CODEC_NOT_FOUND */)\n                {\n                    if (_wcsicmp(ext, L\".heic\") == 0 || _wcsicmp(ext, L\".heif\") == 0)\n                    {\n                        wprintf(L\"INFO: This format requires installing the HEIF Image Extensions - https://aka.ms/heif\\n\");\n                    }\n                    else if (_wcsicmp(ext, L\".webp\") == 0)\n                    {\n                        wprintf(L\"INFO: This format requires installing the WEBP Image Extensions - https://www.microsoft.com/p/webp-image-extensions/9pg2dk419drg\\n\");\n                    }\n                }\n                continue;\n            }\n        }\n\n        PrintInfo(info);\n\n        size_t tMips = (!mipLevels && info.mipLevels > 1) ? info.mipLevels : mipLevels;\n\n        // Convert texture\n        wprintf(L\" as\");\n        fflush(stdout);\n\n        // --- Planar ------------------------------------------------------------------\n        if (IsPlanar(info.format))\n        {\n            auto img = image->GetImage(0, 0, 0);\n            assert(img);\n            const size_t nimg = image->GetImageCount();\n\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            hr = ConvertToSinglePlane(img, nimg, info, *timage);\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [converttosingleplane] (%08X%ls)\\n\",\n                    static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                retVal = 1;\n                continue;\n            }\n\n            auto& tinfo = timage->GetMetadata();\n\n            info.format = tinfo.format;\n\n            assert(info.width == tinfo.width);\n            assert(info.height == tinfo.height);\n            assert(info.depth == tinfo.depth);\n            assert(info.arraySize == tinfo.arraySize);\n            assert(info.mipLevels == tinfo.mipLevels);\n            assert(info.miscFlags == tinfo.miscFlags);\n            assert(info.dimension == tinfo.dimension);\n\n            image.swap(timage);\n        }\n\n        const DXGI_FORMAT tformat = (format == DXGI_FORMAT_UNKNOWN) ? info.format : format;\n\n        // --- Decompress --------------------------------------------------------------\n        std::unique_ptr<ScratchImage> cimage;\n        if (IsCompressed(info.format))\n        {\n            // Direct3D can only create BC resources with multiple-of-4 top levels\n            if ((info.width % 4) != 0 || (info.height % 4) != 0)\n            {\n                if (dwOptions & (uint64_t(1) << OPT_BCNONMULT4FIX))\n                {\n                    std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n                    if (!timage)\n                    {\n                        wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                        return 1;\n                    }\n\n                    // If we started with < 4x4 then no need to generate mips\n                    if (info.width < 4 && info.height < 4)\n                    {\n                        tMips = 1;\n                    }\n\n                    // Fix by changing size but also have to trim any mip-levels which can be invalid\n                    TexMetadata mdata = image->GetMetadata();\n                    mdata.width = (info.width + 3u) & ~0x3u;\n                    mdata.height = (info.height + 3u) & ~0x3u;\n                    mdata.mipLevels = 1;\n                    hr = timage->Initialize(mdata);\n                    if (FAILED(hr))\n                    {\n                        wprintf(L\" FAILED [BC non-multiple-of-4 fixup] (%08X%ls)\\n\",\n                            static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                        return 1;\n                    }\n\n                    if (mdata.dimension == TEX_DIMENSION_TEXTURE3D)\n                    {\n                        for (size_t d = 0; d < mdata.depth; ++d)\n                        {\n                            auto simg = image->GetImage(0, 0, d);\n                            auto dimg = timage->GetImage(0, 0, d);\n\n                            memcpy_s(dimg->pixels, dimg->slicePitch, simg->pixels, simg->slicePitch);\n                        }\n                    }\n                    else\n                    {\n                        for (size_t i = 0; i < mdata.arraySize; ++i)\n                        {\n                            auto simg = image->GetImage(0, i, 0);\n                            auto dimg = timage->GetImage(0, i, 0);\n\n                            memcpy_s(dimg->pixels, dimg->slicePitch, simg->pixels, simg->slicePitch);\n                        }\n                    }\n\n                    info.width = mdata.width;\n                    info.height = mdata.height;\n                    info.mipLevels = mdata.mipLevels;\n                    image.swap(timage);\n                }\n                else if (IsCompressed(tformat))\n                {\n                    non4bc = true;\n                }\n            }\n\n            auto img = image->GetImage(0, 0, 0);\n            assert(img);\n            const size_t nimg = image->GetImageCount();\n\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            hr = Decompress(img, nimg, info, DXGI_FORMAT_UNKNOWN /* picks good default */, *timage);\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [decompress] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                retVal = 1;\n                continue;\n            }\n\n            auto& tinfo = timage->GetMetadata();\n\n            info.format = tinfo.format;\n\n            assert(info.width == tinfo.width);\n            assert(info.height == tinfo.height);\n            assert(info.depth == tinfo.depth);\n            assert(info.arraySize == tinfo.arraySize);\n            assert(info.mipLevels == tinfo.mipLevels);\n            assert(info.miscFlags == tinfo.miscFlags);\n            assert(info.dimension == tinfo.dimension);\n\n            if (FileType == CODEC_DDS)\n            {\n                // Keep the original compressed image in case we can reuse it\n                cimage.reset(image.release());\n                image.reset(timage.release());\n            }\n            else\n            {\n                image.swap(timage);\n            }\n        }\n\n        // --- Undo Premultiplied Alpha (if requested) ---------------------------------\n        if ((dwOptions & (uint64_t(1) << OPT_DEMUL_ALPHA))\n            && HasAlpha(info.format)\n            && info.format != DXGI_FORMAT_A8_UNORM)\n        {\n            Check(false, \"Premultiplied Alpha is not supported\");\n        }\n\n        // --- Flip/Rotate -------------------------------------------------------------\n        if (dwOptions & ((uint64_t(1) << OPT_HFLIP) | (uint64_t(1) << OPT_VFLIP)))\n        {\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            TEX_FR_FLAGS dwFlags = TEX_FR_ROTATE0;\n\n            if (dwOptions & (uint64_t(1) << OPT_HFLIP))\n                dwFlags |= TEX_FR_FLIP_HORIZONTAL;\n\n            if (dwOptions & (uint64_t(1) << OPT_VFLIP))\n                dwFlags |= TEX_FR_FLIP_VERTICAL;\n\n            assert(dwFlags != 0);\n\n            hr = FlipRotate(image->GetImages(), image->GetImageCount(), image->GetMetadata(), dwFlags, *timage);\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [fliprotate] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                return 1;\n            }\n\n            auto& tinfo = timage->GetMetadata();\n\n            info.width = tinfo.width;\n            info.height = tinfo.height;\n\n            assert(info.depth == tinfo.depth);\n            assert(info.arraySize == tinfo.arraySize);\n            assert(info.mipLevels == tinfo.mipLevels);\n            assert(info.miscFlags == tinfo.miscFlags);\n            assert(info.format == tinfo.format);\n            assert(info.dimension == tinfo.dimension);\n\n            image.swap(timage);\n            cimage.reset();\n        }\n\n        // --- Resize ------------------------------------------------------------------\n        size_t twidth = (!width) ? info.width : width;\n        if (twidth > maxSize)\n        {\n            if (!width)\n                twidth = maxSize;\n            else\n                sizewarn = true;\n        }\n\n        size_t theight = (!height) ? info.height : height;\n        if (theight > maxSize)\n        {\n            if (!height)\n                theight = maxSize;\n            else\n                sizewarn = true;\n        }\n\n        if (dwOptions & (uint64_t(1) << OPT_FIT_POWEROF2))\n        {\n            FitPowerOf2(info.width, info.height, twidth, theight, maxSize);\n        }\n\n        if (info.width != twidth || info.height != theight)\n        {\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            hr = Resize(image->GetImages(), image->GetImageCount(), image->GetMetadata(), twidth, theight, dwFilter | dwFilterOpts, *timage);\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [resize] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                return 1;\n            }\n\n            auto& tinfo = timage->GetMetadata();\n\n            assert(tinfo.width == twidth && tinfo.height == theight && tinfo.mipLevels == 1);\n            info.width = tinfo.width;\n            info.height = tinfo.height;\n            info.mipLevels = 1;\n\n            assert(info.depth == tinfo.depth);\n            assert(info.arraySize == tinfo.arraySize);\n            assert(info.miscFlags == tinfo.miscFlags);\n            assert(info.format == tinfo.format);\n            assert(info.dimension == tinfo.dimension);\n\n            image.swap(timage);\n            cimage.reset();\n\n            if (tMips > 0)\n            {\n                const size_t maxMips = (info.depth > 1)\n                    ? CountMips3D(info.width, info.height, info.depth)\n                    : CountMips(info.width, info.height);\n\n                if (tMips > maxMips)\n                {\n                    tMips = maxMips;\n                }\n            }\n        }\n\n        // --- Swizzle (if requested) --------------------------------------------------\n        if (swizzleElements[0] != 0 || swizzleElements[1] != 1 || swizzleElements[2] != 2 || swizzleElements[3] != 3\n            || zeroElements[0] != 0 || zeroElements[1] != 0 || zeroElements[2] != 0 || zeroElements[3] != 0\n            || oneElements[0] != 0 || oneElements[1] != 0 || oneElements[2] != 0 || oneElements[3] != 0)\n        {\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            const XMVECTOR zc = XMVectorSelectControl(zeroElements[0], zeroElements[1], zeroElements[2], zeroElements[3]);\n            const XMVECTOR oc = XMVectorSelectControl(oneElements[0], oneElements[1], oneElements[2], oneElements[3]);\n\n            hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                [&, zc, oc](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)\n                {\n                    UNREFERENCED_PARAMETER(y);\n\n                    for (size_t j = 0; j < w; ++j)\n                    {\n                        XMVECTOR pixel = XMVectorSwizzle(inPixels[j],\n                            swizzleElements[0], swizzleElements[1], swizzleElements[2], swizzleElements[3]);\n                        pixel = XMVectorSelect(pixel, g_XMZero, zc);\n                        outPixels[j] = XMVectorSelect(pixel, g_XMOne, oc);\n                    }\n                }, *timage);\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [swizzle] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                return 1;\n            }\n\n        #ifndef NDEBUG\n            auto& tinfo = timage->GetMetadata();\n        #endif\n\n            assert(info.width == tinfo.width);\n            assert(info.height == tinfo.height);\n            assert(info.depth == tinfo.depth);\n            assert(info.arraySize == tinfo.arraySize);\n            assert(info.mipLevels == tinfo.mipLevels);\n            assert(info.miscFlags == tinfo.miscFlags);\n            assert(info.format == tinfo.format);\n            assert(info.dimension == tinfo.dimension);\n\n            image.swap(timage);\n            cimage.reset();\n        }\n\n        // --- Color rotation (if requested) -------------------------------------------\n        if (dwRotateColor)\n        {\n            if (dwRotateColor == ROTATE_HDR10_TO_709 || dwRotateColor == ROTATE_P3D65_TO_709)\n            {\n                std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n                if (!timage)\n                {\n                    wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                    return 1;\n                }\n\n                hr = Convert(image->GetImages(), image->GetImageCount(), image->GetMetadata(), DXGI_FORMAT_R16G16B16A16_FLOAT,\n                    dwFilter | dwFilterOpts | dwSRGB | dwConvert, alphaThreshold, *timage);\n                if (FAILED(hr))\n                {\n                    wprintf(L\" FAILED [convert] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                    return 1;\n                }\n\n            #ifndef NDEBUG\n                auto& tinfo = timage->GetMetadata();\n            #endif\n\n                assert(tinfo.format == DXGI_FORMAT_R16G16B16A16_FLOAT);\n                info.format = DXGI_FORMAT_R16G16B16A16_FLOAT;\n\n                assert(info.width == tinfo.width);\n                assert(info.height == tinfo.height);\n                assert(info.depth == tinfo.depth);\n                assert(info.arraySize == tinfo.arraySize);\n                assert(info.mipLevels == tinfo.mipLevels);\n                assert(info.miscFlags == tinfo.miscFlags);\n                assert(info.dimension == tinfo.dimension);\n\n                image.swap(timage);\n                cimage.reset();\n            }\n\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            switch (dwRotateColor)\n            {\n            case ROTATE_709_TO_HDR10:\n                hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                    [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)\n                    {\n                        UNREFERENCED_PARAMETER(y);\n\n                        const XMVECTOR paperWhite = XMVectorReplicate(paperWhiteNits);\n\n                        for (size_t j = 0; j < w; ++j)\n                        {\n                            XMVECTOR value = inPixels[j];\n\n                            XMVECTOR nvalue = XMVector3Transform(value, c_from709to2020);\n\n                            // Convert to ST.2084\n                            nvalue = XMVectorDivide(XMVectorMultiply(nvalue, paperWhite), c_MaxNitsFor2084);\n\n                            XMFLOAT4A tmp;\n                            XMStoreFloat4A(&tmp, nvalue);\n\n                            tmp.x = LinearToST2084(tmp.x);\n                            tmp.y = LinearToST2084(tmp.y);\n                            tmp.z = LinearToST2084(tmp.z);\n\n                            nvalue = XMLoadFloat4A(&tmp);\n\n                            value = XMVectorSelect(value, nvalue, g_XMSelect1110);\n\n                            outPixels[j] = value;\n                        }\n                    }, *timage);\n                break;\n\n            case ROTATE_709_TO_2020:\n                hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                    [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)\n                    {\n                        UNREFERENCED_PARAMETER(y);\n\n                        for (size_t j = 0; j < w; ++j)\n                        {\n                            XMVECTOR value = inPixels[j];\n\n                            const XMVECTOR nvalue = XMVector3Transform(value, c_from709to2020);\n\n                            value = XMVectorSelect(value, nvalue, g_XMSelect1110);\n\n                            outPixels[j] = value;\n                        }\n                    }, *timage);\n                break;\n\n            case ROTATE_HDR10_TO_709:\n                hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                    [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)\n                    {\n                        UNREFERENCED_PARAMETER(y);\n\n                        const XMVECTOR paperWhite = XMVectorReplicate(paperWhiteNits);\n\n                        for (size_t j = 0; j < w; ++j)\n                        {\n                            XMVECTOR value = inPixels[j];\n\n                            // Convert from ST.2084\n                            XMFLOAT4A tmp;\n                            XMStoreFloat4A(&tmp, value);\n\n                            tmp.x = ST2084ToLinear(tmp.x);\n                            tmp.y = ST2084ToLinear(tmp.y);\n                            tmp.z = ST2084ToLinear(tmp.z);\n\n                            XMVECTOR nvalue = XMLoadFloat4A(&tmp);\n\n                            nvalue = XMVectorDivide(XMVectorMultiply(nvalue, c_MaxNitsFor2084), paperWhite);\n\n                            nvalue = XMVector3Transform(nvalue, c_from2020to709);\n\n                            value = XMVectorSelect(value, nvalue, g_XMSelect1110);\n\n                            outPixels[j] = value;\n                        }\n                    }, *timage);\n                break;\n\n            case ROTATE_2020_TO_709:\n                hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                    [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)\n                    {\n                        UNREFERENCED_PARAMETER(y);\n\n                        for (size_t j = 0; j < w; ++j)\n                        {\n                            XMVECTOR value = inPixels[j];\n\n                            const XMVECTOR nvalue = XMVector3Transform(value, c_from2020to709);\n\n                            value = XMVectorSelect(value, nvalue, g_XMSelect1110);\n\n                            outPixels[j] = value;\n                        }\n                    }, *timage);\n                break;\n\n            case ROTATE_P3D65_TO_HDR10:\n                hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                    [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)\n                    {\n                        UNREFERENCED_PARAMETER(y);\n\n                        const XMVECTOR paperWhite = XMVectorReplicate(paperWhiteNits);\n\n                        for (size_t j = 0; j < w; ++j)\n                        {\n                            XMVECTOR value = inPixels[j];\n\n                            XMVECTOR nvalue = XMVector3Transform(value, c_fromP3D65to2020);\n\n                            // Convert to ST.2084\n                            nvalue = XMVectorDivide(XMVectorMultiply(nvalue, paperWhite), c_MaxNitsFor2084);\n\n                            XMFLOAT4A tmp;\n                            XMStoreFloat4A(&tmp, nvalue);\n\n                            tmp.x = LinearToST2084(tmp.x);\n                            tmp.y = LinearToST2084(tmp.y);\n                            tmp.z = LinearToST2084(tmp.z);\n\n                            nvalue = XMLoadFloat4A(&tmp);\n\n                            value = XMVectorSelect(value, nvalue, g_XMSelect1110);\n\n                            outPixels[j] = value;\n                        }\n                    }, *timage);\n                break;\n\n            case ROTATE_P3D65_TO_2020:\n                hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                    [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)\n                    {\n                        UNREFERENCED_PARAMETER(y);\n\n                        for (size_t j = 0; j < w; ++j)\n                        {\n                            XMVECTOR value = inPixels[j];\n\n                            const XMVECTOR nvalue = XMVector3Transform(value, c_fromP3D65to2020);\n\n                            value = XMVectorSelect(value, nvalue, g_XMSelect1110);\n\n                            outPixels[j] = value;\n                        }\n                    }, *timage);\n                break;\n\n            case ROTATE_709_TO_P3D65:\n                hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                    [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)\n                    {\n                        UNREFERENCED_PARAMETER(y);\n\n                        for (size_t j = 0; j < w; ++j)\n                        {\n                            XMVECTOR value = inPixels[j];\n\n                            const XMVECTOR nvalue = XMVector3Transform(value, c_from709toP3D65);\n\n                            value = XMVectorSelect(value, nvalue, g_XMSelect1110);\n\n                            outPixels[j] = value;\n                        }\n                    }, *timage);\n                break;\n\n            case ROTATE_P3D65_TO_709:\n                hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                    [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)\n                    {\n                        UNREFERENCED_PARAMETER(y);\n\n                        for (size_t j = 0; j < w; ++j)\n                        {\n                            XMVECTOR value = inPixels[j];\n\n                            const XMVECTOR nvalue = XMVector3Transform(value, c_fromP3D65to709);\n\n                            value = XMVectorSelect(value, nvalue, g_XMSelect1110);\n\n                            outPixels[j] = value;\n                        }\n                    }, *timage);\n                break;\n\n            default:\n                hr = E_NOTIMPL;\n                break;\n            }\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [rotate color apply] (%08X%ls)\\n\",\n                    static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                return 1;\n            }\n\n        #ifndef NDEBUG\n            auto& tinfo = timage->GetMetadata();\n        #endif\n\n            assert(info.width == tinfo.width);\n            assert(info.height == tinfo.height);\n            assert(info.depth == tinfo.depth);\n            assert(info.arraySize == tinfo.arraySize);\n            assert(info.mipLevels == tinfo.mipLevels);\n            assert(info.miscFlags == tinfo.miscFlags);\n            assert(info.format == tinfo.format);\n            assert(info.dimension == tinfo.dimension);\n\n            image.swap(timage);\n            cimage.reset();\n        }\n\n        // --- Tonemap (if requested) --------------------------------------------------\n        if (dwOptions & uint64_t(1) << OPT_TONEMAP)\n        {\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            // Compute max luminosity across all images\n            XMVECTOR maxLum = XMVectorZero();\n            hr = EvaluateImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                [&](const XMVECTOR* pixels, size_t w, size_t y)\n                {\n                    UNREFERENCED_PARAMETER(y);\n\n                    for (size_t j = 0; j < w; ++j)\n                    {\n                        static const XMVECTORF32 s_luminance = { { { 0.3f, 0.59f, 0.11f, 0.f } } };\n\n                        XMVECTOR v = *pixels++;\n\n                        v = XMVector3Dot(v, s_luminance);\n\n                        maxLum = XMVectorMax(v, maxLum);\n                    }\n                });\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [tonemap maxlum] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                return 1;\n            }\n\n            // Reinhard et al, \"Photographic Tone Reproduction for Digital Images\"\n            // http://www.cs.utah.edu/~reinhard/cdrom/\n            maxLum = XMVectorMultiply(maxLum, maxLum);\n\n            hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)\n                {\n                    UNREFERENCED_PARAMETER(y);\n\n                    for (size_t j = 0; j < w; ++j)\n                    {\n                        XMVECTOR value = inPixels[j];\n\n                        const XMVECTOR scale = XMVectorDivide(\n                            XMVectorAdd(g_XMOne, XMVectorDivide(value, maxLum)),\n                            XMVectorAdd(g_XMOne, value));\n                        const XMVECTOR nvalue = XMVectorMultiply(value, scale);\n\n                        value = XMVectorSelect(value, nvalue, g_XMSelect1110);\n\n                        outPixels[j] = value;\n                    }\n                }, *timage);\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [tonemap apply] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                return 1;\n            }\n\n        #ifndef NDEBUG\n            auto& tinfo = timage->GetMetadata();\n        #endif\n\n            assert(info.width == tinfo.width);\n            assert(info.height == tinfo.height);\n            assert(info.depth == tinfo.depth);\n            assert(info.arraySize == tinfo.arraySize);\n            assert(info.mipLevels == tinfo.mipLevels);\n            assert(info.miscFlags == tinfo.miscFlags);\n            assert(info.format == tinfo.format);\n            assert(info.dimension == tinfo.dimension);\n\n            image.swap(timage);\n            cimage.reset();\n        }\n\n        // --- Convert -----------------------------------------------------------------\n        if (dwOptions & (uint64_t(1) << OPT_NORMAL_MAP))\n        {\n            Check(false, \"conversion from a height-map to a normal-map is not supported.\");\n        }\n        else if (info.format != tformat && !IsCompressed(tformat))\n        {\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            hr = Convert(image->GetImages(), image->GetImageCount(), image->GetMetadata(), tformat,\n                dwFilter | dwFilterOpts | dwSRGB | dwConvert, alphaThreshold, *timage);\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [convert] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                return 1;\n            }\n\n            auto& tinfo = timage->GetMetadata();\n\n            assert(tinfo.format == tformat);\n            info.format = tinfo.format;\n\n            assert(info.width == tinfo.width);\n            assert(info.height == tinfo.height);\n            assert(info.depth == tinfo.depth);\n            assert(info.arraySize == tinfo.arraySize);\n            assert(info.mipLevels == tinfo.mipLevels);\n            assert(info.miscFlags == tinfo.miscFlags);\n            assert(info.dimension == tinfo.dimension);\n\n            image.swap(timage);\n            cimage.reset();\n        }\n\n        // --- ColorKey/ChromaKey ------------------------------------------------------\n        if ((dwOptions & (uint64_t(1) << OPT_COLORKEY))\n            && HasAlpha(info.format))\n        {\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            XMVECTOR colorKeyValue = XMLoadColor(reinterpret_cast<const XMCOLOR*>(&colorKey));\n\n            hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)\n                {\n                    static const XMVECTORF32 s_tolerance = { { { 0.2f, 0.2f, 0.2f, 0.f } } };\n\n                    UNREFERENCED_PARAMETER(y);\n\n                    for (size_t j = 0; j < w; ++j)\n                    {\n                        XMVECTOR value = inPixels[j];\n\n                        if (XMVector3NearEqual(value, colorKeyValue, s_tolerance))\n                        {\n                            value = g_XMZero;\n                        }\n                        else\n                        {\n                            value = XMVectorSelect(g_XMOne, value, g_XMSelect1110);\n                        }\n\n                        outPixels[j] = value;\n                    }\n                }, *timage);\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [colorkey] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                return 1;\n            }\n\n        #ifndef NDEBUG\n            auto& tinfo = timage->GetMetadata();\n        #endif\n\n            assert(info.width == tinfo.width);\n            assert(info.height == tinfo.height);\n            assert(info.depth == tinfo.depth);\n            assert(info.arraySize == tinfo.arraySize);\n            assert(info.mipLevels == tinfo.mipLevels);\n            assert(info.miscFlags == tinfo.miscFlags);\n            assert(info.format == tinfo.format);\n            assert(info.dimension == tinfo.dimension);\n\n            image.swap(timage);\n            cimage.reset();\n        }\n\n        // --- Invert Y Channel --------------------------------------------------------\n        if (dwOptions & (uint64_t(1) << OPT_INVERT_Y))\n        {\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)\n                {\n                    static const XMVECTORU32 s_selecty = { { { XM_SELECT_0, XM_SELECT_1, XM_SELECT_0, XM_SELECT_0 } } };\n\n                    UNREFERENCED_PARAMETER(y);\n\n                    for (size_t j = 0; j < w; ++j)\n                    {\n                        const XMVECTOR value = inPixels[j];\n\n                        const XMVECTOR inverty = XMVectorSubtract(g_XMOne, value);\n\n                        outPixels[j] = XMVectorSelect(value, inverty, s_selecty);\n                    }\n                }, *timage);\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [inverty] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                return 1;\n            }\n\n        #ifndef NDEBUG\n            auto& tinfo = timage->GetMetadata();\n        #endif\n\n            assert(info.width == tinfo.width);\n            assert(info.height == tinfo.height);\n            assert(info.depth == tinfo.depth);\n            assert(info.arraySize == tinfo.arraySize);\n            assert(info.mipLevels == tinfo.mipLevels);\n            assert(info.miscFlags == tinfo.miscFlags);\n            assert(info.format == tinfo.format);\n            assert(info.dimension == tinfo.dimension);\n\n            image.swap(timage);\n            cimage.reset();\n        }\n\n        // --- Reconstruct Z Channel ---------------------------------------------------\n        if (dwOptions & (uint64_t(1) << OPT_RECONSTRUCT_Z))\n        {\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            bool isunorm = (FormatDataType(info.format) == FORMAT_TYPE_UNORM) != 0;\n\n            hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),\n                [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)\n                {\n                    static const XMVECTORU32 s_selectz = { { { XM_SELECT_0, XM_SELECT_0, XM_SELECT_1, XM_SELECT_0 } } };\n\n                    UNREFERENCED_PARAMETER(y);\n\n                    for (size_t j = 0; j < w; ++j)\n                    {\n                        const XMVECTOR value = inPixels[j];\n\n                        XMVECTOR z;\n                        if (isunorm)\n                        {\n                            XMVECTOR x2 = XMVectorMultiplyAdd(value, g_XMTwo, g_XMNegativeOne);\n                            x2 = XMVectorSqrt(XMVectorSubtract(g_XMOne, XMVector2Dot(x2, x2)));\n                            z = XMVectorMultiplyAdd(x2, g_XMOneHalf, g_XMOneHalf);\n                        }\n                        else\n                        {\n                            z = XMVectorSqrt(XMVectorSubtract(g_XMOne, XMVector2Dot(value, value)));\n                        }\n\n                        outPixels[j] = XMVectorSelect(value, z, s_selectz);\n                    }\n                }, *timage);\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [reconstructz] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                return 1;\n            }\n\n        #ifndef NDEBUG\n            auto& tinfo = timage->GetMetadata();\n        #endif\n\n            assert(info.width == tinfo.width);\n            assert(info.height == tinfo.height);\n            assert(info.depth == tinfo.depth);\n            assert(info.arraySize == tinfo.arraySize);\n            assert(info.mipLevels == tinfo.mipLevels);\n            assert(info.miscFlags == tinfo.miscFlags);\n            assert(info.format == tinfo.format);\n            assert(info.dimension == tinfo.dimension);\n\n            image.swap(timage);\n            cimage.reset();\n        }\n\n        // --- Determine whether preserve alpha coverage is required (if requested) ----\n        if (preserveAlphaCoverageRef > 0.0f && HasAlpha(info.format) && !image->IsAlphaAllOpaque())\n        {\n            preserveAlphaCoverage = true;\n        }\n\n        // --- Generate mips -----------------------------------------------------------\n        TEX_FILTER_FLAGS dwFilter3D = dwFilter;\n        if (!ispow2(info.width) || !ispow2(info.height) || !ispow2(info.depth))\n        {\n            if (!tMips || info.mipLevels != 1)\n            {\n                nonpow2warn = true;\n            }\n\n            if (info.dimension == TEX_DIMENSION_TEXTURE3D)\n            {\n                // Must force triangle filter for non-power-of-2 volume textures to get correct results\n                dwFilter3D = TEX_FILTER_TRIANGLE;\n            }\n        }\n\n        if ((!tMips || info.mipLevels != tMips || preserveAlphaCoverage) && (info.mipLevels != 1))\n        {\n            // Mips generation only works on a single base image, so strip off existing mip levels\n            // Also required for preserve alpha coverage so that existing mips are regenerated\n\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            TexMetadata mdata = info;\n            mdata.mipLevels = 1;\n            hr = timage->Initialize(mdata);\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [copy to single level] (%08X%ls)\\n\",\n                    static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                return 1;\n            }\n\n            if (info.dimension == TEX_DIMENSION_TEXTURE3D)\n            {\n                for (size_t d = 0; d < info.depth; ++d)\n                {\n                    hr = CopyRectangle(*image->GetImage(0, 0, d), Rect(0, 0, info.width, info.height),\n                        *timage->GetImage(0, 0, d), TEX_FILTER_DEFAULT, 0, 0);\n                    if (FAILED(hr))\n                    {\n                        wprintf(L\" FAILED [copy to single level] (%08X%ls)\\n\",\n                            static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                        return 1;\n                    }\n                }\n            }\n            else\n            {\n                for (size_t i = 0; i < info.arraySize; ++i)\n                {\n                    hr = CopyRectangle(*image->GetImage(0, i, 0), Rect(0, 0, info.width, info.height),\n                        *timage->GetImage(0, i, 0), TEX_FILTER_DEFAULT, 0, 0);\n                    if (FAILED(hr))\n                    {\n                        wprintf(L\" FAILED [copy to single level] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                        return 1;\n                    }\n                }\n            }\n\n            image.swap(timage);\n            info.mipLevels = 1;\n\n            if (cimage && (tMips == 1))\n            {\n                // Special case for trimming mips off compressed images and keeping the original compressed highest level mip\n                mdata = cimage->GetMetadata();\n                mdata.mipLevels = 1;\n                hr = timage->Initialize(mdata);\n                if (FAILED(hr))\n                {\n                    wprintf(L\" FAILED [copy compressed to single level] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                    return 1;\n                }\n\n                if (mdata.dimension == TEX_DIMENSION_TEXTURE3D)\n                {\n                    for (size_t d = 0; d < mdata.depth; ++d)\n                    {\n                        auto simg = cimage->GetImage(0, 0, d);\n                        auto dimg = timage->GetImage(0, 0, d);\n\n                        memcpy_s(dimg->pixels, dimg->slicePitch, simg->pixels, simg->slicePitch);\n                    }\n                }\n                else\n                {\n                    for (size_t i = 0; i < mdata.arraySize; ++i)\n                    {\n                        auto simg = cimage->GetImage(0, i, 0);\n                        auto dimg = timage->GetImage(0, i, 0);\n\n                        memcpy_s(dimg->pixels, dimg->slicePitch, simg->pixels, simg->slicePitch);\n                    }\n                }\n\n                cimage.swap(timage);\n            }\n            else\n            {\n                cimage.reset();\n            }\n        }\n\n        if ((!tMips || info.mipLevels != tMips) && (info.width > 1 || info.height > 1 || info.depth > 1))\n        {\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            if (info.dimension == TEX_DIMENSION_TEXTURE3D)\n            {\n                hr = GenerateMipMaps3D(image->GetImages(), image->GetImageCount(), image->GetMetadata(), dwFilter3D | dwFilterOpts, tMips, *timage);\n            }\n            else\n            {\n                hr = GenerateMipMaps(image->GetImages(), image->GetImageCount(), image->GetMetadata(), dwFilter | dwFilterOpts, tMips, *timage);\n            }\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [mipmaps] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                return 1;\n            }\n\n            auto& tinfo = timage->GetMetadata();\n            info.mipLevels = tinfo.mipLevels;\n\n            assert(info.width == tinfo.width);\n            assert(info.height == tinfo.height);\n            assert(info.depth == tinfo.depth);\n            assert(info.arraySize == tinfo.arraySize);\n            assert(info.miscFlags == tinfo.miscFlags);\n            assert(info.format == tinfo.format);\n            assert(info.dimension == tinfo.dimension);\n\n            image.swap(timage);\n            cimage.reset();\n        }\n\n        // --- Preserve mipmap alpha coverage (if requested) ---------------------------\n        if (preserveAlphaCoverage && info.mipLevels != 1 && (info.dimension != TEX_DIMENSION_TEXTURE3D))\n        {\n            std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n            if (!timage)\n            {\n                wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                return 1;\n            }\n\n            hr = timage->Initialize(image->GetMetadata());\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED [keepcoverage] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                return 1;\n            }\n\n            const size_t items = image->GetMetadata().arraySize;\n            for (size_t item = 0; item < items; ++item)\n            {\n                auto img = image->GetImage(0, item, 0);\n                assert(img);\n\n                hr = ScaleMipMapsAlphaForCoverage(img, info.mipLevels, info, item, preserveAlphaCoverageRef, *timage);\n                if (FAILED(hr))\n                {\n                    wprintf(L\" FAILED [keepcoverage] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                    return 1;\n                }\n            }\n\n        #ifndef NDEBUG\n            auto& tinfo = timage->GetMetadata();\n        #endif\n\n            assert(info.width == tinfo.width);\n            assert(info.height == tinfo.height);\n            assert(info.depth == tinfo.depth);\n            assert(info.arraySize == tinfo.arraySize);\n            assert(info.mipLevels == tinfo.mipLevels);\n            assert(info.miscFlags == tinfo.miscFlags);\n            assert(info.dimension == tinfo.dimension);\n\n            image.swap(timage);\n            cimage.reset();\n        }\n\n        // --- Premultiplied alpha (if requested) --------------------------------------\n        if ((dwOptions & (uint64_t(1) << OPT_PREMUL_ALPHA))\n            && HasAlpha(info.format)\n            && info.format != DXGI_FORMAT_A8_UNORM)\n        {\n            Check(false, \"Premultiplied Alpha is not supported\");\n        }\n\n        // --- Compress ----------------------------------------------------------------\n        if (IsCompressed(tformat) && (FileType == CODEC_DDS))\n        {\n            if (cimage && (cimage->GetMetadata().format == tformat))\n            {\n                // We never changed the image and it was already compressed in our desired format, use original data\n                image.reset(cimage.release());\n\n                auto& tinfo = image->GetMetadata();\n\n                if ((tinfo.width % 4) != 0 || (tinfo.height % 4) != 0)\n                {\n                    non4bc = true;\n                }\n\n                info.format = tinfo.format;\n                assert(info.width == tinfo.width);\n                assert(info.height == tinfo.height);\n                assert(info.depth == tinfo.depth);\n                assert(info.arraySize == tinfo.arraySize);\n                assert(info.mipLevels == tinfo.mipLevels);\n                assert(info.miscFlags == tinfo.miscFlags);\n                assert(info.dimension == tinfo.dimension);\n            }\n            else\n            {\n                cimage.reset();\n\n                auto img = image->GetImage(0, 0, 0);\n                assert(img);\n                const size_t nimg = image->GetImageCount();\n\n                std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);\n                if (!timage)\n                {\n                    wprintf(L\"\\nERROR: Memory allocation failed\\n\");\n                    return 1;\n                }\n\n                bool bc6hbc7 = false;\n                switch (tformat)\n                {\n                case DXGI_FORMAT_BC6H_TYPELESS:\n                case DXGI_FORMAT_BC6H_UF16:\n                case DXGI_FORMAT_BC6H_SF16:\n                case DXGI_FORMAT_BC7_TYPELESS:\n                case DXGI_FORMAT_BC7_UNORM:\n                case DXGI_FORMAT_BC7_UNORM_SRGB:\n                    bc6hbc7 = true;\n                    break;\n\n                default:\n                    break;\n                }\n\n                TEX_COMPRESS_FLAGS cflags = dwCompress;\n\n                if ((img->width % 4) != 0 || (img->height % 4) != 0)\n                {\n                    non4bc = true;\n                }\n\n                if (bc6hbc7)\n                {\n                    hr = Compress(device, img, nimg, info, tformat, dwCompress | dwSRGB, alphaWeight, *timage);\n                }\n                else\n                {\n                    hr = Compress(img, nimg, info, tformat, cflags | dwSRGB, alphaThreshold, *timage);\n                }\n                if (FAILED(hr))\n                {\n                    wprintf(L\" FAILED [compress] (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                    retVal = 1;\n                    continue;\n                }\n\n                auto& tinfo = timage->GetMetadata();\n\n                info.format = tinfo.format;\n                assert(info.width == tinfo.width);\n                assert(info.height == tinfo.height);\n                assert(info.depth == tinfo.depth);\n                assert(info.arraySize == tinfo.arraySize);\n                assert(info.mipLevels == tinfo.mipLevels);\n                assert(info.miscFlags == tinfo.miscFlags);\n                assert(info.dimension == tinfo.dimension);\n\n                image.swap(timage);\n            }\n        }\n        else\n        {\n            cimage.reset();\n        }\n\n        // --- Set alpha mode ----------------------------------------------------------\n        if (HasAlpha(info.format)\n            && info.format != DXGI_FORMAT_A8_UNORM)\n        {\n            if (image->IsAlphaAllOpaque())\n            {\n                info.SetAlphaMode(TEX_ALPHA_MODE_OPAQUE);\n            }\n            else if (info.IsPMAlpha())\n            {\n                // Aleady set TEX_ALPHA_MODE_PREMULTIPLIED\n            }\n            else if (dwOptions & (uint64_t(1) << OPT_SEPALPHA))\n            {\n                info.SetAlphaMode(TEX_ALPHA_MODE_CUSTOM);\n            }\n            else if (info.GetAlphaMode() == TEX_ALPHA_MODE_UNKNOWN)\n            {\n                info.SetAlphaMode(TEX_ALPHA_MODE_STRAIGHT);\n            }\n        }\n        else\n        {\n            info.SetAlphaMode(TEX_ALPHA_MODE_UNKNOWN);\n        }\n\n        // --- Save result -------------------------------------------------------------\n        {\n            auto img = image->GetImage(0, 0, 0);\n            assert(img);\n            const size_t nimg = image->GetImageCount();\n\n            PrintInfo(info);\n            wprintf(L\"\\n\");\n\n            // Figure out dest filename\n            wchar_t *pchSlash, *pchDot;\n\n            wchar_t szDest[1024] = {};\n            wcscpy_s(szDest, szOutputDir);\n\n            if (keepRecursiveDirs && *pConv->szFolder)\n            {\n                wcscat_s(szDest, pConv->szFolder);\n\n                wchar_t szPath[MAX_PATH] = {};\n                if (!GetFullPathNameW(szDest, MAX_PATH, szPath, nullptr))\n                {\n                    wprintf(L\" get full path FAILED (%08X%ls)\\n\",\n                        static_cast<unsigned int>(HRESULT_FROM_WIN32(GetLastError())), GetErrorDesc(HRESULT_FROM_WIN32(GetLastError())));\n                    retVal = 1;\n                    continue;\n                }\n\n                auto const err = static_cast<DWORD>(SHCreateDirectoryExW(nullptr, szPath, nullptr));\n                if (err != ERROR_SUCCESS && err != ERROR_ALREADY_EXISTS)\n                {\n                    wprintf(L\" directory creation FAILED (%08X%ls)\\n\",\n                        static_cast<unsigned int>(HRESULT_FROM_WIN32(err)), GetErrorDesc(HRESULT_FROM_WIN32(err)));\n                    retVal = 1;\n                    continue;\n                }\n            }\n\n            if (*szPrefix)\n                wcscat_s(szDest, szPrefix);\n\n            pchSlash = wcsrchr(pConv->szSrc, L'\\\\');\n            if (pchSlash)\n                wcscat_s(szDest, pchSlash + 1);\n            else\n                wcscat_s(szDest, pConv->szSrc);\n\n            pchSlash = wcsrchr(szDest, '\\\\');\n            pchDot = wcsrchr(szDest, '.');\n\n            if (pchDot > pchSlash)\n                *pchDot = 0;\n\n            if (*szSuffix)\n                wcscat_s(szDest, szSuffix);\n\n            if (dwOptions & (uint64_t(1) << OPT_TOLOWER))\n            {\n                std::ignore = _wcslwr_s(szDest);\n            }\n\n            if (wcslen(szDest) > _MAX_PATH)\n            {\n                wprintf(L\"\\nERROR: Output filename exceeds max-path, skipping!\\n\");\n                retVal = 1;\n                continue;\n            }\n\n            // Write texture\n            wprintf(L\"writing %ls\", szDest);\n            fflush(stdout);\n\n            if (~dwOptions & (uint64_t(1) << OPT_OVERWRITE))\n            {\n                if (GetFileAttributesW(szDest) != INVALID_FILE_ATTRIBUTES)\n                {\n                    //wprintf(L\"\\nERROR: Output file already exists, use -y to overwrite:\\n\");\n                    wprintf(L\"\\nWARNING: Output file already exists, skipping...\\n\");\n                    retVal = 1;\n                    continue;\n                }\n            }\n\n            switch (FileType)\n            {\n            case CODEC_DDS:\n                {\n                    DDS_FLAGS ddsFlags = DDS_FLAGS_NONE;\n                    if (dwOptions & (uint64_t(1) << OPT_USE_DX10))\n                    {\n                        ddsFlags |= DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2;\n                    }\n                    else if (dwOptions & (uint64_t(1) << OPT_USE_DX9))\n                    {\n                        ddsFlags |= DDS_FLAGS_FORCE_DX9_LEGACY;\n                    }\n\n                    hr = SaveToDDSFile(img, nimg, info, ddsFlags, szDest);\n                    break;\n                }\n\n            case CODEC_TGA:\n            case CODEC_HDR:\n            case CODEC_PPM:\n            case CODEC_PFM:\n                Check(false, \"tga, hdr, ppm & pfm are not supported.\")\n                break;\n\n            #ifdef USE_OPENEXR\n            case CODEC_EXR:\n                hr = SaveToEXRFile(img[0], szDest);\n                break;\n            #endif\n\n            default:\n                {\n                    const WICCodecs codec = (FileType == CODEC_HDP || FileType == CODEC_JXR) ? WIC_CODEC_WMP : static_cast<WICCodecs>(FileType);\n                    const size_t nimages = (dwOptions & (uint64_t(1) << OPT_WIC_MULTIFRAME)) ? nimg : 1;\n                    hr = SaveToWICFile(img, nimages, WIC_FLAGS_NONE, GetWICCodec(codec), szDest, nullptr,\n                        [&](IPropertyBag2* props)\n                        {\n                            const bool wicLossless = (dwOptions & (uint64_t(1) << OPT_WIC_LOSSLESS)) != 0;\n\n                            switch (FileType)\n                            {\n                            case WIC_CODEC_JPEG:\n                                if (wicLossless || wicQuality >= 0.f)\n                                {\n                                    PROPBAG2 options = {};\n                                    VARIANT varValues = {};\n                                    options.pstrName = const_cast<wchar_t*>(L\"ImageQuality\");\n                                    varValues.vt = VT_R4;\n                                    varValues.fltVal = (wicLossless) ? 1.f : wicQuality;\n                                    std::ignore = props->Write(1, &options, &varValues);\n                                }\n                                break;\n\n                            case WIC_CODEC_TIFF:\n                                {\n                                    PROPBAG2 options = {};\n                                    VARIANT varValues = {};\n                                    if (wicLossless)\n                                    {\n                                        options.pstrName = const_cast<wchar_t*>(L\"TiffCompressionMethod\");\n                                        varValues.vt = VT_UI1;\n                                        varValues.bVal = WICTiffCompressionNone;\n                                    }\n                                    else if (wicQuality >= 0.f)\n                                    {\n                                        options.pstrName = const_cast<wchar_t*>(L\"CompressionQuality\");\n                                        varValues.vt = VT_R4;\n                                        varValues.fltVal = wicQuality;\n                                    }\n                                    std::ignore = props->Write(1, &options, &varValues);\n                                }\n                                break;\n\n                            case WIC_CODEC_WMP:\n                            case CODEC_HDP:\n                            case CODEC_JXR:\n                                {\n                                    PROPBAG2 options = {};\n                                    VARIANT varValues = {};\n                                    if (wicLossless)\n                                    {\n                                        options.pstrName = const_cast<wchar_t*>(L\"Lossless\");\n                                        varValues.vt = VT_BOOL;\n                                        varValues.bVal = TRUE;\n                                    }\n                                    else if (wicQuality >= 0.f)\n                                    {\n                                        options.pstrName = const_cast<wchar_t*>(L\"ImageQuality\");\n                                        varValues.vt = VT_R4;\n                                        varValues.fltVal = wicQuality;\n                                    }\n                                    std::ignore = props->Write(1, &options, &varValues);\n                                }\n                                break;\n                            }\n                        });\n                }\n                break;\n            }\n\n            if (FAILED(hr))\n            {\n                wprintf(L\" FAILED (%08X%ls)\\n\", static_cast<unsigned int>(hr), GetErrorDesc(hr));\n                retVal = 1;\n                if ((hr == static_cast<HRESULT>(0xc00d5212) /* MF_E_TOPO_CODEC_NOT_FOUND */) && (FileType == WIC_CODEC_HEIF))\n                {\n                    wprintf(L\"INFO: This format requires installing the HEIF Image Extensions - https://aka.ms/heif\\n\");\n                }\n                continue;\n            }\n            wprintf(L\"\\n\");\n        }\n    }\n\n    if (sizewarn)\n    {\n        wprintf(L\"\\nWARNING: Target size exceeds maximum size for feature level (%u)\\n\", maxSize);\n    }\n\n    if (nonpow2warn && maxSize <= 4096)\n    {\n        // Only emit this warning if ran with -fl set to a 9.x feature level\n        wprintf(L\"\\nWARNING: Not all feature levels support non-power-of-2 textures with mipmaps\\n\");\n    }\n\n    if (non4bc)\n        wprintf(L\"\\nWARNING: Direct3D requires BC image to be multiple of 4 in width & height\\n\");\n\n    if (dwOptions & (uint64_t(1) << OPT_TIMING))\n    {\n        LARGE_INTEGER qpcEnd = {};\n        std::ignore = QueryPerformanceCounter(&qpcEnd);\n\n        const LONGLONG delta = qpcEnd.QuadPart - qpcStart.QuadPart;\n        wprintf(L\"\\n Processing time: %f seconds\\n\", double(delta) / double(qpcFreq.QuadPart));\n    }\n\n    return retVal;\n}"
  },
  {
    "path": "Tools/BCnCompressglTF/TexConv/texconv.h",
    "content": "#pragma once\n\n#include <Win32/Win32.h>\n#include <d3d11.h>\n\nint TexConv(int argc, wchar_t* argv[], ID3D11Device* device);\n"
  },
  {
    "path": "Tools/CMakeLists.txt",
    "content": "add_subdirectory(BCnCompressglTF)\nadd_subdirectory(PrecompileShaders)"
  },
  {
    "path": "Tools/Natvis/App.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n\n    <Type Name=\"ZetaRay::App::Filesystem::FilePath&lt;*&gt;\">\n        <DisplayString>{m_path.m_beg,s}</DisplayString>\n        <StringView>m_path.m_beg</StringView>\n        <Expand>\n            <Item Name=\"[size]\" ExcludeView=\"simple\">m_path.m_end - m_path.m_beg</Item>\n        </Expand>\n    </Type>\n\n</AutoVisualizer>"
  },
  {
    "path": "Tools/Natvis/Container.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n    <Type Name=\"ZetaRay::Util::Vector&lt;*&gt;\">\n        <DisplayString>{{ size={m_end - m_beg} }}</DisplayString>\n        <Expand>\n            <Item Name=\"[size]\" ExcludeView=\"simple\">m_end - m_beg</Item>\n            <Item Name=\"[capacity]\" ExcludeView=\"simple\">m_last - m_beg</Item>\n            <ArrayItems>\n                <Size>m_end - m_beg</Size>\n                <ValuePointer>m_beg</ValuePointer>\n            </ArrayItems>\n        </Expand>\n    </Type>\n    <Type Name=\"ZetaRay::Util::SmallVector&lt;*&gt;\">\n        <DisplayString>{{ size={m_end - m_beg} }}</DisplayString>\n        <Expand>\n            <Item Name=\"[size]\" ExcludeView=\"simple\">m_end - m_beg</Item>\n            <Item Name=\"[capacity]\" ExcludeView=\"simple\">m_last - m_beg</Item>\n            <ArrayItems>\n                <Size>m_end - m_beg</Size>\n                <ValuePointer>m_beg</ValuePointer>\n            </ArrayItems>\n        </Expand>\n    </Type>\n    <Type Name=\"ZetaRay::Util::HashTable&lt;*&gt;\">\n        <DisplayString>{{ capacity={m_end - m_beg} }}</DisplayString>\n        <Expand>\n            <Item Name=\"[capacity]\" ExcludeView=\"simple\">m_end - m_beg</Item>\n            <Item Name=\"[num_entries]\" ExcludeView=\"simple\">m_numEntries</Item>\n            <Item Name=\"[num_non_tombstone_entries]\" ExcludeView=\"simple\">m_numNonTombstoneEntries</Item>\n            <Item Name=\"[allocator]\" ExcludeView=\"simple\">m_allocator</Item>\n            <ArrayItems>\n                <Size>m_end - m_beg</Size>\n                <ValuePointer>m_beg</ValuePointer>\n            </ArrayItems>\n        </Expand>\n    </Type>\n    <Type Name=\"ZetaRay::Util::Span&lt;*&gt;\">\n        <DisplayString>{{ size={m_size} }}</DisplayString>\n        <Expand>\n            <Item Name=\"[size]\" ExcludeView=\"simple\">m_size</Item>\n            <ArrayItems>\n                <Size>m_size</Size>\n                <ValuePointer>m_ptr</ValuePointer>\n            </ArrayItems>\n        </Expand>\n    </Type>\n    <Type Name=\"ZetaRay::Util::MutableSpan&lt;*&gt;\">\n        <DisplayString>{{ size={m_size} }}</DisplayString>\n        <Expand>\n            <Item Name=\"[size]\" ExcludeView=\"simple\">m_size</Item>\n            <ArrayItems>\n                <Size>m_size</Size>\n                <ValuePointer>m_ptr</ValuePointer>\n            </ArrayItems>\n        </Expand>\n    </Type>\n\n</AutoVisualizer>"
  },
  {
    "path": "Tools/Natvis/imgui.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n.natvis file for Visual Studio debugger.\nPurpose: provide nicer views on data types used by Dear ImGui.\n\nTo enable:\n* include file in your VS project (most recommended: not intrusive and always kept up to date!)\n* or copy in %USERPROFILE%\\Documents\\Visual Studio XXXX\\Visualizers (current user)\n* or copy in %VsInstallDirectory%\\Common7\\Packages\\Debugger\\Visualizers (all users)\n\nMore information at: https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2019\n-->\n\n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n\n<Type Name=\"ImVector&lt;*&gt;\">\n  <DisplayString>{{Size={Size} Capacity={Capacity}}}</DisplayString>\n  <Expand>\n    <ArrayItems>\n      <Size>Size</Size>\n      <ValuePointer>Data</ValuePointer>\n    </ArrayItems>\n  </Expand>\n</Type>\n\n<Type Name=\"ImSpan&lt;*&gt;\">\n  <DisplayString>{{Size={DataEnd-Data} }}</DisplayString>\n  <Expand>\n    <ArrayItems>\n      <Size>DataEnd-Data</Size>\n      <ValuePointer>Data</ValuePointer>\n    </ArrayItems>\n  </Expand>\n</Type>\n\n<Type Name=\"ImVec2\">\n  <DisplayString>{{x={x,g} y={y,g}}}</DisplayString>\n</Type>\n\n<Type Name=\"ImVec4\">\n  <DisplayString>{{x={x,g} y={y,g} z={z,g} w={w,g}}}</DisplayString>\n</Type>\n\n<Type Name=\"ImRect\">\n  <DisplayString>{{Min=({Min.x,g} {Min.y,g}) Max=({Max.x,g} {Max.y,g}) Size=({Max.x-Min.x,g} {Max.y-Min.y,g})}}</DisplayString>\n  <Expand>\n    <Item Name=\"Min\">Min</Item>\n    <Item Name=\"Max\">Max</Item>\n    <Item Name=\"[Width]\">Max.x - Min.x</Item>\n    <Item Name=\"[Height]\">Max.y - Min.y</Item>\n  </Expand>\n</Type>\n\n<Type Name=\"ImGuiWindow\">\n  <DisplayString>{{Name {Name,s} Active {(Active||WasActive)?1:0,d} Child {(Flags &amp; 0x01000000)?1:0,d} Popup {(Flags &amp; 0x04000000)?1:0,d} Hidden {(Hidden)?1:0,d}}</DisplayString>\n</Type>\n\n</AutoVisualizer>\n"
  },
  {
    "path": "Tools/PrecompileShaders/CMakeLists.txt",
    "content": "set(SOURCES PrecompileShaders.cpp)\n\n# PrecompileShaders executable\nadd_executable(PrecompileShaders ${SOURCES})\ntarget_include_directories(PrecompileShaders BEFORE PRIVATE \"${ZETA_CORE_DIR}\" \"${ZETA_RENDER_PASS_DIR}\" \"${EXTERNAL_DIR}\")\ntarget_link_libraries(PrecompileShaders ZetaCore ZetaRenderPass)\nset_target_properties(PrecompileShaders PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\")\ntarget_compile_options(PrecompileShaders PRIVATE /fp:precise)\n\nsource_group(TREE \"${CMAKE_CURRENT_SOURCE_DIR}\" PREFIX \"PrecompileShaders\" FILES ${SOURCES})\n\nset_target_properties(PrecompileShaders PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})\nset_target_properties(PrecompileShaders PROPERTIES FOLDER \"Tools\")"
  },
  {
    "path": "Tools/PrecompileShaders/PrecompileShaders.cpp",
    "content": "#include <GBuffer/GBufferRT.h>\n#include <Compositing/Compositing.h>\n#include <AutoExposure/AutoExposure.h>\n#include <Display/Display.h>\n#include <DirectLighting/Emissive/DirectLighting.h>\n#include <DirectLighting/Sky/SkyDI.h>\n#include <PreLighting/PreLighting.h>\n#include <IndirectLighting/IndirectLighting.h>\n\nusing namespace ZetaRay;\nusing namespace ZetaRay::App;\nusing namespace ZetaRay::Core;\nusing namespace ZetaRay::Support;\nusing namespace ZetaRay::Util;\nusing namespace ZetaRay::Math;\nusing namespace ZetaRay::RenderPass;\n\nnamespace\n{\n    struct Data\n    {\n        IndirectLighting indLighting;\n        DirectLighting dirLighitng;\n        PreLighting preLighting;\n        Compositing compositing;\n        SkyDI skyDI;\n        AutoExposure autoExposure;\n        GBufferRT gbuffer;\n        DisplayPass display;\n    };\n\n    Data* g_data = nullptr;\n}\n\n// Indicates to hybrid graphics systems to prefer the discrete part by default\nextern \"C\"\n{\n    __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;\n    __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;\n\n    _declspec(dllexport) extern const UINT D3D12SDKVersion = 613;\n    _declspec(dllexport) extern const char8_t* D3D12SDKPath = u8\".\\\\D3D12\\\\\";\n}\n\nint main(int argc, char* argv[])\n{\n    App::InitBasic();\n    g_data = new Data;\n\n    g_data->indLighting.InitPSOs();\n    g_data->dirLighitng.InitPSOs();\n    g_data->skyDI.InitPSOs();\n    g_data->preLighting.InitPSOs();\n    g_data->compositing.InitPSOs();\n    g_data->autoExposure.InitPSOs();\n    g_data->gbuffer.InitPSOs();\n    g_data->display.InitPSOs();\n\n    App::FlushWorkerThreadPool();\n\n    delete g_data;\n    App::ShutdownBasic();\n\n    return 0;\n}"
  }
]