diff --git a/.gitignore b/.gitignore index 4ca96605bb..431373c031 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,6 @@ the_khronos_group_inc.p12 # Place for random developer test files. /testground/ + +# clangd compile commands (used by LSPs) +compile_commands.json diff --git a/.gitmodules b/.gitmodules index dd8e8e8c9e..d3a70682d7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,7 +2,8 @@ # Copyright 2022-2023 RasterGrid Kft. # SPDX-License-Identifier: Apache-2.0 +# TODO: revert this before merging!! [submodule "tests/cts"] path = tests/cts - url = https://github.com/KhronosGroup/KTX-Software-CTS.git + url = https://github.com/walcht/KTX-Software-CTS.git branch = main diff --git a/REUSE.toml b/REUSE.toml index 50710a058d..ed73393fa5 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -119,6 +119,12 @@ precedence = "aggregate" SPDX-FileCopyrightText = "1997-2022 Sam Lantinga " SPDX-License-Identifier = "Zlib" +[[annotations]] +path = "external/bc7enc_rdo/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "2020 Richard Geldreich " +SPDX-License-Identifier = "MIT" + [[annotations]] path = "cmake/modules/FindVulkan.cmake" precedence = "aggregate" diff --git a/external/bc7enc_rdo/.gitrepo b/external/bc7enc_rdo/.gitrepo new file mode 100644 index 0000000000..2c9247be9a --- /dev/null +++ b/external/bc7enc_rdo/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/ingydotnet/git-subrepo#readme +; +[subrepo] + remote = https://github.com/KhronosGroup/bc7enc_rdo.git + branch = changes_for_ktx + commit = dbe416d28a5530b4e8cc45b14bf034dc6b96bbde + parent = 68bb0de88c0c61dc4b34326df20ea9a6ed5f9646 + method = merge + cmdver = 0.4.9 diff --git a/external/bc7enc_rdo/LICENSE b/external/bc7enc_rdo/LICENSE new file mode 100644 index 0000000000..b3b1f69bfe --- /dev/null +++ b/external/bc7enc_rdo/LICENSE @@ -0,0 +1,68 @@ +If you use this software in a product, attribution / credits is requested but not required. + +bc7e.ispc uses the Apache 2.0 license and is Copyright (C) 2018-2021 Binomial LLC. +LodePNG is Copyright (c) 2005-2016 Lode Vandevenne. See LodePNG.cpp for its license. + +All other source code files in this repo are available under 2 licenses -- choose whichever you prefer. + +ALTERNATIVE A - MIT License +Copyright(c) 2020-2021 Richard Geldreich, Jr. +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files(the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions : +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain(www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non - commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain.We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors.We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------ + +LodePNG version 20161127 + +Copyright (c) 2005-2016 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + diff --git a/external/bc7enc_rdo/README.md b/external/bc7enc_rdo/README.md new file mode 100644 index 0000000000..0697fe78e8 --- /dev/null +++ b/external/bc7enc_rdo/README.md @@ -0,0 +1,165 @@ +bc7enc - Fast BC1-7 GPU texture encoders with Rate Distortion Optimization (RDO) + +*Note: An even faster alternative to bc7e.ispc is now available - see [bc7f](https://richg42.blogspot.com/2026/01/bc7f-new-real-time-analytical-bc7.html) (or [here](https://github.com/BinomialLLC/basis_universal/wiki/Transcoder-Internals-Analytical-Real-Time-Encoders)). We've integrated bc7f into this repo for testing, and when we get the time we'll release the integration here.* + +This repo contains fast texture encoders for BC1-7. All formats support a simple post-processing transform on the encoded texture data designed to trade off quality for smaller compressed file sizes using LZ compression. Significant (10-50%) size reductions are possible. The BC7 encoder also supports a "reduced entropy" mode using the -e option which causes the output to be biased/weighted in various ways which minimally impact quality, which results in 5-10% smaller file sizes with no slowdowns in encoding time. + +Currently, the entropy reduction transform is tuned for Deflate, LZHAM, or LZMA. The method used to control the rate-distortion tradeoff is the classic Lagrangian multiplier RDO method, modified to favor MSE on very smooth blocks. Rate is approximated using a fixed Deflate model. The post-processing transform applied to the encoded texture data tries to introduce the longest match it can into every encoded output block. It also tries to continue matches between blocks and (specifically for codecs like LZHAM/LZMA/Zstd) it tries to utilize REP0 (repeat) matches. + +You can see examples of the RDO BC7 encoder's current output [here](https://richg42.blogspot.com/2021/02/more-rdo-bc7-encoding.html). Some examples on how to use the command line tool are on my blog, [here](https://richg42.blogspot.com/2021/02/how-to-use-bc7encrdo.html). + +This repo contains both [bc7e.ispc](https://github.com/BinomialLLC/bc7e) and its distantly related but weaker 4 mode only non-ispc variant, bc7enc.cpp. By default, if you set SUPPORT_BC7E=TRUE when running cmake, you get bc7e.ispc, otherwise you get bc7enc.cpp. (The -C option forces bc7enc.cpp.) bc7e supports all BC7 modes and features, but doesn't yet support reduced entropy BC7 encoding. bc7enc.cpp supports optional reduced entropy encoding (using -e with the command line tool). RDO BC7 is supported when using either encoder, however. + +The next major focus will be improving the default smooth block handling and improving rate distorton performance. + +This repo was originally derived from [bc7enc](https://github.com/richgel999/bc7enc) and [bc7e](https://github.com/BinomialLLC/bc7e). Note this repo contains the latest version of bc7e.ispc, which has a determinism bug fix. + +**Note: If you use this software in a product, attribution / credits is requested but not required. Thanks!** + +### Compiling + +This build has been tested with MSVC 2019 x64 and clang 6.0.0 under Ubuntu v18.04. + +To compile with bc7e.ispc (on Linux this requires [Intel's ISPC compiler](https://ispc.github.io/downloads.html) to be in your path - recommended): + +``` +cmake -D SUPPORT_BC7E=TRUE . +make +``` + +To compile without BC7E: + +``` +cmake . +make +``` + +Note the MSVC and Linux builds enable OpenMP for faster compression. + +### Examples + +The [.DDS](https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide) output files can be loaded/viewed using tools like [AMD Compressonator](https://gpuopen.com/compressonator/). + +To encode to non-RDO BC7 using BC7E, highest quality, linear RGB(A) metrics: + +``` +./bc7enc blah.png +``` + +To encode to non-RDO BC7 using BC7E, highest quality, using perceptual (scaled YCbCr) colorspace error metrics: + +``` +./bc7enc blah.png -s +``` + +To encode to RDO BC7 using BC7E, highest quality, lambda=.5, linear metrics (perceptual colorspace metrics are always automatically disabled when -z is specified), with a balance of encoding performance vs. RDO efficiency: + +``` +./bc7enc blah.png -z.5 +``` + +To encode to RDO BC7 using BC7E, lower baseline quality (-u4) for faster encoding, lambda=.5, and with faster encoding (only inject one match vs two, with a tiny RDO lookback window size of 16 bytes): + +``` +./bc7enc blah.png -u4 -z.5 -ze -zc16 +``` + +To encode to non-RDO BC7 using entropy reduced or quantized/weighted BC7 (no slowdown vs. non-RDO bc7enc.cpp for BC7, slightly reduced quality, but 5-10% better LZ compression, only uses 2 or 4 BC7 modes): + +``` +./bc7enc blah.png -C -e +``` + +To encode to RDO BC7 using the entropy reduction transform combined with reduced entropy BC7 encoding, with a slightly larger window size than the default which is 128 bytes: + +``` +./bc7enc -zc256 blah.png -C -e -z1.0 +``` + +Same as before, but higher compression (allow 2 matches per block instead of 1): + +``` +./bc7enc -zc256 blah.png -C -e -z1.0 -zn +``` + +Same, except disable ultra-smooth block handling: + +``` +./bc7enc -zc256 blah.png -C -e -z1.0 -zu +``` + +To encode to RDO BC7 using the entropy reduction transform at lower quality, combined with reduced entropy BC7 encoding, with a slightly larger window size than the default which is 128 bytes: + +``` +./bc7enc -zc256 blah.png -C -e -z2.0 +``` + +To encode to RDO BC7 using the entropy reduction transform at higher effectivenes using a larger window size, without using reduced entropy BC7 encoding: + +``` +./bc7enc -zc1024 blah.png -z1.0 +``` + +To encode to RDO BC7 using the entropy reduction transform at higher effectivenes using a larger window size, with a manually specified max smooth block max error scale: + +``` +./bc7enc -zc1024 blah.png -z2.0 -zb30.0 +``` + +To encode to RDO BC7 using the entropy reduction transform at higher effectivenes using a larger window size, using only mode 6 (more block artifacts, but better rate-distortion performance as measured by PSNR): + +``` +./bc7enc -zc1024 blah.png -6 -z1.0 -e +``` + +To encode to BC1: +``` +./bc7enc -1 blah.png +``` + +To encode to BC1 with Rate Distortion Optimization (RDO) at lambda=1.0: +``` +./bc7enc -1 -z1.0 blah.png +``` + +The -z option controls lambda, or the rate vs. distortion tradeoff. 0 = maximum quality, higher values=lower bitrates but lower quality. Try values [.25-8]. + +To encode to BC1 with RDO, with RDO debug output, to monitor the percentage of blocks impacted: +``` +./bc7enc -1 -z1.0 -zd blah.png +``` + +To encode to BC1 with RDO with a higher then default smooth block scale factor: +``` +./bc7enc -1 -z1.0 -zb40.0 blah.png +``` + +Use -zb1.0 to disable smooth block error scaling completely, which increases RDO performance but can result in noticeable artifacts on smooth/flat blocks at higher lambdas. + +Use -zc# to control the RDO window size in bytes. Good values to try are 16-8192. +Use -zt to disable RDO multithreading. + +To encode to BC1 with RDO at the highest achievable quality/effectiveness (this is extremely slow): + +``` +./bc7enc -1 -z1.0 -zc32768 blah.png +``` + +This sets the window size to 32KB (the highest setting that makes sense for Deflate). Window sizes of 2KB (the default) to 8KB are way faster and in practice are almost as effective. The maximum window size setting supported by the command line tool is 64KB, but this would be very slow. + +For even higher quality per bit (this is incredibly slow): +``` +./bc7enc -1 -z1.0 -zc32768 -zm blah.png +``` + +### Dependencies +There are no 3rd party code or library dependencies. utils.cpp/.h is only needed by the example command line tool. It uses C++11. The individual .cpp files are designed to be easily dropped into other codebases. + +For RDO post-processing of any block-based format: ert.cpp/.h. You provide this function an array of encoded blocks, an array of source/original 32bpp blocks, some parameters, and a pointer to a block decoder function for your format as a callback. It must return false if the passed in block data is invalid. (Make sure you *really* validate the block's data, because the ERT post-processor will inevitably call your callback with invalid blocks.) This transform works on most other texture formats, such as ETC1/2, EAC, and ASTC. The ERT works on block sizes ranging from 1x1 to 12x12. This file has no other dependencies apart from utils.cpp/h. + +For BC1-5 encoding/decoding: rgbcx.cpp/.h + +For BC7 encoding: bc7enc.cpp/.h + +For BC7 decoding: bc7decomp.cpp/.h + diff --git a/external/bc7enc_rdo/bc7decomp.cpp b/external/bc7enc_rdo/bc7decomp.cpp new file mode 100644 index 0000000000..aa8a4c88ce --- /dev/null +++ b/external/bc7enc_rdo/bc7decomp.cpp @@ -0,0 +1,680 @@ +// File: bc7decomp.c - Richard Geldreich, Jr. 3/31/2020 - MIT license or public domain (see end of file) +#include "bc7decomp.h" +#include + +#if (defined(_M_AMD64) || defined(_M_X64) || defined(__SSE2__)) +# define BC7DECOMP_USE_SSE2 +#endif + +#ifdef BC7DECOMP_USE_SSE2 +#include +#include +#endif + +namespace bc7decomp +{ + +#ifdef BC7DECOMP_USE_SSE2 + const __m128i g_bc7_weights4_sse2[8] = + { + _mm_set_epi16(4, 4, 4, 4, 0, 0, 0, 0), + _mm_set_epi16(13, 13, 13, 13, 9, 9, 9, 9), + _mm_set_epi16(21, 21, 21, 21, 17, 17, 17, 17), + _mm_set_epi16(30, 30, 30, 30, 26, 26, 26, 26), + _mm_set_epi16(38, 38, 38, 38, 34, 34, 34, 34), + _mm_set_epi16(47, 47, 47, 47, 43, 43, 43, 43), + _mm_set_epi16(55, 55, 55, 55, 51, 51, 51, 51), + _mm_set_epi16(64, 64, 64, 64, 60, 60, 60, 60), + }; +#endif + +const uint32_t g_bc7_weights2[4] = { 0, 21, 43, 64 }; +const uint32_t g_bc7_weights3[8] = { 0, 9, 18, 27, 37, 46, 55, 64 }; +const uint32_t g_bc7_weights4[16] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 }; + +const uint8_t g_bc7_partition2[64 * 16] = +{ + 0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1, 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, 0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1, 0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1, 0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1, 0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1, 0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1, 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1, + 0,0,0,0,1,0,0,0,1,1,1,0,1,1,1,1, 0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0, 0,1,1,1,0,0,1,1,0,0,0,1,0,0,0,0, 0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0, 0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1, + 0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0, 0,0,0,0,1,0,0,0,1,0,0,0,1,1,0,0, 0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0, 0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0, 0,0,0,1,0,1,1,1,1,1,1,0,1,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0, 0,0,1,1,1,0,0,1,1,0,0,1,1,1,0,0, + 0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, 0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0, 0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0, 0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0, 0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0, 0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1, 0,1,0,1,1,0,1,0,1,0,1,0,0,1,0,1, + 0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,0, 0,0,0,1,0,0,1,1,1,1,0,0,1,0,0,0, 0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0, 0,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0, 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, 0,0,1,1,1,1,0,0,1,1,0,0,0,0,1,1, 0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1, 0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0, + 0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0, 0,0,1,0,0,1,1,1,0,0,1,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,1,1,1,0,0,1,0, 0,0,0,0,0,1,0,0,1,1,1,0,0,1,0,0, 0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,1, 0,1,1,0,0,0,1,1,1,0,0,1,1,1,0,0, 0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,0, + 0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,1, 0,1,1,0,0,0,1,1,0,0,1,1,1,0,0,1, 0,1,1,1,1,1,1,0,1,0,0,0,0,0,0,1, 0,0,0,1,1,0,0,0,1,1,1,0,0,1,1,1, 0,0,0,0,1,1,1,1,0,0,1,1,0,0,1,1, 0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0, 0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0, 0,1,0,0,0,1,0,0,0,1,1,1,0,1,1,1 +}; + +const uint8_t g_bc7_partition3[64 * 16] = +{ + 0,0,1,1,0,0,1,1,0,2,2,1,2,2,2,2, 0,0,0,1,0,0,1,1,2,2,1,1,2,2,2,1, 0,0,0,0,2,0,0,1,2,2,1,1,2,2,1,1, 0,2,2,2,0,0,2,2,0,0,1,1,0,1,1,1, 0,0,0,0,0,0,0,0,1,1,2,2,1,1,2,2, 0,0,1,1,0,0,1,1,0,0,2,2,0,0,2,2, 0,0,2,2,0,0,2,2,1,1,1,1,1,1,1,1, 0,0,1,1,0,0,1,1,2,2,1,1,2,2,1,1, + 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2, 0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2, 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2, 0,0,1,2,0,0,1,2,0,0,1,2,0,0,1,2, 0,1,1,2,0,1,1,2,0,1,1,2,0,1,1,2, 0,1,2,2,0,1,2,2,0,1,2,2,0,1,2,2, 0,0,1,1,0,1,1,2,1,1,2,2,1,2,2,2, 0,0,1,1,2,0,0,1,2,2,0,0,2,2,2,0, + 0,0,0,1,0,0,1,1,0,1,1,2,1,1,2,2, 0,1,1,1,0,0,1,1,2,0,0,1,2,2,0,0, 0,0,0,0,1,1,2,2,1,1,2,2,1,1,2,2, 0,0,2,2,0,0,2,2,0,0,2,2,1,1,1,1, 0,1,1,1,0,1,1,1,0,2,2,2,0,2,2,2, 0,0,0,1,0,0,0,1,2,2,2,1,2,2,2,1, 0,0,0,0,0,0,1,1,0,1,2,2,0,1,2,2, 0,0,0,0,1,1,0,0,2,2,1,0,2,2,1,0, + 0,1,2,2,0,1,2,2,0,0,1,1,0,0,0,0, 0,0,1,2,0,0,1,2,1,1,2,2,2,2,2,2, 0,1,1,0,1,2,2,1,1,2,2,1,0,1,1,0, 0,0,0,0,0,1,1,0,1,2,2,1,1,2,2,1, 0,0,2,2,1,1,0,2,1,1,0,2,0,0,2,2, 0,1,1,0,0,1,1,0,2,0,0,2,2,2,2,2, 0,0,1,1,0,1,2,2,0,1,2,2,0,0,1,1, 0,0,0,0,2,0,0,0,2,2,1,1,2,2,2,1, + 0,0,0,0,0,0,0,2,1,1,2,2,1,2,2,2, 0,2,2,2,0,0,2,2,0,0,1,2,0,0,1,1, 0,0,1,1,0,0,1,2,0,0,2,2,0,2,2,2, 0,1,2,0,0,1,2,0,0,1,2,0,0,1,2,0, 0,0,0,0,1,1,1,1,2,2,2,2,0,0,0,0, 0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0, 0,1,2,0,2,0,1,2,1,2,0,1,0,1,2,0, 0,0,1,1,2,2,0,0,1,1,2,2,0,0,1,1, + 0,0,1,1,1,1,2,2,2,2,0,0,0,0,1,1, 0,1,0,1,0,1,0,1,2,2,2,2,2,2,2,2, 0,0,0,0,0,0,0,0,2,1,2,1,2,1,2,1, 0,0,2,2,1,1,2,2,0,0,2,2,1,1,2,2, 0,0,2,2,0,0,1,1,0,0,2,2,0,0,1,1, 0,2,2,0,1,2,2,1,0,2,2,0,1,2,2,1, 0,1,0,1,2,2,2,2,2,2,2,2,0,1,0,1, 0,0,0,0,2,1,2,1,2,1,2,1,2,1,2,1, + 0,1,0,1,0,1,0,1,0,1,0,1,2,2,2,2, 0,2,2,2,0,1,1,1,0,2,2,2,0,1,1,1, 0,0,0,2,1,1,1,2,0,0,0,2,1,1,1,2, 0,0,0,0,2,1,1,2,2,1,1,2,2,1,1,2, 0,2,2,2,0,1,1,1,0,1,1,1,0,2,2,2, 0,0,0,2,1,1,1,2,1,1,1,2,0,0,0,2, 0,1,1,0,0,1,1,0,0,1,1,0,2,2,2,2, 0,0,0,0,0,0,0,0,2,1,1,2,2,1,1,2, + 0,1,1,0,0,1,1,0,2,2,2,2,2,2,2,2, 0,0,2,2,0,0,1,1,0,0,1,1,0,0,2,2, 0,0,2,2,1,1,2,2,1,1,2,2,0,0,2,2, 0,0,0,0,0,0,0,0,0,0,0,0,2,1,1,2, 0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,1, 0,2,2,2,1,2,2,2,0,2,2,2,1,2,2,2, 0,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2, 0,1,1,1,2,0,1,1,2,2,0,1,2,2,2,0, +}; + +const uint8_t g_bc7_table_anchor_index_second_subset[64] = { 15,15,15,15,15,15,15,15, 15,15,15,15,15,15,15,15, 15, 2, 8, 2, 2, 8, 8,15, 2, 8, 2, 2, 8, 8, 2, 2, 15,15, 6, 8, 2, 8,15,15, 2, 8, 2, 2, 2,15,15, 6, 6, 2, 6, 8,15,15, 2, 2, 15,15,15,15,15, 2, 2,15 }; + +const uint8_t g_bc7_table_anchor_index_third_subset_1[64] = +{ + 3, 3,15,15, 8, 3,15,15, 8, 8, 6, 6, 6, 5, 3, 3, 3, 3, 8,15, 3, 3, 6,10, 5, 8, 8, 6, 8, 5,15,15, 8,15, 3, 5, 6,10, 8,15, 15, 3,15, 5,15,15,15,15, 3,15, 5, 5, 5, 8, 5,10, 5,10, 8,13,15,12, 3, 3 +}; + +const uint8_t g_bc7_table_anchor_index_third_subset_2[64] = +{ + 15, 8, 8, 3,15,15, 3, 8, 15,15,15,15,15,15,15, 8, 15, 8,15, 3,15, 8,15, 8, 3,15, 6,10,15,15,10, 8, 15, 3,15,10,10, 8, 9,10, 6,15, 8,15, 3, 6, 6, 8, 15, 3,15,15,15,15,15,15, 15,15,15,15, 3,15,15, 8 +}; + +const uint8_t g_bc7_first_byte_to_mode[256] = +{ + 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, +}; + +inline void insert_weight_zero(uint64_t& index_bits, uint32_t bits_per_index, uint32_t offset) +{ + uint64_t LOW_BIT_MASK = (static_cast(1) << ((bits_per_index * (offset + 1)) - 1)) - 1; + uint64_t HIGH_BIT_MASK = ~LOW_BIT_MASK; + + index_bits = ((index_bits & HIGH_BIT_MASK) << 1) | (index_bits & LOW_BIT_MASK); +} + +// BC7 mode 0-7 decompression. +// Instead of one monster routine to unpack all the BC7 modes, we're lumping the 3 subset, 2 subset, 1 subset, and dual plane modes together into simple shared routines. + +static inline uint32_t bc7_dequant(uint32_t val, uint32_t pbit, uint32_t val_bits) { assert(val < (1U << val_bits)); assert(pbit < 2); assert(val_bits >= 4 && val_bits <= 8); const uint32_t total_bits = val_bits + 1; val = (val << 1) | pbit; val <<= (8 - total_bits); val |= (val >> total_bits); assert(val <= 255); return val; } +static inline uint32_t bc7_dequant(uint32_t val, uint32_t val_bits) { assert(val < (1U << val_bits)); assert(val_bits >= 4 && val_bits <= 8); val <<= (8 - val_bits); val |= (val >> val_bits); assert(val <= 255); return val; } + +static inline uint32_t bc7_interp2(uint32_t l, uint32_t h, uint32_t w) { assert(w < 4); return (l * (64 - g_bc7_weights2[w]) + h * g_bc7_weights2[w] + 32) >> 6; } +static inline uint32_t bc7_interp3(uint32_t l, uint32_t h, uint32_t w) { assert(w < 8); return (l * (64 - g_bc7_weights3[w]) + h * g_bc7_weights3[w] + 32) >> 6; } +static inline uint32_t bc7_interp4(uint32_t l, uint32_t h, uint32_t w) { assert(w < 16); return (l * (64 - g_bc7_weights4[w]) + h * g_bc7_weights4[w] + 32) >> 6; } +static inline uint32_t bc7_interp(uint32_t l, uint32_t h, uint32_t w, uint32_t bits) +{ + assert(l <= 255 && h <= 255); + switch (bits) + { + case 2: return bc7_interp2(l, h, w); + case 3: return bc7_interp3(l, h, w); + case 4: return bc7_interp4(l, h, w); + default: + break; + } + return 0; +} + + +#ifdef BC7DECOMP_USE_SSE2 +static inline __m128i bc7_interp_sse2(__m128i l, __m128i h, __m128i w, __m128i iw) +{ + return _mm_srli_epi16(_mm_add_epi16(_mm_add_epi16(_mm_mullo_epi16(l, iw), _mm_mullo_epi16(h, w)), _mm_set1_epi16(32)), 6); +} + +static inline void bc7_interp2_sse2(const color_rgba* endpoint_pair, color_rgba* out_colors) +{ + __m128i endpoints = _mm_loadu_si64(endpoint_pair); + __m128i endpoints_16 = _mm_unpacklo_epi8(endpoints, _mm_setzero_si128()); + + __m128i endpoints_16_swapped = _mm_shuffle_epi32(endpoints_16, _MM_SHUFFLE(1, 0, 3, 2)); + + // Interpolated colors will be color 1 and 2 + __m128i interpolated_colors = bc7_interp_sse2(endpoints_16, endpoints_16_swapped, _mm_set1_epi16(21), _mm_set1_epi16(43)); + + // all_colors will be 1, 2, 0, 3 + __m128i all_colors = _mm_packus_epi16(interpolated_colors, endpoints_16); + + all_colors = _mm_shuffle_epi32(all_colors, _MM_SHUFFLE(3, 1, 0, 2)); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(out_colors), all_colors); +} + +static inline void bc7_interp3_sse2(const color_rgba* endpoint_pair, color_rgba* out_colors) +{ + __m128i endpoints = _mm_loadu_si64(endpoint_pair); + __m128i endpoints_16bit = _mm_unpacklo_epi8(endpoints, _mm_setzero_si128()); + __m128i endpoints_16bit_swapped = _mm_shuffle_epi32(endpoints_16bit, _MM_SHUFFLE(1, 0, 3, 2)); + + __m128i interpolated_16 = bc7_interp_sse2(endpoints_16bit, endpoints_16bit_swapped, _mm_set1_epi16(9), _mm_set1_epi16(55)); + __m128i interpolated_23 = bc7_interp_sse2(endpoints_16bit, endpoints_16bit_swapped, _mm_set_epi16(37, 37, 37, 37, 18, 18, 18, 18), _mm_set_epi16(27, 27, 27, 27, 46, 46, 46, 46)); + __m128i interpolated_45 = bc7_interp_sse2(endpoints_16bit, endpoints_16bit_swapped, _mm_set_epi16(18, 18, 18, 18, 37, 37, 37, 37), _mm_set_epi16(46, 46, 46, 46, 27, 27, 27, 27)); + + __m128i interpolated_01 = _mm_unpacklo_epi64(endpoints_16bit, interpolated_16); + __m128i interpolated_67 = _mm_unpackhi_epi64(interpolated_16, endpoints_16bit); + + __m128i all_colors_0 = _mm_packus_epi16(interpolated_01, interpolated_23); + __m128i all_colors_1 = _mm_packus_epi16(interpolated_45, interpolated_67); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(out_colors), all_colors_0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(out_colors + 4), all_colors_1); +} +#endif + +bool unpack_bc7_mode0_2(uint32_t mode, const uint64_t* data_chunks, color_rgba* pPixels) +{ + //const uint32_t SUBSETS = 3; + const uint32_t ENDPOINTS = 6; + const uint32_t COMPS = 3; + const uint32_t WEIGHT_BITS = (mode == 0) ? 3 : 2; + const uint32_t WEIGHT_MASK = (1 << WEIGHT_BITS) - 1; + const uint32_t ENDPOINT_BITS = (mode == 0) ? 4 : 5; + const uint32_t ENDPOINT_MASK = (1 << ENDPOINT_BITS) - 1; + const uint32_t PBITS = (mode == 0) ? 6 : 0; + [[maybe_unused]] const uint32_t WEIGHT_VALS = 1 << WEIGHT_BITS; + const uint32_t PART_BITS = (mode == 0) ? 4 : 6; + const uint32_t PART_MASK = (1 << PART_BITS) - 1; + + const uint64_t low_chunk = data_chunks[0]; + const uint64_t high_chunk = data_chunks[1]; + + const uint32_t part = (low_chunk >> (mode + 1)) & PART_MASK; + + uint64_t channel_read_chunks[3] = { 0, 0, 0 }; + + if (mode == 0) + { + channel_read_chunks[0] = low_chunk >> 5; + channel_read_chunks[1] = low_chunk >> 29; + channel_read_chunks[2] = ((low_chunk >> 53) | (high_chunk << 11)); + } + else + { + channel_read_chunks[0] = low_chunk >> 9; + channel_read_chunks[1] = ((low_chunk >> 39) | (high_chunk << 25)); + channel_read_chunks[2] = high_chunk >> 5; + } + + color_rgba endpoints[ENDPOINTS]; + for (uint32_t c = 0; c < COMPS; c++) + { + uint64_t channel_read_chunk = channel_read_chunks[c]; + for (uint32_t e = 0; e < ENDPOINTS; e++) + { + endpoints[e][c] = static_cast(channel_read_chunk & ENDPOINT_MASK); + channel_read_chunk >>= ENDPOINT_BITS; + } + } + + uint32_t pbits[6]; + if (mode == 0) + { + uint8_t p_bits_chunk = static_cast((high_chunk >> 13) & 0xff); + + for (uint32_t p = 0; p < PBITS; p++) + pbits[p] = (p_bits_chunk >> p) & 1; + } + + uint64_t weights_read_chunk = high_chunk >> (67 - 16 * WEIGHT_BITS); + insert_weight_zero(weights_read_chunk, WEIGHT_BITS, 0); + insert_weight_zero(weights_read_chunk, WEIGHT_BITS, std::min(g_bc7_table_anchor_index_third_subset_1[part], g_bc7_table_anchor_index_third_subset_2[part])); + insert_weight_zero(weights_read_chunk, WEIGHT_BITS, std::max(g_bc7_table_anchor_index_third_subset_1[part], g_bc7_table_anchor_index_third_subset_2[part])); + + uint32_t weights[16]; + for (uint32_t i = 0; i < 16; i++) + { + weights[i] = static_cast(weights_read_chunk & WEIGHT_MASK); + weights_read_chunk >>= WEIGHT_BITS; + } + + for (uint32_t e = 0; e < ENDPOINTS; e++) + for (uint32_t c = 0; c < 4; c++) + endpoints[e][c] = static_cast((c == 3) ? 255 : (PBITS ? bc7_dequant(endpoints[e][c], pbits[e], ENDPOINT_BITS) : bc7_dequant(endpoints[e][c], ENDPOINT_BITS))); + + color_rgba block_colors[3][8]; + +#ifdef BC7DECOMP_USE_SSE2 + for (uint32_t s = 0; s < 3; s++) + { + if (WEIGHT_BITS == 2) + bc7_interp2_sse2(endpoints + s * 2, block_colors[s]); + else + bc7_interp3_sse2(endpoints + s * 2, block_colors[s]); + } +#else + for (uint32_t s = 0; s < 3; s++) + for (uint32_t i = 0; i < WEIGHT_VALS; i++) + { + for (uint32_t c = 0; c < 3; c++) + block_colors[s][i][c] = static_cast(bc7_interp(endpoints[s * 2 + 0][c], endpoints[s * 2 + 1][c], i, WEIGHT_BITS)); + block_colors[s][i][3] = 255; + } +#endif + + for (uint32_t i = 0; i < 16; i++) + pPixels[i] = block_colors[g_bc7_partition3[part * 16 + i]][weights[i]]; + + return true; +} + +bool unpack_bc7_mode1_3_7(uint32_t mode, const uint64_t* data_chunks, color_rgba* pPixels) +{ + //const uint32_t SUBSETS = 2; + const uint32_t ENDPOINTS = 4; + const uint32_t COMPS = (mode == 7) ? 4 : 3; + const uint32_t WEIGHT_BITS = (mode == 1) ? 3 : 2; + const uint32_t WEIGHT_MASK = (1 << WEIGHT_BITS) - 1; + const uint32_t ENDPOINT_BITS = (mode == 7) ? 5 : ((mode == 1) ? 6 : 7); + const uint32_t ENDPOINT_MASK = (1 << ENDPOINT_BITS) - 1; + const uint32_t PBITS = (mode == 1) ? 2 : 4; + const uint32_t SHARED_PBITS = (mode == 1) ? true : false; + [[maybe_unused]] const uint32_t WEIGHT_VALS = 1 << WEIGHT_BITS; + + const uint64_t low_chunk = data_chunks[0]; + const uint64_t high_chunk = data_chunks[1]; + + const uint32_t part = ((low_chunk >> (mode + 1)) & 0x3f); + + color_rgba endpoints[ENDPOINTS]; + + uint64_t channel_read_chunks[4] = { 0, 0, 0, 0 }; + uint64_t p_read_chunk = 0; + channel_read_chunks[0] = (low_chunk >> (mode + 7)); + uint64_t weight_read_chunk; + + switch (mode) + { + case 1: + channel_read_chunks[1] = (low_chunk >> 32); + channel_read_chunks[2] = ((low_chunk >> 56) | (high_chunk << 8)); + p_read_chunk = high_chunk >> 16; + weight_read_chunk = high_chunk >> 18; + break; + case 3: + channel_read_chunks[1] = ((low_chunk >> 38) | (high_chunk << 26)); + channel_read_chunks[2] = high_chunk >> 2; + p_read_chunk = high_chunk >> 30; + weight_read_chunk = high_chunk >> 34; + break; + case 7: + channel_read_chunks[1] = low_chunk >> 34; + channel_read_chunks[2] = ((low_chunk >> 54) | (high_chunk << 10)); + channel_read_chunks[3] = high_chunk >> 10; + p_read_chunk = (high_chunk >> 30); + weight_read_chunk = (high_chunk >> 34); + break; + default: + return false; + }; + + for (uint32_t c = 0; c < COMPS; c++) + { + uint64_t channel_read_chunk = channel_read_chunks[c]; + for (uint32_t e = 0; e < ENDPOINTS; e++) + { + endpoints[e][c] = static_cast(channel_read_chunk & ENDPOINT_MASK); + channel_read_chunk >>= ENDPOINT_BITS; + } + } + + uint32_t pbits[4]; + for (uint32_t p = 0; p < PBITS; p++) + pbits[p] = (p_read_chunk >> p) & 1; + + insert_weight_zero(weight_read_chunk, WEIGHT_BITS, 0); + insert_weight_zero(weight_read_chunk, WEIGHT_BITS, g_bc7_table_anchor_index_second_subset[part]); + + uint32_t weights[16]; + for (uint32_t i = 0; i < 16; i++) + { + weights[i] = static_cast(weight_read_chunk & WEIGHT_MASK); + weight_read_chunk >>= WEIGHT_BITS; + } + + for (uint32_t e = 0; e < ENDPOINTS; e++) + for (uint32_t c = 0; c < 4; c++) + endpoints[e][c] = static_cast((mode != 7U && c == 3U) ? 255 : bc7_dequant(endpoints[e][c], pbits[SHARED_PBITS ? (e >> 1) : e], ENDPOINT_BITS)); + + color_rgba block_colors[2][8]; +#ifdef BC7DECOMP_USE_SSE2 + for (uint32_t s = 0; s < 2; s++) + { + if (WEIGHT_BITS == 2) + bc7_interp2_sse2(endpoints + s * 2, block_colors[s]); + else + bc7_interp3_sse2(endpoints + s * 2, block_colors[s]); + } +#else + for (uint32_t s = 0; s < 2; s++) + for (uint32_t i = 0; i < WEIGHT_VALS; i++) + { + for (uint32_t c = 0; c < COMPS; c++) + block_colors[s][i][c] = static_cast(bc7_interp(endpoints[s * 2 + 0][c], endpoints[s * 2 + 1][c], i, WEIGHT_BITS)); + block_colors[s][i][3] = (COMPS == 3) ? 255 : block_colors[s][i][3]; + } +#endif + + for (uint32_t i = 0; i < 16; i++) + pPixels[i] = block_colors[g_bc7_partition2[part * 16 + i]][weights[i]]; + + return true; +} + +bool unpack_bc7_mode4_5(uint32_t mode, const uint64_t* data_chunks, color_rgba* pPixels) +{ + const uint32_t ENDPOINTS = 2; + //const uint32_t COMPS = 4; + const uint32_t WEIGHT_BITS = 2; + const uint32_t WEIGHT_MASK = (1 << WEIGHT_BITS) - 1; + const uint32_t A_WEIGHT_BITS = (mode == 4) ? 3 : 2; + const uint32_t A_WEIGHT_MASK = (1 << A_WEIGHT_BITS) - 1; + const uint32_t ENDPOINT_BITS = (mode == 4) ? 5 : 7; + const uint32_t ENDPOINT_MASK = (1 << ENDPOINT_BITS) - 1; + const uint32_t A_ENDPOINT_BITS = (mode == 4) ? 6 : 8; + const uint32_t A_ENDPOINT_MASK = (1 << A_ENDPOINT_BITS) - 1; + //const uint32_t WEIGHT_VALS = 1 << WEIGHT_BITS; + //const uint32_t A_WEIGHT_VALS = 1 << A_WEIGHT_BITS; + + const uint64_t low_chunk = data_chunks[0]; + const uint64_t high_chunk = data_chunks[1]; + + const uint32_t comp_rot = (low_chunk >> (mode + 1)) & 0x3; + const uint32_t index_mode = (mode == 4) ? static_cast((low_chunk >> 7) & 1) : 0; + + uint64_t color_read_bits = low_chunk >> 8; + + color_rgba endpoints[ENDPOINTS]; + for (uint32_t c = 0; c < 3; c++) + { + for (uint32_t e = 0; e < ENDPOINTS; e++) + { + endpoints[e][c] = static_cast(color_read_bits & ENDPOINT_MASK); + color_read_bits >>= ENDPOINT_BITS; + } + } + + endpoints[0][3] = static_cast(color_read_bits & ENDPOINT_MASK); + + uint64_t rgb_weights_chunk; + uint64_t a_weights_chunk; + if (mode == 4) + { + endpoints[0][3] = static_cast(color_read_bits & A_ENDPOINT_MASK); + endpoints[1][3] = static_cast((color_read_bits >> A_ENDPOINT_BITS) & A_ENDPOINT_MASK); + rgb_weights_chunk = ((low_chunk >> 50) | (high_chunk << 14)); + a_weights_chunk = high_chunk >> 17; + } + else if (mode == 5) + { + endpoints[0][3] = static_cast(color_read_bits & A_ENDPOINT_MASK); + endpoints[1][3] = static_cast(((low_chunk >> 58) | (high_chunk << 6)) & A_ENDPOINT_MASK); + rgb_weights_chunk = high_chunk >> 2; + a_weights_chunk = high_chunk >> 33; + } + else + return false; + + insert_weight_zero(rgb_weights_chunk, WEIGHT_BITS, 0); + insert_weight_zero(a_weights_chunk, A_WEIGHT_BITS, 0); + + const uint32_t weight_bits[2] = { index_mode ? A_WEIGHT_BITS : WEIGHT_BITS, index_mode ? WEIGHT_BITS : A_WEIGHT_BITS }; + const uint32_t weight_mask[2] = { index_mode ? A_WEIGHT_MASK : WEIGHT_MASK, index_mode ? WEIGHT_MASK : A_WEIGHT_MASK }; + + uint32_t weights[16], a_weights[16]; + + if (index_mode) + std::swap(rgb_weights_chunk, a_weights_chunk); + + for (uint32_t i = 0; i < 16; i++) + { + weights[i] = (rgb_weights_chunk & weight_mask[0]); + rgb_weights_chunk >>= weight_bits[0]; + } + + for (uint32_t i = 0; i < 16; i++) + { + a_weights[i] = (a_weights_chunk & weight_mask[1]); + a_weights_chunk >>= weight_bits[1]; + } + + for (uint32_t e = 0; e < ENDPOINTS; e++) + for (uint32_t c = 0; c < 4; c++) + endpoints[e][c] = static_cast(bc7_dequant(endpoints[e][c], (c == 3) ? A_ENDPOINT_BITS : ENDPOINT_BITS)); + + color_rgba block_colors[8]; +#ifdef BC7DECOMP_USE_SSE2 + if (weight_bits[0] == 3) + bc7_interp3_sse2(endpoints, block_colors); + else + bc7_interp2_sse2(endpoints, block_colors); +#else + for (uint32_t i = 0; i < (1U << weight_bits[0]); i++) + for (uint32_t c = 0; c < 3; c++) + block_colors[i][c] = static_cast(bc7_interp(endpoints[0][c], endpoints[1][c], i, weight_bits[0])); +#endif + + for (uint32_t i = 0; i < (1U << weight_bits[1]); i++) + block_colors[i][3] = static_cast(bc7_interp(endpoints[0][3], endpoints[1][3], i, weight_bits[1])); + + for (uint32_t i = 0; i < 16; i++) + { + pPixels[i] = block_colors[weights[i]]; + pPixels[i].a = block_colors[a_weights[i]].a; + if (comp_rot >= 1) + std::swap(pPixels[i].a, pPixels[i].m_comps[comp_rot - 1]); + } + + return true; +} + +struct bc7_mode_6 +{ + struct + { + uint64_t m_mode : 7; + uint64_t m_r0 : 7; + uint64_t m_r1 : 7; + uint64_t m_g0 : 7; + uint64_t m_g1 : 7; + uint64_t m_b0 : 7; + uint64_t m_b1 : 7; + uint64_t m_a0 : 7; + uint64_t m_a1 : 7; + uint64_t m_p0 : 1; + } m_lo; + + union + { + struct + { + uint64_t m_p1 : 1; + uint64_t m_s00 : 3; + uint64_t m_s10 : 4; + uint64_t m_s20 : 4; + uint64_t m_s30 : 4; + + uint64_t m_s01 : 4; + uint64_t m_s11 : 4; + uint64_t m_s21 : 4; + uint64_t m_s31 : 4; + + uint64_t m_s02 : 4; + uint64_t m_s12 : 4; + uint64_t m_s22 : 4; + uint64_t m_s32 : 4; + + uint64_t m_s03 : 4; + uint64_t m_s13 : 4; + uint64_t m_s23 : 4; + uint64_t m_s33 : 4; + + } m_hi; + + uint64_t m_hi_bits; + }; +}; + +bool unpack_bc7_mode6(const void *pBlock_bits, color_rgba *pPixels) +{ + static_assert(sizeof(bc7_mode_6) == 16, "sizeof(bc7_mode_6) == 16"); + + const bc7_mode_6 &block = *static_cast(pBlock_bits); + + if (block.m_lo.m_mode != (1 << 6)) + return false; + + const uint32_t r0 = static_cast((block.m_lo.m_r0 << 1) | block.m_lo.m_p0); + const uint32_t g0 = static_cast((block.m_lo.m_g0 << 1) | block.m_lo.m_p0); + const uint32_t b0 = static_cast((block.m_lo.m_b0 << 1) | block.m_lo.m_p0); + const uint32_t a0 = static_cast((block.m_lo.m_a0 << 1) | block.m_lo.m_p0); + const uint32_t r1 = static_cast((block.m_lo.m_r1 << 1) | block.m_hi.m_p1); + const uint32_t g1 = static_cast((block.m_lo.m_g1 << 1) | block.m_hi.m_p1); + const uint32_t b1 = static_cast((block.m_lo.m_b1 << 1) | block.m_hi.m_p1); + const uint32_t a1 = static_cast((block.m_lo.m_a1 << 1) | block.m_hi.m_p1); + + color_rgba vals[16]; +#ifdef BC7DECOMP_USE_SSE2 + __m128i vep0 = _mm_set_epi16((short)a0, (short)b0, (short)g0, (short)r0, (short)a0, (short)b0, (short)g0, (short)r0); + __m128i vep1 = _mm_set_epi16((short)a1, (short)b1, (short)g1, (short)r1, (short)a1, (short)b1, (short)g1, (short)r1); + + for (uint32_t i = 0; i < 16; i += 4) + { + const __m128i w0 = g_bc7_weights4_sse2[i / 4 * 2 + 0]; + const __m128i w1 = g_bc7_weights4_sse2[i / 4 * 2 + 1]; + + const __m128i iw0 = _mm_sub_epi16(_mm_set1_epi16(64), w0); + const __m128i iw1 = _mm_sub_epi16(_mm_set1_epi16(64), w1); + + __m128i first_half = _mm_srli_epi16(_mm_add_epi16(_mm_add_epi16(_mm_mullo_epi16(vep0, iw0), _mm_mullo_epi16(vep1, w0)), _mm_set1_epi16(32)), 6); + __m128i second_half = _mm_srli_epi16(_mm_add_epi16(_mm_add_epi16(_mm_mullo_epi16(vep0, iw1), _mm_mullo_epi16(vep1, w1)), _mm_set1_epi16(32)), 6); + __m128i combined = _mm_packus_epi16(first_half, second_half); + + _mm_storeu_si128(reinterpret_cast<__m128i*>(vals + i), combined); + } +#else + for (uint32_t i = 0; i < 16; i++) + { + const uint32_t w = g_bc7_weights4[i]; + const uint32_t iw = 64 - w; + vals[i].set_noclamp_rgba( + (r0 * iw + r1 * w + 32) >> 6, + (g0 * iw + g1 * w + 32) >> 6, + (b0 * iw + b1 * w + 32) >> 6, + (a0 * iw + a1 * w + 32) >> 6); + } +#endif + + pPixels[0] = vals[block.m_hi.m_s00]; + pPixels[1] = vals[block.m_hi.m_s10]; + pPixels[2] = vals[block.m_hi.m_s20]; + pPixels[3] = vals[block.m_hi.m_s30]; + + pPixels[4] = vals[block.m_hi.m_s01]; + pPixels[5] = vals[block.m_hi.m_s11]; + pPixels[6] = vals[block.m_hi.m_s21]; + pPixels[7] = vals[block.m_hi.m_s31]; + + pPixels[8] = vals[block.m_hi.m_s02]; + pPixels[9] = vals[block.m_hi.m_s12]; + pPixels[10] = vals[block.m_hi.m_s22]; + pPixels[11] = vals[block.m_hi.m_s32]; + + pPixels[12] = vals[block.m_hi.m_s03]; + pPixels[13] = vals[block.m_hi.m_s13]; + pPixels[14] = vals[block.m_hi.m_s23]; + pPixels[15] = vals[block.m_hi.m_s33]; + + return true; +} + +bool unpack_bc7(const void *pBlock, color_rgba *pPixels) +{ + const uint8_t *block_bytes = static_cast(pBlock); + uint8_t mode = g_bc7_first_byte_to_mode[block_bytes[0]]; + + uint64_t data_chunks[2]; + + uint64_t endian_check = 1; + if (*reinterpret_cast(&endian_check) == 1) + memcpy(data_chunks, pBlock, 16); + else + { + data_chunks[0] = data_chunks[1] = 0; + for (int chunk_index = 0; chunk_index < 2; chunk_index++) + { + for (int byte_index = 0; byte_index < 8; byte_index++) + data_chunks[chunk_index] |= static_cast(block_bytes[chunk_index * 8 + byte_index]) << (byte_index * 8); + } + } + + switch (mode) + { + case 0: + case 2: + return unpack_bc7_mode0_2(mode, data_chunks, pPixels); + case 1: + case 3: + case 7: + return unpack_bc7_mode1_3_7(mode, data_chunks, pPixels); + case 4: + case 5: + return unpack_bc7_mode4_5(mode, data_chunks, pPixels); + case 6: + return unpack_bc7_mode6(data_chunks, pPixels); + default: + // cast into void* to stop the compiler from complaining (this is a trivial type) + memset(reinterpret_cast(pPixels), 0, sizeof(color_rgba) * 16); + break; + } + + return false; +} + +} // namespace bc7decomp + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright(c) 2020 Richard Geldreich, Jr. +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files(the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions : +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain(www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non - commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain.We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors.We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ + diff --git a/external/bc7enc_rdo/bc7decomp.h b/external/bc7enc_rdo/bc7decomp.h new file mode 100644 index 0000000000..078f438ed2 --- /dev/null +++ b/external/bc7enc_rdo/bc7decomp.h @@ -0,0 +1,179 @@ +#pragma once + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4201) // nonstandard extension used: nameless struct/union +#endif + +#include +#include +#include +#include +#include + +namespace bc7decomp +{ + +enum eNoClamp { cNoClamp }; + +template inline S clamp(S value, S low, S high) { return (value < low) ? low : ((value > high) ? high : value); } + +class color_rgba +{ +public: + union + { + uint8_t m_comps[4]; + + struct + { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + }; + }; + + inline color_rgba() + { + static_assert(sizeof(*this) == 4, "sizeof(*this) != 4"); + } + + inline color_rgba(int y) + { + set(y); + } + + inline color_rgba(int y, int na) + { + set(y, na); + } + + inline color_rgba(int sr, int sg, int sb, int sa) + { + set(sr, sg, sb, sa); + } + + inline color_rgba(eNoClamp, int sr, int sg, int sb, int sa) + { + set_noclamp_rgba((uint8_t)sr, (uint8_t)sg, (uint8_t)sb, (uint8_t)sa); + } + + inline color_rgba& set_noclamp_y(int y) + { + m_comps[0] = (uint8_t)y; + m_comps[1] = (uint8_t)y; + m_comps[2] = (uint8_t)y; + m_comps[3] = (uint8_t)255; + return *this; + } + + inline color_rgba &set_noclamp_rgba(int sr, int sg, int sb, int sa) + { + m_comps[0] = (uint8_t)sr; + m_comps[1] = (uint8_t)sg; + m_comps[2] = (uint8_t)sb; + m_comps[3] = (uint8_t)sa; + return *this; + } + + inline color_rgba &set(int y) + { + m_comps[0] = static_cast(clamp(y, 0, 255)); + m_comps[1] = m_comps[0]; + m_comps[2] = m_comps[0]; + m_comps[3] = 255; + return *this; + } + + inline color_rgba &set(int y, int na) + { + m_comps[0] = static_cast(clamp(y, 0, 255)); + m_comps[1] = m_comps[0]; + m_comps[2] = m_comps[0]; + m_comps[3] = static_cast(clamp(na, 0, 255)); + return *this; + } + + inline color_rgba &set(int sr, int sg, int sb, int sa) + { + m_comps[0] = static_cast(clamp(sr, 0, 255)); + m_comps[1] = static_cast(clamp(sg, 0, 255)); + m_comps[2] = static_cast(clamp(sb, 0, 255)); + m_comps[3] = static_cast(clamp(sa, 0, 255)); + return *this; + } + + inline color_rgba &set_rgb(int sr, int sg, int sb) + { + m_comps[0] = static_cast(clamp(sr, 0, 255)); + m_comps[1] = static_cast(clamp(sg, 0, 255)); + m_comps[2] = static_cast(clamp(sb, 0, 255)); + return *this; + } + + inline color_rgba &set_rgb(const color_rgba &other) + { + r = other.r; + g = other.g; + b = other.b; + return *this; + } + + inline const uint8_t &operator[] (uint32_t index) const { assert(index < 4); return m_comps[index]; } + inline uint8_t &operator[] (uint32_t index) { assert(index < 4); return m_comps[index]; } + + inline void clear() + { + m_comps[0] = 0; + m_comps[1] = 0; + m_comps[2] = 0; + m_comps[3] = 0; + } + + inline bool operator== (const color_rgba &rhs) const + { + if (m_comps[0] != rhs.m_comps[0]) return false; + if (m_comps[1] != rhs.m_comps[1]) return false; + if (m_comps[2] != rhs.m_comps[2]) return false; + if (m_comps[3] != rhs.m_comps[3]) return false; + return true; + } + + inline bool operator!= (const color_rgba &rhs) const + { + return !(*this == rhs); + } + + inline bool operator<(const color_rgba &rhs) const + { + for (int i = 0; i < 4; i++) + { + if (m_comps[i] < rhs.m_comps[i]) + return true; + else if (m_comps[i] != rhs.m_comps[i]) + return false; + } + return false; + } + + inline int get_601_luma() const { return (19595U * m_comps[0] + 38470U * m_comps[1] + 7471U * m_comps[2] + 32768U) >> 16U; } + inline int get_709_luma() const { return (13938U * m_comps[0] + 46869U * m_comps[1] + 4729U * m_comps[2] + 32768U) >> 16U; } + inline int get_luma(bool luma_601) const { return luma_601 ? get_601_luma() : get_709_luma(); } + + static color_rgba comp_min(const color_rgba& a, const color_rgba& b) { return color_rgba(std::min(a[0], b[0]), std::min(a[1], b[1]), std::min(a[2], b[2]), std::min(a[3], b[3])); } + static color_rgba comp_max(const color_rgba& a, const color_rgba& b) { return color_rgba(std::max(a[0], b[0]), std::max(a[1], b[1]), std::max(a[2], b[2]), std::max(a[3], b[3])); } +}; + +bool unpack_bc7(const void *pBlock, color_rgba *pPixels); + +} // namespace bc7decomp + +namespace bc7decomp_ref +{ + bool unpack_bc7(const void* pBlock, bc7decomp::color_rgba* pPixels); +} // namespace bc7decomp_ref + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/external/bc7enc_rdo/bc7decomp_ref.cpp b/external/bc7enc_rdo/bc7decomp_ref.cpp new file mode 100644 index 0000000000..8a69e94740 --- /dev/null +++ b/external/bc7enc_rdo/bc7decomp_ref.cpp @@ -0,0 +1,431 @@ +// File: bc7decomp.c - Richard Geldreich, Jr. 3/31/2020 - MIT license or public domain (see end of file) +#include "bc7decomp.h" + +using namespace bc7decomp; + +namespace bc7decomp_ref +{ + +const uint32_t g_bc7_weights2[4] = { 0, 21, 43, 64 }; +const uint32_t g_bc7_weights3[8] = { 0, 9, 18, 27, 37, 46, 55, 64 }; +const uint32_t g_bc7_weights4[16] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 }; + +const uint8_t g_bc7_partition2[64 * 16] = +{ + 0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1, 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, 0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1, 0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1, 0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1, 0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1, 0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1, 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1, + 0,0,0,0,1,0,0,0,1,1,1,0,1,1,1,1, 0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0, 0,1,1,1,0,0,1,1,0,0,0,1,0,0,0,0, 0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0, 0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1, + 0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0, 0,0,0,0,1,0,0,0,1,0,0,0,1,1,0,0, 0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0, 0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0, 0,0,0,1,0,1,1,1,1,1,1,0,1,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0, 0,0,1,1,1,0,0,1,1,0,0,1,1,1,0,0, + 0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, 0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0, 0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0, 0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0, 0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0, 0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1, 0,1,0,1,1,0,1,0,1,0,1,0,0,1,0,1, + 0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,0, 0,0,0,1,0,0,1,1,1,1,0,0,1,0,0,0, 0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0, 0,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0, 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, 0,0,1,1,1,1,0,0,1,1,0,0,0,0,1,1, 0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1, 0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0, + 0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0, 0,0,1,0,0,1,1,1,0,0,1,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,1,1,1,0,0,1,0, 0,0,0,0,0,1,0,0,1,1,1,0,0,1,0,0, 0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,1, 0,1,1,0,0,0,1,1,1,0,0,1,1,1,0,0, 0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,0, + 0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,1, 0,1,1,0,0,0,1,1,0,0,1,1,1,0,0,1, 0,1,1,1,1,1,1,0,1,0,0,0,0,0,0,1, 0,0,0,1,1,0,0,0,1,1,1,0,0,1,1,1, 0,0,0,0,1,1,1,1,0,0,1,1,0,0,1,1, 0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0, 0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0, 0,1,0,0,0,1,0,0,0,1,1,1,0,1,1,1 +}; + +const uint8_t g_bc7_partition3[64 * 16] = +{ + 0,0,1,1,0,0,1,1,0,2,2,1,2,2,2,2, 0,0,0,1,0,0,1,1,2,2,1,1,2,2,2,1, 0,0,0,0,2,0,0,1,2,2,1,1,2,2,1,1, 0,2,2,2,0,0,2,2,0,0,1,1,0,1,1,1, 0,0,0,0,0,0,0,0,1,1,2,2,1,1,2,2, 0,0,1,1,0,0,1,1,0,0,2,2,0,0,2,2, 0,0,2,2,0,0,2,2,1,1,1,1,1,1,1,1, 0,0,1,1,0,0,1,1,2,2,1,1,2,2,1,1, + 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2, 0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2, 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2, 0,0,1,2,0,0,1,2,0,0,1,2,0,0,1,2, 0,1,1,2,0,1,1,2,0,1,1,2,0,1,1,2, 0,1,2,2,0,1,2,2,0,1,2,2,0,1,2,2, 0,0,1,1,0,1,1,2,1,1,2,2,1,2,2,2, 0,0,1,1,2,0,0,1,2,2,0,0,2,2,2,0, + 0,0,0,1,0,0,1,1,0,1,1,2,1,1,2,2, 0,1,1,1,0,0,1,1,2,0,0,1,2,2,0,0, 0,0,0,0,1,1,2,2,1,1,2,2,1,1,2,2, 0,0,2,2,0,0,2,2,0,0,2,2,1,1,1,1, 0,1,1,1,0,1,1,1,0,2,2,2,0,2,2,2, 0,0,0,1,0,0,0,1,2,2,2,1,2,2,2,1, 0,0,0,0,0,0,1,1,0,1,2,2,0,1,2,2, 0,0,0,0,1,1,0,0,2,2,1,0,2,2,1,0, + 0,1,2,2,0,1,2,2,0,0,1,1,0,0,0,0, 0,0,1,2,0,0,1,2,1,1,2,2,2,2,2,2, 0,1,1,0,1,2,2,1,1,2,2,1,0,1,1,0, 0,0,0,0,0,1,1,0,1,2,2,1,1,2,2,1, 0,0,2,2,1,1,0,2,1,1,0,2,0,0,2,2, 0,1,1,0,0,1,1,0,2,0,0,2,2,2,2,2, 0,0,1,1,0,1,2,2,0,1,2,2,0,0,1,1, 0,0,0,0,2,0,0,0,2,2,1,1,2,2,2,1, + 0,0,0,0,0,0,0,2,1,1,2,2,1,2,2,2, 0,2,2,2,0,0,2,2,0,0,1,2,0,0,1,1, 0,0,1,1,0,0,1,2,0,0,2,2,0,2,2,2, 0,1,2,0,0,1,2,0,0,1,2,0,0,1,2,0, 0,0,0,0,1,1,1,1,2,2,2,2,0,0,0,0, 0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0, 0,1,2,0,2,0,1,2,1,2,0,1,0,1,2,0, 0,0,1,1,2,2,0,0,1,1,2,2,0,0,1,1, + 0,0,1,1,1,1,2,2,2,2,0,0,0,0,1,1, 0,1,0,1,0,1,0,1,2,2,2,2,2,2,2,2, 0,0,0,0,0,0,0,0,2,1,2,1,2,1,2,1, 0,0,2,2,1,1,2,2,0,0,2,2,1,1,2,2, 0,0,2,2,0,0,1,1,0,0,2,2,0,0,1,1, 0,2,2,0,1,2,2,1,0,2,2,0,1,2,2,1, 0,1,0,1,2,2,2,2,2,2,2,2,0,1,0,1, 0,0,0,0,2,1,2,1,2,1,2,1,2,1,2,1, + 0,1,0,1,0,1,0,1,0,1,0,1,2,2,2,2, 0,2,2,2,0,1,1,1,0,2,2,2,0,1,1,1, 0,0,0,2,1,1,1,2,0,0,0,2,1,1,1,2, 0,0,0,0,2,1,1,2,2,1,1,2,2,1,1,2, 0,2,2,2,0,1,1,1,0,1,1,1,0,2,2,2, 0,0,0,2,1,1,1,2,1,1,1,2,0,0,0,2, 0,1,1,0,0,1,1,0,0,1,1,0,2,2,2,2, 0,0,0,0,0,0,0,0,2,1,1,2,2,1,1,2, + 0,1,1,0,0,1,1,0,2,2,2,2,2,2,2,2, 0,0,2,2,0,0,1,1,0,0,1,1,0,0,2,2, 0,0,2,2,1,1,2,2,1,1,2,2,0,0,2,2, 0,0,0,0,0,0,0,0,0,0,0,0,2,1,1,2, 0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,1, 0,2,2,2,1,2,2,2,0,2,2,2,1,2,2,2, 0,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2, 0,1,1,1,2,0,1,1,2,2,0,1,2,2,2,0, +}; + +const uint8_t g_bc7_table_anchor_index_second_subset[64] = { 15,15,15,15,15,15,15,15, 15,15,15,15,15,15,15,15, 15, 2, 8, 2, 2, 8, 8,15, 2, 8, 2, 2, 8, 8, 2, 2, 15,15, 6, 8, 2, 8,15,15, 2, 8, 2, 2, 2,15,15, 6, 6, 2, 6, 8,15,15, 2, 2, 15,15,15,15,15, 2, 2,15 }; + +const uint8_t g_bc7_table_anchor_index_third_subset_1[64] = +{ + 3, 3,15,15, 8, 3,15,15, 8, 8, 6, 6, 6, 5, 3, 3, 3, 3, 8,15, 3, 3, 6,10, 5, 8, 8, 6, 8, 5,15,15, 8,15, 3, 5, 6,10, 8,15, 15, 3,15, 5,15,15,15,15, 3,15, 5, 5, 5, 8, 5,10, 5,10, 8,13,15,12, 3, 3 +}; + +const uint8_t g_bc7_table_anchor_index_third_subset_2[64] = +{ + 15, 8, 8, 3,15,15, 3, 8, 15,15,15,15,15,15,15, 8, 15, 8,15, 3,15, 8,15, 8, 3,15, 6,10,15,15,10, 8, 15, 3,15,10,10, 8, 9,10, 6,15, 8,15, 3, 6, 6, 8, 15, 3,15,15,15,15,15,15, 15,15,15,15, 3,15,15, 8 +}; + +inline uint32_t read_bits32(const uint8_t* pBuf, uint32_t& bit_offset, uint32_t codesize) +{ + assert(codesize <= 32); + uint32_t bits = 0; + uint32_t total_bits = 0; + + while (total_bits < codesize) + { + uint32_t byte_bit_offset = bit_offset & 7; + uint32_t bits_to_read = std::min(codesize - total_bits, 8 - byte_bit_offset); + + uint32_t byte_bits = pBuf[bit_offset >> 3] >> byte_bit_offset; + byte_bits &= ((1 << bits_to_read) - 1); + + bits |= (byte_bits << total_bits); + + total_bits += bits_to_read; + bit_offset += bits_to_read; + } + + return bits; +} + +// BC7 mode 0-7 decompression. +// Instead of one monster routine to unpack all the BC7 modes, we're lumping the 3 subset, 2 subset, 1 subset, and dual plane modes together into simple shared routines. + +static inline uint32_t bc7_dequant(uint32_t val, uint32_t pbit, uint32_t val_bits) { assert(val < (1U << val_bits)); assert(pbit < 2); assert(val_bits >= 4 && val_bits <= 8); const uint32_t total_bits = val_bits + 1; val = (val << 1) | pbit; val <<= (8 - total_bits); val |= (val >> total_bits); assert(val <= 255); return val; } +static inline uint32_t bc7_dequant(uint32_t val, uint32_t val_bits) { assert(val < (1U << val_bits)); assert(val_bits >= 4 && val_bits <= 8); val <<= (8 - val_bits); val |= (val >> val_bits); assert(val <= 255); return val; } + +static inline uint32_t bc7_interp2(uint32_t l, uint32_t h, uint32_t w) { assert(w < 4); return (l * (64 - g_bc7_weights2[w]) + h * g_bc7_weights2[w] + 32) >> 6; } +static inline uint32_t bc7_interp3(uint32_t l, uint32_t h, uint32_t w) { assert(w < 8); return (l * (64 - g_bc7_weights3[w]) + h * g_bc7_weights3[w] + 32) >> 6; } +static inline uint32_t bc7_interp4(uint32_t l, uint32_t h, uint32_t w) { assert(w < 16); return (l * (64 - g_bc7_weights4[w]) + h * g_bc7_weights4[w] + 32) >> 6; } +static inline uint32_t bc7_interp(uint32_t l, uint32_t h, uint32_t w, uint32_t bits) +{ + assert(l <= 255 && h <= 255); + switch (bits) + { + case 2: return bc7_interp2(l, h, w); + case 3: return bc7_interp3(l, h, w); + case 4: return bc7_interp4(l, h, w); + default: + break; + } + return 0; +} + +bool unpack_bc7_mode0_2(uint32_t mode, const void* pBlock_bits, color_rgba* pPixels) +{ + //const uint32_t SUBSETS = 3; + const uint32_t ENDPOINTS = 6; + const uint32_t COMPS = 3; + const uint32_t WEIGHT_BITS = (mode == 0) ? 3 : 2; + const uint32_t ENDPOINT_BITS = (mode == 0) ? 4 : 5; + const uint32_t PBITS = (mode == 0) ? 6 : 0; + const uint32_t WEIGHT_VALS = 1 << WEIGHT_BITS; + + uint32_t bit_offset = 0; + const uint8_t* pBuf = static_cast(pBlock_bits); + + if (read_bits32(pBuf, bit_offset, mode + 1) != (1U << mode)) return false; + + const uint32_t part = read_bits32(pBuf, bit_offset, (mode == 0) ? 4 : 6); + + color_rgba endpoints[ENDPOINTS]; + for (uint32_t c = 0; c < COMPS; c++) + for (uint32_t e = 0; e < ENDPOINTS; e++) + endpoints[e][c] = (uint8_t)read_bits32(pBuf, bit_offset, ENDPOINT_BITS); + + uint32_t pbits[6]; + for (uint32_t p = 0; p < PBITS; p++) + pbits[p] = read_bits32(pBuf, bit_offset, 1); + + uint32_t weights[16]; + for (uint32_t i = 0; i < 16; i++) + weights[i] = read_bits32(pBuf, bit_offset, ((!i) || (i == g_bc7_table_anchor_index_third_subset_1[part]) || (i == g_bc7_table_anchor_index_third_subset_2[part])) ? (WEIGHT_BITS - 1) : WEIGHT_BITS); + + assert(bit_offset == 128); + + for (uint32_t e = 0; e < ENDPOINTS; e++) + for (uint32_t c = 0; c < 4; c++) + endpoints[e][c] = (uint8_t)((c == 3) ? 255 : (PBITS ? bc7_dequant(endpoints[e][c], pbits[e], ENDPOINT_BITS) : bc7_dequant(endpoints[e][c], ENDPOINT_BITS))); + + color_rgba block_colors[3][8]; + for (uint32_t s = 0; s < 3; s++) + for (uint32_t i = 0; i < WEIGHT_VALS; i++) + { + for (uint32_t c = 0; c < 3; c++) + block_colors[s][i][c] = (uint8_t)bc7_interp(endpoints[s * 2 + 0][c], endpoints[s * 2 + 1][c], i, WEIGHT_BITS); + block_colors[s][i][3] = 255; + } + + for (uint32_t i = 0; i < 16; i++) + pPixels[i] = block_colors[g_bc7_partition3[part * 16 + i]][weights[i]]; + + return true; +} + +bool unpack_bc7_mode1_3_7(uint32_t mode, const void* pBlock_bits, color_rgba* pPixels) +{ + //const uint32_t SUBSETS = 2; + const uint32_t ENDPOINTS = 4; + const uint32_t COMPS = (mode == 7) ? 4 : 3; + const uint32_t WEIGHT_BITS = (mode == 1) ? 3 : 2; + const uint32_t ENDPOINT_BITS = (mode == 7) ? 5 : ((mode == 1) ? 6 : 7); + const uint32_t PBITS = (mode == 1) ? 2 : 4; + const uint32_t SHARED_PBITS = (mode == 1) ? true : false; + const uint32_t WEIGHT_VALS = 1 << WEIGHT_BITS; + + uint32_t bit_offset = 0; + const uint8_t* pBuf = static_cast(pBlock_bits); + + if (read_bits32(pBuf, bit_offset, mode + 1) != (1U << mode)) return false; + + const uint32_t part = read_bits32(pBuf, bit_offset, 6); + + color_rgba endpoints[ENDPOINTS]; + for (uint32_t c = 0; c < COMPS; c++) + for (uint32_t e = 0; e < ENDPOINTS; e++) + endpoints[e][c] = (uint8_t)read_bits32(pBuf, bit_offset, ENDPOINT_BITS); + + uint32_t pbits[4]; + for (uint32_t p = 0; p < PBITS; p++) + pbits[p] = read_bits32(pBuf, bit_offset, 1); + + uint32_t weights[16]; + for (uint32_t i = 0; i < 16; i++) + weights[i] = read_bits32(pBuf, bit_offset, ((!i) || (i == g_bc7_table_anchor_index_second_subset[part])) ? (WEIGHT_BITS - 1) : WEIGHT_BITS); + + assert(bit_offset == 128); + + for (uint32_t e = 0; e < ENDPOINTS; e++) + for (uint32_t c = 0; c < 4; c++) + endpoints[e][c] = (uint8_t)((c == ((mode == 7U) ? 4U : 3U)) ? 255 : bc7_dequant(endpoints[e][c], pbits[SHARED_PBITS ? (e >> 1) : e], ENDPOINT_BITS)); + + color_rgba block_colors[2][8]; + for (uint32_t s = 0; s < 2; s++) + for (uint32_t i = 0; i < WEIGHT_VALS; i++) + { + for (uint32_t c = 0; c < COMPS; c++) + block_colors[s][i][c] = (uint8_t)bc7_interp(endpoints[s * 2 + 0][c], endpoints[s * 2 + 1][c], i, WEIGHT_BITS); + block_colors[s][i][3] = (COMPS == 3) ? 255 : block_colors[s][i][3]; + } + + for (uint32_t i = 0; i < 16; i++) + pPixels[i] = block_colors[g_bc7_partition2[part * 16 + i]][weights[i]]; + + return true; +} + +bool unpack_bc7_mode4_5(uint32_t mode, const void* pBlock_bits, color_rgba* pPixels) +{ + const uint32_t ENDPOINTS = 2; + const uint32_t COMPS = 4; + const uint32_t WEIGHT_BITS = 2; + const uint32_t A_WEIGHT_BITS = (mode == 4) ? 3 : 2; + const uint32_t ENDPOINT_BITS = (mode == 4) ? 5 : 7; + const uint32_t A_ENDPOINT_BITS = (mode == 4) ? 6 : 8; + //const uint32_t WEIGHT_VALS = 1 << WEIGHT_BITS; + //const uint32_t A_WEIGHT_VALS = 1 << A_WEIGHT_BITS; + + uint32_t bit_offset = 0; + const uint8_t* pBuf = static_cast(pBlock_bits); + + if (read_bits32(pBuf, bit_offset, mode + 1) != (1U << mode)) return false; + + const uint32_t comp_rot = read_bits32(pBuf, bit_offset, 2); + const uint32_t index_mode = (mode == 4) ? read_bits32(pBuf, bit_offset, 1) : 0; + + color_rgba endpoints[ENDPOINTS]; + for (uint32_t c = 0; c < COMPS; c++) + for (uint32_t e = 0; e < ENDPOINTS; e++) + endpoints[e][c] = (uint8_t)read_bits32(pBuf, bit_offset, (c == 3) ? A_ENDPOINT_BITS : ENDPOINT_BITS); + + const uint32_t weight_bits[2] = { index_mode ? A_WEIGHT_BITS : WEIGHT_BITS, index_mode ? WEIGHT_BITS : A_WEIGHT_BITS }; + + uint32_t weights[16], a_weights[16]; + + for (uint32_t i = 0; i < 16; i++) + (index_mode ? a_weights : weights)[i] = read_bits32(pBuf, bit_offset, weight_bits[index_mode] - ((!i) ? 1 : 0)); + + for (uint32_t i = 0; i < 16; i++) + (index_mode ? weights : a_weights)[i] = read_bits32(pBuf, bit_offset, weight_bits[1 - index_mode] - ((!i) ? 1 : 0)); + + assert(bit_offset == 128); + + for (uint32_t e = 0; e < ENDPOINTS; e++) + for (uint32_t c = 0; c < 4; c++) + endpoints[e][c] = (uint8_t)bc7_dequant(endpoints[e][c], (c == 3) ? A_ENDPOINT_BITS : ENDPOINT_BITS); + + color_rgba block_colors[8]; + for (uint32_t i = 0; i < (1U << weight_bits[0]); i++) + for (uint32_t c = 0; c < 3; c++) + block_colors[i][c] = (uint8_t)bc7_interp(endpoints[0][c], endpoints[1][c], i, weight_bits[0]); + + for (uint32_t i = 0; i < (1U << weight_bits[1]); i++) + block_colors[i][3] = (uint8_t)bc7_interp(endpoints[0][3], endpoints[1][3], i, weight_bits[1]); + + for (uint32_t i = 0; i < 16; i++) + { + pPixels[i] = block_colors[weights[i]]; + pPixels[i].a = block_colors[a_weights[i]].a; + if (comp_rot >= 1) + std::swap(pPixels[i].a, pPixels[i].m_comps[comp_rot - 1]); + } + + return true; +} + +struct bc7_mode_6 +{ + struct + { + uint64_t m_mode : 7; + uint64_t m_r0 : 7; + uint64_t m_r1 : 7; + uint64_t m_g0 : 7; + uint64_t m_g1 : 7; + uint64_t m_b0 : 7; + uint64_t m_b1 : 7; + uint64_t m_a0 : 7; + uint64_t m_a1 : 7; + uint64_t m_p0 : 1; + } m_lo; + + union + { + struct + { + uint64_t m_p1 : 1; + uint64_t m_s00 : 3; + uint64_t m_s10 : 4; + uint64_t m_s20 : 4; + uint64_t m_s30 : 4; + + uint64_t m_s01 : 4; + uint64_t m_s11 : 4; + uint64_t m_s21 : 4; + uint64_t m_s31 : 4; + + uint64_t m_s02 : 4; + uint64_t m_s12 : 4; + uint64_t m_s22 : 4; + uint64_t m_s32 : 4; + + uint64_t m_s03 : 4; + uint64_t m_s13 : 4; + uint64_t m_s23 : 4; + uint64_t m_s33 : 4; + + } m_hi; + + uint64_t m_hi_bits; + }; +}; + +bool unpack_bc7_mode6(const void *pBlock_bits, color_rgba *pPixels) +{ + static_assert(sizeof(bc7_mode_6) == 16, "sizeof(bc7_mode_6) == 16"); + + const bc7_mode_6 &block = *static_cast(pBlock_bits); + + if (block.m_lo.m_mode != (1 << 6)) + return false; + + const uint32_t r0 = (uint32_t)((block.m_lo.m_r0 << 1) | block.m_lo.m_p0); + const uint32_t g0 = (uint32_t)((block.m_lo.m_g0 << 1) | block.m_lo.m_p0); + const uint32_t b0 = (uint32_t)((block.m_lo.m_b0 << 1) | block.m_lo.m_p0); + const uint32_t a0 = (uint32_t)((block.m_lo.m_a0 << 1) | block.m_lo.m_p0); + const uint32_t r1 = (uint32_t)((block.m_lo.m_r1 << 1) | block.m_hi.m_p1); + const uint32_t g1 = (uint32_t)((block.m_lo.m_g1 << 1) | block.m_hi.m_p1); + const uint32_t b1 = (uint32_t)((block.m_lo.m_b1 << 1) | block.m_hi.m_p1); + const uint32_t a1 = (uint32_t)((block.m_lo.m_a1 << 1) | block.m_hi.m_p1); + + color_rgba vals[16]; + for (uint32_t i = 0; i < 16; i++) + { + const uint32_t w = g_bc7_weights4[i]; + const uint32_t iw = 64 - w; + vals[i].set_noclamp_rgba( + (r0 * iw + r1 * w + 32) >> 6, + (g0 * iw + g1 * w + 32) >> 6, + (b0 * iw + b1 * w + 32) >> 6, + (a0 * iw + a1 * w + 32) >> 6); + } + + pPixels[0] = vals[block.m_hi.m_s00]; + pPixels[1] = vals[block.m_hi.m_s10]; + pPixels[2] = vals[block.m_hi.m_s20]; + pPixels[3] = vals[block.m_hi.m_s30]; + + pPixels[4] = vals[block.m_hi.m_s01]; + pPixels[5] = vals[block.m_hi.m_s11]; + pPixels[6] = vals[block.m_hi.m_s21]; + pPixels[7] = vals[block.m_hi.m_s31]; + + pPixels[8] = vals[block.m_hi.m_s02]; + pPixels[9] = vals[block.m_hi.m_s12]; + pPixels[10] = vals[block.m_hi.m_s22]; + pPixels[11] = vals[block.m_hi.m_s32]; + + pPixels[12] = vals[block.m_hi.m_s03]; + pPixels[13] = vals[block.m_hi.m_s13]; + pPixels[14] = vals[block.m_hi.m_s23]; + pPixels[15] = vals[block.m_hi.m_s33]; + + return true; +} + +bool unpack_bc7(const void *pBlock, bc7decomp::color_rgba *pPixels) +{ + const uint32_t first_byte = static_cast(pBlock)[0]; + + for (uint32_t mode = 0; mode <= 7; mode++) + { + if (first_byte & (1U << mode)) + { + switch (mode) + { + case 0: + case 2: + return unpack_bc7_mode0_2(mode, pBlock, pPixels); + case 1: + case 3: + case 7: + return unpack_bc7_mode1_3_7(mode, pBlock, pPixels); + case 4: + case 5: + return unpack_bc7_mode4_5(mode, pBlock, pPixels); + case 6: + return unpack_bc7_mode6(pBlock, pPixels); + default: + break; + } + } + } + + return false; +} + +} // namespace bc7decomp_ref + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright(c) 2020 Richard Geldreich, Jr. +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files(the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions : +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain(www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non - commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain.We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors.We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ + diff --git a/external/bc7enc_rdo/bc7enc.cpp b/external/bc7enc_rdo/bc7enc.cpp new file mode 100644 index 0000000000..f4db36ea5d --- /dev/null +++ b/external/bc7enc_rdo/bc7enc.cpp @@ -0,0 +1,2580 @@ +// File: bc7enc.c - Richard Geldreich, Jr. 3/31/2020 - MIT license or public domain (see end of file) +// Currently supports modes 1, 6 for RGB blocks, and modes 5, 6, 7 for RGBA blocks. +#include "bc7enc.h" +#include +#include +#include +#include +#include + +// Helpers +static inline int32_t clampi(int32_t value, int32_t low, int32_t high) { if (value < low) value = low; else if (value > high) value = high; return value; } +static inline float clampf(float value, float low, float high) { if (value < low) value = low; else if (value > high) value = high; return value; } +static inline float saturate(float value) { return clampf(value, 0, 1.0f); } +[[maybe_unused]] static inline uint8_t minimumub(uint8_t a, uint8_t b) { return (a < b) ? a : b; } +static inline int32_t minimumi(int32_t a, int32_t b) { return (a < b) ? a : b; } +static inline uint32_t minimumu(uint32_t a, uint32_t b) { return (a < b) ? a : b; } +static inline float minimumf(float a, float b) { return (a < b) ? a : b; } +[[maybe_unused]] static inline uint8_t maximumub(uint8_t a, uint8_t b) { return (a > b) ? a : b; } +static inline uint32_t maximumu(uint32_t a, uint32_t b) { return (a > b) ? a : b; } +[[maybe_unused]] static inline int32_t maximumi(int32_t a, int32_t b) { return (a > b) ? a : b; } +static inline float maximumf(float a, float b) { return (a > b) ? a : b; } +static inline int squarei(int i) { return i * i; } +static inline float squaref(float i) { return i * i; } +template inline T0 lerp(T0 a, T0 b, T1 c) { return a + (b - a) * c; } + +static inline int32_t iabs32(int32_t v) { uint32_t msk = v >> 31; return (v ^ msk) - msk; } +[[maybe_unused]] static inline void swapub(uint8_t* a, uint8_t* b) { uint8_t t = *a; *a = *b; *b = t; } +static inline void swapu(uint32_t* a, uint32_t* b) { uint32_t t = *a; *a = *b; *b = t; } +[[maybe_unused]] static inline void swapf(float* a, float* b) { float t = *a; *a = *b; *b = t; } + +struct vec4F { float m_c[4]; }; + +static inline color_rgba *color_quad_u8_set_clamped(color_rgba *pRes, int32_t r, int32_t g, int32_t b, int32_t a) { pRes->m_c[0] = (uint8_t)clampi(r, 0, 255); pRes->m_c[1] = (uint8_t)clampi(g, 0, 255); pRes->m_c[2] = (uint8_t)clampi(b, 0, 255); pRes->m_c[3] = (uint8_t)clampi(a, 0, 255); return pRes; } +static inline color_rgba *color_quad_u8_set(color_rgba *pRes, int32_t r, int32_t g, int32_t b, int32_t a) { assert((uint32_t)(r | g | b | a) <= 255); pRes->m_c[0] = (uint8_t)r; pRes->m_c[1] = (uint8_t)g; pRes->m_c[2] = (uint8_t)b; pRes->m_c[3] = (uint8_t)a; return pRes; } +static inline bool color_quad_u8_notequals(const color_rgba *pLHS, const color_rgba *pRHS) { return (pLHS->m_c[0] != pRHS->m_c[0]) || (pLHS->m_c[1] != pRHS->m_c[1]) || (pLHS->m_c[2] != pRHS->m_c[2]) || (pLHS->m_c[3] != pRHS->m_c[3]); } +static inline vec4F *vec4F_set_scalar(vec4F *pV, float x) { pV->m_c[0] = x; pV->m_c[1] = x; pV->m_c[2] = x; pV->m_c[3] = x; return pV; } +static inline vec4F *vec4F_set(vec4F *pV, float x, float y, float z, float w) { pV->m_c[0] = x; pV->m_c[1] = y; pV->m_c[2] = z; pV->m_c[3] = w; return pV; } +static inline vec4F *vec4F_saturate_in_place(vec4F *pV) { pV->m_c[0] = saturate(pV->m_c[0]); pV->m_c[1] = saturate(pV->m_c[1]); pV->m_c[2] = saturate(pV->m_c[2]); pV->m_c[3] = saturate(pV->m_c[3]); return pV; } +static inline vec4F vec4F_saturate(const vec4F *pV) { vec4F res; res.m_c[0] = saturate(pV->m_c[0]); res.m_c[1] = saturate(pV->m_c[1]); res.m_c[2] = saturate(pV->m_c[2]); res.m_c[3] = saturate(pV->m_c[3]); return res; } +static inline vec4F vec4F_from_color(const color_rgba *pC) { vec4F res; vec4F_set(&res, pC->m_c[0], pC->m_c[1], pC->m_c[2], pC->m_c[3]); return res; } +static inline vec4F vec4F_add(const vec4F *pLHS, const vec4F *pRHS) { vec4F res; vec4F_set(&res, pLHS->m_c[0] + pRHS->m_c[0], pLHS->m_c[1] + pRHS->m_c[1], pLHS->m_c[2] + pRHS->m_c[2], pLHS->m_c[3] + pRHS->m_c[3]); return res; } +static inline vec4F vec4F_sub(const vec4F *pLHS, const vec4F *pRHS) { vec4F res; vec4F_set(&res, pLHS->m_c[0] - pRHS->m_c[0], pLHS->m_c[1] - pRHS->m_c[1], pLHS->m_c[2] - pRHS->m_c[2], pLHS->m_c[3] - pRHS->m_c[3]); return res; } +static inline float vec4F_dot(const vec4F *pLHS, const vec4F *pRHS) { return pLHS->m_c[0] * pRHS->m_c[0] + pLHS->m_c[1] * pRHS->m_c[1] + pLHS->m_c[2] * pRHS->m_c[2] + pLHS->m_c[3] * pRHS->m_c[3]; } +static inline vec4F vec4F_mul(const vec4F *pLHS, float s) { vec4F res; vec4F_set(&res, pLHS->m_c[0] * s, pLHS->m_c[1] * s, pLHS->m_c[2] * s, pLHS->m_c[3] * s); return res; } +static inline vec4F *vec4F_normalize_in_place(vec4F *pV) { float s = pV->m_c[0] * pV->m_c[0] + pV->m_c[1] * pV->m_c[1] + pV->m_c[2] * pV->m_c[2] + pV->m_c[3] * pV->m_c[3]; if (s != 0.0f) { s = 1.0f / sqrtf(s); pV->m_c[0] *= s; pV->m_c[1] *= s; pV->m_c[2] *= s; pV->m_c[3] *= s; } return pV; } + +// Various BC7 tables +static const uint32_t g_bc7_weights2[4] = { 0, 21, 43, 64 }; +static const uint32_t g_bc7_weights3[8] = { 0, 9, 18, 27, 37, 46, 55, 64 }; +static const uint32_t g_bc7_weights4[16] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 }; +// Precomputed weight constants used during least fit determination. For each entry in g_bc7_weights[]: w * w, (1.0f - w) * w, (1.0f - w) * (1.0f - w), w +static const float g_bc7_weights2x[4 * 4] = { 0.000000f, 0.000000f, 1.000000f, 0.000000f, 0.107666f, 0.220459f, 0.451416f, 0.328125f, 0.451416f, 0.220459f, 0.107666f, 0.671875f, 1.000000f, 0.000000f, 0.000000f, 1.000000f }; +static const float g_bc7_weights3x[8 * 4] = { 0.000000f, 0.000000f, 1.000000f, 0.000000f, 0.019775f, 0.120850f, 0.738525f, 0.140625f, 0.079102f, 0.202148f, 0.516602f, 0.281250f, 0.177979f, 0.243896f, 0.334229f, 0.421875f, 0.334229f, 0.243896f, 0.177979f, 0.578125f, 0.516602f, 0.202148f, + 0.079102f, 0.718750f, 0.738525f, 0.120850f, 0.019775f, 0.859375f, 1.000000f, 0.000000f, 0.000000f, 1.000000f }; +static const float g_bc7_weights4x[16 * 4] = { 0.000000f, 0.000000f, 1.000000f, 0.000000f, 0.003906f, 0.058594f, 0.878906f, 0.062500f, 0.019775f, 0.120850f, 0.738525f, 0.140625f, 0.041260f, 0.161865f, 0.635010f, 0.203125f, 0.070557f, 0.195068f, 0.539307f, 0.265625f, 0.107666f, 0.220459f, + 0.451416f, 0.328125f, 0.165039f, 0.241211f, 0.352539f, 0.406250f, 0.219727f, 0.249023f, 0.282227f, 0.468750f, 0.282227f, 0.249023f, 0.219727f, 0.531250f, 0.352539f, 0.241211f, 0.165039f, 0.593750f, 0.451416f, 0.220459f, 0.107666f, 0.671875f, 0.539307f, 0.195068f, 0.070557f, 0.734375f, + 0.635010f, 0.161865f, 0.041260f, 0.796875f, 0.738525f, 0.120850f, 0.019775f, 0.859375f, 0.878906f, 0.058594f, 0.003906f, 0.937500f, 1.000000f, 0.000000f, 0.000000f, 1.000000f }; + +static const uint8_t g_bc7_partition1[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; +static const uint8_t g_bc7_partition2[64 * 16] = +{ + 0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1, 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, 0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1, 0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1, 0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1, 0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1, 0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1, 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1, + 0,0,0,0,1,0,0,0,1,1,1,0,1,1,1,1, 0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0, 0,1,1,1,0,0,1,1,0,0,0,1,0,0,0,0, 0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0, 0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1, + 0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0, 0,0,0,0,1,0,0,0,1,0,0,0,1,1,0,0, 0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0, 0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0, 0,0,0,1,0,1,1,1,1,1,1,0,1,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0, 0,0,1,1,1,0,0,1,1,0,0,1,1,1,0,0, + 0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, 0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0, 0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0, 0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0, 0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0, 0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1, 0,1,0,1,1,0,1,0,1,0,1,0,0,1,0,1, + 0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,0, 0,0,0,1,0,0,1,1,1,1,0,0,1,0,0,0, 0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0, 0,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0, 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, 0,0,1,1,1,1,0,0,1,1,0,0,0,0,1,1, 0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1, 0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0, + 0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0, 0,0,1,0,0,1,1,1,0,0,1,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,1,1,1,0,0,1,0, 0,0,0,0,0,1,0,0,1,1,1,0,0,1,0,0, 0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,1, 0,1,1,0,0,0,1,1,1,0,0,1,1,1,0,0, 0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,0, + 0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,1, 0,1,1,0,0,0,1,1,0,0,1,1,1,0,0,1, 0,1,1,1,1,1,1,0,1,0,0,0,0,0,0,1, 0,0,0,1,1,0,0,0,1,1,1,0,0,1,1,1, 0,0,0,0,1,1,1,1,0,0,1,1,0,0,1,1, 0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0, 0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0, 0,1,0,0,0,1,0,0,0,1,1,1,0,1,1,1 +}; + +static const uint8_t g_bc7_partition3[64 * 16] = +{ + 0,0,1,1,0,0,1,1,0,2,2,1,2,2,2,2, 0,0,0,1,0,0,1,1,2,2,1,1,2,2,2,1, 0,0,0,0,2,0,0,1,2,2,1,1,2,2,1,1, 0,2,2,2,0,0,2,2,0,0,1,1,0,1,1,1, 0,0,0,0,0,0,0,0,1,1,2,2,1,1,2,2, 0,0,1,1,0,0,1,1,0,0,2,2,0,0,2,2, 0,0,2,2,0,0,2,2,1,1,1,1,1,1,1,1, 0,0,1,1,0,0,1,1,2,2,1,1,2,2,1,1, + 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2, 0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2, 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2, 0,0,1,2,0,0,1,2,0,0,1,2,0,0,1,2, 0,1,1,2,0,1,1,2,0,1,1,2,0,1,1,2, 0,1,2,2,0,1,2,2,0,1,2,2,0,1,2,2, 0,0,1,1,0,1,1,2,1,1,2,2,1,2,2,2, 0,0,1,1,2,0,0,1,2,2,0,0,2,2,2,0, + 0,0,0,1,0,0,1,1,0,1,1,2,1,1,2,2, 0,1,1,1,0,0,1,1,2,0,0,1,2,2,0,0, 0,0,0,0,1,1,2,2,1,1,2,2,1,1,2,2, 0,0,2,2,0,0,2,2,0,0,2,2,1,1,1,1, 0,1,1,1,0,1,1,1,0,2,2,2,0,2,2,2, 0,0,0,1,0,0,0,1,2,2,2,1,2,2,2,1, 0,0,0,0,0,0,1,1,0,1,2,2,0,1,2,2, 0,0,0,0,1,1,0,0,2,2,1,0,2,2,1,0, + 0,1,2,2,0,1,2,2,0,0,1,1,0,0,0,0, 0,0,1,2,0,0,1,2,1,1,2,2,2,2,2,2, 0,1,1,0,1,2,2,1,1,2,2,1,0,1,1,0, 0,0,0,0,0,1,1,0,1,2,2,1,1,2,2,1, 0,0,2,2,1,1,0,2,1,1,0,2,0,0,2,2, 0,1,1,0,0,1,1,0,2,0,0,2,2,2,2,2, 0,0,1,1,0,1,2,2,0,1,2,2,0,0,1,1, 0,0,0,0,2,0,0,0,2,2,1,1,2,2,2,1, + 0,0,0,0,0,0,0,2,1,1,2,2,1,2,2,2, 0,2,2,2,0,0,2,2,0,0,1,2,0,0,1,1, 0,0,1,1,0,0,1,2,0,0,2,2,0,2,2,2, 0,1,2,0,0,1,2,0,0,1,2,0,0,1,2,0, 0,0,0,0,1,1,1,1,2,2,2,2,0,0,0,0, 0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0, 0,1,2,0,2,0,1,2,1,2,0,1,0,1,2,0, 0,0,1,1,2,2,0,0,1,1,2,2,0,0,1,1, + 0,0,1,1,1,1,2,2,2,2,0,0,0,0,1,1, 0,1,0,1,0,1,0,1,2,2,2,2,2,2,2,2, 0,0,0,0,0,0,0,0,2,1,2,1,2,1,2,1, 0,0,2,2,1,1,2,2,0,0,2,2,1,1,2,2, 0,0,2,2,0,0,1,1,0,0,2,2,0,0,1,1, 0,2,2,0,1,2,2,1,0,2,2,0,1,2,2,1, 0,1,0,1,2,2,2,2,2,2,2,2,0,1,0,1, 0,0,0,0,2,1,2,1,2,1,2,1,2,1,2,1, + 0,1,0,1,0,1,0,1,0,1,0,1,2,2,2,2, 0,2,2,2,0,1,1,1,0,2,2,2,0,1,1,1, 0,0,0,2,1,1,1,2,0,0,0,2,1,1,1,2, 0,0,0,0,2,1,1,2,2,1,1,2,2,1,1,2, 0,2,2,2,0,1,1,1,0,1,1,1,0,2,2,2, 0,0,0,2,1,1,1,2,1,1,1,2,0,0,0,2, 0,1,1,0,0,1,1,0,0,1,1,0,2,2,2,2, 0,0,0,0,0,0,0,0,2,1,1,2,2,1,1,2, + 0,1,1,0,0,1,1,0,2,2,2,2,2,2,2,2, 0,0,2,2,0,0,1,1,0,0,1,1,0,0,2,2, 0,0,2,2,1,1,2,2,1,1,2,2,0,0,2,2, 0,0,0,0,0,0,0,0,0,0,0,0,2,1,1,2, 0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,1, 0,2,2,2,1,2,2,2,0,2,2,2,1,2,2,2, 0,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2, 0,1,1,1,2,0,1,1,2,2,0,1,2,2,2,0, +}; + +static const uint8_t g_bc7_table_anchor_index_third_subset_1[64] = +{ + 3, 3,15,15, 8, 3,15,15, 8, 8, 6, 6, 6, 5, 3, 3, 3, 3, 8,15, 3, 3, 6,10, 5, 8, 8, 6, 8, 5,15,15, 8,15, 3, 5, 6,10, 8,15, 15, 3,15, 5,15,15,15,15, 3,15, 5, 5, 5, 8, 5,10, 5,10, 8,13,15,12, 3, 3 +}; + +static const uint8_t g_bc7_table_anchor_index_third_subset_2[64] = +{ + 15, 8, 8, 3,15,15, 3, 8, 15,15,15,15,15,15,15, 8, 15, 8,15, 3,15, 8,15, 8, 3,15, 6,10,15,15,10, 8, 15, 3,15,10,10, 8, 9,10, 6,15, 8,15, 3, 6, 6, 8, 15, 3,15,15,15,15,15,15, 15,15,15,15, 3,15,15, 8 +}; + +static const uint8_t g_bc7_table_anchor_index_second_subset[64] = { 15,15,15,15,15,15,15,15, 15,15,15,15,15,15,15,15, 15, 2, 8, 2, 2, 8, 8,15, 2, 8, 2, 2, 8, 8, 2, 2, 15,15, 6, 8, 2, 8,15,15, 2, 8, 2, 2, 2,15,15, 6, 6, 2, 6, 8,15,15, 2, 2, 15,15,15,15,15, 2, 2,15 }; +static const uint8_t g_bc7_num_subsets[8] = { 3, 2, 3, 2, 1, 1, 1, 2 }; +static const uint8_t g_bc7_partition_bits[8] = { 4, 6, 6, 6, 0, 0, 0, 6 }; +static const uint8_t g_bc7_color_index_bitcount[8] = { 3, 3, 2, 2, 2, 2, 4, 2 }; +static int get_bc7_color_index_size(int mode, int index_selection_bit) { return g_bc7_color_index_bitcount[mode] + index_selection_bit; } +static uint8_t g_bc7_alpha_index_bitcount[8] = { 0, 0, 0, 0, 3, 2, 4, 2 }; +static int get_bc7_alpha_index_size(int mode, int index_selection_bit) { return g_bc7_alpha_index_bitcount[mode] - index_selection_bit; } +static const uint8_t g_bc7_mode_has_p_bits[8] = { 1, 1, 0, 1, 0, 0, 1, 1 }; +static const uint8_t g_bc7_mode_has_shared_p_bits[8] = { 0, 1, 0, 0, 0, 0, 0, 0 }; +static const uint8_t g_bc7_color_precision_table[8] = { 4, 6, 5, 7, 5, 7, 7, 5 }; +static const int8_t g_bc7_alpha_precision_table[8] = { 0, 0, 0, 0, 6, 8, 7, 5 }; +static bool get_bc7_mode_has_seperate_alpha_selectors(int mode) { return (mode == 4) || (mode == 5); } + +typedef struct { uint16_t m_error; uint8_t m_lo; uint8_t m_hi; } endpoint_err; + +static endpoint_err g_bc7_mode_1_optimal_endpoints[256][2]; // [c][pbit] +static const uint32_t BC7ENC_MODE_1_OPTIMAL_INDEX = 2; + +static endpoint_err g_bc7_mode_7_optimal_endpoints[256][2][2]; // [c][pbit][hp][lp] +const uint32_t BC7E_MODE_7_OPTIMAL_INDEX = 1; + +static float g_mode1_rgba_midpoints[64][2]; +static float g_mode5_rgba_midpoints[128]; +static float g_mode7_rgba_midpoints[32][2]; + +static uint8_t g_mode6_reduced_quant[2048][2]; + +static bool g_initialized; + +// Initialize the lookup table used for optimal single color compression in mode 1/7. Must be called before encoding. +void bc7enc_compress_block_init() +{ + if (g_initialized) + return; + + // Mode 7 endpoint midpoints + for (uint32_t p = 0; p < 2; p++) + { + for (uint32_t i = 0; i < 32; i++) + { + uint32_t vl = ((i << 1) | p) << 2; + vl |= (vl >> 6); + float lo = vl / 255.0f; + + uint32_t vh = ((minimumi(31, (i + 1)) << 1) | p) << 2; + vh |= (vh >> 6); + float hi = vh / 255.0f; + + //g_mode7_quant_values[i][p] = lo; + if (i == 31) + g_mode7_rgba_midpoints[i][p] = 1.0f; + else + g_mode7_rgba_midpoints[i][p] = (lo + hi) / 2.0f; + } + } + + // Mode 1 endpoint midpoints + for (uint32_t p = 0; p < 2; p++) + { + for (uint32_t i = 0; i < 64; i++) + { + uint32_t vl = ((i << 1) | p) << 1; + vl |= (vl >> 7); + float lo = vl / 255.0f; + + uint32_t vh = ((minimumi(63, (i + 1)) << 1) | p) << 1; + vh |= (vh >> 7); + float hi = vh / 255.0f; + + //g_mode1_quant_values[i][p] = lo; + if (i == 63) + g_mode1_rgba_midpoints[i][p] = 1.0f; + else + g_mode1_rgba_midpoints[i][p] = (lo + hi) / 2.0f; + } + } + + // Mode 5 endpoint midpoints + for (uint32_t i = 0; i < 128; i++) + { + uint32_t vl = (i << 1); + vl |= (vl >> 7); + float lo = vl / 255.0f; + + uint32_t vh = minimumi(127, i + 1) << 1; + vh |= (vh >> 7); + float hi = vh / 255.0f; + + if (i == 127) + g_mode5_rgba_midpoints[i] = 1.0f; + else + g_mode5_rgba_midpoints[i] = (lo + hi) / 2.0f; + } + + for (uint32_t p = 0; p < 2; p++) + { + for (uint32_t i = 0; i < 2048; i++) + { + float f = i / 2047.0f; + + float best_err = 1e+9f; + int best_index = 0; + for (int j = 0; j < 64; j++) + { + int ik = (j * 127 + 31) / 63; + float k = ((ik << 1) + p) / 255.0f; + + float e = fabsf(k - f); + if (e < best_err) + { + best_err = e; + best_index = ik; + } + } + + g_mode6_reduced_quant[i][p] = (uint8_t)best_index; + } + } // p + + // Mode 1 + for (int c = 0; c < 256; c++) + { + for (uint32_t lp = 0; lp < 2; lp++) + { + endpoint_err best; + best.m_error = (uint16_t)UINT16_MAX; + for (uint32_t l = 0; l < 64; l++) + { + uint32_t low = ((l << 1) | lp) << 1; + low |= (low >> 7); + for (uint32_t h = 0; h < 64; h++) + { + uint32_t high = ((h << 1) | lp) << 1; + high |= (high >> 7); + const int k = (low * (64 - g_bc7_weights3[BC7ENC_MODE_1_OPTIMAL_INDEX]) + high * g_bc7_weights3[BC7ENC_MODE_1_OPTIMAL_INDEX] + 32) >> 6; + const int err = (k - c) * (k - c); + if (err < best.m_error) + { + best.m_error = (uint16_t)err; + best.m_lo = (uint8_t)l; + best.m_hi = (uint8_t)h; + } + } // h + } // l + g_bc7_mode_1_optimal_endpoints[c][lp] = best; + } // lp + } // c + + // Mode 7: 555.1 2-bit indices + for (int c = 0; c < 256; c++) + { + for (uint32_t hp = 0; hp < 2; hp++) + { + for (uint32_t lp = 0; lp < 2; lp++) + { + endpoint_err best; + best.m_error = (uint16_t)UINT16_MAX; + best.m_lo = 0; + best.m_hi = 0; + + for (uint32_t l = 0; l < 32; l++) + { + uint32_t low = ((l << 1) | lp) << 2; + low |= (low >> 6); + + for (uint32_t h = 0; h < 32; h++) + { + uint32_t high = ((h << 1) | hp) << 2; + high |= (high >> 6); + + const int k = (low * (64 - g_bc7_weights2[BC7E_MODE_7_OPTIMAL_INDEX]) + high * g_bc7_weights2[BC7E_MODE_7_OPTIMAL_INDEX] + 32) >> 6; + + const int err = (k - c) * (k - c); + if (err < best.m_error) + { + best.m_error = (uint16_t)err; + best.m_lo = (uint8_t)l; + best.m_hi = (uint8_t)h; + } + } // h + } // l + + g_bc7_mode_7_optimal_endpoints[c][hp][lp] = best; + + } // hp + + } // lp + + } // c + + g_initialized = true; +} + +static void compute_least_squares_endpoints_rgba(uint32_t N, const uint8_t *pSelectors, const vec4F *pSelector_weights, vec4F *pXl, vec4F *pXh, const color_rgba *pColors) +{ + // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf + // I did this in matrix form first, expanded out all the ops, then optimized it a bit. + float z00 = 0.0f, z01 = 0.0f, z10 = 0.0f, z11 = 0.0f; + float q00_r = 0.0f, q10_r = 0.0f, t_r = 0.0f; + float q00_g = 0.0f, q10_g = 0.0f, t_g = 0.0f; + float q00_b = 0.0f, q10_b = 0.0f, t_b = 0.0f; + float q00_a = 0.0f, q10_a = 0.0f, t_a = 0.0f; + for (uint32_t i = 0; i < N; i++) + { + const uint32_t sel = pSelectors[i]; + z00 += pSelector_weights[sel].m_c[0]; + z10 += pSelector_weights[sel].m_c[1]; + z11 += pSelector_weights[sel].m_c[2]; + float w = pSelector_weights[sel].m_c[3]; + q00_r += w * pColors[i].m_c[0]; t_r += pColors[i].m_c[0]; + q00_g += w * pColors[i].m_c[1]; t_g += pColors[i].m_c[1]; + q00_b += w * pColors[i].m_c[2]; t_b += pColors[i].m_c[2]; + q00_a += w * pColors[i].m_c[3]; t_a += pColors[i].m_c[3]; + } + + q10_r = t_r - q00_r; + q10_g = t_g - q00_g; + q10_b = t_b - q00_b; + q10_a = t_a - q00_a; + + z01 = z10; + + float det = z00 * z11 - z01 * z10; + if (det != 0.0f) + det = 1.0f / det; + + float iz00, iz01, iz10, iz11; + iz00 = z11 * det; + iz01 = -z01 * det; + iz10 = -z10 * det; + iz11 = z00 * det; + + pXl->m_c[0] = (float)(iz00 * q00_r + iz01 * q10_r); pXh->m_c[0] = (float)(iz10 * q00_r + iz11 * q10_r); + pXl->m_c[1] = (float)(iz00 * q00_g + iz01 * q10_g); pXh->m_c[1] = (float)(iz10 * q00_g + iz11 * q10_g); + pXl->m_c[2] = (float)(iz00 * q00_b + iz01 * q10_b); pXh->m_c[2] = (float)(iz10 * q00_b + iz11 * q10_b); + pXl->m_c[3] = (float)(iz00 * q00_a + iz01 * q10_a); pXh->m_c[3] = (float)(iz10 * q00_a + iz11 * q10_a); + + for (uint32_t c = 0; c < 4; c++) + { + if ((pXl->m_c[c] < 0.0f) || (pXh->m_c[c] > 255.0f)) + { + uint32_t lo_v = UINT32_MAX, hi_v = 0; + for (uint32_t i = 0; i < N; i++) + { + lo_v = minimumu(lo_v, pColors[i].m_c[c]); + hi_v = maximumu(hi_v, pColors[i].m_c[c]); + } + + if (lo_v == hi_v) + { + pXl->m_c[c] = (float)lo_v; + pXh->m_c[c] = (float)hi_v; + } + } + } +} + +static void compute_least_squares_endpoints_rgb(uint32_t N, const uint8_t *pSelectors, const vec4F *pSelector_weights, vec4F *pXl, vec4F *pXh, const color_rgba*pColors) +{ + float z00 = 0.0f, z01 = 0.0f, z10 = 0.0f, z11 = 0.0f; + float q00_r = 0.0f, q10_r = 0.0f, t_r = 0.0f; + float q00_g = 0.0f, q10_g = 0.0f, t_g = 0.0f; + float q00_b = 0.0f, q10_b = 0.0f, t_b = 0.0f; + for (uint32_t i = 0; i < N; i++) + { + const uint32_t sel = pSelectors[i]; + z00 += pSelector_weights[sel].m_c[0]; + z10 += pSelector_weights[sel].m_c[1]; + z11 += pSelector_weights[sel].m_c[2]; + float w = pSelector_weights[sel].m_c[3]; + q00_r += w * pColors[i].m_c[0]; t_r += pColors[i].m_c[0]; + q00_g += w * pColors[i].m_c[1]; t_g += pColors[i].m_c[1]; + q00_b += w * pColors[i].m_c[2]; t_b += pColors[i].m_c[2]; + } + + q10_r = t_r - q00_r; + q10_g = t_g - q00_g; + q10_b = t_b - q00_b; + + z01 = z10; + + float det = z00 * z11 - z01 * z10; + if (det != 0.0f) + det = 1.0f / det; + + float iz00, iz01, iz10, iz11; + iz00 = z11 * det; + iz01 = -z01 * det; + iz10 = -z10 * det; + iz11 = z00 * det; + + pXl->m_c[0] = (float)(iz00 * q00_r + iz01 * q10_r); pXh->m_c[0] = (float)(iz10 * q00_r + iz11 * q10_r); + pXl->m_c[1] = (float)(iz00 * q00_g + iz01 * q10_g); pXh->m_c[1] = (float)(iz10 * q00_g + iz11 * q10_g); + pXl->m_c[2] = (float)(iz00 * q00_b + iz01 * q10_b); pXh->m_c[2] = (float)(iz10 * q00_b + iz11 * q10_b); + pXl->m_c[3] = 255.0f; pXh->m_c[3] = 255.0f; + + for (uint32_t c = 0; c < 3; c++) + { + if ((pXl->m_c[c] < 0.0f) || (pXh->m_c[c] > 255.0f)) + { + uint32_t lo_v = UINT32_MAX, hi_v = 0; + for (uint32_t i = 0; i < N; i++) + { + lo_v = minimumu(lo_v, pColors[i].m_c[c]); + hi_v = maximumu(hi_v, pColors[i].m_c[c]); + } + + if (lo_v == hi_v) + { + pXl->m_c[c] = (float)lo_v; + pXh->m_c[c] = (float)hi_v; + } + } + } +} + +static void compute_least_squares_endpoints_a(uint32_t N, const uint8_t* pSelectors, const vec4F* pSelector_weights, float* pXl, float* pXh, const color_rgba *pColors) +{ + // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf + // I did this in matrix form first, expanded out all the ops, then optimized it a bit. + float z00 = 0.0f, z01 = 0.0f, z10 = 0.0f, z11 = 0.0f; + float q00_a = 0.0f, q10_a = 0.0f, t_a = 0.0f; + for (uint32_t i = 0; i < N; i++) + { + const uint32_t sel = pSelectors[i]; + + z00 += pSelector_weights[sel].m_c[0]; + z10 += pSelector_weights[sel].m_c[1]; + z11 += pSelector_weights[sel].m_c[2]; + + float w = pSelector_weights[sel].m_c[3]; + + q00_a += w * pColors[i].m_c[3]; t_a += pColors[i].m_c[3]; + } + + q10_a = t_a - q00_a; + + z01 = z10; + + float det = z00 * z11 - z01 * z10; + if (det != 0.0f) + det = 1.0f / det; + + float iz00, iz01, iz10, iz11; + iz00 = z11 * det; + iz01 = -z01 * det; + iz10 = -z10 * det; + iz11 = z00 * det; + + *pXl = (float)(iz00 * q00_a + iz01 * q10_a); *pXh = (float)(iz10 * q00_a + iz11 * q10_a); + + if ((*pXl < 0.0f) || (*pXh > 255.0f)) + { + uint32_t lo_v = UINT32_MAX, hi_v = 0; + for (uint32_t i = 0; i < N; i++) + { + lo_v = minimumu(lo_v, pColors[i].m_c[3]); + hi_v = maximumu(hi_v, pColors[i].m_c[3]); + } + + if (lo_v == hi_v) + { + *pXl = (float)lo_v; + *pXh = (float)hi_v; + } + } +} + +struct color_cell_compressor_params +{ + uint32_t m_num_pixels; + const color_rgba *m_pPixels; + uint32_t m_num_selector_weights; + const uint32_t *m_pSelector_weights; + const vec4F *m_pSelector_weightsx; + uint32_t m_comp_bits; + uint32_t m_weights[4]; + bool m_has_alpha; + bool m_has_pbits; + bool m_endpoints_share_pbit; + bool m_perceptual; +}; + +struct color_cell_compressor_results +{ + uint64_t m_best_overall_err; + color_rgba m_low_endpoint; + color_rgba m_high_endpoint; + uint32_t m_pbits[2]; + uint8_t *m_pSelectors; + uint8_t *m_pSelectors_temp; +}; + +static inline color_rgba scale_color(const color_rgba *pC, const color_cell_compressor_params *pParams) +{ + color_rgba results; + + const uint32_t n = pParams->m_comp_bits + (pParams->m_has_pbits ? 1 : 0); + assert((n >= 4) && (n <= 8)); + + for (uint32_t i = 0; i < 4; i++) + { + uint32_t v = pC->m_c[i] << (8 - n); + v |= (v >> n); + assert(v <= 255); + results.m_c[i] = (uint8_t)(v); + } + + return results; +} + +static inline uint64_t compute_color_distance_rgb(const color_rgba *pE1, const color_rgba *pE2, bool perceptual, const uint32_t weights[4]) +{ + int dr, dg, db; + + if (perceptual) + { + const int l1 = pE1->m_c[0] * 109 + pE1->m_c[1] * 366 + pE1->m_c[2] * 37; + const int cr1 = ((int)pE1->m_c[0] << 9) - l1; + const int cb1 = ((int)pE1->m_c[2] << 9) - l1; + const int l2 = pE2->m_c[0] * 109 + pE2->m_c[1] * 366 + pE2->m_c[2] * 37; + const int cr2 = ((int)pE2->m_c[0] << 9) - l2; + const int cb2 = ((int)pE2->m_c[2] << 9) - l2; + dr = (l1 - l2) >> 8; + dg = (cr1 - cr2) >> 8; + db = (cb1 - cb2) >> 8; + } + else + { + dr = (int)pE1->m_c[0] - (int)pE2->m_c[0]; + dg = (int)pE1->m_c[1] - (int)pE2->m_c[1]; + db = (int)pE1->m_c[2] - (int)pE2->m_c[2]; + } + + return weights[0] * (uint32_t)(dr * dr) + weights[1] * (uint32_t)(dg * dg) + weights[2] * (uint32_t)(db * db); +} + +static inline uint64_t compute_color_distance_rgba(const color_rgba *pE1, const color_rgba *pE2, bool perceptual, const uint32_t weights[4]) +{ + int da = (int)pE1->m_c[3] - (int)pE2->m_c[3]; + return compute_color_distance_rgb(pE1, pE2, perceptual, weights) + (weights[3] * (uint32_t)(da * da)); +} + +static uint64_t pack_mode1_to_one_color(const color_cell_compressor_params *pParams, color_cell_compressor_results *pResults, uint32_t r, uint32_t g, uint32_t b, uint8_t *pSelectors) +{ + uint32_t best_err = UINT_MAX; + uint32_t best_p = 0; + + for (uint32_t p = 0; p < 2; p++) + { + uint32_t err = g_bc7_mode_1_optimal_endpoints[r][p].m_error + g_bc7_mode_1_optimal_endpoints[g][p].m_error + g_bc7_mode_1_optimal_endpoints[b][p].m_error; + if (err < best_err) + { + best_err = err; + best_p = p; + if (!best_err) + break; + } + } + + const endpoint_err *pEr = &g_bc7_mode_1_optimal_endpoints[r][best_p]; + const endpoint_err *pEg = &g_bc7_mode_1_optimal_endpoints[g][best_p]; + const endpoint_err *pEb = &g_bc7_mode_1_optimal_endpoints[b][best_p]; + + color_quad_u8_set(&pResults->m_low_endpoint, pEr->m_lo, pEg->m_lo, pEb->m_lo, 0); + color_quad_u8_set(&pResults->m_high_endpoint, pEr->m_hi, pEg->m_hi, pEb->m_hi, 0); + pResults->m_pbits[0] = best_p; + pResults->m_pbits[1] = 0; + + memset(pSelectors, BC7ENC_MODE_1_OPTIMAL_INDEX, pParams->m_num_pixels); + + color_rgba p; + for (uint32_t i = 0; i < 3; i++) + { + uint32_t low = ((pResults->m_low_endpoint.m_c[i] << 1) | pResults->m_pbits[0]) << 1; + low |= (low >> 7); + + uint32_t high = ((pResults->m_high_endpoint.m_c[i] << 1) | pResults->m_pbits[0]) << 1; + high |= (high >> 7); + + p.m_c[i] = (uint8_t)((low * (64 - g_bc7_weights3[BC7ENC_MODE_1_OPTIMAL_INDEX]) + high * g_bc7_weights3[BC7ENC_MODE_1_OPTIMAL_INDEX] + 32) >> 6); + } + p.m_c[3] = 255; + + uint64_t total_err = 0; + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + total_err += compute_color_distance_rgb(&p, &pParams->m_pPixels[i], pParams->m_perceptual, pParams->m_weights); + + pResults->m_best_overall_err = total_err; + + return total_err; +} + +static uint64_t pack_mode7_to_one_color(const color_cell_compressor_params* pParams, color_cell_compressor_results* pResults, uint32_t r, uint32_t g, uint32_t b, uint32_t a, + uint8_t* pSelectors, uint32_t num_pixels, const color_rgba *pPixels) +{ + uint32_t best_err = UINT_MAX; + uint32_t best_p = 0; + + for (uint32_t p = 0; p < 4; p++) + { + uint32_t hi_p = p >> 1; + uint32_t lo_p = p & 1; + uint32_t err = g_bc7_mode_7_optimal_endpoints[r][hi_p][lo_p].m_error + g_bc7_mode_7_optimal_endpoints[g][hi_p][lo_p].m_error + g_bc7_mode_7_optimal_endpoints[b][hi_p][lo_p].m_error + g_bc7_mode_7_optimal_endpoints[a][hi_p][lo_p].m_error; + if (err < best_err) + { + best_err = err; + best_p = p; + if (!best_err) + break; + } + } + + uint32_t best_hi_p = best_p >> 1; + uint32_t best_lo_p = best_p & 1; + + const endpoint_err* pEr = &g_bc7_mode_7_optimal_endpoints[r][best_hi_p][best_lo_p]; + const endpoint_err* pEg = &g_bc7_mode_7_optimal_endpoints[g][best_hi_p][best_lo_p]; + const endpoint_err* pEb = &g_bc7_mode_7_optimal_endpoints[b][best_hi_p][best_lo_p]; + const endpoint_err* pEa = &g_bc7_mode_7_optimal_endpoints[a][best_hi_p][best_lo_p]; + + color_quad_u8_set(&pResults->m_low_endpoint, pEr->m_lo, pEg->m_lo, pEb->m_lo, pEa->m_lo); + color_quad_u8_set(&pResults->m_high_endpoint, pEr->m_hi, pEg->m_hi, pEb->m_hi, pEa->m_hi); + pResults->m_pbits[0] = best_lo_p; + pResults->m_pbits[1] = best_hi_p; + + for (uint32_t i = 0; i < num_pixels; i++) + pSelectors[i] = (uint8_t)BC7E_MODE_7_OPTIMAL_INDEX; + + color_rgba p; + + for (uint32_t i = 0; i < 4; i++) + { + uint32_t low = (pResults->m_low_endpoint.m_c[i] << 1) | pResults->m_pbits[0]; + uint32_t high = (pResults->m_high_endpoint.m_c[i] << 1) | pResults->m_pbits[1]; + + low = (low << 2) | (low >> 6); + high = (high << 2) | (high >> 6); + + p.m_c[i] = (uint8_t)((low * (64 - g_bc7_weights2[BC7E_MODE_7_OPTIMAL_INDEX]) + high * g_bc7_weights2[BC7E_MODE_7_OPTIMAL_INDEX] + 32) >> 6); + } + + uint64_t total_err = 0; + for (uint32_t i = 0; i < num_pixels; i++) + total_err += compute_color_distance_rgba(&p, &pPixels[i], pParams->m_perceptual, pParams->m_weights); + + pResults->m_best_overall_err = total_err; + + return total_err; +} + +static uint64_t evaluate_solution(const color_rgba *pLow, const color_rgba *pHigh, const uint32_t pbits[2], const color_cell_compressor_params *pParams, color_cell_compressor_results *pResults, + const bc7enc_compress_block_params* pComp_params) +{ + color_rgba quantMinColor = *pLow; + color_rgba quantMaxColor = *pHigh; + + if (pParams->m_has_pbits) + { + uint32_t minPBit, maxPBit; + + if (pParams->m_endpoints_share_pbit) + maxPBit = minPBit = pbits[0]; + else + { + minPBit = pbits[0]; + maxPBit = pbits[1]; + } + + quantMinColor.m_c[0] = (uint8_t)((pLow->m_c[0] << 1) | minPBit); + quantMinColor.m_c[1] = (uint8_t)((pLow->m_c[1] << 1) | minPBit); + quantMinColor.m_c[2] = (uint8_t)((pLow->m_c[2] << 1) | minPBit); + quantMinColor.m_c[3] = (uint8_t)((pLow->m_c[3] << 1) | minPBit); + + quantMaxColor.m_c[0] = (uint8_t)((pHigh->m_c[0] << 1) | maxPBit); + quantMaxColor.m_c[1] = (uint8_t)((pHigh->m_c[1] << 1) | maxPBit); + quantMaxColor.m_c[2] = (uint8_t)((pHigh->m_c[2] << 1) | maxPBit); + quantMaxColor.m_c[3] = (uint8_t)((pHigh->m_c[3] << 1) | maxPBit); + } + + color_rgba actualMinColor = scale_color(&quantMinColor, pParams); + color_rgba actualMaxColor = scale_color(&quantMaxColor, pParams); + + const uint32_t N = pParams->m_num_selector_weights; + + color_rgba weightedColors[16]; + weightedColors[0] = actualMinColor; + weightedColors[N - 1] = actualMaxColor; + + const uint32_t nc = pParams->m_has_alpha ? 4 : 3; + for (uint32_t i = 1; i < (N - 1); i++) + for (uint32_t j = 0; j < nc; j++) + weightedColors[i].m_c[j] = (uint8_t)((actualMinColor.m_c[j] * (64 - pParams->m_pSelector_weights[i]) + actualMaxColor.m_c[j] * pParams->m_pSelector_weights[i] + 32) >> 6); + + const int lr = actualMinColor.m_c[0]; + const int lg = actualMinColor.m_c[1]; + const int lb = actualMinColor.m_c[2]; + const int dr = actualMaxColor.m_c[0] - lr; + const int dg = actualMaxColor.m_c[1] - lg; + const int db = actualMaxColor.m_c[2] - lb; + + uint64_t total_err = 0; + + if (pComp_params->m_force_selectors) + { + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + { + const uint32_t best_sel = pComp_params->m_selectors[i]; + + uint64_t best_err; + if (pParams->m_has_alpha) + best_err = compute_color_distance_rgba(&weightedColors[best_sel], &pParams->m_pPixels[i], pParams->m_perceptual, pParams->m_weights); + else + best_err = compute_color_distance_rgb(&weightedColors[best_sel], &pParams->m_pPixels[i], pParams->m_perceptual, pParams->m_weights); + + total_err += best_err; + + pResults->m_pSelectors_temp[i] = (uint8_t)best_sel; + } + } + else if (!pParams->m_perceptual) + { + if (pParams->m_has_alpha) + { + const int la = actualMinColor.m_c[3]; + const int da = actualMaxColor.m_c[3] - la; + + const float f = N / (float)(squarei(dr) + squarei(dg) + squarei(db) + squarei(da) + .00000125f); + + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + { + const color_rgba *pC = &pParams->m_pPixels[i]; + int r = pC->m_c[0]; + int g = pC->m_c[1]; + int b = pC->m_c[2]; + int a = pC->m_c[3]; + + int best_sel = (int)((float)((r - lr) * dr + (g - lg) * dg + (b - lb) * db + (a - la) * da) * f + .5f); + best_sel = clampi(best_sel, 1, N - 1); + + uint64_t err0 = compute_color_distance_rgba(&weightedColors[best_sel - 1], pC, false, pParams->m_weights); + uint64_t err1 = compute_color_distance_rgba(&weightedColors[best_sel], pC, false, pParams->m_weights); + + if (err1 > err0) + { + err1 = err0; + --best_sel; + } + total_err += err1; + + pResults->m_pSelectors_temp[i] = (uint8_t)best_sel; + } + } + else + { + const float f = N / (float)(squarei(dr) + squarei(dg) + squarei(db) + .00000125f); + + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + { + const color_rgba *pC = &pParams->m_pPixels[i]; + int r = pC->m_c[0]; + int g = pC->m_c[1]; + int b = pC->m_c[2]; + + int sel = (int)((float)((r - lr) * dr + (g - lg) * dg + (b - lb) * db) * f + .5f); + sel = clampi(sel, 1, N - 1); + + uint64_t err0 = compute_color_distance_rgb(&weightedColors[sel - 1], pC, false, pParams->m_weights); + uint64_t err1 = compute_color_distance_rgb(&weightedColors[sel], pC, false, pParams->m_weights); + + int best_sel = sel; + uint64_t best_err = err1; + if (err0 < best_err) + { + best_err = err0; + best_sel = sel - 1; + } + + total_err += best_err; + + pResults->m_pSelectors_temp[i] = (uint8_t)best_sel; + } + } + } + else + { + // TODO: This could be improved. + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + { + uint64_t best_err = UINT64_MAX; + uint32_t best_sel = 0; + + if (pParams->m_has_alpha) + { + for (uint32_t j = 0; j < N; j++) + { + uint64_t err = compute_color_distance_rgba(&weightedColors[j], &pParams->m_pPixels[i], true, pParams->m_weights); + if (err < best_err) + { + best_err = err; + best_sel = j; + } + } + } + else + { + for (uint32_t j = 0; j < N; j++) + { + uint64_t err = compute_color_distance_rgb(&weightedColors[j], &pParams->m_pPixels[i], true, pParams->m_weights); + if (err < best_err) + { + best_err = err; + best_sel = j; + } + } + } + + total_err += best_err; + + pResults->m_pSelectors_temp[i] = (uint8_t)best_sel; + } + } + + if (total_err < pResults->m_best_overall_err) + { + pResults->m_best_overall_err = total_err; + + pResults->m_low_endpoint = *pLow; + pResults->m_high_endpoint = *pHigh; + + pResults->m_pbits[0] = pbits[0]; + pResults->m_pbits[1] = pbits[1]; + + memcpy(pResults->m_pSelectors, pResults->m_pSelectors_temp, sizeof(pResults->m_pSelectors[0]) * pParams->m_num_pixels); + } + + return total_err; +} + +static void fixDegenerateEndpoints(uint32_t mode, color_rgba *pTrialMinColor, color_rgba *pTrialMaxColor, const vec4F *pXl, const vec4F *pXh, uint32_t iscale, + const bc7enc_compress_block_params* pComp_params) +{ + //if ((mode == 1) || (mode == 7)) + //if (mode == 1) + if ( (mode == 1) || ((mode == 6) && (pComp_params->m_quant_mode6_endpoints)) ) + { + // fix degenerate case where the input collapses to a single colorspace voxel, and we loose all freedom (test with grayscale ramps) + for (uint32_t i = 0; i < 3; i++) + { + if (pTrialMinColor->m_c[i] == pTrialMaxColor->m_c[i]) + { + if (fabs(pXl->m_c[i] - pXh->m_c[i]) > 0.0f) + { + if (pTrialMinColor->m_c[i] > (iscale >> 1)) + { + if (pTrialMinColor->m_c[i] > 0) + pTrialMinColor->m_c[i]--; + else + if (pTrialMaxColor->m_c[i] < iscale) + pTrialMaxColor->m_c[i]++; + } + else + { + if (pTrialMaxColor->m_c[i] < iscale) + pTrialMaxColor->m_c[i]++; + else if (pTrialMinColor->m_c[i] > 0) + pTrialMinColor->m_c[i]--; + } + } + } + } + } +} + +static uint64_t find_optimal_solution(uint32_t mode, vec4F xl, vec4F xh, const color_cell_compressor_params *pParams, color_cell_compressor_results *pResults, + const bc7enc_compress_block_params* pComp_params) +{ + vec4F_saturate_in_place(&xl); vec4F_saturate_in_place(&xh); + + if (pParams->m_has_pbits) + { + const int iscalep = (1 << (pParams->m_comp_bits + 1)) - 1; + const float scalep = (float)iscalep; + + const int32_t totalComps = pParams->m_has_alpha ? 4 : 3; + + uint32_t best_pbits[2]; + color_rgba bestMinColor, bestMaxColor; + + if (!pParams->m_endpoints_share_pbit) + { + if ((pParams->m_comp_bits == 7) && (pComp_params->m_quant_mode6_endpoints)) + { + best_pbits[0] = 0; + bestMinColor.m_c[0] = g_mode6_reduced_quant[(int)((xl.m_c[0] * 2047.0f) + .5f)][0]; + bestMinColor.m_c[1] = g_mode6_reduced_quant[(int)((xl.m_c[1] * 2047.0f) + .5f)][0]; + bestMinColor.m_c[2] = g_mode6_reduced_quant[(int)((xl.m_c[2] * 2047.0f) + .5f)][0]; + bestMinColor.m_c[3] = g_mode6_reduced_quant[(int)((xl.m_c[3] * 2047.0f) + .5f)][0]; + + best_pbits[1] = 1; + bestMaxColor.m_c[0] = g_mode6_reduced_quant[(int)((xh.m_c[0] * 2047.0f) + .5f)][1]; + bestMaxColor.m_c[1] = g_mode6_reduced_quant[(int)((xh.m_c[1] * 2047.0f) + .5f)][1]; + bestMaxColor.m_c[2] = g_mode6_reduced_quant[(int)((xh.m_c[2] * 2047.0f) + .5f)][1]; + bestMaxColor.m_c[3] = g_mode6_reduced_quant[(int)((xh.m_c[3] * 2047.0f) + .5f)][1]; + } + else + { + float best_err0 = 1e+9; + float best_err1 = 1e+9; + + for (int p = 0; p < 2; p++) + { + color_rgba xMinColor, xMaxColor; + + // Notes: The pbit controls which quantization intervals are selected. + // total_levels=2^(comp_bits+1), where comp_bits=4 for mode 0, etc. + // pbit 0: v=(b*2)/(total_levels-1), pbit 1: v=(b*2+1)/(total_levels-1) where b is the component bin from [0,total_levels/2-1] and v is the [0,1] component value + // rearranging you get for pbit 0: b=floor(v*(total_levels-1)/2+.5) + // rearranging you get for pbit 1: b=floor((v*(total_levels-1)-1)/2+.5) + if (pParams->m_comp_bits == 5) + { + for (uint32_t c = 0; c < 4; c++) + { + int vl = (int)(xl.m_c[c] * 31.0f); + vl += (xl.m_c[c] > g_mode7_rgba_midpoints[vl][p]); + xMinColor.m_c[c] = (uint8_t)clampi(vl * 2 + p, p, 63 - 1 + p); + + int vh = (int)(xh.m_c[c] * 31.0f); + vh += (xh.m_c[c] > g_mode7_rgba_midpoints[vh][p]); + xMaxColor.m_c[c] = (uint8_t)clampi(vh * 2 + p, p, 63 - 1 + p); + } + } + else + { + for (uint32_t c = 0; c < 4; c++) + { + xMinColor.m_c[c] = (uint8_t)(clampi(((int)((xl.m_c[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p)); + xMaxColor.m_c[c] = (uint8_t)(clampi(((int)((xh.m_c[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p)); + } + } + + color_rgba scaledLow = scale_color(&xMinColor, pParams); + color_rgba scaledHigh = scale_color(&xMaxColor, pParams); + + float err0 = 0, err1 = 0; + for (int i = 0; i < totalComps; i++) + { + err0 += squaref(scaledLow.m_c[i] - xl.m_c[i] * 255.0f); + err1 += squaref(scaledHigh.m_c[i] - xh.m_c[i] * 255.0f); + } + + if (p == 1) + { + err0 *= pComp_params->m_pbit1_weight; + err1 *= pComp_params->m_pbit1_weight; + } + + if (err0 < best_err0) + { + best_err0 = err0; + best_pbits[0] = p; + + bestMinColor.m_c[0] = xMinColor.m_c[0] >> 1; + bestMinColor.m_c[1] = xMinColor.m_c[1] >> 1; + bestMinColor.m_c[2] = xMinColor.m_c[2] >> 1; + bestMinColor.m_c[3] = xMinColor.m_c[3] >> 1; + } + + if (err1 < best_err1) + { + best_err1 = err1; + best_pbits[1] = p; + + bestMaxColor.m_c[0] = xMaxColor.m_c[0] >> 1; + bestMaxColor.m_c[1] = xMaxColor.m_c[1] >> 1; + bestMaxColor.m_c[2] = xMaxColor.m_c[2] >> 1; + bestMaxColor.m_c[3] = xMaxColor.m_c[3] >> 1; + } + } + } + } + else + { + if ((mode == 1) && (pComp_params->m_bias_mode1_pbits)) + { + float x = 0.0f; + for (uint32_t c = 0; c < 3; c++) + x = std::max(std::max(x, xl.m_c[c]), xh.m_c[c]); + + int p = 0; + if (x > (253.0f / 255.0f)) + p = 1; + + color_rgba xMinColor, xMaxColor; + for (uint32_t c = 0; c < 4; c++) + { + int vl = (int)(xl.m_c[c] * 63.0f); + vl += (xl.m_c[c] > g_mode1_rgba_midpoints[vl][p]); + xMinColor.m_c[c] = (uint8_t)clampi(vl * 2 + p, p, 127 - 1 + p); + + int vh = (int)(xh.m_c[c] * 63.0f); + vh += (xh.m_c[c] > g_mode1_rgba_midpoints[vh][p]); + xMaxColor.m_c[c] = (uint8_t)clampi(vh * 2 + p, p, 127 - 1 + p); + } + + best_pbits[0] = p; + best_pbits[1] = p; + for (uint32_t j = 0; j < 4; j++) + { + bestMinColor.m_c[j] = xMinColor.m_c[j] >> 1; + bestMaxColor.m_c[j] = xMaxColor.m_c[j] >> 1; + } + } + else + { + // Endpoints share pbits + float best_err = 1e+9; + + for (int p = 0; p < 2; p++) + { + color_rgba xMinColor, xMaxColor; + if (pParams->m_comp_bits == 6) + { + for (uint32_t c = 0; c < 4; c++) + { + int vl = (int)(xl.m_c[c] * 63.0f); + vl += (xl.m_c[c] > g_mode1_rgba_midpoints[vl][p]); + xMinColor.m_c[c] = (uint8_t)clampi(vl * 2 + p, p, 127 - 1 + p); + + int vh = (int)(xh.m_c[c] * 63.0f); + vh += (xh.m_c[c] > g_mode1_rgba_midpoints[vh][p]); + xMaxColor.m_c[c] = (uint8_t)clampi(vh * 2 + p, p, 127 - 1 + p); + } + } + else + { + for (uint32_t c = 0; c < 4; c++) + { + xMinColor.m_c[c] = (uint8_t)(clampi(((int)((xl.m_c[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p)); + xMaxColor.m_c[c] = (uint8_t)(clampi(((int)((xh.m_c[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p)); + } + } + + color_rgba scaledLow = scale_color(&xMinColor, pParams); + color_rgba scaledHigh = scale_color(&xMaxColor, pParams); + + float err = 0; + for (int i = 0; i < totalComps; i++) + err += squaref((scaledLow.m_c[i] / 255.0f) - xl.m_c[i]) + squaref((scaledHigh.m_c[i] / 255.0f) - xh.m_c[i]); + + if (p == 1) + err *= pComp_params->m_pbit1_weight; + + if (err < best_err) + { + best_err = err; + best_pbits[0] = p; + best_pbits[1] = p; + for (uint32_t j = 0; j < 4; j++) + { + bestMinColor.m_c[j] = xMinColor.m_c[j] >> 1; + bestMaxColor.m_c[j] = xMaxColor.m_c[j] >> 1; + } + } + } + } + } + + fixDegenerateEndpoints(mode, &bestMinColor, &bestMaxColor, &xl, &xh, iscalep >> 1, pComp_params); + + if ((pResults->m_best_overall_err == UINT64_MAX) || color_quad_u8_notequals(&bestMinColor, &pResults->m_low_endpoint) || color_quad_u8_notequals(&bestMaxColor, &pResults->m_high_endpoint) || (best_pbits[0] != pResults->m_pbits[0]) || (best_pbits[1] != pResults->m_pbits[1])) + evaluate_solution(&bestMinColor, &bestMaxColor, best_pbits, pParams, pResults, pComp_params); + } + else + { + const int iscale = (1 << pParams->m_comp_bits) - 1; + const float scale = (float)iscale; + + color_rgba trialMinColor, trialMaxColor; + if (pParams->m_comp_bits == 7) + { + for (uint32_t c = 0; c < 4; c++) + { + int vl = (int)(xl.m_c[c] * 127.0f); + vl += (xl.m_c[c] > g_mode5_rgba_midpoints[vl]); + trialMinColor.m_c[c] = (uint8_t)clampi(vl, 0, 127); + + int vh = (int)(xh.m_c[c] * 127.0f); + vh += (xh.m_c[c] > g_mode5_rgba_midpoints[vh]); + trialMaxColor.m_c[c] = (uint8_t)clampi(vh, 0, 127); + } + } + else + { + color_quad_u8_set_clamped(&trialMinColor, (int)(xl.m_c[0] * scale + .5f), (int)(xl.m_c[1] * scale + .5f), (int)(xl.m_c[2] * scale + .5f), (int)(xl.m_c[3] * scale + .5f)); + color_quad_u8_set_clamped(&trialMaxColor, (int)(xh.m_c[0] * scale + .5f), (int)(xh.m_c[1] * scale + .5f), (int)(xh.m_c[2] * scale + .5f), (int)(xh.m_c[3] * scale + .5f)); + } + + fixDegenerateEndpoints(mode, &trialMinColor, &trialMaxColor, &xl, &xh, iscale, pComp_params); + + if ((pResults->m_best_overall_err == UINT64_MAX) || color_quad_u8_notequals(&trialMinColor, &pResults->m_low_endpoint) || color_quad_u8_notequals(&trialMaxColor, &pResults->m_high_endpoint)) + evaluate_solution(&trialMinColor, &trialMaxColor, pResults->m_pbits, pParams, pResults, pComp_params); + } + + return pResults->m_best_overall_err; +} + +static uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_params *pParams, color_cell_compressor_results *pResults, const bc7enc_compress_block_params *pComp_params) +{ + assert((mode == 6) || (mode == 7) || (!pParams->m_has_alpha)); + + pResults->m_best_overall_err = UINT64_MAX; + + // If the partition's colors are all the same in mode 1, then just pack them as a single color. + if (mode == 1) + { + const uint32_t cr = pParams->m_pPixels[0].m_c[0], cg = pParams->m_pPixels[0].m_c[1], cb = pParams->m_pPixels[0].m_c[2]; + + bool allSame = true; + for (uint32_t i = 1; i < pParams->m_num_pixels; i++) + { + if ((cr != pParams->m_pPixels[i].m_c[0]) || (cg != pParams->m_pPixels[i].m_c[1]) || (cb != pParams->m_pPixels[i].m_c[2])) + { + allSame = false; + break; + } + } + + if (allSame) + return pack_mode1_to_one_color(pParams, pResults, cr, cg, cb, pResults->m_pSelectors); + } + else if (mode == 7) + { + const uint32_t cr = pParams->m_pPixels[0].m_c[0], cg = pParams->m_pPixels[0].m_c[1], cb = pParams->m_pPixels[0].m_c[2], ca = pParams->m_pPixels[0].m_c[3]; + + bool allSame = true; + for (uint32_t i = 1; i < pParams->m_num_pixels; i++) + { + if ((cr != pParams->m_pPixels[i].m_c[0]) || (cg != pParams->m_pPixels[i].m_c[1]) || (cb != pParams->m_pPixels[i].m_c[2]) || (ca != pParams->m_pPixels[i].m_c[3])) + { + allSame = false; + break; + } + } + + if (allSame) + return pack_mode7_to_one_color(pParams, pResults, cr, cg, cb, ca, pResults->m_pSelectors, pParams->m_num_pixels, pParams->m_pPixels); + } + + // Compute partition's mean color and principle axis. + vec4F meanColor, axis; + vec4F_set_scalar(&meanColor, 0.0f); + + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + { + vec4F color = vec4F_from_color(&pParams->m_pPixels[i]); + meanColor = vec4F_add(&meanColor, &color); + } + + vec4F meanColorScaled = vec4F_mul(&meanColor, 1.0f / (float)(pParams->m_num_pixels)); + + meanColor = vec4F_mul(&meanColor, 1.0f / (float)(pParams->m_num_pixels * 255.0f)); + vec4F_saturate_in_place(&meanColor); + + if (pParams->m_has_alpha) + { + // Use incremental PCA for RGBA PCA, because it's simple. + vec4F_set_scalar(&axis, 0.0f); + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + { + vec4F color = vec4F_from_color(&pParams->m_pPixels[i]); + color = vec4F_sub(&color, &meanColorScaled); + vec4F a = vec4F_mul(&color, color.m_c[0]); + vec4F b = vec4F_mul(&color, color.m_c[1]); + vec4F c = vec4F_mul(&color, color.m_c[2]); + vec4F d = vec4F_mul(&color, color.m_c[3]); + vec4F n = i ? axis : color; + vec4F_normalize_in_place(&n); + axis.m_c[0] += vec4F_dot(&a, &n); + axis.m_c[1] += vec4F_dot(&b, &n); + axis.m_c[2] += vec4F_dot(&c, &n); + axis.m_c[3] += vec4F_dot(&d, &n); + } + vec4F_normalize_in_place(&axis); + } + else + { + // Use covar technique for RGB PCA, because it doesn't require per-pixel normalization. + float cov[6] = { 0, 0, 0, 0, 0, 0 }; + + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + { + const color_rgba *pV = &pParams->m_pPixels[i]; + float r = pV->m_c[0] - meanColorScaled.m_c[0]; + float g = pV->m_c[1] - meanColorScaled.m_c[1]; + float b = pV->m_c[2] - meanColorScaled.m_c[2]; + cov[0] += r*r; cov[1] += r*g; cov[2] += r*b; cov[3] += g*g; cov[4] += g*b; cov[5] += b*b; + } + + float vfr = .9f, vfg = 1.0f, vfb = .7f; + for (uint32_t iter = 0; iter < 3; iter++) + { + float r = vfr*cov[0] + vfg*cov[1] + vfb*cov[2]; + float g = vfr*cov[1] + vfg*cov[3] + vfb*cov[4]; + float b = vfr*cov[2] + vfg*cov[4] + vfb*cov[5]; + + float m = maximumf(maximumf(fabsf(r), fabsf(g)), fabsf(b)); + if (m > 1e-10f) + { + m = 1.0f / m; + r *= m; g *= m; b *= m; + } + + vfr = r; vfg = g; vfb = b; + } + + float len = vfr*vfr + vfg*vfg + vfb*vfb; + if (len < 1e-10f) + vec4F_set_scalar(&axis, 0.0f); + else + { + len = 1.0f / sqrtf(len); + vfr *= len; vfg *= len; vfb *= len; + vec4F_set(&axis, vfr, vfg, vfb, 0); + } + } + + // TODO: Try picking the 2 colors with the largest projection onto the axis, instead of computing new colors along the axis. + + if (vec4F_dot(&axis, &axis) < .5f) + { + if (pParams->m_perceptual) + vec4F_set(&axis, .213f, .715f, .072f, pParams->m_has_alpha ? .715f : 0); + else + vec4F_set(&axis, 1.0f, 1.0f, 1.0f, pParams->m_has_alpha ? 1.0f : 0); + vec4F_normalize_in_place(&axis); + } + + float l = 1e+9f, h = -1e+9f; + + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + { + vec4F color = vec4F_from_color(&pParams->m_pPixels[i]); + + vec4F q = vec4F_sub(&color, &meanColorScaled); + float d = vec4F_dot(&q, &axis); + + l = minimumf(l, d); + h = maximumf(h, d); + } + + l *= (1.0f / 255.0f); + h *= (1.0f / 255.0f); + + vec4F b0 = vec4F_mul(&axis, l); + vec4F b1 = vec4F_mul(&axis, h); + vec4F c0 = vec4F_add(&meanColor, &b0); + vec4F c1 = vec4F_add(&meanColor, &b1); + vec4F minColor = vec4F_saturate(&c0); + vec4F maxColor = vec4F_saturate(&c1); + + vec4F whiteVec; + vec4F_set_scalar(&whiteVec, 1.0f); + + if (vec4F_dot(&minColor, &whiteVec) > vec4F_dot(&maxColor, &whiteVec)) + { +#if 0 + // Don't compile correctly with VC 2019 in release. + vec4F temp = minColor; + minColor = maxColor; + maxColor = temp; +#else + float a = minColor.m_c[0], b = minColor.m_c[1], c = minColor.m_c[2], d = minColor.m_c[3]; + minColor.m_c[0] = maxColor.m_c[0]; + minColor.m_c[1] = maxColor.m_c[1]; + minColor.m_c[2] = maxColor.m_c[2]; + minColor.m_c[3] = maxColor.m_c[3]; + maxColor.m_c[0] = a; + maxColor.m_c[1] = b; + maxColor.m_c[2] = c; + maxColor.m_c[3] = d; +#endif + } + + // First find a solution using the block's PCA. + if (!find_optimal_solution(mode, minColor, maxColor, pParams, pResults, pComp_params)) + return 0; + + if (pComp_params->m_try_least_squares) + { + // Now try to refine the solution using least squares by computing the optimal endpoints from the current selectors. + vec4F xl, xh; + vec4F_set_scalar(&xl, 0.0f); + vec4F_set_scalar(&xh, 0.0f); + if (pParams->m_has_alpha) + compute_least_squares_endpoints_rgba(pParams->m_num_pixels, pResults->m_pSelectors, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels); + else + compute_least_squares_endpoints_rgb(pParams->m_num_pixels, pResults->m_pSelectors, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels); + + xl = vec4F_mul(&xl, (1.0f / 255.0f)); + xh = vec4F_mul(&xh, (1.0f / 255.0f)); + + if (!find_optimal_solution(mode, xl, xh, pParams, pResults, pComp_params)) + return 0; + } + + if (pComp_params->m_uber_level > 0) + { + // In uber level 1, try varying the selectors a little, somewhat like cluster fit would. First try incrementing the minimum selectors, + // then try decrementing the selectrors, then try both. + uint8_t selectors_temp[16], selectors_temp1[16]; + memcpy(selectors_temp, pResults->m_pSelectors, pParams->m_num_pixels); + + const int max_selector = pParams->m_num_selector_weights - 1; + + uint32_t min_sel = 16; + uint32_t max_sel = 0; + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + { + uint32_t sel = selectors_temp[i]; + min_sel = minimumu(min_sel, sel); + max_sel = maximumu(max_sel, sel); + } + + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + { + uint32_t sel = selectors_temp[i]; + if ((sel == min_sel) && (sel < (pParams->m_num_selector_weights - 1))) + sel++; + selectors_temp1[i] = (uint8_t)sel; + } + + vec4F xl, xh; + vec4F_set_scalar(&xl, 0.0f); + vec4F_set_scalar(&xh, 0.0f); + if (pParams->m_has_alpha) + compute_least_squares_endpoints_rgba(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels); + else + compute_least_squares_endpoints_rgb(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels); + + xl = vec4F_mul(&xl, (1.0f / 255.0f)); + xh = vec4F_mul(&xh, (1.0f / 255.0f)); + + if (!find_optimal_solution(mode, xl, xh, pParams, pResults, pComp_params)) + return 0; + + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + { + uint32_t sel = selectors_temp[i]; + if ((sel == max_sel) && (sel > 0)) + sel--; + selectors_temp1[i] = (uint8_t)sel; + } + + if (pParams->m_has_alpha) + compute_least_squares_endpoints_rgba(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels); + else + compute_least_squares_endpoints_rgb(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels); + + xl = vec4F_mul(&xl, (1.0f / 255.0f)); + xh = vec4F_mul(&xh, (1.0f / 255.0f)); + + if (!find_optimal_solution(mode, xl, xh, pParams, pResults, pComp_params)) + return 0; + + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + { + uint32_t sel = selectors_temp[i]; + if ((sel == min_sel) && (sel < (pParams->m_num_selector_weights - 1))) + sel++; + else if ((sel == max_sel) && (sel > 0)) + sel--; + selectors_temp1[i] = (uint8_t)sel; + } + + if (pParams->m_has_alpha) + compute_least_squares_endpoints_rgba(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels); + else + compute_least_squares_endpoints_rgb(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels); + + xl = vec4F_mul(&xl, (1.0f / 255.0f)); + xh = vec4F_mul(&xh, (1.0f / 255.0f)); + + if (!find_optimal_solution(mode, xl, xh, pParams, pResults, pComp_params)) + return 0; + + // In uber levels 2+, try taking more advantage of endpoint extrapolation by scaling the selectors in one direction or another. + const uint32_t uber_err_thresh = (pParams->m_num_pixels * 56) >> 4; + if ((pComp_params->m_uber_level >= 2) && (pResults->m_best_overall_err > uber_err_thresh)) + { + const int Q = (pComp_params->m_uber_level >= 4) ? (pComp_params->m_uber_level - 2) : 1; + for (int ly = -Q; ly <= 1; ly++) + { + for (int hy = max_selector - 1; hy <= (max_selector + Q); hy++) + { + if ((ly == 0) && (hy == max_selector)) + continue; + + for (uint32_t i = 0; i < pParams->m_num_pixels; i++) + selectors_temp1[i] = (uint8_t)clampf(floorf((float)max_selector * ((float)selectors_temp[i] - (float)ly) / ((float)hy - (float)ly) + .5f), 0, (float)max_selector); + + //vec4F xl, xh; + vec4F_set_scalar(&xl, 0.0f); + vec4F_set_scalar(&xh, 0.0f); + if (pParams->m_has_alpha) + compute_least_squares_endpoints_rgba(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels); + else + compute_least_squares_endpoints_rgb(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels); + + xl = vec4F_mul(&xl, (1.0f / 255.0f)); + xh = vec4F_mul(&xh, (1.0f / 255.0f)); + + if (!find_optimal_solution(mode, xl, xh, pParams, pResults, pComp_params)) + return 0; + } + } + } + } + + if (mode == 1) + { + // Try encoding the partition as a single color by using the optimal singe colors tables to encode the block to its mean. + color_cell_compressor_results avg_results = *pResults; + const uint32_t r = (int)(.5f + meanColor.m_c[0] * 255.0f), g = (int)(.5f + meanColor.m_c[1] * 255.0f), b = (int)(.5f + meanColor.m_c[2] * 255.0f); + uint64_t avg_err = pack_mode1_to_one_color(pParams, &avg_results, r, g, b, pResults->m_pSelectors_temp); + if (avg_err < pResults->m_best_overall_err) + { + *pResults = avg_results; + memcpy(pResults->m_pSelectors, pResults->m_pSelectors_temp, sizeof(pResults->m_pSelectors[0]) * pParams->m_num_pixels); + pResults->m_best_overall_err = avg_err; + } + } + else if (mode == 7) + { + // Try encoding the partition as a single color by using the optimal singe colors tables to encode the block to its mean. + color_cell_compressor_results avg_results = *pResults; + const uint32_t r = (int)(.5f + meanColor.m_c[0] * 255.0f), g = (int)(.5f + meanColor.m_c[1] * 255.0f), b = (int)(.5f + meanColor.m_c[2] * 255.0f), a = (int)(.5f + meanColor.m_c[3] * 255.0f); + uint64_t avg_err = pack_mode7_to_one_color(pParams, &avg_results, r, g, b, a, pResults->m_pSelectors_temp, pParams->m_num_pixels, pParams->m_pPixels); + if (avg_err < pResults->m_best_overall_err) + { + *pResults = avg_results; + memcpy(pResults->m_pSelectors, pResults->m_pSelectors_temp, sizeof(pResults->m_pSelectors[0]) * pParams->m_num_pixels); + pResults->m_best_overall_err = avg_err; + } + } + + return pResults->m_best_overall_err; +} + +static uint64_t color_cell_compression_est_mode1(uint32_t num_pixels, const color_rgba *pPixels, bool perceptual, uint32_t pweights[4], uint64_t best_err_so_far) +{ + // Find RGB bounds as an approximation of the block's principle axis + uint32_t lr = 255, lg = 255, lb = 255; + uint32_t hr = 0, hg = 0, hb = 0; + for (uint32_t i = 0; i < num_pixels; i++) + { + const color_rgba *pC = &pPixels[i]; + if (pC->m_c[0] < lr) lr = pC->m_c[0]; + if (pC->m_c[1] < lg) lg = pC->m_c[1]; + if (pC->m_c[2] < lb) lb = pC->m_c[2]; + if (pC->m_c[0] > hr) hr = pC->m_c[0]; + if (pC->m_c[1] > hg) hg = pC->m_c[1]; + if (pC->m_c[2] > hb) hb = pC->m_c[2]; + } + + color_rgba lowColor; color_quad_u8_set(&lowColor, lr, lg, lb, 0); + color_rgba highColor; color_quad_u8_set(&highColor, hr, hg, hb, 0); + + // Place endpoints at bbox diagonals and compute interpolated colors + const uint32_t N = 8; + color_rgba weightedColors[8]; + + weightedColors[0] = lowColor; + weightedColors[N - 1] = highColor; + for (uint32_t i = 1; i < (N - 1); i++) + { + weightedColors[i].m_c[0] = (uint8_t)((lowColor.m_c[0] * (64 - g_bc7_weights3[i]) + highColor.m_c[0] * g_bc7_weights3[i] + 32) >> 6); + weightedColors[i].m_c[1] = (uint8_t)((lowColor.m_c[1] * (64 - g_bc7_weights3[i]) + highColor.m_c[1] * g_bc7_weights3[i] + 32) >> 6); + weightedColors[i].m_c[2] = (uint8_t)((lowColor.m_c[2] * (64 - g_bc7_weights3[i]) + highColor.m_c[2] * g_bc7_weights3[i] + 32) >> 6); + } + + // Compute dots and thresholds + const int ar = highColor.m_c[0] - lowColor.m_c[0]; + const int ag = highColor.m_c[1] - lowColor.m_c[1]; + const int ab = highColor.m_c[2] - lowColor.m_c[2]; + + int dots[8]; + for (uint32_t i = 0; i < N; i++) + dots[i] = weightedColors[i].m_c[0] * ar + weightedColors[i].m_c[1] * ag + weightedColors[i].m_c[2] * ab; + + int thresh[8 - 1]; + for (uint32_t i = 0; i < (N - 1); i++) + thresh[i] = (dots[i] + dots[i + 1] + 1) >> 1; + + uint64_t total_err = 0; + if (perceptual) + { + // Transform block's interpolated colors to YCbCr + int l1[8], cr1[8], cb1[8]; + for (int j = 0; j < 8; j++) + { + const color_rgba *pE1 = &weightedColors[j]; + l1[j] = pE1->m_c[0] * 109 + pE1->m_c[1] * 366 + pE1->m_c[2] * 37; + cr1[j] = ((int)pE1->m_c[0] << 9) - l1[j]; + cb1[j] = ((int)pE1->m_c[2] << 9) - l1[j]; + } + + for (uint32_t i = 0; i < num_pixels; i++) + { + const color_rgba *pC = &pPixels[i]; + + int d = ar * pC->m_c[0] + ag * pC->m_c[1] + ab * pC->m_c[2]; + + // Find approximate selector + uint32_t s = 0; + if (d >= thresh[6]) + s = 7; + else if (d >= thresh[5]) + s = 6; + else if (d >= thresh[4]) + s = 5; + else if (d >= thresh[3]) + s = 4; + else if (d >= thresh[2]) + s = 3; + else if (d >= thresh[1]) + s = 2; + else if (d >= thresh[0]) + s = 1; + + // Compute error + const int l2 = pC->m_c[0] * 109 + pC->m_c[1] * 366 + pC->m_c[2] * 37; + const int cr2 = ((int)pC->m_c[0] << 9) - l2; + const int cb2 = ((int)pC->m_c[2] << 9) - l2; + + const int dl = (l1[s] - l2) >> 8; + const int dcr = (cr1[s] - cr2) >> 8; + const int dcb = (cb1[s] - cb2) >> 8; + + int ie = (pweights[0] * dl * dl) + (pweights[1] * dcr * dcr) + (pweights[2] * dcb * dcb); + + total_err += ie; + if (total_err > best_err_so_far) + break; + } + } + else + { + for (uint32_t i = 0; i < num_pixels; i++) + { + const color_rgba *pC = &pPixels[i]; + + int d = ar * pC->m_c[0] + ag * pC->m_c[1] + ab * pC->m_c[2]; + + // Find approximate selector + uint32_t s = 0; + if (d >= thresh[6]) + s = 7; + else if (d >= thresh[5]) + s = 6; + else if (d >= thresh[4]) + s = 5; + else if (d >= thresh[3]) + s = 4; + else if (d >= thresh[2]) + s = 3; + else if (d >= thresh[1]) + s = 2; + else if (d >= thresh[0]) + s = 1; + + // Compute error + const color_rgba *pE1 = &weightedColors[s]; + + int dr = (int)pE1->m_c[0] - (int)pC->m_c[0]; + int dg = (int)pE1->m_c[1] - (int)pC->m_c[1]; + int db = (int)pE1->m_c[2] - (int)pC->m_c[2]; + + total_err += pweights[0] * (dr * dr) + pweights[1] * (dg * dg) + pweights[2] * (db * db); + if (total_err > best_err_so_far) + break; + } + } + + return total_err; +} + +static uint64_t color_cell_compression_est_mode7(uint32_t num_pixels, const color_rgba * pPixels, bool perceptual, uint32_t pweights[4], uint64_t best_err_so_far) +{ + // Find RGB bounds as an approximation of the block's principle axis + uint32_t lr = 255, lg = 255, lb = 255, la = 255; + uint32_t hr = 0, hg = 0, hb = 0, ha = 0; + for (uint32_t i = 0; i < num_pixels; i++) + { + const color_rgba* pC = &pPixels[i]; + if (pC->m_c[0] < lr) lr = pC->m_c[0]; + if (pC->m_c[1] < lg) lg = pC->m_c[1]; + if (pC->m_c[2] < lb) lb = pC->m_c[2]; + if (pC->m_c[3] < la) la = pC->m_c[3]; + + if (pC->m_c[0] > hr) hr = pC->m_c[0]; + if (pC->m_c[1] > hg) hg = pC->m_c[1]; + if (pC->m_c[2] > hb) hb = pC->m_c[2]; + if (pC->m_c[3] > ha) ha = pC->m_c[3]; + } + + color_rgba lowColor; color_quad_u8_set(&lowColor, lr, lg, lb, la); + color_rgba highColor; color_quad_u8_set(&highColor, hr, hg, hb, ha); + + // Place endpoints at bbox diagonals and compute interpolated colors + const uint32_t N = 4; + color_rgba weightedColors[4]; + + weightedColors[0] = lowColor; + weightedColors[N - 1] = highColor; + for (uint32_t i = 1; i < (N - 1); i++) + { + weightedColors[i].m_c[0] = (uint8_t)((lowColor.m_c[0] * (64 - g_bc7_weights2[i]) + highColor.m_c[0] * g_bc7_weights2[i] + 32) >> 6); + weightedColors[i].m_c[1] = (uint8_t)((lowColor.m_c[1] * (64 - g_bc7_weights2[i]) + highColor.m_c[1] * g_bc7_weights2[i] + 32) >> 6); + weightedColors[i].m_c[2] = (uint8_t)((lowColor.m_c[2] * (64 - g_bc7_weights2[i]) + highColor.m_c[2] * g_bc7_weights2[i] + 32) >> 6); + weightedColors[i].m_c[3] = (uint8_t)((lowColor.m_c[3] * (64 - g_bc7_weights2[i]) + highColor.m_c[3] * g_bc7_weights2[i] + 32) >> 6); + } + + // Compute dots and thresholds + const int ar = highColor.m_c[0] - lowColor.m_c[0]; + const int ag = highColor.m_c[1] - lowColor.m_c[1]; + const int ab = highColor.m_c[2] - lowColor.m_c[2]; + const int aa = highColor.m_c[3] - lowColor.m_c[3]; + + int dots[4]; + for (uint32_t i = 0; i < N; i++) + dots[i] = weightedColors[i].m_c[0] * ar + weightedColors[i].m_c[1] * ag + weightedColors[i].m_c[2] * ab + weightedColors[i].m_c[3] * aa; + + int thresh[4 - 1]; + for (uint32_t i = 0; i < (N - 1); i++) + thresh[i] = (dots[i] + dots[i + 1] + 1) >> 1; + + uint64_t total_err = 0; + if (perceptual) + { + // Transform block's interpolated colors to YCbCr + int l1[4], cr1[4], cb1[4]; + for (int j = 0; j < 4; j++) + { + const color_rgba* pE1 = &weightedColors[j]; + l1[j] = pE1->m_c[0] * 109 + pE1->m_c[1] * 366 + pE1->m_c[2] * 37; + cr1[j] = ((int)pE1->m_c[0] << 9) - l1[j]; + cb1[j] = ((int)pE1->m_c[2] << 9) - l1[j]; + } + + for (uint32_t i = 0; i < num_pixels; i++) + { + const color_rgba* pC = &pPixels[i]; + + int d = ar * pC->m_c[0] + ag * pC->m_c[1] + ab * pC->m_c[2] + aa * pC->m_c[3]; + + // Find approximate selector + uint32_t s = 0; + if (d >= thresh[2]) + s = 3; + else if (d >= thresh[1]) + s = 2; + else if (d >= thresh[0]) + s = 1; + + // Compute error + const int l2 = pC->m_c[0] * 109 + pC->m_c[1] * 366 + pC->m_c[2] * 37; + const int cr2 = ((int)pC->m_c[0] << 9) - l2; + const int cb2 = ((int)pC->m_c[2] << 9) - l2; + + const int dl = (l1[s] - l2) >> 8; + const int dcr = (cr1[s] - cr2) >> 8; + const int dcb = (cb1[s] - cb2) >> 8; + + const int dca = (int)pC->m_c[3] - (int)weightedColors[s].m_c[3]; + + int ie = (pweights[0] * dl * dl) + (pweights[1] * dcr * dcr) + (pweights[2] * dcb * dcb) + (pweights[3] * dca * dca); + + total_err += ie; + if (total_err > best_err_so_far) + break; + } + } + else + { + for (uint32_t i = 0; i < num_pixels; i++) + { + const color_rgba* pC = &pPixels[i]; + + int d = ar * pC->m_c[0] + ag * pC->m_c[1] + ab * pC->m_c[2] + aa * pC->m_c[3]; + + // Find approximate selector + uint32_t s = 0; + if (d >= thresh[2]) + s = 3; + else if (d >= thresh[1]) + s = 2; + else if (d >= thresh[0]) + s = 1; + + // Compute error + const color_rgba* pE1 = &weightedColors[s]; + + int dr = (int)pE1->m_c[0] - (int)pC->m_c[0]; + int dg = (int)pE1->m_c[1] - (int)pC->m_c[1]; + int db = (int)pE1->m_c[2] - (int)pC->m_c[2]; + int da = (int)pE1->m_c[3] - (int)pC->m_c[3]; + + total_err += pweights[0] * (dr * dr) + pweights[1] * (dg * dg) + pweights[2] * (db * db) + pweights[3] * (da * da); + if (total_err > best_err_so_far) + break; + } + } + + return total_err; +} + +// This table contains bitmasks indicating which "key" partitions must be best ranked before this partition is worth evaluating. +// We first rank the best/most used 14 partitions (sorted by usefulness), record the best one found as the key partition, then use +// that to control the other partitions to evaluate. The quality loss is ~.08 dB RGB PSNR, the perf gain is up to ~11% (at uber level 0). +static const uint32_t g_partition_predictors[35] = +{ + UINT32_MAX, + UINT32_MAX, + UINT32_MAX, + UINT32_MAX, + UINT32_MAX, + (1 << 1) | (1 << 2) | (1 << 8), + (1 << 1) | (1 << 3) | (1 << 7), + UINT32_MAX, + UINT32_MAX, + (1 << 2) | (1 << 8) | (1 << 16), + (1 << 7) | (1 << 3) | (1 << 15), + UINT32_MAX, + (1 << 8) | (1 << 14) | (1 << 16), + (1 << 7) | (1 << 14) | (1 << 15), + UINT32_MAX, + UINT32_MAX, + UINT32_MAX, + UINT32_MAX, + (1 << 14) | (1 << 15), + (1 << 16) | (1 << 22) | (1 << 14), + (1 << 17) | (1 << 24) | (1 << 14), + (1 << 2) | (1 << 14) | (1 << 15) | (1 << 1), + UINT32_MAX, + (1 << 1) | (1 << 3) | (1 << 14) | (1 << 16) | (1 << 22), + UINT32_MAX, + (1 << 1) | (1 << 2) | (1 << 15) | (1 << 17) | (1 << 24), + (1 << 1) | (1 << 3) | (1 << 22), + UINT32_MAX, + UINT32_MAX, + UINT32_MAX, + (1 << 14) | (1 << 15) | (1 << 16) | (1 << 17), + UINT32_MAX, + UINT32_MAX, + (1 << 1) | (1 << 2) | (1 << 3) | (1 << 27) | (1 << 4) | (1 << 24), + (1 << 14) | (1 << 15) | (1 << 16) | (1 << 11) | (1 << 17) | (1 << 27) +}; + +// Estimate the partition used by modes 1/7. This scans through each partition and computes an approximate error for each. +static uint32_t estimate_partition(const color_rgba *pPixels, const bc7enc_compress_block_params *pComp_params, uint32_t pweights[4], uint32_t mode) +{ + const uint32_t total_partitions = minimumu(pComp_params->m_max_partitions, BC7ENC_MAX_PARTITIONS); + if (total_partitions <= 1) + return 0; + + uint64_t best_err = UINT64_MAX; + uint32_t best_partition = 0; + + // Partition order sorted by usage frequency across a large test corpus. Pattern 34 (checkerboard) must appear in slot 34. + // Using a sorted order allows the user to decrease the # of partitions to scan with minimal loss in quality. + static const uint8_t s_sorted_partition_order[64] = + { + 1 - 1, 14 - 1, 2 - 1, 3 - 1, 16 - 1, 15 - 1, 11 - 1, 17 - 1, + 4 - 1, 24 - 1, 27 - 1, 7 - 1, 8 - 1, 22 - 1, 20 - 1, 30 - 1, + 9 - 1, 5 - 1, 10 - 1, 21 - 1, 6 - 1, 32 - 1, 23 - 1, 18 - 1, + 19 - 1, 12 - 1, 13 - 1, 31 - 1, 25 - 1, 26 - 1, 29 - 1, 28 - 1, + 33 - 1, 34 - 1, 35 - 1, 46 - 1, 47 - 1, 52 - 1, 50 - 1, 51 - 1, + 49 - 1, 39 - 1, 40 - 1, 38 - 1, 54 - 1, 53 - 1, 55 - 1, 37 - 1, + 58 - 1, 59 - 1, 56 - 1, 42 - 1, 41 - 1, 43 - 1, 44 - 1, 60 - 1, + 45 - 1, 57 - 1, 48 - 1, 36 - 1, 61 - 1, 64 - 1, 63 - 1, 62 - 1 + }; + + assert(s_sorted_partition_order[34] == 34); + + int best_key_partition = 0; + + for (uint32_t partition_iter = 0; (partition_iter < total_partitions) && (best_err > 0); partition_iter++) + { + const uint32_t partition = s_sorted_partition_order[partition_iter]; + + // Check to see if we should bother evaluating this partition at all, depending on the best partition found from the first 14. + if (pComp_params->m_mode17_partition_estimation_filterbank) + { + if ((partition_iter >= 14) && (partition_iter <= 34)) + { + const uint32_t best_key_partition_bitmask = 1 << (best_key_partition + 1); + if ((g_partition_predictors[partition] & best_key_partition_bitmask) == 0) + { + if (partition_iter == 34) + break; + + continue; + } + } + } + + const uint8_t *pPartition = &g_bc7_partition2[partition * 16]; + + color_rgba subset_colors[2][16]; + uint32_t subset_total_colors[2] = { 0, 0 }; + for (uint32_t index = 0; index < 16; index++) + subset_colors[pPartition[index]][subset_total_colors[pPartition[index]]++] = pPixels[index]; + + uint64_t total_subset_err = 0; + for (uint32_t subset = 0; (subset < 2) && (total_subset_err < best_err); subset++) + { + if (mode == 7) + total_subset_err += color_cell_compression_est_mode7(subset_total_colors[subset], &subset_colors[subset][0], pComp_params->m_perceptual, pweights, best_err); + else + total_subset_err += color_cell_compression_est_mode1(subset_total_colors[subset], &subset_colors[subset][0], pComp_params->m_perceptual, pweights, best_err); + } + + if (partition < 16) + { + total_subset_err = (uint64_t)((double)total_subset_err * pComp_params->m_low_frequency_partition_weight + .5f); + } + + if (total_subset_err < best_err) + { + best_err = total_subset_err; + best_partition = partition; + } + + // If the checkerboard pattern doesn't get the highest ranking vs. the previous (lower frequency) patterns, then just stop now because statistically the subsequent patterns won't do well either. + if ((partition == 34) && (best_partition != 34)) + break; + + if (partition_iter == 13) + best_key_partition = best_partition; + + } // partition + + return best_partition; +} + +static void set_block_bits(uint8_t *pBytes, uint32_t val, uint32_t num_bits, uint32_t *pCur_ofs) +{ + assert((num_bits <= 32) && (val < (1ULL << num_bits))); + while (num_bits) + { + const uint32_t n = minimumu(8 - (*pCur_ofs & 7), num_bits); + pBytes[*pCur_ofs >> 3] |= (uint8_t)(val << (*pCur_ofs & 7)); + val >>= n; + num_bits -= n; + *pCur_ofs += n; + } + assert(*pCur_ofs <= 128); +} + +struct bc7_optimization_results +{ + uint32_t m_mode; + uint32_t m_partition; + uint8_t m_selectors[16]; + uint8_t m_alpha_selectors[16]; + color_rgba m_low[3]; + color_rgba m_high[3]; + uint32_t m_pbits[3][2]; + uint32_t m_rotation; + uint32_t m_index_selector; +}; + +void encode_bc7_block(void* pBlock, const bc7_optimization_results* pResults) +{ + assert(pResults->m_index_selector <= 1); + assert(pResults->m_rotation <= 3); + + const uint32_t best_mode = pResults->m_mode; + + const uint32_t total_subsets = g_bc7_num_subsets[best_mode]; + const uint32_t total_partitions = 1 << g_bc7_partition_bits[best_mode]; + //const uint32_t num_rotations = 1 << g_bc7_rotation_bits[best_mode]; + //const uint32_t num_index_selectors = (best_mode == 4) ? 2 : 1; + + const uint8_t* pPartition; + if (total_subsets == 1) + pPartition = &g_bc7_partition1[0]; + else if (total_subsets == 2) + pPartition = &g_bc7_partition2[pResults->m_partition * 16]; + else + pPartition = &g_bc7_partition3[pResults->m_partition * 16]; + + uint8_t color_selectors[16]; + memcpy(color_selectors, pResults->m_selectors, 16); + + uint8_t alpha_selectors[16]; + memcpy(alpha_selectors, pResults->m_alpha_selectors, 16); + + color_rgba low[3], high[3]; + memcpy(low, pResults->m_low, sizeof(low)); + memcpy(high, pResults->m_high, sizeof(high)); + + uint32_t pbits[3][2]; + memcpy(pbits, pResults->m_pbits, sizeof(pbits)); + + int anchor[3] = { -1, -1, -1 }; + + for (uint32_t k = 0; k < total_subsets; k++) + { + uint32_t anchor_index = 0; + if (k) + { + if ((total_subsets == 3) && (k == 1)) + anchor_index = g_bc7_table_anchor_index_third_subset_1[pResults->m_partition]; + else if ((total_subsets == 3) && (k == 2)) + anchor_index = g_bc7_table_anchor_index_third_subset_2[pResults->m_partition]; + else + anchor_index = g_bc7_table_anchor_index_second_subset[pResults->m_partition]; + } + + anchor[k] = anchor_index; + + const uint32_t color_index_bits = get_bc7_color_index_size(best_mode, pResults->m_index_selector); + const uint32_t num_color_indices = 1 << color_index_bits; + + if (color_selectors[anchor_index] & (num_color_indices >> 1)) + { + for (uint32_t i = 0; i < 16; i++) + if (pPartition[i] == k) + color_selectors[i] = (uint8_t)((num_color_indices - 1) - color_selectors[i]); + + if (get_bc7_mode_has_seperate_alpha_selectors(best_mode)) + { + for (uint32_t q = 0; q < 3; q++) + { + uint8_t t = low[k].m_c[q]; + low[k].m_c[q] = high[k].m_c[q]; + high[k].m_c[q] = t; + } + } + else + { + color_rgba tmp = low[k]; + low[k] = high[k]; + high[k] = tmp; + } + + if (!g_bc7_mode_has_shared_p_bits[best_mode]) + { + uint32_t t = pbits[k][0]; + pbits[k][0] = pbits[k][1]; + pbits[k][1] = t; + } + } + + if (get_bc7_mode_has_seperate_alpha_selectors(best_mode)) + { + const uint32_t alpha_index_bits = get_bc7_alpha_index_size(best_mode, pResults->m_index_selector); + const uint32_t num_alpha_indices = 1 << alpha_index_bits; + + if (alpha_selectors[anchor_index] & (num_alpha_indices >> 1)) + { + for (uint32_t i = 0; i < 16; i++) + if (pPartition[i] == k) + alpha_selectors[i] = (uint8_t)((num_alpha_indices - 1) - alpha_selectors[i]); + + uint8_t t = low[k].m_c[3]; + low[k].m_c[3] = high[k].m_c[3]; + high[k].m_c[3] = t; + } + } + } + + uint8_t* pBlock_bytes = (uint8_t*)(pBlock); + memset(pBlock_bytes, 0, BC7ENC_BLOCK_SIZE); + + uint32_t cur_bit_ofs = 0; + set_block_bits(pBlock_bytes, 1 << best_mode, best_mode + 1, &cur_bit_ofs); + + if ((best_mode == 4) || (best_mode == 5)) + set_block_bits(pBlock_bytes, pResults->m_rotation, 2, &cur_bit_ofs); + + if (best_mode == 4) + set_block_bits(pBlock_bytes, pResults->m_index_selector, 1, &cur_bit_ofs); + + if (total_partitions > 1) + set_block_bits(pBlock_bytes, pResults->m_partition, (total_partitions == 64) ? 6 : 4, &cur_bit_ofs); + + const uint32_t total_comps = (best_mode >= 4) ? 4 : 3; + for (uint32_t comp = 0; comp < total_comps; comp++) + { + for (uint32_t subset = 0; subset < total_subsets; subset++) + { + set_block_bits(pBlock_bytes, low[subset].m_c[comp], (comp == 3) ? g_bc7_alpha_precision_table[best_mode] : g_bc7_color_precision_table[best_mode], &cur_bit_ofs); + set_block_bits(pBlock_bytes, high[subset].m_c[comp], (comp == 3) ? g_bc7_alpha_precision_table[best_mode] : g_bc7_color_precision_table[best_mode], &cur_bit_ofs); + } + } + + if (g_bc7_mode_has_p_bits[best_mode]) + { + for (uint32_t subset = 0; subset < total_subsets; subset++) + { + set_block_bits(pBlock_bytes, pbits[subset][0], 1, &cur_bit_ofs); + if (!g_bc7_mode_has_shared_p_bits[best_mode]) + set_block_bits(pBlock_bytes, pbits[subset][1], 1, &cur_bit_ofs); + } + } + + for (uint32_t y = 0; y < 4; y++) + { + for (uint32_t x = 0; x < 4; x++) + { + int idx = x + y * 4; + + uint32_t n = pResults->m_index_selector ? get_bc7_alpha_index_size(best_mode, pResults->m_index_selector) : get_bc7_color_index_size(best_mode, pResults->m_index_selector); + + if ((idx == anchor[0]) || (idx == anchor[1]) || (idx == anchor[2])) + n--; + + set_block_bits(pBlock_bytes, pResults->m_index_selector ? alpha_selectors[idx] : color_selectors[idx], n, &cur_bit_ofs); + } + } + + if (get_bc7_mode_has_seperate_alpha_selectors(best_mode)) + { + for (uint32_t y = 0; y < 4; y++) + { + for (uint32_t x = 0; x < 4; x++) + { + int idx = x + y * 4; + + uint32_t n = pResults->m_index_selector ? get_bc7_color_index_size(best_mode, pResults->m_index_selector) : get_bc7_alpha_index_size(best_mode, pResults->m_index_selector); + + if ((idx == anchor[0]) || (idx == anchor[1]) || (idx == anchor[2])) + n--; + + set_block_bits(pBlock_bytes, pResults->m_index_selector ? color_selectors[idx] : alpha_selectors[idx], n, &cur_bit_ofs); + } + } + } + + assert(cur_bit_ofs == 128); +} + +static void handle_alpha_block_mode5(const color_rgba* pPixels, const bc7enc_compress_block_params* pComp_params, color_cell_compressor_params* pParams, uint32_t lo_a, uint32_t hi_a, bc7_optimization_results* pOpt_results5, uint64_t* pMode5_err, uint64_t* pMode5_alpha_err) +{ + pParams->m_pSelector_weights = g_bc7_weights2; + pParams->m_pSelector_weightsx = (const vec4F*)g_bc7_weights2x; + pParams->m_num_selector_weights = 4; + + pParams->m_comp_bits = 7; + pParams->m_has_pbits = false; + pParams->m_endpoints_share_pbit = false; + pParams->m_has_alpha = false; + + pParams->m_perceptual = pComp_params->m_perceptual; + + pParams->m_num_pixels = 16; + pParams->m_pPixels = pPixels; + + color_cell_compressor_results results5; + results5.m_pSelectors = pOpt_results5->m_selectors; + + uint8_t selectors_temp[16]; + results5.m_pSelectors_temp = selectors_temp; + + *pMode5_err = color_cell_compression(5, pParams, &results5, pComp_params); + assert(*pMode5_err == results5.m_best_overall_err); + + pOpt_results5->m_low[0] = results5.m_low_endpoint; + pOpt_results5->m_high[0] = results5.m_high_endpoint; + + if (lo_a == hi_a) + { + *pMode5_alpha_err = 0; + pOpt_results5->m_low[0].m_c[3] = (uint8_t)lo_a; + pOpt_results5->m_high[0].m_c[3] = (uint8_t)hi_a; + memset(pOpt_results5->m_alpha_selectors, 0, sizeof(pOpt_results5->m_alpha_selectors)); + } + else + { + *pMode5_alpha_err = UINT64_MAX; + + const uint32_t total_passes = (pComp_params->m_uber_level >= 1) ? 3 : 2; + for (uint32_t pass = 0; pass < total_passes; pass++) + { + int32_t vals[4]; + vals[0] = lo_a; + vals[3] = hi_a; + + const int32_t w_s1 = 21, w_s2 = 43; + vals[1] = (vals[0] * (64 - w_s1) + vals[3] * w_s1 + 32) >> 6; + vals[2] = (vals[0] * (64 - w_s2) + vals[3] * w_s2 + 32) >> 6; + + uint8_t trial_alpha_selectors[16]; + + uint64_t trial_alpha_err = 0; + for (uint32_t i = 0; i < 16; i++) + { + const int32_t a = pParams->m_pPixels[i].m_c[3]; + + int s = 0; + int32_t be = iabs32(a - vals[0]); + int e = iabs32(a - vals[1]); if (e < be) { be = e; s = 1; } + e = iabs32(a - vals[2]); if (e < be) { be = e; s = 2; } + e = iabs32(a - vals[3]); if (e < be) { be = e; s = 3; } + + trial_alpha_selectors[i] = (uint8_t)s; + + uint32_t a_err = (uint32_t)(be * be) * pParams->m_weights[3]; + + trial_alpha_err += a_err; + } + + if (trial_alpha_err < *pMode5_alpha_err) + { + *pMode5_alpha_err = trial_alpha_err; + pOpt_results5->m_low[0].m_c[3] = (uint8_t)lo_a; + pOpt_results5->m_high[0].m_c[3] = (uint8_t)hi_a; + memcpy(pOpt_results5->m_alpha_selectors, trial_alpha_selectors, sizeof(pOpt_results5->m_alpha_selectors)); + } + + if (pass != (total_passes - 1U)) + { + float xl, xh; + compute_least_squares_endpoints_a(16, trial_alpha_selectors, (const vec4F*)g_bc7_weights2x, &xl, &xh, pParams->m_pPixels); + + uint32_t new_lo_a = clampi((int)floor(xl + .5f), 0, 255); + uint32_t new_hi_a = clampi((int)floor(xh + .5f), 0, 255); + if (new_lo_a > new_hi_a) + swapu(&new_lo_a, &new_hi_a); + + if ((new_lo_a == lo_a) && (new_hi_a == hi_a)) + break; + + lo_a = new_lo_a; + hi_a = new_hi_a; + } + } + + *pMode5_err += *pMode5_alpha_err; + } +} + +static void handle_alpha_block(void *pBlock, const color_rgba *pPixels, const bc7enc_compress_block_params *pComp_params, color_cell_compressor_params *pParams) +{ + assert((pComp_params->m_mode_mask & (1 << 6)) || (pComp_params->m_mode_mask & (1 << 5)) || (pComp_params->m_mode_mask & (1 << 7))); + + pParams->m_pSelector_weights = g_bc7_weights4; + pParams->m_pSelector_weightsx = (const vec4F *)g_bc7_weights4x; + pParams->m_num_selector_weights = 16; + pParams->m_comp_bits = 7; + pParams->m_has_pbits = true; + pParams->m_endpoints_share_pbit = false; + pParams->m_has_alpha = true; + pParams->m_perceptual = pComp_params->m_perceptual; + pParams->m_num_pixels = 16; + pParams->m_pPixels = pPixels; + + bc7_optimization_results opt_results6, opt_results5, opt_results7; + color_cell_compressor_results results6; + memset(&results6, 0, sizeof(results6)); + + uint64_t best_err = UINT64_MAX; + uint32_t best_mode = 0; + uint8_t selectors_temp[16]; + + if (pComp_params->m_mode_mask & (1 << 6)) + { + results6.m_pSelectors = opt_results6.m_selectors; + results6.m_pSelectors_temp = selectors_temp; + + best_err = (uint64_t)(color_cell_compression(6, pParams, &results6, pComp_params) * pComp_params->m_mode6_error_weight + .5f); + best_mode = 6; + } + + if ((best_err > 0) && (pComp_params->m_mode_mask & (1 << 5))) + { + uint32_t lo_a = 255, hi_a = 0; + for (uint32_t i = 0; i < 16; i++) + { + uint32_t a = pPixels[i].m_c[3]; + lo_a = minimumu(lo_a, a); + hi_a = maximumu(hi_a, a); + } + + uint64_t mode5_err, mode5_alpha_err; + handle_alpha_block_mode5(pPixels, pComp_params, pParams, lo_a, hi_a, &opt_results5, &mode5_err, &mode5_alpha_err); + + mode5_err = (uint64_t)(mode5_err * pComp_params->m_mode5_error_weight + .5f); + + if (mode5_err < best_err) + { + best_err = mode5_err; + best_mode = 5; + } + } + + if ((best_err > 0) && (pComp_params->m_mode_mask & (1 << 7))) + { + const uint32_t trial_partition = estimate_partition(pPixels, pComp_params, pParams->m_weights, 7); + + pParams->m_pSelector_weights = g_bc7_weights2; + pParams->m_pSelector_weightsx = (const vec4F*)g_bc7_weights2x; + pParams->m_num_selector_weights = 4; + pParams->m_comp_bits = 5; + pParams->m_has_pbits = true; + pParams->m_endpoints_share_pbit = false; + pParams->m_has_alpha = true; + + const uint8_t* pPartition = &g_bc7_partition2[trial_partition * 16]; + + color_rgba subset_colors[2][16]; + + uint32_t subset_total_colors7[2] = { 0, 0 }; + + uint8_t subset_pixel_index7[2][16]; + uint8_t subset_selectors7[2][16]; + color_cell_compressor_results subset_results7[2]; + + for (uint32_t idx = 0; idx < 16; idx++) + { + const uint32_t p = pPartition[idx]; + subset_colors[p][subset_total_colors7[p]] = pPixels[idx]; + subset_pixel_index7[p][subset_total_colors7[p]] = (uint8_t)idx; + subset_total_colors7[p]++; + } + + uint64_t trial_err = 0; + for (uint32_t subset = 0; subset < 2; subset++) + { + pParams->m_num_pixels = subset_total_colors7[subset]; + pParams->m_pPixels = &subset_colors[subset][0]; + + color_cell_compressor_results* pResults = &subset_results7[subset]; + pResults->m_pSelectors = &subset_selectors7[subset][0]; + pResults->m_pSelectors_temp = selectors_temp; + uint64_t err = color_cell_compression(7, pParams, pResults, pComp_params); + trial_err += err; + if ((uint64_t)(trial_err * pComp_params->m_mode7_error_weight + .5f) > best_err) + break; + + } // subset + + const uint64_t mode7_trial_err = (uint64_t)(trial_err * pComp_params->m_mode7_error_weight + .5f); + + if (mode7_trial_err < best_err) + { + best_err = mode7_trial_err; + best_mode = 7; + opt_results7.m_mode = 7; + opt_results7.m_partition = trial_partition; + opt_results7.m_index_selector = 0; + opt_results7.m_rotation = 0; + for (uint32_t subset = 0; subset < 2; subset++) + { + for (uint32_t i = 0; i < subset_total_colors7[subset]; i++) + opt_results7.m_selectors[subset_pixel_index7[subset][i]] = subset_selectors7[subset][i]; + opt_results7.m_low[subset] = subset_results7[subset].m_low_endpoint; + opt_results7.m_high[subset] = subset_results7[subset].m_high_endpoint; + opt_results7.m_pbits[subset][0] = subset_results7[subset].m_pbits[0]; + opt_results7.m_pbits[subset][1] = subset_results7[subset].m_pbits[1]; + } + } + } + + if (best_mode == 7) + { + encode_bc7_block(pBlock, &opt_results7); + } + else if (best_mode == 5) + { + opt_results5.m_mode = 5; + opt_results5.m_partition = 0; + opt_results5.m_rotation = 0; + opt_results5.m_index_selector = 0; + + encode_bc7_block(pBlock, &opt_results5); + } + else if (best_mode == 6) + { + opt_results6.m_mode = 6; + opt_results6.m_partition = 0; + opt_results6.m_low[0] = results6.m_low_endpoint; + opt_results6.m_high[0] = results6.m_high_endpoint; + opt_results6.m_pbits[0][0] = results6.m_pbits[0]; + opt_results6.m_pbits[0][1] = results6.m_pbits[1]; + opt_results6.m_rotation = 0; + opt_results6.m_index_selector = 0; + + encode_bc7_block(pBlock, &opt_results6); + } + else + { + assert(0); + } +} + +static void handle_opaque_block(void *pBlock, const color_rgba *pPixels, const bc7enc_compress_block_params *pComp_params, color_cell_compressor_params *pParams) +{ + assert((pComp_params->m_mode_mask & (1 << 6)) || (pComp_params->m_mode_mask & (1 << 1))); + + uint8_t selectors_temp[16]; + + bc7_optimization_results opt_results; + + uint64_t best_err = UINT64_MAX; + + pParams->m_perceptual = pComp_params->m_perceptual; + pParams->m_num_pixels = 16; + pParams->m_pPixels = pPixels; + pParams->m_has_alpha = false; + + opt_results.m_partition = 0; + opt_results.m_index_selector = 0; + opt_results.m_rotation = 0; + + // Mode 6 + if (pComp_params->m_mode_mask & (1 << 6)) + { + pParams->m_pSelector_weights = g_bc7_weights4; + pParams->m_pSelector_weightsx = (const vec4F*)g_bc7_weights4x; + pParams->m_num_selector_weights = 16; + pParams->m_comp_bits = 7; + pParams->m_has_pbits = true; + pParams->m_endpoints_share_pbit = false; + + color_cell_compressor_results results6; + results6.m_pSelectors = opt_results.m_selectors; + results6.m_pSelectors_temp = selectors_temp; + + best_err = (uint64_t)(color_cell_compression(6, pParams, &results6, pComp_params) * pComp_params->m_mode6_error_weight + .5f); + + opt_results.m_mode = 6; + opt_results.m_low[0] = results6.m_low_endpoint; + opt_results.m_high[0] = results6.m_high_endpoint; + opt_results.m_pbits[0][0] = results6.m_pbits[0]; + opt_results.m_pbits[0][1] = results6.m_pbits[1]; + } + + // Mode 1 + if ((best_err > 0) && (pComp_params->m_max_partitions > 0) && (pComp_params->m_mode_mask & (1 << 1))) + { + const uint32_t trial_partition = estimate_partition(pPixels, pComp_params, pParams->m_weights, 1); + + pParams->m_pSelector_weights = g_bc7_weights3; + pParams->m_pSelector_weightsx = (const vec4F *)g_bc7_weights3x; + pParams->m_num_selector_weights = 8; + pParams->m_comp_bits = 6; + pParams->m_has_pbits = true; + pParams->m_endpoints_share_pbit = true; + + const uint8_t *pPartition = &g_bc7_partition2[trial_partition * 16]; + + color_rgba subset_colors[2][16]; + + uint32_t subset_total_colors1[2] = { 0, 0 }; + + uint8_t subset_pixel_index1[2][16]; + uint8_t subset_selectors1[2][16]; + color_cell_compressor_results subset_results1[2]; + + for (uint32_t idx = 0; idx < 16; idx++) + { + const uint32_t p = pPartition[idx]; + subset_colors[p][subset_total_colors1[p]] = pPixels[idx]; + subset_pixel_index1[p][subset_total_colors1[p]] = (uint8_t)idx; + subset_total_colors1[p]++; + } + + uint64_t trial_err = 0; + for (uint32_t subset = 0; subset < 2; subset++) + { + pParams->m_num_pixels = subset_total_colors1[subset]; + pParams->m_pPixels = &subset_colors[subset][0]; + + color_cell_compressor_results *pResults = &subset_results1[subset]; + pResults->m_pSelectors = &subset_selectors1[subset][0]; + pResults->m_pSelectors_temp = selectors_temp; + uint64_t err = color_cell_compression(1, pParams, pResults, pComp_params); + + trial_err += err; + if ((uint64_t)(trial_err * pComp_params->m_mode1_error_weight + .5f) > best_err) + break; + + } // subset + + const uint64_t mode1_trial_err = (uint64_t)(trial_err * pComp_params->m_mode1_error_weight + .5f); + if (mode1_trial_err < best_err) + { + best_err = mode1_trial_err; + opt_results.m_mode = 1; + opt_results.m_partition = trial_partition; + for (uint32_t subset = 0; subset < 2; subset++) + { + for (uint32_t i = 0; i < subset_total_colors1[subset]; i++) + opt_results.m_selectors[subset_pixel_index1[subset][i]] = subset_selectors1[subset][i]; + opt_results.m_low[subset] = subset_results1[subset].m_low_endpoint; + opt_results.m_high[subset] = subset_results1[subset].m_high_endpoint; + opt_results.m_pbits[subset][0] = subset_results1[subset].m_pbits[0]; + } + } + } + + encode_bc7_block(pBlock, &opt_results); +} + +bool bc7enc_compress_block(void *pBlock, const void *pPixelsRGBA, const bc7enc_compress_block_params *pComp_params) +{ + assert(g_bc7_mode_1_optimal_endpoints[255][0].m_hi != 0); + + const color_rgba *pPixels = (const color_rgba *)(pPixelsRGBA); + + color_cell_compressor_params params; + if (pComp_params->m_perceptual) + { + // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.709_conversion + const float pr_weight = (.5f / (1.0f - .2126f)) * (.5f / (1.0f - .2126f)); + const float pb_weight = (.5f / (1.0f - .0722f)) * (.5f / (1.0f - .0722f)); + params.m_weights[0] = (int)(pComp_params->m_weights[0] * 4.0f); + params.m_weights[1] = (int)(pComp_params->m_weights[1] * 4.0f * pr_weight); + params.m_weights[2] = (int)(pComp_params->m_weights[2] * 4.0f * pb_weight); + params.m_weights[3] = pComp_params->m_weights[3] * 4; + } + else + memcpy(params.m_weights, pComp_params->m_weights, sizeof(params.m_weights)); + + if (pComp_params->m_force_alpha) + { + handle_alpha_block(pBlock, pPixels, pComp_params, ¶ms); + return true; + } + + for (uint32_t i = 0; i < 16; i++) + { + if (pPixels[i].m_c[3] < 255) + { + handle_alpha_block(pBlock, pPixels, pComp_params, ¶ms); + return true; + } + } + handle_opaque_block(pBlock, pPixels, pComp_params, ¶ms); + return false; +} + +static const uint8_t g_tdefl_small_dist_extra[512] = +{ + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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, 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, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 +}; + +static const uint8_t g_tdefl_large_dist_extra[128] = +{ + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 +}; + +[[maybe_unused]] static inline uint32_t compute_match_cost_estimate(uint32_t dist, uint32_t match_len_in_bytes) +{ + assert(match_len_in_bytes <= 258); + + uint32_t len_cost = 6; + if (match_len_in_bytes >= 12) + len_cost = 9; + else if (match_len_in_bytes >= 8) + len_cost = 8; + else if (match_len_in_bytes >= 6) + len_cost = 7; + + uint32_t dist_cost = 5; + if (dist < 512) + dist_cost += g_tdefl_small_dist_extra[dist & 511]; + else + { + dist_cost += g_tdefl_large_dist_extra[std::min(dist, 32767) >> 8]; + while (dist >= 32768) + { + dist_cost++; + dist >>= 1; + } + } + return len_cost + dist_cost; +} + +class tracked_stat +{ +public: + tracked_stat() { clear(); } + + void clear() { m_num = 0; m_total = 0; m_total2 = 0; } + + void update(uint32_t val) { m_num++; m_total += val; m_total2 += val * val; } + + tracked_stat& operator += (uint32_t val) { update(val); return *this; } + + uint32_t get_number_of_values() { return m_num; } + uint64_t get_total() const { return m_total; } + uint64_t get_total2() const { return m_total2; } + + float get_average() const { return m_num ? (float)m_total / m_num : 0.0f; }; + float get_std_dev() const { return m_num ? sqrtf((float)(m_num * m_total2 - m_total * m_total)) / m_num : 0.0f; } + float get_variance() const { float s = get_std_dev(); return s * s; } + +private: + uint32_t m_num; + uint64_t m_total; + uint64_t m_total2; +}; + +[[maybe_unused]] static inline float compute_block_max_std_dev(const color_rgba* pPixels) +{ + tracked_stat r_stats, g_stats, b_stats, a_stats; + + for (uint32_t i = 0; i < 16; i++) + { + r_stats.update(pPixels[i].m_c[0]); + g_stats.update(pPixels[i].m_c[1]); + b_stats.update(pPixels[i].m_c[2]); + a_stats.update(pPixels[i].m_c[3]); + } + + return std::max(std::max(std::max(r_stats.get_std_dev(), g_stats.get_std_dev()), b_stats.get_std_dev()), a_stats.get_std_dev()); +} + +struct bc7_block +{ + uint8_t m_bytes[16]; + + uint32_t get_mode() const + { + uint32_t bc7_mode = 0; + while (((m_bytes[0] & (1 << bc7_mode)) == 0) && (bc7_mode < 8)) + bc7_mode++; + return bc7_mode; + } +}; + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +If you use this software in a product, attribution / credits is requested but not required. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright(c) 2020-2021 Richard Geldreich, Jr. +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files(the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions : +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain(www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non - commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain.We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors.We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/external/bc7enc_rdo/bc7enc.h b/external/bc7enc_rdo/bc7enc.h new file mode 100644 index 0000000000..1ad52796f5 --- /dev/null +++ b/external/bc7enc_rdo/bc7enc.h @@ -0,0 +1,126 @@ +// File: bc7enc.h - Richard Geldreich, Jr. - MIT license or public domain (see end of bc7enc.c) +// If you use this software in a product, attribution / credits is requested but not required. + +#pragma once + +#include +#include +#include +#include + +#define BC7ENC_BLOCK_SIZE (16) +#define BC7ENC_MAX_PARTITIONS (64) +#define BC7ENC_MAX_UBER_LEVEL (4) + +struct color_rgba { uint8_t m_c[4]; }; + +struct bc7enc_compress_block_params +{ + uint32_t m_mode_mask; + + // m_max_partitions may range from 0 (disables mode 1) to BC7ENC_MAX_PARTITIONS. The higher this value, the slower the compressor, but the higher the quality. + uint32_t m_max_partitions; + + // Relative RGBA or YCbCrA weights. + uint32_t m_weights[4]; + + // m_uber_level may range from 0 to BC7ENC_MAX_UBER_LEVEL. The higher this value, the slower the compressor, but the higher the quality. + uint32_t m_uber_level; + + // If m_perceptual is true, colorspace error is computed in YCbCr space, otherwise RGB. + bool m_perceptual; + + // Set m_try_least_squares to false for slightly faster/lower quality compression. + bool m_try_least_squares; + + // When m_mode17_partition_estimation_filterbank, the mode1 partition estimator skips lesser used partition patterns unless they are strongly predicted to be potentially useful. + // There's a slight loss in quality with this enabled (around .08 dB RGB PSNR or .05 dB Y PSNR), but up to a 11% gain in speed depending on the other settings. + bool m_mode17_partition_estimation_filterbank; + + bool m_force_alpha; + + bool m_force_selectors; + uint8_t m_selectors[16]; + + bool m_quant_mode6_endpoints; + bool m_bias_mode1_pbits; + + float m_pbit1_weight; + + float m_mode1_error_weight; + float m_mode5_error_weight; + float m_mode6_error_weight; + float m_mode7_error_weight; + + float m_low_frequency_partition_weight; + + void clear() + { + memset(this, 0, sizeof(*this)); + } + + void print() + { + printf("Mode mask: 0x%X\n", m_mode_mask); + printf("Max partitions: %u\n", m_max_partitions); + printf("Weights: %u %u %u %u\n", m_weights[0], m_weights[1], m_weights[2], m_weights[3]); + printf("Uber level: %u\n", m_uber_level); + printf("Perceptual: %u\n", m_perceptual); + printf("Try least squares: %u\n", m_try_least_squares); + printf("Mode 1/7 partition estimation filterbank: %u\n", m_mode17_partition_estimation_filterbank); + printf("Force alpha: %u\n", m_force_alpha); + printf("Quant mode 6 endpoints: %u\n", m_quant_mode6_endpoints); + printf("Bias mode 1 p-bits: %u\n", m_bias_mode1_pbits); + printf("p-bit 1 weight: %f\n", m_pbit1_weight); + printf("Mode error weights: %f %f %f %f\n", m_mode1_error_weight, m_mode5_error_weight, m_mode6_error_weight, m_mode7_error_weight); + printf("Low frequency partition weight: %f\n", m_low_frequency_partition_weight); + } +}; + +inline void bc7enc_compress_block_params_init_linear_weights(bc7enc_compress_block_params *p) +{ + p->m_perceptual = false; + p->m_weights[0] = 1; + p->m_weights[1] = 1; + p->m_weights[2] = 1; + p->m_weights[3] = 1; +} + +inline void bc7enc_compress_block_params_init_perceptual_weights(bc7enc_compress_block_params *p) +{ + p->m_perceptual = true; + p->m_weights[0] = 128; + p->m_weights[1] = 64; + p->m_weights[2] = 16; + p->m_weights[3] = 32; +} + +inline void bc7enc_compress_block_params_init(bc7enc_compress_block_params *p) +{ + p->m_mode_mask = UINT32_MAX; + p->m_max_partitions = BC7ENC_MAX_PARTITIONS; + p->m_try_least_squares = true; + p->m_mode17_partition_estimation_filterbank = true; + p->m_uber_level = 0; + p->m_force_selectors = false; + p->m_force_alpha = false; + p->m_quant_mode6_endpoints = false; + p->m_bias_mode1_pbits = false; + p->m_pbit1_weight = 1.0f; + p->m_mode1_error_weight = 1.0f; + p->m_mode5_error_weight = 1.0f; + p->m_mode6_error_weight = 1.0f; + p->m_mode7_error_weight = 1.0f; + p->m_low_frequency_partition_weight = 1.0f; + bc7enc_compress_block_params_init_perceptual_weights(p); +} + +// bc7enc_compress_block_init() MUST be called before calling bc7enc_compress_block() (or you'll get artifacts). +void bc7enc_compress_block_init(); + +// Packs a single block of 16x16 RGBA pixels (R first in memory) to 128-bit BC7 block pBlock, using either mode 1 and/or 6. +// Alpha blocks will always use mode 6, and by default opaque blocks will use either modes 1 or 6. +// Returns true if the block had any pixels with alpha < 255, otherwise it return false. (This is not an error code - a block is always encoded.) +bool bc7enc_compress_block(void *pBlock, const void *pPixelsRGBA, const bc7enc_compress_block_params *pComp_params); + + diff --git a/external/bc7enc_rdo/ert.cpp b/external/bc7enc_rdo/ert.cpp new file mode 100644 index 0000000000..b94e7a671f --- /dev/null +++ b/external/bc7enc_rdo/ert.cpp @@ -0,0 +1,705 @@ +#include "ert.h" +#include +#include +#include + +#define ERT_FAVOR_CONT_AND_REP0_MATCHES (1) +#define ERT_FAVOR_REP0_MATCHES (0) + +namespace ert +{ + const uint32_t MAX_BLOCK_PIXELS = 12 * 12; + const uint32_t MAX_BLOCK_SIZE_IN_BYTES = 256; + const uint32_t MIN_MATCH_LEN = 3; + const float LITERAL_BITS = 13.0f; + const float MATCH_CONTINUE_BITS = 1.0f; + const float MATCH_REP0_BITS = 4.0f; + + static inline float clampf(float value, float low, float high) { if (value < low) value = low; else if (value > high) value = high; return value; } + template inline F lerp(F a, F b, F s) { return a + (b - a) * s; } + + static const uint8_t g_tdefl_small_dist_extra[512] = + { + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 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, 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, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 + }; + + static const uint8_t g_tdefl_large_dist_extra[128] = + { + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 + }; + + static inline uint32_t compute_match_cost_estimate(uint32_t dist, uint32_t match_len_in_bytes) + { + assert(match_len_in_bytes <= 258); + + uint32_t len_cost = 6; + if (match_len_in_bytes >= 12) + len_cost = 9; + else if (match_len_in_bytes >= 8) + len_cost = 8; + else if (match_len_in_bytes >= 6) + len_cost = 7; + + uint32_t dist_cost = 5; + if (dist < 512) + dist_cost += g_tdefl_small_dist_extra[dist & 511]; + else + { + dist_cost += g_tdefl_large_dist_extra[std::min(dist, 32767) >> 8]; + while (dist >= 32768) + { + dist_cost++; + dist >>= 1; + } + } + return len_cost + dist_cost; + } + + class tracked_stat + { + public: + tracked_stat() { clear(); } + + void clear() { m_num = 0; m_total = 0; m_total2 = 0; } + + void update(uint32_t val) { m_num++; m_total += val; m_total2 += val * val; } + + tracked_stat& operator += (uint32_t val) { update(val); return *this; } + + uint32_t get_number_of_values() { return m_num; } + uint64_t get_total() const { return m_total; } + uint64_t get_total2() const { return m_total2; } + + float get_average() const { return m_num ? (float)m_total / m_num : 0.0f; }; + float get_std_dev() const { return m_num ? sqrtf((float)(m_num * m_total2 - m_total * m_total)) / m_num : 0.0f; } + float get_variance() const { float s = get_std_dev(); return s * s; } + + private: + uint32_t m_num; + uint64_t m_total; + uint64_t m_total2; + }; + + static inline float compute_block_max_std_dev(const color_rgba* pPixels, uint32_t block_width, uint32_t block_height, uint32_t num_comps) + { + tracked_stat comp_stats[4]; + + for (uint32_t y = 0; y < block_height; y++) + { + for (uint32_t x = 0; x < block_width; x++) + { + const color_rgba* pPixel = pPixels + x + y * block_width; + + for (uint32_t c = 0; c < num_comps; c++) + comp_stats[c].update(pPixel->m_c[c]); + } + } + + float max_std_dev = 0.0f; + for (uint32_t i = 0; i < num_comps; i++) + max_std_dev = std::max(max_std_dev, comp_stats[i].get_std_dev()); + return max_std_dev; + } + + static inline float compute_block_mse(const color_rgba* pPixelsA, const color_rgba* pPixelsB, uint32_t block_width, uint32_t block_height, uint32_t total_block_pixels, uint32_t num_comps, const uint32_t weights[4], float one_over_total_color_weight) + { + uint64_t total_err = 0; + + if ((block_width == 4) && (block_height == 4) && (num_comps == 4)) + { + if ((weights[0] == 1) && (weights[1] == 1) && (weights[2] == 1) && (weights[3] == 1)) + { + for (uint32_t i = 0; i < 16; i++) + { + const color_rgba* pA = pPixelsA + i; + const color_rgba* pB = pPixelsB + i; + + const int dr = pA->m_c[0] - pB->m_c[0]; + const int dg = pA->m_c[1] - pB->m_c[1]; + const int db = pA->m_c[2] - pB->m_c[2]; + const int da = pA->m_c[3] - pB->m_c[3]; + + total_err += dr * dr + dg * dg + db * db + da * da; + } + } + else + { + for (uint32_t i = 0; i < 16; i++) + { + const color_rgba* pA = pPixelsA + i; + const color_rgba* pB = pPixelsB + i; + + const int dr = pA->m_c[0] - pB->m_c[0]; + const int dg = pA->m_c[1] - pB->m_c[1]; + const int db = pA->m_c[2] - pB->m_c[2]; + const int da = pA->m_c[3] - pB->m_c[3]; + + total_err += weights[0] * dr * dr + weights[1] * dg * dg + weights[2] * db * db + weights[3] * da * da; + } + } + } + else if ((block_width == 4) && (block_height == 4) && (num_comps == 3)) + { + for (uint32_t y = 0; y < 4; y++) + { + const uint32_t y_ofs = y * 4; + for (uint32_t x = 0; x < 4; x++) + { + const color_rgba* pA = pPixelsA + x + y_ofs; + const color_rgba* pB = pPixelsB + x + y_ofs; + + const int dr = pA->m_c[0] - pB->m_c[0]; + const int dg = pA->m_c[1] - pB->m_c[1]; + const int db = pA->m_c[2] - pB->m_c[2]; + + total_err += weights[0] * dr * dr + weights[1] * dg * dg + weights[2] * db * db; + } + } + } + else if ((block_width == 4) && (block_height == 4) && (num_comps == 2)) + { + for (uint32_t y = 0; y < 4; y++) + { + const uint32_t y_ofs = y * 4; + for (uint32_t x = 0; x < 4; x++) + { + const color_rgba* pA = pPixelsA + x + y_ofs; + const color_rgba* pB = pPixelsB + x + y_ofs; + + const int dr = pA->m_c[0] - pB->m_c[0]; + const int dg = pA->m_c[1] - pB->m_c[1]; + + total_err += weights[0] * dr * dr + weights[1] * dg * dg; + } + } + } + else if ((block_width == 4) && (block_height == 4) && (num_comps == 1)) + { + for (uint32_t y = 0; y < 4; y++) + { + const uint32_t y_ofs = y * 4; + for (uint32_t x = 0; x < 4; x++) + { + const color_rgba* pA = pPixelsA + x + y_ofs; + const color_rgba* pB = pPixelsB + x + y_ofs; + + const int dr = pA->m_c[0] - pB->m_c[0]; + + total_err += weights[0] * dr * dr; + } + } + } + else + { + for (uint32_t y = 0; y < block_height; y++) + { + const uint32_t y_ofs = y * block_width; + for (uint32_t x = 0; x < block_width; x++) + { + const color_rgba* pA = pPixelsA + x + y_ofs; + const color_rgba* pB = pPixelsB + x + y_ofs; + + for (uint32_t c = 0; c < num_comps; c++) + { + const int d = pA->m_c[c] - pB->m_c[c]; + total_err += weights[c] * d * d; + } + } + } + } + + return total_err * (one_over_total_color_weight / total_block_pixels); + } + + uint32_t hash_hsieh(const uint8_t* pBuf, size_t len, uint32_t salt) + { + if (!pBuf || !len) + return 0; + + uint32_t h = static_cast(len + (salt << 16)); + + const uint32_t bytes_left = len & 3; + len >>= 2; + + while (len--) + { + const uint16_t* pWords = reinterpret_cast(pBuf); + + h += pWords[0]; + + const uint32_t t = (pWords[1] << 11) ^ h; + h = (h << 16) ^ t; + + pBuf += sizeof(uint32_t); + + h += h >> 11; + } + + switch (bytes_left) + { + case 1: + h += *reinterpret_cast(pBuf); + h ^= h << 10; + h += h >> 1; + break; + case 2: + h += *reinterpret_cast(pBuf); + h ^= h << 11; + h += h >> 17; + break; + case 3: + h += *reinterpret_cast(pBuf); + h ^= h << 16; + h ^= (static_cast(pBuf[sizeof(uint16_t)])) << 18; + h += h >> 11; + break; + default: + break; + } + + h ^= h << 3; + h += h >> 5; + h ^= h << 4; + h += h >> 17; + h ^= h << 25; + h += h >> 6; + + return h; + } + + // BC7 entropy reduction transform with Deflate/LZMA/LZHAM optimizations + bool reduce_entropy(void* pBlocks, uint32_t num_blocks, + uint32_t total_block_stride_in_bytes, uint32_t block_size_to_optimize_in_bytes, uint32_t block_width, uint32_t block_height, uint32_t num_comps, + const color_rgba* pBlock_pixels, const reduce_entropy_params& params, uint32_t& total_modified, + pUnpack_block_func pUnpack_block_func, void* pUnpack_block_func_user_data, + std::vector* pBlock_mse_scales) + { + assert(total_block_stride_in_bytes && block_size_to_optimize_in_bytes); + assert(total_block_stride_in_bytes >= block_size_to_optimize_in_bytes); + + assert(num_comps >= 1 && num_comps <= 4); + for (uint32_t i = num_comps; i < 4; i++) + { + assert(!params.m_color_weights[i]); + if (params.m_color_weights[i]) + return false; + } + + const uint32_t total_color_weight = params.m_color_weights[0] + params.m_color_weights[1] + params.m_color_weights[2] + params.m_color_weights[3]; + assert(total_color_weight); + const float one_over_total_color_weight = 1.0f / total_color_weight; + + assert((block_size_to_optimize_in_bytes >= MIN_MATCH_LEN) && (block_size_to_optimize_in_bytes <= MAX_BLOCK_SIZE_IN_BYTES)); + if ((block_size_to_optimize_in_bytes < MIN_MATCH_LEN) || (block_size_to_optimize_in_bytes > MAX_BLOCK_SIZE_IN_BYTES)) + return false; + + uint8_t* pBlock_bytes = (uint8_t*)pBlocks; + + const uint32_t total_block_pixels = block_width * block_height; + if (total_block_pixels > MAX_BLOCK_PIXELS) + return false; + + const int total_blocks_to_check = std::max(1U, params.m_lookback_window_size / total_block_stride_in_bytes); + + std::vector len_hist(MAX_BLOCK_SIZE_IN_BYTES + 1); + std::vector second_len_hist(MAX_BLOCK_SIZE_IN_BYTES + 1); + uint32_t total_second_matches = 0; + + int prev_match_window_ofs_to_favor_cont = -1, prev_match_dist_to_favor = -1; + + uint32_t total_smooth_blocks = 0; + + const uint32_t HASH_SIZE = 8192; + uint32_t hash[HASH_SIZE]; + + for (uint32_t block_index = 0; block_index < num_blocks; block_index++) + { + if ((block_index & 0xFF) == 0) + memset(hash, 0, sizeof(hash)); + + uint8_t* pOrig_block = &pBlock_bytes[block_index * total_block_stride_in_bytes]; + const color_rgba* pPixels = &pBlock_pixels[block_index * total_block_pixels]; + + color_rgba decoded_block[MAX_BLOCK_PIXELS]; + if (!(*pUnpack_block_func)(pOrig_block, decoded_block, block_index, pUnpack_block_func_user_data)) + return false; + + float cur_mse = compute_block_mse(pPixels, decoded_block, block_width, block_height, total_block_pixels, num_comps, params.m_color_weights, one_over_total_color_weight); + + if ((params.m_skip_zero_mse_blocks) && (cur_mse == 0.0f)) + continue; + + const float max_std_dev = compute_block_max_std_dev(pPixels, block_width, block_height, num_comps); + + float yl = clampf(max_std_dev / params.m_max_smooth_block_std_dev, 0.0f, 1.0f); + yl = yl * yl; + float smooth_block_mse_scale = lerp(params.m_smooth_block_max_mse_scale, 1.0f, yl); + + if (pBlock_mse_scales) + { + if ((*pBlock_mse_scales)[block_index] > 0.0f) + { + smooth_block_mse_scale = (*pBlock_mse_scales)[block_index]; + } + } + + if (smooth_block_mse_scale > 1.0f) + total_smooth_blocks++; + + float cur_bits = (LITERAL_BITS * block_size_to_optimize_in_bytes); + float cur_t = cur_mse * smooth_block_mse_scale + cur_bits * params.m_lambda; + + int first_block_to_check = std::max(0, block_index - total_blocks_to_check); + int last_block_to_check = block_index - 1; + + uint8_t best_block[MAX_BLOCK_SIZE_IN_BYTES]; + memcpy(best_block, pOrig_block, block_size_to_optimize_in_bytes); + + float best_t = cur_t; + uint32_t best_match_len = 0, best_match_src_window_ofs = 0, best_match_dst_window_ofs = 0, best_match_dst_block_ofs = 0; + [[maybe_unused]] uint32_t best_match_src_block_ofs = 0; + float best_match_bits = 0; + + // Don't let thresh_ms_err be 0 to let zero error blocks have slightly increased distortion + const float thresh_ms_err = params.m_max_allowed_rms_increase_ratio * params.m_max_allowed_rms_increase_ratio * std::max(cur_mse, 1.0f); + + for (int prev_block_index = last_block_to_check; prev_block_index >= first_block_to_check; --prev_block_index) + { + const uint8_t* pPrev_blk = &pBlock_bytes[prev_block_index * total_block_stride_in_bytes]; + + for (uint32_t len = block_size_to_optimize_in_bytes; len >= MIN_MATCH_LEN; len--) + { + if (params.m_allow_relative_movement) + { + for (uint32_t src_ofs = 0; src_ofs <= (block_size_to_optimize_in_bytes - len); src_ofs++) + { + assert(len + src_ofs <= block_size_to_optimize_in_bytes); + + const uint32_t src_match_window_ofs = prev_block_index * total_block_stride_in_bytes + src_ofs; + + for (uint32_t dst_ofs = 0; dst_ofs <= (block_size_to_optimize_in_bytes - len); dst_ofs++) + { + assert(len + dst_ofs <= block_size_to_optimize_in_bytes); + + const uint32_t dst_match_window_ofs = block_index * total_block_stride_in_bytes + dst_ofs; + + const uint32_t match_dist = dst_match_window_ofs - src_match_window_ofs; + + float trial_match_bits, trial_total_bits; + + uint32_t hs = hash_hsieh(pPrev_blk + src_ofs, len, dst_ofs); + +#if ERT_FAVOR_CONT_AND_REP0_MATCHES + // Continue a previous match (which would cross block boundaries) + if (((int)src_match_window_ofs == prev_match_window_ofs_to_favor_cont) && (dst_ofs == 0)) + { + trial_match_bits = MATCH_CONTINUE_BITS; + trial_total_bits = (block_size_to_optimize_in_bytes - len) * LITERAL_BITS + MATCH_CONTINUE_BITS; + } + // Exploit REP0 matches + else if ((prev_match_dist_to_favor != -1) && (src_match_window_ofs == (dst_match_window_ofs - prev_match_dist_to_favor))) + { + trial_match_bits = MATCH_REP0_BITS; + trial_total_bits = (block_size_to_optimize_in_bytes - len) * LITERAL_BITS + MATCH_REP0_BITS; + } + else + { + trial_match_bits = (float)compute_match_cost_estimate(match_dist, len); + trial_total_bits = (block_size_to_optimize_in_bytes - len) * LITERAL_BITS + trial_match_bits; + + uint32_t hash_check = hash[hs & (HASH_SIZE - 1)]; + if ((hash_check & 0xFF) == (block_index & 0xFF)) + { + if ((hash_check >> 8) == (hs >> 8)) + continue; + } + } +#else + uint32_t hash_check = hash[hs & (HASH_SIZE - 1)]; + if ((hash_check & 0xFF) == (block_index & 0xFF)) + { + if ((hash_check >> 8) == (hs >> 8)) + continue; + } +#endif + + hash[hs & (HASH_SIZE - 1)] = (hs & 0xFFFFFF00) | (block_index & 0xFF); + + const float trial_total_bits_times_lambda = trial_total_bits * params.m_lambda; + + uint8_t trial_block[MAX_BLOCK_SIZE_IN_BYTES]; + memcpy(trial_block, pOrig_block, block_size_to_optimize_in_bytes); + memcpy(trial_block + dst_ofs, pPrev_blk + src_ofs, len); + + color_rgba decoded_trial_block[MAX_BLOCK_PIXELS]; + if (!(*pUnpack_block_func)(trial_block, decoded_trial_block, block_index, pUnpack_block_func_user_data)) + continue; + + float trial_mse = compute_block_mse(pPixels, decoded_trial_block, block_width, block_height, total_block_pixels, num_comps, params.m_color_weights, one_over_total_color_weight); + + if (trial_mse < thresh_ms_err) + { + float t = trial_mse * smooth_block_mse_scale + trial_total_bits_times_lambda; + + if (t < best_t) + { + best_t = t; + memcpy(best_block, trial_block, block_size_to_optimize_in_bytes); + best_match_len = len; + best_match_src_window_ofs = src_match_window_ofs; + best_match_dst_window_ofs = dst_match_window_ofs; + best_match_src_block_ofs = src_ofs; + best_match_dst_block_ofs = dst_ofs; + best_match_bits = trial_match_bits; + } + } + + } // dst_ofs + } // src_ofs + } + else + { + const uint32_t match_dist = (block_index - prev_block_index) * total_block_stride_in_bytes; + + // Assume the block has 1 match and block_size_to_optimize_in_bytes-match_len literals. + const float trial_match_bits = (float)compute_match_cost_estimate(match_dist, len); + const float trial_total_bits = (block_size_to_optimize_in_bytes - len) * LITERAL_BITS + trial_match_bits; + const float trial_total_bits_times_lambda = trial_total_bits * params.m_lambda; + + for (uint32_t ofs = 0; ofs <= (block_size_to_optimize_in_bytes - len); ofs++) + { + assert(len + ofs <= block_size_to_optimize_in_bytes); + + const uint32_t dst_match_window_ofs = block_index * total_block_stride_in_bytes + ofs; + const uint32_t src_match_window_ofs = prev_block_index * total_block_stride_in_bytes + ofs; + + float trial_match_bits_to_use = trial_match_bits; + float trial_total_bits_times_lambda_to_use = trial_total_bits_times_lambda; + + uint32_t hs = hash_hsieh(pPrev_blk + ofs, len, ofs); + +#if ERT_FAVOR_CONT_AND_REP0_MATCHES + // Continue a previous match (which would cross block boundaries) + if (((int)src_match_window_ofs == prev_match_window_ofs_to_favor_cont) && (ofs == 0)) + { + float continue_match_trial_bits = (block_size_to_optimize_in_bytes - len) * LITERAL_BITS + MATCH_CONTINUE_BITS; + trial_match_bits_to_use = MATCH_CONTINUE_BITS; + trial_total_bits_times_lambda_to_use = continue_match_trial_bits * params.m_lambda; + } + // Exploit REP0 matches + else if ((prev_match_dist_to_favor != -1) && (src_match_window_ofs == (dst_match_window_ofs - prev_match_dist_to_favor))) + { + float continue_match_trial_bits = (block_size_to_optimize_in_bytes - len) * LITERAL_BITS + MATCH_REP0_BITS; + trial_match_bits_to_use = MATCH_REP0_BITS; + trial_total_bits_times_lambda_to_use = continue_match_trial_bits * params.m_lambda; + } + else + { + uint32_t hash_check = hash[hs & (HASH_SIZE - 1)]; + if ((hash_check & 0xFF) == (block_index & 0xFF)) + { + if ((hash_check >> 8) == (hs >> 8)) + continue; + } + } +#else + uint32_t hash_check = hash[hs & (HASH_SIZE - 1)]; + if ((hash_check & 0xFF) == (block_index & 0xFF)) + { + if ((hash_check >> 8) == (hs >> 8)) + continue; + } +#endif + + hash[hs & (HASH_SIZE - 1)] = (hs & 0xFFFFFF00) | (block_index & 0xFF); + + uint8_t trial_block[MAX_BLOCK_SIZE_IN_BYTES]; + memcpy(trial_block, pOrig_block, block_size_to_optimize_in_bytes); + memcpy(trial_block + ofs, pPrev_blk + ofs, len); + + color_rgba decoded_trial_block[MAX_BLOCK_PIXELS]; + if (!(*pUnpack_block_func)(trial_block, decoded_trial_block, block_index, pUnpack_block_func_user_data)) + continue; + + float trial_mse = compute_block_mse(pPixels, decoded_trial_block, block_width, block_height, total_block_pixels, num_comps, params.m_color_weights, one_over_total_color_weight); + + if (trial_mse < thresh_ms_err) + { + float t = trial_mse * smooth_block_mse_scale + trial_total_bits_times_lambda_to_use; + + if (t < best_t) + { + best_t = t; + memcpy(best_block, trial_block, block_size_to_optimize_in_bytes); + best_match_len = len; + best_match_src_window_ofs = src_match_window_ofs; + best_match_dst_window_ofs = dst_match_window_ofs; + best_match_src_block_ofs = ofs; + best_match_dst_block_ofs = ofs; + best_match_bits = trial_match_bits_to_use; + } + } + } // ofs + } + + } // len + + } // prev_block_index + + if (best_t < cur_t) + { + uint32_t best_second_match_len = 0, best_second_match_src_window_ofs = 0, best_second_match_dst_window_ofs = 0, best_second_match_dst_block_ofs = 0; + [[maybe_unused]] uint32_t best_second_match_src_block_ofs = 0; + + // Try injecting a second match, being sure it does't overlap with the first. + if ((params.m_try_two_matches) && (best_match_len <= (block_size_to_optimize_in_bytes - 3))) + { + uint8_t matched_flags[MAX_BLOCK_SIZE_IN_BYTES]; + memset(matched_flags, 0, sizeof(matched_flags)); + memset(matched_flags + best_match_dst_block_ofs, 1, best_match_len); + + uint8_t orig_best_block[MAX_BLOCK_SIZE_IN_BYTES]; + memcpy(orig_best_block, best_block, block_size_to_optimize_in_bytes); + + for (int prev_block_index = last_block_to_check; prev_block_index >= first_block_to_check; --prev_block_index) + { + const uint8_t* pPrev_blk = &pBlock_bytes[prev_block_index * total_block_stride_in_bytes]; + + const uint32_t match_dist = (block_index - prev_block_index) * total_block_stride_in_bytes; + + for (uint32_t len = 3; len <= (block_size_to_optimize_in_bytes - best_match_len); len++) + { + const float trial_total_bits = (block_size_to_optimize_in_bytes - len - best_match_len) * LITERAL_BITS + compute_match_cost_estimate(match_dist, len) + best_match_bits; + + const float trial_total_bits_times_lambda = trial_total_bits * params.m_lambda; + + for (uint32_t ofs = 0; ofs <= (block_size_to_optimize_in_bytes - len); ofs++) + { + int i; + for (i = 0; i < (int)len; i++) + if (matched_flags[ofs + i]) + break; + if (i != (int)len) + continue; + + assert(len + ofs <= block_size_to_optimize_in_bytes); + + const uint32_t dst_match_window_ofs = block_index * total_block_stride_in_bytes + ofs; + const uint32_t src_match_window_ofs = prev_block_index * total_block_stride_in_bytes + ofs; + + uint8_t trial_block[MAX_BLOCK_SIZE_IN_BYTES]; + memcpy(trial_block, orig_best_block, block_size_to_optimize_in_bytes); + memcpy(trial_block + ofs, pPrev_blk + ofs, len); + + color_rgba decoded_trial_block[MAX_BLOCK_PIXELS]; + if (!(*pUnpack_block_func)(trial_block, decoded_trial_block, block_index, pUnpack_block_func_user_data)) + continue; + + float trial_mse = compute_block_mse(pPixels, decoded_trial_block, block_width, block_height, total_block_pixels, num_comps, params.m_color_weights, one_over_total_color_weight); + + if (trial_mse < thresh_ms_err) + { + float t = trial_mse * smooth_block_mse_scale + trial_total_bits_times_lambda; + + if (t < best_t) + { + best_t = t; + memcpy(best_block, trial_block, block_size_to_optimize_in_bytes); + best_second_match_len = len; + best_second_match_src_window_ofs = src_match_window_ofs; + best_second_match_dst_window_ofs = dst_match_window_ofs; + best_second_match_src_block_ofs = ofs; + best_second_match_dst_block_ofs = ofs; + } + } + } + } + } + } + + memcpy(pOrig_block, best_block, block_size_to_optimize_in_bytes); + total_modified++; + + if ((best_second_match_len == 0) || (best_match_dst_window_ofs > best_second_match_dst_window_ofs)) + { + int best_match_dist = best_match_dst_window_ofs - best_match_src_window_ofs; + assert(best_match_dist >= 1); + (void)best_match_dist; + + if (block_size_to_optimize_in_bytes == total_block_stride_in_bytes) + { + // If the match goes all the way to the end of a block, we can try to continue it on the next encoded block. + if ((best_match_dst_block_ofs + best_match_len) == total_block_stride_in_bytes) + prev_match_window_ofs_to_favor_cont = best_match_src_window_ofs + best_match_len; + else + prev_match_window_ofs_to_favor_cont = -1; + } + +#if ERT_FAVOR_REP0_MATCHES + // Compute the window offset where a cheaper REP0 match would be available + prev_match_dist_to_favor = best_match_dist; +#endif + } + else + { + int best_match_dist = best_second_match_dst_window_ofs - best_second_match_src_window_ofs; + assert(best_match_dist >= 1); + (void)best_match_dist; + + if (block_size_to_optimize_in_bytes == total_block_stride_in_bytes) + { + // If the match goes all the way to the end of a block, we can try to continue it on the next encoded block. + if ((best_second_match_dst_block_ofs + best_second_match_len) == total_block_stride_in_bytes) + prev_match_window_ofs_to_favor_cont = best_second_match_src_window_ofs + best_second_match_len; + else + prev_match_window_ofs_to_favor_cont = -1; + } + +#if ERT_FAVOR_REP0_MATCHES + // Compute the window offset where a cheaper REP0 match would be available + prev_match_dist_to_favor = best_match_dist; +#endif + } + + len_hist[best_match_len]++; + + if (best_second_match_len) + { + second_len_hist[best_second_match_len]++; + total_second_matches++; + } + } + else + { + prev_match_window_ofs_to_favor_cont = -1; + } + + } // block_index + + if (params.m_debug_output) + { + printf("Total smooth blocks: %3.2f%%\n", total_smooth_blocks * 100.0f / num_blocks); + + printf("Match length histogram:\n"); + for (uint32_t i = MIN_MATCH_LEN; i <= block_size_to_optimize_in_bytes; i++) + printf("%u%c", len_hist[i], (i < block_size_to_optimize_in_bytes) ? ',' : '\n'); + + printf("Total second matches: %u %3.2f%%\n", total_second_matches, total_second_matches * 100.0f / num_blocks); + printf("Secod match length histogram:\n"); + for (uint32_t i = MIN_MATCH_LEN; i <= block_size_to_optimize_in_bytes; i++) + printf("%u%c", second_len_hist[i], (i < block_size_to_optimize_in_bytes) ? ',' : '\n'); + } + + return true; + } + +} // namespace ert diff --git a/external/bc7enc_rdo/ert.h b/external/bc7enc_rdo/ert.h new file mode 100644 index 0000000000..fc6b47e70d --- /dev/null +++ b/external/bc7enc_rdo/ert.h @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ert +{ + struct color_rgba { uint8_t m_c[4]; }; + + struct reduce_entropy_params + { + // m_lambda: The post-processor tries to reduce distortion*smooth_block_scale + rate*lambda (rate is approximate LZ bits and distortion is scaled MS error multiplied against the smooth block MSE weighting factor). + // Larger values push the postprocessor towards optimizing more for lower rate, and smaller values more for distortion. 0=minimal distortion. + float m_lambda; + + // m_lookback_window_size: The number of bytes the encoder can look back from each block to find matches. The larger this value, the slower the encoder but the higher the quality per LZ compressed bit. + uint32_t m_lookback_window_size; + + // m_max_allowed_rms_increase_ratio: How much the RMS error of a block is allowed to increase before a trial is rejected. 1.0=no increase allowed, 1.05=5% increase allowed, etc. + float m_max_allowed_rms_increase_ratio; + + float m_max_smooth_block_std_dev; + float m_smooth_block_max_mse_scale; + + uint32_t m_color_weights[4]; + + bool m_try_two_matches; + bool m_allow_relative_movement; + bool m_skip_zero_mse_blocks; + bool m_debug_output; + + reduce_entropy_params() { clear(); } + + void clear() + { + m_lookback_window_size = 256; + m_lambda = 1.0f; + m_max_allowed_rms_increase_ratio = 10.0f; + m_max_smooth_block_std_dev = 18.0f; + m_smooth_block_max_mse_scale = 10.0f; + m_color_weights[0] = 1; + m_color_weights[1] = 1; + m_color_weights[2] = 1; + m_color_weights[3] = 1; + m_try_two_matches = false; + m_allow_relative_movement = false; + m_skip_zero_mse_blocks = false; + m_debug_output = false; + } + + void print() + { + printf("lambda: %f\n", m_lambda); + printf("Lookback window size: %u\n", m_lookback_window_size); + printf("Max allowed RMS increase ratio: %f\n", m_max_allowed_rms_increase_ratio); + printf("Max smooth block std dev: %f\n", m_max_smooth_block_std_dev); + printf("Smooth block max MSE scale: %f\n", m_smooth_block_max_mse_scale); + printf("Color weights: %u %u %u %u\n", m_color_weights[0], m_color_weights[1], m_color_weights[2], m_color_weights[3]); + printf("Try two matches: %u\n", m_try_two_matches); + printf("Allow relative movement: %u\n", m_allow_relative_movement); + printf("Skip zero MSE blocks: %u\n", m_skip_zero_mse_blocks); + } + }; + + typedef bool (*pUnpack_block_func)(const void* pBlock, color_rgba* pPixels, uint32_t block_index, void* pUser_data); + + // BC7 entropy reduction transform with Deflate/LZMA/LZHAM optimizations + bool reduce_entropy(void* pBlocks, uint32_t num_blocks, + uint32_t total_block_stride_in_bytes, uint32_t block_size_to_optimize_in_bytes, uint32_t block_width, uint32_t block_height, uint32_t num_comps, + const color_rgba* pBlock_pixels, const reduce_entropy_params& params, uint32_t& total_modified, + pUnpack_block_func pUnpack_block_func, void* pUnpack_block_func_user_data, + std::vector* pBlock_mse_scales = nullptr); + +} // namespace ert diff --git a/external/bc7enc_rdo/rgbcx.cpp b/external/bc7enc_rdo/rgbcx.cpp new file mode 100644 index 0000000000..d989ed094d --- /dev/null +++ b/external/bc7enc_rdo/rgbcx.cpp @@ -0,0 +1,3083 @@ +// rgbcx.cpp - see license at end of rgbcx.h +#include "rgbcx.h" +#include +#include +#include + +namespace rgbcx +{ + [[maybe_unused]] const uint8_t g_bc1_to_linear[4] = { 0, 3, 1, 2 }; + + const uint32_t NUM_UNIQUE_TOTAL_ORDERINGS4 = 969; + +#ifdef _MSC_VER +#pragma region +#endif + // All total orderings for 16 pixels 2-bit selectors. + // BC1 selector order 0, 2, 3, 1 (i.e. the selectors are reordered into linear order). + static uint8_t g_unique_total_orders4[NUM_UNIQUE_TOTAL_ORDERINGS4][4] = + { + {0,8,2,6},{4,3,9,0},{4,8,1,3},{12,0,3,1},{11,3,2,0},{6,4,6,0},{7,5,0,4},{6,0,8,2},{1,0,0,15},{3,0,8,5},{1,1,13,1},{13,1,2,0},{0,14,1,1},{0,15,1,0},{0,13,0,3},{16,0,0,0},{4,3,4,5},{8,6,0,2},{0,10,0,6},{10,0,4,2},{7,2,1,6},{4,7,5,0},{1,4,7,4},{0,14,2,0},{2,7,2,5},{9,0,5,2},{9,2,2,3},{10,0,5,1},{2,3,7,4},{4,9,0,3},{1,5,0,10},{1,1,6,8}, + {6,6,4,0},{11,5,0,0},{11,2,0,3},{4,0,10,2},{2,3,10,1},{1,13,1,1},{0,14,0,2},{2,3,3,8},{12,3,1,0},{14,0,0,2},{9,1,3,3},{6,4,0,6},{1,1,5,9},{5,9,0,2},{2,10,1,3},{12,0,0,4},{4,6,6,0},{0,6,4,6},{3,7,4,2},{0,13,3,0},{3,10,0,3},{10,2,1,3},{1,12,1,2},{2,0,13,1},{11,0,5,0},{12,1,3,0},{6,4,5,1},{10,4,2,0},{3,6,1,6},{7,3,6,0},{10,4,0,2},{10,0,2,4}, + {0,5,9,2},{0,9,3,4},{6,4,2,4},{3,4,7,2},{3,3,5,5},{4,2,9,1},{6,2,8,0},{3,5,3,5},{4,10,1,1},{10,1,3,2},{5,7,0,4},{5,3,7,1},{6,8,1,1},{8,8,0,0},{11,1,0,4},{14,1,0,1},{9,3,2,2},{8,2,1,5},{0,0,2,14},{3,3,9,1},{10,1,5,0},{8,3,1,4},{1,5,8,2},{6,1,9,0},{3,2,1,10},{3,11,1,1},{7,6,3,0},{9,0,3,4},{5,2,5,4},{0,2,3,11},{15,0,0,1},{0,6,6,4}, + {3,4,9,0},{4,7,0,5},{0,4,4,8},{0,13,2,1},{2,4,1,9},{3,2,5,6},{10,6,0,0},{3,5,6,2},{8,0,4,4},{1,3,6,6},{7,7,0,2},{6,1,4,5},{0,11,1,4},{2,2,8,4},{0,1,2,13},{15,0,1,0},{7,2,6,1},{8,1,7,0},{1,8,4,3},{2,13,1,0},{1,0,7,8},{14,2,0,0},{1,8,1,6},{9,3,3,1},{0,0,7,9},{4,4,1,7},{9,0,6,1},{10,2,4,0},{1,7,3,5},{0,3,8,5},{5,2,4,5},{1,2,5,8}, + {0,8,7,1},{10,3,2,1},{12,0,4,0},{2,1,4,9},{5,2,2,7},{1,9,3,3},{15,1,0,0},{6,3,4,3},{9,5,0,2},{1,6,9,0},{6,6,0,4},{13,2,1,0},{5,1,8,2},{0,5,11,0},{7,1,0,8},{1,2,12,1},{0,3,3,10},{7,4,2,3},{5,1,4,6},{7,0,3,6},{3,12,0,1},{3,4,5,4},{1,10,0,5},{7,4,3,2},{10,5,0,1},{13,3,0,0},{2,5,4,5},{3,10,1,2},{5,1,2,8},{14,0,1,1},{1,5,4,6},{1,4,5,6}, + {2,3,11,0},{11,0,4,1},{11,2,2,1},{5,3,8,0},{1,3,10,2},{0,1,13,2},{3,1,4,8},{4,2,4,6},{1,5,6,4},{2,1,11,2},{1,2,9,4},{4,7,3,2},{6,2,5,3},{7,2,2,5},{8,1,4,3},{3,2,8,3},{12,1,0,3},{7,8,1,0},{7,0,2,7},{5,10,0,1},{0,2,14,0},{2,9,3,2},{7,0,0,9},{11,1,4,0},{10,4,1,1},{2,2,9,3},{5,7,2,2},{1,3,1,11},{13,2,0,1},{4,2,8,2},{2,3,1,10},{4,2,5,5}, + {7,0,7,2},{10,0,0,6},{0,8,5,3},{4,4,0,8},{12,4,0,0},{0,1,14,1},{8,0,1,7},{5,1,5,5},{11,0,3,2},{0,4,1,11},{0,8,8,0},{0,2,5,9},{7,3,2,4},{7,8,0,1},{1,0,3,12},{7,4,5,0},{1,6,7,2},{7,6,1,2},{9,6,1,0},{12,2,0,2},{4,1,6,5},{4,0,1,11},{8,4,4,0},{13,0,1,2},{8,6,2,0},{4,12,0,0},{2,7,5,2},{2,0,5,9},{5,4,5,2},{3,8,5,0},{7,3,3,3},{4,4,8,0}, + {2,1,3,10},{5,0,1,10},{6,4,3,3},{4,9,1,2},{1,4,0,11},{11,3,1,1},{4,0,12,0},{13,0,0,3},{6,1,6,3},{9,0,4,3},{8,0,0,8},{8,4,0,4},{0,12,1,3},{0,4,10,2},{3,4,8,1},{1,3,8,4},{9,2,5,0},{5,7,4,0},{1,0,11,4},{4,10,0,2},{1,3,12,0},{6,9,0,1},{5,0,9,2},{5,9,2,0},{13,1,0,2},{9,3,4,0},{9,4,0,3},{3,1,12,0},{2,4,3,7},{1,2,13,0},{2,2,4,8},{6,8,0,2}, + {9,2,1,4},{9,5,1,1},{2,0,4,10},{5,4,0,7},{0,0,6,10},{1,2,0,13},{4,7,2,3},{6,5,5,0},{3,3,1,9},{1,6,1,8},{12,2,1,1},{4,4,5,3},{1,0,6,9},{0,6,10,0},{4,8,3,1},{4,3,2,7},{2,1,7,6},{1,9,1,5},{3,1,3,9},{8,7,1,0},{1,2,3,10},{14,1,1,0},{5,4,4,3},{3,7,0,6},{7,4,1,4},{3,7,5,1},{1,1,0,14},{0,10,3,3},{0,4,3,9},{1,7,7,1},{2,0,10,4},{5,8,0,3}, + {6,7,3,0},{0,8,4,4},{5,7,3,1},{7,9,0,0},{7,6,2,1},{0,4,5,7},{6,3,5,2},{1,2,1,12},{5,2,0,9},{8,5,0,3},{4,6,1,5},{1,1,7,7},{10,5,1,0},{1,2,8,5},{1,8,2,5},{5,1,0,10},{6,9,1,0},{13,0,2,1},{8,3,5,0},{6,3,6,1},{2,11,3,0},{3,7,3,3},{1,5,2,8},{7,5,2,2},{0,6,7,3},{13,1,1,1},{5,3,4,4},{7,2,7,0},{5,8,3,0},{3,13,0,0},{0,7,9,0},{8,0,3,5}, + {1,3,7,5},{4,0,2,10},{12,0,1,3},{1,7,6,2},{3,9,0,4},{7,2,0,7},{0,1,7,8},{2,1,8,5},{0,13,1,2},{0,8,1,7},{5,0,11,0},{5,6,2,3},{0,3,0,13},{2,3,4,7},{5,6,3,2},{4,2,10,0},{3,3,7,3},{7,2,5,2},{1,1,11,3},{12,3,0,1},{5,1,1,9},{1,15,0,0},{9,7,0,0},{9,1,2,4},{0,7,3,6},{3,0,13,0},{3,0,11,2},{0,6,5,5},{8,2,2,4},{6,10,0,0},{4,8,4,0},{0,0,3,13}, + {0,4,12,0},{7,1,6,2},{3,5,0,8},{8,0,6,2},{6,2,3,5},{2,10,0,4},{4,11,0,1},{6,1,5,4},{5,1,3,7},{0,11,3,2},{4,6,0,6},{2,6,0,8},{3,1,7,5},{2,14,0,0},{2,9,2,3},{0,3,4,9},{11,0,1,4},{13,0,3,0},{8,3,0,5},{0,5,3,8},{5,11,0,0},{0,1,4,11},{2,1,9,4},{3,4,4,5},{7,1,2,6},{12,2,2,0},{9,4,1,2},{6,0,2,8},{4,6,2,4},{11,2,3,0},{3,2,2,9},{10,3,1,2}, + {1,1,2,12},{0,5,2,9},{0,1,11,4},{6,2,4,4},{2,8,2,4},{0,9,4,3},{11,0,2,3},{0,2,11,3},{6,0,7,3},{0,3,6,7},{4,5,5,2},{1,2,6,7},{7,5,1,3},{9,0,2,5},{2,6,4,4},{4,1,9,2},{4,8,2,2},{1,12,3,0},{0,9,6,1},{0,10,6,0},{3,1,5,7},{2,13,0,1},{2,2,1,11},{3,6,0,7},{5,6,5,0},{5,5,4,2},{4,0,3,9},{3,4,1,8},{0,11,2,3},{2,12,1,1},{7,1,3,5},{7,0,9,0}, + {8,0,8,0},{1,0,2,13},{3,3,10,0},{2,4,4,6},{2,3,8,3},{1,10,5,0},{7,3,0,6},{2,9,0,5},{1,4,6,5},{6,6,3,1},{5,6,0,5},{6,3,0,7},{3,10,2,1},{2,5,5,4},{3,8,4,1},{1,14,0,1},{10,3,3,0},{3,5,7,1},{1,1,3,11},{2,4,0,10},{9,3,1,3},{5,10,1,0},{3,0,6,7},{3,1,9,3},{11,2,1,2},{5,3,3,5},{0,5,1,10},{4,1,11,0},{10,2,0,4},{7,6,0,3},{2,7,0,7},{4,2,2,8}, + {6,1,7,2},{4,9,2,1},{0,0,8,8},{3,7,2,4},{9,6,0,1},{0,12,4,0},{6,7,1,2},{0,7,2,7},{1,0,10,5},{0,0,14,2},{2,7,3,4},{5,0,0,11},{7,7,1,1},{6,2,7,1},{4,5,3,4},{3,5,1,7},{5,9,1,1},{6,2,1,7},{3,2,0,11},{0,11,0,5},{3,11,2,0},{10,1,4,1},{7,0,4,5},{11,4,0,1},{10,3,0,3},{0,2,4,10},{0,15,0,1},{0,11,5,0},{6,7,2,1},{1,12,2,1},{4,1,3,8},{1,0,13,2}, + {1,8,5,2},{7,0,1,8},{3,12,1,0},{9,2,4,1},{1,7,4,4},{11,4,1,0},{4,3,8,1},{2,8,4,2},{1,11,3,1},{1,1,4,10},{4,10,2,0},{8,2,5,1},{1,0,9,6},{5,3,2,6},{0,9,7,0},{10,2,2,2},{5,8,1,2},{8,7,0,1},{0,3,12,1},{1,0,1,14},{4,8,0,4},{3,8,0,5},{4,6,5,1},{0,9,5,2},{10,2,3,1},{2,3,9,2},{1,0,12,3},{11,3,0,2},{4,5,2,5},{0,2,12,2},{9,1,0,6},{9,2,0,5}, + {1,2,7,6},{4,7,4,1},{0,12,2,2},{0,0,0,16},{2,8,3,3},{3,6,2,5},{0,6,3,7},{7,5,4,0},{3,3,3,7},{3,3,0,10},{5,0,6,5},{0,0,10,6},{8,5,3,0},{8,1,5,2},{6,0,9,1},{11,1,2,2},{2,11,2,1},{9,5,2,0},{3,0,4,9},{2,2,12,0},{2,6,6,2},{2,1,13,0},{6,0,5,5},{2,0,14,0},{2,11,1,2},{4,4,7,1},{2,0,11,3},{3,1,1,11},{2,9,4,1},{3,7,6,0},{14,0,2,0},{1,10,4,1}, + {8,0,7,1},{3,6,5,2},{0,3,11,2},{2,5,6,3},{11,1,3,1},{6,5,3,2},{3,8,1,4},{0,2,7,7},{2,10,2,2},{1,6,2,7},{11,0,0,5},{12,1,1,2},{12,1,2,1},{0,7,1,8},{0,3,9,4},{0,2,1,13},{7,1,4,4},{10,1,0,5},{4,0,8,4},{5,2,7,2},{0,2,0,14},{4,3,7,2},{2,7,1,6},{1,2,2,11},{6,3,3,4},{1,14,1,0},{2,4,6,4},{5,3,6,2},{5,3,5,3},{8,4,1,3},{1,3,0,12},{3,5,2,6}, + {1,8,7,0},{0,7,4,5},{2,1,6,7},{4,11,1,0},{7,2,4,3},{6,1,3,6},{4,5,4,3},{2,11,0,3},{1,5,7,3},{12,0,2,2},{5,0,4,7},{1,13,0,2},{7,7,2,0},{4,1,7,4},{4,5,0,7},{5,0,5,6},{6,5,4,1},{2,4,2,8},{1,10,1,4},{6,3,1,6},{3,3,8,2},{0,7,7,2},{4,4,2,6},{1,1,8,6},{1,12,0,3},{2,1,12,1},{1,9,2,4},{1,11,0,4},{2,5,2,7},{10,0,3,3},{4,6,3,3},{3,7,1,5}, + {1,9,0,6},{7,1,7,1},{1,6,5,4},{9,2,3,2},{6,2,2,6},{2,2,2,10},{8,3,3,2},{0,1,8,7},{2,0,8,6},{0,3,1,12},{9,4,2,1},{9,4,3,0},{6,2,6,2},{1,8,0,7},{5,1,10,0},{0,5,5,6},{8,2,4,2},{2,3,2,9},{6,0,3,7},{2,2,6,6},{2,6,2,6},{1,13,2,0},{9,3,0,4},{7,3,5,1},{6,5,2,3},{5,2,6,3},{2,0,12,2},{5,7,1,3},{8,1,3,4},{3,1,10,2},{1,0,15,0},{0,8,0,8}, + {5,0,7,4},{4,4,6,2},{0,1,0,15},{10,0,1,5},{7,3,4,2},{4,9,3,0},{2,5,7,2},{3,4,2,7},{8,3,2,3},{5,1,6,4},{0,10,2,4},{6,6,1,3},{6,0,0,10},{4,4,3,5},{1,3,9,3},{7,5,3,1},{3,0,7,6},{1,8,6,1},{4,3,0,9},{3,11,0,2},{6,0,6,4},{0,1,3,12},{0,4,2,10},{5,5,6,0},{4,1,4,7},{8,1,6,1},{5,6,4,1},{8,4,2,2},{4,3,1,8},{3,0,2,11},{1,11,4,0},{0,8,3,5}, + {5,1,7,3},{7,0,8,1},{4,3,5,4},{4,6,4,2},{3,2,4,7},{1,6,3,6},{0,7,8,1},{3,0,1,12},{9,1,4,2},{7,4,0,5},{1,7,0,8},{5,4,1,6},{9,1,5,1},{1,1,9,5},{4,1,1,10},{5,3,0,8},{2,2,5,7},{4,0,0,12},{9,0,7,0},{3,4,0,9},{0,2,6,8},{8,2,0,6},{3,2,6,5},{4,2,6,4},{3,6,4,3},{2,8,6,0},{5,0,3,8},{0,4,0,12},{0,16,0,0},{0,9,2,5},{4,0,11,1},{1,6,4,5}, + {0,1,6,9},{3,4,6,3},{3,0,10,3},{7,0,6,3},{1,4,9,2},{1,5,3,7},{8,5,2,1},{0,12,0,4},{7,2,3,4},{0,5,6,5},{11,1,1,3},{6,5,0,5},{2,1,5,8},{1,4,11,0},{9,1,1,5},{0,0,13,3},{5,8,2,1},{2,12,0,2},{3,3,6,4},{4,1,10,1},{4,0,5,7},{8,1,0,7},{5,1,9,1},{4,3,3,6},{0,2,2,12},{6,3,2,5},{0,0,12,4},{1,5,1,9},{2,6,5,3},{3,6,3,4},{2,12,2,0},{1,6,8,1}, + {10,1,1,4},{1,3,4,8},{7,4,4,1},{1,11,1,3},{1,2,10,3},{3,9,3,1},{8,5,1,2},{2,10,4,0},{4,2,0,10},{2,7,6,1},{8,2,3,3},{1,5,5,5},{3,1,0,12},{3,10,3,0},{8,0,5,3},{0,6,8,2},{0,3,13,0},{0,0,16,0},{1,9,4,2},{4,1,8,3},{1,6,6,3},{0,10,5,1},{0,1,12,3},{4,0,6,6},{3,8,3,2},{0,5,4,7},{1,0,14,1},{0,4,6,6},{3,9,1,3},{3,5,8,0},{3,6,6,1},{5,4,7,0}, + {3,0,12,1},{8,6,1,1},{2,9,5,0},{6,1,1,8},{4,1,2,9},{3,9,4,0},{5,2,9,0},{0,12,3,1},{1,4,10,1},{4,0,7,5},{3,1,2,10},{5,4,2,5},{5,5,5,1},{4,2,3,7},{1,7,5,3},{2,8,0,6},{8,1,2,5},{3,8,2,3},{6,1,2,7},{3,9,2,2},{9,0,0,7},{0,8,6,2},{8,4,3,1},{0,2,8,6},{6,5,1,4},{2,3,5,6},{2,10,3,1},{0,7,0,9},{4,2,7,3},{2,4,8,2},{7,1,1,7},{2,4,7,3}, + {2,4,10,0},{0,1,10,5},{4,7,1,4},{0,10,4,2},{9,0,1,6},{1,9,6,0},{3,3,4,6},{4,5,7,0},{5,5,2,4},{2,8,1,5},{2,3,6,5},{0,1,1,14},{3,2,3,8},{10,1,2,3},{9,1,6,0},{3,4,3,6},{2,2,0,12},{0,0,9,7},{4,0,9,3},{7,0,5,4},{4,5,6,1},{2,5,1,8},{2,5,9,0},{3,5,4,4},{1,3,11,1},{7,1,5,3},{3,2,7,4},{1,4,2,9},{1,11,2,2},{2,2,3,9},{5,0,10,1},{3,2,11,0}, + {1,10,3,2},{8,3,4,1},{3,6,7,0},{0,7,5,4},{1,3,3,9},{2,2,10,2},{1,9,5,1},{0,5,0,11},{3,0,3,10},{0,4,8,4},{2,7,7,0},{2,0,2,12},{1,2,11,2},{6,3,7,0},{0,6,2,8},{0,10,1,5},{0,9,0,7},{6,4,4,2},{6,0,1,9},{1,5,10,0},{5,4,6,1},{5,5,3,3},{0,0,4,12},{0,3,2,11},{1,4,1,10},{3,0,9,4},{5,5,0,6},{1,7,8,0},{2,0,3,11},{6,4,1,5},{10,0,6,0},{0,6,0,10}, + {0,4,11,1},{3,1,6,6},{2,5,8,1},{0,2,10,4},{3,1,11,1},{6,6,2,2},{1,1,10,4},{2,1,2,11},{6,1,8,1},{0,2,13,1},{0,7,6,3},{6,8,2,0},{3,0,0,13},{4,4,4,4},{6,2,0,8},{7,3,1,5},{0,11,4,1},{6,7,0,3},{2,6,3,5},{5,2,1,8},{7,1,8,0},{5,5,1,5},{1,8,3,4},{8,2,6,0},{6,0,10,0},{5,6,1,4},{1,4,4,7},{2,7,4,3},{1,4,8,3},{5,4,3,4},{1,10,2,3},{2,9,1,4}, + {2,2,11,1},{2,5,0,9},{0,0,1,15},{0,0,11,5},{0,4,7,5},{0,1,15,0},{2,1,0,13},{0,3,10,3},{8,0,2,6},{3,3,2,8},{3,5,5,3},{1,7,1,7},{1,3,2,10},{4,0,4,8},{2,0,9,5},{1,1,1,13},{2,2,7,5},{2,1,10,3},{4,2,1,9},{4,3,6,3},{1,3,5,7},{2,5,3,6},{1,0,8,7},{5,0,2,9},{2,8,5,1},{1,6,0,9},{0,0,5,11},{0,4,9,3},{2,0,7,7},{1,7,2,6},{2,1,1,12},{2,4,9,1}, + {0,5,7,4},{6,0,4,6},{3,2,10,1},{0,6,1,9},{2,6,1,7},{0,5,8,3},{4,1,0,11},{1,2,4,9},{4,1,5,6},{6,1,0,9},{1,4,3,8},{4,5,1,6},{1,0,5,10},{5,3,1,7},{0,9,1,6},{2,0,1,13},{2,0,6,8},{8,1,1,6},{1,5,9,1},{0,6,9,1},{0,3,5,8},{0,2,9,5},{5,2,8,1},{1,1,14,0},{3,2,9,2},{5,0,8,3},{0,5,10,1},{5,2,3,6},{2,6,7,1},{2,3,0,11},{0,1,9,6},{1,0,4,11}, + {3,0,5,8},{0,0,15,1},{2,4,5,5},{0,3,7,6},{2,0,0,14},{1,1,12,2},{2,6,8,0},{3,1,8,4},{0,1,5,10} + }; + + // All total orderings for 16 pixels [0,2] 2-bit selectors. + // BC1 selector order: 0, 1, 2 + // Note this is different from g_unique_total_orders4[], which reorders the selectors into linear order. + const uint32_t NUM_UNIQUE_TOTAL_ORDERINGS3 = 153; + static uint8_t g_unique_total_orders3[NUM_UNIQUE_TOTAL_ORDERINGS3][3] = + { + {6,0,10},{3,6,7},{3,0,13},{13,3,0},{12,4,0},{9,1,6},{2,13,1},{4,7,5},{7,5,4},{9,6,1},{7,4,5},{8,6,2},{16,0,0},{10,6,0},{2,7,7}, + {0,0,16},{0,3,13},{1,15,0},{0,2,14},{1,4,11},{15,1,0},{1,12,3},{9,2,5},{14,1,1},{8,2,6},{3,3,10},{4,2,10},{14,0,2},{0,14,2},{1,7,8},{6,6,4}, + {11,5,0},{6,4,6},{11,3,2},{4,3,9},{7,1,8},{10,4,2},{12,1,3},{11,0,5},{9,3,4},{1,0,15},{9,0,7},{2,6,8},{12,2,2},{6,2,8},{6,8,2},{15,0,1}, + {4,8,4},{0,4,12},{8,5,3},{5,9,2},{11,2,3},{12,3,1},{6,3,7},{1,1,14},{2,9,5},{1,8,7},{4,10,2},{7,7,2},{13,1,2},{0,15,1},{3,2,11},{7,0,9}, + {4,4,8},{3,8,5},{0,5,11},{13,2,1},{1,10,5},{4,11,1},{3,10,3},{5,10,1},{10,2,4},{0,6,10},{14,2,0},{11,4,1},{3,12,1},{1,13,2},{1,5,10},{5,11,0}, + {12,0,4},{8,1,7},{6,10,0},{3,13,0},{7,2,7},{0,7,9},{5,8,3},{0,12,4},{11,1,4},{13,0,3},{0,16,0},{5,7,4},{10,3,3},{10,0,6},{0,13,3},{4,6,6}, + {2,8,6},{2,5,9},{7,8,1},{2,1,13},{2,0,14},{7,3,6},{5,1,10},{3,11,2},{5,4,7},{8,3,5},{10,5,1},{6,9,1},{1,3,12},{4,5,7},{2,2,12},{4,1,11}, + {0,8,8},{4,12,0},{6,5,5},{8,7,1},{5,5,6},{3,7,6},{7,9,0},{4,9,3},{0,10,6},{8,0,8},{5,3,8},{10,1,5},{6,1,9},{7,6,3},{9,5,2},{0,1,15}, + {9,7,0},{2,14,0},{3,4,9},{8,4,4},{9,4,3},{0,9,7},{1,9,6},{3,9,4},{5,2,9},{2,3,11},{5,6,5},{1,14,1},{6,7,3},{2,4,10},{2,12,2},{8,8,0}, + {2,10,4},{4,0,12},{0,11,5},{2,11,3},{1,11,4},{3,5,8},{5,0,11},{3,1,12},{1,2,13},{1,6,9} + }; + + // For each total ordering, this table indicates which other total orderings are likely to improve quality using a least squares pass. Each array is sorted by usefulness. + static uint16_t g_best_total_orderings4[NUM_UNIQUE_TOTAL_ORDERINGS4][MAX_TOTAL_ORDERINGS4] = + { +#if RGBCX_USE_SMALLER_TABLES + #include "rgbcx_table4_small.h" +#else + #include "rgbcx_table4.h" +#endif + }; + + static uint8_t g_best_total_orderings3[NUM_UNIQUE_TOTAL_ORDERINGS3][32] = + { + { 12,1,3,5,27,2,4,38,8,7,16,18,6,10,41,79,40,23,46,9,20,88,22,37,14,19,24,126,99,119,35,11 }, + { 7,64,116,14,94,30,8,42,1,108,47,55,137,10,134,95,96,115,69,32,63,29,90,113,11,148,16,103,19,9,34,25 }, + { 12,1,0,5,3,7,4,27,8,6,38,40,41,16,18,46,9,10,20,23,79,62,14,22,88,99,37,126,92,19,120,11 }, + { 16,88,27,18,46,48,126,107,79,19,59,38,37,65,23,66,0,2,3,43,12,151,28,25,5,87,72,40,1,20,52,92 }, + { 79,48,88,16,27,65,18,38,46,19,37,4,72,33,126,41,52,0,12,92,5,1,2,107,3,77,23,91,43,51,22,74 }, + { 1,8,41,122,10,22,2,0,87,24,37,120,38,7,39,4,5,3,9,92,62,59,23,16,104,11,27,79,19,26,25,32 }, + { 2,76,99,28,40,86,93,21,138,60,6,0,17,128,145,119,98,144,141,82,147,54,67,75,5,12,27,132,146,1,38,14 }, + { 47,7,64,90,1,118,116,85,57,14,30,94,50,45,137,134,8,42,69,139,55,68,58,108,95,29,10,115,0,32,2,11 }, + { 49,8,10,30,124,11,32,113,130,58,125,9,100,53,104,115,131,103,24,7,1,39,45,36,139,0,137,22,90,44,114,105 }, + { 9,38,72,125,49,41,84,11,13,5,27,0,16,92,8,2,65,105,10,18,48,29,127,131,36,14,1,46,111,79,130,12 }, + { 130,8,10,100,104,131,49,32,53,39,30,36,113,24,11,22,124,44,83,58,7,103,1,4,9,125,5,0,91,33,115,74 }, + { 114,11,58,8,120,49,9,124,142,111,41,30,10,0,97,130,62,84,38,5,72,125,92,127,100,27,139,113,13,132,32,1 }, + { 60,46,28,27,40,20,0,17,18,2,126,16,6,38,86,23,79,54,1,93,5,88,41,14,21,111,7,48,3,84,72,62 }, + { 72,92,38,65,84,48,41,79,27,16,29,111,88,5,18,46,1,0,152,14,37,19,77,42,132,7,22,13,119,56,12,2 }, + { 7,55,1,95,29,56,64,116,143,8,14,30,47,94,152,90,65,67,10,133,42,72,146,84,16,48,6,0,25,108,77,21 }, + { 27,23,20,5,0,79,38,2,3,1,59,46,4,41,33,86,37,87,88,92,7,126,43,8,22,152,151,150,149,148,147,146 }, + { 12,0,1,2,7,6,3,5,28,4,8,14,60,40,17,19,21,86,126,93,10,18,9,29,48,99,65,25,84,119,72,41 }, + { 60,40,99,2,54,12,0,1,19,28,98,93,6,138,21,5,27,17,151,14,76,46,16,18,38,29,86,144,107,7,25,41 }, + { 12,0,1,2,3,5,6,7,4,28,8,60,14,40,16,17,21,10,19,9,86,38,126,41,93,27,29,48,62,84,79,99 }, + { 0,1,2,10,5,8,3,25,4,29,32,34,63,7,77,26,16,48,65,56,14,22,129,103,72,24,18,152,140,53,96,42 }, + { 46,126,18,54,12,16,1,0,5,2,27,98,20,23,6,3,88,48,28,7,19,8,4,60,151,38,37,21,79,14,65,40 }, + { 76,6,141,86,119,2,138,67,28,145,0,93,17,1,40,60,146,99,147,14,21,144,132,7,5,29,55,27,16,75,19,12 }, + { 71,5,51,39,22,80,0,43,10,122,8,62,41,24,104,87,35,37,2,91,33,120,36,38,1,131,9,100,130,66,3,4 }, + { 126,18,46,27,20,16,88,23,12,79,54,59,48,0,73,1,37,151,5,19,28,38,2,66,60,3,65,98,14,26,6,43 }, + { 22,10,8,5,0,71,35,80,104,39,24,51,100,1,62,32,2,130,11,41,7,9,53,43,49,83,122,120,30,44,37,38 }, + { 1,34,14,129,53,63,42,26,121,148,7,44,96,10,0,24,100,32,64,116,140,22,5,19,29,103,135,108,8,61,39,83 }, + { 1,7,34,63,44,25,135,14,24,108,22,0,83,94,5,129,35,101,47,121,2,19,42,53,6,110,103,8,148,10,16,123 }, + { 12,28,16,60,18,1,6,21,14,0,86,19,2,48,93,17,38,29,7,5,65,126,46,72,41,79,84,119,40,56,54,88 }, + { 0,2,12,27,5,46,38,40,41,79,88,99,3,23,1,62,20,4,22,37,92,35,18,8,16,24,10,60,7,120,98,54 }, + { 1,7,14,56,8,0,84,67,10,2,133,72,42,111,5,30,21,4,9,3,25,94,16,116,47,11,65,18,132,90,55,64 }, + { 30,8,124,139,45,11,58,90,113,137,7,115,10,32,1,49,94,85,9,47,108,103,0,97,63,14,50,114,53,106,100,25 }, + { 65,38,48,27,16,79,72,18,88,19,46,77,84,92,37,41,0,29,1,14,12,111,2,5,31,36,87,74,105,40,28,51 }, + { 10,8,30,113,130,100,53,32,115,103,104,7,1,121,39,49,131,44,24,36,63,137,34,45,22,90,108,83,26,11,94,139 }, + { 51,52,43,33,5,74,16,37,71,91,38,3,36,87,48,22,4,0,122,41,39,18,66,27,79,24,65,88,59,23,62,92 }, + { 1,7,63,53,108,121,94,44,103,100,14,10,129,47,32,26,24,25,148,42,135,22,0,61,83,8,39,104,5,64,115,34 }, + { 1,8,10,7,5,0,80,32,62,2,24,44,53,83,9,41,30,22,100,11,14,25,120,4,26,6,3,16,122,34,19,35 }, + { 74,4,36,48,33,91,39,79,22,16,65,5,131,38,24,71,27,52,0,105,51,18,88,104,3,31,10,37,72,19,41,130 }, + { 59,43,38,79,23,27,92,51,0,16,46,5,18,88,41,37,66,3,87,20,48,2,122,4,22,12,1,126,19,65,33,24 }, + { 12,28,1,27,0,16,2,46,65,60,21,3,5,18,6,19,48,14,4,7,79,88,86,29,22,72,93,40,23,8,17,41 }, + { 22,91,39,33,24,71,5,131,36,10,51,0,130,8,104,2,35,125,9,43,52,49,83,80,100,41,122,3,37,38,4,16 }, + { 12,0,1,2,5,3,4,8,7,27,18,38,10,6,16,46,9,20,41,23,126,79,22,14,19,99,88,54,37,48,62,35 }, + { 12,27,1,2,3,0,46,4,38,16,8,28,7,79,18,5,84,6,88,10,14,21,23,20,40,22,60,19,9,29,72,65 }, + { 1,14,7,55,95,29,8,94,30,56,10,108,77,116,152,64,32,48,63,42,143,148,16,25,137,65,11,0,115,9,19,72 }, + { 37,79,66,38,16,52,48,59,43,27,87,33,41,4,23,51,3,5,88,18,92,46,73,122,22,71,20,0,65,19,2,120 }, + { 24,32,83,22,53,1,8,10,7,30,35,5,103,0,100,101,121,113,34,123,63,2,44,25,71,115,80,14,26,108,51,39 }, + { 97,45,111,58,85,139,0,90,47,7,120,106,142,30,50,132,41,62,84,1,119,114,14,56,117,8,38,29,2,64,116,5 }, + { 12,28,16,18,1,60,6,14,2,21,0,86,126,19,48,93,7,27,17,29,5,65,54,38,72,79,84,88,119,145,8,111 }, + { 118,47,64,116,57,85,7,14,50,1,42,0,45,68,86,69,2,111,134,28,90,55,16,29,56,48,84,144,60,30,112,41 }, + { 12,1,2,0,7,6,28,5,3,4,8,14,60,21,18,40,17,86,10,9,16,29,19,93,126,79,38,84,72,27,111,119 }, + { 11,8,49,130,10,125,9,124,100,114,131,30,58,104,32,39,24,113,36,105,0,41,22,120,5,53,111,38,142,44,83,35 }, + { 50,70,47,118,85,57,106,0,45,7,64,90,81,14,2,134,28,62,86,55,69,1,78,119,68,56,18,67,16,60,29,21 }, + { 43,37,33,87,51,41,66,5,122,38,22,59,92,0,23,91,27,16,71,79,18,52,120,4,3,24,46,20,73,39,62,36 }, + { 79,48,4,16,27,88,43,33,18,38,65,37,46,3,19,51,52,22,66,87,74,5,41,91,23,59,0,71,122,72,20,92 }, + { 32,100,10,8,30,104,24,44,39,113,83,103,1,7,22,53,115,63,135,121,26,35,34,5,0,108,137,90,91,45,2,130 }, + { 0,1,2,5,16,12,6,7,14,3,19,18,29,20,4,21,40,8,17,35,23,48,126,22,25,56,26,10,98,27,38,65 }, + { 143,67,56,146,1,7,133,55,64,141,134,69,6,47,14,29,84,21,111,147,57,16,95,72,118,132,50,0,2,18,119,42 }, + { 1,7,67,14,133,111,8,84,0,21,2,47,64,132,55,10,95,147,119,42,16,5,72,56,4,3,6,29,9,25,18,30 }, + { 68,57,69,112,144,86,102,2,134,55,0,70,118,64,75,47,14,28,93,143,67,7,50,149,1,21,29,56,119,95,60,78 }, + { 58,97,114,30,124,45,11,139,8,90,0,142,7,10,41,113,84,62,49,111,85,1,9,5,137,120,32,14,2,117,47,38 }, + { 23,66,18,79,38,20,43,27,16,88,46,59,126,37,87,12,73,92,3,5,48,0,19,54,2,51,28,1,41,65,122,22 }, + { 0,12,2,27,5,40,46,38,1,41,3,79,88,23,99,4,20,62,22,54,92,18,8,37,16,35,10,7,19,120,144,24 }, + { 1,14,25,26,0,7,44,34,129,42,24,5,135,22,19,148,6,96,83,2,29,16,63,35,101,64,140,136,116,110,3,10 }, + { 12,1,2,27,3,4,38,5,7,8,18,16,46,6,0,40,41,10,79,23,88,9,20,22,14,19,37,92,48,126,28,21 }, + { 7,1,10,32,108,103,94,47,8,53,25,14,34,115,100,129,121,130,148,42,64,116,63,26,44,0,24,30,113,4,104,22 }, + { 47,134,7,14,55,69,64,95,1,29,85,118,56,116,45,57,102,143,50,90,42,30,16,94,0,8,67,75,133,2,18,48 }, + { 12,1,2,0,7,6,28,8,14,5,3,4,40,21,17,18,60,86,16,93,126,10,9,29,99,38,119,25,19,54,27,84 }, + { 59,16,27,18,23,88,79,37,46,66,38,20,73,126,3,43,48,87,92,51,41,12,19,5,52,107,65,0,151,122,54,2 }, + { 1,21,147,7,119,14,76,132,55,0,86,145,2,6,69,67,16,143,111,138,17,28,29,60,18,93,8,19,40,56,84,5 }, + { 144,86,112,2,68,102,69,0,149,93,75,28,57,55,145,60,21,67,99,134,143,40,146,119,82,110,62,6,29,26,78,14 }, + { 102,57,55,69,143,75,146,67,56,68,134,2,29,141,0,21,6,14,133,118,64,1,7,95,47,84,111,28,147,82,72,119 }, + { 0,70,57,119,50,145,2,86,28,118,69,78,149,47,60,68,67,55,93,81,134,21,14,62,64,7,5,1,132,85,41,16 }, + { 51,5,43,71,122,87,41,37,91,39,0,22,33,36,38,24,66,120,62,2,80,16,92,10,59,4,27,23,35,79,8,3 }, + { 12,1,2,0,7,6,28,5,8,14,3,21,40,4,60,17,86,18,16,93,10,9,126,119,99,29,19,41,38,27,25,92 }, + { 27,18,46,126,23,16,88,79,20,151,59,73,48,38,0,54,12,2,37,1,19,5,28,60,66,41,3,109,86,65,40,6 }, + { 48,79,4,33,16,74,65,38,88,27,91,52,18,36,22,19,46,0,37,3,51,5,71,39,72,43,24,41,92,87,2,10 }, + { 86,2,144,93,28,112,141,6,102,21,99,60,75,0,68,82,69,146,67,149,55,40,145,76,111,147,56,119,110,143,26,132 }, + { 6,138,2,99,86,17,40,93,28,21,145,141,0,60,119,147,128,76,67,54,1,12,5,27,144,14,38,98,146,41,29,19 }, + { 1,8,0,10,2,29,7,5,3,56,4,25,14,152,63,32,65,72,96,42,34,108,48,9,26,16,84,103,67,148,22,129 }, + { 149,145,0,86,2,28,93,144,62,60,119,101,21,41,5,35,78,99,26,40,12,68,57,67,110,120,69,18,55,76,132,70 }, + { 12,28,16,1,48,19,6,60,2,14,18,21,0,27,46,65,86,29,5,7,72,93,40,3,17,84,56,88,126,4,38,8 }, + { 1,8,5,10,7,24,2,62,0,41,22,122,120,9,4,3,32,87,11,37,38,83,100,44,25,104,16,26,39,80,14,6 }, + { 0,119,62,86,145,149,28,132,93,2,120,67,60,41,35,5,144,21,123,38,111,81,84,56,12,44,24,50,92,55,40,22 }, + { 2,93,99,28,40,144,60,0,86,150,76,21,149,98,6,25,1,61,82,26,12,5,54,141,7,18,145,16,27,138,110,38 }, + { 24,8,10,22,32,35,100,5,1,53,0,7,71,80,30,123,83,104,51,11,2,39,44,113,9,62,25,103,34,101,43,41 }, + { 12,1,2,0,7,6,28,5,40,60,8,16,3,18,14,4,86,21,17,93,41,10,9,99,27,119,38,19,126,22,48,145 }, + { 45,47,50,7,85,90,97,1,64,139,116,118,30,58,14,106,70,111,0,57,94,42,137,142,29,120,8,56,18,134,84,41 }, + { 12,0,2,5,27,38,1,46,41,40,79,144,3,22,88,23,28,60,99,62,6,24,26,7,4,16,10,35,37,18,14,20 }, + { 37,38,59,92,0,5,23,51,79,41,27,22,2,3,87,16,46,4,1,43,20,33,18,88,24,71,8,10,48,19,126,122 }, + { 12,28,16,60,1,18,6,21,19,14,48,0,2,86,93,5,46,29,17,27,65,7,3,72,38,126,119,40,84,37,56,4 }, + { 0,2,5,1,16,6,27,28,18,38,60,7,14,21,46,40,86,41,19,48,93,8,3,79,22,4,10,37,62,23,24,111 }, + { 85,7,90,30,47,139,45,50,94,58,137,1,8,64,14,116,118,115,113,11,124,108,0,10,97,57,32,70,42,106,29,114 }, + { 33,36,22,71,51,5,91,39,0,52,43,24,131,74,16,37,38,122,41,3,87,48,4,104,35,80,10,2,105,62,27,18 }, + { 12,1,27,2,0,16,3,28,46,18,4,6,5,72,21,79,38,7,14,60,88,8,65,19,48,29,23,40,22,20,86,126 }, + { 0,12,2,27,5,38,46,41,1,40,79,3,88,23,22,99,20,37,62,4,18,6,16,35,60,28,24,7,92,8,14,10 }, + { 7,47,1,30,137,8,116,94,90,64,14,115,108,118,57,10,148,113,42,85,32,11,63,50,103,45,124,134,55,9,69,34 }, + { 55,7,1,29,56,143,64,47,67,133,14,146,95,72,84,8,116,111,6,134,141,21,65,0,69,30,16,45,85,42,50,10 }, + { 14,1,42,8,10,29,108,63,55,148,95,32,7,19,25,115,103,34,56,129,77,0,16,152,94,30,113,26,2,5,48,4 }, + { 111,120,142,97,58,0,41,45,62,132,114,84,139,30,5,8,38,2,7,85,119,90,117,1,124,11,56,47,28,27,35,72 }, + { 1,0,14,2,6,5,16,19,7,29,42,18,3,25,12,35,21,8,26,17,40,4,20,48,109,99,22,96,55,101,10,61 }, + { 12,0,1,5,3,2,4,7,27,8,38,6,40,18,16,10,20,46,9,41,23,22,79,14,62,19,37,126,88,11,92,48 }, + { 10,8,104,39,24,32,22,83,44,100,30,130,53,91,113,5,11,1,35,33,7,49,0,2,103,71,36,124,9,80,131,34 }, + { 1,7,0,14,8,34,5,25,35,26,6,63,10,123,2,16,103,19,44,32,135,121,108,80,62,30,115,94,149,144,53,18 }, + { 75,68,146,141,102,67,2,21,6,57,69,143,0,55,82,86,28,144,147,29,93,112,56,119,133,14,76,60,84,134,111,145 }, + { 10,32,115,7,8,53,1,108,30,113,94,137,100,63,90,34,130,103,121,47,44,25,104,39,24,26,85,14,49,36,22,131 }, + { 39,24,10,22,8,130,91,104,83,49,5,33,100,11,0,35,32,131,71,36,9,44,53,2,80,51,30,1,41,7,43,62 }, + { 38,36,65,105,27,72,31,79,41,131,5,48,125,39,0,16,92,46,22,13,18,84,24,37,88,2,33,74,91,71,130,49 }, + { 0,106,62,50,45,119,85,81,132,28,2,86,41,47,38,60,35,117,5,29,7,30,145,90,55,70,14,111,18,67,93,56 }, + { 0,2,5,1,3,25,19,26,4,34,29,10,22,16,8,7,24,14,48,65,53,18,6,77,44,56,72,61,121,21,136,40 }, + { 7,1,94,8,47,115,10,32,113,103,30,108,137,63,14,64,116,148,129,42,90,25,34,118,53,57,11,49,85,9,96,50 }, + { 14,0,1,26,19,5,42,2,25,24,29,22,6,44,61,16,7,96,136,3,140,34,35,55,135,18,48,77,83,4,8,10 }, + { 1,7,14,0,25,6,34,5,26,16,63,2,19,8,35,101,108,29,94,10,18,42,123,144,129,47,61,21,3,62,149,4 }, + { 12,0,2,1,28,5,6,120,7,60,40,16,18,86,27,14,21,93,8,62,41,38,3,17,4,119,99,48,19,126,10,9 }, + { 86,144,93,2,28,149,0,60,99,112,110,145,40,21,102,26,75,62,69,1,12,101,119,25,76,67,7,68,55,5,6,14 }, + { 8,30,10,32,113,49,115,137,124,103,45,90,7,139,11,1,58,53,130,94,108,100,9,63,85,125,34,47,0,24,44,104 }, + { 120,142,111,41,58,114,97,0,11,62,84,124,5,30,8,38,132,127,27,139,92,10,72,45,49,9,28,2,29,56,16,1 }, + { 8,113,30,137,7,32,10,90,94,115,1,103,108,63,47,85,49,53,11,45,34,50,14,25,9,124,100,130,139,121,42,26 }, + { 64,7,14,47,134,55,1,42,95,69,116,90,94,30,8,29,56,137,45,108,85,10,57,16,102,143,118,19,63,32,11,50 }, + { 62,132,0,119,120,41,111,86,35,28,5,84,56,38,2,93,145,60,67,12,92,27,29,72,55,117,21,24,133,149,22,45 }, + { 57,68,69,118,134,64,50,47,55,14,7,2,102,144,0,112,70,86,85,1,95,29,116,143,42,75,16,56,28,45,21,48 }, + { 0,12,2,1,5,28,6,40,60,27,7,38,16,14,86,18,93,41,62,46,99,35,8,23,3,17,22,21,10,19,79,20 }, + { 12,1,2,27,16,3,38,111,4,0,18,5,7,46,40,8,79,6,14,28,88,10,48,41,19,84,21,9,22,23,20,72 }, + { 53,103,32,7,1,100,22,63,71,44,10,115,108,24,92,104,26,30,122,94,8,39,83,34,137,135,90,91,121,5,87,47 }, + { 87,37,41,0,22,38,2,92,1,24,4,8,3,59,10,5,39,23,71,79,122,27,16,46,33,7,91,20,18,51,9,120 }, + { 1,7,8,10,0,5,35,32,53,44,14,30,2,80,25,34,6,62,26,103,16,19,63,9,149,24,121,41,22,11,113,83 }, + { 11,58,8,30,124,49,10,113,9,114,139,45,97,32,7,137,90,1,0,130,115,125,100,24,5,94,53,41,14,13,35,38 }, + { 125,105,9,36,131,49,8,130,39,11,10,5,22,38,41,104,0,31,13,24,27,16,2,72,65,91,48,32,84,18,100,74 }, + { 12,1,0,2,6,3,7,5,4,8,14,28,16,60,18,10,21,17,19,9,40,27,86,93,29,38,54,11,25,48,46,41 }, + { 84,41,38,72,92,29,111,5,65,120,79,0,27,56,48,14,132,16,119,22,86,88,46,28,62,12,1,2,93,18,24,127 }, + { 99,28,40,60,2,93,138,0,98,17,86,54,76,12,27,1,21,144,128,38,5,14,46,18,25,16,109,6,41,145,7,29 }, + { 1,63,10,32,148,14,103,34,42,7,8,108,116,53,64,96,25,121,26,94,140,0,29,19,55,24,100,136,5,4,44,115 }, + { 131,100,130,49,10,8,36,104,39,0,48,41,11,38,4,24,27,22,16,44,79,5,33,2,53,9,125,74,91,120,32,83 }, + { 36,39,131,74,4,91,22,33,125,104,130,48,10,24,16,5,49,8,100,105,79,0,9,65,71,2,18,83,31,11,19,44 }, + { 0,12,2,1,6,5,7,28,40,60,16,14,18,62,86,27,93,8,17,38,21,41,35,99,3,19,10,23,22,4,9,48 }, + { 1,7,67,14,21,147,111,55,132,119,0,8,2,76,64,16,47,84,6,18,86,95,145,10,42,29,133,5,56,134,17,72 }, + { 69,55,47,134,102,143,7,57,118,95,14,64,29,56,1,50,75,67,146,2,0,133,68,16,21,6,141,85,116,18,72,65 }, + { 1,44,7,24,83,63,34,103,22,121,53,32,25,35,0,115,108,5,14,8,10,101,94,30,2,123,110,26,137,47,90,19 }, + { 14,1,25,42,34,0,26,96,19,29,140,5,53,10,2,121,3,24,44,22,55,77,129,7,63,16,8,4,6,61,100,48 }, + { 30,90,7,8,137,94,85,1,47,113,115,108,45,139,124,11,10,32,50,58,103,14,63,64,9,116,49,42,25,148,0,53 }, + { 40,99,2,60,28,17,0,54,93,98,86,138,6,12,21,76,1,5,27,144,128,38,19,46,14,41,145,7,16,67,3,109 }, + { 45,58,30,139,90,7,85,137,97,8,124,47,1,11,106,114,50,94,0,113,10,115,14,32,9,64,108,41,49,29,62,116 }, + { 14,42,10,1,63,96,32,25,34,8,129,29,0,103,55,19,26,53,77,5,95,2,4,7,3,16,148,56,18,24,121,108 }, + { 21,2,75,86,6,76,144,28,119,99,93,147,141,67,102,145,60,132,146,128,0,82,40,138,55,111,143,17,133,112,69,14 }, + { 111,120,41,62,84,132,0,5,38,119,56,92,72,142,27,28,29,35,58,80,2,86,65,79,12,14,1,24,145,16,21,48 }, + { 146,67,141,69,133,21,6,143,57,55,111,147,56,1,14,132,7,2,134,102,0,119,29,84,76,64,86,72,28,68,47,75 }, + { 12,1,0,5,27,3,7,4,38,8,6,41,16,40,46,10,18,79,2,9,23,86,20,22,62,14,37,88,92,19,24,11 }, + { 0,12,2,1,27,5,38,28,60,6,40,7,16,46,18,14,41,99,93,62,3,79,86,23,149,8,22,35,88,17,19,10 }, + { 141,6,21,67,147,102,146,2,76,119,132,69,55,111,86,75,28,133,143,0,1,145,14,128,56,99,17,60,29,93,84,68 }, + { 21,76,1,119,86,145,2,0,14,7,6,138,146,55,17,28,132,93,67,40,60,143,29,147,111,16,69,141,5,56,19,133 }, + { 1,8,108,14,7,116,64,42,10,63,94,32,115,103,113,96,30,34,55,47,95,148,29,140,129,25,134,53,69,26,19,11 }, + { 12,1,3,5,4,2,0,7,8,38,27,16,18,6,10,20,41,40,79,46,9,23,22,88,92,37,14,24,62,19,48,99 }, + { 1,14,7,0,6,25,5,16,19,2,42,26,29,35,61,8,18,129,101,21,3,110,34,148,96,10,17,4,22,40,12,20 }, + { 0,2,5,1,3,19,22,26,16,24,29,7,14,6,4,25,18,44,8,48,12,61,20,21,10,35,65,56,23,40,17,107 }, + { 1,7,8,29,56,0,10,14,2,42,72,5,4,65,3,30,84,94,67,9,25,133,111,11,32,108,16,63,21,96,26,48 } + }; +#ifdef _MSC_VER +#pragma endregion +#endif + + static inline uint32_t iabs(int32_t i) { return (i < 0) ? static_cast(-i) : static_cast(i); } + //static inline uint64_t iabs(int64_t i) { return (i < 0) ? static_cast(-i) : static_cast(i); } + + static inline uint8_t to_5(uint32_t v) { v = v * 31 + 128; return (uint8_t)((v + (v >> 8)) >> 8); } + static inline uint8_t to_6(uint32_t v) { v = v * 63 + 128; return (uint8_t)((v + (v >> 8)) >> 8); } + + template inline T square(T a) { return a * a; } + + static inline float clampf(float value, float low, float high) { if (value < low) value = low; else if (value > high) value = high; return value; } + + template inline S clamp(S value, S low, S high) { return (value < low) ? low : ((value > high) ? high : value); } + static inline int32_t clampi(int32_t value, int32_t low, int32_t high) { if (value < low) value = low; else if (value > high) value = high; return value; } + + static inline int squarei(int a) { return a * a; } + //static inline int absi(int a) { return (a < 0) ? -a : a; } + + template inline F lerp(F a, F b, F s) { return a + (b - a) * s; } + + static const uint32_t TOTAL_ORDER_4_0_16 = 15; + static const uint32_t TOTAL_ORDER_4_1_16 = 700; + static const uint32_t TOTAL_ORDER_4_2_16 = 753; + static const uint32_t TOTAL_ORDER_4_3_16 = 515; + static uint16_t g_total_ordering4_hash[4096]; + static float g_selector_factors4[NUM_UNIQUE_TOTAL_ORDERINGS4][3]; + + static const uint32_t TOTAL_ORDER_3_0_16 = 12; + static const uint32_t TOTAL_ORDER_3_1_16 = 15; + static const uint32_t TOTAL_ORDER_3_2_16 = 89; + static uint16_t g_total_ordering3_hash[256]; + static float g_selector_factors3[NUM_UNIQUE_TOTAL_ORDERINGS3][3]; + + struct hist4 + { + uint8_t m_hist[4]; + + hist4() + { + memset(m_hist, 0, sizeof(m_hist)); + } + + hist4(uint32_t i, uint32_t j, uint32_t k, uint32_t l) + { + m_hist[0] = (uint8_t)i; + m_hist[1] = (uint8_t)j; + m_hist[2] = (uint8_t)k; + m_hist[3] = (uint8_t)l; + } + + inline bool operator== (const hist4& h) const + { + if (m_hist[0] != h.m_hist[0]) return false; + if (m_hist[1] != h.m_hist[1]) return false; + if (m_hist[2] != h.m_hist[2]) return false; + if (m_hist[3] != h.m_hist[3]) return false; + return true; + } + + inline bool any_16() const + { + return (m_hist[0] == 16) || (m_hist[1] == 16) || (m_hist[2] == 16) || (m_hist[3] == 16); + } + + inline uint32_t lookup_total_ordering_index() const + { + if (m_hist[0] == 16) + return TOTAL_ORDER_4_0_16; + else if (m_hist[1] == 16) + return TOTAL_ORDER_4_1_16; + else if (m_hist[2] == 16) + return TOTAL_ORDER_4_2_16; + else if (m_hist[3] == 16) + return TOTAL_ORDER_4_3_16; + + // Must sum to 16, so m_hist[3] isn't needed. + return g_total_ordering4_hash[m_hist[0] | (m_hist[1] << 4) | (m_hist[2] << 8)]; + } + }; + + struct hist3 + { + uint8_t m_hist[3]; + + hist3() + { + memset(m_hist, 0, sizeof(m_hist)); + } + + hist3(uint32_t i, uint32_t j, uint32_t k) + { + m_hist[0] = (uint8_t)i; + m_hist[1] = (uint8_t)j; + m_hist[2] = (uint8_t)k; + } + + inline bool operator== (const hist3& h) const + { + if (m_hist[0] != h.m_hist[0]) return false; + if (m_hist[1] != h.m_hist[1]) return false; + if (m_hist[2] != h.m_hist[2]) return false; + return true; + } + + inline bool any_16() const + { + return (m_hist[0] == 16) || (m_hist[1] == 16) || (m_hist[2] == 16); + } + + inline uint32_t lookup_total_ordering_index() const + { + if (m_hist[0] == 16) + return TOTAL_ORDER_3_0_16; + else if (m_hist[1] == 16) + return TOTAL_ORDER_3_1_16; + else if (m_hist[2] == 16) + return TOTAL_ORDER_3_2_16; + + // Must sum to 16, so m_hist[2] isn't needed. + return g_total_ordering3_hash[m_hist[0] | (m_hist[1] << 4)]; + } + }; + + struct bc1_match_entry + { + uint8_t m_hi; + uint8_t m_lo; + uint8_t m_e; + }; + + static bc1_approx_mode g_bc1_approx_mode; + static bc1_match_entry g_bc1_match5_equals_1[256], g_bc1_match6_equals_1[256]; + static bc1_match_entry g_bc1_match5_half[256], g_bc1_match6_half[256]; + + [[maybe_unused]] static inline int scale_5_to_8(int v) { return (v << 3) | (v >> 2); } + [[maybe_unused]] static inline int scale_6_to_8(int v) { return (v << 2) | (v >> 4); } + + // v0, v1 = unexpanded DXT1 endpoint values (5/6-bits) + // c0, c1 = expanded DXT1 endpoint values (8-bits) + static inline int interp_5_6_ideal(int c0, int c1) { assert(c0 < 256 && c1 < 256); return (c0 * 2 + c1) / 3; } + static inline int interp_5_6_ideal_round(int c0, int c1) { assert(c0 < 256 && c1 < 256); return (c0 * 2 + c1 + 1) / 3; } + static inline int interp_half_5_6_ideal(int c0, int c1) { assert(c0 < 256 && c1 < 256); return (c0 + c1) / 2; } + + static inline int interp_5_nv(int v0, int v1) { assert(v0 < 32 && v1 < 32); return ((2 * v0 + v1) * 22) / 8; } + static inline int interp_6_nv(int c0, int c1) { assert(c0 < 256 && c1 < 256); const int gdiff = c1 - c0; return (256 * c0 + (gdiff / 4) + 128 + gdiff * 80) / 256; } + + static inline int interp_half_5_nv(int v0, int v1) { assert(v0 < 32 && v1 < 32); return ((v0 + v1) * 33) / 8; } + static inline int interp_half_6_nv(int c0, int c1) { assert(c0 < 256 && c1 < 256); const int gdiff = c1 - c0; return (256 * c0 + gdiff / 4 + 128 + gdiff * 128) / 256; } + + static inline int interp_5_6_amd(int c0, int c1) { assert(c0 < 256 && c1 < 256); return (c0 * 43 + c1 * 21 + 32) >> 6; } + static inline int interp_half_5_6_amd(int c0, int c1) { assert(c0 < 256 && c1 < 256); return (c0 + c1 + 1) >> 1; } + + static inline int interp_5(int v0, int v1, int c0, int c1, bc1_approx_mode mode) + { + assert(scale_5_to_8(v0) == c0 && scale_5_to_8(v1) == c1); + switch (mode) + { + case bc1_approx_mode::cBC1NVidia: return interp_5_nv(v0, v1); + case bc1_approx_mode::cBC1AMD: return interp_5_6_amd(c0, c1); + default: + case bc1_approx_mode::cBC1Ideal: return interp_5_6_ideal(c0, c1); + case bc1_approx_mode::cBC1IdealRound4: return interp_5_6_ideal_round(c0, c1); + } + } + + static inline int interp_6(int v0, int v1, int c0, int c1, bc1_approx_mode mode) + { + (void)v0; (void)v1; + assert(scale_6_to_8(v0) == c0 && scale_6_to_8(v1) == c1); + switch (mode) + { + case bc1_approx_mode::cBC1NVidia: return interp_6_nv(c0, c1); + case bc1_approx_mode::cBC1AMD: return interp_5_6_amd(c0, c1); + default: + case bc1_approx_mode::cBC1Ideal: return interp_5_6_ideal(c0, c1); + case bc1_approx_mode::cBC1IdealRound4: return interp_5_6_ideal_round(c0, c1); + } + } + + static inline int interp_half_5(int v0, int v1, int c0, int c1, bc1_approx_mode mode) + { + assert(scale_5_to_8(v0) == c0 && scale_5_to_8(v1) == c1); + switch (mode) + { + case bc1_approx_mode::cBC1NVidia: return interp_half_5_nv(v0, v1); + case bc1_approx_mode::cBC1AMD: return interp_half_5_6_amd(c0, c1); + case bc1_approx_mode::cBC1Ideal: + case bc1_approx_mode::cBC1IdealRound4: + default: + return interp_half_5_6_ideal(c0, c1); + } + } + + static inline int interp_half_6(int v0, int v1, int c0, int c1, bc1_approx_mode mode) + { + (void)v0; (void)v1; + assert(scale_6_to_8(v0) == c0 && scale_6_to_8(v1) == c1); + switch (mode) + { + case bc1_approx_mode::cBC1NVidia: return interp_half_6_nv(c0, c1); + case bc1_approx_mode::cBC1AMD: return interp_half_5_6_amd(c0, c1); + case bc1_approx_mode::cBC1Ideal: + case bc1_approx_mode::cBC1IdealRound4: + default: + return interp_half_5_6_ideal(c0, c1); + } + } + + static void prepare_bc1_single_color_table_half(bc1_match_entry* pTable, const uint8_t* pExpand, int size, bc1_approx_mode mode) + { + for (int i = 0; i < 256; i++) + { + int lowest_e = 256; + for (int lo = 0; lo < size; lo++) + { + const int lo_e = pExpand[lo]; + + for (int hi = 0; hi < size; hi++) + { + const int hi_e = pExpand[hi]; + + const int v = (size == 32) ? interp_half_5(hi, lo, hi_e, lo_e, mode) : interp_half_6(hi, lo, hi_e, lo_e, mode); + + int e = iabs(v - i); + + // We only need to factor in 3% error in BC1 ideal mode. + if ((mode == bc1_approx_mode::cBC1Ideal) || (mode == bc1_approx_mode::cBC1IdealRound4)) + e += (iabs(hi_e - lo_e) * 3) / 100; + + // Favor equal endpoints, for lower error on actual GPU's which approximate the interpolation. + if ((e < lowest_e) || ((e == lowest_e) && (lo == hi))) + { + pTable[i].m_hi = static_cast(hi); + pTable[i].m_lo = static_cast(lo); + + assert(e <= UINT8_MAX); + pTable[i].m_e = static_cast(e); + + lowest_e = e; + } + + } // hi + } // lo + } + } + + static void prepare_bc1_single_color_table(bc1_match_entry* pTable, const uint8_t* pExpand, int size, bc1_approx_mode mode) + { + for (int i = 0; i < 256; i++) + { + int lowest_e = 256; + for (int lo = 0; lo < size; lo++) + { + const int lo_e = pExpand[lo]; + + for (int hi = 0; hi < size; hi++) + { + const int hi_e = pExpand[hi]; + + const int v = (size == 32) ? interp_5(hi, lo, hi_e, lo_e, mode) : interp_6(hi, lo, hi_e, lo_e, mode); + + int e = iabs(v - i); + + if ((mode == bc1_approx_mode::cBC1Ideal) || (mode == bc1_approx_mode::cBC1IdealRound4)) + e += (iabs(hi_e - lo_e) * 3) / 100; + + // Favor equal endpoints, for lower error on actual GPU's which approximate the interpolation. + if ((e < lowest_e) || ((e == lowest_e) && (lo == hi))) + { + pTable[i].m_hi = static_cast(hi); + pTable[i].m_lo = static_cast(lo); + + assert(e <= UINT8_MAX); + pTable[i].m_e = static_cast(e); + + lowest_e = e; + } + + } // hi + } // lo + } + } + + // This table is: 9 * (w * w), 9 * ((1.0f - w) * w), 9 * ((1.0f - w) * (1.0f - w)) + // where w is [0,1/3,2/3,1]. 9 is the perfect multiplier. + static const uint32_t g_weight_vals4[4] = { 0x000009, 0x010204, 0x040201, 0x090000 }; + + // multiplier is 4 for 3-color + static const uint32_t g_weight_vals3[3] = { 0x000004, 0x040000, 0x010101 }; + + static inline void compute_selector_factors4(const hist4& h, float& iz00, float& iz10, float& iz11) + { + uint32_t weight_accum = 0; + for (uint32_t sel = 0; sel < 4; sel++) + weight_accum += g_weight_vals4[sel] * h.m_hist[sel]; + + float z00 = (float)((weight_accum >> 16) & 0xFF); + float z10 = (float)((weight_accum >> 8) & 0xFF); + float z11 = (float)(weight_accum & 0xFF); + float z01 = z10; + + float det = z00 * z11 - z01 * z10; + if (fabs(det) < 1e-8f) + det = 0.0f; + else + det = (3.0f / 255.0f) / det; + + iz00 = z11 * det; + iz10 = -z10 * det; + iz11 = z00 * det; + } + + static inline void compute_selector_factors3(const hist3& h, float& iz00, float& iz10, float& iz11) + { + uint32_t weight_accum = 0; + for (uint32_t sel = 0; sel < 3; sel++) + weight_accum += g_weight_vals3[sel] * h.m_hist[sel]; + + float z00 = (float)((weight_accum >> 16) & 0xFF); + float z10 = (float)((weight_accum >> 8) & 0xFF); + float z11 = (float)(weight_accum & 0xFF); + float z01 = z10; + + float det = z00 * z11 - z01 * z10; + if (fabs(det) < 1e-8f) + det = 0.0f; + else + det = (2.0f / 255.0f) / det; + + iz00 = z11 * det; + iz10 = -z10 * det; + iz11 = z00 * det; + } + + [[maybe_unused]] static bool g_initialized; + + void init(bc1_approx_mode mode) + { + g_bc1_approx_mode = mode; + + uint8_t bc1_expand5[32]; + for (int i = 0; i < 32; i++) + bc1_expand5[i] = static_cast((i << 3) | (i >> 2)); + prepare_bc1_single_color_table(g_bc1_match5_equals_1, bc1_expand5, 32, mode); + prepare_bc1_single_color_table_half(g_bc1_match5_half, bc1_expand5, 32, mode); + + uint8_t bc1_expand6[64]; + for (int i = 0; i < 64; i++) + bc1_expand6[i] = static_cast((i << 2) | (i >> 4)); + prepare_bc1_single_color_table(g_bc1_match6_equals_1, bc1_expand6, 64, mode); + prepare_bc1_single_color_table_half(g_bc1_match6_half, bc1_expand6, 64, mode); + + for (uint32_t i = 0; i < NUM_UNIQUE_TOTAL_ORDERINGS4; i++) + { + hist4 h; + h.m_hist[0] = (uint8_t)g_unique_total_orders4[i][0]; + h.m_hist[1] = (uint8_t)g_unique_total_orders4[i][1]; + h.m_hist[2] = (uint8_t)g_unique_total_orders4[i][2]; + h.m_hist[3] = (uint8_t)g_unique_total_orders4[i][3]; + + if (!h.any_16()) + { + const uint32_t index = h.m_hist[0] | (h.m_hist[1] << 4) | (h.m_hist[2] << 8); + assert(index < 4096); + g_total_ordering4_hash[index] = (uint16_t)i; + } + + compute_selector_factors4(h, g_selector_factors4[i][0], g_selector_factors4[i][1], g_selector_factors4[i][2]); + } + + for (uint32_t i = 0; i < NUM_UNIQUE_TOTAL_ORDERINGS3; i++) + { + hist3 h; + h.m_hist[0] = (uint8_t)g_unique_total_orders3[i][0]; + h.m_hist[1] = (uint8_t)g_unique_total_orders3[i][1]; + h.m_hist[2] = (uint8_t)g_unique_total_orders3[i][2]; + + if (!h.any_16()) + { + const uint32_t index = h.m_hist[0] | (h.m_hist[1] << 4); + assert(index < 256); + g_total_ordering3_hash[index] = (uint16_t)i; + } + + compute_selector_factors3(h, g_selector_factors3[i][0], g_selector_factors3[i][1], g_selector_factors3[i][2]); + } + + g_initialized = true; + } + + void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb, bool allow_3color) + { + bc1_block* pDst_block = static_cast(pDst); + + uint32_t mask = 0xAA; + int max16 = -1, min16 = 0; + + if (allow_3color) + { + const uint32_t err4 = g_bc1_match5_equals_1[fr].m_e + g_bc1_match6_equals_1[fg].m_e + g_bc1_match5_equals_1[fb].m_e; + const uint32_t err3 = g_bc1_match5_half[fr].m_e + g_bc1_match6_half[fg].m_e + g_bc1_match5_half[fb].m_e; + + if (err3 < err4) + { + max16 = (g_bc1_match5_half[fr].m_hi << 11) | (g_bc1_match6_half[fg].m_hi << 5) | g_bc1_match5_half[fb].m_hi; + min16 = (g_bc1_match5_half[fr].m_lo << 11) | (g_bc1_match6_half[fg].m_lo << 5) | g_bc1_match5_half[fb].m_lo; + + if (max16 > min16) + std::swap(max16, min16); + } + } + + if (max16 == -1) + { + max16 = (g_bc1_match5_equals_1[fr].m_hi << 11) | (g_bc1_match6_equals_1[fg].m_hi << 5) | g_bc1_match5_equals_1[fb].m_hi; + min16 = (g_bc1_match5_equals_1[fr].m_lo << 11) | (g_bc1_match6_equals_1[fg].m_lo << 5) | g_bc1_match5_equals_1[fb].m_lo; + + if (min16 == max16) + { + // Always forbid 3 color blocks + // This is to guarantee that BC3 blocks never use punchthrough alpha (3 color) mode, which isn't supported on some (all?) GPU's. + mask = 0; + + // Make l > h + if (min16 > 0) + min16--; + else + { + // l = h = 0 + assert(min16 == max16 && max16 == 0); + + max16 = 1; + min16 = 0; + mask = 0x55; + } + + assert(max16 > min16); + } + + if (max16 < min16) + { + std::swap(max16, min16); + mask ^= 0x55; + } + } + + pDst_block->set_low_color(static_cast(max16)); + pDst_block->set_high_color(static_cast(min16)); + pDst_block->m_selectors[0] = static_cast(mask); + pDst_block->m_selectors[1] = static_cast(mask); + pDst_block->m_selectors[2] = static_cast(mask); + pDst_block->m_selectors[3] = static_cast(mask); + } + + static const float g_midpoint5[32] = { .015686f, .047059f, .078431f, .111765f, .145098f, .176471f, .207843f, .241176f, .274510f, .305882f, .337255f, .370588f, .403922f, .435294f, .466667f, .5f, .533333f, .564706f, .596078f, .629412f, .662745f, .694118f, .725490f, .758824f, .792157f, .823529f, .854902f, .888235f, .921569f, .952941f, .984314f, 1e+37f }; + static const float g_midpoint6[64] = { .007843f, .023529f, .039216f, .054902f, .070588f, .086275f, .101961f, .117647f, .133333f, .149020f, .164706f, .180392f, .196078f, .211765f, .227451f, .245098f, .262745f, .278431f, .294118f, .309804f, .325490f, .341176f, .356863f, .372549f, .388235f, .403922f, .419608f, .435294f, .450980f, .466667f, .482353f, .500000f, .517647f, .533333f, .549020f, .564706f, .580392f, .596078f, .611765f, .627451f, .643137f, .658824f, .674510f, .690196f, .705882f, .721569f, .737255f, .754902f, .772549f, .788235f, .803922f, .819608f, .835294f, .850980f, .866667f, .882353f, .898039f, .913725f, .929412f, .945098f, .960784f, .976471f, .992157f, 1e+37f }; + + struct vec3F { float c[3]; }; + + static inline void compute_least_squares_endpoints4_rgb( + vec3F* pXl, vec3F* pXh, + int total_r, int total_g, int total_b, + float iz00, float iz10, float iz11, + uint32_t s, const uint32_t r_sum[17], const uint32_t g_sum[17], const uint32_t b_sum[17]) + { + const float iz01 = iz10; + + const uint32_t f1 = g_unique_total_orders4[s][0]; + const uint32_t f2 = g_unique_total_orders4[s][0] + g_unique_total_orders4[s][1]; + const uint32_t f3 = g_unique_total_orders4[s][0] + g_unique_total_orders4[s][1] + g_unique_total_orders4[s][2]; + uint32_t uq00_r = (r_sum[f2] - r_sum[f1]) + (r_sum[f3] - r_sum[f2]) * 2 + (r_sum[16] - r_sum[f3]) * 3; + uint32_t uq00_g = (g_sum[f2] - g_sum[f1]) + (g_sum[f3] - g_sum[f2]) * 2 + (g_sum[16] - g_sum[f3]) * 3; + uint32_t uq00_b = (b_sum[f2] - b_sum[f1]) + (b_sum[f3] - b_sum[f2]) * 2 + (b_sum[16] - b_sum[f3]) * 3; + + float q10_r = (float)(total_r * 3 - uq00_r); + float q10_g = (float)(total_g * 3 - uq00_g); + float q10_b = (float)(total_b * 3 - uq00_b); + + pXl->c[0] = iz00 * (float)uq00_r + iz01 * q10_r; + pXh->c[0] = iz10 * (float)uq00_r + iz11 * q10_r; + + pXl->c[1] = iz00 * (float)uq00_g + iz01 * q10_g; + pXh->c[1] = iz10 * (float)uq00_g + iz11 * q10_g; + + pXl->c[2] = iz00 * (float)uq00_b + iz01 * q10_b; + pXh->c[2] = iz10 * (float)uq00_b + iz11 * q10_b; + } + + static inline bool compute_least_squares_endpoints4_rgb(const color32* pColors, const uint8_t* pSelectors, vec3F* pXl, vec3F* pXh, int total_r, int total_g, int total_b) + { + uint32_t uq00_r = 0, uq00_g = 0, uq00_b = 0; + uint32_t weight_accum = 0; + for (uint32_t i = 0; i < 16; i++) + { + const uint8_t r = pColors[i].c[0], g = pColors[i].c[1], b = pColors[i].c[2]; + const uint8_t sel = pSelectors[i]; + + weight_accum += g_weight_vals4[sel]; + uq00_r += sel * r; + uq00_g += sel * g; + uq00_b += sel * b; + } + + int q10_r = total_r * 3 - uq00_r; + int q10_g = total_g * 3 - uq00_g; + int q10_b = total_b * 3 - uq00_b; + + float z00 = (float)((weight_accum >> 16) & 0xFF); + float z10 = (float)((weight_accum >> 8) & 0xFF); + float z11 = (float)(weight_accum & 0xFF); + float z01 = z10; + + float det = z00 * z11 - z01 * z10; + if (fabs(det) < 1e-8f) + return false; + + det = (3.0f / 255.0f) / det; + + float iz00, iz01, iz10, iz11; + iz00 = z11 * det; + iz01 = -z01 * det; + iz10 = -z10 * det; + iz11 = z00 * det; + + pXl->c[0] = iz00 * (float)uq00_r + iz01 * q10_r; + pXh->c[0] = iz10 * (float)uq00_r + iz11 * q10_r; + + pXl->c[1] = iz00 * (float)uq00_g + iz01 * q10_g; + pXh->c[1] = iz10 * (float)uq00_g + iz11 * q10_g; + + pXl->c[2] = iz00 * (float)uq00_b + iz01 * q10_b; + pXh->c[2] = iz10 * (float)uq00_b + iz11 * q10_b; + + return true; + } + + static inline void compute_least_squares_endpoints3_rgb( + vec3F* pXl, vec3F* pXh, + int total_r, int total_g, int total_b, + float iz00, float iz10, float iz11, + uint32_t s, const uint32_t r_sum[17], const uint32_t g_sum[17], const uint32_t b_sum[17]) + { + const float iz01 = iz10; + + // Compensates for BC1 3-color ordering, which is selector 0, 2, 1 + const uint32_t f1 = g_unique_total_orders3[s][0]; + const uint32_t f2 = g_unique_total_orders3[s][0] + g_unique_total_orders3[s][2]; + uint32_t uq00_r = (r_sum[16] - r_sum[f2]) * 2 + (r_sum[f2] - r_sum[f1]); + uint32_t uq00_g = (g_sum[16] - g_sum[f2]) * 2 + (g_sum[f2] - g_sum[f1]); + uint32_t uq00_b = (b_sum[16] - b_sum[f2]) * 2 + (b_sum[f2] - b_sum[f1]); + + float q10_r = (float)(total_r * 2 - uq00_r); + float q10_g = (float)(total_g * 2 - uq00_g); + float q10_b = (float)(total_b * 2 - uq00_b); + + pXl->c[0] = iz00 * (float)uq00_r + iz01 * q10_r; + pXh->c[0] = iz10 * (float)uq00_r + iz11 * q10_r; + + pXl->c[1] = iz00 * (float)uq00_g + iz01 * q10_g; + pXh->c[1] = iz10 * (float)uq00_g + iz11 * q10_g; + + pXl->c[2] = iz00 * (float)uq00_b + iz01 * q10_b; + pXh->c[2] = iz10 * (float)uq00_b + iz11 * q10_b; + } + + static inline bool compute_least_squares_endpoints3_rgb(bool use_black, const color32* pColors, const uint8_t* pSelectors, vec3F* pXl, vec3F* pXh) + { + int uq00_r = 0, uq00_g = 0, uq00_b = 0; + uint32_t weight_accum = 0; + int total_r = 0, total_g = 0, total_b = 0; + for (uint32_t i = 0; i < 16; i++) + { + const uint8_t r = pColors[i].c[0], g = pColors[i].c[1], b = pColors[i].c[2]; + if (use_black) + { + if ((r | g | b) < 4) + continue; + } + + const uint8_t sel = pSelectors[i]; + assert(sel <= 3); + if (sel == 3) + continue; + + weight_accum += g_weight_vals3[sel]; + + static const uint8_t s_tran[3] = { 0, 2, 1 }; + const uint8_t tsel = s_tran[sel]; + uq00_r += tsel * r; + uq00_g += tsel * g; + uq00_b += tsel * b; + + total_r += r; + total_g += g; + total_b += b; + } + + int q10_r = total_r * 2 - uq00_r; + int q10_g = total_g * 2 - uq00_g; + int q10_b = total_b * 2 - uq00_b; + + float z00 = (float)((weight_accum >> 16) & 0xFF); + float z10 = (float)((weight_accum >> 8) & 0xFF); + float z11 = (float)(weight_accum & 0xFF); + float z01 = z10; + + float det = z00 * z11 - z01 * z10; + if (fabs(det) < 1e-8f) + return false; + + det = (2.0f / 255.0f) / det; + + float iz00, iz01, iz10, iz11; + iz00 = z11 * det; + iz01 = -z01 * det; + iz10 = -z10 * det; + iz11 = z00 * det; + + pXl->c[0] = iz00 * (float)uq00_r + iz01 * q10_r; + pXh->c[0] = iz10 * (float)uq00_r + iz11 * q10_r; + + pXl->c[1] = iz00 * (float)uq00_g + iz01 * q10_g; + pXh->c[1] = iz10 * (float)uq00_g + iz11 * q10_g; + + pXl->c[2] = iz00 * (float)uq00_b + iz01 * q10_b; + pXh->c[2] = iz10 * (float)uq00_b + iz11 * q10_b; + + return true; + } + + static inline void bc1_get_block_colors4(uint32_t block_r[4], uint32_t block_g[4], uint32_t block_b[4], uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb) + { + block_r[0] = (lr << 3) | (lr >> 2); block_g[0] = (lg << 2) | (lg >> 4); block_b[0] = (lb << 3) | (lb >> 2); + block_r[3] = (hr << 3) | (hr >> 2); block_g[3] = (hg << 2) | (hg >> 4); block_b[3] = (hb << 3) | (hb >> 2); + + if (g_bc1_approx_mode == bc1_approx_mode::cBC1Ideal) + { + block_r[1] = (block_r[0] * 2 + block_r[3]) / 3; block_g[1] = (block_g[0] * 2 + block_g[3]) / 3; block_b[1] = (block_b[0] * 2 + block_b[3]) / 3; + block_r[2] = (block_r[3] * 2 + block_r[0]) / 3; block_g[2] = (block_g[3] * 2 + block_g[0]) / 3; block_b[2] = (block_b[3] * 2 + block_b[0]) / 3; + } + else if (g_bc1_approx_mode == bc1_approx_mode::cBC1IdealRound4) + { + block_r[1] = (block_r[0] * 2 + block_r[3] + 1) / 3; block_g[1] = (block_g[0] * 2 + block_g[3] + 1) / 3; block_b[1] = (block_b[0] * 2 + block_b[3] + 1) / 3; + block_r[2] = (block_r[3] * 2 + block_r[0] + 1) / 3; block_g[2] = (block_g[3] * 2 + block_g[0] + 1) / 3; block_b[2] = (block_b[3] * 2 + block_b[0] + 1) / 3; + } + else if (g_bc1_approx_mode == bc1_approx_mode::cBC1AMD) + { + block_r[1] = interp_5_6_amd(block_r[0], block_r[3]); block_g[1] = interp_5_6_amd(block_g[0], block_g[3]); block_b[1] = interp_5_6_amd(block_b[0], block_b[3]); + block_r[2] = interp_5_6_amd(block_r[3], block_r[0]); block_g[2] = interp_5_6_amd(block_g[3], block_g[0]); block_b[2] = interp_5_6_amd(block_b[3], block_b[0]); + } + else + { + block_r[1] = interp_5_nv(lr, hr); block_g[1] = interp_6_nv(block_g[0], block_g[3]); block_b[1] = interp_5_nv(lb, hb); + block_r[2] = interp_5_nv(hr, lr); block_g[2] = interp_6_nv(block_g[3], block_g[0]); block_b[2] = interp_5_nv(hb, lb); + } + } + + static inline void bc1_get_block_colors3(uint32_t block_r[3], uint32_t block_g[3], uint32_t block_b[3], uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb) + { + block_r[0] = (lr << 3) | (lr >> 2); block_g[0] = (lg << 2) | (lg >> 4); block_b[0] = (lb << 3) | (lb >> 2); + block_r[1] = (hr << 3) | (hr >> 2); block_g[1] = (hg << 2) | (hg >> 4); block_b[1] = (hb << 3) | (hb >> 2); + + if ((g_bc1_approx_mode == bc1_approx_mode::cBC1Ideal) || (g_bc1_approx_mode == bc1_approx_mode::cBC1IdealRound4)) + { + block_r[2] = (block_r[0] + block_r[1]) / 2; block_g[2] = (block_g[0] + block_g[1]) / 2; block_b[2] = (block_b[0] + block_b[1]) / 2; + } + else if (g_bc1_approx_mode == bc1_approx_mode::cBC1AMD) + { + block_r[2] = interp_half_5_6_amd(block_r[0], block_r[1]); block_g[2] = interp_half_5_6_amd(block_g[0], block_g[1]); block_b[2] = interp_half_5_6_amd(block_b[0], block_b[1]); + } + else + { + block_r[2] = interp_half_5_nv(lr, hr); block_g[2] = interp_half_6_nv(block_g[0], block_g[1]); block_b[2] = interp_half_5_nv(lb, hb); + } + } + + static inline void bc1_find_sels4_noerr(const color32* pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb, uint8_t sels[16], const uint8_t* pForce_selectors) + { + if (pForce_selectors) + { + memcpy(sels, pForce_selectors, 16); + return; + } + + uint32_t block_r[4], block_g[4], block_b[4]; + bc1_get_block_colors4(block_r, block_g, block_b, lr, lg, lb, hr, hg, hb); + + int ar = block_r[3] - block_r[0], ag = block_g[3] - block_g[0], ab = block_b[3] - block_b[0]; + + int dots[4]; + for (uint32_t i = 0; i < 4; i++) + dots[i] = (int)block_r[i] * ar + (int)block_g[i] * ag + (int)block_b[i] * ab; + + int t0 = dots[0] + dots[1], t1 = dots[1] + dots[2], t2 = dots[2] + dots[3]; + + ar *= 2; ag *= 2; ab *= 2; + + static const uint8_t s_sels[4] = { 3, 2, 1, 0 }; + + for (uint32_t i = 0; i < 16; i += 4) + { + const int d0 = pSrc_pixels[i + 0].r * ar + pSrc_pixels[i + 0].g * ag + pSrc_pixels[i + 0].b * ab; + const int d1 = pSrc_pixels[i + 1].r * ar + pSrc_pixels[i + 1].g * ag + pSrc_pixels[i + 1].b * ab; + const int d2 = pSrc_pixels[i + 2].r * ar + pSrc_pixels[i + 2].g * ag + pSrc_pixels[i + 2].b * ab; + const int d3 = pSrc_pixels[i + 3].r * ar + pSrc_pixels[i + 3].g * ag + pSrc_pixels[i + 3].b * ab; + + sels[i + 0] = s_sels[(d0 <= t0) + (d0 < t1) + (d0 < t2)]; + sels[i + 1] = s_sels[(d1 <= t0) + (d1 < t1) + (d1 < t2)]; + sels[i + 2] = s_sels[(d2 <= t0) + (d2 < t1) + (d2 < t2)]; + sels[i + 3] = s_sels[(d3 <= t0) + (d3 < t1) + (d3 < t2)]; + } + } + + static inline uint32_t bc1_find_sels4_fasterr(const color32* pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb, uint8_t sels[16], uint32_t cur_err) + { + uint32_t block_r[4], block_g[4], block_b[4]; + bc1_get_block_colors4(block_r, block_g, block_b, lr, lg, lb, hr, hg, hb); + + int ar = block_r[3] - block_r[0], ag = block_g[3] - block_g[0], ab = block_b[3] - block_b[0]; + + int dots[4]; + for (uint32_t i = 0; i < 4; i++) + dots[i] = (int)block_r[i] * ar + (int)block_g[i] * ag + (int)block_b[i] * ab; + + int t0 = dots[0] + dots[1], t1 = dots[1] + dots[2], t2 = dots[2] + dots[3]; + + ar *= 2; ag *= 2; ab *= 2; + + static const uint8_t s_sels[4] = { 3, 2, 1, 0 }; + + uint32_t total_err = 0; + + for (uint32_t i = 0; i < 16; i += 4) + { + const int d0 = pSrc_pixels[i + 0].r * ar + pSrc_pixels[i + 0].g * ag + pSrc_pixels[i + 0].b * ab; + const int d1 = pSrc_pixels[i + 1].r * ar + pSrc_pixels[i + 1].g * ag + pSrc_pixels[i + 1].b * ab; + const int d2 = pSrc_pixels[i + 2].r * ar + pSrc_pixels[i + 2].g * ag + pSrc_pixels[i + 2].b * ab; + const int d3 = pSrc_pixels[i + 3].r * ar + pSrc_pixels[i + 3].g * ag + pSrc_pixels[i + 3].b * ab; + + uint8_t sel0 = s_sels[(d0 <= t0) + (d0 < t1) + (d0 < t2)]; + uint8_t sel1 = s_sels[(d1 <= t0) + (d1 < t1) + (d1 < t2)]; + uint8_t sel2 = s_sels[(d2 <= t0) + (d2 < t1) + (d2 < t2)]; + uint8_t sel3 = s_sels[(d3 <= t0) + (d3 < t1) + (d3 < t2)]; + + sels[i + 0] = sel0; + sels[i + 1] = sel1; + sels[i + 2] = sel2; + sels[i + 3] = sel3; + + total_err += squarei(pSrc_pixels[i + 0].r - block_r[sel0]) + squarei(pSrc_pixels[i + 0].g - block_g[sel0]) + squarei(pSrc_pixels[i + 0].b - block_b[sel0]); + total_err += squarei(pSrc_pixels[i + 1].r - block_r[sel1]) + squarei(pSrc_pixels[i + 1].g - block_g[sel1]) + squarei(pSrc_pixels[i + 1].b - block_b[sel1]); + total_err += squarei(pSrc_pixels[i + 2].r - block_r[sel2]) + squarei(pSrc_pixels[i + 2].g - block_g[sel2]) + squarei(pSrc_pixels[i + 2].b - block_b[sel2]); + total_err += squarei(pSrc_pixels[i + 3].r - block_r[sel3]) + squarei(pSrc_pixels[i + 3].g - block_g[sel3]) + squarei(pSrc_pixels[i + 3].b - block_b[sel3]); + + if (total_err >= cur_err) + break; + } + + return total_err; + } + + static inline uint32_t bc1_find_sels4_check2_err(const color32* pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb, uint8_t sels[16], uint32_t cur_err) + { + uint32_t block_r[4], block_g[4], block_b[4]; + bc1_get_block_colors4(block_r, block_g, block_b, lr, lg, lb, hr, hg, hb); + + int dr = block_r[3] - block_r[0], dg = block_g[3] - block_g[0], db = block_b[3] - block_b[0]; + + const float f = 4.0f / (float)(squarei(dr) + squarei(dg) + squarei(db) + .00000125f); + + uint32_t total_err = 0; + + for (uint32_t i = 0; i < 16; i++) + { + const int r = pSrc_pixels[i].r; + const int g = pSrc_pixels[i].g; + const int b = pSrc_pixels[i].b; + + int sel = (int)((float)((r - (int)block_r[0]) * dr + (g - (int)block_g[0]) * dg + (b - (int)block_b[0]) * db) * f + .5f); + sel = clampi(sel, 1, 3); + + uint32_t err0 = squarei((int)block_r[sel - 1] - (int)r) + squarei((int)block_g[sel - 1] - (int)g) + squarei((int)block_b[sel - 1] - (int)b); + uint32_t err1 = squarei((int)block_r[sel] - (int)r) + squarei((int)block_g[sel] - (int)g) + squarei((int)block_b[sel] - (int)b); + + int best_sel = sel; + uint32_t best_err = err1; + if (err0 == err1) + { + // Prefer non-interpolation + if ((best_sel - 1) == 0) + best_sel = 0; + } + else if (err0 < best_err) + { + best_sel = sel - 1; + best_err = err0; + } + + total_err += best_err; + + if (total_err >= cur_err) + break; + + sels[i] = (uint8_t)best_sel; + } + return total_err; + } + + static inline uint32_t bc1_find_sels4_fullerr(const color32* pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb, uint8_t sels[16], uint32_t cur_err) + { + uint32_t block_r[4], block_g[4], block_b[4]; + bc1_get_block_colors4(block_r, block_g, block_b, lr, lg, lb, hr, hg, hb); + + uint32_t total_err = 0; + + for (uint32_t i = 0; i < 16; i++) + { + const int r = pSrc_pixels[i].r; + const int g = pSrc_pixels[i].g; + const int b = pSrc_pixels[i].b; + + uint32_t best_err = squarei((int)block_r[0] - (int)r) + squarei((int)block_g[0] - (int)g) + squarei((int)block_b[0] - (int)b); + uint8_t best_sel = 0; + + for (uint32_t j = 1; (j < 4) && best_err; j++) + { + uint32_t err = squarei((int)block_r[j] - (int)r) + squarei((int)block_g[j] - (int)g) + squarei((int)block_b[j] - (int)b); + if ((err < best_err) || ((err == best_err) && (j == 3))) + { + best_err = err; + best_sel = (uint8_t)j; + } + } + + total_err += best_err; + + if (total_err >= cur_err) + break; + + sels[i] = (uint8_t)best_sel; + } + return total_err; + } + + static inline uint32_t bc1_find_sels4(uint32_t flags, const color32* pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb, uint8_t sels[16], uint32_t cur_err, const uint8_t* pForce_selectors) + { + uint32_t err; + + if (pForce_selectors) + { + memcpy(sels, pForce_selectors, 16); + + uint32_t block_r[4], block_g[4], block_b[4]; + bc1_get_block_colors4(block_r, block_g, block_b, lr, lg, lb, hr, hg, hb); + + err = 0; + for (uint32_t i = 0; i < 16; i++) + { + const int r = pSrc_pixels[i].r; + const int g = pSrc_pixels[i].g; + const int b = pSrc_pixels[i].b; + + const uint32_t sel = pForce_selectors[i]; + assert(sel <= 3); + + err += squarei((int)block_r[sel] - (int)r) + squarei((int)block_g[sel] - (int)g) + squarei((int)block_b[sel] - (int)b); + } + } + else + { + if (flags & cEncodeBC1UseFasterMSEEval) + err = bc1_find_sels4_fasterr(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels, cur_err); + else if (flags & cEncodeBC1UseFullMSEEval) + err = bc1_find_sels4_fullerr(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels, cur_err); + else + err = bc1_find_sels4_check2_err(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels, cur_err); + } + + return err; + } + + static inline uint32_t bc1_find_sels3_fullerr(bool use_black, const color32* pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb, uint8_t sels[16], uint32_t cur_err, const uint8_t* pForce_selectors) + { + uint32_t block_r[4], block_g[4], block_b[4]; + bc1_get_block_colors3(block_r, block_g, block_b, lr, lg, lb, hr, hg, hb); + + uint32_t total_err = 0; + + if (pForce_selectors) + { + memcpy(sels, pForce_selectors, 16); + + //uint32_t block_r[4], block_g[4], block_b[4]; + //bc1_get_block_colors3(block_r, block_g, block_b, lr, lg, lb, hr, hg, hb); + + block_r[3] = 0; block_g[3] = 0; block_b[3] = 0; + + for (uint32_t i = 0; i < 16; i++) + { + const int r = pSrc_pixels[i].r; + const int g = pSrc_pixels[i].g; + const int b = pSrc_pixels[i].b; + + const uint32_t sel = pForce_selectors[i]; + assert(sel <= 3); + + total_err += squarei((int)block_r[sel] - (int)r) + squarei((int)block_g[sel] - (int)g) + squarei((int)block_b[sel] - (int)b); + } + } + else + { + for (uint32_t i = 0; i < 16; i++) + { + const int r = pSrc_pixels[i].r; + const int g = pSrc_pixels[i].g; + const int b = pSrc_pixels[i].b; + + uint32_t best_err = squarei((int)block_r[0] - (int)r) + squarei((int)block_g[0] - (int)g) + squarei((int)block_b[0] - (int)b); + uint32_t best_sel = 0; + + uint32_t err1 = squarei((int)block_r[1] - (int)r) + squarei((int)block_g[1] - (int)g) + squarei((int)block_b[1] - (int)b); + if (err1 < best_err) + { + best_err = err1; + best_sel = 1; + } + + uint32_t err2 = squarei((int)block_r[2] - (int)r) + squarei((int)block_g[2] - (int)g) + squarei((int)block_b[2] - (int)b); + if (err2 < best_err) + { + best_err = err2; + best_sel = 2; + } + + if (use_black) + { + uint32_t err3 = squarei(r) + squarei(g) + squarei(b); + if (err3 < best_err) + { + best_err = err3; + best_sel = 3; + } + } + + total_err += best_err; + if (total_err >= cur_err) + return total_err; + + sels[i] = (uint8_t)best_sel; + } + } + + return total_err; + } + + static inline void precise_round_565(const vec3F& xl, const vec3F& xh, + int& trial_lr, int& trial_lg, int& trial_lb, + int& trial_hr, int& trial_hg, int& trial_hb) + { + trial_lr = (int)(xl.c[0] * 31.0f); + trial_lg = (int)(xl.c[1] * 63.0f); + trial_lb = (int)(xl.c[2] * 31.0f); + + trial_hr = (int)(xh.c[0] * 31.0f); + trial_hg = (int)(xh.c[1] * 63.0f); + trial_hb = (int)(xh.c[2] * 31.0f); + + if ((uint32_t)(trial_lr | trial_lb | trial_hr | trial_hb) > 31U) + { + trial_lr = ((uint32_t)trial_lr > 31U) ? (~trial_lr >> 31) & 31 : trial_lr; + trial_hr = ((uint32_t)trial_hr > 31U) ? (~trial_hr >> 31) & 31 : trial_hr; + + trial_lb = ((uint32_t)trial_lb > 31U) ? (~trial_lb >> 31) & 31 : trial_lb; + trial_hb = ((uint32_t)trial_hb > 31U) ? (~trial_hb >> 31) & 31 : trial_hb; + } + + if ((uint32_t)(trial_lg | trial_hg) > 63U) + { + trial_lg = ((uint32_t)trial_lg > 63U) ? (~trial_lg >> 31) & 63 : trial_lg; + trial_hg = ((uint32_t)trial_hg > 63U) ? (~trial_hg >> 31) & 63 : trial_hg; + } + + trial_lr = (trial_lr + (xl.c[0] > g_midpoint5[trial_lr])) & 31; + trial_lg = (trial_lg + (xl.c[1] > g_midpoint6[trial_lg])) & 63; + trial_lb = (trial_lb + (xl.c[2] > g_midpoint5[trial_lb])) & 31; + + trial_hr = (trial_hr + (xh.c[0] > g_midpoint5[trial_hr])) & 31; + trial_hg = (trial_hg + (xh.c[1] > g_midpoint6[trial_hg])) & 63; + trial_hb = (trial_hb + (xh.c[2] > g_midpoint5[trial_hb])) & 31; + } + + static inline void precise_round_565_noscale(vec3F xl, vec3F xh, + int& trial_lr, int& trial_lg, int& trial_lb, + int& trial_hr, int& trial_hg, int& trial_hb) + { + xl.c[0] *= 1.0f / 255.0f; + xl.c[1] *= 1.0f / 255.0f; + xl.c[2] *= 1.0f / 255.0f; + + xh.c[0] *= 1.0f / 255.0f; + xh.c[1] *= 1.0f / 255.0f; + xh.c[2] *= 1.0f / 255.0f; + + precise_round_565(xl, xh, trial_lr, trial_lg, trial_lb, trial_hr, trial_hg, trial_hb); + } + + static inline void bc1_encode4(bc1_block* pDst_block, int lr, int lg, int lb, int hr, int hg, int hb, const uint8_t sels[16]) + { + uint32_t lc16 = bc1_block::pack_unscaled_color(lr, lg, lb); + uint32_t hc16 = bc1_block::pack_unscaled_color(hr, hg, hb); + + // Always forbid 3 color blocks + if (lc16 == hc16) + { + uint8_t mask = 0; + + // Make l > h + if (hc16 > 0) + hc16--; + else + { + // lc16 = hc16 = 0 + assert(lc16 == hc16 && hc16 == 0); + + hc16 = 0; + lc16 = 1; + mask = 0x55; // select hc16 + } + + assert(lc16 > hc16); + pDst_block->set_low_color(static_cast(lc16)); + pDst_block->set_high_color(static_cast(hc16)); + + pDst_block->m_selectors[0] = mask; + pDst_block->m_selectors[1] = mask; + pDst_block->m_selectors[2] = mask; + pDst_block->m_selectors[3] = mask; + } + else + { + uint8_t invert_mask = 0; + if (lc16 < hc16) + { + std::swap(lc16, hc16); + invert_mask = 0x55; + } + + assert(lc16 > hc16); + pDst_block->set_low_color((uint16_t)lc16); + pDst_block->set_high_color((uint16_t)hc16); + + uint32_t packed_sels = 0; + static const uint8_t s_sel_trans[4] = { 0, 2, 3, 1 }; + for (uint32_t i = 0; i < 16; i++) + packed_sels |= ((uint32_t)s_sel_trans[sels[i]] << (i * 2)); + + pDst_block->m_selectors[0] = (uint8_t)packed_sels ^ invert_mask; + pDst_block->m_selectors[1] = (uint8_t)(packed_sels >> 8) ^ invert_mask; + pDst_block->m_selectors[2] = (uint8_t)(packed_sels >> 16) ^ invert_mask; + pDst_block->m_selectors[3] = (uint8_t)(packed_sels >> 24) ^ invert_mask; + } + } + + static inline void bc1_encode3(bc1_block* pDst_block, int lr, int lg, int lb, int hr, int hg, int hb, const uint8_t sels[16]) + { + uint32_t lc16 = bc1_block::pack_unscaled_color(lr, lg, lb); + uint32_t hc16 = bc1_block::pack_unscaled_color(hr, hg, hb); + + bool invert_flag = false; + if (lc16 > hc16) + { + std::swap(lc16, hc16); + invert_flag = true; + } + + assert(lc16 <= hc16); + + pDst_block->set_low_color((uint16_t)lc16); + pDst_block->set_high_color((uint16_t)hc16); + + uint32_t packed_sels = 0; + + if (invert_flag) + { + static const uint8_t s_sel_trans_inv[4] = { 1, 0, 2, 3 }; + + for (uint32_t i = 0; i < 16; i++) + packed_sels |= ((uint32_t)s_sel_trans_inv[sels[i]] << (i * 2)); + } + else + { + for (uint32_t i = 0; i < 16; i++) + packed_sels |= ((uint32_t)sels[i] << (i * 2)); + } + + pDst_block->m_selectors[0] = (uint8_t)packed_sels; + pDst_block->m_selectors[1] = (uint8_t)(packed_sels >> 8); + pDst_block->m_selectors[2] = (uint8_t)(packed_sels >> 16); + pDst_block->m_selectors[3] = (uint8_t)(packed_sels >> 24); + } + + struct bc1_encode_results + { + int lr, lg, lb; + int hr, hg, hb; + uint8_t sels[16]; + bool m_3color; + }; + + static bool try_3color_block_useblack(const color32* pSrc_pixels, uint32_t flags, uint32_t& cur_err, bc1_encode_results& results, const uint8_t* pForce_selectors) + { + int total_r = 0, total_g = 0, total_b = 0; + int max_r = 0, max_g = 0, max_b = 0; + int min_r = 255, min_g = 255, min_b = 255; + int total_pixels = 0; + for (uint32_t i = 0; i < 16; i++) + { + const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b; + if ((r | g | b) < 4) + continue; + + max_r = std::max(max_r, r); max_g = std::max(max_g, g); max_b = std::max(max_b, b); + min_r = std::min(min_r, r); min_g = std::min(min_g, g); min_b = std::min(min_b, b); + total_r += r; total_g += g; total_b += b; + + total_pixels++; + } + + if (!total_pixels) + return false; + + int half_total_pixels = total_pixels >> 1; + int avg_r = (total_r + half_total_pixels) / total_pixels; + int avg_g = (total_g + half_total_pixels) / total_pixels; + int avg_b = (total_b + half_total_pixels) / total_pixels; + + uint32_t low_c = 0, high_c = 0; + + int icov[6] = { 0, 0, 0, 0, 0, 0 }; + for (uint32_t i = 0; i < 16; i++) + { + int r = (int)pSrc_pixels[i].r; + int g = (int)pSrc_pixels[i].g; + int b = (int)pSrc_pixels[i].b; + + if ((r | g | b) < 4) + continue; + + r -= avg_r; + g -= avg_g; + b -= avg_b; + + icov[0] += r * r; + icov[1] += r * g; + icov[2] += r * b; + icov[3] += g * g; + icov[4] += g * b; + icov[5] += b * b; + } + + float cov[6]; + for (uint32_t i = 0; i < 6; i++) + cov[i] = (float)(icov[i]) * (1.0f / 255.0f); + + float xr = (float)(max_r - min_r); + float xg = (float)(max_g - min_g); + float xb = (float)(max_b - min_b); + + if (icov[2] < 0) + xr = -xr; + + if (icov[4] < 0) + xg = -xg; + + for (uint32_t power_iter = 0; power_iter < 4; power_iter++) + { + float r = xr * cov[0] + xg * cov[1] + xb * cov[2]; + float g = xr * cov[1] + xg * cov[3] + xb * cov[4]; + float b = xr * cov[2] + xg * cov[4] + xb * cov[5]; + xr = r; xg = g; xb = b; + } + + float k = maximum(fabsf(xr), fabsf(xg), fabsf(xb)); + int saxis_r = 306, saxis_g = 601, saxis_b = 117; + if (k >= 2) + { + float m = 1024.0f / k; + saxis_r = (int)(xr * m); + saxis_g = (int)(xg * m); + saxis_b = (int)(xb * m); + } + + int low_dot = INT_MAX, high_dot = INT_MIN; + for (uint32_t i = 0; i < 16; i++) + { + int r = (int)pSrc_pixels[i].r, g = (int)pSrc_pixels[i].g, b = (int)pSrc_pixels[i].b; + + if ((r | g | b) < 4) + continue; + + int dot = r * saxis_r + g * saxis_g + b * saxis_b; + if (dot < low_dot) + { + low_dot = dot; + low_c = i; + } + if (dot > high_dot) + { + high_dot = dot; + high_c = i; + } + } + + int lr = to_5(pSrc_pixels[low_c].r); + int lg = to_6(pSrc_pixels[low_c].g); + int lb = to_5(pSrc_pixels[low_c].b); + + int hr = to_5(pSrc_pixels[high_c].r); + int hg = to_6(pSrc_pixels[high_c].g); + int hb = to_5(pSrc_pixels[high_c].b); + + uint8_t trial_sels[16]; + uint32_t trial_err = bc1_find_sels3_fullerr(true, pSrc_pixels, lr, lg, lb, hr, hg, hb, trial_sels, UINT32_MAX, pForce_selectors); + + if (trial_err) + { + const uint32_t total_ls_passes = flags & cEncodeBC1TwoLeastSquaresPasses ? 2 : 1; + for (uint32_t trials = 0; trials < total_ls_passes; trials++) + { + vec3F xl, xh; + int lr2, lg2, lb2, hr2, hg2, hb2; + if (!compute_least_squares_endpoints3_rgb(true, pSrc_pixels, trial_sels, &xl, &xh)) + { + lr2 = g_bc1_match5_half[avg_r].m_hi; + lg2 = g_bc1_match6_half[avg_g].m_hi; + lb2 = g_bc1_match5_half[avg_b].m_hi; + + hr2 = g_bc1_match5_half[avg_r].m_lo; + hg2 = g_bc1_match6_half[avg_g].m_lo; + hb2 = g_bc1_match5_half[avg_b].m_lo; + } + else + { + precise_round_565(xl, xh, hr2, hg2, hb2, lr2, lg2, lb2); + } + + if ((lr == lr2) && (lg == lg2) && (lb == lb2) && (hr == hr2) && (hg == hg2) && (hb == hb2)) + break; + + uint8_t trial_sels2[16]; + uint32_t trial_err2 = bc1_find_sels3_fullerr(true, pSrc_pixels, lr2, lg2, lb2, hr2, hg2, hb2, trial_sels2, trial_err, pForce_selectors); + + if (trial_err2 < trial_err) + { + trial_err = trial_err2; + lr = lr2; lg = lg2; lb = lb2; + hr = hr2; hg = hg2; hb = hb2; + memcpy(trial_sels, trial_sels2, sizeof(trial_sels)); + } + else + break; + } + } + + if (trial_err < cur_err) + { + results.m_3color = true; + results.lr = lr; + results.lg = lg; + results.lb = lb; + results.hr = hr; + results.hg = hg; + results.hb = hb; + memcpy(results.sels, trial_sels, 16); + + cur_err = trial_err; + + return true; + } + + return false; + } + + static bool try_3color_block(const color32* pSrc_pixels, uint32_t flags, uint32_t& cur_err, + int avg_r, int avg_g, int avg_b, int lr, int lg, int lb, int hr, int hg, int hb, int total_r, int total_g, int total_b, uint32_t total_orderings_to_try, + bc1_encode_results& results, const uint8_t* pForce_selectors) + { + if (pForce_selectors) + { + for (uint32_t i = 0; i < 16; i++) + if (pForce_selectors[i] == 3) + return false; + } + + uint8_t trial_sels[16]; + uint32_t trial_err = bc1_find_sels3_fullerr(false, pSrc_pixels, lr, lg, lb, hr, hg, hb, trial_sels, UINT32_MAX, pForce_selectors); + + if (trial_err) + { + const uint32_t total_ls_passes = flags & cEncodeBC1TwoLeastSquaresPasses ? 2 : 1; + for (uint32_t trials = 0; trials < total_ls_passes; trials++) + { + vec3F xl, xh; + int lr2, lg2, lb2, hr2, hg2, hb2; + if (!compute_least_squares_endpoints3_rgb(false, pSrc_pixels, trial_sels, &xl, &xh)) + { + lr2 = g_bc1_match5_half[avg_r].m_hi; + lg2 = g_bc1_match6_half[avg_g].m_hi; + lb2 = g_bc1_match5_half[avg_b].m_hi; + + hr2 = g_bc1_match5_half[avg_r].m_lo; + hg2 = g_bc1_match6_half[avg_g].m_lo; + hb2 = g_bc1_match5_half[avg_b].m_lo; + } + else + { + precise_round_565(xl, xh, hr2, hg2, hb2, lr2, lg2, lb2); + } + + if ((lr == lr2) && (lg == lg2) && (lb == lb2) && (hr == hr2) && (hg == hg2) && (hb == hb2)) + break; + + uint8_t trial_sels2[16]; + uint32_t trial_err2 = bc1_find_sels3_fullerr(false, pSrc_pixels, lr2, lg2, lb2, hr2, hg2, hb2, trial_sels2, trial_err, pForce_selectors); + + if (trial_err2 < trial_err) + { + trial_err = trial_err2; + lr = lr2; lg = lg2; lb = lb2; + hr = hr2; hg = hg2; hb = hb2; + memcpy(trial_sels, trial_sels2, sizeof(trial_sels)); + } + else + break; + } + } + + if ((trial_err) && (flags & cEncodeBC1UseLikelyTotalOrderings) && (total_orderings_to_try)) + { + hist3 h; + for (uint32_t i = 0; i < 16; i++) + { + assert(trial_sels[i] < 3); + h.m_hist[trial_sels[i]]++; + } + + const uint32_t orig_total_order_index = h.lookup_total_ordering_index(); + + int r0, g0, b0, r3, g3, b3; + r0 = (lr << 3) | (lr >> 2); g0 = (lg << 2) | (lg >> 4); b0 = (lb << 3) | (lb >> 2); + r3 = (hr << 3) | (hr >> 2); g3 = (hg << 2) | (hg >> 4); b3 = (hb << 3) | (hb >> 2); + + int ar = r3 - r0, ag = g3 - g0, ab = b3 - b0; + + int dots[16]; + for (uint32_t i = 0; i < 16; i++) + { + int r = pSrc_pixels[i].r; + int g = pSrc_pixels[i].g; + int b = pSrc_pixels[i].b; + int d = 0x1000000 + (r * ar + g * ag + b * ab); + assert(d >= 0); + dots[i] = (d << 4) + i; + } + + std::sort(dots, dots + 16); + + uint32_t r_sum[17], g_sum[17], b_sum[17]; + uint32_t r = 0, g = 0, b = 0; + for (uint32_t i = 0; i < 16; i++) + { + const uint32_t p = dots[i] & 15; + + r_sum[i] = r; + g_sum[i] = g; + b_sum[i] = b; + + r += pSrc_pixels[p].r; + g += pSrc_pixels[p].g; + b += pSrc_pixels[p].b; + } + + r_sum[16] = total_r; + g_sum[16] = total_g; + b_sum[16] = total_b; + + const uint32_t q_total = (flags & cEncodeBC1Exhaustive) ? NUM_UNIQUE_TOTAL_ORDERINGS3 : std::min(total_orderings_to_try, MAX_TOTAL_ORDERINGS3); + for (uint32_t q = 0; q < q_total; q++) + { + const uint32_t s = (flags & cEncodeBC1Exhaustive) ? q : g_best_total_orderings3[orig_total_order_index][q]; + + int trial_lr, trial_lg, trial_lb, trial_hr, trial_hg, trial_hb; + + vec3F xl, xh; + + if ((s == TOTAL_ORDER_3_0_16) || (s == TOTAL_ORDER_3_1_16) || (s == TOTAL_ORDER_3_2_16)) + { + trial_lr = g_bc1_match5_half[avg_r].m_hi; + trial_lg = g_bc1_match6_half[avg_g].m_hi; + trial_lb = g_bc1_match5_half[avg_b].m_hi; + + trial_hr = g_bc1_match5_half[avg_r].m_lo; + trial_hg = g_bc1_match6_half[avg_g].m_lo; + trial_hb = g_bc1_match5_half[avg_b].m_lo; + } + else + { + compute_least_squares_endpoints3_rgb(&xl, &xh, total_r, total_g, total_b, + g_selector_factors3[s][0], g_selector_factors3[s][1], g_selector_factors3[s][2], s, r_sum, g_sum, b_sum); + + precise_round_565(xl, xh, trial_hr, trial_hg, trial_hb, trial_lr, trial_lg, trial_lb); + } + + uint8_t trial_sels2[16]; + uint32_t trial_err2 = bc1_find_sels3_fullerr(false, pSrc_pixels, trial_lr, trial_lg, trial_lb, trial_hr, trial_hg, trial_hb, trial_sels2, UINT32_MAX, pForce_selectors); + + if (trial_err2 < trial_err) + { + trial_err = trial_err2; + + lr = trial_lr; + lg = trial_lg; + lb = trial_lb; + + hr = trial_hr; + hg = trial_hg; + hb = trial_hb; + + memcpy(trial_sels, trial_sels2, sizeof(trial_sels)); + } + + } // s + } + + if (trial_err < cur_err) + { + results.m_3color = true; + results.lr = lr; + results.lg = lg; + results.lb = lb; + results.hr = hr; + results.hg = hg; + results.hb = hb; + memcpy(results.sels, trial_sels, 16); + + cur_err = trial_err; + + return true; + } + + return false; + } + + void encode_bc1(uint32_t level, void* pDst, const uint8_t* pPixels, bool allow_3color, bool allow_transparent_texels_for_black, const uint8_t* pForce_selectors) + { + uint32_t flags = 0, total_orderings4 = 1, total_orderings3 = 1; + + static_assert(MAX_TOTAL_ORDERINGS3 >= 32, "MAX_TOTAL_ORDERINGS3 >= 32"); + static_assert(MAX_TOTAL_ORDERINGS4 >= 32, "MAX_TOTAL_ORDERINGS4 >= 32"); + + switch (level) + { + case 0: + // Faster/higher quality than stb_dxt default. + flags = cEncodeBC1BoundingBoxInt; + break; + case 1: + // Faster/higher quality than stb_dxt default. A bit higher average quality vs. mode 0. + flags = cEncodeBC1Use2DLS; + break; + case 2: + // On average mode 2 is a little weaker than modes 0/1, but it's stronger on outliers (very tough textures). + // Slightly stronger than stb_dxt. + flags = 0; + break; + case 3: + // Slightly stronger than stb_dxt HIGHQUAL. + flags = cEncodeBC1TwoLeastSquaresPasses; + break; + case 4: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseFullMSEEval | cEncodeBC1Use6PowerIters; + break; + default: + case 5: + // stb_dxt HIGHQUAL + permit 3 color (if it's enabled). + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseFasterMSEEval; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + break; + case 6: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseFasterMSEEval | cEncodeBC1UseLikelyTotalOrderings; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + break; + case 7: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseFasterMSEEval | cEncodeBC1UseLikelyTotalOrderings; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + total_orderings4 = 4; + break; + case 8: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseFasterMSEEval | cEncodeBC1UseLikelyTotalOrderings; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + total_orderings4 = 8; + break; + case 9: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseLikelyTotalOrderings; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + total_orderings4 = 11; + total_orderings3 = 3; + break; + case 10: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseLikelyTotalOrderings; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + total_orderings4 = 20; + total_orderings3 = 8; + break; + case 11: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseLikelyTotalOrderings; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + total_orderings4 = 28; + total_orderings3 = 16; + break; + case 12: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseLikelyTotalOrderings; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + total_orderings4 = 32; + total_orderings3 = 32; + break; + case 13: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseFullMSEEval | cEncodeBC1UseLikelyTotalOrderings | cEncodeBC1Use6PowerIters | (20 << cEncodeBC1EndpointSearchRoundsShift) | cEncodeBC1TryAllInitialEndponts; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + total_orderings4 = 32; + total_orderings3 = 32; + break; + case 14: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseFullMSEEval | cEncodeBC1UseLikelyTotalOrderings | cEncodeBC1Use6PowerIters | (32 << cEncodeBC1EndpointSearchRoundsShift) | cEncodeBC1TryAllInitialEndponts; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + total_orderings4 = 32; + total_orderings3 = 32; + break; + case 15: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseFullMSEEval | cEncodeBC1UseLikelyTotalOrderings | cEncodeBC1Use6PowerIters | (32 << cEncodeBC1EndpointSearchRoundsShift) | cEncodeBC1TryAllInitialEndponts; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + total_orderings4 = ((((32 + MAX_TOTAL_ORDERINGS4) / 2) + 32) / 2); + total_orderings3 = 32; + break; + case 16: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseFullMSEEval | cEncodeBC1UseLikelyTotalOrderings | cEncodeBC1Use6PowerIters | (256 << cEncodeBC1EndpointSearchRoundsShift) | cEncodeBC1TryAllInitialEndponts; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + total_orderings4 = (32 + MAX_TOTAL_ORDERINGS4) / 2; + total_orderings3 = 32; + break; + case 17: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseFullMSEEval | cEncodeBC1UseLikelyTotalOrderings | cEncodeBC1Use6PowerIters | (256 << cEncodeBC1EndpointSearchRoundsShift) | cEncodeBC1TryAllInitialEndponts; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + total_orderings4 = MAX_TOTAL_ORDERINGS4; + total_orderings3 = 32; + break; + case 18: + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseFullMSEEval | cEncodeBC1UseLikelyTotalOrderings | cEncodeBC1Use6PowerIters | cEncodeBC1Iterative | (256 << cEncodeBC1EndpointSearchRoundsShift) | cEncodeBC1TryAllInitialEndponts; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + total_orderings4 = MAX_TOTAL_ORDERINGS4; + total_orderings3 = 32; + break; + case 19: + // This hidden mode is *extremely* slow and abuses the encoder. It's just for testing/training. + flags = cEncodeBC1TwoLeastSquaresPasses | cEncodeBC1UseFullMSEEval | cEncodeBC1UseLikelyTotalOrderings | cEncodeBC1Use6PowerIters | cEncodeBC1Exhaustive | cEncodeBC1Iterative | (256 << cEncodeBC1EndpointSearchRoundsShift) | cEncodeBC1TryAllInitialEndponts; + flags |= (allow_3color ? (uint32_t)cEncodeBC1Use3ColorBlocks : 0u) | (allow_transparent_texels_for_black ? (uint32_t)cEncodeBC1Use3ColorBlocksForBlackPixels : 0u); + total_orderings4 = 32; + total_orderings3 = 32; + break; + } + + encode_bc1(pDst, pPixels, flags, total_orderings4, total_orderings3, pForce_selectors); + } + + static inline void encode_bc1_pick_initial(const color32* pSrc_pixels, uint32_t flags, bool grayscale_flag, + int min_r, int min_g, int min_b, int max_r, int max_g, int max_b, + int avg_r, int avg_g, int avg_b, int total_r, int total_g, int total_b, + int& lr, int& lg, int& lb, int& hr, int& hg, int& hb) + { + if (grayscale_flag) + { + const int fr = pSrc_pixels[0].r; + + // Grayscale blocks are a common enough case to specialize. + if ((max_r - min_r) < 2) + { + lr = lb = hr = hb = to_5(fr); + lg = hg = to_6(fr); + } + else + { + lr = lb = to_5(min_r); + lg = to_6(min_r); + + hr = hb = to_5(max_r); + hg = to_6(max_r); + } + } + else if (flags & cEncodeBC1Use2DLS) + { + // 2D Least Squares approach from Humus's example, with added inset and optimal rounding. + int big_chan = 0, min_chan_val = min_r, max_chan_val = max_r; + if ((max_g - min_g) > (max_chan_val - min_chan_val)) + big_chan = 1, min_chan_val = min_g, max_chan_val = max_g; + + if ((max_b - min_b) > (max_chan_val - min_chan_val)) + big_chan = 2, min_chan_val = min_b, max_chan_val = max_b; + + int sum_xy_r = 0, sum_xy_g = 0, sum_xy_b = 0; + vec3F l, h; + if (big_chan == 0) + { + for (uint32_t i = 0; i < 16; i++) + { + const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b; + sum_xy_r += r * r, sum_xy_g += r * g, sum_xy_b += r * b; + } + + int sum_x = total_r; + int sum_x2 = sum_xy_r; + + float div = (float)(16 * sum_x2 - sum_x * sum_x); + float b_y = 0.0f, b_z = 0.0f; + if (fabs(div) > 1e-8f) + { + div = 1.0f / div; + b_y = (16 * sum_xy_g - sum_x * total_g) * div; + b_z = (16 * sum_xy_b - sum_x * total_b) * div; + } + + float a_y = (total_g - b_y * sum_x) / 16.0f; + float a_z = (total_b - b_z * sum_x) / 16.0f; + + l.c[1] = a_y + b_y * min_chan_val; + l.c[2] = a_z + b_z * min_chan_val; + + h.c[1] = a_y + b_y * max_chan_val; + h.c[2] = a_z + b_z * max_chan_val; + + float dg = (h.c[1] - l.c[1]); + float db = (h.c[2] - l.c[2]); + + h.c[1] = l.c[1] + dg * (15.0f / 16.0f); + h.c[2] = l.c[2] + db * (15.0f / 16.0f); + + l.c[1] = l.c[1] + dg * (1.0f / 16.0f); + l.c[2] = l.c[2] + db * (1.0f / 16.0f); + + float d = (float)(max_chan_val - min_chan_val); + float fmin_chan_val = min_chan_val + d * (1.0f / 16.0f); + float fmax_chan_val = min_chan_val + d * (15.0f / 16.0f); + + l.c[0] = fmin_chan_val; + h.c[0] = fmax_chan_val; + } + else if (big_chan == 1) + { + for (uint32_t i = 0; i < 16; i++) + { + const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b; + sum_xy_r += g * r, sum_xy_g += g * g, sum_xy_b += g * b; + } + + int sum_x = total_g; + int sum_x2 = sum_xy_g; + + float div = (float)(16 * sum_x2 - sum_x * sum_x); + float b_x = 0.0f, b_z = 0.0f; + if (fabs(div) > 1e-8f) + { + div = 1.0f / div; + b_x = (16 * sum_xy_r - sum_x * total_r) * div; + b_z = (16 * sum_xy_b - sum_x * total_b) * div; + } + + float a_x = (total_r - b_x * sum_x) / 16.0f; + float a_z = (total_b - b_z * sum_x) / 16.0f; + + l.c[0] = a_x + b_x * min_chan_val; + l.c[2] = a_z + b_z * min_chan_val; + + h.c[0] = a_x + b_x * max_chan_val; + h.c[2] = a_z + b_z * max_chan_val; + + float dr = (h.c[0] - l.c[0]); + float db = (h.c[2] - l.c[2]); + + h.c[0] = l.c[0] + dr * (15.0f / 16.0f); + h.c[2] = l.c[2] + db * (15.0f / 16.0f); + + l.c[0] = l.c[0] + dr * (1.0f / 16.0f); + l.c[2] = l.c[2] + db * (1.0f / 16.0f); + + float d = (float)(max_chan_val - min_chan_val); + float fmin_chan_val = min_chan_val + d * (1.0f / 16.0f); + float fmax_chan_val = min_chan_val + d * (15.0f / 16.0f); + + l.c[1] = fmin_chan_val; + h.c[1] = fmax_chan_val; + } + else + { + for (uint32_t i = 0; i < 16; i++) + { + const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b; + sum_xy_r += b * r, sum_xy_g += b * g, sum_xy_b += b * b; + } + + int sum_x = total_b; + int sum_x2 = sum_xy_b; + + float div = (float)(16 * sum_x2 - sum_x * sum_x); + float b_x = 0.0f, b_y = 0.0f; + if (fabs(div) > 1e-8f) + { + div = 1.0f / div; + b_x = (16 * sum_xy_r - sum_x * total_r) * div; + b_y = (16 * sum_xy_g - sum_x * total_g) * div; + } + + float a_x = (total_r - b_x * sum_x) / 16.0f; + float a_y = (total_g - b_y * sum_x) / 16.0f; + + l.c[0] = a_x + b_x * min_chan_val; + l.c[1] = a_y + b_y * min_chan_val; + + h.c[0] = a_x + b_x * max_chan_val; + h.c[1] = a_y + b_y * max_chan_val; + + float dr = (h.c[0] - l.c[0]); + float dg = (h.c[1] - l.c[1]); + + h.c[0] = l.c[0] + dr * (15.0f / 16.0f); + h.c[1] = l.c[1] + dg * (15.0f / 16.0f); + + l.c[0] = l.c[0] + dr * (1.0f / 16.0f); + l.c[1] = l.c[1] + dg * (1.0f / 16.0f); + + float d = (float)(max_chan_val - min_chan_val); + float fmin_chan_val = min_chan_val + d * (1.0f / 16.0f); + float fmax_chan_val = min_chan_val + d * (15.0f / 16.0f); + + l.c[2] = fmin_chan_val; + h.c[2] = fmax_chan_val; + } + + precise_round_565_noscale(l, h, lr, lg, lb, hr, hg, hb); + } + else if (flags & cEncodeBC1BoundingBox) + { + // Algorithm from icbc.h compress_dxt1_fast() + vec3F l, h; + l.c[0] = min_r * (1.0f / 255.0f); + l.c[1] = min_g * (1.0f / 255.0f); + l.c[2] = min_b * (1.0f / 255.0f); + + h.c[0] = max_r * (1.0f / 255.0f); + h.c[1] = max_g * (1.0f / 255.0f); + h.c[2] = max_b * (1.0f / 255.0f); + + const float bias = 8.0f / 255.0f; + float inset_r = (h.c[0] - l.c[0] - bias) * (1.0f / 16.0f); + float inset_g = (h.c[1] - l.c[1] - bias) * (1.0f / 16.0f); + float inset_b = (h.c[2] - l.c[2] - bias) * (1.0f / 16.0f); + + l.c[0] = clampf(l.c[0] + inset_r, 0.0f, 1.0f); + l.c[1] = clampf(l.c[1] + inset_g, 0.0f, 1.0f); + l.c[2] = clampf(l.c[2] + inset_b, 0.0f, 1.0f); + + h.c[0] = clampf(h.c[0] - inset_r, 0.0f, 1.0f); + h.c[1] = clampf(h.c[1] - inset_g, 0.0f, 1.0f); + h.c[2] = clampf(h.c[2] - inset_b, 0.0f, 1.0f); + + int icov_xz = 0, icov_yz = 0; + for (uint32_t i = 0; i < 16; i++) + { + int r = (int)pSrc_pixels[i].r - avg_r; + int g = (int)pSrc_pixels[i].g - avg_g; + int b = (int)pSrc_pixels[i].b - avg_b; + icov_xz += r * b; + icov_yz += g * b; + } + + if (icov_xz < 0) + std::swap(l.c[0], h.c[0]); + + if (icov_yz < 0) + std::swap(l.c[1], h.c[1]); + + precise_round_565(l, h, lr, lg, lb, hr, hg, hb); + } + else if (flags & cEncodeBC1BoundingBoxInt) + { + // Algorithm from icbc.h compress_dxt1_fast(), but converted to integer. + int inset_r = (max_r - min_r - 8) >> 4; + int inset_g = (max_g - min_g - 8) >> 4; + int inset_b = (max_b - min_b - 8) >> 4; + + min_r += inset_r; + min_g += inset_g; + min_b += inset_b; + if ((uint32_t)(min_r | min_g | min_b) > 255U) + { + min_r = clampi(min_r, 0, 255); + min_g = clampi(min_g, 0, 255); + min_b = clampi(min_b, 0, 255); + } + + max_r -= inset_r; + max_g -= inset_g; + max_b -= inset_b; + if ((uint32_t)(max_r | max_g | max_b) > 255U) + { + max_r = clampi(max_r, 0, 255); + max_g = clampi(max_g, 0, 255); + max_b = clampi(max_b, 0, 255); + } + + int icov_xz = 0, icov_yz = 0; + for (uint32_t i = 0; i < 16; i++) + { + int r = (int)pSrc_pixels[i].r - avg_r; + int g = (int)pSrc_pixels[i].g - avg_g; + int b = (int)pSrc_pixels[i].b - avg_b; + icov_xz += r * b; + icov_yz += g * b; + } + + int x0 = min_r; + int y0 = min_g; + int x1 = max_r; + int y1 = max_g; + + if (icov_xz < 0) + std::swap(x0, x1); + + if (icov_yz < 0) + std::swap(y0, y1); + + lr = to_5(x0); + lg = to_6(y0); + lb = to_5(min_b); + + hr = to_5(x1); + hg = to_6(y1); + hb = to_5(max_b); + } + else + { + // Select 2 colors along the principle axis. (There must be a faster/simpler way.) + uint32_t low_c = 0, high_c = 0; + + int icov[6] = { 0, 0, 0, 0, 0, 0 }; + for (uint32_t i = 0; i < 16; i++) + { + int r = (int)pSrc_pixels[i].r - avg_r; + int g = (int)pSrc_pixels[i].g - avg_g; + int b = (int)pSrc_pixels[i].b - avg_b; + icov[0] += r * r; + icov[1] += r * g; + icov[2] += r * b; + icov[3] += g * g; + icov[4] += g * b; + icov[5] += b * b; + } + + int saxis_r = 306, saxis_g = 601, saxis_b = 117; + + float xr = (float)(max_r - min_r); + float xg = (float)(max_g - min_g); + float xb = (float)(max_b - min_b); + + if (icov[2] < 0) + xr = -xr; + + if (icov[4] < 0) + xg = -xg; + + float cov[6]; + for (uint32_t i = 0; i < 6; i++) + cov[i] = (float)(icov[i]) * (1.0f / 255.0f); + + const uint32_t total_power_iters = (flags & cEncodeBC1Use6PowerIters) ? 6 : 4; + for (uint32_t power_iter = 0; power_iter < total_power_iters; power_iter++) + { + float r = xr * cov[0] + xg * cov[1] + xb * cov[2]; + float g = xr * cov[1] + xg * cov[3] + xb * cov[4]; + float b = xr * cov[2] + xg * cov[4] + xb * cov[5]; + xr = r; xg = g; xb = b; + } + + float k = maximum(fabsf(xr), fabsf(xg), fabsf(xb)); + if (k >= 2) + { + float m = 2048.0f / k; + saxis_r = (int)(xr * m); + saxis_g = (int)(xg * m); + saxis_b = (int)(xb * m); + } + + int low_dot = INT_MAX, high_dot = INT_MIN; + + saxis_r = (int)((uint32_t)saxis_r << 4U); + saxis_g = (int)((uint32_t)saxis_g << 4U); + saxis_b = (int)((uint32_t)saxis_b << 4U); + + for (uint32_t i = 0; i < 16; i += 4) + { + int dot0 = ((pSrc_pixels[i].r * saxis_r + pSrc_pixels[i].g * saxis_g + pSrc_pixels[i].b * saxis_b) & ~0xF) + i; + int dot1 = ((pSrc_pixels[i + 1].r * saxis_r + pSrc_pixels[i + 1].g * saxis_g + pSrc_pixels[i + 1].b * saxis_b) & ~0xF) + i + 1; + int dot2 = ((pSrc_pixels[i + 2].r * saxis_r + pSrc_pixels[i + 2].g * saxis_g + pSrc_pixels[i + 2].b * saxis_b) & ~0xF) + i + 2; + int dot3 = ((pSrc_pixels[i + 3].r * saxis_r + pSrc_pixels[i + 3].g * saxis_g + pSrc_pixels[i + 3].b * saxis_b) & ~0xF) + i + 3; + + int min_d01 = std::min(dot0, dot1); + int max_d01 = std::max(dot0, dot1); + + int min_d23 = std::min(dot2, dot3); + int max_d23 = std::max(dot2, dot3); + + int min_d = std::min(min_d01, min_d23); + int max_d = std::max(max_d01, max_d23); + + low_dot = std::min(low_dot, min_d); + high_dot = std::max(high_dot, max_d); + } + low_c = low_dot & 15; + high_c = high_dot & 15; + + lr = to_5(pSrc_pixels[low_c].r); + lg = to_6(pSrc_pixels[low_c].g); + lb = to_5(pSrc_pixels[low_c].b); + + hr = to_5(pSrc_pixels[high_c].r); + hg = to_6(pSrc_pixels[high_c].g); + hb = to_5(pSrc_pixels[high_c].b); + } + } + + static const int8_t s_adjacent_voxels[16][4] = + { + { 1,0,0, 3 }, // 0 + { 0,1,0, 4 }, // 1 + { 0,0,1, 5 }, // 2 + { -1,0,0, 0 }, // 3 + { 0,-1,0, 1 }, // 4 + { 0,0,-1, 2 }, // 5 + { 1,1,0, 9 }, // 6 + { 1,0,1, 10 }, // 7 + { 0,1,1, 11 }, // 8 + { -1,-1,0, 6 }, // 9 + { -1,0,-1, 7 }, // 10 + { 0,-1,-1, 8 }, // 11 + { -1,1,0, 13 }, // 12 + { 1,-1,0, 12 }, // 13 + { 0,-1,1, 15 }, // 14 + { 0,1,-1, 14 }, // 15 + }; + + // From icbc's high quality mode. + static inline void encode_bc1_endpoint_search(const color32* pSrc_pixels, bool any_black_pixels, + uint32_t flags, bc1_encode_results& results, uint32_t cur_err, const uint8_t* pForce_selectors) + { + int& lr = results.lr, & lg = results.lg, & lb = results.lb, & hr = results.hr, & hg = results.hg, & hb = results.hb; + uint8_t* sels = results.sels; + + int prev_improvement_index = 0, forbidden_direction = -1; + + const int endpoint_search_rounds = (flags & cEncodeBC1EndpointSearchRoundsMask) >> cEncodeBC1EndpointSearchRoundsShift; + for (int i = 0; i < endpoint_search_rounds; i++) + { + assert(s_adjacent_voxels[s_adjacent_voxels[i & 15][3]][3] == (i & 15)); + + if (forbidden_direction == (i & 31)) + continue; + + const int8_t delta[3] = { s_adjacent_voxels[i & 15][0], s_adjacent_voxels[i & 15][1], s_adjacent_voxels[i & 15][2] }; + + int trial_lr = lr, trial_lg = lg, trial_lb = lb, trial_hr = hr, trial_hg = hg, trial_hb = hb; + + if ((i >> 4) & 1) + { + trial_lr = clampi(trial_lr + delta[0], 0, 31); + trial_lg = clampi(trial_lg + delta[1], 0, 63); + trial_lb = clampi(trial_lb + delta[2], 0, 31); + } + else + { + trial_hr = clampi(trial_hr + delta[0], 0, 31); + trial_hg = clampi(trial_hg + delta[1], 0, 63); + trial_hb = clampi(trial_hb + delta[2], 0, 31); + } + + uint8_t trial_sels[16]; + + uint32_t trial_err; + if (results.m_3color) + { + trial_err = bc1_find_sels3_fullerr( + ((any_black_pixels) && ((flags & cEncodeBC1Use3ColorBlocksForBlackPixels) != 0)), + pSrc_pixels, trial_lr, trial_lg, trial_lb, trial_hr, trial_hg, trial_hb, trial_sels, cur_err, pForce_selectors); + } + else + { + trial_err = bc1_find_sels4(flags, pSrc_pixels, trial_lr, trial_lg, trial_lb, trial_hr, trial_hg, trial_hb, trial_sels, cur_err, pForce_selectors); + } + + if (trial_err < cur_err) + { + cur_err = trial_err; + + forbidden_direction = s_adjacent_voxels[i & 15][3] | (i & 16); + + lr = trial_lr, lg = trial_lg, lb = trial_lb, hr = trial_hr, hg = trial_hg, hb = trial_hb; + + memcpy(sels, trial_sels, 16); + + prev_improvement_index = i; + } + + if (i - prev_improvement_index > 32) + break; + } + } + + void encode_bc1(void* pDst, const uint8_t* pPixels, uint32_t flags, uint32_t total_orderings_to_try, uint32_t total_orderings_to_try3, const uint8_t* pForce_selectors) + { + assert(g_initialized); + + const color32* pSrc_pixels = (const color32*)pPixels; + bc1_block* pDst_block = static_cast(pDst); + + int avg_r, avg_g, avg_b, min_r, min_g, min_b, max_r, max_g, max_b; + + const uint32_t fr = pSrc_pixels[0].r, fg = pSrc_pixels[0].g, fb = pSrc_pixels[0].b; + + uint32_t j; + for (j = 15; j >= 1; --j) + if ((pSrc_pixels[j].r != fr) || (pSrc_pixels[j].g != fg) || (pSrc_pixels[j].b != fb)) + break; + + if (j == 0) + { + encode_bc1_solid_block(pDst, fr, fg, fb, (flags & (cEncodeBC1Use3ColorBlocks | cEncodeBC1Use3ColorBlocksForBlackPixels)) != 0); + return; + } + + int total_r = fr, total_g = fg, total_b = fb; + + max_r = fr, max_g = fg, max_b = fb; + min_r = fr, min_g = fg, min_b = fb; + + uint32_t grayscale_flag = (fr == fg) && (fr == fb); + uint32_t any_black_pixels = (fr | fg | fb) < 4; + + for (uint32_t i = 1; i < 16; i++) + { + const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b; + + grayscale_flag &= ((r == g) && (r == b)); + any_black_pixels |= ((r | g | b) < 4); + + max_r = std::max(max_r, r); max_g = std::max(max_g, g); max_b = std::max(max_b, b); + min_r = std::min(min_r, r); min_g = std::min(min_g, g); min_b = std::min(min_b, b); + total_r += r; total_g += g; total_b += b; + } + + avg_r = (total_r + 8) >> 4, avg_g = (total_g + 8) >> 4, avg_b = (total_b + 8) >> 4; + + bc1_encode_results results; + results.m_3color = false; + + uint8_t* sels = results.sels; + int& lr = results.lr, & lg = results.lg, & lb = results.lb, & hr = results.hr, & hg = results.hg, & hb = results.hb; + int orig_lr = 0, orig_lg = 0, orig_lb = 0, orig_hr = 0, orig_hg = 0, orig_hb = 0; + + lr = 0, lg = 0, lb = 0, hr = 0, hg = 0, hb = 0; + + const bool needs_block_error = ((flags & (cEncodeBC1UseLikelyTotalOrderings | cEncodeBC1Use3ColorBlocks | cEncodeBC1UseFullMSEEval | cEncodeBC1EndpointSearchRoundsMask)) != 0) || + (any_black_pixels && ((flags & cEncodeBC1Use3ColorBlocksForBlackPixels) != 0)); + + uint32_t cur_err = UINT32_MAX; + + if (!needs_block_error) + { + assert((flags & cEncodeBC1TryAllInitialEndponts) == 0); + + encode_bc1_pick_initial(pSrc_pixels, flags, grayscale_flag != 0, + min_r, min_g, min_b, max_r, max_g, max_b, + avg_r, avg_g, avg_b, total_r, total_g, total_b, + lr, lg, lb, hr, hg, hb); + + orig_lr = lr, orig_lg = lg, orig_lb = lb, orig_hr = hr, orig_hg = hg, orig_hb = hb; + + bc1_find_sels4_noerr(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels, pForce_selectors); + + const uint32_t total_ls_passes = flags & cEncodeBC1TwoLeastSquaresPasses ? 2 : 1; + for (uint32_t ls_pass = 0; ls_pass < total_ls_passes; ls_pass++) + { + int trial_lr, trial_lg, trial_lb, trial_hr, trial_hg, trial_hb; + + vec3F xl, xh; + if (!compute_least_squares_endpoints4_rgb(pSrc_pixels, sels, &xl, &xh, total_r, total_g, total_b)) + { + // All selectors equal - treat it as a solid block which should always be equal or better. + trial_lr = g_bc1_match5_equals_1[avg_r].m_hi; + trial_lg = g_bc1_match6_equals_1[avg_g].m_hi; + trial_lb = g_bc1_match5_equals_1[avg_b].m_hi; + + trial_hr = g_bc1_match5_equals_1[avg_r].m_lo; + trial_hg = g_bc1_match6_equals_1[avg_g].m_lo; + trial_hb = g_bc1_match5_equals_1[avg_b].m_lo; + + // In high/higher quality mode, let it try again in case the optimal tables have caused the sels to diverge. + } + else + { + precise_round_565(xl, xh, trial_hr, trial_hg, trial_hb, trial_lr, trial_lg, trial_lb); + } + + if ((lr == trial_lr) && (lg == trial_lg) && (lb == trial_lb) && (hr == trial_hr) && (hg == trial_hg) && (hb == trial_hb)) + break; + + bc1_find_sels4_noerr(pSrc_pixels, trial_lr, trial_lg, trial_lb, trial_hr, trial_hg, trial_hb, sels, pForce_selectors); + + lr = trial_lr; + lg = trial_lg; + lb = trial_lb; + hr = trial_hr; + hg = trial_hg; + hb = trial_hb; + + } // ls_pass + } + else + { + const uint32_t total_rounds = (flags & cEncodeBC1TryAllInitialEndponts) ? 2 : 1; + for (uint32_t round = 0; round < total_rounds; round++) + { + uint32_t modified_flags = flags; + if (round == 1) + { + modified_flags &= ~(cEncodeBC1Use2DLS | cEncodeBC1BoundingBox); + modified_flags |= cEncodeBC1BoundingBox; + } + + int round_lr, round_lg, round_lb, round_hr, round_hg, round_hb; + uint8_t round_sels[16]; + + encode_bc1_pick_initial(pSrc_pixels, modified_flags, grayscale_flag != 0, + min_r, min_g, min_b, max_r, max_g, max_b, + avg_r, avg_g, avg_b, total_r, total_g, total_b, + round_lr, round_lg, round_lb, round_hr, round_hg, round_hb); + + int orig_round_lr = round_lr, orig_round_lg = round_lg, orig_round_lb = round_lb, orig_round_hr = round_hr, orig_round_hg = round_hg, orig_round_hb = round_hb; + + uint32_t round_err = bc1_find_sels4(flags, pSrc_pixels, round_lr, round_lg, round_lb, round_hr, round_hg, round_hb, round_sels, UINT32_MAX, pForce_selectors); + + const uint32_t total_ls_passes = flags & cEncodeBC1TwoLeastSquaresPasses ? 2 : 1; + for (uint32_t ls_pass = 0; ls_pass < total_ls_passes; ls_pass++) + { + int trial_lr, trial_lg, trial_lb, trial_hr, trial_hg, trial_hb; + + vec3F xl, xh; + if (!compute_least_squares_endpoints4_rgb(pSrc_pixels, round_sels, &xl, &xh, total_r, total_g, total_b)) + { + // All selectors equal - treat it as a solid block which should always be equal or better. + trial_lr = g_bc1_match5_equals_1[avg_r].m_hi; + trial_lg = g_bc1_match6_equals_1[avg_g].m_hi; + trial_lb = g_bc1_match5_equals_1[avg_b].m_hi; + + trial_hr = g_bc1_match5_equals_1[avg_r].m_lo; + trial_hg = g_bc1_match6_equals_1[avg_g].m_lo; + trial_hb = g_bc1_match5_equals_1[avg_b].m_lo; + + // In high/higher quality mode, let it try again in case the optimal tables have caused the sels to diverge. + } + else + { + precise_round_565(xl, xh, trial_hr, trial_hg, trial_hb, trial_lr, trial_lg, trial_lb); + } + + if ((round_lr == trial_lr) && (round_lg == trial_lg) && (round_lb == trial_lb) && (round_hr == trial_hr) && (round_hg == trial_hg) && (round_hb == trial_hb)) + break; + + uint8_t trial_sels[16]; + uint32_t trial_err = bc1_find_sels4(flags, pSrc_pixels, trial_lr, trial_lg, trial_lb, trial_hr, trial_hg, trial_hb, trial_sels, round_err, pForce_selectors); + + if (trial_err < round_err) + { + round_lr = trial_lr; + round_lg = trial_lg; + round_lb = trial_lb; + + round_hr = trial_hr; + round_hg = trial_hg; + round_hb = trial_hb; + + round_err = trial_err; + memcpy(round_sels, trial_sels, 16); + } + else + break; + + } // ls_pass + + if (round_err <= cur_err) + { + cur_err = round_err; + + lr = round_lr; + lg = round_lg; + lb = round_lb; + hr = round_hr; + hg = round_hg; + hb = round_hb; + + orig_lr = orig_round_lr; + orig_lg = orig_round_lg; + orig_lb = orig_round_lb; + orig_hr = orig_round_hr; + orig_hg = orig_round_hg; + orig_hb = orig_round_hb; + + memcpy(sels, round_sels, 16); + } + + } // round + } + + if ((cur_err) && (flags & cEncodeBC1UseLikelyTotalOrderings)) + { + assert(needs_block_error); + + const uint32_t total_iters = (flags & cEncodeBC1Iterative) ? 2 : 1; + for (uint32_t iter_index = 0; iter_index < total_iters; iter_index++) + { + const uint32_t orig_err = cur_err; + + hist4 h; + for (uint32_t i = 0; i < 16; i++) + { + assert(sels[i] < 4); + h.m_hist[sels[i]]++; + } + + const uint32_t orig_total_order_index = h.lookup_total_ordering_index(); + + int r0, g0, b0, r3, g3, b3; + r0 = (lr << 3) | (lr >> 2); g0 = (lg << 2) | (lg >> 4); b0 = (lb << 3) | (lb >> 2); + r3 = (hr << 3) | (hr >> 2); g3 = (hg << 2) | (hg >> 4); b3 = (hb << 3) | (hb >> 2); + + int ar = r3 - r0, ag = g3 - g0, ab = b3 - b0; + + int dots[16]; + for (uint32_t i = 0; i < 16; i++) + { + int r = pSrc_pixels[i].r; + int g = pSrc_pixels[i].g; + int b = pSrc_pixels[i].b; + int d = 0x1000000 + (r * ar + g * ag + b * ab); + assert(d >= 0); + dots[i] = (d << 4) + i; + } + + std::sort(dots, dots + 16); + + uint32_t r_sum[17], g_sum[17], b_sum[17]; + uint32_t r = 0, g = 0, b = 0; + for (uint32_t i = 0; i < 16; i++) + { + const uint32_t p = dots[i] & 15; + + r_sum[i] = r; + g_sum[i] = g; + b_sum[i] = b; + + r += pSrc_pixels[p].r; + g += pSrc_pixels[p].g; + b += pSrc_pixels[p].b; + } + + r_sum[16] = total_r; + g_sum[16] = total_g; + b_sum[16] = total_b; + + const uint32_t q_total = (flags & cEncodeBC1Exhaustive) ? NUM_UNIQUE_TOTAL_ORDERINGS4 : clampi(total_orderings_to_try, MIN_TOTAL_ORDERINGS, MAX_TOTAL_ORDERINGS4); + for (uint32_t q = 0; q < q_total; q++) + { + const uint32_t s = (flags & cEncodeBC1Exhaustive) ? q : g_best_total_orderings4[orig_total_order_index][q]; + + int trial_lr, trial_lg, trial_lb, trial_hr, trial_hg, trial_hb; + + vec3F xl, xh; + + if ((s == TOTAL_ORDER_4_0_16) || (s == TOTAL_ORDER_4_1_16) || (s == TOTAL_ORDER_4_2_16) || (s == TOTAL_ORDER_4_3_16)) + { + trial_lr = g_bc1_match5_equals_1[avg_r].m_hi; + trial_lg = g_bc1_match6_equals_1[avg_g].m_hi; + trial_lb = g_bc1_match5_equals_1[avg_b].m_hi; + + trial_hr = g_bc1_match5_equals_1[avg_r].m_lo; + trial_hg = g_bc1_match6_equals_1[avg_g].m_lo; + trial_hb = g_bc1_match5_equals_1[avg_b].m_lo; + } + else + { + compute_least_squares_endpoints4_rgb(&xl, &xh, total_r, total_g, total_b, + g_selector_factors4[s][0], g_selector_factors4[s][1], g_selector_factors4[s][2], s, r_sum, g_sum, b_sum); + + precise_round_565(xl, xh, trial_hr, trial_hg, trial_hb, trial_lr, trial_lg, trial_lb); + } + + uint8_t trial_sels[16]; + + uint32_t trial_err = bc1_find_sels4(flags, pSrc_pixels, trial_lr, trial_lg, trial_lb, trial_hr, trial_hg, trial_hb, trial_sels, cur_err, pForce_selectors); + + if (trial_err < cur_err) + { + cur_err = trial_err; + + lr = trial_lr; + lg = trial_lg; + lb = trial_lb; + + hr = trial_hr; + hg = trial_hg; + hb = trial_hb; + + memcpy(sels, trial_sels, 16); + } + + } // s + + if ((!cur_err) || (cur_err == orig_err)) + break; + + } // iter_index + } + + if (((flags & (cEncodeBC1Use3ColorBlocks | cEncodeBC1Use3ColorBlocksForBlackPixels)) != 0) && (cur_err)) + { + if (flags & cEncodeBC1Use3ColorBlocks) + { + assert(needs_block_error); + try_3color_block(pSrc_pixels, flags, cur_err, avg_r, avg_g, avg_b, orig_lr, orig_lg, orig_lb, orig_hr, orig_hg, orig_hb, total_r, total_g, total_b, total_orderings_to_try3, results, pForce_selectors); + } + + if ((any_black_pixels) && ((flags & cEncodeBC1Use3ColorBlocksForBlackPixels) != 0)) + { + assert(needs_block_error); + try_3color_block_useblack(pSrc_pixels, flags, cur_err, results, pForce_selectors); + } + } + + if ((flags & cEncodeBC1EndpointSearchRoundsMask) && (cur_err)) + { + assert(needs_block_error); + + encode_bc1_endpoint_search(pSrc_pixels, any_black_pixels != 0, flags, results, cur_err, pForce_selectors); + } + + if (results.m_3color) + bc1_encode3(pDst_block, results.lr, results.lg, results.lb, results.hr, results.hg, results.hb, results.sels); + else + bc1_encode4(pDst_block, results.lr, results.lg, results.lb, results.hr, results.hg, results.hb, results.sels); + } + + // BC3-5 + + void encode_bc4(void* pDst, const uint8_t* pPixels, uint32_t stride) + { + assert(g_initialized); + + uint32_t min0_v, max0_v, min1_v, max1_v, min2_v, max2_v, min3_v, max3_v; + + { + min0_v = max0_v = pPixels[0 * stride]; + min1_v = max1_v = pPixels[1 * stride]; + min2_v = max2_v = pPixels[2 * stride]; + min3_v = max3_v = pPixels[3 * stride]; + } + + { + uint32_t v0 = pPixels[4 * stride]; min0_v = std::min(min0_v, v0); max0_v = std::max(max0_v, v0); + uint32_t v1 = pPixels[5 * stride]; min1_v = std::min(min1_v, v1); max1_v = std::max(max1_v, v1); + uint32_t v2 = pPixels[6 * stride]; min2_v = std::min(min2_v, v2); max2_v = std::max(max2_v, v2); + uint32_t v3 = pPixels[7 * stride]; min3_v = std::min(min3_v, v3); max3_v = std::max(max3_v, v3); + } + + { + uint32_t v0 = pPixels[8 * stride]; min0_v = std::min(min0_v, v0); max0_v = std::max(max0_v, v0); + uint32_t v1 = pPixels[9 * stride]; min1_v = std::min(min1_v, v1); max1_v = std::max(max1_v, v1); + uint32_t v2 = pPixels[10 * stride]; min2_v = std::min(min2_v, v2); max2_v = std::max(max2_v, v2); + uint32_t v3 = pPixels[11 * stride]; min3_v = std::min(min3_v, v3); max3_v = std::max(max3_v, v3); + } + + { + uint32_t v0 = pPixels[12 * stride]; min0_v = std::min(min0_v, v0); max0_v = std::max(max0_v, v0); + uint32_t v1 = pPixels[13 * stride]; min1_v = std::min(min1_v, v1); max1_v = std::max(max1_v, v1); + uint32_t v2 = pPixels[14 * stride]; min2_v = std::min(min2_v, v2); max2_v = std::max(max2_v, v2); + uint32_t v3 = pPixels[15 * stride]; min3_v = std::min(min3_v, v3); max3_v = std::max(max3_v, v3); + } + + const uint32_t min_v = minimum(min0_v, min1_v, min2_v, min3_v); + const uint32_t max_v = maximum(max0_v, max1_v, max2_v, max3_v); + + uint8_t* pDst_bytes = static_cast(pDst); + pDst_bytes[0] = (uint8_t)max_v; + pDst_bytes[1] = (uint8_t)min_v; + + if (max_v == min_v) + { + memset(pDst_bytes + 2, 0, 6); + return; + } + + const uint32_t delta = max_v - min_v; + + // min_v is now 0. Compute thresholds between values by scaling max_v. It's x14 because we're adding two x7 scale factors. + const int t0 = delta * 13; + const int t1 = delta * 11; + const int t2 = delta * 9; + const int t3 = delta * 7; + const int t4 = delta * 5; + const int t5 = delta * 3; + const int t6 = delta * 1; + + // BC4 floors in its divisions, which we compensate for with the 4 bias. + // This function is optimal for all possible inputs (i.e. it outputs the same results as checking all 8 values and choosing the closest one). + const int bias = 4 - min_v * 14; + + static const uint32_t s_tran0[8] = { 1U , 7U , 6U , 5U , 4U , 3U , 2U , 0U }; + static const uint32_t s_tran1[8] = { 1U << 3U, 7U << 3U, 6U << 3U, 5U << 3U, 4U << 3U, 3U << 3U, 2U << 3U, 0U << 3U }; + static const uint32_t s_tran2[8] = { 1U << 6U, 7U << 6U, 6U << 6U, 5U << 6U, 4U << 6U, 3U << 6U, 2U << 6U, 0U << 6U }; + static const uint32_t s_tran3[8] = { 1U << 9U, 7U << 9U, 6U << 9U, 5U << 9U, 4U << 9U, 3U << 9U, 2U << 9U, 0U << 9U }; + + uint64_t a0, a1, a2, a3; + { + const int v0 = pPixels[0 * stride] * 14 + bias; + const int v1 = pPixels[1 * stride] * 14 + bias; + const int v2 = pPixels[2 * stride] * 14 + bias; + const int v3 = pPixels[3 * stride] * 14 + bias; + a0 = s_tran0[(v0 >= t0) + (v0 >= t1) + (v0 >= t2) + (v0 >= t3) + (v0 >= t4) + (v0 >= t5) + (v0 >= t6)]; + a1 = s_tran1[(v1 >= t0) + (v1 >= t1) + (v1 >= t2) + (v1 >= t3) + (v1 >= t4) + (v1 >= t5) + (v1 >= t6)]; + a2 = s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)]; + a3 = s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)]; + } + + { + const int v0 = pPixels[4 * stride] * 14 + bias; + const int v1 = pPixels[5 * stride] * 14 + bias; + const int v2 = pPixels[6 * stride] * 14 + bias; + const int v3 = pPixels[7 * stride] * 14 + bias; + a0 |= (uint64_t)(s_tran0[(v0 >= t0) + (v0 >= t1) + (v0 >= t2) + (v0 >= t3) + (v0 >= t4) + (v0 >= t5) + (v0 >= t6)] << 12U); + a1 |= (uint64_t)(s_tran1[(v1 >= t0) + (v1 >= t1) + (v1 >= t2) + (v1 >= t3) + (v1 >= t4) + (v1 >= t5) + (v1 >= t6)] << 12U); + a2 |= (uint64_t)(s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)] << 12U); + a3 |= (uint64_t)(s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)] << 12U); + } + + { + const int v0 = pPixels[8 * stride] * 14 + bias; + const int v1 = pPixels[9 * stride] * 14 + bias; + const int v2 = pPixels[10 * stride] * 14 + bias; + const int v3 = pPixels[11 * stride] * 14 + bias; + a0 |= (((uint64_t)s_tran0[(v0 >= t0) + (v0 >= t1) + (v0 >= t2) + (v0 >= t3) + (v0 >= t4) + (v0 >= t5) + (v0 >= t6)]) << 24U); + a1 |= (((uint64_t)s_tran1[(v1 >= t0) + (v1 >= t1) + (v1 >= t2) + (v1 >= t3) + (v1 >= t4) + (v1 >= t5) + (v1 >= t6)]) << 24U); + a2 |= (((uint64_t)s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)]) << 24U); + a3 |= (((uint64_t)s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)]) << 24U); + } + + { + const int v0 = pPixels[12 * stride] * 14 + bias; + const int v1 = pPixels[13 * stride] * 14 + bias; + const int v2 = pPixels[14 * stride] * 14 + bias; + const int v3 = pPixels[15 * stride] * 14 + bias; + a0 |= (((uint64_t)s_tran0[(v0 >= t0) + (v0 >= t1) + (v0 >= t2) + (v0 >= t3) + (v0 >= t4) + (v0 >= t5) + (v0 >= t6)]) << 36U); + a1 |= (((uint64_t)s_tran1[(v1 >= t0) + (v1 >= t1) + (v1 >= t2) + (v1 >= t3) + (v1 >= t4) + (v1 >= t5) + (v1 >= t6)]) << 36U); + a2 |= (((uint64_t)s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)]) << 36U); + a3 |= (((uint64_t)s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)]) << 36U); + } + + const uint64_t f = a0 | a1 | a2 | a3; + + pDst_bytes[2] = (uint8_t)f; + pDst_bytes[3] = (uint8_t)(f >> 8U); + pDst_bytes[4] = (uint8_t)(f >> 16U); + pDst_bytes[5] = (uint8_t)(f >> 24U); + pDst_bytes[6] = (uint8_t)(f >> 32U); + pDst_bytes[7] = (uint8_t)(f >> 40U); + } + + uint32_t encode_bc4_hq(void* pDst, const uint8_t* pPixels, uint32_t stride, uint32_t search_rad, uint32_t mode_flag, const uint8_t* pForce_selectors) + { + assert(mode_flag); + + uint8_t* pDst_bytes = static_cast(pDst); + + uint32_t min_val = 255, max_val = 0; + for (uint32_t i = 0; i < 16; i++) + { + uint32_t val = pPixels[i * stride]; + min_val = std::min(val, min_val); + max_val = std::max(val, max_val); + } + + if (min_val == max_val) + { + if (mode_flag & BC4_USE_MODE6_FLAG) + { + pDst_bytes[0] = (uint8_t)min_val; + pDst_bytes[1] = (uint8_t)min_val; + + memset(pDst_bytes + 2, 0, 6); + + assert(!(pDst_bytes[0] > pDst_bytes[1])); + } + else + { + // Use an 8 value encoding + if (min_val > 0) + { + pDst_bytes[0] = (uint8_t)min_val; + pDst_bytes[1] = (uint8_t)min_val - 1; + + memset(pDst_bytes + 2, 0, 6); + } + else + { + static const uint8_t s_const_1_vals[8] = { 1, 0, 0x49, 0x92, 0x24, 0x49, 0x92, 0x24 }; + memcpy(pDst_bytes, s_const_1_vals, 8); + } + + assert(pDst_bytes[0] > pDst_bytes[1]); + } + +#if defined(_DEBUG) || defined(DEBUG) + { + bc4_block* pBlock = (bc4_block*)pDst; + uint8_t pixels[16]; + unpack_bc4(pDst, pixels, 1); + for (uint32_t i = 0; i < 16; i++) + assert(pixels[i] == min_val); + if (mode_flag & BC4_USE_MODE6_FLAG) + { + assert(pBlock->is_alpha6_block()); + } + else + { + assert(!pBlock->is_alpha6_block()); + } + } +#endif + + return 0; + } + + uint32_t best_err = UINT32_MAX; + for (uint32_t mode = 0; mode < 2; mode++) + { + if ((mode_flag & (1 << mode)) == 0) + continue; + + for (int lo_delta = -(int)search_rad; lo_delta <= (int)search_rad; lo_delta++) + { + for (int hi_delta = -(int)search_rad; hi_delta <= (int)search_rad; hi_delta++) + { + bc4_block trial_block; + trial_block.m_endpoints[0] = (uint8_t)clamp(max_val + hi_delta, 0, 255); + trial_block.m_endpoints[1] = (uint8_t)clamp(min_val + lo_delta, 0, 255); + + if (trial_block.m_endpoints[0] == trial_block.m_endpoints[1]) + continue; + + if (mode == 0) + { + if (trial_block.is_alpha6_block()) + std::swap(trial_block.m_endpoints[0], trial_block.m_endpoints[1]); + } + else if (!trial_block.is_alpha6_block()) + std::swap(trial_block.m_endpoints[0], trial_block.m_endpoints[1]); + + uint8_t block_vals[8]; + trial_block.get_block_values(block_vals, trial_block.m_endpoints[0], trial_block.m_endpoints[1]); + + uint32_t trial_err = 0; + uint8_t trial_sels[16]; + + if (pForce_selectors) + { + memcpy(trial_sels, pForce_selectors, 16); + + for (uint32_t i = 0; i < 16; i++) + trial_err += squarei(block_vals[pForce_selectors[i]] - pPixels[i * stride]); + } + else + { + for (uint32_t i = 0; i < 16; i++) + { + uint32_t best_index_err = UINT32_MAX; + uint32_t best_index = 0; + for (uint32_t j = 0; j < 8; j++) + { + uint32_t err = squarei(block_vals[j] - pPixels[i * stride]); + if (err < best_index_err) + { + best_index_err = err; + best_index = j; + if (!err) + break; + } + } + + trial_err += best_index_err; + if (trial_err >= best_err) + break; + + trial_sels[i] = (uint8_t)best_index; + } // i + } + + if (trial_err < best_err) + { + best_err = trial_err; + + uint64_t sel_vals = 0; + for (uint32_t i = 0; i < 16; i++) + sel_vals |= ((uint64_t)trial_sels[i] << (i * 3)); + + trial_block.m_selectors[0] = (uint8_t)sel_vals; + trial_block.m_selectors[1] = (uint8_t)(sel_vals >> 8); + trial_block.m_selectors[2] = (uint8_t)(sel_vals >> 16); + trial_block.m_selectors[3] = (uint8_t)(sel_vals >> 24); + trial_block.m_selectors[4] = (uint8_t)(sel_vals >> 32); + trial_block.m_selectors[5] = (uint8_t)(sel_vals >> 40); + + memcpy(pDst_bytes, &trial_block, sizeof(bc4_block)); + } // if (trial_err < best_err) + + } // hi_delta + + } // lo_delta + + } // mode + + return best_err; + } + + void encode_bc3(void* pDst, const uint8_t* pPixels, uint32_t flags, uint32_t total_orderings_to_try) + { + assert(g_initialized); + + // 3-color blocks are not allowed with BC3 (on most GPU's). + flags &= ~(cEncodeBC1Use3ColorBlocksForBlackPixels | cEncodeBC1Use3ColorBlocks); + + encode_bc4(pDst, pPixels + 3, 4); + encode_bc1(static_cast(pDst) + 8, pPixels, flags, total_orderings_to_try); + } + + void encode_bc3(uint32_t level, void* pDst, const uint8_t* pPixels) + { + assert(g_initialized); + + encode_bc4(pDst, pPixels + 3, 4); + encode_bc1(level, static_cast(pDst) + 8, pPixels, false, false); + } + + void encode_bc3_hq(uint32_t level, void* pDst, const uint8_t* pPixels, uint32_t alpha_search_rad, uint32_t alpha_modes) + { + assert(g_initialized); + + encode_bc4_hq(pDst, pPixels + 3, 4, alpha_search_rad, alpha_modes); + encode_bc1(level, static_cast(pDst) + 8, pPixels, false, false); + } + + void encode_bc5(void* pDst, const uint8_t* pPixels, uint32_t chan0, uint32_t chan1, uint32_t stride) + { + assert(g_initialized); + + encode_bc4(pDst, pPixels + chan0, stride); + encode_bc4(static_cast(pDst) + 8, pPixels + chan1, stride); + } + + void encode_bc5_hq(void* pDst, const uint8_t* pPixels, uint32_t chan0, uint32_t chan1, uint32_t stride, uint32_t alpha_search_rad, uint32_t alpha_modes) + { + assert(g_initialized); + + encode_bc4_hq(pDst, pPixels + chan0, stride, alpha_search_rad, alpha_modes); + encode_bc4_hq(static_cast(pDst) + 8, pPixels + chan1, stride, alpha_search_rad, alpha_modes); + } + + bool unpack_bc1_block_colors(const void* pBlock_bits, color32* c, bc1_approx_mode mode) + { + const bc1_block* pBlock = static_cast(pBlock_bits); + + const uint32_t l = pBlock->get_low_color(); + const uint32_t h = pBlock->get_high_color(); + + const int cr0 = (l >> 11) & 31; + const int cg0 = (l >> 5) & 63; + const int cb0 = l & 31; + const int r0 = (cr0 << 3) | (cr0 >> 2); + const int g0 = (cg0 << 2) | (cg0 >> 4); + const int b0 = (cb0 << 3) | (cb0 >> 2); + + const int cr1 = (h >> 11) & 31; + const int cg1 = (h >> 5) & 63; + const int cb1 = h & 31; + const int r1 = (cr1 << 3) | (cr1 >> 2); + const int g1 = (cg1 << 2) | (cg1 >> 4); + const int b1 = (cb1 << 3) | (cb1 >> 2); + + bool used_punchthrough = false; + + if (l > h) + { + c[0].set_noclamp_rgba(r0, g0, b0, 255); + c[1].set_noclamp_rgba(r1, g1, b1, 255); + switch (mode) + { + case bc1_approx_mode::cBC1Ideal: + c[2].set_noclamp_rgba((r0 * 2 + r1) / 3, (g0 * 2 + g1) / 3, (b0 * 2 + b1) / 3, 255); + c[3].set_noclamp_rgba((r1 * 2 + r0) / 3, (g1 * 2 + g0) / 3, (b1 * 2 + b0) / 3, 255); + break; + case bc1_approx_mode::cBC1IdealRound4: + c[2].set_noclamp_rgba((r0 * 2 + r1 + 1) / 3, (g0 * 2 + g1 + 1) / 3, (b0 * 2 + b1 + 1) / 3, 255); + c[3].set_noclamp_rgba((r1 * 2 + r0 + 1) / 3, (g1 * 2 + g0 + 1) / 3, (b1 * 2 + b0 + 1) / 3, 255); + break; + case bc1_approx_mode::cBC1NVidia: + c[2].set_noclamp_rgba(interp_5_nv(cr0, cr1), interp_6_nv(g0, g1), interp_5_nv(cb0, cb1), 255); + c[3].set_noclamp_rgba(interp_5_nv(cr1, cr0), interp_6_nv(g1, g0), interp_5_nv(cb1, cb0), 255); + break; + case bc1_approx_mode::cBC1AMD: + c[2].set_noclamp_rgba(interp_5_6_amd(r0, r1), interp_5_6_amd(g0, g1), interp_5_6_amd(b0, b1), 255); + c[3].set_noclamp_rgba(interp_5_6_amd(r1, r0), interp_5_6_amd(g1, g0), interp_5_6_amd(b1, b0), 255); + break; + } + } + else + { + c[0].set_noclamp_rgba(r0, g0, b0, 255); + c[1].set_noclamp_rgba(r1, g1, b1, 255); + switch (mode) + { + case bc1_approx_mode::cBC1Ideal: + case bc1_approx_mode::cBC1IdealRound4: + c[2].set_noclamp_rgba((r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2, 255); + break; + case bc1_approx_mode::cBC1NVidia: + c[2].set_noclamp_rgba(interp_half_5_nv(cr0, cr1), interp_half_6_nv(g0, g1), interp_half_5_nv(cb0, cb1), 255); + break; + case bc1_approx_mode::cBC1AMD: + c[2].set_noclamp_rgba(interp_half_5_6_amd(r0, r1), interp_half_5_6_amd(g0, g1), interp_half_5_6_amd(b0, b1), 255); + break; + } + + c[3].set_noclamp_rgba(0, 0, 0, 0); + used_punchthrough = true; + } + + return used_punchthrough; + } + + // Returns true if the block uses 3 color punchthrough alpha mode. + bool unpack_bc1(const void* pBlock_bits, void* pPixels, bool set_alpha, bc1_approx_mode mode) + { + color32* pDst_pixels = static_cast(pPixels); + + static_assert(sizeof(bc1_block) == 8, "sizeof(bc1_block) == 8"); + static_assert(sizeof(bc4_block) == 8, "sizeof(bc4_block) == 8"); + + const bc1_block* pBlock = static_cast(pBlock_bits); + + color32 c[4]; + const bool used_punchthrough = unpack_bc1_block_colors(pBlock_bits, c, mode); + + if (set_alpha) + { + for (uint32_t y = 0; y < 4; y++, pDst_pixels += 4) + { + pDst_pixels[0] = c[pBlock->get_selector(0, y)]; + pDst_pixels[1] = c[pBlock->get_selector(1, y)]; + pDst_pixels[2] = c[pBlock->get_selector(2, y)]; + pDst_pixels[3] = c[pBlock->get_selector(3, y)]; + } + } + else + { + for (uint32_t y = 0; y < 4; y++, pDst_pixels += 4) + { + pDst_pixels[0].set_rgb(c[pBlock->get_selector(0, y)]); + pDst_pixels[1].set_rgb(c[pBlock->get_selector(1, y)]); + pDst_pixels[2].set_rgb(c[pBlock->get_selector(2, y)]); + pDst_pixels[3].set_rgb(c[pBlock->get_selector(3, y)]); + } + } + + return used_punchthrough; + } + + void unpack_bc4(const void* pBlock_bits, uint8_t* pPixels, uint32_t stride) + { + static_assert(sizeof(bc4_block) == 8, "sizeof(bc4_block) == 8"); + + const bc4_block* pBlock = static_cast(pBlock_bits); + + uint8_t sel_values[8]; + bc4_block::get_block_values(sel_values, pBlock->get_low_alpha(), pBlock->get_high_alpha()); + + const uint64_t selector_bits = pBlock->get_selector_bits(); + + for (uint32_t y = 0; y < 4; y++, pPixels += (stride * 4U)) + { + pPixels[0] = sel_values[pBlock->get_selector(0, y, selector_bits)]; + pPixels[stride * 1] = sel_values[pBlock->get_selector(1, y, selector_bits)]; + pPixels[stride * 2] = sel_values[pBlock->get_selector(2, y, selector_bits)]; + pPixels[stride * 3] = sel_values[pBlock->get_selector(3, y, selector_bits)]; + } + } + + // Returns false if the block uses 3-color punchthrough alpha mode, which isn't supported on some GPU's for BC3. + bool unpack_bc3(const void* pBlock_bits, void* pPixels, bc1_approx_mode mode) + { + color32* pDst_pixels = static_cast(pPixels); + + bool success = true; + + if (unpack_bc1((const uint8_t*)pBlock_bits + sizeof(bc4_block), pDst_pixels, true, mode)) + success = false; + + unpack_bc4(pBlock_bits, &pDst_pixels[0].a, sizeof(color32)); + + return success; + } + + // writes RG + void unpack_bc5(const void* pBlock_bits, void* pPixels, uint32_t chan0, uint32_t chan1, uint32_t stride) + { + unpack_bc4(pBlock_bits, (uint8_t*)pPixels + chan0, stride); + unpack_bc4((const uint8_t*)pBlock_bits + sizeof(bc4_block), (uint8_t*)pPixels + chan1, stride); + } + +} // namespace rgbcx + + + diff --git a/external/bc7enc_rdo/rgbcx.h b/external/bc7enc_rdo/rgbcx.h new file mode 100644 index 0000000000..f5649c5503 --- /dev/null +++ b/external/bc7enc_rdo/rgbcx.h @@ -0,0 +1,468 @@ +// rgbcx.h v1.13 +// High-performance scalar encoders and RDO (Rate Distortion Optimization) post processors for BC1-5. +// Public Domain or MIT license (you choose - see below), written by Richard Geldreich 2020 . +// +// Influential references: +// https://tinyurl.com/y3vxz457 (Ortego and Ramchandran, "Rate-distortion Methods for Image and Video Compression", 1998) +// http://sjbrown.co.uk/2006/01/19/dxt-compression-techniques/ +// https://github.com/nothings/stb/blob/master/stb_dxt.h +// https://gist.github.com/castano/c92c7626f288f9e99e158520b14a61cf +// https://github.com/castano/icbc/blob/master/icbc.h +// http://www.humus.name/index.php?page=3D&ID=79 +// +// This is a single header file library. Be sure to "#define RGBCX_IMPLEMENTATION" in one .cpp file somewhere. +// +// Instructions: +// +// The library MUST be initialized by calling this function at least once before using any encoder or decoder functions: +// +// void rgbcx::init(bc1_approx_mode mode = cBC1Ideal); +// +// This function manipulates global state, so it is not thread safe. +// You can call it multiple times to change the global BC1 approximation mode. +// Important: BC1/3 textures encoded using non-ideal BC1 approximation modes should only be sampled on parts from that vendor. +// If you encode for AMD, average error on AMD parts will go down, but average error on NVidia parts will go up and vice versa. +// If in doubt, encode in ideal BC1 mode. +// +// Call these functions to encode BC1-5: +// void rgbcx::encode_bc1(uint32_t level, void* pDst, const uint8_t* pPixels, bool allow_3color, bool use_transparent_texels_for_black); +// void rgbcx::encode_bc3(uint32_t level, void* pDst, const uint8_t* pPixels); +// void rgbcx::encode_bc4(void* pDst, const uint8_t* pPixels, uint32_t stride = 4); +// void rgbcx::encode_bc5(void* pDst, const uint8_t* pPixels, uint32_t chan0 = 0, uint32_t chan1 = 1, uint32_t stride = 4); +// +// - level ranges from MIN_LEVEL to MAX_LEVEL. The higher the level, the slower the encoder goes, but the higher the average quality. +// levels [0,4] are fast and compete against stb_dxt (default and HIGHQUAL). The remaining levels compete against squish/NVTT/icbc and icbc HQ. +// If in doubt just use level 10, set allow_3color to true and use_transparent_texels_for_black to false, and adjust as needed. +// +// - pDst is a pointer to the 8-byte (BC1/4) or 16-byte (BC3/5) destination block. +// +// - pPixels is a pointer to the 32-bpp pixels, in either RGBX or RGBA format (R is first in memory). +// Alpha is always ignored by encode_bc1(). +// +// - allow_3color: If true the encoder will use 3-color blocks. This flag is ignored unless level is >= 5 (because lower levels compete against stb_dxt and it doesn't support 3-color blocks). +// Do not enable on BC3-5 textures. 3-color block usage slows down encoding. +// +// - use_transparent_texels_for_black: If true the encoder will use 3-color block transparent black pixels to code very dark or black texels. Your engine/shader MUST ignore the sampled +// alpha value for textures encoded in this mode. This is how NVidia's classic "nvdxt" encoder (used by many original Xbox titles) used to work by default on DXT1C textures. It increases +// average quality substantially (because dark texels/black are very common) and is highly recommended. +// Do not enable on BC3-5 textures. +// +// - stride is the source pixel stride, in bytes. It's typically 4. +// +// - chan0 and chan1 are the source channels. Typically they will be 0 and 1. +// +// All encoding and decoding functions are threade-safe. +// +// To reduce the compiled size of the encoder, set #define RGBCX_USE_SMALLER_TABLES to 1 before including this header. +// +#pragma once + +#ifdef _MSC_VER +#pragma warning (disable:4201) //nameless struct/union +#endif + +#include +#include +#include +#include +#include + +// By default, the table used to accelerate cluster fit on 4 color blocks uses a 969x128 entry table. +// To reduce the executable size, set RGBCX_USE_SMALLER_TABLES to 1, which selects the smaller 969x32 entry table. +#ifndef RGBCX_USE_SMALLER_TABLES +#define RGBCX_USE_SMALLER_TABLES 0 +#endif + +namespace rgbcx +{ + enum class bc1_approx_mode + { + // The default mode. No rounding for 4-color colors 2,3. My older tools/compressors use this mode. + // This matches the D3D10 docs on BC1. + cBC1Ideal = 0, + + // NVidia GPU mode. + cBC1NVidia = 1, + + // AMD GPU mode. + cBC1AMD = 2, + + // This mode matches AMD Compressonator's output. It rounds 4-color colors 2,3 (not 3-color color 2). + // This matches the D3D9 docs on DXT1. + cBC1IdealRound4 = 3 + }; + + enum class eNoClamp { cNoClamp }; + static inline uint8_t clamp255(int32_t i) { return (uint8_t)((i & 0xFFFFFF00U) ? (~(i >> 31)) : i); } + + template inline S maximum(S a, S b) { return (a > b) ? a : b; } + template inline S maximum(S a, S b, S c) { return maximum(maximum(a, b), c); } + template inline S maximum(S a, S b, S c, S d) { return maximum(maximum(maximum(a, b), c), d); } + + template inline S minimum(S a, S b) { return (a < b) ? a : b; } + template inline S minimum(S a, S b, S c) { return minimum(minimum(a, b), c); } + template inline S minimum(S a, S b, S c, S d) { return minimum(minimum(minimum(a, b), c), d); } + + struct color32 + { + union + { + struct + { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + }; + + uint8_t c[4]; + + uint32_t m; + }; + + color32() { } + + color32(uint32_t vr, uint32_t vg, uint32_t vb, uint32_t va) { set(vr, vg, vb, va); } + color32(eNoClamp unused, uint32_t vr, uint32_t vg, uint32_t vb, uint32_t va) { (void)unused; set_noclamp_rgba(vr, vg, vb, va); } + + void set(uint32_t vr, uint32_t vg, uint32_t vb, uint32_t va) { c[0] = static_cast(vr); c[1] = static_cast(vg); c[2] = static_cast(vb); c[3] = static_cast(va); } + + void set_noclamp_rgb(uint32_t vr, uint32_t vg, uint32_t vb) { c[0] = static_cast(vr); c[1] = static_cast(vg); c[2] = static_cast(vb); } + void set_noclamp_rgba(uint32_t vr, uint32_t vg, uint32_t vb, uint32_t va) { set(vr, vg, vb, va); } + + void set_clamped(int vr, int vg, int vb, int va) { c[0] = clamp255(vr); c[1] = clamp255(vg); c[2] = clamp255(vb); c[3] = clamp255(va); } + + uint8_t operator[] (uint32_t idx) const { assert(idx < 4); return c[idx]; } + uint8_t& operator[] (uint32_t idx) { assert(idx < 4); return c[idx]; } + + bool operator== (const color32& rhs) const { return m == rhs.m; } + + void set_rgb(const color32& other) { c[0] = static_cast(other.c[0]); c[1] = static_cast(other.c[1]); c[2] = static_cast(other.c[2]); } + + static color32 comp_min(const color32& a, const color32& b) { return color32(eNoClamp::cNoClamp, std::min(a[0], b[0]), std::min(a[1], b[1]), std::min(a[2], b[2]), std::min(a[3], b[3])); } + static color32 comp_max(const color32& a, const color32& b) { return color32(eNoClamp::cNoClamp, std::max(a[0], b[0]), std::max(a[1], b[1]), std::max(a[2], b[2]), std::max(a[3], b[3])); } + }; + + // init() MUST be called once before using the BC1 encoder. + // This function may be called multiple times to change the BC1 approximation mode. + // This function initializes global state, so don't call it while other threads inside the encoder. + // Important: If you encode textures for a specific vendor's GPU's, beware that using that texture data on other GPU's may result in ugly artifacts. + // Encode to cBC1Ideal unless you know the texture data will only be deployed or used on a specific vendor's GPU. + void init(bc1_approx_mode mode = bc1_approx_mode::cBC1Ideal); + + // Optimally encodes a solid color block to BC1 format. + void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb, bool allow_3color); + + // BC1 low-level API encoder flags. You can ignore this if you use the simple level API. + enum + { + // Try to improve quality using the most likely total orderings. + // The total_orderings_to_try parameter will then control the number of total orderings to try for 4 color blocks, and the + // total_orderings_to_try3 parameter will control the number of total orderings to try for 3 color blocks (if they are enabled). + cEncodeBC1UseLikelyTotalOrderings = 2, + + // Use 2 least squares pass, instead of one (same as stb_dxt's HIGHQUAL option). + // Recommended if you're enabling cEncodeBC1UseLikelyTotalOrderings. + cEncodeBC1TwoLeastSquaresPasses = 4, + + // cEncodeBC1Use3ColorBlocksForBlackPixels allows the BC1 encoder to use 3-color blocks for blocks containing black or very dark pixels. + // You shader/engine MUST ignore the alpha channel on textures encoded with this flag. + // Average quality goes up substantially for my 100 texture corpus (~.5 dB), so it's worth using if you can. + // Note the BC1 encoder does not actually support transparency in 3-color mode. + // Don't set when encoding to BC3. + cEncodeBC1Use3ColorBlocksForBlackPixels = 8, + + // If cEncodeBC1Use3ColorBlocks is set, the encoder can use 3-color mode for a small but noticeable gain in average quality, but lower perf. + // If you also specify the cEncodeBC1UseLikelyTotalOrderings flag, set the total_orderings_to_try3 paramter to the number of total orderings to try. + // Don't set when encoding to BC3. + cEncodeBC1Use3ColorBlocks = 16, + + // cEncodeBC1Iterative will greatly increase encode time, but is very slightly higher quality. + // Same as squish's iterative cluster fit option. Not really worth the tiny boost in quality, unless you just don't care about perf. at all. + cEncodeBC1Iterative = 32, + + // cEncodeBC1BoundingBox enables a fast all-integer PCA approximation on 4-color blocks. + // At level 0 options (no other flags), this is ~15% faster, and higher *average* quality. + cEncodeBC1BoundingBox = 64, + + // Use a slightly lower quality, but ~30% faster MSE evaluation function for 4-color blocks. + cEncodeBC1UseFasterMSEEval = 128, + + // Examine all colors to compute selectors/MSE (slower than default) + cEncodeBC1UseFullMSEEval = 256, + + // Use 2D least squares+inset+optimal rounding (the method used in Humus's GPU texture encoding demo), instead of PCA. + // Around 18% faster, very slightly lower average quality to better (depends on the content). + cEncodeBC1Use2DLS = 512, + + // Use 6 power iterations vs. 4 for PCA. + cEncodeBC1Use6PowerIters = 2048, + + // Check all total orderings - *very* slow. The encoder is not designed to be used in this way. + cEncodeBC1Exhaustive = 8192, + + // Try 2 different ways of choosing the initial endpoints. + cEncodeBC1TryAllInitialEndponts = 16384, + + // Same as cEncodeBC1BoundingBox, but implemented using integer math (faster, slightly less quality) + cEncodeBC1BoundingBoxInt = 32768, + + // Try refining the final endpoints by examining nearby colors. + cEncodeBC1EndpointSearchRoundsShift = 22, + cEncodeBC1EndpointSearchRoundsMask = 1023U << cEncodeBC1EndpointSearchRoundsShift, + }; + + const uint32_t MIN_TOTAL_ORDERINGS = 1; + const uint32_t MAX_TOTAL_ORDERINGS3 = 32; + +#if RGBCX_USE_SMALLER_TABLES + const uint32_t MAX_TOTAL_ORDERINGS4 = 32; +#else + const uint32_t MAX_TOTAL_ORDERINGS4 = 128; +#endif + + // DEFAULT_TOTAL_ORDERINGS_TO_TRY is around 3x faster than libsquish at slightly higher average quality. 10-16 is a good range to start to compete against libsquish. + const uint32_t DEFAULT_TOTAL_ORDERINGS_TO_TRY = 10; + + const uint32_t DEFAULT_TOTAL_ORDERINGS_TO_TRY3 = 1; + + // Encodes a 4x4 block of RGBX (X=ignored) pixels to BC1 format. + // This is the simplified interface for BC1 encoding, which accepts a level parameter and converts that to the best overall flags. + // The pixels are in RGBA format, where R is first in memory. The BC1 encoder completely ignores the alpha channel (i.e. there is no punchthrough alpha support). + // This is the recommended function to use for BC1 encoding, becuase it configures the encoder for you in the best possible way (on average). + // Note that the 3 color modes won't be used at all until level 5 or higher. + // No transparency supported, however if you set use_transparent_texels_for_black to true the encocer will use transparent selectors on very dark/black texels to reduce MSE. + const uint32_t MIN_LEVEL = 0, MAX_LEVEL = 18; + void encode_bc1(uint32_t level, void* pDst, const uint8_t* pPixels, bool allow_3color, bool use_transparent_texels_for_black, const uint8_t* pForce_selectors = nullptr); + + // Low-level interface for BC1 encoding. + // Always returns a 4 color block, unless cEncodeBC1Use3ColorBlocksForBlackPixels or cEncodeBC1Use3ColorBlock flags are specified. + // total_orderings_to_try controls the perf. vs. quality tradeoff on 4-color blocks when the cEncodeBC1UseLikelyTotalOrderings flag is used. It must range between [MIN_TOTAL_ORDERINGS, MAX_TOTAL_ORDERINGS4]. + // total_orderings_to_try3 controls the perf. vs. quality tradeoff on 3-color bocks when the cEncodeBC1UseLikelyTotalOrderings and the cEncodeBC1Use3ColorBlocks flags are used. Valid range is [0,MAX_TOTAL_ORDERINGS3] (0=disabled). + void encode_bc1(void* pDst, const uint8_t* pPixels, uint32_t flags = 0, uint32_t total_orderings_to_try = DEFAULT_TOTAL_ORDERINGS_TO_TRY, uint32_t total_orderings_to_try3 = DEFAULT_TOTAL_ORDERINGS_TO_TRY3, const uint8_t *pForce_selectors = nullptr); + + // Constants used for high quality BC4/BC5 encoding (and alpha of BC3) + const uint32_t BC4_DEFAULT_SEARCH_RAD = 3; + const uint32_t BC4_USE_MODE8_FLAG = 1; + const uint32_t BC4_USE_MODE6_FLAG = 2; + const uint32_t BC4_USE_ALL_MODES = 3; + + // Encodes a 4x4 block of RGBA pixels to BC3 format. + // There are two encode_bc3() functions. + // The first is the recommended function, which accepts a level parameter. + // The second is a low-level version that allows fine control over BC1 encoding. + void encode_bc3(uint32_t level, void* pDst, const uint8_t* pPixels); + void encode_bc3(void* pDst, const uint8_t* pPixels, uint32_t flags = 0, uint32_t total_orderings_to_try = DEFAULT_TOTAL_ORDERINGS_TO_TRY); + void encode_bc3_hq(uint32_t level, void* pDst, const uint8_t* pPixels, uint32_t alpha_search_rad = BC4_DEFAULT_SEARCH_RAD, uint32_t alpha_modes = BC4_USE_ALL_MODES); + + // Encodes a single channel to BC4. + // stride is the source pixel stride in bytes. + void encode_bc4(void* pDst, const uint8_t* pPixels, uint32_t stride = 4); + uint32_t encode_bc4_hq(void* pDst, const uint8_t* pPixels, uint32_t stride = 4, uint32_t search_rad = BC4_DEFAULT_SEARCH_RAD, uint32_t mode_flag = BC4_USE_ALL_MODES, const uint8_t* pForce_selectors = nullptr); + + // Encodes two channels to BC5. + // chan0/chan1 control which channels, stride is the source pixel stride in bytes. + void encode_bc5(void* pDst, const uint8_t* pPixels, uint32_t chan0 = 0, uint32_t chan1 = 1, uint32_t stride = 4); + void encode_bc5_hq(void* pDst, const uint8_t* pPixels, uint32_t chan0 = 0, uint32_t chan1 = 1, uint32_t stride = 4, uint32_t alpha_search_rad = BC4_DEFAULT_SEARCH_RAD, uint32_t alpha_modes = BC4_USE_ALL_MODES); + + // Decompression functions. + + bool unpack_bc1_block_colors(const void* pBlock_bits, color32* c, bc1_approx_mode mode = bc1_approx_mode::cBC1Ideal); + + // Returns true if the block uses 3 color punchthrough alpha mode. + bool unpack_bc1(const void* pBlock_bits, void* pPixels, bool set_alpha = true, bc1_approx_mode mode = bc1_approx_mode::cBC1Ideal); + + void unpack_bc4(const void* pBlock_bits, uint8_t* pPixels, uint32_t stride = 4); + + // Returns true if the block uses 3 color punchthrough alpha mode. + bool unpack_bc3(const void* pBlock_bits, void* pPixels, bc1_approx_mode mode = bc1_approx_mode::cBC1Ideal); + + void unpack_bc5(const void* pBlock_bits, void* pPixels, uint32_t chan0 = 0, uint32_t chan1 = 1, uint32_t stride = 4); + + // Rate Distortion Optimization (RDO) + enum dxt_constants + { + cDXT1SelectorBits = 2U, cDXT1SelectorValues = 1U << cDXT1SelectorBits, cDXT1SelectorMask = cDXT1SelectorValues - 1U, + cDXT5SelectorBits = 3U, cDXT5SelectorValues = 1U << cDXT5SelectorBits, cDXT5SelectorMask = cDXT5SelectorValues - 1U, + }; + + struct bc1_block + { + enum { cTotalEndpointBytes = 2, cTotalSelectorBytes = 4 }; + + uint8_t m_low_color[cTotalEndpointBytes]; + uint8_t m_high_color[cTotalEndpointBytes]; + uint8_t m_selectors[cTotalSelectorBytes]; + + inline uint32_t get_low_color() const { return m_low_color[0] | (m_low_color[1] << 8U); } + inline uint32_t get_high_color() const { return m_high_color[0] | (m_high_color[1] << 8U); } + inline bool is_3color() const { return get_low_color() <= get_high_color(); } + inline void set_low_color(uint16_t c) { m_low_color[0] = static_cast(c & 0xFF); m_low_color[1] = static_cast((c >> 8) & 0xFF); } + inline void set_high_color(uint16_t c) { m_high_color[0] = static_cast(c & 0xFF); m_high_color[1] = static_cast((c >> 8) & 0xFF); } + inline uint32_t get_selector(uint32_t x, uint32_t y) const { assert((x < 4U) && (y < 4U)); return (m_selectors[y] >> (x * cDXT1SelectorBits)) & cDXT1SelectorMask; } + inline void set_selector(uint32_t x, uint32_t y, uint32_t val) { assert((x < 4U) && (y < 4U) && (val < 4U)); m_selectors[y] &= (~(cDXT1SelectorMask << (x * cDXT1SelectorBits))); m_selectors[y] |= (val << (x * cDXT1SelectorBits)); } + + inline uint32_t get_endpoint_bits() const { return m_low_color[0] | (m_low_color[1] << 8) | (m_high_color[0] << 16) | (m_high_color[1] << 24); } + inline void set_endpoint_bits(uint32_t s) { m_low_color[0] = (uint8_t)s; m_low_color[1] = (uint8_t)(s >> 8); m_high_color[0] = (uint8_t)(s >> 16); m_high_color[1] = (uint8_t)(s >> 24); } + + inline uint32_t get_selector_bits() const { return m_selectors[0] | (m_selectors[1] << 8) | (m_selectors[2] << 16) | (m_selectors[3] << 24); } + inline void set_selector_bits(uint32_t s) { m_selectors[0] = (uint8_t)s; m_selectors[1] = (uint8_t)(s >> 8); m_selectors[2] = (uint8_t)(s >> 16); m_selectors[3] = (uint8_t)(s >> 24); } + + inline bool any_selectors_transparent() const + { + uint32_t sel_bits = get_selector_bits(); + for (uint32_t i = 0; i < 16; i++) + { + if ((sel_bits & 3) == 3) + return true; + + sel_bits >>= 2; + } + return false; + } + + static inline uint16_t pack_color(const color32& color, bool scaled, uint32_t bias = 127U) + { + uint32_t r = color.r, g = color.g, b = color.b; + if (scaled) + { + r = (r * 31U + bias) / 255U; + g = (g * 63U + bias) / 255U; + b = (b * 31U + bias) / 255U; + } + return static_cast(minimum(b, 31U) | (minimum(g, 63U) << 5U) | (minimum(r, 31U) << 11U)); + } + + static inline uint16_t pack_unscaled_color(uint32_t r, uint32_t g, uint32_t b) { return static_cast(b | (g << 5U) | (r << 11U)); } + + static inline void unpack_color(uint32_t c, uint32_t& r, uint32_t& g, uint32_t& b) + { + r = (c >> 11) & 31; + g = (c >> 5) & 63; + b = c & 31; + + r = (r << 3) | (r >> 2); + g = (g << 2) | (g >> 4); + b = (b << 3) | (b >> 2); + } + + static inline void unpack_color_unscaled(uint32_t c, uint32_t& r, uint32_t& g, uint32_t& b) + { + r = (c >> 11) & 31; + g = (c >> 5) & 63; + b = c & 31; + } + }; + + struct bc4_block + { + enum { cBC4SelectorBits = 3, cTotalSelectorBytes = 6, cMaxSelectorValues = 8 }; + uint8_t m_endpoints[2]; + + uint8_t m_selectors[cTotalSelectorBytes]; + + inline uint32_t get_low_alpha() const { return m_endpoints[0]; } + inline uint32_t get_high_alpha() const { return m_endpoints[1]; } + inline bool is_alpha6_block() const { return get_low_alpha() <= get_high_alpha(); } + + inline uint64_t get_selector_bits() const + { + return ((uint64_t)((uint32_t)m_selectors[0] | ((uint32_t)m_selectors[1] << 8U) | ((uint32_t)m_selectors[2] << 16U) | ((uint32_t)m_selectors[3] << 24U))) | + (((uint64_t)m_selectors[4]) << 32U) | + (((uint64_t)m_selectors[5]) << 40U); + } + + inline void set_selector_bits(uint64_t v) + { + for (uint32_t i = 0; i < 6; i++) + { + m_selectors[i] = (uint8_t)v; + v >>= 8; + } + } + + inline uint32_t get_selector(uint32_t x, uint32_t y, uint64_t selector_bits) const + { + assert((x < 4U) && (y < 4U)); + return (selector_bits >> (((y * 4) + x) * cBC4SelectorBits)) & (cMaxSelectorValues - 1); + } + + static inline uint32_t get_block_values6(uint8_t* pDst, uint32_t l, uint32_t h) + { + pDst[0] = static_cast(l); + pDst[1] = static_cast(h); + pDst[2] = static_cast((l * 4 + h) / 5); + pDst[3] = static_cast((l * 3 + h * 2) / 5); + pDst[4] = static_cast((l * 2 + h * 3) / 5); + pDst[5] = static_cast((l + h * 4) / 5); + pDst[6] = 0; + pDst[7] = 255; + return 6; + } + + static inline uint32_t get_block_values8(uint8_t* pDst, uint32_t l, uint32_t h) + { + pDst[0] = static_cast(l); + pDst[1] = static_cast(h); + pDst[2] = static_cast((l * 6 + h) / 7); + pDst[3] = static_cast((l * 5 + h * 2) / 7); + pDst[4] = static_cast((l * 4 + h * 3) / 7); + pDst[5] = static_cast((l * 3 + h * 4) / 7); + pDst[6] = static_cast((l * 2 + h * 5) / 7); + pDst[7] = static_cast((l + h * 6) / 7); + return 8; + } + + static inline uint32_t get_block_values(uint8_t* pDst, uint32_t l, uint32_t h) + { + if (l > h) + return get_block_values8(pDst, l, h); + else + return get_block_values6(pDst, l, h); + } + }; + +} + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright(c) 2020 Richard Geldreich, Jr. +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files(the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions : +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain(www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non - commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain.We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors.We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ + diff --git a/external/bc7enc_rdo/rgbcx_table4.h b/external/bc7enc_rdo/rgbcx_table4.h new file mode 100644 index 0000000000..cda3f0a1ac --- /dev/null +++ b/external/bc7enc_rdo/rgbcx_table4.h @@ -0,0 +1,969 @@ +{ 202,403,51,450,318,23,120,13,494,5,523,260,77,21,15,128,48,141,33,817,137,269,12,102,1,475,4,326,7,32,453,64,196,115,730,49,165,2,82,342,6,401,180,31,899,59,402,351,197,17,125,457,14,386,40,3,61,58,37,221,95,16,99,719,98,20,10,854,117,153,27,576,134,341,308,216,11,194,30,24,922,285,9,50,86,65,19,615,391,44,75,237,177,90,352,93,56,22,18,116,70,96,247,291,45,110,105,60,57,54,43,36,0,217,421,203,46,629,569,365,210,92,69,66,38,28,144,551 }, +{ 13,115,51,23,141,217,269,137,318,202,77,21,317,5,64,4,291,2,352,7,32,33,6,372,0,48,365,3,102,349,12,341,177,180,10,237,9,221,403,165,752,22,11,244,28,308,15,128,247,197,49,16,494,125,98,40,120,498,31,90,304,143,95,93,437,196,144,86,44,864,153,18,678,342,901,39,24,30,203,160,117,105,475,14,482,253,457,873,59,35,579,36,569,450,206,72,99,17,717,401,241,453,110,546,201,83,421,61,37,326,260,509,284,275,96,8,109,57,391,386,468,134,82,961,822,576,89,68 }, +{ 29,58,262,74,287,52,151,331,171,500,396,334,75,27,635,220,53,1,26,409,6,324,5,70,145,223,163,112,73,50,45,549,445,113,297,19,675,651,46,61,502,307,14,17,34,573,186,80,394,436,583,315,138,38,21,767,250,491,820,350,64,2,32,357,42,852,25,764,309,67,802,96,631,48,606,780,243,881,103,241,115,807,13,4,155,181,11,106,611,614,278,153,23,108,69,845,841,308,400,72,853,200,66,196,226,237,587,632,24,281,785,133,128,125,117,380,95,474,294,83,197,90,161,134,366,236,760,311 }, +{ 40,51,62,33,453,14,23,56,730,196,475,99,12,34,139,775,153,403,585,440,102,38,130,47,162,17,108,880,117,11,202,57,361,84,123,27,184,236,4,128,19,2,670,136,54,26,111,134,13,161,277,719,152,6,377,183,5,59,211,53,412,485,46,328,77,711,78,21,556,452,65,283,421,129,37,514,507,402,176,29,25,229,401,488,757,45,76,205,899,322,32,177,494,527,383,497,457,249,300,114,215,555,386,119,133,0,349,115,3,862,1,165,73,41,523,72,200,64,291,217,80,305,22,318,194,308,18,714 }, +{ 33,51,102,202,23,128,196,13,64,153,40,12,141,99,403,15,10,269,77,139,475,453,5,318,117,2,14,134,1,86,165,120,401,3,0,22,137,6,197,277,17,402,180,21,421,494,37,115,31,82,38,9,95,342,93,7,110,351,125,457,65,36,361,49,54,19,260,111,44,291,237,28,8,11,194,961,719,352,217,18,485,523,308,730,386,326,210,450,328,300,98,899,27,32,341,48,25,670,34,50,629,26,24,503,498,285,317,67,817,143,365,177,509,41,164,116,757,55,46,203,569,898,373,114,144,16,349,775 }, +{ 13,23,51,115,77,177,202,4,141,32,40,33,217,64,128,90,269,102,59,318,11,291,0,137,403,22,21,7,165,197,15,210,247,180,16,117,153,352,14,2,125,494,10,49,237,18,95,453,6,9,1,24,28,349,475,216,12,342,317,304,3,196,86,98,275,134,31,17,35,25,365,308,19,341,44,36,372,30,93,20,401,76,241,402,139,752,57,244,105,386,37,26,260,110,288,120,116,48,326,421,221,285,901,38,99,82,498,39,468,55,523,143,111,482,65,300,214,450,203,457,351,43,29,27,8,576,678,569 }, +{ 235,26,19,648,624,630,78,47,122,444,145,27,665,112,85,42,390,416,813,113,130,65,680,64,711,25,453,108,644,6,53,73,138,256,95,412,22,730,29,289,90,194,34,525,74,690,32,297,128,45,196,250,287,133,445,86,283,214,236,237,137,222,884,200,746,59,52,312,77,280,632,0,17,114,835,51,123,14,288,881,28,307,180,57,381,141,183,70,4,472,10,33,76,337,3,389,247,315,2,18,368,849,874,573,23,58,544,153,151,436,102,322,99,352,36,1,177,714,719,125,597,63,165,519,285,49,13,396 }, +{ 64,352,751,141,217,247,237,304,269,954,437,372,177,947,312,86,318,349,180,875,95,864,291,597,498,128,678,77,232,92,115,317,752,32,202,588,59,197,579,90,638,392,652,76,210,546,260,1,448,126,340,164,18,303,13,165,275,14,582,120,633,205,179,69,156,296,35,230,391,888,267,572,28,16,379,851,660,96,717,314,0,23,863,49,195,39,223,5,386,137,75,509,107,571,563,46,194,526,309,21,450,342,288,140,83,24,330,87,70,50,12,9,514,365,246,199,100,65,36,385,55,125,658,244,326,264,696,453 }, +{ 642,898,638,180,901,341,82,197,951,10,762,253,165,15,752,811,479,244,143,365,569,873,242,110,506,351,31,8,116,55,137,115,317,499,141,352,44,338,206,373,386,854,164,22,758,93,37,217,36,1,417,77,629,661,21,717,33,9,564,160,401,456,30,4,203,559,5,509,86,28,326,102,282,268,535,0,13,308,170,269,11,498,391,51,120,2,457,64,704,965,40,32,23,299,421,482,148,615,39,318,533,3,169,961,801,202,260,851,576,117,247,221,349,372,670,968,403,468,291,285,128,824,134,719,237,734,177,342 }, +{ 51,221,23,254,308,438,21,125,166,39,530,656,159,401,49,13,158,115,386,421,688,613,629,228,743,48,518,190,627,453,0,829,333,30,105,912,341,9,670,424,827,165,406,217,404,840,669,391,137,274,197,301,286,272,170,468,457,95,89,22,770,242,33,310,109,569,938,393,960,1,101,36,88,773,538,364,890,131,616,100,28,219,456,344,64,479,679,734,327,846,365,261,55,317,32,5,4,492,180,68,67,482,237,475,793,385,2,367,16,7,347,293,371,224,86,35,719,762,578,332,202,102,442,865,12,949,351,98 }, +{ 1,143,31,197,44,116,242,2,180,125,23,55,206,13,93,498,5,8,115,341,36,752,638,338,141,268,64,901,165,456,0,203,951,546,479,365,873,253,417,4,569,137,15,762,506,237,12,352,965,120,3,299,244,170,164,7,22,282,51,144,6,86,864,21,269,384,558,128,37,9,457,326,844,492,160,961,391,499,202,509,599,870,260,317,685,434,127,217,824,393,373,489,629,77,98,903,308,33,559,332,811,473,301,318,401,102,963,28,386,564,918,367,110,105,911,285,959,523,134,482,740,678,169,617,14,96,758,450 }, +{ 12,23,51,37,13,99,14,38,15,196,328,54,21,134,153,64,453,401,117,128,2,33,139,120,308,5,82,141,361,0,277,29,403,351,719,165,10,115,629,457,46,475,89,450,22,32,110,260,1,31,269,93,9,137,8,386,202,125,86,18,40,111,52,180,17,49,48,4,102,72,477,523,474,326,318,45,898,3,44,402,197,77,730,203,28,24,6,19,421,854,961,352,237,194,114,65,155,373,116,50,36,498,242,236,221,98,55,16,25,7,217,391,569,880,615,41,546,144,509,59,316,79,57,514,494,317,899,488 }, +{ 13,23,15,961,457,115,569,51,165,38,197,2,4,1,474,5,719,99,629,77,0,14,37,401,3,33,7,94,6,128,11,40,10,453,59,64,153,79,509,482,54,17,21,328,111,89,139,277,12,102,498,188,9,152,141,734,76,157,873,386,196,402,32,475,177,117,72,391,36,8,730,758,237,45,304,57,403,134,579,148,202,775,22,523,341,29,431,318,317,308,120,546,62,313,468,437,86,405,217,180,361,50,269,46,342,90,31,143,16,48,44,339,184,19,49,27,18,749,41,450,880,542,205,901,300,216,164,52 }, +{ 15,10,12,0,1,23,961,197,5,82,2,4,3,120,134,457,7,165,260,33,51,9,6,11,351,31,22,21,14,64,8,180,40,450,110,141,386,898,719,523,37,17,153,102,77,117,44,341,217,32,326,93,36,854,269,317,115,18,730,352,49,922,196,365,202,901,28,38,99,59,291,817,125,318,16,569,453,403,55,498,475,111,48,30,94,372,349,342,752,41,391,139,72,474,128,19,899,373,210,203,57,873,661,177,494,98,79,86,143,95,509,27,76,401,89,864,615,304,116,431,144,482,758,137,35,45,29,277 }, +{ 23,51,13,961,719,457,730,401,453,386,758,165,99,899,328,0,10,9,2,1,308,15,134,33,7,6,5,117,54,12,153,11,523,4,391,403,197,629,40,139,14,22,361,28,202,509,128,402,236,231,888,488,369,111,87,57,196,514,79,115,880,317,65,35,817,377,3,291,46,176,77,49,44,38,31,8,450,64,585,477,244,180,141,498,120,507,412,283,102,59,775,475,114,108,62,52,546,237,188,160,157,152,137,94,452,383,260,95,56,440,215,830,774,757,622,569,494,485,472,342,330,300,275,210,203,201,187,144 }, +{ 134,898,82,117,13,23,33,102,153,77,351,341,196,197,110,260,961,180,901,10,120,165,115,111,457,8,450,854,177,40,569,51,94,365,37,11,922,523,277,4,326,291,0,79,55,342,1,9,93,642,12,217,59,352,817,202,5,730,317,21,873,719,141,31,661,811,629,349,16,98,509,373,386,453,372,44,64,18,54,32,3,139,203,116,615,275,22,125,269,210,899,38,318,128,2,144,752,57,479,49,704,17,28,90,30,6,564,638,95,7,403,475,137,304,494,758,474,300,48,36,391,237,498,482,105,499,14,39 }, +{ 60,126,167,191,18,71,35,121,199,16,271,24,212,92,146,150,118,575,107,68,727,566,446,132,21,273,463,108,246,7,279,467,48,653,695,608,517,589,1,101,9,598,5,354,14,649,55,562,345,522,97,98,441,375,140,0,195,22,407,640,149,28,32,223,10,156,49,298,125,13,423,755,508,953,363,221,23,411,314,46,50,781,346,447,154,37,12,818,356,95,647,302,31,230,43,69,674,2,388,20,783,809,232,621,359,189,267,362,124,175,67,293,105,51,109,65,360,493,520,236,163,607,535,75,165,103,39,33 }, +{ 136,62,129,123,128,41,162,789,211,618,249,214,183,678,248,507,38,216,710,119,152,177,269,130,64,17,57,141,245,597,318,205,184,4,179,90,503,77,59,402,305,106,3,313,229,157,266,54,210,139,102,257,275,556,209,45,117,40,13,11,292,99,328,76,457,33,339,23,452,378,217,86,291,80,194,471,369,947,349,383,188,524,497,304,542,381,255,153,519,751,494,240,361,84,803,588,202,32,440,372,115,403,742,164,56,529,12,137,37,790,21,5,504,432,207,196,10,14,285,215,134,342,36,15,587,0,358,165 }, +{ 523,494,475,403,51,899,817,453,202,23,450,730,421,13,805,120,128,757,102,5,4,719,33,21,342,318,958,326,196,153,260,402,7,1,386,12,48,133,65,20,32,457,141,9,8,615,16,114,108,14,10,77,19,0,361,137,17,300,84,82,59,351,123,3,194,576,11,700,221,401,269,95,64,49,177,541,27,40,57,26,115,125,117,22,474,308,99,37,862,701,304,193,56,503,91,697,551,134,105,283,50,129,86,24,249,240,2,942,814,673,671,579,569,519,490,468,437,397,389,365,352,349,306,291,281,247,218,208 }, +{ 59,4,84,62,77,40,3,102,76,119,27,33,56,177,32,12,161,73,21,196,136,123,17,210,11,193,216,80,90,18,64,57,128,51,6,25,13,611,300,63,202,65,48,415,42,605,106,23,152,0,99,275,22,217,803,26,49,205,122,503,291,53,5,2,37,29,349,87,667,453,402,318,209,361,19,690,283,403,718,445,342,129,14,61,194,79,436,245,370,397,297,141,86,862,485,269,240,52,91,85,494,304,510,153,95,573,115,1,45,416,249,184,139,757,475,255,133,81,529,292,41,469,111,680,250,813,113,31 }, +{ 43,414,422,319,20,819,945,7,0,376,61,904,97,470,325,173,707,5,804,693,22,104,14,49,560,426,330,95,595,32,392,17,107,147,207,887,577,246,46,21,324,356,77,74,344,725,58,52,1,198,113,784,347,28,27,18,66,38,76,427,135,105,329,31,858,25,12,158,526,291,263,112,9,523,357,239,232,120,115,362,81,230,359,118,19,10,715,450,119,241,64,44,259,424,315,24,260,140,13,942,292,350,165,102,56,45,37,36,861,125,879,817,719,600,86,33,30,2,814,204,500,476,205,98,26,16,180,179 }, +{ 13,23,51,217,115,77,141,2,33,10,4,0,64,7,180,6,102,40,11,22,317,9,14,269,352,3,1,5,202,197,15,177,341,165,59,237,291,125,365,16,12,128,28,18,247,318,308,31,153,196,349,95,372,117,36,17,24,137,49,498,98,752,32,403,304,134,90,475,342,457,453,210,143,401,93,391,19,86,44,120,30,901,275,386,8,57,105,216,244,164,569,39,65,494,509,20,29,110,25,421,864,961,139,116,873,38,55,27,719,37,35,82,50,221,482,46,260,56,26,546,450,316,468,351,326,45,899,523 }, +{ 28,49,24,105,35,65,159,0,55,109,1,16,239,320,14,7,347,95,424,158,168,170,124,9,2,185,67,68,301,18,169,654,286,149,12,289,175,36,5,127,154,21,10,71,69,114,98,64,740,83,512,39,108,13,272,48,164,327,31,23,623,420,374,395,46,50,713,125,371,518,51,194,338,577,312,6,37,143,916,22,346,344,429,570,32,86,835,103,336,761,101,928,44,638,242,890,737,60,133,202,237,293,115,538,30,762,128,141,137,38,302,398,747,484,479,165,439,189,96,844,610,92,221,299,892,308,54,131 }, +{ 15,10,0,12,1,457,13,165,5,2,82,9,4,117,120,7,961,3,134,6,64,22,197,14,11,260,351,37,33,32,51,21,31,719,77,141,180,38,341,17,8,365,450,317,102,217,153,28,523,269,110,115,44,93,898,372,854,202,386,18,196,40,291,326,99,901,49,730,349,453,352,16,128,125,922,36,237,72,111,318,509,177,76,59,342,403,48,475,817,401,98,391,29,30,89,752,90,474,373,569,27,137,45,704,24,275,19,95,328,55,494,54,498,86,899,143,437,139,210,304,629,758,57,25,402,116,546,873 }, +{ 7,97,71,14,92,150,140,60,149,189,18,16,517,69,336,398,298,154,124,66,302,35,43,68,175,467,273,38,230,118,251,508,314,429,24,2,28,399,172,232,20,0,882,36,279,55,423,173,267,6,46,1,107,126,67,375,83,566,108,22,74,65,547,29,607,104,192,5,426,246,135,847,52,81,531,420,109,596,501,10,809,9,13,952,387,533,505,608,484,169,21,458,330,674,628,49,823,86,25,345,158,51,191,705,48,101,637,12,386,723,439,570,324,653,462,185,168,697,779,535,783,796,346,114,722,861,799,95 }, +{ 102,4,77,59,33,210,11,342,40,32,12,64,128,139,624,5,503,196,202,90,494,21,300,91,51,233,318,403,23,17,291,177,416,269,275,678,141,817,450,13,529,0,25,10,3,485,277,153,151,49,37,42,789,216,496,457,115,57,197,680,214,22,18,788,523,249,205,27,389,194,86,72,453,122,145,480,81,26,961,280,148,138,134,111,104,74,65,6,899,730,204,165,120,89,209,804,475,348,123,95,19,636,396,174,693,651,287,125,869,750,629,306,257,76,48,386,349,221,61,45,803,784,544,402,397,240,58,31 }, +{ 25,42,256,235,19,122,85,436,813,6,297,680,53,26,573,416,233,445,390,63,605,73,250,343,80,27,65,630,389,283,106,255,194,444,45,17,138,544,396,690,525,503,648,269,141,64,119,33,145,123,611,113,128,102,174,112,84,91,29,789,70,624,4,412,77,0,736,483,209,358,205,597,179,56,117,249,243,280,287,108,153,650,196,619,114,32,136,78,678,18,746,348,5,129,2,495,200,57,14,378,76,240,40,511,86,137,161,90,216,10,684,881,23,665,222,22,432,12,289,51,177,1,21,214,370,245,134,11 }, +{ 102,300,402,128,202,403,33,23,342,77,40,99,21,757,84,12,115,196,483,318,19,119,117,210,494,139,90,32,25,4,569,153,469,277,26,475,91,134,63,59,80,523,73,14,275,51,485,453,44,36,31,10,6,48,576,37,49,22,352,193,56,165,18,790,152,415,53,42,880,125,370,291,177,74,13,1,197,180,81,64,62,3,814,611,343,161,136,106,391,386,138,129,66,54,45,38,34,27,17,2,678,11,378,770,697,543,511,504,120,65,82,226,961,899,862,730,718,690,643,317,256,235,89,87,72,61,47,605 }, +{ 158,109,9,39,49,0,35,65,168,68,24,124,159,344,185,154,22,55,333,577,272,175,254,289,810,169,16,327,101,346,95,105,570,149,747,627,286,374,71,310,703,67,439,793,30,28,252,429,131,419,1,455,912,114,610,671,347,18,424,364,7,36,835,100,194,14,21,420,239,336,86,688,10,634,69,108,83,538,706,709,578,484,23,518,2,320,64,51,13,166,48,12,60,118,962,170,128,5,190,133,913,398,50,46,125,677,535,137,127,96,98,345,302,189,826,584,103,251,31,224,638,37,265,92,160,722,219,32 }, +{ 237,498,546,180,115,197,873,287,5,34,923,61,297,509,165,45,400,80,445,2,311,341,3,58,52,468,176,231,186,881,250,64,13,56,151,48,17,217,62,490,14,153,141,23,513,901,51,391,21,667,334,247,352,903,171,84,482,161,549,10,72,401,243,53,738,592,196,46,316,73,719,308,869,666,396,365,645,106,130,585,125,887,635,569,215,86,749,1,207,864,472,177,211,317,22,659,573,37,95,40,227,136,33,372,527,29,507,483,128,651,90,469,229,629,436,833,721,787,758,515,437,54,36,27,117,32,430,304 }, +{ 120,968,704,260,373,450,202,137,661,326,717,269,349,110,217,77,318,473,1,652,95,851,291,93,177,244,33,21,372,141,719,102,351,82,518,156,51,48,848,340,210,928,713,160,922,98,296,128,817,146,86,827,304,264,32,197,225,115,623,317,212,96,23,751,386,854,35,13,7,863,698,180,919,494,385,64,800,253,730,678,523,140,15,70,65,303,453,437,275,247,49,642,341,352,127,37,888,737,5,942,898,167,776,87,658,744,692,615,389,203,101,36,478,196,190,393,59,55,363,132,118,850,163,131,916,836,811,599 }, +{ 44,116,144,268,489,434,367,384,127,918,98,855,940,948,617,206,203,959,93,137,105,31,332,393,492,22,131,9,911,282,276,141,219,202,0,49,284,28,299,120,326,36,39,417,269,1,51,523,30,473,935,899,293,318,352,125,23,395,253,64,13,244,55,160,10,551,128,95,403,373,201,143,450,115,260,8,692,386,21,86,109,110,187,730,165,456,272,737,159,791,261,499,170,7,16,341,728,295,77,951,5,48,96,944,559,242,258,365,371,494,24,254,2,317,421,578,752,18,224,716,164,197,391,285,301,498,924,12 }, +{ 77,13,23,51,102,33,141,64,115,0,177,291,217,202,269,6,2,7,4,318,40,14,180,128,59,1,10,196,117,153,22,11,16,15,352,95,134,9,137,3,165,197,210,18,86,403,17,237,28,49,304,342,125,275,12,349,24,341,247,317,453,5,90,19,475,216,57,25,36,494,65,365,27,20,457,31,120,143,93,498,372,308,401,402,391,29,26,752,260,98,110,719,312,82,961,164,45,56,386,35,44,139,21,99,509,30,730,194,38,244,144,351,8,37,111,203,421,546,50,300,96,288,285,208,46,54,39,901 }, +{ 15,4,11,40,141,165,23,32,202,180,21,197,64,269,125,13,59,386,120,93,51,110,77,5,128,57,318,457,82,3,12,523,260,0,17,49,10,450,730,134,117,31,403,1,719,352,8,102,137,22,115,90,153,899,351,98,44,326,237,2,494,475,139,203,391,144,9,111,961,56,37,402,116,177,210,48,801,453,65,196,6,95,217,341,509,14,421,99,76,291,7,86,216,373,758,401,498,18,28,752,27,36,275,365,300,72,342,615,901,854,898,247,317,45,922,105,127,30,308,152,304,123,817,551,19,791,393,55 }, +{ 176,231,585,62,56,161,412,34,236,527,14,440,202,3,57,17,283,361,84,402,136,23,369,51,128,4,803,13,130,472,383,548,322,507,46,719,457,555,53,73,38,514,503,250,381,119,59,200,162,64,77,452,401,495,153,469,11,229,318,29,205,211,196,497,453,152,2,730,556,240,33,390,27,372,210,184,106,961,215,183,123,65,757,629,99,494,108,129,52,37,18,0,21,40,529,515,475,54,377,828,275,209,197,217,117,1,899,543,300,269,245,862,483,305,45,504,378,342,297,111,102,76,50,24,10,95,12,611 }, +{ 101,9,237,180,0,352,217,230,498,141,100,88,702,115,68,317,83,175,213,39,365,1,252,30,345,752,64,546,482,208,321,864,265,341,490,562,13,372,818,336,952,399,128,69,36,244,197,212,96,410,21,154,689,269,158,28,251,289,166,194,65,382,419,48,443,759,596,901,873,23,468,67,51,16,547,831,797,165,570,55,285,264,930,329,49,756,646,346,124,694,144,391,579,799,854,247,35,190,189,164,699,755,24,364,203,777,323,238,429,569,768,435,37,724,466,201,349,12,509,723,840,50,789,826,160,676,291,137 }, +{ 28,22,49,109,9,39,1,95,0,105,158,168,83,185,159,55,86,30,96,208,141,272,128,12,420,5,505,13,31,327,169,160,131,69,67,137,23,202,21,64,115,251,286,254,51,35,98,127,2,101,244,44,238,194,48,197,50,531,10,7,217,927,180,533,175,352,584,103,285,269,165,37,65,218,100,535,317,323,68,374,946,239,597,24,837,735,289,797,896,418,341,347,333,601,170,116,346,365,237,143,318,345,678,32,344,125,16,164,498,627,253,752,402,577,424,310,4,219,99,403,252,6,312,144,578,166,789,242 }, +{ 72,76,38,89,51,477,4,413,308,179,474,12,152,401,57,148,59,11,205,99,54,421,670,23,245,17,629,431,79,488,405,90,94,184,13,569,21,453,32,229,128,3,358,45,197,14,475,188,77,528,157,464,316,165,257,543,115,41,288,202,457,428,961,216,15,341,403,40,734,266,5,339,749,10,64,33,2,452,328,217,645,460,141,775,111,313,468,1,247,361,102,277,432,743,365,381,587,482,62,509,37,269,0,769,497,471,285,137,402,177,794,449,155,6,318,542,377,86,805,181,129,9,369,7,153,524,349,243 }, +{ 23,13,457,961,15,51,165,629,12,719,11,3,197,2,1,37,0,117,5,569,7,509,33,153,40,196,6,134,328,99,9,542,391,237,17,474,139,111,277,64,453,54,730,546,386,401,57,4,38,14,514,45,775,59,734,361,115,21,102,41,498,477,77,873,431,475,880,369,339,19,587,62,89,377,29,27,523,479,248,128,758,308,482,352,291,275,210,32,8,468,413,164,94,155,659,428,864,752,751,579,494,405,403,397,342,247,240,216,184,180,171,148,122,106,91,84,72,56,52,34,721,188,157,79,654,597,312,95 }, +{ 254,310,100,166,625,9,265,272,30,731,190,39,404,557,688,1,578,131,98,593,101,616,438,264,0,31,829,252,795,716,127,21,382,51,812,49,88,93,613,48,105,827,478,274,18,639,329,36,44,656,23,203,363,68,411,96,682,159,16,116,327,160,242,128,333,13,5,938,910,224,35,447,286,676,144,165,921,530,67,228,137,520,125,219,223,22,724,455,86,33,846,110,284,118,627,905,120,24,77,115,65,83,737,435,32,158,856,664,95,326,924,821,102,518,167,960,202,385,395,931,371,406,10,69,403,55,709,40 }, +{ 51,23,202,99,128,12,15,13,120,403,10,453,153,196,141,64,165,5,318,117,475,82,197,269,401,33,260,2,37,3,1,110,0,14,180,93,386,22,21,450,421,31,402,115,125,137,17,351,134,326,102,494,6,38,308,457,44,36,4,77,11,95,523,28,49,7,9,8,719,237,352,730,32,203,116,391,373,57,18,98,59,361,86,54,19,89,285,775,328,277,757,498,341,854,111,16,27,139,72,45,48,41,143,79,509,961,898,758,342,291,65,474,488,30,569,217,144,56,901,242,899,670,34,24,678,817,922,194 }, +{ 38,99,542,453,139,196,117,457,23,328,13,111,37,134,961,11,12,775,401,51,587,40,474,153,277,477,54,629,475,33,719,79,165,41,14,569,157,4,413,188,89,115,64,339,734,308,15,361,369,197,313,102,94,247,155,45,248,236,57,514,72,758,402,128,181,485,377,509,86,237,488,0,403,266,141,46,10,164,211,471,184,588,65,180,29,2,875,528,490,95,76,22,5,50,17,7,721,670,391,49,18,503,817,789,431,21,257,216,32,208,305,177,136,1,880,803,352,140,342,260,229,202,67,867,597,59,757,899 }, +{ 85,6,233,343,91,25,138,26,63,174,256,235,122,29,19,81,283,65,605,648,42,718,445,370,4,74,59,573,389,416,194,396,45,177,544,297,355,64,141,348,145,77,114,216,123,280,436,881,133,680,432,87,70,511,137,108,27,128,57,630,0,11,415,18,90,503,619,86,412,40,287,17,397,789,222,14,73,269,32,66,52,291,204,243,56,22,209,275,597,104,76,72,529,148,678,84,80,119,53,643,304,210,208,285,33,46,2,523,5,311,813,636,510,381,255,10,524,112,102,403,289,214,152,483,62,736,525,349 }, +{ 49,5,197,408,193,18,20,61,713,350,173,21,64,97,509,95,729,841,263,0,241,32,165,104,43,422,65,125,35,510,60,474,7,120,102,523,397,14,48,232,260,128,347,68,546,387,38,58,693,403,16,105,81,71,115,784,10,560,91,72,6,862,27,92,51,707,344,22,9,237,319,29,414,107,55,66,643,147,663,450,391,498,240,357,70,468,90,2,751,370,98,701,84,819,903,330,207,623,141,63,52,718,569,308,864,475,25,159,74,283,356,326,158,86,12,900,494,137,171,42,221,202,85,734,386,847,873,650 }, +{ 434,144,268,489,116,384,367,855,940,206,617,332,959,911,127,93,44,98,203,137,276,282,219,202,131,22,141,31,417,284,918,9,36,105,28,201,269,258,244,120,473,23,318,523,51,326,253,1,450,39,0,30,352,160,948,143,10,13,8,110,49,64,125,55,551,935,951,692,295,187,128,21,86,261,567,260,499,559,373,96,224,170,899,386,242,115,299,817,95,662,728,293,165,197,811,395,159,48,492,365,109,317,498,403,37,752,341,393,836,638,717,5,180,254,77,15,272,851,164,24,944,494,237,385,16,7,301,391 }, +{ 106,17,255,32,64,62,136,292,162,129,476,352,237,214,123,519,241,720,141,752,498,247,211,41,119,209,864,507,249,180,179,290,710,954,425,148,317,618,197,90,186,21,5,115,248,77,76,269,217,183,45,48,14,227,130,3,263,12,304,38,165,128,243,546,23,2,358,207,117,164,57,579,51,245,205,54,454,313,152,350,177,13,155,873,339,270,50,4,428,378,157,655,449,496,305,400,365,171,86,1,437,742,556,372,369,408,471,328,266,216,33,80,153,139,460,181,597,542,316,40,102,29,751,59,361,257,84,341 }, +{ 2,29,52,58,5,50,27,6,53,26,171,45,366,151,14,287,61,19,357,74,17,73,764,1,113,34,297,309,218,262,181,38,133,48,583,70,487,600,739,334,25,396,250,760,281,96,186,445,516,75,502,635,315,114,308,108,3,223,80,549,42,545,103,331,324,106,200,163,112,21,785,67,436,145,603,238,401,243,51,37,651,433,155,834,491,675,236,99,745,209,161,13,845,32,227,115,409,23,894,388,765,12,56,36,311,255,220,920,766,138,323,453,573,24,594,62,59,65,832,754,160,86,54,307,283,83,285,629 }, +{ 130,711,412,381,59,196,210,730,236,77,402,401,803,202,453,361,99,108,283,291,153,57,183,128,503,421,4,51,14,719,432,11,318,275,117,23,529,757,3,475,13,339,457,133,488,123,670,899,603,369,134,33,65,46,266,386,2,47,754,12,32,389,114,38,838,56,300,40,102,177,739,111,961,523,629,328,758,64,54,90,216,514,269,21,594,0,743,37,775,657,576,894,403,152,650,194,471,34,200,5,832,162,50,494,805,472,18,165,22,6,29,181,95,285,10,129,188,480,15,1,322,24,229,342,139,714,79,86 }, +{ 13,23,51,217,115,77,141,33,4,64,10,202,102,180,0,40,317,352,177,11,291,269,197,165,9,32,22,59,7,2,128,318,341,18,15,21,237,137,117,6,16,5,95,3,153,403,125,349,365,14,247,752,49,12,196,28,31,453,90,1,24,98,304,17,143,494,372,308,244,475,498,134,210,221,120,901,401,36,342,421,86,93,44,30,216,260,35,164,457,19,110,275,569,391,57,386,203,105,326,55,864,82,402,523,241,139,8,450,39,873,730,719,144,65,20,253,160,27,351,116,72,29,437,509,37,629,285,546 }, +{ 23,13,202,51,21,269,141,120,5,48,128,137,318,523,15,102,125,98,1,450,93,403,165,260,64,197,77,33,180,12,457,32,221,82,817,115,44,110,31,7,352,494,2,386,475,308,117,4,153,326,14,401,719,116,196,421,37,237,16,453,9,144,730,351,17,99,6,30,291,402,203,18,11,899,19,24,217,96,498,40,391,20,10,39,95,854,3,341,50,134,349,293,373,177,615,35,365,65,139,0,45,285,372,61,8,317,90,922,805,901,342,59,43,898,76,29,509,393,127,86,752,170,208,105,89,72,67,38 }, +{ 2,1,46,14,52,29,171,67,38,103,58,75,70,69,163,24,83,223,5,96,309,181,54,186,112,334,108,45,394,675,155,366,220,35,238,151,16,236,409,18,281,760,307,133,537,400,36,71,189,328,227,433,28,218,766,61,545,65,17,487,149,7,48,552,21,502,0,12,262,19,87,6,765,114,25,388,267,150,113,820,418,50,549,27,26,37,251,22,99,335,430,486,32,60,536,287,68,587,9,828,55,64,74,243,10,516,137,160,86,66,128,311,600,696,739,852,583,451,336,315,514,72,135,80,175,145,89,294 }, +{ 15,2,1,13,0,10,153,5,9,7,12,23,3,14,117,6,165,134,4,719,457,196,82,341,180,197,33,22,120,115,77,8,961,21,64,217,102,317,569,365,351,141,260,32,31,18,28,291,11,16,110,111,37,125,93,386,17,202,40,450,269,372,730,901,99,898,44,36,177,854,38,342,349,352,48,523,758,318,453,57,128,401,391,304,72,76,403,19,922,326,752,29,629,49,509,475,237,137,116,98,89,55,373,95,24,27,26,30,494,247,59,482,86,25,210,96,54,46,437,899,139,65,253,817,661,498,308,873 }, +{ 509,197,546,391,165,180,308,13,23,498,569,29,873,115,901,5,401,61,457,903,80,734,629,468,3,287,34,2,45,758,311,445,250,579,297,341,961,237,17,186,171,749,386,51,14,38,217,231,48,58,62,400,46,752,247,64,211,176,490,106,719,56,764,738,667,227,215,349,151,11,558,316,502,513,833,32,161,243,54,317,153,196,50,21,53,40,365,583,155,923,10,6,587,334,305,483,33,4,369,372,181,136,1,125,119,12,482,130,552,263,57,52,95,123,814,266,84,832,495,645,739,864,96,15,787,472,129,36 }, +{ 73,19,250,27,714,200,444,472,26,34,813,53,390,322,17,283,78,297,106,630,436,113,122,690,123,432,136,128,176,862,161,389,503,684,611,495,80,378,62,42,108,529,14,56,469,57,25,412,236,177,59,47,65,102,6,216,275,3,381,680,235,179,527,605,84,129,383,130,619,183,368,46,255,814,33,23,318,2,789,77,141,13,453,194,245,51,11,445,45,4,152,63,650,269,22,90,64,0,133,440,29,349,40,585,86,678,736,291,95,196,153,184,361,18,210,38,58,803,401,5,117,10,114,358,61,730,249,119 }, +{ 17,21,3,45,62,32,155,119,106,38,5,328,14,828,227,76,2,401,209,123,129,243,270,115,540,29,56,536,46,12,221,488,99,13,629,57,72,719,181,51,552,290,361,136,41,37,514,165,543,152,421,408,84,48,77,308,207,255,90,306,23,263,569,11,454,52,587,162,758,378,4,89,80,754,130,402,236,197,186,440,457,27,383,157,50,1,183,311,832,128,10,794,425,59,576,961,211,741,453,805,790,86,742,496,386,34,313,54,700,600,266,148,659,202,19,94,341,22,880,509,229,240,697,770,670,548,73,177 }, +{ 115,341,873,365,197,13,901,180,569,752,317,1,509,498,10,143,15,4,634,165,268,943,261,5,258,23,237,116,141,0,127,601,244,843,282,253,164,44,12,33,64,860,638,533,219,77,144,9,567,31,134,7,2,352,864,276,160,535,51,206,217,824,125,391,8,28,951,295,11,93,332,201,40,964,844,308,137,6,3,120,531,260,22,36,482,98,177,111,318,474,417,37,170,82,961,291,196,102,169,924,434,203,153,94,954,395,734,898,384,269,242,479,965,735,405,326,30,728,662,617,386,159,24,18,944,401,301,367 }, +{ 453,51,23,33,403,475,421,196,153,102,670,13,117,753,134,40,494,523,4,730,342,0,21,65,59,22,12,880,77,11,86,801,401,719,202,48,28,899,18,805,757,64,14,10,24,128,1,629,457,99,108,57,308,5,2,217,317,139,16,485,569,165,141,36,361,341,365,177,143,125,283,386,120,82,44,9,115,221,7,817,576,300,152,137,124,123,98,61,50,46,32,6,450,111,775,543,488,417,269,197,114,110,95,93,54,35,31,402,34,17,3,911,642,564,561,554,511,431,332,277,261,253,242,239,194,170,116,96 }, +{ 23,13,51,33,12,453,196,117,99,153,134,40,102,403,14,128,202,77,15,401,475,37,139,38,54,11,64,165,421,21,2,0,141,115,308,318,719,328,65,108,670,197,10,46,457,361,269,730,79,1,22,402,28,111,120,95,82,18,3,386,9,389,6,17,283,50,36,24,86,236,114,125,775,5,494,180,4,260,31,94,41,32,899,523,19,210,110,137,59,391,7,326,488,450,351,291,217,177,412,341,93,300,485,477,509,880,377,44,39,30,277,52,221,16,8,961,629,365,203,29,758,133,26,817,350,342,237,194 }, +{ 2,7,14,5,52,29,70,61,112,46,87,592,135,1,66,45,38,16,32,6,186,21,315,290,48,227,24,72,307,113,75,172,425,20,243,58,74,97,666,128,845,631,76,226,155,294,18,738,23,270,25,35,64,141,334,115,0,89,22,50,43,163,151,37,51,171,77,207,69,17,220,36,177,202,19,262,10,13,137,9,90,232,4,54,86,92,263,269,255,278,59,496,655,60,28,95,140,26,106,27,180,12,454,192,148,67,40,209,102,318,33,292,400,849,49,65,324,331,409,405,217,491,311,461,549,476,431,210 }, +{ 33,102,128,202,51,23,141,196,64,153,13,269,318,403,77,117,10,137,134,40,1,5,453,2,6,165,3,0,14,475,86,99,139,15,180,120,12,22,494,402,17,197,352,260,19,7,95,342,21,110,237,65,82,115,93,125,31,36,37,277,18,217,210,9,49,44,25,177,291,326,523,38,450,401,194,32,457,421,285,386,26,28,351,16,111,719,27,4,11,114,48,341,203,300,8,752,98,373,143,730,361,498,57,54,365,317,24,164,961,116,569,108,275,899,50,34,391,45,41,901,96,244,29,629,133,72,509,144 }, +{ 92,16,43,20,126,107,7,35,71,97,14,60,140,246,279,68,18,149,230,121,575,356,375,191,362,24,783,150,118,55,695,566,345,48,0,359,175,173,319,598,298,232,939,22,653,441,167,463,21,414,125,819,467,407,33,69,346,38,422,146,77,446,154,608,28,649,336,172,10,199,102,101,104,168,189,637,251,212,49,314,376,2,124,51,9,595,399,221,23,66,5,392,541,755,196,470,386,13,6,158,117,768,393,147,628,551,493,683,165,67,46,36,259,108,81,1,727,535,364,342,325,672,267,281,674,120,203,153 }, +{ 13,23,77,115,51,33,59,4,177,40,90,64,102,32,141,202,10,128,22,210,291,0,11,21,117,95,137,217,16,318,196,9,180,153,7,197,165,49,28,269,6,342,14,18,2,216,1,237,134,86,98,352,349,203,326,24,403,36,494,31,125,450,120,475,275,15,93,351,341,260,194,386,105,3,247,48,57,365,373,20,372,402,317,457,44,5,139,110,17,35,30,25,12,498,76,144,116,72,39,453,304,19,300,244,208,82,60,401,143,285,65,214,55,38,26,817,569,50,678,551,391,308,123,111,46,854,509,523 }, +{ 507,162,129,211,41,183,38,123,4,248,59,62,57,556,130,99,361,402,305,128,202,11,266,136,17,3,77,803,152,497,313,452,184,210,369,33,40,471,339,56,117,757,157,54,328,229,205,494,381,23,139,457,153,12,403,84,503,257,19,34,65,13,76,514,119,275,37,188,542,14,80,106,440,475,775,318,618,102,21,134,453,300,27,432,64,880,95,89,49,141,86,196,32,529,377,249,73,79,460,177,50,5,10,90,53,619,548,342,94,401,269,179,288,587,961,383,148,114,579,115,477,216,72,45,805,285,291,217 }, +{ 643,123,193,718,650,18,802,65,389,84,415,91,177,25,90,619,256,216,87,289,511,183,736,370,217,324,380,235,108,63,808,500,432,102,249,57,275,194,152,6,673,510,304,862,240,524,355,588,561,397,233,372,13,523,130,81,96,4,0,343,605,141,1,22,103,77,59,283,214,64,789,437,306,630,23,85,153,80,33,475,597,529,210,544,349,196,129,56,291,32,27,847,300,114,889,550,138,86,886,444,269,124,28,26,416,421,280,208,174,70,10,2,814,401,115,19,851,117,42,730,469,352,204,17,202,150,73,51 }, +{ 23,13,51,15,5,1,2,7,115,0,12,6,165,141,21,3,4,457,9,197,180,32,77,14,37,202,217,10,33,120,341,352,11,269,22,8,16,93,569,961,31,401,318,102,247,719,453,308,629,17,365,18,260,403,177,317,901,386,40,48,509,137,752,44,730,28,391,498,72,117,523,128,110,153,59,450,98,494,99,196,36,372,237,30,90,49,475,134,291,326,125,24,210,95,349,89,899,482,38,116,421,468,351,304,19,76,873,82,20,139,57,734,203,86,342,373,546,54,39,437,45,65,817,854,758,922,144,96 }, +{ 51,23,13,453,21,403,12,475,202,165,141,64,128,115,32,5,95,523,125,730,494,180,197,401,899,308,48,120,37,719,386,269,318,817,457,4,99,421,3,326,1,6,237,17,450,2,260,10,19,22,14,0,217,194,18,402,77,221,90,247,15,177,27,25,26,961,59,9,7,758,137,16,670,391,352,117,11,801,312,33,110,82,50,28,241,57,40,351,123,153,49,615,317,291,72,341,210,24,86,54,61,29,196,102,216,93,56,569,31,304,170,98,275,289,46,42,20,629,361,108,58,89,389,283,144,45,84,203 }, +{ 204,74,135,174,192,66,138,85,6,280,353,348,580,172,7,673,97,889,426,500,792,568,95,87,355,32,620,64,712,29,65,91,233,81,232,222,52,448,43,872,25,825,42,104,173,888,22,289,226,63,526,86,387,5,312,636,861,49,90,237,278,2,343,415,194,560,21,0,715,92,38,214,145,140,20,256,835,324,235,330,18,10,750,61,28,75,808,1,4,26,681,288,77,36,24,70,69,58,107,45,874,347,125,14,112,314,33,72,337,102,298,241,294,707,59,729,108,180,37,115,370,40,287,76,48,356,164,117 }, +{ 35,68,149,24,69,0,65,133,103,16,189,9,28,18,50,114,175,336,124,101,1,71,154,46,83,251,14,7,2,55,283,118,230,108,218,238,38,398,345,140,705,75,54,302,443,39,596,22,532,309,335,181,96,361,418,21,399,12,52,394,565,433,412,267,346,109,60,5,29,36,486,236,48,160,375,732,831,545,23,480,487,516,51,220,92,366,86,429,10,13,64,323,328,67,49,252,30,37,330,514,364,212,100,439,547,158,389,95,87,458,194,115,32,646,891,930,246,208,70,641,171,163,6,191,223,722,167,99 }, +{ 101,118,16,71,24,9,18,154,191,212,0,35,60,520,124,68,694,806,167,364,375,252,604,346,55,302,562,628,28,39,149,917,439,126,419,92,65,826,329,100,706,589,166,108,175,265,264,21,1,273,199,109,22,701,48,925,676,49,158,7,150,363,404,10,146,942,5,88,121,815,105,411,14,967,682,67,23,535,69,13,818,566,882,50,777,907,647,429,95,159,51,96,30,12,333,621,31,2,857,848,32,107,140,722,98,575,821,246,37,847,46,382,905,221,677,169,36,336,125,553,695,83,467,593,185,759,114,286 }, +{ 35,16,9,0,68,24,65,1,18,71,149,103,67,189,101,28,21,48,212,114,23,335,486,124,13,51,39,118,167,191,55,154,7,133,238,433,50,30,443,141,96,230,22,100,140,218,60,5,137,64,537,352,115,12,88,330,217,223,75,10,128,399,37,269,49,83,411,202,32,283,175,36,31,221,246,264,98,163,398,2,281,723,375,302,69,166,478,447,125,108,487,180,54,372,317,589,44,99,520,336,181,361,345,418,318,363,177,86,695,341,664,565,77,160,95,545,562,252,70,237,116,752,532,190,72,105,92,14 }, +{ 13,23,202,77,51,128,33,32,115,102,21,269,177,141,318,64,5,217,137,494,291,11,4,10,0,48,22,153,95,210,117,86,90,196,3,15,6,317,2,49,125,349,40,18,12,342,352,9,31,17,247,304,403,194,134,36,16,7,14,450,19,275,98,180,120,1,61,44,372,216,28,341,65,165,221,326,116,76,20,260,59,523,237,365,285,203,24,35,105,453,288,143,386,678,30,351,101,68,60,55,25,817,421,475,96,901,401,367,308,293,99,93,82,39,37,27,752,312,144,615,323,730,58,72,437,859,899,316 }, +{ 16,92,60,35,7,18,68,150,24,126,149,97,191,246,375,118,14,230,107,140,71,273,575,175,517,653,154,566,55,43,298,345,167,399,0,121,28,467,20,108,279,212,101,441,346,302,336,66,423,232,508,48,22,674,124,38,356,608,314,9,21,2,189,199,359,446,49,10,695,46,5,69,1,463,65,815,589,12,172,439,607,755,251,146,37,362,67,392,23,173,6,109,13,722,125,809,702,796,628,36,32,51,95,637,74,135,354,398,52,132,83,29,429,221,407,768,882,105,672,50,64,104,86,271,501,364,535,96 }, +{ 76,90,464,21,179,316,205,288,460,245,32,257,184,148,45,358,152,57,270,48,241,38,449,89,14,2,1,350,769,645,229,155,5,497,221,54,17,524,37,243,12,59,227,405,266,428,4,452,413,308,749,432,50,619,99,720,51,29,292,476,217,11,290,46,157,115,79,188,339,129,313,216,401,381,431,471,171,341,247,77,10,94,106,513,400,3,23,64,317,141,52,7,0,365,773,474,477,72,430,528,36,659,162,369,453,181,62,214,128,33,237,741,186,9,6,281,328,13,202,102,502,349,536,498,177,291,180,372 }, +{ 19,297,26,27,813,80,436,495,17,73,53,250,122,106,200,113,378,390,690,42,4,45,469,361,59,25,742,128,136,161,77,255,202,736,445,605,402,123,862,630,40,63,318,78,383,803,56,11,235,102,283,444,119,527,6,62,210,503,680,14,57,33,148,472,209,129,684,256,84,412,667,611,18,573,85,365,483,0,177,12,3,300,814,153,504,65,22,76,139,61,34,205,133,341,117,64,51,23,13,58,269,152,90,257,10,236,2,358,497,38,432,342,95,47,368,243,183,494,757,453,619,196,184,548,171,714,475,322 }, +{ 6,26,235,138,145,112,19,42,624,122,70,648,27,331,262,85,78,47,25,500,52,632,630,226,113,444,307,644,409,453,29,222,665,163,75,50,849,324,2,65,108,390,294,64,675,53,416,711,130,220,22,34,196,17,73,813,87,32,95,680,14,280,223,852,412,133,730,151,74,237,315,33,86,45,115,66,197,287,241,58,236,153,583,51,256,28,5,114,1,297,283,792,180,4,165,38,90,63,135,102,337,690,250,21,3,171,820,396,546,36,853,889,357,10,183,137,46,200,445,56,475,125,99,461,603,309,117,0 }, +{ 16,7,14,92,24,35,60,18,46,140,126,71,87,50,171,54,9,2,38,5,0,220,108,69,23,230,21,13,246,128,163,70,12,107,394,58,20,68,64,121,155,150,330,309,28,48,22,67,32,10,51,141,267,137,55,314,236,202,146,1,37,281,115,181,502,461,269,189,307,852,232,774,132,97,571,328,75,43,223,65,278,199,52,217,86,820,77,366,335,172,72,112,186,6,409,622,318,99,61,95,103,149,262,49,780,552,177,133,36,227,29,294,462,430,17,334,135,352,572,45,675,563,270,66,33,451,39,180 }, +{ 257,90,205,184,460,769,245,32,179,524,5,45,229,497,288,152,619,21,57,432,452,2,17,292,59,381,266,14,476,1,4,48,106,241,316,358,216,255,29,77,38,217,11,54,155,58,313,64,263,157,425,76,471,12,129,6,227,72,243,148,186,141,3,79,247,37,128,7,339,464,214,188,290,209,207,99,720,519,369,317,177,40,50,115,365,33,710,51,89,270,269,102,221,588,86,46,162,61,202,529,237,291,111,454,94,10,62,372,408,875,23,277,350,618,210,645,349,123,308,19,52,25,180,36,449,352,119,181 }, +{ 15,4,5,11,13,23,141,21,32,40,202,180,1,0,33,269,3,128,17,318,352,134,51,120,2,64,153,117,450,31,326,12,137,196,22,197,102,82,260,44,6,752,165,59,10,49,7,48,177,217,494,57,341,115,403,523,95,901,237,386,457,37,210,14,317,98,351,365,90,56,9,961,203,817,498,719,125,93,28,730,18,110,19,372,116,291,244,678,86,475,615,8,194,76,342,27,45,453,349,36,61,139,96,873,864,216,402,391,111,72,373,16,275,143,285,30,25,247,39,144,300,253,24,922,214,38,70,164 }, +{ 130,711,47,412,108,453,730,196,283,390,78,381,27,183,236,503,472,51,14,200,803,128,153,719,59,250,133,432,34,318,57,73,123,4,114,117,65,17,53,177,33,576,714,216,657,56,378,322,475,46,23,3,529,754,134,369,275,339,19,11,269,12,389,899,291,813,402,650,368,40,603,401,21,444,361,436,266,210,99,457,297,202,480,77,102,54,666,592,513,349,403,129,194,106,894,38,471,0,523,32,739,137,18,22,2,690,136,386,594,152,161,684,678,181,162,548,26,670,141,37,10,184,814,743,421,789,45,629 }, +{ 12,277,51,474,153,111,99,23,37,13,629,961,431,94,569,38,453,542,139,115,79,134,117,401,196,33,40,188,157,89,11,775,457,72,485,15,405,54,4,339,413,300,377,197,477,148,313,328,165,59,734,308,102,719,76,14,45,210,179,21,128,730,152,3,64,17,509,498,386,10,266,880,2,77,32,391,57,482,41,475,0,471,403,304,141,177,898,523,82,18,365,490,205,758,275,5,217,29,402,546,372,488,260,351,341,120,24,202,452,358,237,22,352,873,468,361,6,269,317,216,155,437,162,48,1,229,31,811 }, +{ 495,469,17,378,106,26,27,483,161,862,383,742,19,73,80,527,53,436,814,136,297,84,62,119,611,56,250,25,440,209,113,42,6,122,34,4,255,128,240,14,3,684,200,59,585,129,65,45,29,123,504,57,573,2,5,11,445,361,141,630,61,64,205,179,86,833,76,32,667,690,33,235,202,245,162,618,40,283,680,548,318,472,402,269,503,77,555,102,194,184,108,183,207,95,151,21,152,112,177,514,46,153,887,491,311,803,54,58,257,12,38,10,507,90,648,196,51,176,22,614,306,48,0,229,130,145,1,114 }, +{ 681,636,81,750,91,370,138,718,0,104,348,784,174,397,673,693,18,29,355,192,173,280,74,426,306,65,207,6,701,715,86,319,64,124,671,85,52,32,289,95,510,22,90,511,887,204,343,712,560,879,526,422,240,233,214,7,49,312,40,120,72,77,519,43,24,707,484,4,577,353,42,523,84,63,11,177,27,145,835,730,57,474,643,151,448,756,28,25,10,61,19,21,20,260,415,102,194,888,580,87,861,610,825,33,288,232,193,115,66,59,817,76,45,172,847,17,2,719,457,273,114,26,23,450,168,13,414,302 }, +{ 15,33,77,102,115,117,4,134,153,40,196,11,13,217,1,5,23,317,21,3,365,2,291,341,32,12,59,51,177,139,342,6,0,349,210,7,372,37,180,48,351,111,17,90,569,141,275,36,57,197,457,202,137,72,89,304,14,308,9,120,854,901,898,300,277,10,55,96,64,148,247,961,160,27,165,450,128,437,269,719,352,260,752,38,401,318,523,216,730,734,93,629,76,221,94,482,56,579,18,16,143,253,873,922,453,61,638,179,49,19,22,31,244,498,125,8,697,45,24,817,44,245,403,485,79,326,84,899 }, +{ 9,0,28,68,35,65,101,39,67,175,1,124,154,69,24,22,55,18,16,238,103,30,336,114,12,49,251,109,149,96,50,13,21,51,7,23,252,5,345,100,596,218,158,141,831,418,189,480,532,37,10,166,115,346,2,433,64,323,217,128,137,48,443,88,86,160,36,439,75,237,547,269,202,71,289,866,646,429,118,335,389,364,285,230,317,930,197,352,180,159,143,181,486,503,402,283,99,133,281,95,223,194,498,208,165,168,318,32,60,14,83,4,657,105,212,131,265,694,745,956,54,185,163,484,6,403,77,722 }, +{ 23,33,102,40,51,77,13,403,117,196,153,64,11,128,453,134,137,300,59,291,141,4,10,202,22,475,180,95,57,719,139,99,0,342,86,65,494,90,12,28,9,49,485,421,21,115,114,1,194,901,752,210,177,165,120,108,15,37,18,349,328,2,323,269,899,450,391,351,260,197,125,36,961,523,457,361,48,14,341,958,954,947,922,854,817,758,730,546,509,498,412,365,289,275,236,160,93,54,32,16,7,847,805,576,401,217,962,570,467,285,218,124,105,874,835,775,701,670,629,577,569,541,386,373,372,347,277,247 }, +{ 214,90,289,874,6,65,256,235,64,751,25,42,312,249,194,746,288,875,525,519,247,835,174,85,233,348,544,217,437,32,524,352,343,95,123,138,26,63,355,954,86,122,91,280,630,416,0,177,605,22,204,317,752,648,222,736,141,77,45,579,864,180,74,216,415,304,389,59,597,57,66,306,81,237,287,56,881,588,243,115,84,208,19,445,370,108,498,114,183,87,29,671,4,316,49,283,76,145,275,18,444,205,573,396,240,52,28,112,337,104,10,636,202,624,70,368,11,511,353,33,21,135,102,650,680,137,291,619 }, +{ 1,22,2,28,67,36,50,5,12,49,0,95,14,168,55,7,83,46,103,105,114,69,194,9,38,21,159,584,35,65,239,133,169,109,24,218,23,16,158,208,10,323,48,170,54,51,96,37,160,597,164,13,29,6,18,320,244,708,32,115,892,202,128,503,505,424,185,874,776,253,312,64,347,143,68,75,238,654,137,141,756,31,124,480,301,531,39,181,269,289,824,3,251,835,646,389,361,318,789,52,98,189,797,532,30,638,285,180,165,308,420,99,286,751,127,237,17,283,45,4,175,44,577,125,533,154,72,197 }, +{ 269,318,352,202,141,13,77,51,180,102,349,23,372,291,137,403,33,128,125,197,21,44,31,494,342,317,217,32,402,117,1,365,16,901,475,177,49,22,11,5,116,98,93,386,165,160,153,115,59,40,18,752,253,244,15,14,12,10,7,2,0,4,947,704,692,678,661,615,597,576,473,373,326,208,203,48,39,30,6,90,28,24,498,453,421,127,96,17,961,899,817,474,408,401,350,308,304,285,263,241,196,194,185,169,168,148,134,113,111,101,95,94,89,86,71,64,55,36,35,769,638,569,275,257,152,9,8,968 }, +{ 435,144,274,88,203,418,410,778,190,30,530,960,521,795,686,466,1,321,326,96,367,100,166,822,382,264,692,855,539,131,438,576,335,213,9,265,201,98,613,921,93,615,859,44,31,840,765,403,800,83,772,662,225,744,523,494,284,473,116,957,924,0,909,36,478,217,817,141,28,966,69,934,831,551,137,21,120,731,269,829,219,128,948,669,406,51,639,625,23,5,230,206,39,13,268,77,944,372,110,617,238,260,404,125,716,557,67,856,691,224,32,7,442,349,332,16,805,492,254,242,228,10,704,291,223,35,842,64 }, +{ 76,72,90,179,205,21,245,316,428,288,32,464,184,37,38,257,460,413,148,54,645,405,57,749,45,308,12,358,152,221,431,14,449,4,155,350,229,48,401,50,270,2,59,1,99,5,497,769,17,11,528,524,452,474,266,241,115,51,243,247,10,128,773,477,79,741,432,281,430,217,129,188,77,181,619,292,64,659,157,339,46,313,227,106,23,453,476,720,36,202,468,7,328,743,381,488,216,94,341,141,3,0,498,794,471,197,137,421,180,536,317,403,237,629,490,29,62,482,86,13,6,165,540,369,33,402,352,162 }, +{ 77,102,33,141,64,115,23,40,177,13,51,291,2,269,202,217,6,128,10,210,180,318,1,196,7,14,352,137,197,0,165,3,22,4,153,237,95,117,19,17,59,5,275,15,134,139,86,11,342,125,9,16,317,18,25,349,341,12,36,26,494,216,49,403,31,498,752,27,93,143,111,65,300,24,110,312,28,120,457,391,372,386,44,98,21,247,20,901,164,304,29,82,203,453,402,401,365,99,569,57,719,56,509,475,961,194,260,34,730,678,546,45,116,32,50,48,244,35,38,864,37,308,629,46,450,326,8,54 }, +{ 397,32,788,81,65,693,249,681,90,422,4,804,194,123,21,59,56,348,11,64,23,61,95,91,690,3,725,718,84,319,0,280,152,237,138,43,355,817,174,6,510,57,494,17,523,899,141,114,49,214,52,165,414,370,784,77,526,60,86,51,386,217,74,40,12,904,85,365,102,450,326,208,18,120,945,750,636,343,242,233,115,650,615,5,20,511,342,29,33,887,457,888,524,880,350,263,180,137,133,108,36,24,15,13,222,204,183,177,160,582,532,391,278,135,730,719,289,715,671,597,10,566,421,403,221,218,207,202 }, +{ 126,60,16,314,150,121,199,146,107,92,246,7,132,35,71,359,232,18,24,14,298,392,649,672,423,517,140,441,97,279,508,388,95,653,32,462,877,195,108,21,230,598,607,407,167,46,172,451,5,118,68,22,387,357,38,267,640,55,522,191,28,156,467,360,271,380,594,0,10,953,733,49,48,2,356,64,66,955,633,809,603,273,278,75,149,65,50,1,52,660,783,135,43,12,362,354,674,236,711,212,702,86,309,13,9,115,493,37,330,20,125,36,220,312,241,54,501,324,101,87,29,345,23,90,550,928,446,77 }, +{ 217,15,141,115,317,365,341,13,23,260,51,137,120,202,77,372,180,33,349,4,269,352,64,102,40,1,110,373,450,291,197,21,32,36,160,117,244,752,318,128,5,854,351,0,11,922,59,247,134,661,9,304,10,901,165,12,153,22,457,177,143,96,253,28,86,82,48,523,2,196,730,494,57,90,811,49,403,7,326,237,16,83,3,8,18,437,125,39,817,30,72,111,139,55,37,17,961,898,498,899,308,719,24,475,386,76,164,35,717,288,873,704,6,89,221,569,14,642,391,241,203,67,56,509,210,285,95,342 }, +{ 111,134,117,474,23,13,961,569,12,431,51,37,115,99,277,15,405,38,197,89,72,629,148,457,76,54,4,45,165,11,139,94,719,498,106,59,873,14,79,128,40,10,196,33,482,3,17,179,188,2,64,413,730,775,245,177,153,205,471,57,509,477,401,358,453,0,403,6,485,22,5,152,304,1,180,402,275,475,300,341,901,36,880,339,237,210,82,141,386,32,110,7,758,120,452,77,365,317,260,129,391,31,95,202,308,46,864,542,523,8,757,86,18,44,752,217,162,93,65,734,437,497,421,678,269,229,546,285 }, +{ 23,13,51,5,202,21,32,1,12,2,141,15,165,115,269,7,4,453,197,403,318,6,48,120,9,0,3,386,128,64,180,14,125,37,475,308,401,137,457,16,10,99,18,450,260,196,523,33,352,237,494,730,719,17,77,11,421,341,326,31,22,40,221,102,8,391,90,24,82,217,30,93,59,117,177,153,351,365,28,19,44,110,899,98,317,569,39,72,61,629,961,817,49,134,509,57,498,247,76,20,29,402,45,27,203,38,36,96,752,89,241,50,56,373,144,25,304,758,86,291,46,54,65,35,349,116,901,576 }, +{ 13,141,23,5,115,202,4,51,269,352,217,11,2,318,180,137,317,21,7,341,77,3,6,32,197,752,33,1,291,12,64,372,10,365,128,9,102,22,0,165,403,40,15,349,494,498,482,48,308,177,901,31,28,16,37,873,44,237,14,49,125,153,247,18,244,98,30,59,453,120,143,55,401,475,304,36,39,457,342,93,17,72,95,221,24,196,35,117,134,253,86,90,509,579,76,116,203,864,326,961,576,569,210,717,523,859,144,421,678,160,8,719,110,127,216,89,391,260,468,730,65,386,629,450,437,805,164,105 }, +{ 165,125,391,197,21,13,558,380,23,48,386,237,900,221,66,509,180,14,326,120,457,33,32,357,115,961,97,426,401,298,135,278,308,719,51,98,758,841,172,75,38,56,12,6,571,204,770,74,19,72,554,867,629,408,393,77,670,64,63,25,10,1,42,498,462,134,40,7,563,247,102,715,773,90,31,763,324,808,494,451,523,450,317,293,244,210,177,43,29,20,171,22,572,501,681,582,350,743,615,365,335,262,217,203,105,87,69,490,482,641,370,26,11,81,73,65,53,4,579,192,963,367,342,267,260,241,239,216 }, +{ 120,82,260,450,351,15,141,21,854,77,217,13,23,51,1,202,817,180,33,898,110,48,326,93,102,32,128,137,5,165,523,269,352,318,125,291,922,2,177,203,275,403,317,4,210,12,373,494,115,64,197,96,386,7,144,0,342,196,36,457,752,37,349,453,9,6,16,221,50,237,615,59,10,475,341,14,372,730,244,18,22,223,285,160,67,365,86,498,661,421,402,401,31,901,308,719,391,70,3,99,35,44,24,95,90,28,473,899,69,30,65,864,704,116,11,29,8,83,367,17,163,49,551,304,961,216,61,692 }, +{ 23,51,13,15,961,0,2,10,115,1,457,5,569,453,4,7,9,719,14,33,629,11,165,40,197,6,77,21,64,3,474,139,38,401,59,22,72,57,102,12,111,475,32,79,341,730,386,128,54,37,509,177,17,8,196,391,36,237,141,202,277,18,89,148,76,99,734,28,758,308,41,117,498,180,90,403,873,365,482,31,45,328,94,546,48,153,86,210,93,317,24,468,494,247,304,300,269,82,16,95,402,120,670,134,46,488,757,194,110,55,62,125,155,29,188,52,405,49,899,775,50,275,221,880,477,44,152,523 }, +{ 264,166,435,9,39,254,30,382,921,404,438,363,656,190,100,897,411,478,93,203,812,274,625,1,795,691,88,156,101,473,326,110,265,639,340,51,447,272,141,18,35,165,131,33,329,67,0,354,77,910,616,291,914,530,105,68,118,197,731,137,120,23,21,578,128,36,333,49,593,494,271,98,676,310,102,44,664,613,48,349,28,228,195,5,960,658,800,180,24,724,96,682,678,403,160,688,523,127,829,242,521,83,31,716,13,342,159,69,16,144,260,352,32,269,55,167,158,219,576,364,704,4,615,202,65,60,318,456 }, +{ 252,9,0,166,265,100,364,329,404,39,101,520,676,419,68,118,553,604,382,88,167,274,18,212,593,333,158,264,16,49,806,865,438,48,812,21,154,30,677,310,1,35,656,24,96,124,51,857,22,13,23,105,28,60,31,71,286,562,65,777,435,455,190,98,639,159,759,109,917,254,344,191,647,125,10,55,907,694,363,221,44,127,5,557,131,327,682,411,67,628,95,83,538,936,149,925,272,36,664,175,375,478,121,64,793,146,821,50,671,69,302,271,921,116,625,541,942,446,530,724,709,706,33,634,463,170,128,223 }, +{ 15,4,11,141,5,13,21,23,202,40,269,32,12,165,523,3,180,64,318,17,352,457,197,1,93,0,110,2,125,120,128,386,51,59,77,31,117,326,49,10,719,403,961,82,153,48,137,134,899,450,115,260,494,196,44,33,37,730,6,57,203,817,177,752,22,98,9,90,18,373,237,8,7,217,958,351,291,14,139,95,341,144,27,210,475,615,402,391,56,453,901,116,19,143,86,349,244,317,72,105,498,123,485,365,111,152,342,401,76,28,30,247,678,801,65,45,216,36,569,300,308,509,221,99,127,84,164,873 }, +{ 24,35,69,18,71,68,46,67,16,1,2,50,14,149,108,133,189,28,38,75,83,0,7,9,218,65,238,114,52,335,29,54,251,60,55,309,236,175,118,336,486,267,96,394,181,220,366,87,418,124,154,5,545,412,516,140,70,22,487,12,21,36,101,171,433,641,230,328,58,48,458,345,361,398,283,92,6,37,103,514,302,906,10,388,596,565,273,443,64,160,532,163,399,705,223,891,86,150,262,537,32,51,39,831,23,109,95,375,155,13,99,480,571,45,49,128,281,696,112,194,754,25,137,294,602,208,323,191 }, +{ 90,214,289,874,64,712,751,77,51,13,177,32,312,23,192,66,194,202,216,59,288,4,835,875,65,0,249,247,95,519,102,57,5,123,33,22,524,234,104,450,173,49,437,500,889,210,217,636,319,597,21,153,416,196,38,20,117,954,304,115,134,120,18,715,86,583,113,494,61,204,10,784,291,28,275,342,147,318,879,43,74,142,11,588,888,403,864,237,2,198,352,426,752,707,48,1,639,17,81,180,750,861,52,315,207,560,24,128,402,40,141,16,671,31,372,36,130,455,260,12,9,317,37,325,349,389,904,306 }, +{ 9,0,49,127,28,301,98,371,395,159,512,158,916,737,761,31,101,24,623,16,272,68,18,39,35,293,242,1,286,109,44,385,327,65,170,299,55,125,51,23,22,518,105,836,21,116,616,137,685,284,48,599,344,252,7,124,13,276,64,187,95,506,5,131,890,202,456,627,36,2,219,30,254,333,419,763,14,347,12,154,578,320,96,713,141,935,201,144,338,442,870,118,71,128,10,364,168,374,67,60,37,310,221,100,32,318,424,93,269,393,910,165,403,86,688,160,793,908,50,83,69,203,421,492,401,6,244,166 }, +{ 17,136,62,214,123,129,249,710,119,162,618,292,209,141,32,183,77,128,211,106,64,45,4,11,179,269,507,519,207,59,177,130,3,40,90,86,255,378,33,202,76,57,205,655,790,152,678,38,21,245,37,742,248,5,102,597,476,306,556,41,291,229,117,349,80,339,153,313,266,318,84,54,947,184,56,12,155,134,240,197,305,157,304,217,148,186,165,275,257,789,99,216,13,497,317,72,137,115,10,196,460,383,619,61,51,188,361,457,369,425,50,290,440,14,342,263,180,503,452,241,208,237,194,432,381,65,111,22 }, +{ 5,107,581,441,356,493,362,660,279,534,32,683,298,423,259,786,22,612,590,359,21,13,49,147,61,508,241,263,929,48,97,246,14,126,0,132,7,465,939,232,64,230,607,95,121,941,23,92,771,115,470,314,51,387,626,172,1,58,12,347,779,392,407,17,150,687,16,357,28,146,43,77,87,60,199,197,37,40,711,178,501,65,10,9,180,140,35,33,24,595,102,120,56,30,70,207,344,324,125,46,31,165,18,20,577,414,376,2,350,4,260,427,173,408,195,141,247,76,603,217,86,11,379,55,729,90,75,50 }, +{ 51,475,453,13,23,15,730,403,457,421,386,523,899,719,670,401,12,361,6,99,33,1,128,269,961,141,27,19,5,494,165,21,64,2,450,153,202,117,65,115,236,7,196,77,95,32,328,37,14,10,0,318,134,17,391,197,102,308,40,26,120,9,22,4,125,412,389,16,34,194,57,569,402,54,53,8,352,25,758,291,59,3,880,757,503,488,217,90,38,72,48,45,801,177,11,304,509,326,283,260,180,139,137,76,47,41,867,350,629,558,949,838,832,803,775,773,770,754,749,657,597,576,543,514,468,297,255,250 }, +{ 49,159,272,28,9,327,254,158,22,347,95,627,374,286,131,424,105,168,35,39,912,65,68,578,688,0,538,55,24,518,175,154,124,239,634,346,289,224,169,913,577,16,320,364,747,219,185,616,101,716,67,344,1,890,570,170,30,810,109,333,228,420,21,36,439,64,149,23,127,371,194,13,706,827,125,51,114,312,83,187,98,429,613,10,137,829,610,86,310,166,910,31,835,190,406,71,18,242,202,846,141,938,160,44,14,2,385,69,7,48,308,301,258,128,638,237,115,12,165,96,100,103,562,703,221,116,164,50 }, +{ 15,33,77,4,102,317,341,141,117,365,134,13,180,1,40,153,5,115,23,11,197,10,217,196,21,901,22,64,752,352,143,253,244,351,137,51,32,2,269,177,82,59,165,12,3,291,569,202,120,0,854,139,342,86,55,36,372,31,9,898,48,498,349,37,260,7,28,111,125,17,482,49,318,160,457,6,450,44,128,90,275,237,95,210,57,386,873,638,98,523,105,164,89,93,30,719,922,961,509,308,8,14,72,951,403,401,730,391,304,116,326,39,468,56,38,717,94,24,579,817,76,61,96,16,18,546,629,494 }, +{ 134,13,15,23,12,474,569,51,37,10,197,457,961,99,115,4,38,2,165,0,153,5,3,11,719,64,139,431,1,277,120,82,33,6,94,873,14,401,110,7,89,117,351,40,498,128,260,148,54,93,72,629,453,180,21,31,22,9,405,143,141,8,17,77,36,102,44,386,41,509,196,59,450,125,730,55,342,523,86,403,326,45,95,898,98,32,854,237,365,217,391,775,116,349,291,210,179,203,202,317,752,901,372,341,352,177,402,49,57,76,922,475,28,30,144,373,421,318,308,269,90,494,413,46,18,678,899,242 }, +{ 7,2,66,20,58,29,52,74,128,14,135,5,32,97,192,43,38,61,6,631,16,151,87,21,25,315,172,177,46,48,173,186,45,884,70,90,113,77,227,72,226,23,102,51,137,35,210,337,202,59,40,104,402,155,115,269,89,592,81,33,122,13,60,174,112,107,24,19,243,0,145,222,580,76,37,49,64,10,416,318,738,18,353,204,26,491,678,95,4,290,141,54,232,69,92,22,415,140,712,270,217,12,171,496,86,220,27,17,549,294,209,1,355,609,494,425,285,50,665,148,403,560,36,216,400,75,275,307 }, +{ 77,202,13,23,128,318,33,269,141,102,403,117,4,342,153,134,51,40,64,196,32,0,49,177,22,494,291,137,11,21,59,65,95,475,98,165,210,90,18,115,48,217,197,15,275,105,10,120,127,86,28,180,9,453,352,36,39,317,31,125,5,194,402,57,450,349,372,14,116,44,16,300,6,2,284,96,24,20,30,457,12,859,678,299,289,242,114,110,109,61,7,1,216,214,100,326,304,260,237,3,82,789,752,579,576,490,347,344,293,207,205,144,139,93,37,615,373,351,285,421,401,961,391,203,817,923,922,901 }, +{ 2,14,1,46,29,38,6,52,103,50,65,36,67,5,108,75,83,7,22,24,25,69,28,86,208,133,0,323,19,26,484,18,309,782,96,283,236,238,124,160,135,21,10,12,74,87,66,168,17,262,70,412,23,389,16,51,650,278,289,532,45,194,3,756,218,32,220,58,646,244,42,115,95,37,27,13,48,886,49,267,366,226,302,128,54,610,64,516,547,584,137,253,9,308,143,388,141,717,335,480,401,164,185,357,505,109,150,732,602,420,99,285,172,202,891,112,189,324,181,35,418,696,331,90,114,55,294,458 }, +{ 15,5,1,2,3,4,12,11,13,10,0,341,21,180,7,33,197,6,134,17,77,32,365,23,901,37,117,9,8,40,165,102,153,961,51,498,196,569,14,873,752,217,22,94,64,317,59,36,352,474,31,509,99,141,110,55,291,111,457,120,391,57,19,16,82,48,177,401,38,386,349,202,308,139,93,342,453,72,275,18,44,143,351,28,27,90,128,403,269,372,45,137,76,260,318,89,326,210,86,277,898,413,237,719,148,864,730,96,95,79,373,475,61,24,46,30,523,253,98,482,83,546,54,49,50,41,899,758 }, +{ 203,268,206,940,93,417,959,499,473,137,31,44,728,692,8,120,202,559,564,450,127,141,260,326,817,244,22,10,0,23,551,318,144,125,13,523,269,128,299,98,1,253,373,51,494,403,9,116,341,143,64,110,638,285,5,615,642,859,367,55,918,576,21,421,180,386,922,165,105,36,401,2,365,115,899,242,352,28,951,393,704,86,30,901,475,7,762,276,77,384,948,237,32,197,49,492,434,160,661,489,170,15,39,752,317,498,854,453,282,717,6,18,16,569,395,479,351,805,12,958,898,456,48,293,851,308,301,509 }, +{ 15,120,82,10,165,31,0,197,64,260,33,8,93,110,22,351,40,44,77,23,153,13,9,102,4,51,196,125,326,11,450,49,139,28,237,203,386,98,457,18,32,373,95,523,1,21,277,59,854,180,111,202,12,141,898,17,36,116,144,14,115,922,86,57,128,5,45,30,2,391,217,7,817,37,177,730,90,509,719,72,99,16,76,62,453,291,352,475,318,269,403,341,48,134,961,55,24,3,143,899,308,401,137,65,38,615,210,629,317,901,758,342,569,494,661,365,39,247,164,421,704,546,61,6,811,41,642,752 }, +{ 60,7,16,71,43,0,14,20,28,97,68,22,92,24,149,2,35,10,154,13,126,615,608,51,124,362,140,55,805,18,958,576,566,175,23,359,6,1,48,453,158,150,703,21,421,260,173,475,298,153,107,74,64,36,29,925,46,12,882,899,441,801,81,357,246,196,77,69,38,25,9,117,65,49,314,37,484,386,730,336,115,570,403,356,324,221,135,121,19,401,99,939,420,399,859,942,628,610,289,285,259,125,101,95,33,26,702,677,165,4,653,375,185,192,91,515,302,197,104,326,595,318,230,202,191,143,102,90 }, +{ 26,19,6,27,80,25,84,45,17,5,504,42,129,2,240,123,618,29,56,106,113,710,4,76,119,128,14,136,65,64,73,59,1,209,483,53,162,51,90,548,122,205,249,202,40,99,3,460,32,257,62,292,61,214,77,245,57,12,378,141,183,453,34,297,11,184,108,23,255,469,0,403,22,33,58,95,10,86,814,318,769,114,179,402,611,667,130,475,21,151,210,137,742,161,38,177,494,7,436,269,102,194,115,445,18,36,421,13,47,153,880,775,54,133,196,37,49,495,306,311,112,46,52,117,250,28,491,48 }, +{ 15,77,13,33,4,23,102,11,51,5,40,177,0,117,10,202,64,8,93,22,291,32,21,44,31,153,110,1,141,49,115,59,82,180,9,17,318,196,98,269,351,403,137,453,36,95,457,217,3,90,139,128,48,28,898,12,165,450,475,349,341,197,523,18,30,210,317,86,16,260,401,2,961,901,719,57,116,494,854,326,373,125,365,817,352,730,275,134,39,386,105,76,24,7,308,372,37,342,6,421,120,704,144,14,899,922,203,111,304,569,638,72,661,61,629,96,127,99,811,535,498,65,615,752,247,83,402,758 }, +{ 195,271,98,223,167,132,407,146,360,591,1,212,834,121,522,393,293,199,259,354,446,668,590,562,807,191,156,48,765,125,107,147,941,163,727,541,535,465,126,284,21,346,31,279,23,55,18,5,687,16,60,640,13,697,586,178,534,35,20,608,581,150,955,427,68,70,589,43,142,791,463,198,116,51,883,362,9,963,781,202,49,0,818,96,493,7,948,281,120,165,367,798,450,10,44,318,77,105,14,325,221,92,28,22,61,770,101,777,58,93,32,97,467,141,386,33,144,371,75,127,37,108,929,269,411,598,551,128 }, +{ 210,128,202,77,402,318,102,403,33,342,275,40,196,475,6,300,139,29,177,99,494,269,42,503,111,757,277,141,117,52,2,4,678,13,153,12,0,23,59,285,37,137,85,81,7,291,859,657,351,122,82,576,44,31,880,260,216,120,91,78,63,14,11,1,745,65,64,93,854,27,684,22,485,180,76,74,19,3,21,805,49,38,281,48,966,838,631,452,450,421,218,134,26,25,569,341,115,898,738,592,110,98,10,315,788,707,491,483,432,396,319,268,242,125,116,95,62,57,56,50,17,16,9,655,526,453,426,422 }, +{ 40,33,102,23,51,13,117,196,153,77,134,64,128,202,4,59,141,453,65,475,11,403,22,95,0,137,14,139,15,342,210,12,86,318,269,165,115,1,49,10,494,177,28,180,36,291,421,21,57,5,6,217,18,194,99,401,2,457,108,719,125,19,111,260,82,37,27,48,17,3,523,197,133,26,402,120,114,670,352,7,24,730,93,216,90,46,237,50,32,386,361,9,341,351,25,349,300,283,277,38,34,901,365,326,275,98,110,285,45,41,391,44,317,576,961,242,143,16,509,170,31,854,308,54,116,817,757,629 }, +{ 7,14,16,24,18,28,71,2,92,60,35,22,20,0,154,118,168,6,1,97,69,703,302,149,140,150,185,38,109,43,66,68,108,420,29,55,10,158,610,12,65,67,5,701,189,273,570,95,230,429,46,124,246,289,298,51,21,169,143,49,175,23,107,747,126,671,13,64,48,159,25,925,677,137,36,52,398,32,9,251,584,467,164,128,942,19,86,577,847,83,173,336,403,74,50,424,202,232,882,172,17,344,279,638,375,105,314,104,37,125,115,441,356,505,99,253,239,26,221,359,329,194,533,837,517,165,494,601 }, +{ 23,1,15,51,2,13,5,0,7,180,21,9,6,115,197,120,12,165,4,33,457,386,523,202,141,3,14,260,450,48,8,16,77,93,31,341,37,269,40,403,44,730,110,326,32,102,317,137,318,453,352,719,365,18,128,217,153,82,475,36,98,64,391,752,401,901,899,421,308,196,11,498,22,28,351,99,116,10,117,24,817,96,221,30,39,494,509,569,177,203,49,961,144,291,373,615,59,17,801,372,482,72,758,90,89,854,50,629,134,127,35,86,349,922,160,55,244,105,237,143,468,898,210,54,46,670,342,45 }, +{ 132,146,199,107,60,121,126,279,150,441,92,649,16,955,493,195,598,423,653,298,35,407,356,640,362,508,32,21,953,7,360,359,522,18,271,783,5,246,167,0,660,156,534,939,71,191,22,517,590,24,49,259,314,10,607,28,392,13,232,147,68,97,95,14,43,883,118,1,37,581,48,501,354,809,55,108,4,591,12,20,23,347,345,212,467,230,446,241,125,50,941,75,9,31,98,683,929,77,2,672,33,713,463,702,273,61,40,59,70,46,101,58,172,586,357,296,115,779,36,350,109,727,388,236,207,87,105,408 }, +{ 31,44,276,284,98,299,935,116,201,662,9,39,492,144,489,131,567,371,268,0,49,918,127,137,367,254,28,434,293,737,30,203,1,295,22,456,93,125,219,385,23,202,187,393,21,716,105,599,578,51,36,128,141,836,272,269,244,318,384,13,159,395,48,261,96,110,224,616,326,242,35,16,253,5,95,55,64,160,258,158,143,18,100,699,165,24,115,948,120,37,403,86,166,310,12,924,457,855,940,77,10,442,494,101,109,7,197,317,206,68,2,373,617,761,352,285,908,217,332,341,916,228,32,33,518,688,730,473 }, +{ 13,15,23,51,1,0,10,2,4,115,77,5,9,202,3,197,457,7,22,11,165,6,961,12,33,14,59,177,403,21,102,40,453,180,719,217,18,31,120,141,32,475,8,318,569,37,16,341,210,17,386,450,401,28,269,64,99,326,494,317,730,308,44,523,93,352,291,90,125,365,260,36,275,24,134,49,139,30,110,498,421,98,57,196,391,19,117,72,342,153,48,817,873,349,482,901,221,629,76,237,111,899,86,95,216,509,752,304,137,247,82,372,116,758,89,27,38,39,65,203,55,402,45,29,373,300,143,615 }, +{ 162,123,257,184,183,17,229,130,84,136,497,556,152,383,129,452,99,80,3,205,62,57,56,266,106,119,12,128,40,4,161,378,27,14,495,504,381,202,769,469,249,59,77,432,11,34,33,305,64,90,403,240,38,54,5,102,45,32,23,73,618,475,51,361,440,139,775,37,402,471,318,53,21,494,65,141,19,372,453,313,421,177,880,472,757,217,245,548,250,527,2,76,524,349,61,86,216,153,210,196,115,179,10,619,328,269,291,214,72,483,117,209,6,26,22,477,111,95,13,401,114,157,369,211,36,134,48,306 }, +{ 196,153,117,453,134,33,40,23,102,51,13,475,0,14,22,15,12,2,64,670,21,401,730,4,18,99,65,10,9,11,1,28,95,57,128,77,5,38,46,37,403,386,202,719,24,6,108,457,899,139,31,59,16,82,36,165,32,120,961,86,236,48,8,342,141,775,125,308,137,7,54,523,50,269,197,494,318,115,300,260,39,758,450,180,421,277,90,217,341,629,361,49,3,326,114,93,391,291,210,194,328,317,111,17,352,558,110,377,29,275,283,133,485,817,898,615,801,351,160,19,488,569,350,373,109,84,56,183 }, +{ 224,219,187,258,442,871,908,385,836,131,944,574,839,127,98,613,31,116,926,44,137,829,860,160,827,276,39,254,284,36,144,228,201,96,406,1,371,530,202,856,716,93,30,51,9,203,268,737,902,492,23,49,21,190,13,318,843,531,326,269,924,125,367,141,64,77,120,166,816,935,800,242,299,115,456,260,293,274,931,494,395,567,110,217,662,5,317,22,717,100,143,434,128,28,48,86,533,10,295,105,332,55,489,180,365,918,418,102,578,197,244,83,341,576,403,384,625,165,261,177,159,352,291,822,863,473,251,206 }, +{ 195,121,360,590,146,407,156,786,522,132,883,591,626,929,941,259,687,279,379,586,296,465,467,150,178,354,5,21,55,534,70,60,783,771,13,346,340,48,271,581,49,493,163,1,199,147,608,668,125,955,167,562,535,98,518,108,362,18,371,212,446,107,761,878,31,126,50,463,35,818,105,75,120,598,87,0,767,223,165,640,22,447,293,777,159,16,23,9,142,115,658,92,481,44,95,37,807,93,61,58,24,191,33,7,846,395,12,197,4,385,127,423,71,140,82,427,144,116,17,117,2,363,698,246,39,64,32,781 }, +{ 2,1,29,14,6,46,52,26,75,38,5,25,19,50,96,70,108,114,309,36,103,74,17,65,27,112,45,262,236,220,145,218,58,42,86,516,24,366,22,7,67,21,12,66,532,87,412,18,480,283,602,323,137,3,163,226,238,0,194,51,32,28,10,69,171,37,23,115,208,128,331,394,135,48,99,64,13,433,285,160,61,782,113,357,308,222,95,484,401,16,141,294,151,287,223,83,646,124,389,361,894,866,545,421,54,324,4,278,388,396,186,650,594,53,168,453,289,202,59,253,181,90,273,138,150,403,756,606 }, +{ 15,82,120,10,197,260,0,165,351,8,64,31,110,93,9,22,117,13,457,450,1,44,33,23,326,102,49,125,898,153,719,77,854,523,18,14,98,12,40,7,961,2,115,373,180,5,51,386,36,111,141,95,730,28,196,922,139,203,55,116,4,817,498,899,128,30,177,86,569,144,661,99,37,202,16,24,65,318,21,873,11,59,6,277,217,391,269,341,38,32,291,143,237,352,210,317,3,365,509,474,349,758,704,642,216,39,615,137,453,275,403,401,94,300,304,629,247,372,242,342,90,48,752,901,801,308,221,811 }, +{ 7,66,97,172,232,192,226,2,74,324,52,29,135,92,568,222,43,107,353,87,387,580,500,38,620,448,331,526,140,330,5,138,294,174,356,20,14,262,298,32,357,145,173,853,6,359,21,126,58,16,204,808,64,888,337,104,314,673,35,22,729,95,872,25,278,380,70,802,37,583,426,1,49,12,112,69,75,65,86,61,45,60,48,10,246,90,230,0,42,355,24,220,415,85,81,889,46,885,36,825,287,28,194,72,171,792,392,632,560,280,312,50,71,115,76,54,26,18,151,155,707,587,89,17,4,764,147,59 }, +{ 62,129,123,162,183,507,618,136,249,152,211,57,77,184,205,59,130,4,128,41,11,40,117,17,229,497,361,257,3,33,38,313,452,266,378,248,153,64,106,90,210,383,119,12,328,214,99,432,216,157,196,86,202,556,179,54,102,80,37,381,402,471,134,245,177,5,514,369,188,339,440,305,275,524,141,45,269,84,710,529,291,403,139,342,115,56,318,209,76,504,421,372,742,619,292,240,237,79,27,14,775,22,19,10,23,457,95,21,207,488,13,494,180,542,65,300,401,306,32,34,114,26,215,25,217,769,151,110 }, +{ 13,1,4,5,2,23,115,15,3,51,6,0,7,77,341,217,11,141,177,33,317,12,180,21,365,197,202,32,318,352,269,102,901,9,291,10,165,40,403,752,59,22,8,31,401,569,349,494,120,308,304,44,110,90,17,386,64,93,37,247,153,210,326,14,450,28,373,117,16,372,48,196,457,260,98,275,475,498,237,453,125,30,18,203,523,342,49,509,391,36,961,128,873,134,719,116,629,24,482,421,39,221,216,139,244,72,730,253,95,817,55,86,143,615,57,661,351,704,144,127,899,105,76,864,576,82,922,758 }, +{ 6,26,235,145,19,47,112,78,648,624,630,27,85,64,42,95,122,444,25,644,113,70,108,453,29,632,130,711,53,222,74,390,32,65,237,412,416,280,665,287,813,138,730,307,73,680,283,14,196,52,34,4,312,51,236,226,90,262,17,337,22,180,59,331,500,128,86,884,315,194,690,114,133,498,849,137,50,200,3,256,21,2,49,45,33,23,13,66,141,409,445,297,288,57,381,719,11,396,289,247,87,163,165,1,250,5,46,115,153,525,99,183,76,746,324,63,792,675,294,316,56,214,28,583,751,125,285,503 }, +{ 51,23,99,12,15,13,153,10,117,403,120,37,82,165,128,453,401,64,202,197,2,115,110,14,260,457,21,475,5,308,0,38,93,719,31,3,22,134,141,1,33,196,386,180,351,17,421,569,44,326,125,523,961,11,730,269,137,402,318,450,4,494,8,49,36,9,98,18,7,95,391,6,54,629,328,32,237,28,40,19,86,775,373,57,116,41,854,77,79,59,899,352,94,474,102,203,509,477,65,758,89,341,285,221,901,217,111,177,16,361,144,30,880,757,498,46,29,27,670,105,898,143,24,62,72,277,317,55 }, +{ 16,24,71,18,92,108,35,60,146,64,7,118,246,199,126,121,32,50,9,267,649,156,167,830,271,133,273,140,36,68,5,230,132,247,21,14,1,640,12,563,48,0,87,388,75,2,237,220,330,86,46,354,115,65,672,304,128,55,751,522,180,360,95,28,236,191,516,114,163,696,149,953,189,22,54,565,141,51,137,217,674,412,352,49,340,23,633,37,309,458,202,39,10,394,58,103,70,597,125,262,72,38,947,726,591,502,437,195,164,363,67,641,514,602,954,124,864,448,107,150,143,101,366,283,13,678,317,177 }, +{ 15,2,0,13,1,4,3,5,23,7,217,6,9,115,51,8,341,10,11,317,372,180,365,77,33,12,22,247,901,18,120,197,457,14,16,165,291,28,21,202,31,349,961,719,102,260,32,453,30,352,523,40,752,569,730,24,82,450,304,308,110,437,93,117,44,177,36,351,196,403,64,17,318,475,153,899,134,269,494,922,401,386,128,48,482,316,326,37,137,49,57,873,125,39,854,59,55,509,90,579,342,35,817,629,758,373,210,98,498,237,898,116,65,111,144,139,615,19,670,241,20,56,638,468,89,95,275,801 }, +{ 234,639,178,416,77,455,5,49,142,202,450,427,0,147,329,21,198,315,61,557,344,13,113,32,318,120,22,23,325,48,259,534,494,105,95,347,518,798,39,884,159,58,481,99,817,623,878,291,112,711,70,64,17,1,31,320,51,265,158,65,465,128,362,192,137,236,845,260,403,44,310,141,196,342,177,30,7,271,241,195,135,269,28,290,210,929,15,4,307,170,125,663,102,33,275,263,132,859,408,294,194,786,581,402,301,153,86,523,98,150,423,346,167,25,237,415,36,858,682,592,352,117,100,12,37,10,709,146 }, +{ 31,1,44,36,116,64,55,5,180,2,22,352,98,86,127,141,12,164,13,498,125,115,144,253,170,4,242,137,752,197,128,105,7,244,0,160,237,23,341,21,165,9,365,299,901,301,3,951,317,10,6,28,864,51,338,269,15,268,844,83,169,217,202,873,638,93,569,509,96,824,546,8,37,456,740,293,512,203,77,395,479,318,206,14,776,599,95,506,33,367,276,11,48,685,954,285,239,457,535,201,492,762,717,401,965,533,102,393,482,208,49,109,391,601,558,489,67,870,284,947,961,403,708,946,35,434,923,40 }, +{ 120,217,260,141,23,77,13,51,317,1,180,269,15,115,202,450,137,110,373,291,21,352,64,349,5,177,82,326,351,48,318,854,341,36,365,304,165,197,0,32,922,372,128,96,9,93,752,12,22,523,160,10,2,244,7,457,4,28,898,386,86,901,661,498,719,33,16,275,90,247,203,143,11,253,482,40,37,83,403,730,494,102,50,18,961,615,473,221,237,8,817,30,968,125,704,216,39,59,14,67,6,117,210,35,49,95,72,342,308,24,89,453,55,134,475,76,69,116,17,61,31,3,437,864,70,899,576,98 }, +{ 26,396,648,6,112,122,624,145,287,19,222,416,42,25,573,138,74,651,644,151,66,113,445,45,85,665,280,29,525,204,64,174,337,680,87,884,135,53,65,70,436,27,95,58,297,881,194,73,80,746,544,235,17,86,2,90,243,32,22,5,128,1,609,353,311,141,61,315,307,491,226,106,0,52,81,813,614,209,255,7,632,75,114,10,36,186,580,415,289,63,611,14,34,33,49,214,28,792,117,250,312,283,77,125,172,108,389,76,192,208,355,237,667,56,4,91,165,294,40,348,148,635,102,123,256,153,46,549 }, +{ 156,360,522,271,146,354,21,446,121,132,5,463,591,340,195,727,586,18,48,407,13,49,167,32,668,60,199,566,23,16,447,698,955,575,9,658,296,493,608,150,126,0,534,35,24,581,92,71,590,363,107,279,141,125,640,31,212,4,929,411,467,562,10,1,51,115,783,165,191,22,623,68,598,379,61,12,293,273,202,95,197,303,163,663,269,108,37,101,221,118,621,391,76,28,17,40,109,7,767,260,55,518,120,33,11,77,259,39,347,941,44,252,713,478,98,140,408,350,93,626,346,264,900,509,818,30,170,763 }, +{ 21,5,61,49,98,23,95,32,612,178,259,51,182,48,13,481,120,77,683,660,427,291,147,64,70,4,465,33,344,269,241,0,17,767,318,263,202,141,107,415,817,450,180,22,534,392,362,125,116,347,11,929,350,121,595,408,423,352,293,260,196,165,117,105,102,87,86,59,37,18,7,3,557,376,845,663,579,541,490,356,316,115,90,163,928,711,28,132,590,407,941,922,704,645,523,360,346,284,268,232,210,203,195,177,144,134,118,97,65,60,40,16,1,298,153,146,58,937,798,414,113,31,771,246,207,142,281,647 }, +{ 468,89,358,79,365,94,179,205,317,405,482,498,245,72,115,341,217,180,413,490,111,734,247,431,188,216,37,474,152,452,11,629,569,873,752,749,497,197,4,339,308,13,12,59,901,428,864,579,40,76,23,372,291,875,10,352,134,961,117,77,542,528,401,51,588,349,471,529,33,464,546,477,645,139,221,1,377,38,21,99,36,177,509,64,449,316,14,2,304,143,102,437,9,32,196,741,3,165,5,275,202,128,54,277,237,153,210,743,457,430,300,773,485,460,141,17,0,350,22,288,421,257,270,48,8,184,137,15 }, +{ 24,35,71,68,16,18,92,118,375,108,7,101,302,175,336,154,60,273,14,124,9,398,230,140,0,150,55,149,28,345,189,399,246,191,65,346,69,722,212,46,1,458,167,22,429,314,2,267,126,674,21,388,439,97,67,38,114,10,48,252,628,95,364,251,882,50,133,637,36,49,39,109,12,823,172,768,602,103,236,650,5,83,520,66,232,64,517,32,562,847,694,815,589,702,107,96,51,594,23,695,363,298,37,535,462,484,29,13,796,86,467,886,604,806,868,121,419,125,54,755,451,168,100,135,570,158,6,169 }, +{ 421,453,51,801,730,475,23,523,386,670,401,719,13,629,899,365,403,758,457,115,494,569,805,958,576,543,697,165,615,221,423,817,450,33,488,308,197,102,66,21,514,388,56,14,38,734,341,117,7,326,69,467,961,880,323,196,153,19,202,886,770,128,273,97,120,811,642,532,458,207,110,24,10,6,1,540,67,0,753,554,390,135,134,92,73,52,43,894,37,32,743,214,114,103,90,65,29,891,847,782,125,451,269,208,75,754,602,480,244,229,200,133,130,119,16,9,426,162,83,40,22,2,42,25,203,123,4,901 }, +{ 113,311,614,29,491,145,45,112,80,6,151,631,209,315,74,61,27,2,73,5,287,66,26,243,25,70,396,611,667,52,138,19,58,454,869,122,222,17,186,106,87,255,445,32,64,496,42,297,1,135,684,227,4,128,644,7,86,624,76,337,95,416,65,22,72,85,59,14,204,148,90,21,738,174,250,53,119,141,280,10,483,0,833,137,651,690,549,46,75,226,11,378,37,665,155,742,200,56,194,207,57,177,179,525,12,114,84,77,48,495,40,469,172,292,307,161,49,38,884,887,655,573,881,89,425,18,36,33 }, +{ 471,339,188,4,11,59,377,79,12,99,94,102,77,33,51,111,542,37,342,152,961,13,474,403,40,202,196,153,128,3,452,453,177,229,431,475,401,23,139,117,184,266,157,57,134,115,494,210,300,17,291,402,129,90,32,529,629,5,141,76,775,72,64,275,38,21,318,757,569,277,216,162,14,421,313,123,269,880,89,1,2,497,257,62,197,405,27,45,285,54,304,148,485,217,15,457,41,10,6,179,165,205,180,137,477,349,130,488,245,19,523,432,437,260,22,120,95,769,372,0,352,381,249,618,482,308,237,7 }, +{ 15,40,4,11,33,120,10,82,165,77,110,93,31,8,260,0,23,22,102,51,13,59,44,351,125,64,197,139,32,9,21,326,28,450,196,180,98,203,57,141,386,49,373,12,111,95,1,391,5,457,99,403,115,18,453,116,202,134,475,523,719,854,37,117,128,401,237,48,144,177,14,898,36,217,2,90,308,269,342,758,30,210,318,277,730,494,17,509,922,352,291,817,86,3,65,16,901,24,194,402,105,38,137,7,341,317,29,961,39,629,55,72,76,300,661,752,421,899,242,54,775,247,349,365,569,143,615,485 }, +{ 16,71,24,35,68,18,118,60,0,28,124,92,7,55,9,419,375,14,109,175,149,101,126,252,302,346,150,439,108,154,158,570,169,185,364,22,273,49,65,917,701,329,168,962,420,191,925,39,628,107,2,1,604,46,140,67,97,21,535,265,38,69,159,942,677,10,722,336,105,345,694,467,703,48,5,95,246,553,810,882,20,83,333,43,12,706,13,637,826,100,23,847,671,36,167,279,121,793,189,199,374,50,125,51,212,230,286,66,272,566,6,484,634,344,32,429,289,327,86,103,96,601,114,441,517,37,64,298 }, +{ 17,45,227,106,209,243,21,290,255,400,207,48,263,270,62,186,119,2,496,454,50,32,3,5,52,221,29,425,136,408,430,46,513,171,14,659,54,84,787,721,741,56,281,38,536,80,181,378,240,742,587,552,1,306,76,123,241,541,655,328,428,61,129,41,666,72,502,57,89,12,760,540,115,155,148,383,449,794,37,96,361,152,11,34,214,4,311,51,440,474,592,431,64,790,202,179,405,350,292,36,90,67,663,6,141,59,13,498,103,583,130,697,514,40,211,99,58,10,128,237,217,770,27,869,157,828,834,391 }, +{ 340,354,586,658,668,156,195,698,363,447,883,296,1,411,303,18,379,9,919,360,51,621,98,31,48,591,371,13,21,446,163,5,121,70,132,125,23,759,846,127,761,478,60,293,223,271,146,385,120,664,691,108,763,82,634,638,75,4,260,24,807,774,144,44,522,407,30,457,32,16,914,463,126,777,335,93,771,367,71,49,39,12,0,687,351,118,299,201,40,7,50,848,518,284,922,854,758,538,364,279,11,10,724,310,217,326,64,393,77,541,767,167,150,137,105,103,101,87,58,17,115,286,225,33,401,867,850,663 }, +{ 277,153,111,12,23,51,474,99,38,139,37,457,453,117,542,41,79,629,196,401,13,11,14,569,961,102,33,134,188,89,40,157,54,328,72,775,57,115,17,94,413,339,431,15,377,369,3,477,308,719,248,165,313,4,468,45,485,148,32,197,76,734,216,62,2,21,10,587,405,64,5,59,29,34,6,210,82,509,471,128,155,152,730,177,490,7,266,361,52,120,475,1,0,873,19,305,758,9,899,125,22,110,386,300,211,93,529,229,48,260,237,180,65,50,528,880,77,391,86,36,27,588,326,546,482,402,514,56 }, +{ 18,16,24,0,159,35,68,49,105,9,60,71,101,28,344,55,7,118,320,109,424,14,327,455,239,22,286,170,272,310,1,374,252,154,419,329,167,158,124,518,23,95,709,39,2,21,51,65,13,301,5,890,48,92,265,98,191,212,12,10,108,137,347,128,30,538,31,364,125,202,37,553,20,149,121,557,185,36,677,67,333,169,338,146,127,346,46,175,64,6,126,100,577,50,254,32,512,916,33,403,86,395,69,242,806,371,115,96,44,77,318,221,479,694,616,102,165,623,83,910,627,737,917,38,793,578,846,375 }, +{ 0,105,9,16,49,18,24,68,101,518,158,320,28,35,301,170,272,890,344,286,109,327,39,65,55,512,7,1,127,916,98,118,252,60,737,159,239,371,21,71,124,395,154,14,48,455,623,242,31,23,51,419,374,364,761,5,2,12,137,310,95,125,293,333,846,202,13,616,329,347,338,385,30,37,131,44,938,479,128,836,709,22,538,265,506,64,793,627,10,67,167,299,403,827,212,713,578,149,116,32,36,219,100,910,254,553,175,318,677,108,185,50,6,96,46,685,221,421,424,191,577,92,93,269,599,187,165,284 }, +{ 141,180,1,5,352,365,13,2,4,217,341,115,269,317,15,23,752,3,7,901,6,0,197,21,51,31,77,202,44,318,32,64,372,873,498,10,93,8,11,244,33,9,165,12,102,137,22,253,49,48,237,116,30,98,125,39,177,569,401,28,143,291,308,864,509,40,120,349,403,37,105,391,144,153,482,203,450,110,421,127,72,576,494,95,453,260,247,96,475,373,326,117,36,717,304,131,128,134,90,89,14,457,854,221,206,196,55,811,82,947,629,351,922,386,59,961,734,670,17,437,661,224,201,16,88,76,164,187 }, +{ 51,4,23,102,33,300,40,485,453,880,153,19,17,196,27,342,78,26,53,403,47,77,210,0,475,117,73,2,57,34,11,5,200,13,99,494,14,1,22,12,176,421,64,111,41,21,368,361,59,757,231,130,123,6,139,128,134,401,106,18,56,49,322,317,177,45,775,48,115,165,108,10,125,65,504,495,197,32,605,229,80,341,221,183,390,813,46,37,618,306,95,719,554,152,753,736,543,444,161,402,277,119,630,236,216,122,113,29,730,237,25,899,217,714,383,297,472,445,378,250,38,678,670,527,503,469,412,318 }, +{ 62,440,56,184,229,183,556,130,3,136,548,152,266,99,162,161,17,57,84,452,305,12,383,257,123,403,34,40,527,14,205,349,504,555,497,328,4,361,202,139,775,33,38,37,128,475,129,880,313,381,757,102,11,196,59,119,401,432,402,54,471,453,215,77,23,514,507,585,51,211,153,80,494,495,469,236,477,117,111,64,421,240,369,106,21,214,277,157,308,5,291,141,378,249,13,2,803,619,318,45,76,177,27,485,472,134,41,32,412,339,216,65,524,197,10,72,114,176,165,53,90,372,22,188,245,86,217,543 }, +{ 13,23,115,51,141,202,77,64,269,217,33,318,102,32,21,128,137,0,177,180,4,5,291,9,48,352,10,197,90,196,317,40,153,7,372,18,15,349,22,2,247,165,275,6,403,11,117,125,237,59,3,16,752,494,28,342,304,31,341,134,14,98,86,210,36,241,12,244,49,95,24,498,30,116,39,1,143,901,453,20,450,144,365,402,221,17,475,93,203,127,65,253,216,72,326,120,164,576,35,19,96,44,437,160,421,308,83,67,864,954,569,817,719,25,101,100,61,55,57,284,805,523,401,60,293,285,105,88 }, +{ 1,22,36,105,170,28,55,239,86,31,2,95,5,9,127,0,98,301,12,64,67,7,49,320,109,654,44,83,10,169,208,143,21,312,35,13,23,128,141,740,125,242,14,512,293,116,160,237,51,395,50,338,37,159,96,6,933,114,115,708,299,751,185,137,844,505,269,168,69,48,638,103,597,928,202,180,244,323,16,352,253,165,3,713,197,194,892,39,24,599,65,54,341,285,318,286,46,685,456,951,4,623,824,32,133,158,365,584,601,535,38,498,144,218,251,841,533,506,30,371,217,479,8,503,284,870,752,276 }, +{ 15,0,1,2,5,13,23,7,901,9,6,8,12,51,4,3,457,180,341,898,82,22,115,10,141,120,117,31,351,14,202,260,197,28,269,33,153,961,64,30,44,37,93,18,569,854,11,21,16,77,217,137,365,386,719,237,134,391,110,128,523,49,450,36,629,498,352,102,125,326,317,40,401,509,730,318,196,24,203,546,308,39,116,922,55,752,32,86,817,17,403,90,98,35,453,95,373,59,99,873,177,758,111,143,38,291,242,139,65,48,244,899,372,285,642,349,247,144,734,638,615,482,277,72,253,421,89,475 }, +{ 274,98,100,39,1,265,438,190,310,625,382,30,530,223,909,96,264,593,166,778,88,812,410,960,731,557,252,31,125,21,539,23,254,9,48,51,116,639,44,478,393,131,127,13,101,0,293,284,329,795,404,840,144,656,435,333,724,616,5,219,228,321,272,421,834,165,921,957,224,105,32,36,93,128,697,367,541,669,765,242,221,49,676,137,418,455,160,748,83,897,163,202,682,578,475,453,553,386,807,217,213,551,613,406,335,403,141,466,197,827,180,948,37,158,187,115,905,821,791,203,352,286,258,371,120,863,730,2 }, +{ 212,18,118,447,167,781,363,411,271,647,146,121,60,562,664,621,463,815,478,1,16,446,9,777,354,628,21,936,48,101,932,132,68,191,98,520,522,223,71,264,5,24,759,55,199,575,727,566,126,13,23,724,156,360,691,125,0,407,591,608,49,293,604,221,51,35,92,195,346,31,107,252,108,375,586,96,154,914,682,541,807,150,39,589,124,848,265,69,22,105,50,834,32,364,302,393,329,12,4,10,382,535,404,28,166,765,100,668,273,33,149,88,706,806,163,279,95,410,598,44,335,955,7,30,67,284,159,467 }, +{ 24,28,14,7,35,16,22,65,0,1,2,158,49,109,55,159,124,95,18,67,149,105,71,239,169,68,108,185,424,289,9,12,69,46,577,10,175,154,320,5,164,347,6,747,344,21,835,36,286,50,38,83,170,654,892,23,420,92,114,51,64,143,60,13,374,189,302,429,140,48,103,570,118,32,37,29,336,610,133,327,312,398,39,484,128,638,168,301,272,125,202,137,86,150,30,194,230,671,345,584,703,96,54,115,273,251,310,283,141,518,98,308,20,538,401,101,127,52,31,221,346,455,535,236,403,389,458,267 }, +{ 105,272,131,22,286,239,320,327,98,127,219,9,185,224,374,187,55,28,578,86,31,258,36,913,616,535,1,95,538,64,164,837,634,109,116,601,44,654,312,170,910,49,708,623,115,23,5,0,713,371,201,159,13,505,2,197,83,892,7,35,67,180,533,928,51,933,317,737,301,751,10,716,352,284,6,160,776,237,509,916,165,242,498,251,531,12,395,39,924,137,638,385,293,269,30,276,168,141,217,254,752,208,144,569,896,836,143,346,24,824,21,4,546,468,169,308,14,761,128,345,244,318,482,365,3,597,391,384 }, +{ 28,301,22,31,127,512,105,98,395,109,44,299,293,95,9,320,1,599,685,900,55,0,239,36,763,338,242,49,116,125,841,168,870,456,286,23,276,506,86,35,284,51,185,65,492,159,2,24,374,479,13,393,928,5,144,7,64,169,713,141,12,137,327,21,202,14,268,237,16,935,10,201,558,272,538,67,401,367,37,143,83,308,424,164,312,128,158,115,48,165,918,654,194,269,923,740,39,347,244,623,18,6,489,253,318,114,963,160,352,289,124,180,68,96,420,170,203,175,131,421,219,434,197,391,221,762,453,93 }, +{ 2,58,29,52,1,186,334,46,5,14,151,75,45,400,155,50,61,227,163,262,502,69,549,70,220,223,48,38,311,112,67,409,113,780,7,243,675,767,27,17,209,24,103,80,394,96,21,315,54,307,513,536,83,287,787,309,37,281,6,16,106,807,171,587,496,267,19,32,631,474,270,491,12,35,181,26,583,454,74,869,820,852,36,324,721,255,845,278,64,73,335,357,89,87,140,72,537,25,760,290,18,659,614,430,189,66,97,133,663,114,108,592,552,128,331,666,764,141,606,3,86,380,486,366,76,65,148,10 }, +{ 7,107,232,135,97,387,92,356,298,66,14,2,192,359,278,172,52,357,126,324,448,35,60,526,314,16,38,29,46,330,380,43,362,259,392,230,20,226,74,140,262,246,279,147,24,825,64,58,5,121,568,87,294,32,220,501,132,21,612,465,95,150,86,104,620,18,12,71,173,581,54,534,0,893,37,22,808,583,178,353,90,10,580,550,146,707,802,600,606,331,194,112,222,28,69,660,853,65,70,199,171,68,560,1,174,36,50,77,49,48,779,500,204,683,493,414,6,61,25,764,55,138,33,102,750,888,307,45 }, +{ 20,43,104,414,560,426,707,784,173,319,861,7,819,81,715,422,879,0,376,330,74,95,97,52,32,192,64,38,22,49,526,356,66,204,681,397,207,140,232,5,470,65,693,61,359,636,387,500,107,324,28,91,712,18,10,29,147,77,21,595,392,113,577,172,729,2,325,24,138,92,33,347,125,86,945,102,90,306,40,115,4,198,370,583,230,174,12,904,180,11,858,312,153,124,17,587,750,76,59,69,344,298,3,135,13,37,46,825,718,357,165,348,315,214,72,887,117,289,353,246,196,141,84,36,427,51,237,48 }, +{ 104,74,636,204,355,222,66,81,0,145,25,319,784,746,192,750,29,20,173,174,792,64,90,138,280,715,65,194,91,879,525,32,22,4,348,287,43,95,18,422,7,214,415,86,77,42,40,6,681,289,59,524,151,33,10,52,712,2,28,544,945,13,597,102,45,177,97,21,57,11,243,49,85,36,312,500,426,693,141,5,673,624,396,16,1,122,87,115,648,24,26,186,632,233,67,17,172,414,304,416,123,12,353,389,117,651,580,69,588,751,153,113,874,112,14,23,227,216,128,58,217,197,27,875,114,635,137,707 }, +{ 101,0,9,35,68,154,252,39,65,28,364,124,166,100,149,336,158,289,346,439,429,419,67,55,114,570,694,30,16,265,24,109,484,88,1,329,69,194,404,637,49,189,389,547,133,398,703,826,671,283,22,168,610,175,212,190,7,83,345,103,64,14,768,399,71,274,333,344,230,95,799,50,21,706,36,722,677,420,10,185,962,51,23,18,553,140,254,159,125,967,535,676,46,48,310,2,86,96,952,264,13,12,169,382,5,596,108,323,705,782,251,118,208,857,702,756,562,865,438,218,60,267,131,237,37,755,105,272 }, +{ 57,14,4,236,231,59,369,361,300,585,342,51,23,719,401,13,38,176,46,202,62,402,3,56,210,54,12,2,412,803,381,457,215,11,507,128,40,757,555,77,514,961,32,730,629,322,161,328,37,162,33,133,283,108,129,21,211,34,102,494,17,152,130,29,99,139,153,52,527,472,181,79,123,475,229,6,497,899,453,240,758,194,205,184,188,183,177,0,136,377,305,134,155,248,165,157,425,290,440,714,495,209,739,196,277,269,80,50,556,10,805,64,65,523,503,386,257,141,16,7,5,179,403,84,600,469,318,180 }, +{ 2,1,3,5,141,6,7,15,0,269,180,64,33,77,10,352,102,13,202,128,318,11,197,17,14,4,291,12,134,117,9,120,752,165,153,196,137,217,498,341,349,260,110,21,342,93,40,31,237,23,317,44,82,115,22,16,59,19,86,51,351,678,32,57,36,961,37,450,111,125,365,457,27,143,901,569,95,79,203,49,403,873,326,8,139,494,864,372,28,98,402,116,18,244,56,854,509,48,719,386,947,29,922,954,76,94,373,38,45,523,25,391,285,99,730,546,144,475,275,72,90,164,210,26,24,453,817,253 }, +{ 5,21,61,48,32,202,1,70,259,13,58,115,22,23,178,90,0,494,51,12,475,453,182,18,465,403,49,17,76,450,120,142,318,141,137,147,534,455,402,146,132,128,64,31,11,522,260,771,953,922,859,523,420,269,241,221,207,175,121,72,37,6,4,3,2,768,205,179,415,376,362,28,10,237,30,937,702,113,68,16,9,798,247,590,326,197,165,626,344,279,347,878,125,195,955,933,928,868,854,851,821,815,795,780,765,727,678,668,657,576,562,540,503,502,493,488,482,430,423,411,365,288,285,281,273,118,87,65 }, +{ 205,141,59,152,245,4,352,72,497,76,216,247,79,452,11,588,94,21,188,217,89,875,77,339,864,954,464,269,115,148,64,12,37,529,38,111,32,358,180,5,316,405,471,490,45,474,365,317,349,752,177,288,437,498,51,99,90,468,102,372,128,318,48,1,237,17,542,23,947,241,431,221,54,3,33,291,2,734,197,413,377,270,460,13,401,961,873,341,14,196,579,482,244,569,629,40,308,645,184,257,304,678,720,449,36,10,202,749,275,134,117,428,15,290,153,143,453,57,139,7,430,6,350,769,281,210,476,403 }, +{ 15,1,0,2,5,13,4,3,7,6,23,365,341,115,8,51,9,77,31,10,457,93,44,569,120,197,202,141,12,961,165,33,317,450,901,11,260,55,110,352,22,719,730,453,217,98,82,64,401,18,102,40,21,269,523,403,70,386,49,351,752,105,498,28,16,629,308,318,111,61,898,30,117,475,509,391,817,95,922,342,36,59,494,210,134,899,137,421,873,116,854,14,32,177,196,139,153,734,128,143,291,24,20,349,37,758,372,247,90,326,690,801,113,216,48,275,670,27,125,25,39,57,638,17,304,35,237,244 }, +{ 5,2,50,58,171,186,46,29,14,52,45,38,61,155,17,218,1,281,334,151,227,400,48,487,502,36,54,760,67,133,103,114,21,96,328,236,366,243,80,552,209,83,311,828,27,745,160,920,19,24,766,32,6,108,832,65,12,223,106,514,3,433,70,787,842,99,28,549,113,112,834,540,361,163,26,37,536,516,496,137,765,75,480,454,754,532,780,0,430,966,739,22,238,86,474,51,767,283,18,25,583,115,285,587,309,7,73,287,72,255,23,600,412,128,822,807,13,323,315,208,76,119,545,10,956,270,64,16 }, +{ 457,795,70,120,846,48,23,761,125,318,64,751,415,291,758,221,763,202,391,269,87,401,77,352,237,21,165,128,96,163,558,13,1,260,137,494,5,51,851,767,141,197,546,557,867,597,49,518,102,349,450,623,509,33,98,177,678,922,900,743,498,293,31,223,342,403,371,32,180,873,854,0,217,884,196,153,95,4,44,308,7,2,541,17,30,127,765,58,351,372,386,117,807,6,903,704,182,845,22,134,663,210,105,39,27,402,326,859,307,159,285,281,82,817,719,455,353,312,192,61,931,523,203,947,247,207,385,45 }, +{ 23,51,13,40,453,102,33,4,196,77,117,475,64,153,0,22,10,11,65,59,15,12,134,21,1,403,139,202,95,14,210,28,177,108,18,115,141,165,57,137,128,457,86,2,31,99,6,37,36,401,269,49,9,318,82,7,275,180,5,24,217,342,485,16,111,277,125,386,291,44,32,300,197,19,421,352,46,48,194,730,341,237,17,120,93,494,283,133,90,25,523,260,3,285,114,89,216,8,317,899,38,961,719,498,312,50,26,20,365,351,67,391,54,110,373,326,289,208,168,546,752,569,308,304,98,377,402,361 }, +{ 229,152,266,57,381,452,432,313,471,12,99,17,184,339,369,62,4,129,59,157,128,77,497,3,11,38,123,202,162,37,291,188,257,40,403,136,5,216,21,205,102,111,775,79,51,475,14,33,32,45,402,453,54,619,90,119,115,64,76,177,2,106,361,377,72,880,139,23,494,130,277,757,183,349,84,401,27,56,308,89,80,19,318,141,117,1,94,10,328,529,474,210,245,249,41,36,217,269,421,86,618,6,148,556,342,305,588,179,383,0,134,34,514,477,304,769,542,22,214,378,275,137,13,65,300,95,285,82 }, +{ 49,109,159,28,272,22,327,9,105,95,254,168,131,374,286,347,39,35,424,158,55,175,169,420,627,578,312,67,346,194,0,912,1,224,219,65,86,239,892,36,83,518,114,688,320,538,127,634,584,913,439,371,64,616,30,69,24,10,535,187,336,2,228,7,716,289,68,98,601,23,16,31,164,654,208,505,51,258,14,13,170,874,128,44,12,837,103,890,160,115,385,137,345,50,185,143,116,756,251,141,101,96,190,747,333,125,202,5,166,708,133,21,637,570,242,237,46,835,189,165,638,149,610,706,100,751,48,577 }, +{ 5,61,29,58,311,2,45,209,80,52,454,227,243,106,17,496,592,869,1,151,255,334,75,667,287,70,738,549,171,48,46,483,663,74,155,14,50,163,207,666,290,6,186,119,32,27,378,21,220,659,263,112,136,84,742,307,833,7,400,780,469,767,62,64,72,513,113,148,262,56,409,270,161,331,315,635,425,89,19,38,495,631,3,76,73,383,887,502,69,66,34,223,128,26,240,54,86,306,87,491,96,67,845,408,135,814,37,4,25,445,181,95,294,24,90,226,103,10,405,237,12,297,141,22,655,129,11,16 }, +{ 260,244,373,276,44,269,141,228,110,131,574,219,137,30,839,717,224,217,661,36,352,567,406,120,1,116,253,93,318,160,202,341,31,21,88,201,39,190,187,77,372,752,96,180,64,851,268,55,98,317,82,22,258,613,326,86,351,48,51,23,115,295,213,100,539,291,144,860,35,922,864,9,450,261,489,28,365,105,13,177,442,840,515,321,83,166,856,854,49,935,203,530,284,0,274,349,816,69,197,954,251,165,67,10,811,434,247,778,143,385,531,254,968,957,237,498,843,127,384,669,466,824,102,223,32,5,871,800 }, +{ 99,12,139,79,453,11,277,196,474,51,37,542,111,401,23,94,188,775,33,13,40,102,313,339,961,629,153,431,477,4,38,485,475,300,115,569,134,117,377,157,210,59,14,471,266,15,89,328,880,148,369,57,457,54,413,405,308,403,197,152,128,72,64,165,734,10,3,2,21,17,670,488,719,202,229,82,757,0,5,402,32,41,77,275,177,45,76,29,305,22,342,36,498,1,730,46,494,184,28,318,93,31,529,162,514,6,269,27,482,62,110,873,528,452,179,120,141,137,86,421,317,7,237,129,8,18,361,428 }, +{ 68,35,16,149,24,71,9,69,0,18,67,118,101,212,65,191,114,230,167,133,124,103,399,140,154,1,50,283,246,398,60,7,64,565,55,695,39,218,336,723,375,302,796,28,108,238,267,705,83,189,330,100,23,486,589,702,562,458,21,443,175,13,361,48,75,345,92,96,22,51,181,237,532,755,46,30,2,115,88,14,10,86,363,650,732,335,12,36,49,54,891,520,217,411,516,141,166,95,412,394,641,180,37,5,906,478,447,223,251,247,264,433,252,389,146,480,98,596,602,545,830,346,664,309,271,121,364,628 }, +{ 88,274,435,30,613,100,131,829,166,530,382,93,960,795,190,127,856,466,957,187,521,264,473,778,31,254,228,716,406,1,686,39,863,203,410,224,800,457,137,9,160,704,219,438,28,924,944,120,450,144,836,492,299,326,260,44,116,840,98,202,83,96,321,36,0,21,921,55,141,367,341,827,639,385,265,158,128,772,201,49,539,64,258,317,180,110,86,269,851,442,295,125,908,77,662,276,23,669,744,272,373,242,105,82,931,48,35,968,351,168,318,859,115,578,822,33,557,418,371,616,32,625,67,213,217,109,523,365 }, +{ 167,118,212,18,16,71,60,24,191,375,411,68,363,146,447,101,199,589,271,562,126,302,647,121,815,9,628,566,273,35,575,664,21,92,55,781,621,1,48,777,478,0,149,936,818,108,520,150,354,154,446,847,463,124,346,132,264,98,107,7,65,522,156,28,759,13,22,23,39,49,932,727,882,5,14,223,32,640,608,467,100,51,604,125,695,10,69,724,806,246,221,50,140,195,517,67,252,96,768,279,293,31,360,848,88,166,105,691,95,682,674,46,535,103,2,175,649,109,159,598,458,265,329,364,914,12,653,33 }, +{ 141,64,86,177,128,597,77,269,95,180,237,352,304,291,275,147,588,372,102,194,125,947,13,678,49,875,202,349,120,437,115,4,59,137,153,751,197,40,208,342,465,954,67,23,5,318,135,32,216,660,470,534,196,182,98,31,22,612,90,38,312,448,107,7,10,581,165,353,192,172,707,51,262,498,494,117,33,21,17,1,389,76,203,14,46,565,563,65,569,546,391,330,285,284,277,210,205,139,134,26,25,20,19,12,9,6,3,620,217,11,326,97,853,629,259,278,232,789,380,365,294,289,244,55,43,0,247,111 }, +{ 18,289,701,65,240,194,90,403,523,214,421,283,475,389,217,102,862,202,847,437,494,453,650,64,697,874,51,352,751,401,817,33,84,0,899,13,597,5,196,805,32,23,11,954,95,3,27,22,24,757,875,141,671,312,108,21,153,19,306,114,118,247,450,288,77,17,730,56,4,12,177,942,273,958,814,117,519,86,61,128,859,207,835,193,880,123,249,838,28,120,342,49,134,300,2,6,801,216,719,57,457,576,864,304,125,302,124,14,615,372,16,210,40,237,60,577,504,119,770,608,752,62,10,9,643,48,1,15 }, +{ 51,23,13,202,115,21,12,5,32,128,403,453,141,401,165,308,120,318,457,15,475,4,269,64,1,0,197,10,719,494,99,2,450,37,48,730,3,180,523,77,7,18,386,14,9,6,16,59,22,217,260,125,11,17,90,177,341,237,117,421,153,24,221,899,33,352,317,102,28,326,137,247,82,817,961,19,40,365,402,391,569,27,629,57,95,49,25,31,8,216,210,110,758,304,72,29,93,54,351,26,38,291,98,20,134,61,196,76,56,45,44,241,275,139,372,349,509,36,65,342,350,615,678,285,89,214,50,670 }, +{ 98,223,393,125,31,791,834,116,271,1,93,202,697,44,64,167,127,293,5,541,51,446,801,77,450,212,48,284,807,234,120,23,765,21,318,13,421,18,195,948,639,551,132,360,730,770,141,142,562,146,163,96,386,49,963,144,668,354,591,197,346,128,260,221,0,198,82,165,416,269,494,670,367,949,817,147,33,178,522,70,32,535,455,719,137,453,326,203,842,22,102,687,61,156,55,121,407,4,315,2,325,105,403,883,110,329,217,342,95,692,10,781,615,463,798,12,958,291,351,7,17,39,878,586,113,196,28,68 }, +{ 15,4,40,11,23,165,13,51,110,93,120,32,82,77,125,33,197,141,260,202,59,10,0,21,102,64,180,5,57,31,453,22,386,12,269,8,318,128,403,134,3,139,95,475,457,730,44,9,49,719,326,117,203,1,115,351,98,450,17,352,28,99,116,217,494,523,210,373,391,961,37,177,90,144,137,2,342,18,153,317,401,56,854,14,48,65,237,341,36,758,421,291,111,277,402,365,509,30,7,922,242,105,275,372,349,24,86,901,801,899,898,300,39,308,817,72,6,670,16,45,752,498,27,38,76,304,170,615 }, +{ 15,1,0,13,2,5,901,7,23,6,9,341,8,3,4,51,961,12,115,10,898,180,82,569,134,31,22,141,351,202,457,120,44,269,165,77,260,365,403,401,318,317,14,33,217,11,854,93,28,30,453,18,137,37,386,21,110,64,719,36,498,352,128,450,16,117,922,475,509,49,177,55,111,391,40,730,523,99,326,98,102,629,758,153,32,39,642,372,24,873,752,116,291,308,421,125,373,95,143,482,203,817,494,35,899,196,86,304,349,17,244,38,237,65,275,247,242,59,105,402,210,638,48,615,144,342,148,127 }, +{ 234,416,77,315,5,639,202,325,147,113,198,49,450,455,61,142,329,178,21,0,427,470,494,342,58,32,557,22,318,230,725,43,858,112,120,70,102,13,48,263,20,344,260,884,425,817,128,798,115,290,105,518,291,137,95,904,23,403,64,141,491,159,241,845,523,31,121,33,319,97,320,392,246,196,153,17,173,104,10,39,663,269,117,592,501,125,51,347,72,30,163,28,253,170,408,194,376,107,18,265,544,326,352,270,341,4,738,615,534,475,595,98,259,66,631,449,301,922,158,76,134,720,512,312,9,180,859,690 }, +{ 146,60,271,126,16,156,360,199,18,121,167,640,522,132,24,446,354,591,71,463,118,340,150,92,598,273,441,195,107,212,22,0,407,10,5,21,108,467,28,279,586,575,423,566,727,191,101,493,649,534,68,95,608,517,55,35,32,783,653,9,408,48,49,508,363,296,607,698,246,13,668,33,64,117,109,356,98,314,39,658,140,105,7,362,660,447,809,411,955,93,31,621,50,303,298,153,347,12,158,125,65,953,713,264,163,350,359,141,124,14,143,51,939,478,149,115,36,75,4,781,581,225,207,102,77,30,562,44 }, +{ 4,11,361,300,77,56,377,368,14,59,40,161,51,128,33,200,210,23,378,27,54,495,102,554,38,494,453,17,21,12,202,80,444,108,53,757,37,46,78,13,245,457,342,390,139,133,123,386,84,523,32,605,196,862,527,736,803,99,73,57,19,630,561,475,3,542,509,421,317,250,181,136,111,277,269,450,197,472,183,48,26,485,730,297,62,714,402,381,403,391,880,122,719,341,318,306,145,25,5,514,256,61,899,546,106,90,50,34,383,833,236,775,497,165,129,85,401,366,184,469,436,838,358,328,316,291,275,241 }, +{ 141,351,217,82,352,120,854,260,64,15,180,372,1,922,269,317,36,137,752,373,13,21,349,51,898,450,77,202,110,23,318,160,93,115,291,128,365,48,197,177,901,96,5,165,244,864,10,86,457,4,40,237,523,247,33,579,341,32,304,11,661,125,83,143,498,326,817,2,203,275,437,69,102,954,717,16,59,961,35,386,851,730,22,475,28,253,31,7,57,98,95,134,144,391,12,6,719,117,210,116,17,196,139,0,3,37,494,473,403,114,49,30,29,164,899,704,559,153,90,72,55,9,45,509,482,453,393,230 }, +{ 15,77,13,1,0,102,23,33,2,4,51,5,10,291,7,9,3,450,6,217,117,120,177,317,341,260,11,12,817,342,365,115,8,134,21,153,180,16,18,22,349,40,165,82,14,64,141,453,372,31,457,523,901,196,197,326,275,352,210,961,719,730,28,304,475,403,569,44,128,32,899,93,59,269,401,24,17,49,752,98,318,110,36,629,216,30,386,125,95,494,90,137,48,351,308,116,111,57,139,37,86,99,498,65,615,247,482,144,39,237,221,20,96,19,244,421,300,758,203,670,194,509,38,854,402,873,437,391 }, +{ 15,23,13,77,141,260,137,120,51,202,180,115,1,365,217,0,341,450,269,291,317,318,5,197,128,21,9,177,373,351,110,352,165,2,12,523,7,64,349,326,10,48,36,901,32,33,22,403,854,82,90,96,4,922,16,37,28,18,752,457,40,386,244,372,102,494,6,308,8,160,86,24,30,14,401,49,661,817,453,719,421,402,11,704,961,475,237,873,342,55,3,39,730,391,59,196,93,221,117,143,216,615,898,44,498,275,253,210,304,35,285,95,125,31,98,17,139,509,72,153,811,482,89,83,144,899,99,576 }, +{ 348,174,85,138,6,280,74,355,233,192,204,636,580,353,343,289,673,66,65,91,81,104,712,750,25,42,214,792,95,64,681,173,194,32,715,135,90,312,29,879,172,825,63,235,835,86,22,87,145,370,5,256,7,222,415,52,0,874,426,97,500,519,17,26,237,43,4,288,36,18,10,389,20,33,560,76,21,61,40,544,45,59,249,888,77,577,746,232,28,102,2,72,49,568,123,287,56,525,448,751,180,11,337,526,707,671,226,27,19,247,24,319,117,48,422,114,12,69,108,84,208,597,37,1,861,67,889,58 }, +{ 152,452,497,59,216,4,269,188,77,11,79,339,128,529,94,471,318,141,202,588,32,76,377,177,678,33,111,291,349,90,5,102,21,137,51,72,12,179,542,38,99,64,257,184,37,1,245,217,460,196,48,372,115,947,148,45,402,474,40,89,342,210,17,352,205,288,3,153,769,13,117,10,2,134,292,54,275,304,139,875,498,431,23,405,241,403,247,317,569,229,401,453,494,285,358,180,197,86,300,57,0,476,961,6,954,308,36,143,524,165,277,475,316,597,14,95,237,15,7,221,341,58,157,735,129,266,214,421 }, +{ 417,253,244,499,141,10,559,564,110,8,260,352,728,143,180,951,120,642,638,661,752,922,341,373,811,137,269,901,717,197,93,206,498,44,165,31,116,203,160,854,384,351,36,873,762,326,704,268,217,1,64,115,282,317,959,55,144,15,365,82,898,968,509,164,86,479,318,13,851,22,21,332,473,434,51,202,77,940,911,569,23,125,450,864,824,237,261,9,242,615,372,617,127,48,201,102,128,4,33,5,96,506,0,391,117,98,28,401,386,40,295,105,32,758,531,276,338,37,83,35,349,59,533,153,177,629,11,12 }, +{ 77,13,23,51,177,102,33,115,59,4,40,0,141,128,90,210,202,137,64,22,269,291,217,10,196,28,153,117,318,7,49,2,14,216,134,18,180,16,6,11,9,24,403,1,275,197,3,95,36,86,125,165,247,342,31,352,494,19,32,402,12,139,453,317,20,237,98,65,15,349,44,475,26,285,17,30,120,111,57,93,21,372,105,27,25,719,194,457,341,203,304,386,260,391,730,116,421,365,35,29,5,99,326,123,498,208,39,569,509,244,288,752,450,143,678,144,110,523,401,308,82,214,300,351,43,37,48,164 }, +{ 1,2,22,50,67,14,36,5,46,28,103,12,0,38,83,114,65,168,194,7,69,133,86,95,24,49,218,29,54,21,55,96,109,160,51,10,584,16,128,6,9,23,48,158,18,75,756,37,35,105,169,32,389,289,159,323,238,181,52,244,202,13,503,646,164,137,532,141,239,115,361,480,185,64,17,143,789,283,124,708,253,505,946,597,3,717,45,776,58,170,108,269,70,735,312,874,285,610,68,782,189,318,424,71,531,31,308,237,320,171,4,892,72,402,99,328,220,418,251,420,394,19,180,577,487,401,347,344 }, +{ 17,106,119,378,742,255,306,136,207,240,84,383,62,790,80,655,61,45,5,56,311,3,209,504,440,667,76,151,32,58,263,483,179,29,2,833,292,548,214,123,129,425,186,454,128,243,205,738,445,64,21,245,148,52,38,14,26,249,57,27,328,19,90,6,4,555,11,34,59,54,162,202,184,507,469,141,592,229,48,215,887,710,152,73,86,40,161,72,618,460,266,257,491,77,358,211,227,287,25,869,183,318,297,50,290,495,10,216,130,614,155,1,476,177,137,361,12,315,37,112,33,22,46,95,113,269,194,171 }, +{ 141,128,202,3,5,2,1,269,64,318,6,33,17,102,15,180,0,196,137,10,153,7,120,352,197,13,77,117,51,134,403,14,165,12,23,402,11,93,9,342,260,82,110,21,494,19,22,237,31,351,4,125,86,475,457,450,326,27,44,32,203,40,36,95,291,961,453,115,25,285,143,111,678,98,341,37,139,99,523,817,49,57,752,498,45,386,18,38,217,8,116,65,16,244,28,144,317,365,56,719,373,901,194,854,79,898,277,59,29,576,26,421,30,569,401,730,947,177,164,864,48,72,391,922,24,873,94,349 }, +{ 38,514,328,377,11,57,266,248,41,880,313,471,556,152,361,4,485,99,305,757,403,157,12,102,339,54,369,40,211,130,542,457,3,37,188,14,139,23,13,153,494,117,33,475,775,229,507,381,300,196,77,453,452,59,555,162,488,184,277,585,236,477,440,629,62,128,51,111,421,134,402,183,215,961,670,79,548,123,342,210,202,89,401,527,474,94,65,587,719,543,432,181,45,17,257,291,80,64,72,21,619,108,32,413,828,46,5,29,0,95,2,275,129,308,10,56,504,205,86,618,155,76,177,49,431,569,90,497 }, +{ 68,520,167,101,264,118,478,562,0,9,664,777,936,604,212,100,191,252,154,18,124,806,265,16,759,21,48,1,71,375,88,724,628,24,329,35,682,411,410,363,166,302,815,447,65,419,589,55,23,39,647,149,917,909,821,382,125,942,98,346,925,772,13,701,146,96,223,51,108,31,10,221,271,22,60,28,321,44,92,905,69,30,676,639,49,593,364,882,274,694,521,907,64,105,5,158,67,621,781,812,126,133,553,189,848,897,213,686,95,32,121,404,522,199,103,116,156,50,140,83,429,706,763,273,115,165,127,77 }, +{ 230,689,699,213,466,831,352,217,30,443,418,854,144,201,840,855,251,203,957,822,96,530,1,539,93,36,137,800,317,83,190,128,326,669,752,351,748,494,88,206,160,31,473,859,335,202,141,44,321,253,735,498,269,435,116,367,187,86,35,927,332,180,237,69,98,778,244,285,219,82,131,576,228,617,208,922,866,930,372,100,120,64,2,934,403,349,531,702,48,21,731,817,274,23,5,10,13,406,365,224,947,824,795,345,898,291,382,295,223,692,318,286,238,39,341,276,863,77,615,166,260,625,678,51,28,67,410,125 }, +{ 77,33,102,117,134,153,196,291,13,51,15,23,82,64,40,202,128,120,0,141,260,351,450,22,4,95,59,137,269,342,177,386,318,326,11,115,10,210,65,373,86,180,217,49,403,1,165,275,28,18,453,57,36,125,98,352,494,523,139,197,14,31,854,475,2,194,216,9,7,817,21,719,93,6,730,24,457,237,90,12,116,16,44,349,110,3,5,402,99,961,317,114,372,19,48,32,285,105,96,17,365,341,300,143,8,203,401,247,164,108,421,25,752,144,26,30,20,391,39,111,304,109,758,50,221,208,37,289 }, +{ 11,40,33,51,542,328,13,117,38,14,23,139,153,134,54,102,111,12,485,377,775,37,99,403,231,277,401,719,369,3,475,453,514,4,629,308,211,880,457,291,305,89,266,152,130,2,57,196,961,6,488,215,5,176,59,555,471,313,72,300,477,183,62,184,79,0,507,248,115,21,670,339,249,548,361,1,165,292,29,197,229,77,556,474,236,386,421,157,413,188,452,17,758,41,162,391,449,587,32,46,123,428,509,52,247,569,136,899,757,523,210,753,155,129,76,50,237,64,730,720,476,383,312,440,275,90,45,342 }, +{ 77,64,141,202,33,102,128,153,2,117,269,6,23,318,1,13,0,134,137,51,5,180,3,196,10,7,40,165,15,14,352,197,86,291,237,115,403,95,17,177,22,217,36,139,210,9,120,19,125,342,494,275,82,475,457,49,453,16,12,31,4,65,21,402,11,143,260,194,110,93,450,25,28,351,317,111,498,326,27,18,349,752,44,341,59,164,386,26,285,116,365,98,719,208,32,391,300,509,401,523,99,20,24,38,114,244,373,730,55,48,901,372,203,312,961,8,277,160,678,304,34,37,57,854,56,546,29,144 }, +{ 15,4,93,5,13,21,11,1,23,32,110,141,64,82,180,2,33,40,3,98,352,120,6,10,0,12,77,7,341,197,37,51,102,351,269,854,95,17,202,31,9,752,901,44,165,117,48,318,153,291,134,137,115,365,237,196,372,59,498,260,349,450,14,128,90,36,317,244,899,22,342,922,437,125,143,873,453,16,160,72,105,482,179,817,19,89,401,457,57,661,403,523,177,164,45,308,864,373,253,245,8,898,49,421,569,223,76,719,28,61,18,247,139,56,96,27,490,210,468,111,494,475,144,38,961,391,304,25 }, +{ 1,2,50,46,14,67,103,38,24,83,133,29,52,96,75,28,114,5,36,238,65,54,108,171,70,0,58,18,69,181,160,532,236,7,22,412,433,754,283,55,163,220,480,361,487,124,12,223,545,45,328,394,21,398,16,155,9,366,48,35,956,6,154,87,323,646,309,514,112,186,822,137,17,109,149,418,745,175,547,86,37,285,68,800,866,10,429,732,516,25,208,302,51,32,118,334,281,99,531,71,61,194,537,458,23,891,389,19,151,675,409,336,128,168,13,400,307,95,262,832,227,49,273,420,3,115,484,64 }, +{ 258,276,860,201,843,295,137,160,567,116,261,144,268,943,284,202,187,935,662,203,699,131,219,224,44,141,127,36,326,96,98,31,318,269,244,964,23,93,384,489,55,21,434,332,13,403,51,120,1,617,918,352,908,367,110,206,180,365,254,197,492,473,871,442,48,82,10,143,800,260,39,574,28,944,299,940,282,253,9,115,494,418,341,125,855,77,8,49,128,836,535,165,100,576,30,523,385,105,822,217,395,959,564,22,531,911,37,83,393,851,717,64,817,752,421,716,5,317,901,551,373,859,0,170,291,599,533,251 }, +{ 7,2,14,87,46,52,278,92,16,140,75,29,135,294,262,70,38,35,172,171,409,24,60,58,69,5,97,112,66,314,1,163,571,71,50,461,155,267,232,330,18,220,54,334,357,126,380,307,21,74,12,230,48,309,186,675,32,37,298,331,226,246,151,45,774,107,64,337,25,324,6,67,606,189,622,20,448,150,43,61,0,400,22,849,287,10,68,9,86,563,28,95,227,583,192,394,620,103,36,764,572,108,128,335,83,55,587,550,13,145,600,549,536,65,141,852,366,49,415,90,26,236,526,950,17,4,181,72 }, +{ 13,23,51,115,2,33,77,0,1,10,4,7,217,5,9,141,102,6,3,180,11,40,317,22,15,64,14,197,352,202,16,12,341,269,365,165,18,318,177,17,59,153,453,196,752,291,32,117,308,237,125,403,31,128,8,36,401,24,28,349,372,49,498,137,475,247,95,304,143,569,901,21,98,468,457,134,44,139,19,90,421,86,210,120,386,629,93,37,116,482,494,57,110,873,342,55,961,275,111,391,546,35,509,244,203,30,27,99,29,437,48,20,260,65,719,216,734,25,38,54,450,326,50,351,46,864,105,253 }, +{ 74,145,204,66,138,42,25,6,337,174,525,222,192,29,26,544,746,287,415,632,85,609,135,7,353,280,112,580,87,396,712,355,64,122,81,104,2,45,173,673,416,648,172,43,792,226,52,22,97,651,151,194,70,65,0,19,32,20,715,95,825,348,5,624,233,113,86,635,91,879,294,10,644,235,1,90,500,36,573,560,49,636,243,58,63,21,331,426,61,75,389,27,445,14,69,750,28,289,46,38,17,888,311,312,18,24,140,186,76,283,141,12,874,16,232,278,72,461,707,53,4,526,597,255,665,180,114,881 }, +{ 77,217,33,102,317,291,202,23,13,51,141,15,275,269,318,115,342,180,21,4,196,352,64,128,11,494,32,5,137,403,40,2,0,125,3,177,10,98,365,349,12,7,372,6,341,453,165,197,153,475,48,752,22,237,31,117,9,95,59,93,16,90,120,247,308,450,49,221,244,36,28,18,144,86,14,134,326,421,203,44,17,304,24,116,523,260,110,864,210,498,401,901,1,35,241,386,82,127,817,39,72,437,160,105,65,143,730,719,351,216,457,402,30,350,293,164,37,859,96,367,139,284,19,579,576,391,285,373 }, +{ 187,258,871,219,442,574,908,839,926,160,116,44,137,224,276,201,36,860,131,202,613,228,144,531,406,93,31,902,567,385,843,318,203,268,800,98,662,856,494,23,190,120,127,418,30,295,533,836,1,284,96,822,244,64,944,717,86,851,55,13,21,51,22,840,434,269,251,367,489,326,48,110,141,699,816,260,39,384,261,371,473,83,206,254,859,10,669,492,28,317,373,128,49,365,450,77,180,863,559,530,82,829,341,918,253,32,9,197,125,351,332,165,143,943,728,535,67,831,576,855,940,403,217,716,105,274,69,959 }, +{ 1,372,23,5,141,21,744,13,291,77,225,349,144,48,459,96,839,260,304,269,442,335,691,352,32,30,622,203,303,284,330,64,45,521,180,317,217,160,88,752,418,120,93,190,948,166,954,340,919,686,342,244,228,202,201,189,137,110,321,914,411,447,781,772,254,51,765,31,656,264,237,167,724,478,842,437,274,127,125,69,44,662,466,435,351,326,82,9,897,410,253,716,286,678,479,299,238,197,68,7,2,934,223,100,70,58,154,98,682,393,967,960,922,856,805,762,475,402,365,341,336,285,247,221,177,169,163,131 }, +{ 66,222,74,135,87,29,145,2,337,294,52,172,138,331,6,7,25,226,42,97,632,70,192,112,353,609,525,415,461,204,287,500,26,174,75,43,324,1,58,32,220,5,232,544,580,85,620,635,278,45,746,64,426,568,448,396,262,122,173,151,69,20,95,19,61,526,140,65,889,86,307,14,104,280,21,46,81,355,92,38,872,22,387,651,186,648,113,194,416,72,163,673,90,24,35,155,49,16,330,37,792,0,888,243,17,36,76,861,10,48,849,67,644,227,50,4,89,853,334,63,27,314,312,12,825,712,91,298 }, +{ 45,17,106,209,255,119,186,5,263,207,454,29,2,48,425,243,21,496,62,290,3,270,400,408,52,155,136,659,171,14,56,513,50,80,84,32,378,46,61,655,666,742,221,58,383,38,1,54,311,306,240,721,181,440,502,430,334,129,72,536,227,123,76,790,592,214,89,328,281,555,34,787,241,148,64,215,663,287,587,37,11,405,162,27,237,504,57,90,130,152,541,179,12,211,548,41,36,552,184,4,741,115,431,292,449,869,229,96,77,507,223,128,183,40,7,86,51,249,205,245,161,6,738,236,103,151,59,10 }, +{ 213,88,260,120,93,373,141,30,100,450,166,36,372,321,459,473,264,180,110,326,1,225,144,704,717,351,82,855,530,269,466,352,217,265,190,22,274,131,96,539,165,86,457,291,28,244,64,187,318,752,39,349,661,330,9,160,202,219,77,410,197,44,908,254,116,49,137,968,276,317,125,406,31,521,523,435,15,98,228,128,32,299,35,662,293,143,115,21,934,778,224,33,856,923,876,854,689,403,371,341,10,935,851,498,437,8,922,48,642,776,903,839,836,730,613,365,268,242,55,0,944,899,492,898,615,385,304,285 }, +{ 266,57,152,381,471,313,369,99,229,12,339,62,157,77,4,37,188,40,475,162,38,3,452,775,129,184,403,17,59,128,11,432,202,111,453,33,56,183,291,401,216,361,328,102,136,402,79,54,440,14,139,880,123,494,51,23,514,277,507,130,757,474,377,21,94,529,177,548,421,349,64,76,211,90,117,89,72,308,13,318,383,5,141,210,134,556,342,153,305,497,257,555,119,485,84,269,275,106,670,2,115,477,488,45,196,41,300,205,32,542,10,543,304,431,86,180,504,19,27,82,179,36,629,249,46,50,237,245 }, +{ 352,217,317,141,752,372,365,180,341,15,349,77,864,21,291,244,115,13,120,269,1,498,5,901,579,98,144,64,23,48,482,351,51,237,102,201,82,437,125,137,318,4,2,247,202,0,31,854,203,143,253,260,32,177,160,490,10,96,110,44,22,494,251,33,128,403,9,3,898,717,164,28,197,72,93,11,873,450,36,165,386,95,373,6,223,661,30,12,49,922,342,206,523,16,457,127,109,468,308,391,116,531,332,473,187,39,88,35,730,453,326,221,7,719,69,86,105,100,83,851,475,90,350,230,678,421,101,304 }, +{ 14,514,369,880,102,403,377,51,719,485,153,23,453,401,457,11,40,13,328,12,57,4,33,38,629,236,670,54,730,117,111,361,961,59,37,134,99,758,757,165,2,46,386,412,421,391,277,29,308,543,477,494,188,600,6,196,21,542,197,139,300,739,475,52,899,79,509,523,488,775,583,283,231,7,803,552,32,5,402,89,828,3,507,176,77,50,15,155,211,64,17,569,215,115,18,381,237,305,266,202,90,34,342,194,128,62,555,389,242,125,108,65,0,471,338,136,56,548,506,221,181,133,10,440,114,248,95,1 }, +{ 107,172,7,359,126,92,14,135,314,278,60,150,298,46,392,279,232,192,2,441,356,330,357,16,32,380,97,534,423,581,35,526,38,448,493,132,52,288,246,660,5,121,66,24,230,324,572,21,387,226,462,259,247,95,220,146,140,77,18,508,147,262,90,48,312,707,20,71,603,54,33,195,550,362,86,236,108,739,199,830,23,64,43,29,895,802,451,22,36,28,929,294,606,50,87,70,501,13,808,177,55,1,194,178,711,316,4,0,102,590,366,49,893,600,37,582,309,872,267,117,388,241,620,115,786,939,571,360 }, +{ 59,4,90,45,216,13,25,0,177,23,77,51,27,95,72,26,115,65,12,91,210,123,275,37,389,19,102,33,11,49,22,18,194,5,214,21,85,53,48,202,343,291,31,57,6,128,42,746,93,73,58,44,32,196,283,81,319,61,141,249,153,64,138,117,422,355,40,348,139,403,789,145,788,300,247,240,134,74,34,804,619,370,104,86,38,1,304,180,524,494,217,20,597,544,318,352,323,233,174,114,76,17,475,280,204,588,342,285,14,3,43,725,287,7,888,636,235,52,29,63,337,232,122,784,125,397,817,678 }, +{ 5,315,416,49,455,639,202,350,77,408,21,197,137,450,402,13,61,509,329,113,713,344,569,347,401,48,0,841,494,318,734,749,64,70,308,95,903,120,342,884,237,557,32,194,546,115,845,1,23,165,663,128,873,102,291,518,22,58,817,391,498,263,17,33,221,269,403,923,260,105,241,125,51,196,312,39,10,31,153,234,112,523,158,18,4,265,12,141,9,159,928,623,326,207,25,177,310,3,2,859,98,28,65,30,163,11,19,275,491,290,6,117,541,16,15,124,76,72,27,922,210,44,341,349,134,773,147,24 }, +{ 130,47,381,390,59,90,200,472,214,714,65,289,6,122,874,85,64,29,751,648,52,50,74,875,247,194,624,249,288,26,312,437,32,217,630,881,4,123,95,78,835,352,196,665,519,33,57,711,524,954,108,42,19,77,22,153,597,416,412,0,145,444,27,243,25,14,183,304,117,453,51,256,141,730,102,177,134,236,315,680,86,112,34,11,115,235,287,237,113,45,283,151,317,588,579,99,3,752,216,342,813,128,445,864,180,56,46,28,18,73,12,23,114,13,389,53,644,719,21,396,58,17,372,947,137,316,10,250 }, +{ 51,453,23,719,13,730,165,457,37,197,99,12,386,401,475,961,4,17,11,64,59,308,54,115,57,38,328,758,391,6,5,2,899,3,753,403,32,523,670,10,509,40,33,421,629,120,21,65,19,22,0,202,125,95,569,117,90,558,29,26,514,494,1,775,128,134,14,450,361,34,9,86,194,177,350,269,72,27,25,7,880,757,111,62,153,316,236,141,50,56,260,217,196,867,546,161,130,106,77,48,41,31,16,8,317,152,468,242,221,136,734,80,89,968,949,862,814,801,717,704,495,469,440,428,412,383,378,326 }, +{ 15,13,1,5,23,2,7,0,6,3,12,51,4,180,115,21,9,165,457,197,141,352,11,14,202,217,10,37,8,32,341,120,22,117,752,269,16,77,134,961,901,719,318,48,317,365,33,110,93,31,569,18,102,28,40,260,17,509,128,44,153,137,82,498,59,629,351,72,386,403,36,49,401,453,730,308,196,450,89,873,30,523,125,99,391,326,177,98,64,247,494,854,24,291,95,475,38,86,482,39,203,922,372,349,116,90,144,57,35,758,55,864,221,468,244,210,421,139,817,76,373,899,54,105,19,304,342,96 }, +{ 0,9,35,28,68,24,67,65,1,16,18,114,69,103,50,101,149,22,175,124,55,39,12,218,133,96,154,189,5,83,21,71,23,7,336,433,251,13,49,75,118,335,2,51,48,486,30,14,10,283,181,745,115,223,137,54,230,109,418,37,345,64,128,141,108,281,99,36,60,100,202,956,537,163,532,480,221,766,302,596,487,95,252,346,58,158,46,180,217,361,237,70,398,86,269,160,31,32,105,657,443,140,285,125,87,212,166,167,502,6,88,375,165,323,831,317,754,29,318,439,77,98,364,38,197,429,44,765 }, +{ 28,105,22,320,109,49,301,0,9,170,95,1,35,55,127,65,24,168,98,159,713,16,512,31,395,36,623,2,7,293,740,14,338,347,424,185,286,12,44,23,21,169,124,5,158,68,67,928,13,371,18,299,242,125,51,289,175,916,64,761,479,374,39,737,685,154,48,272,6,114,599,116,10,86,141,37,194,83,149,506,327,312,841,202,763,237,50,900,870,538,284,115,131,420,346,137,654,385,456,165,187,762,30,276,239,32,308,69,143,269,429,96,570,71,128,180,933,160,164,46,197,221,401,634,965,219,101,318 }, +{ 77,13,51,102,4,59,23,33,202,210,115,40,403,177,128,196,141,153,117,64,494,269,318,134,475,217,342,0,291,11,90,453,22,402,137,15,216,139,10,180,275,86,95,65,57,6,36,18,523,1,125,21,317,365,197,49,28,421,32,14,352,25,19,7,2,899,730,719,391,341,152,24,401,48,27,17,12,901,247,123,114,16,9,111,99,26,349,285,576,50,20,3,386,372,326,260,194,120,110,351,283,482,293,242,165,96,29,37,30,817,801,498,457,450,393,373,299,237,214,203,615,569,116,93,34,82,958,805 }, +{ 13,23,77,51,33,141,115,102,0,217,10,2,6,4,7,64,22,1,11,177,180,40,3,14,202,269,9,291,352,15,165,197,17,128,317,153,196,5,318,18,372,117,16,28,59,36,19,137,95,210,237,247,125,49,86,349,341,304,134,365,24,275,12,31,27,453,403,752,25,143,308,26,57,20,901,120,475,44,401,457,29,498,90,139,65,8,391,93,342,494,216,509,164,98,99,35,55,386,244,111,32,45,37,21,260,38,110,56,450,105,39,730,402,523,46,437,82,30,719,569,203,961,873,326,285,194,116,421 }, +{ 456,116,492,268,949,867,203,51,719,8,391,918,791,457,730,499,13,386,23,206,685,125,31,551,170,870,93,417,401,10,22,479,506,338,940,44,509,143,64,692,670,558,453,0,473,197,523,758,629,341,165,1,564,55,899,762,308,961,421,959,36,638,115,569,801,180,642,86,299,164,28,37,141,965,498,559,9,5,120,237,95,546,260,873,599,137,253,12,244,903,901,2,817,752,728,128,352,450,105,202,7,615,127,365,958,21,301,49,951,403,740,326,239,898,373,922,475,6,854,242,15,3,318,4,269,98,65,99 }, +{ 17,237,106,62,180,45,136,32,498,64,115,41,255,129,546,752,864,197,21,227,241,490,352,482,57,123,292,350,247,509,449,162,365,468,214,38,23,13,4,476,148,76,437,155,507,141,165,77,3,720,317,290,270,873,211,164,72,153,209,117,5,659,54,48,249,217,341,186,710,33,40,14,12,496,119,11,519,90,183,618,139,179,37,328,579,221,431,248,372,405,130,59,99,400,263,205,425,2,358,349,901,51,177,171,89,428,50,454,304,207,542,1,457,308,734,721,391,316,29,569,94,243,143,339,196,313,128,111 }, +{ 1,5,180,15,2,4,0,352,3,13,901,341,7,752,6,141,217,23,365,317,115,197,21,51,165,269,12,11,9,202,31,33,77,569,44,93,318,137,110,120,36,10,22,372,260,498,116,64,32,873,125,48,102,308,8,349,98,482,291,386,401,14,373,326,28,237,37,55,86,134,203,457,391,16,117,177,253,144,509,421,127,153,40,206,403,961,864,468,221,494,437,453,18,17,196,304,143,128,96,854,450,72,247,35,579,89,642,758,82,342,160,629,719,282,811,59,351,922,730,95,638,523,210,546,332,661,49,734 }, +{ 141,205,497,216,269,152,588,59,452,128,4,76,352,875,188,77,79,11,94,678,947,339,954,217,471,372,90,529,72,318,247,64,32,89,177,12,288,37,1,304,349,202,5,51,291,33,474,102,111,23,115,21,99,179,864,38,148,377,13,460,431,498,437,316,180,2,961,40,358,542,137,490,405,241,464,317,3,45,54,7,184,196,17,10,402,752,245,342,210,14,873,48,143,285,153,257,197,308,292,0,36,569,769,237,134,482,139,275,165,468,341,629,413,734,86,476,365,6,300,851,117,751,494,401,270,229,453,29 }, +{ 247,64,317,217,237,437,180,498,349,115,752,579,304,372,864,482,291,141,352,468,197,177,13,391,164,490,23,546,33,365,77,153,72,216,954,597,277,10,708,269,134,569,275,51,695,509,318,179,0,678,244,140,312,640,117,76,629,196,751,128,36,953,674,260,102,901,32,21,22,225,401,86,717,143,92,873,351,16,133,114,191,386,253,165,69,59,9,458,341,202,149,82,649,35,453,398,166,100,95,93,90,125,15,373,330,923,316,48,854,586,213,486,230,922,5,411,823,734,189,139,103,65,50,24,18,12,830,167 }, +{ 2,1,5,7,6,3,77,0,141,13,180,15,217,64,33,23,102,10,352,14,117,9,11,197,165,40,269,17,291,4,115,134,12,153,341,317,752,372,237,51,349,22,498,202,318,16,457,128,196,36,177,365,32,21,59,19,125,901,342,8,86,120,139,93,45,961,57,95,38,143,509,28,29,391,111,210,27,260,873,244,82,137,18,386,164,37,719,25,48,31,304,49,864,98,402,275,569,110,351,629,253,546,26,41,90,494,50,730,56,523,453,44,54,144,24,99,30,403,678,76,898,450,437,55,954,482,308,277 }, +{ 11,40,38,328,542,33,339,313,12,377,157,775,485,99,51,471,41,369,23,37,475,57,54,457,14,117,13,188,305,629,102,403,79,4,139,514,880,961,111,266,719,152,248,474,134,453,401,153,211,342,477,21,2,59,361,89,587,277,94,29,308,196,64,32,413,77,229,210,184,215,402,128,431,381,46,670,5,247,197,165,556,757,386,115,300,50,17,391,803,494,875,490,730,177,162,450,421,275,202,0,6,1,257,76,72,65,48,19,10,129,569,236,130,15,7,555,901,898,588,86,9,543,488,90,452,749,619,507 }, +{ 77,102,33,196,40,51,202,23,153,128,117,13,342,64,134,141,4,59,0,269,210,177,22,318,137,403,65,86,10,475,139,453,95,115,28,99,11,165,217,36,180,197,49,402,291,125,1,352,18,15,494,421,194,275,31,300,110,120,57,90,93,12,237,401,317,6,457,14,2,82,24,114,260,9,386,44,285,108,361,98,16,7,21,349,326,216,5,116,730,341,372,19,133,719,203,48,32,391,39,25,143,111,105,67,576,752,670,961,899,308,498,37,351,304,20,30,283,901,523,365,27,244,208,55,3,164,485,8 }, +{ 472,34,80,495,250,469,176,389,527,17,14,161,53,231,4,128,56,283,216,106,84,57,27,483,177,59,119,503,436,45,585,297,194,29,378,3,42,62,269,136,26,40,11,2,862,678,619,33,73,236,255,514,719,200,25,6,64,240,179,141,52,102,789,361,618,129,597,5,153,611,349,205,65,245,803,402,210,457,123,383,90,304,667,318,814,504,328,133,130,51,32,48,684,108,714,412,215,13,139,19,95,77,47,275,99,12,311,211,165,1,432,207,322,196,117,61,23,524,152,115,369,183,134,114,573,54,162,46 }, +{ 752,352,317,180,141,217,365,269,244,341,498,115,253,901,1,372,202,21,318,4,5,23,700,717,13,137,2,349,197,864,10,873,143,7,482,0,51,3,64,11,67,308,531,12,8,6,28,237,22,31,468,579,533,291,160,221,35,30,96,48,55,33,9,961,120,49,44,39,32,247,83,69,450,326,260,77,36,98,851,509,165,37,16,457,437,110,93,88,82,14,345,822,765,638,421,219,190,131,128,114,203,144,99,800,401,844,453,125,494,475,373,351,241,206,170,164,148,134,127,116,105,100,86,40,38,18,811,19 }, +{ 9,39,101,265,18,333,520,329,100,593,553,364,310,252,167,16,68,604,0,363,404,118,166,121,254,158,272,24,60,271,212,286,639,327,159,35,146,1,109,30,455,411,793,105,557,49,132,647,31,71,621,21,656,354,438,627,676,688,98,48,682,28,156,538,190,22,5,55,23,195,65,44,848,264,51,446,857,709,127,374,781,447,191,344,865,625,821,13,124,96,93,7,578,125,419,907,360,463,32,116,126,37,274,777,88,731,108,67,154,92,95,36,199,12,137,131,10,562,128,326,664,203,382,50,806,242,921,435 }, +{ 15,1,901,180,2,4,5,3,0,752,7,6,341,13,115,317,365,23,217,141,9,197,352,165,51,21,137,11,36,202,12,33,22,873,308,77,269,10,64,86,498,569,31,372,55,93,40,120,160,44,509,318,349,482,638,8,117,37,116,164,102,32,28,401,110,128,196,144,206,244,153,457,468,951,17,291,16,203,96,260,811,143,373,642,125,134,437,386,546,268,247,177,14,48,758,717,719,391,579,72,421,89,661,629,111,730,559,961,221,59,403,523,304,851,35,30,169,854,494,127,82,326,450,251,898,417,475,734 }, +{ 131,39,829,166,613,827,716,578,9,100,224,310,406,30,98,616,228,1,254,856,219,438,938,190,31,846,265,931,0,127,96,625,274,924,44,371,101,385,116,252,272,863,51,137,88,21,333,731,557,36,23,404,48,223,125,49,264,160,187,737,242,105,28,258,144,93,13,530,158,944,382,284,395,203,812,593,518,442,5,456,836,128,326,293,68,329,403,35,202,816,77,115,83,909,688,86,890,478,120,64,22,639,16,165,276,393,455,871,410,201,286,299,33,576,960,656,24,217,95,159,110,32,367,421,492,221,55,102 }, +{ 17,64,62,141,106,136,751,292,129,352,41,38,954,86,476,214,217,128,177,32,237,947,180,162,123,209,710,269,519,247,90,864,157,77,318,99,57,76,59,4,437,40,179,358,11,45,618,119,313,5,304,211,597,148,875,23,249,197,130,95,507,37,54,3,216,457,248,58,210,115,288,12,425,678,186,164,328,72,454,339,245,102,80,498,312,165,372,139,155,2,152,56,33,21,655,243,720,183,207,14,29,241,117,266,290,471,137,84,51,188,305,275,205,449,7,263,48,542,13,270,742,171,752,509,61,317,349,369 }, +{ 42,25,235,650,736,65,605,630,233,343,123,256,122,85,26,416,6,389,63,141,249,368,444,194,511,174,544,19,108,597,348,524,138,90,27,183,32,370,304,525,84,56,53,283,789,445,18,78,280,91,130,947,588,619,45,355,17,680,73,4,0,222,112,3,813,119,145,64,678,297,250,80,21,573,523,86,214,216,102,76,11,746,40,33,269,240,29,289,624,177,323,450,57,24,561,77,152,114,184,74,287,28,396,665,648,378,372,137,37,5,390,106,70,22,847,51,49,349,874,47,881,23,817,432,337,243,153,124 }, +{ 184,229,152,432,266,452,57,497,381,619,17,313,471,257,59,129,369,339,4,12,205,99,157,77,3,5,45,128,123,106,62,202,162,32,21,216,40,136,11,188,119,249,402,349,2,403,14,37,38,54,64,291,618,524,102,475,76,177,80,90,214,33,79,141,453,23,210,111,245,372,137,27,318,269,217,494,775,86,94,139,10,1,19,115,51,401,56,769,183,361,84,529,474,277,757,72,48,880,6,247,29,209,710,179,377,89,41,292,285,328,13,588,180,342,130,556,36,477,308,275,460,378,61,197,196,0,165,421 }, +{ 137,202,160,131,860,567,318,36,295,141,843,39,800,93,30,105,187,224,276,201,261,943,964,98,49,269,219,851,116,9,22,473,1,352,203,127,822,100,206,699,144,268,662,244,253,10,717,535,332,120,44,258,143,31,64,450,704,96,859,190,180,115,55,365,531,326,95,217,28,110,564,752,86,373,284,228,317,21,77,341,13,48,434,221,197,51,911,940,159,23,384,533,260,494,559,935,291,901,88,109,574,282,128,442,367,308,959,617,5,83,489,299,251,728,170,164,165,177,492,406,926,417,293,401,349,871,125,968 }, +{ 125,64,493,0,49,165,35,293,55,93,18,98,9,325,68,10,279,137,31,48,453,389,194,197,147,13,788,14,132,95,107,77,391,371,342,174,61,43,581,105,28,22,5,259,319,104,758,671,590,128,44,32,20,767,761,457,146,121,725,465,198,126,757,289,116,100,23,21,110,763,612,12,663,199,142,120,102,101,7,427,4,356,37,941,963,867,848,498,156,88,86,58,51,33,690,558,376,180,2,864,163,955,70,623,804,422,657,202,1,40,534,90,649,470,798,522,392,352,945,502,386,359,237,221,203,177,159,144 }, +{ 15,33,4,77,13,102,23,40,32,5,11,349,51,177,21,141,117,93,202,59,110,153,64,291,318,196,31,217,269,115,10,180,82,137,1,8,44,3,98,125,134,0,165,22,12,128,351,17,95,116,2,304,120,139,403,457,210,197,49,341,453,144,372,450,494,86,48,352,386,523,36,90,719,898,6,275,30,365,57,730,28,9,317,247,326,854,76,373,475,7,72,37,421,817,638,901,401,111,961,342,899,216,402,277,260,18,237,758,569,203,99,629,437,535,39,61,16,96,752,14,300,208,922,704,105,83,308,143 }, +{ 110,854,253,811,352,141,951,661,244,642,180,752,143,498,384,269,559,317,922,10,911,160,351,533,365,373,206,902,638,873,332,261,345,260,137,717,116,843,31,417,120,44,959,531,217,341,535,201,125,36,699,860,82,55,564,434,926,318,268,940,197,901,164,574,864,276,251,824,295,876,127,450,64,617,943,93,258,776,15,282,326,165,546,817,855,851,203,96,187,144,728,83,1,372,601,219,224,762,237,284,509,21,170,169,499,98,391,479,115,768,482,473,406,86,898,662,349,48,202,131,51,5,0,896,871,401,238,228 }, +{ 2,29,70,75,220,52,112,331,145,1,163,26,74,324,6,69,58,307,19,409,278,287,38,226,46,223,394,87,25,294,606,50,66,14,632,135,583,151,42,67,45,27,396,357,171,380,675,138,5,21,113,267,262,97,24,7,309,764,635,53,537,222,103,48,335,500,83,32,122,16,550,186,96,17,73,334,849,155,189,644,852,802,37,61,54,64,571,140,35,12,582,651,461,486,853,108,36,80,18,133,451,315,624,65,337,785,573,366,445,72,86,774,92,89,297,400,10,114,95,416,587,648,462,172,71,600,820,238 }, +{ 23,13,77,51,115,177,64,141,33,102,4,217,202,40,128,269,291,59,0,180,10,2,6,7,318,11,196,14,137,90,32,22,95,153,352,210,9,1,117,15,165,16,197,49,3,125,86,237,349,18,403,216,19,17,247,21,317,304,342,24,341,134,475,453,12,275,25,36,28,20,98,494,372,57,31,93,65,44,110,27,26,120,139,365,752,111,37,35,326,164,116,402,901,260,457,30,288,421,105,56,498,29,144,391,82,203,5,401,308,285,719,386,99,143,48,39,351,55,194,437,312,450,96,523,76,509,244,316 }, +{ 340,897,691,478,914,658,724,382,363,812,698,682,100,156,166,521,264,447,909,411,1,404,88,354,303,438,96,296,274,772,39,656,418,921,9,30,410,144,23,744,848,639,664,435,21,586,919,13,271,31,335,254,51,5,850,98,367,225,960,77,203,759,621,190,48,127,676,120,32,668,33,83,4,67,44,36,272,217,69,291,131,284,286,360,821,101,285,116,242,18,223,686,102,265,905,842,317,329,93,68,82,822,195,128,125,576,692,351,103,64,238,115,652,475,349,765,326,141,966,578,110,118,0,260,403,201,163,105 }, +{ 310,18,9,326,265,252,121,51,159,77,195,105,101,120,363,33,24,354,271,102,272,709,167,98,16,13,132,639,23,158,260,55,333,327,704,450,35,170,60,202,49,557,125,93,411,254,1,364,95,455,146,817,28,520,338,494,7,286,137,156,109,39,21,14,48,128,116,64,40,31,859,320,118,212,141,360,890,318,293,4,523,615,269,576,169,20,165,153,75,196,329,373,210,177,92,69,0,301,291,781,479,371,217,627,407,403,342,127,71,44,36,910,374,5,50,668,647,351,936,682,578,538,593,553,203,185,180,110 }, +{ 57,313,471,99,369,12,339,157,266,152,38,475,328,453,775,37,403,401,514,40,188,342,139,77,11,59,377,361,229,474,33,4,51,880,277,54,3,211,14,102,62,381,23,111,162,196,130,529,556,305,757,275,128,79,115,629,13,402,421,507,308,485,210,129,123,184,177,494,41,477,153,488,117,542,452,248,300,216,202,236,134,94,670,431,89,64,17,183,440,569,136,555,72,76,734,432,457,543,961,257,215,291,304,10,413,15,205,548,90,56,2,21,46,165,318,247,349,197,86,32,0,283,412,141,36,828,386,82 }, +{ 16,24,35,60,140,71,92,7,14,230,189,108,18,69,46,150,388,246,278,2,172,68,1,451,38,330,135,126,236,309,149,443,50,267,121,565,67,582,21,75,48,462,52,563,594,314,29,399,66,191,877,103,572,55,232,366,97,696,357,380,733,167,83,220,517,5,28,674,74,12,65,0,54,9,118,262,335,146,516,32,37,653,915,22,36,133,251,96,324,87,273,394,64,199,723,223,107,10,486,458,711,13,6,95,163,571,86,726,448,212,641,192,345,70,181,132,23,49,114,550,98,20,271,606,298,633,99,603 }, +{ 206,417,940,959,93,473,728,559,499,203,137,202,8,450,564,31,44,120,269,260,318,141,116,326,244,253,10,127,268,143,22,125,98,817,434,1,373,144,128,615,51,638,23,384,692,523,341,64,922,0,851,13,489,110,352,105,9,951,717,86,28,386,367,403,299,704,642,242,55,551,901,36,958,282,859,160,77,49,291,494,801,968,30,180,492,365,911,661,498,276,854,165,164,873,37,762,456,197,21,317,12,15,5,7,569,285,918,421,752,629,576,479,115,95,2,349,96,401,758,899,393,170,898,217,457,391,48,39 }, +{ 15,1,2,13,0,5,23,7,4,3,6,51,9,217,77,341,115,10,8,11,33,349,12,317,291,180,177,14,102,16,365,120,22,901,304,165,457,21,372,260,197,32,18,40,403,453,31,202,82,961,719,475,28,247,523,117,450,64,93,141,730,110,30,352,351,752,569,44,401,153,17,386,196,59,308,24,134,36,854,494,318,899,48,137,342,326,125,629,90,49,128,437,37,817,95,275,922,421,498,758,98,210,111,203,99,237,391,116,216,57,482,144,373,39,35,20,19,468,139,615,55,221,288,898,873,509,244,86 }, +{ 2,1,14,5,50,48,46,290,21,45,29,32,263,155,207,52,38,425,171,76,408,72,449,17,292,227,89,58,513,400,428,119,476,7,61,54,67,720,75,241,243,186,502,655,69,221,36,148,24,96,6,306,3,214,106,37,0,103,223,10,179,281,16,83,350,64,90,129,430,464,181,663,666,22,413,405,18,240,710,84,262,790,123,431,28,12,741,163,115,460,255,536,56,128,35,334,141,9,220,65,205,51,86,659,99,249,23,541,95,245,618,209,519,202,70,592,270,237,528,62,27,217,133,4,394,137,114,675 }, +{ 132,121,354,167,146,463,271,195,668,446,98,223,407,360,18,212,522,447,1,781,60,48,591,411,156,562,586,363,664,21,777,393,199,293,125,807,936,9,23,590,163,16,13,658,5,126,541,55,101,941,107,259,621,191,51,834,786,68,647,765,31,150,929,759,284,35,71,49,24,465,221,118,520,7,92,883,116,608,279,727,535,70,96,44,687,478,105,50,346,697,467,963,281,33,10,566,22,581,626,93,77,296,493,4,102,108,115,640,147,75,39,770,87,32,914,127,144,598,178,0,117,273,12,2,37,783,691,932 }, +{ 131,578,371,219,224,716,105,616,737,385,187,761,258,916,254,159,49,910,9,623,98,127,836,924,272,286,442,39,28,688,890,320,627,518,293,0,944,871,574,242,31,395,22,201,327,44,116,158,276,109,908,301,860,284,36,51,23,137,95,926,713,512,30,160,125,333,170,239,96,21,456,347,228,13,86,64,128,1,68,101,839,202,506,424,295,662,938,144,55,168,24,567,48,843,406,83,65,185,613,438,203,268,35,165,492,244,299,902,221,384,16,141,115,166,827,93,10,829,37,364,763,261,169,269,5,656,434,685 }, +{ 302,467,484,97,453,6,398,124,69,36,51,14,421,298,1,66,273,87,74,523,81,426,2,403,67,168,18,386,886,756,701,801,158,13,65,0,26,23,475,24,758,86,22,108,719,25,547,615,401,159,117,423,150,730,847,563,154,75,19,646,29,7,505,817,189,278,457,165,42,458,717,572,267,138,782,531,429,153,135,450,134,49,700,208,958,671,715,622,336,244,172,143,114,95,85,63,60,52,650,197,46,899,140,92,160,28,10,791,885,718,327,314,12,5,610,109,43,703,673,670,370,341,326,289,38,35,805,879 }, +{ 190,30,778,530,539,88,100,625,382,1,960,410,731,274,96,840,957,435,321,795,748,264,669,438,466,39,166,131,36,418,144,265,9,44,228,213,23,219,224,921,223,160,406,251,31,863,83,98,310,116,21,613,13,557,203,51,128,0,252,367,335,137,254,5,924,521,284,352,829,48,765,856,258,475,827,69,201,93,49,909,404,716,238,101,616,822,33,421,32,456,593,217,125,127,944,752,67,286,276,679,931,831,329,403,816,158,77,812,221,772,317,639,37,35,28,242,120,268,578,50,230,966,686,494,187,551,478,285 }, +{ 141,202,128,2,269,1,64,5,180,3,318,33,197,6,352,15,7,102,77,0,134,13,137,10,196,153,165,120,117,14,17,11,12,82,110,4,9,237,23,291,260,494,93,51,403,217,21,498,752,450,342,341,31,32,351,22,326,125,402,457,317,143,86,36,115,19,203,40,111,961,285,16,48,475,98,116,44,678,365,95,8,37,57,28,244,27,18,901,49,45,864,569,349,373,386,391,453,59,523,144,719,139,509,25,854,372,38,24,56,898,194,164,947,79,29,817,94,253,99,873,954,730,55,65,597,61,26,546 }, +{ 44,201,567,489,116,662,224,268,131,219,434,295,187,144,31,276,699,384,137,110,442,258,36,160,228,261,367,613,93,30,64,120,908,244,284,203,260,141,202,385,1,9,269,940,39,855,253,918,98,96,373,22,406,856,326,105,206,143,318,10,217,127,55,523,115,77,125,717,617,86,49,13,836,51,28,23,574,332,128,83,190,180,871,839,371,393,944,352,317,21,164,473,935,197,450,341,959,0,177,911,840,254,531,165,291,716,418,899,800,88,829,282,827,494,48,492,661,854,5,351,100,82,299,851,822,15,860,365 }, +{ 51,12,23,15,99,37,13,10,453,165,117,38,0,197,629,569,82,115,401,120,64,134,22,474,457,11,110,719,31,93,260,9,14,475,111,32,153,79,1,94,21,40,308,128,125,8,28,5,18,54,403,351,3,44,180,202,89,450,328,33,961,2,139,36,4,49,77,45,141,523,326,386,730,48,17,217,30,431,148,405,317,237,29,98,16,341,775,413,196,365,352,55,318,72,758,116,6,59,24,7,477,898,734,509,58,39,203,95,372,482,86,854,19,391,421,402,269,144,494,90,102,291,922,817,57,373,899,27 }, +{ 135,7,172,2,92,140,66,52,97,74,324,14,226,29,232,46,38,380,87,262,314,357,278,330,16,298,571,448,35,126,60,220,620,606,75,6,24,192,107,69,246,230,331,1,5,267,294,70,622,353,222,853,550,563,71,572,583,138,150,600,189,500,25,43,50,309,21,526,32,872,12,174,54,58,37,20,893,802,22,48,145,86,64,580,462,95,67,18,888,42,950,65,387,36,171,108,451,112,10,501,26,726,335,441,103,785,83,359,204,582,279,337,461,49,0,72,423,45,443,409,61,68,356,28,392,163,673,114 }, +{ 125,386,391,23,963,60,51,949,165,221,21,13,541,393,118,719,150,197,326,758,421,791,517,801,566,558,308,48,362,7,834,670,453,551,173,401,203,102,43,20,5,71,36,457,251,77,697,279,140,867,33,126,115,32,92,149,422,743,367,232,193,0,770,4,98,509,40,674,81,18,341,11,783,192,577,546,397,16,494,510,508,217,189,104,705,610,330,2,596,105,823,293,202,117,10,314,796,64,862,629,475,468,281,246,242,38,403,29,474,298,31,27,14,858,414,95,942,779,773,569,523,430,317,301,172,134,116,91 }, +{ 85,6,42,138,235,25,222,174,525,256,746,26,289,64,280,214,544,65,32,337,90,204,355,348,74,312,95,415,145,122,233,609,416,66,194,19,29,630,835,63,22,87,45,237,874,5,605,353,112,86,519,343,135,17,648,76,736,70,287,249,180,681,0,288,21,580,27,123,444,4,226,192,52,247,81,1,56,751,216,78,58,75,49,91,792,23,48,53,183,396,108,59,61,28,3,636,624,2,208,84,370,368,12,207,37,114,10,151,153,389,197,172,51,673,72,33,671,597,18,115,125,31,730,573,179,141,73,250 }, +{ 1,14,50,24,5,67,46,2,69,103,18,54,58,48,16,38,83,96,0,35,28,502,21,36,45,181,155,12,61,7,223,513,430,22,270,65,108,9,75,10,37,133,540,29,32,290,71,52,17,171,238,114,218,72,236,55,99,309,807,70,149,328,89,433,163,227,834,68,64,23,189,51,666,6,766,765,221,115,474,86,60,366,552,541,488,13,487,243,425,95,592,536,76,780,141,477,767,186,128,663,267,251,3,794,49,741,137,418,263,202,160,207,545,27,543,920,335,428,388,408,400,150,760,148,124,106,19,269 }, +{ 811,351,642,951,180,752,110,638,253,10,352,854,197,82,365,564,873,341,499,55,143,244,535,36,498,559,901,417,22,661,141,9,28,282,165,30,206,898,373,35,509,260,115,922,728,8,39,332,49,317,31,44,762,964,93,15,911,533,203,160,1,217,120,391,137,24,116,33,105,102,479,943,77,569,717,338,134,117,968,125,965,164,64,473,127,196,153,531,384,269,601,308,98,37,959,23,177,13,867,109,617,291,864,482,169,21,372,242,546,843,434,824,692,40,32,4,551,299,758,5,468,11,629,903,12,89,949,791 }, +{ 51,23,13,453,403,12,475,115,4,15,165,202,523,719,21,457,386,99,308,37,401,2,730,5,197,32,494,0,33,1,120,450,10,59,102,128,17,14,117,3,961,77,153,9,217,569,11,196,134,899,421,40,318,391,247,90,6,629,64,7,16,57,210,48,341,177,141,269,38,260,402,180,22,468,29,27,758,317,291,817,25,19,72,18,56,361,326,133,304,54,221,757,236,34,26,288,300,275,670,365,514,509,125,237,36,65,139,137,108,45,76,52,28,498,351,801,82,805,576,114,89,61,352,41,615,24,8,854 }, +{ 120,13,23,141,77,51,260,217,202,326,1,137,291,269,93,102,82,21,203,450,351,15,180,110,165,318,352,5,128,177,373,48,854,197,64,922,523,317,96,36,349,32,0,386,372,144,33,2,9,125,752,115,59,12,210,7,457,16,817,90,403,244,367,14,898,237,160,28,35,342,719,6,275,10,18,494,304,37,30,341,50,39,24,498,730,365,391,22,473,901,4,86,223,285,247,116,31,704,453,678,83,221,661,216,44,69,61,615,201,421,65,402,8,475,268,401,11,468,49,29,98,88,899,300,242,68,3,418 }, +{ 1,5,22,12,0,2,36,21,28,48,10,14,86,32,54,50,37,7,49,9,23,65,51,55,202,96,95,13,24,208,128,3,137,323,67,17,6,99,4,16,168,18,38,194,83,115,114,281,58,45,64,318,141,745,402,46,269,31,160,480,77,103,503,105,11,403,164,69,35,218,181,72,133,29,822,433,735,430,75,180,223,89,109,584,244,341,197,361,289,165,657,169,401,239,757,177,389,98,124,217,851,238,159,33,158,956,30,59,143,70,102,39,308,44,494,754,40,253,90,155,61,766,163,540,221,76,270,756 }, +{ 219,127,98,258,23,308,301,51,910,401,276,616,284,170,395,293,105,165,22,13,327,242,512,125,201,944,115,900,374,320,109,924,964,763,272,239,567,28,860,629,391,131,116,386,55,197,935,453,843,341,9,943,743,365,506,206,457,261,758,295,36,180,670,31,95,237,538,535,662,44,224,456,185,558,332,64,911,479,0,143,169,569,492,634,10,841,317,421,867,338,282,253,49,144,685,740,384,110,901,468,187,734,719,86,417,844,509,268,12,564,141,286,713,762,918,475,299,120,1,578,164,137,159,403,870,168,551,498 }, +{ 64,180,237,5,80,165,61,58,498,250,297,197,186,2,752,864,34,445,95,869,881,17,311,391,231,115,29,151,546,549,3,312,247,483,153,469,45,27,22,365,334,73,26,136,933,62,56,495,32,52,243,215,21,90,472,592,396,509,288,651,48,738,106,53,490,482,161,211,11,316,287,177,13,369,635,378,141,86,262,667,119,663,216,128,179,40,19,209,50,164,719,457,145,23,10,352,176,241,196,527,666,171,833,269,383,125,758,14,46,70,341,507,317,873,579,464,255,400,37,875,405,210,117,33,143,331,84,6 }, +{ 77,13,102,23,64,33,141,2,115,51,1,0,10,7,177,217,6,269,180,40,3,14,202,128,22,15,318,291,196,5,197,165,153,9,117,352,210,4,237,95,17,134,16,11,125,137,86,18,317,139,12,31,93,59,28,36,49,341,24,275,304,19,349,365,110,44,342,143,403,27,120,29,719,752,457,498,164,372,111,45,203,453,82,25,569,391,8,494,216,144,98,21,247,386,475,26,401,402,30,312,37,99,57,65,20,901,38,678,244,116,326,260,56,308,450,32,35,509,300,34,961,597,194,730,48,629,55,351 }, +{ 15,120,450,51,23,13,202,523,153,196,260,457,719,386,326,4,730,128,318,141,21,11,64,403,453,33,77,32,475,269,95,5,494,125,102,165,48,12,98,1,115,2,401,117,116,10,0,180,40,197,817,7,9,308,99,899,3,352,137,90,16,37,6,18,14,237,22,17,59,217,421,402,134,8,291,49,31,961,82,28,177,670,341,351,342,247,61,758,221,194,19,391,30,317,44,93,214,365,24,57,27,20,275,25,241,216,312,285,29,288,65,576,349,629,70,72,26,39,304,498,36,96,569,123,210,46,289,854 }, +{ 2,5,1,29,45,14,58,207,263,425,52,32,46,76,186,72,292,50,7,61,476,655,408,227,48,38,155,21,720,89,17,75,243,119,6,449,171,148,306,70,241,163,106,334,214,592,54,400,36,179,90,64,790,663,24,666,84,3,16,67,69,240,10,464,56,405,496,128,0,710,74,86,270,129,22,290,460,519,255,209,220,18,141,428,223,123,659,205,96,65,19,513,83,37,4,12,27,25,112,103,115,358,66,23,9,202,95,262,249,221,51,151,28,26,767,59,35,77,350,87,137,780,245,40,409,99,237,618 }, +{ 15,4,13,11,5,23,21,32,1,40,141,3,33,2,180,17,197,64,12,269,31,352,44,117,165,102,202,120,37,318,153,0,6,137,51,10,196,341,134,22,7,49,77,752,59,217,128,48,260,203,125,237,901,82,93,317,115,365,498,90,14,110,342,111,450,95,177,873,72,326,61,8,494,244,457,57,45,19,36,210,139,386,96,144,56,89,509,143,98,76,372,275,719,27,9,160,403,94,351,349,546,854,704,678,817,391,947,253,453,304,99,569,864,308,401,247,29,70,216,758,717,670,475,474,961,116,523,221 }, +{ 214,76,5,129,710,249,618,123,45,460,2,257,17,179,769,205,245,519,207,61,184,106,162,29,209,90,119,32,1,58,6,14,255,292,183,128,77,229,64,21,141,3,655,48,27,38,52,19,263,57,59,4,40,497,151,25,202,152,464,72,7,26,80,99,102,306,311,269,33,115,288,130,318,524,86,54,177,790,62,358,50,243,452,137,46,10,84,186,454,0,425,51,12,148,619,11,210,56,23,556,22,240,112,266,402,36,217,216,37,432,476,136,227,65,70,403,738,155,237,95,111,194,381,139,241,317,180,13 }, +{ 51,23,141,1,202,13,120,21,326,15,269,137,180,165,318,197,352,5,128,48,260,2,77,0,217,12,33,102,7,403,450,203,93,9,32,110,386,115,16,14,64,6,36,4,82,523,373,457,125,18,494,237,291,351,24,342,196,96,37,453,475,817,3,752,391,177,244,615,50,144,28,854,730,210,35,719,99,30,8,317,341,401,160,31,10,44,901,86,221,98,421,22,349,402,576,365,116,922,153,308,39,704,40,72,20,285,17,59,498,372,367,393,661,49,899,67,95,551,70,55,90,275,29,247,89,83,65,69 }, +{ 7,135,2,172,97,87,66,29,52,14,112,70,58,232,337,92,46,226,74,43,262,192,331,461,20,409,16,307,5,294,107,155,334,186,171,278,140,38,151,32,849,324,415,35,75,21,25,45,609,24,227,6,145,1,298,222,60,448,61,64,620,353,387,126,37,86,69,287,549,356,173,48,400,330,644,10,314,583,18,12,22,113,220,526,54,128,359,49,853,36,95,0,76,525,163,67,568,50,65,872,28,104,72,243,138,90,137,587,71,357,4,141,17,246,544,26,230,888,177,194,380,122,474,311,315,635,83,631 }, +{ 574,187,926,860,384,258,531,434,269,110,160,244,141,253,116,871,533,940,261,717,699,959,902,219,661,224,201,373,143,36,911,352,137,260,268,31,851,617,817,728,10,318,523,180,206,295,332,144,811,489,44,843,922,64,251,662,816,120,450,55,127,93,276,855,535,839,98,131,752,951,284,559,824,164,406,642,854,203,1,864,202,317,237,228,365,345,776,498,326,567,442,197,125,282,341,367,96,21,217,417,13,943,86,351,83,679,115,908,564,954,473,82,800,896,165,968,23,128,35,669,48,5,22,170,901,873,169,385 }, +{ 354,156,296,586,1,98,850,163,223,698,379,291,64,44,31,937,48,340,96,349,182,125,237,120,658,77,284,39,30,367,23,385,221,195,293,18,202,144,105,774,128,771,687,541,342,197,116,49,371,121,118,93,5,626,360,16,692,591,453,421,386,352,318,242,153,117,36,10,795,759,260,141,463,372,326,102,87,33,697,11,4,931,446,13,35,948,103,958,899,827,781,752,664,638,558,551,497,475,457,415,304,269,217,205,201,179,166,140,131,127,126,113,107,100,92,89,88,72,55,37,24,883,203,70,21,7,914,846 }, +{ 250,34,472,80,495,483,194,469,141,176,17,64,53,161,33,814,4,667,527,73,27,231,84,56,833,269,14,102,297,585,283,503,59,597,119,106,77,862,255,128,789,11,90,153,209,389,95,887,57,76,3,240,58,23,678,61,236,40,202,134,113,117,151,51,123,304,342,136,369,137,22,237,86,65,45,32,62,445,412,311,200,573,129,436,803,328,19,10,611,196,177,133,491,214,514,72,36,947,26,5,52,139,402,378,318,504,114,0,216,180,287,322,13,381,396,358,629,475,285,46,28,2,383,179,130,112,738,247 }, +{ 97,140,66,172,7,192,314,81,92,426,74,232,298,462,501,43,508,330,69,135,279,6,230,189,24,48,21,885,104,14,448,861,38,712,126,173,715,572,60,563,246,267,16,91,633,423,71,526,52,36,357,29,362,387,18,204,63,443,32,568,324,681,879,441,138,107,67,22,20,0,150,517,85,636,607,12,825,5,893,2,174,278,65,37,149,28,726,86,87,35,779,380,560,42,125,565,95,750,83,124,46,1,49,370,251,653,77,64,877,25,4,10,221,54,33,61,672,40,23,451,98,102,31,9,51,120,348,915 }, +{ 44,31,116,144,268,434,489,367,918,492,384,948,393,127,98,9,940,22,206,105,203,0,855,332,49,93,395,959,28,456,617,911,293,137,1,299,39,125,282,202,51,141,473,55,963,120,417,326,23,95,159,21,599,109,276,730,242,13,36,10,131,8,272,284,253,551,219,30,318,523,2,352,165,512,403,269,18,64,5,7,899,244,16,301,616,450,158,115,12,170,559,935,160,924,143,260,791,386,86,692,201,421,128,457,24,719,728,499,373,37,261,916,110,197,578,48,951,239,286,576,811,494,308,35,96,564,14,498 }, +{ 202,128,141,3,51,64,15,269,5,120,33,2,102,13,403,318,1,23,196,197,153,10,165,17,0,137,82,6,110,117,180,260,453,93,352,12,475,14,125,7,351,450,494,22,11,523,457,402,31,326,77,342,86,99,386,237,9,32,36,21,19,4,134,44,27,203,18,730,37,115,8,373,95,817,421,719,40,291,139,401,49,143,341,98,285,57,111,116,25,961,498,28,391,38,854,317,144,26,752,56,16,217,308,65,277,899,365,898,509,59,45,79,922,48,72,30,41,678,757,569,24,177,615,34,29,864,873,244 }, +{ 127,98,31,105,395,293,28,9,512,299,22,44,0,49,763,599,242,685,109,284,320,159,276,95,1,116,456,870,55,286,900,125,492,36,713,506,158,51,23,935,393,24,327,16,35,239,623,144,201,13,2,65,272,21,39,7,338,12,168,141,18,202,424,5,268,14,170,347,137,86,489,841,68,367,918,301,269,64,374,185,124,165,48,567,479,221,403,662,37,963,308,131,30,401,6,318,67,616,948,115,83,197,237,434,160,295,96,169,128,421,203,154,10,143,538,194,916,352,101,371,253,928,910,261,180,164,244,737 }, +{ 7,24,97,124,2,69,66,1,14,92,18,6,140,67,20,71,43,16,21,118,29,23,149,52,150,51,32,81,5,429,189,48,36,484,172,273,38,60,65,28,22,25,74,83,46,91,13,0,298,314,12,420,610,154,42,108,398,701,467,135,35,505,173,221,576,104,421,168,336,423,37,232,403,302,143,185,847,267,137,115,10,703,158,251,308,508,330,75,68,49,86,61,26,253,202,230,107,401,64,799,388,128,99,443,102,72,607,165,426,453,570,387,547,326,105,125,85,109,517,386,95,138,615,87,126,192,671,63 }, +{ 1,349,64,303,284,442,622,202,691,141,652,447,682,67,717,917,340,237,154,352,269,919,752,547,429,411,197,293,260,44,335,180,160,863,238,201,191,167,318,9,751,730,98,453,33,418,956,475,360,69,77,765,217,140,96,31,153,120,87,724,664,389,323,268,206,116,922,888,102,948,854,842,805,196,127,399,586,658,873,851,850,796,781,695,657,385,330,244,149,137,0,662,367,351,82,947,774,551,498,363,225,146,125,35,212,909,899,848,807,776,772,770,759,726,604,576,541,523,480,450,403,393,372,332,329,327,301,296 }, +{ 1,2,141,15,7,10,180,3,5,6,64,0,13,197,77,269,33,11,352,165,9,102,14,4,349,12,291,341,23,237,134,752,22,120,117,202,498,128,36,217,318,115,51,17,317,40,153,93,365,110,342,961,82,31,864,901,125,137,59,143,196,372,16,86,21,260,111,44,873,32,49,947,457,95,57,244,326,8,351,37,28,569,954,203,19,373,678,18,139,450,29,30,48,386,72,27,79,45,854,391,144,509,55,546,94,99,164,98,116,20,76,83,253,56,898,922,38,25,24,39,61,177,210,719,58,523,494,402 }, +{ 139,99,12,453,196,277,775,475,40,401,215,33,51,111,130,23,11,77,313,211,14,38,266,129,474,477,37,328,339,369,153,719,162,152,54,231,3,308,57,700,117,403,305,188,629,102,880,457,569,183,62,514,229,961,157,556,555,115,176,41,177,471,248,13,507,670,342,4,542,257,17,123,291,236,72,79,304,134,452,89,34,184,90,2,59,76,383,488,94,421,80,32,361,128,440,377,202,119,56,316,21,494,46,165,757,288,45,543,197,528,730,585,249,431,136,5,0,432,52,210,402,120,485,29,1,529,548,536 }, +{ 77,102,33,141,128,202,23,64,51,59,269,153,4,40,115,177,13,196,318,117,291,210,0,137,134,403,22,90,217,342,10,95,180,494,18,49,11,1,475,65,32,6,16,352,216,36,15,139,86,7,194,24,402,275,14,28,9,2,21,19,125,453,165,20,25,120,57,237,3,260,26,341,317,114,349,197,326,214,48,31,12,5,82,17,300,111,421,308,365,523,450,98,110,93,247,304,351,457,285,498,39,27,312,123,44,152,99,401,37,615,373,108,372,170,143,116,68,67,56,96,719,678,361,29,961,205,35,133 }, +{ 7,14,2,58,46,16,70,112,87,38,52,135,5,155,29,66,97,294,172,32,20,334,24,92,186,35,128,227,18,171,6,21,107,37,64,75,780,666,400,61,140,43,60,48,220,232,0,23,141,177,1,54,202,307,13,592,461,115,22,77,12,45,50,51,126,163,137,409,10,315,192,270,25,845,69,90,269,76,72,513,28,113,74,210,49,262,243,9,95,89,71,318,402,631,86,884,298,40,431,102,4,275,290,278,17,324,217,19,180,151,36,237,230,67,356,291,352,314,65,403,59,33,26,609,387,226,285,330 }, +{ 15,13,1,5,2,23,3,0,365,10,7,4,341,51,11,6,9,115,180,317,14,33,77,12,217,102,40,197,21,153,165,17,64,8,117,141,569,22,901,134,32,16,202,352,37,36,457,291,128,31,269,125,237,18,139,196,44,453,391,177,372,28,349,59,719,93,482,629,86,509,961,318,873,498,99,55,752,386,19,401,210,143,48,137,120,342,50,38,49,29,27,403,24,30,758,111,110,57,475,95,203,730,46,98,260,116,90,45,523,494,326,54,105,72,96,65,546,402,351,242,277,164,67,450,734,253,83,26 }, +{ 2,1,75,29,52,14,69,220,67,262,46,38,70,87,103,6,74,24,83,267,25,226,357,366,394,96,26,189,451,112,606,486,135,145,388,324,294,108,335,278,50,66,42,238,163,58,16,331,150,71,19,149,545,222,35,236,18,418,696,133,114,7,218,582,5,36,45,433,516,537,60,380,171,138,641,600,65,550,251,151,21,54,309,603,853,223,181,12,27,287,28,0,739,565,22,17,785,48,86,68,140,461,594,37,97,10,32,423,458,95,160,733,337,583,61,122,307,281,336,64,571,186,273,85,55,774,632,172 }, +{ 9,105,18,101,39,557,16,890,1,252,272,100,265,938,21,326,23,51,301,49,0,68,24,60,264,13,35,310,254,159,737,363,167,593,137,127,121,166,98,846,118,827,156,48,202,30,333,31,55,5,411,395,128,329,132,146,578,44,520,512,242,77,731,682,170,320,371,120,71,916,518,450,373,28,821,286,33,447,327,212,354,271,32,195,639,125,7,364,95,704,102,65,616,385,615,36,688,203,64,12,110,523,455,96,141,197,75,910,4,116,836,506,88,165,93,604,404,22,318,931,2,10,260,86,338,817,40,905 }, +{ 80,209,667,61,45,17,106,483,255,6,833,151,454,29,5,738,378,2,887,742,112,311,27,119,26,469,495,113,491,161,58,145,396,19,25,84,73,70,315,207,814,76,56,136,42,64,32,1,243,62,52,306,614,287,128,445,14,74,383,53,631,3,90,240,34,141,179,86,297,4,72,148,496,65,250,611,214,138,527,46,194,123,137,186,21,655,95,66,549,50,881,292,592,790,48,87,7,11,129,263,205,122,22,440,361,59,222,573,307,38,202,227,75,269,57,85,10,358,245,644,684,54,200,862,651,425,36,171 }, +{ 23,13,51,5,21,115,12,202,15,1,141,32,2,165,0,269,180,197,401,7,4,3,9,457,308,403,453,6,341,37,318,10,719,14,48,120,128,352,33,77,22,137,11,730,217,523,40,386,99,16,260,31,475,569,18,64,450,317,28,237,391,90,17,494,421,365,177,59,125,8,102,72,93,30,629,247,961,24,221,117,44,153,498,758,351,291,196,509,899,402,817,49,304,134,76,89,210,98,326,82,482,45,57,110,38,36,752,901,39,139,468,20,96,372,116,216,19,349,203,288,29,61,95,275,546,670,27,576 }, +{ 99,12,453,277,139,474,369,339,51,38,157,196,37,775,401,188,23,475,111,328,11,313,471,153,40,629,266,79,54,4,477,33,102,59,14,57,248,880,152,342,13,457,305,542,117,377,403,514,94,308,115,229,569,488,961,210,300,211,431,41,89,734,361,485,275,670,134,128,184,381,3,72,529,2,556,719,402,64,413,21,15,215,46,177,757,165,77,197,236,32,62,421,155,50,130,17,162,202,5,45,587,52,507,10,183,555,82,247,490,129,588,123,405,148,216,76,141,7,0,1,181,29,432,6,730,90,468,452 }, +{ 7,92,232,126,97,298,387,140,107,16,60,246,14,66,35,462,150,441,104,357,314,359,279,330,633,423,380,172,230,199,24,121,38,392,356,71,132,192,451,324,22,146,893,508,493,568,289,65,560,95,0,5,32,74,189,830,2,135,21,173,18,603,64,46,43,707,20,501,52,362,90,214,712,550,877,86,607,28,426,312,48,36,29,10,69,278,12,194,49,37,1,6,672,874,204,81,267,68,526,108,835,259,733,895,388,500,779,649,448,915,61,125,149,443,50,55,54,399,590,70,72,939,572,191,124,711,517,167 }, +{ 13,23,318,202,77,177,51,269,33,102,141,115,494,4,90,403,210,153,40,196,117,32,59,128,11,137,342,134,217,291,64,21,12,475,352,31,341,14,2,98,93,10,7,95,700,49,317,275,216,20,19,16,44,22,365,116,6,453,110,247,144,180,96,9,24,17,5,82,0,498,402,349,300,127,48,3,125,57,111,87,28,86,1,203,197,35,25,401,18,165,351,326,139,60,43,26,36,450,873,864,551,473,393,373,372,288,678,576,285,37,523,120,70,65,817,67,752,697,529,421,415,386,304,214,164,152,123,61 }, +{ 13,77,2,23,141,6,0,1,217,115,7,3,180,5,10,51,33,14,197,269,352,64,102,177,9,291,15,4,317,40,17,165,22,11,341,202,318,237,196,117,153,349,16,365,28,210,372,752,134,19,18,128,304,498,36,247,12,125,59,139,95,8,275,457,86,31,27,49,21,24,29,391,342,569,509,25,93,45,143,901,137,32,244,403,26,57,38,719,111,873,386,120,44,864,20,37,546,56,494,39,961,164,758,401,30,453,110,475,35,730,98,65,216,437,34,203,41,326,99,402,300,253,82,90,55,46,194,351 }, +{ 15,4,110,13,120,93,11,23,5,21,32,1,40,180,10,82,165,2,3,33,197,141,51,37,0,48,901,102,12,31,6,7,125,117,352,77,752,341,144,153,351,196,9,237,64,134,498,143,17,269,457,342,59,202,115,98,365,450,318,22,44,401,291,873,8,244,217,475,57,391,253,14,72,349,854,372,55,36,509,89,898,403,90,719,19,386,697,139,111,546,661,27,260,61,56,177,96,569,482,961,16,638,332,758,494,28,864,148,76,45,241,79,350,308,247,437,421,70,474,559,221,210,41,164,160,137,453,275 }, +{ 15,1,13,2,0,23,4,5,3,7,6,51,77,9,341,10,115,291,11,33,217,8,12,102,177,365,317,14,165,16,22,120,349,40,180,197,31,457,901,453,18,21,450,153,961,141,719,260,523,32,44,82,64,117,304,28,93,372,110,17,210,475,59,30,134,352,386,342,569,401,752,275,196,730,90,403,326,202,36,49,629,125,817,216,98,308,247,269,351,24,203,494,899,37,95,111,139,482,758,373,391,19,48,116,237,922,509,57,144,86,137,498,854,421,128,670,873,898,253,437,65,300,55,99,20,704,244,615 }, +{ 20,43,198,325,904,104,173,147,234,422,66,97,426,319,861,77,376,712,416,725,427,945,0,7,5,470,450,192,142,32,707,178,330,819,639,38,202,22,500,21,784,583,414,2,324,230,858,61,889,49,315,113,671,81,455,18,392,74,207,232,52,24,329,107,342,33,560,13,140,595,10,715,291,120,102,95,48,1,64,359,693,600,879,16,798,58,312,494,4,14,344,835,764,306,105,526,290,40,23,289,259,90,159,158,884,577,246,37,9,170,204,681,138,29,239,194,112,12,17,31,318,72,28,226,70,397,153,65 }, +{ 105,28,0,9,49,301,159,127,512,16,170,623,24,109,35,395,158,98,68,1,65,22,55,31,761,371,713,916,18,293,286,7,242,124,347,95,338,737,327,44,39,21,2,14,272,424,154,36,506,685,23,168,101,125,299,51,12,479,48,13,870,763,374,284,64,385,320,599,5,67,202,71,276,116,131,141,185,137,836,456,175,344,239,37,900,187,30,10,577,538,6,616,289,740,60,518,118,86,169,83,364,912,219,96,50,115,928,128,935,165,318,149,747,221,346,32,114,69,810,254,237,627,269,308,144,393,201,492 }, +{ 213,466,689,88,230,435,321,30,699,795,201,831,352,144,217,443,854,530,840,190,539,957,418,1,96,203,382,855,251,100,669,410,335,93,83,748,367,44,662,960,31,934,36,206,141,752,351,317,822,128,731,116,778,120,284,274,131,98,228,927,332,187,69,438,521,800,21,242,160,224,48,372,219,310,137,735,686,557,326,285,237,576,127,922,5,859,269,260,13,494,264,82,523,403,35,244,202,615,166,39,616,551,345,930,180,67,253,921,299,966,2,10,9,258,23,473,365,692,265,197,866,32,276,51,816,617,856,223 }, +{ 130,453,196,47,57,4,236,14,59,412,51,711,381,730,153,77,202,108,128,361,23,46,283,402,210,11,300,719,13,117,38,803,200,401,183,78,34,475,54,342,318,27,369,432,275,2,757,133,503,472,12,3,585,134,62,862,161,529,37,328,457,56,390,494,102,73,176,50,440,322,111,670,65,52,377,899,181,629,17,114,33,136,99,266,123,40,514,339,291,53,250,84,177,21,188,216,389,217,386,139,32,961,155,480,162,754,832,714,894,739,383,657,269,152,106,603,543,527,523,497,277,485,838,137,86,64,48,758 }, +{ 1,2,14,50,5,38,46,36,22,67,103,0,114,65,29,12,28,218,54,7,133,83,86,96,69,21,75,208,24,6,52,168,194,389,10,128,51,160,55,17,23,48,18,181,238,45,37,32,95,16,283,532,58,137,503,202,49,124,171,361,480,13,735,9,289,109,782,285,3,115,70,756,141,169,484,584,35,244,717,64,402,4,328,220,163,646,158,803,505,19,253,789,164,185,108,25,155,487,236,269,143,946,394,318,610,401,335,105,433,403,851,87,800,223,866,309,420,61,27,180,597,99,366,308,59,754,514,418 }, +{ 6,74,26,19,165,453,391,197,14,138,730,29,357,70,51,457,1,50,108,125,500,509,27,145,386,112,366,52,46,235,133,262,13,308,47,331,2,719,78,42,309,75,603,25,223,394,785,23,600,218,38,163,115,114,17,558,34,53,220,128,487,58,236,122,65,130,766,401,498,96,409,307,45,85,66,444,899,73,516,632,64,711,54,630,412,196,5,103,21,180,894,113,221,137,624,241,237,594,773,758,867,629,433,390,475,820,546,12,648,67,32,153,285,606,99,545,745,569,644,324,583,3,181,675,903,283,802,670 }, +{ 10,9,30,376,0,68,55,39,18,43,20,49,174,104,88,501,120,342,450,858,28,2,137,523,470,453,197,757,603,37,414,165,31,325,730,729,671,595,455,222,204,77,64,58,22,21,17,13,5,194,110,95,389,318,260,177,128,102,97,33,1,904,725,7,788,568,387,90,54,46,32,14,11,259,98,147,61,817,392,518,961,958,922,899,873,854,819,805,785,739,719,713,661,615,550,534,528,494,477,475,474,465,457,449,386,372,355,351,349,337,298,294,291,289,269,262,247,196,173,171,155,135,122,105,94,56,48,36 }, +{ 15,23,13,1,202,0,51,77,5,9,341,141,137,120,4,260,115,2,351,21,128,7,12,450,82,901,197,180,269,318,10,8,11,22,403,32,854,33,165,40,6,18,3,16,37,494,523,457,102,177,28,64,352,453,14,317,922,217,36,365,48,421,401,719,475,291,30,110,59,24,569,817,93,961,308,730,17,752,125,117,898,31,342,153,196,285,44,99,576,86,275,642,49,90,402,39,143,139,98,221,386,244,116,373,55,57,629,144,210,661,349,134,203,859,899,95,498,35,482,372,72,237,253,105,216,96,111,758 }, +{ 272,131,105,578,219,159,371,49,616,716,9,224,320,286,737,623,187,910,385,28,258,98,761,127,254,347,916,424,22,109,627,158,713,95,924,239,0,242,836,39,201,31,301,912,944,442,125,170,116,327,293,44,538,688,374,23,55,168,276,36,64,284,51,871,185,395,35,506,221,512,518,202,890,137,101,13,860,169,68,574,479,86,908,10,24,333,16,1,65,144,269,364,308,228,344,141,21,338,567,30,577,165,128,160,747,18,763,124,839,926,299,261,456,268,295,164,662,406,197,67,312,175,7,928,421,685,154,810 }, +{ 457,51,13,23,961,719,12,453,629,99,401,57,515,3,4,165,11,45,62,41,14,17,2,569,37,77,33,32,5,0,40,59,1,308,76,115,197,38,72,79,730,21,474,102,7,475,6,54,9,64,403,10,56,775,237,477,202,29,152,188,341,328,90,509,111,89,215,128,880,734,339,247,757,134,386,84,421,317,313,217,129,94,22,318,157,34,130,117,361,210,670,555,369,365,285,269,266,186,181,153,123,24,899,485,120,542,25,391,758,514,468,277,270,243,227,196,180,179,155,148,137,52,50,49,46,18,471,236 }, +{ 202,318,5,120,450,494,77,33,102,260,21,1,128,13,165,403,523,23,269,342,12,326,817,32,475,141,402,64,2,17,82,457,180,137,48,730,125,291,197,453,37,93,51,615,922,719,386,210,15,177,854,351,98,7,899,576,275,6,44,25,961,4,196,117,115,285,95,14,217,31,391,352,237,65,38,29,27,20,758,40,10,9,153,194,367,116,110,105,50,49,35,16,139,498,341,61,163,39,30,11,349,293,216,144,108,99,76,58,54,43,0,203,3,134,113,70,959,958,940,933,923,900,855,841,750,725,704,639 }, +{ 141,269,352,180,217,202,349,64,160,137,317,318,372,494,752,418,244,954,864,437,753,237,13,341,291,165,717,22,197,115,304,260,365,93,36,21,351,247,120,922,77,82,48,498,32,5,579,144,10,23,342,373,33,854,95,128,0,391,164,143,125,98,482,51,403,28,326,898,386,76,72,1,951,678,638,453,201,86,110,30,457,312,253,221,163,96,44,475,102,901,719,421,196,134,190,166,131,100,88,474,401,203,859,597,521,509,466,459,435,393,321,284,228,108,65,59,40,4,851,576,350,308,288,241,216,214,179,99 }, +{ 70,145,29,112,74,26,2,75,287,52,220,226,632,87,294,6,135,307,163,66,19,396,278,138,635,409,25,151,58,113,1,122,331,222,5,97,42,644,324,461,27,849,500,69,651,45,7,172,262,853,337,53,648,573,624,64,334,445,171,21,67,186,32,73,297,46,38,416,14,17,140,80,61,50,436,155,884,223,24,22,85,48,380,852,92,65,86,889,12,315,36,774,571,103,549,37,10,95,243,491,83,16,72,665,227,89,357,394,76,309,35,106,54,675,808,267,474,250,609,71,881,209,133,606,96,232,583,400 }, +{ 351,82,317,141,752,898,901,180,352,341,15,365,1,498,217,115,33,253,32,143,10,160,55,0,854,5,197,269,21,77,4,36,137,23,64,2,110,482,169,873,120,244,96,7,89,13,349,86,164,102,72,93,372,148,922,40,16,345,90,531,9,83,437,22,251,35,260,457,546,165,202,6,864,48,291,51,28,719,59,238,18,308,247,128,11,304,117,12,569,237,65,961,817,509,450,535,196,95,125,730,523,468,144,98,49,3,899,661,342,318,373,153,579,734,14,490,116,203,134,559,391,312,130,123,109,84,76,326 }, +{ 39,9,310,254,101,252,265,272,100,0,557,30,49,688,455,105,190,166,329,627,159,286,625,709,327,333,18,68,158,404,520,578,131,438,731,16,553,24,98,364,31,676,35,118,593,1,518,48,344,44,167,23,65,21,93,604,829,795,127,60,890,96,88,616,22,363,656,51,242,28,419,716,125,124,846,71,274,36,264,613,13,137,95,116,212,938,109,224,827,411,154,910,160,639,371,664,128,5,374,144,530,395,228,170,219,865,67,10,203,759,121,83,301,382,320,737,55,682,37,647,86,271,793,7,821,115,916,285 }, +{ 2,58,29,151,52,186,70,5,549,75,1,112,45,400,61,163,113,227,307,315,311,287,220,46,7,14,155,74,243,87,409,66,27,80,209,631,845,780,69,262,135,48,50,171,767,496,869,454,331,6,491,17,334,278,106,32,19,64,614,21,73,145,26,294,24,592,67,25,38,659,223,16,97,255,172,72,226,502,852,128,37,140,721,666,89,667,290,36,103,324,86,849,267,76,141,54,35,83,65,207,22,148,96,270,12,635,10,4,95,92,738,474,18,445,119,611,425,137,431,263,114,396,663,0,122,133,90,237 }, +{ 141,217,269,352,317,180,23,13,21,115,77,349,202,137,51,64,372,165,197,32,365,752,318,291,341,5,237,102,15,177,498,33,48,244,304,128,125,4,864,253,39,30,44,11,247,22,9,0,31,901,308,403,1,717,201,342,49,10,98,16,7,221,95,144,40,88,494,90,12,28,117,93,678,120,68,326,100,203,86,96,468,2,475,206,116,546,457,160,437,8,873,210,127,110,76,65,55,37,418,386,350,72,18,453,223,143,24,153,851,351,260,284,579,576,401,268,482,196,35,421,82,3,402,166,101,954,391,83 }, +{ 68,35,101,149,124,154,0,65,9,175,24,398,28,16,189,71,118,429,55,346,67,114,7,345,18,230,399,364,133,14,252,722,39,283,1,547,140,69,108,484,302,694,100,439,103,46,705,83,166,267,389,2,458,92,336,50,212,289,21,246,375,251,419,109,36,520,329,158,22,637,12,60,952,48,265,236,702,596,96,806,30,732,5,826,604,64,194,49,412,701,388,88,420,191,535,264,562,167,886,23,796,168,51,650,238,570,782,868,86,13,218,95,917,768,38,10,32,309,404,706,37,54,221,602,125,159,105,676 }, +{ 66,7,29,112,52,97,2,192,20,151,74,43,145,173,222,135,226,525,415,172,644,104,337,544,353,580,32,45,25,287,186,609,58,70,204,155,14,5,21,712,122,87,227,174,331,61,849,549,426,90,355,81,334,560,6,232,416,243,632,46,0,92,324,177,64,113,673,624,107,59,37,635,216,140,396,138,22,500,16,38,4,707,128,65,48,307,17,77,86,137,91,35,12,721,665,789,141,24,294,884,85,42,414,194,115,526,72,311,825,11,126,262,597,76,89,10,28,75,1,387,209,60,304,171,51,147,651,40 }, +{ 31,125,44,299,116,22,170,55,242,456,599,685,36,870,64,393,492,268,1,479,164,86,558,28,506,144,10,740,23,206,903,9,2,0,963,237,127,546,301,13,434,143,367,5,169,93,51,239,12,654,965,384,137,498,7,923,203,918,489,98,180,95,391,141,762,115,352,417,638,841,253,6,105,14,951,8,940,165,197,844,128,948,457,401,959,244,160,308,282,185,21,312,109,286,202,332,341,49,168,386,752,269,538,365,4,37,24,512,911,473,873,509,551,634,499,318,719,3,208,395,708,217,450,421,96,901,35,16 }, +{ 188,11,79,12,99,377,542,94,339,33,474,37,40,139,111,102,453,4,51,775,475,277,13,471,23,196,629,153,431,401,117,210,134,266,152,403,115,38,961,128,59,300,57,77,880,342,157,485,313,569,3,229,202,14,177,275,477,54,308,184,488,328,21,89,72,670,32,64,2,76,10,402,15,90,165,369,148,141,5,162,318,405,17,269,257,205,216,413,757,129,62,361,0,494,734,41,421,179,45,452,197,217,291,120,82,22,130,386,123,1,50,237,358,125,381,497,498,6,137,285,36,180,48,482,372,29,46,341 }, +{ 658,698,340,303,31,363,919,98,44,156,296,850,586,668,354,87,914,120,163,30,127,70,23,385,51,48,1,478,125,49,77,774,223,260,291,82,691,349,13,854,225,217,116,39,10,724,21,922,898,447,351,293,201,75,9,269,284,759,541,480,281,268,221,165,621,141,442,622,411,371,318,187,153,115,105,102,65,777,93,64,33,652,352,202,744,453,433,398,330,191,180,177,137,128,117,95,69,35,931,638,40,5,888,372,146,140,100,88,565,457,450,335,326,317,219,190,159,158,134,36,32,22,518,482,401,394,276,947 }, +{ 15,82,4,197,13,33,1,23,901,21,5,11,10,165,32,0,120,180,2,40,3,51,110,77,642,7,8,351,326,115,6,386,365,217,457,9,117,401,12,37,102,260,523,134,719,758,569,22,36,59,317,730,31,57,342,898,961,450,453,153,17,141,291,137,475,55,177,48,116,90,196,93,44,403,14,64,352,629,54,372,817,28,143,18,269,139,16,958,96,202,494,349,421,275,752,210,128,49,94,86,244,29,498,899,801,318,851,38,670,72,615,474,304,148,41,89,25,19,308,482,160,373,253,70,61,30,277,125 }, +{ 15,4,11,13,23,5,21,180,141,32,202,269,3,40,1,352,318,17,12,64,33,165,197,31,2,0,51,120,128,117,326,59,457,10,153,196,134,817,6,48,125,93,237,82,44,137,450,77,494,403,49,203,386,752,37,523,7,22,961,217,260,8,115,110,341,57,177,498,719,90,615,9,317,102,365,139,14,730,901,210,98,402,72,453,19,116,65,18,111,391,45,56,95,351,27,899,99,349,293,291,300,475,86,28,36,401,25,55,144,244,275,509,247,216,38,678,76,61,393,29,372,576,485,373,30,253,551,468 }, +{ 91,233,370,718,85,6,81,25,65,256,63,235,42,138,511,397,123,26,343,74,650,87,249,643,355,544,18,64,194,510,636,45,174,280,90,22,108,348,681,104,1,84,86,114,389,4,415,66,19,0,673,283,214,141,122,524,289,56,53,193,208,95,240,750,297,29,119,605,27,573,445,436,736,10,14,11,287,597,32,630,49,24,192,57,5,17,204,475,103,61,102,70,947,152,51,588,23,16,183,77,619,730,523,453,444,59,561,2,813,701,874,323,75,33,28,804,129,96,403,368,21,9,145,177,396,255,693,611 }, +{ 23,51,202,13,21,128,318,141,403,120,450,137,48,494,269,5,1,165,125,64,32,260,15,523,102,475,115,12,14,457,31,33,197,77,817,44,98,453,2,308,95,49,99,16,7,180,18,93,326,37,221,6,4,352,421,401,116,291,61,386,203,82,59,36,9,40,30,24,719,117,110,20,217,153,730,17,615,351,402,237,50,854,10,196,39,19,342,3,922,25,96,341,35,28,22,11,105,177,90,72,58,38,317,247,54,961,805,576,207,68,57,46,349,210,134,86,704,75,70,899,373,65,901,670,0,391,89,45 }, +{ 365,180,317,752,341,217,115,352,901,482,372,498,291,15,253,244,141,13,1,579,269,349,7,5,21,4,318,23,351,82,0,2,51,77,93,125,10,898,89,160,202,44,6,854,165,3,96,308,221,148,137,332,247,197,33,11,304,851,531,144,120,494,40,717,468,251,403,72,177,391,32,12,546,453,421,260,203,437,961,574,258,533,48,509,55,922,880,661,615,373,261,134,241,873,475,345,949,867,734,728,699,569,490,473,434,295,288,237,219,143,127,110,27,17,16,187,153,117,876,350,99,36,9,947,128,86,64,679 }, +{ 115,498,901,197,341,468,13,352,482,546,165,509,237,569,9,873,64,23,365,22,180,95,391,317,758,558,49,752,734,109,28,105,217,51,844,86,837,143,629,131,254,876,12,159,158,719,39,406,308,148,141,679,117,490,83,637,457,10,708,166,36,706,102,89,35,505,168,442,372,125,55,530,221,37,208,669,535,332,272,153,103,98,903,401,261,219,768,114,33,864,364,187,169,345,4,574,434,258,242,224,67,30,3,253,961,868,164,228,816,77,843,120,438,384,351,230,134,128,100,99,2,753,50,44,31,584,347,170 }, +{ 23,13,51,202,141,21,180,165,5,197,125,1,115,269,32,120,12,128,318,64,15,137,523,2,33,386,7,260,14,403,48,457,102,4,450,6,93,99,82,401,719,9,730,110,16,31,237,77,326,308,421,98,453,352,37,221,475,90,44,117,30,0,18,144,899,153,10,817,3,203,391,196,11,59,351,40,217,494,177,17,341,134,116,39,8,24,95,752,498,402,20,509,615,61,28,96,19,247,961,291,36,72,365,86,317,285,241,76,49,373,38,29,25,342,70,304,58,57,242,546,576,22,350,349,901,629,801,551 }, +{ 214,289,90,174,874,280,355,138,65,85,64,6,751,81,312,194,249,835,233,348,636,875,91,343,288,519,32,0,524,247,415,104,29,370,681,750,74,204,22,95,217,437,235,86,123,25,352,192,42,597,954,256,77,18,673,63,864,752,671,306,87,353,746,287,712,237,397,389,115,588,222,177,180,145,580,715,21,141,59,474,317,207,66,56,49,52,33,28,579,45,544,10,84,61,784,102,4,511,202,693,57,40,24,117,173,76,319,240,208,5,216,26,304,134,291,205,114,525,72,17,153,577,168,11,108,422,718,498 }, +{ 15,4,11,5,13,23,21,32,33,1,37,31,2,141,3,180,64,102,44,12,49,196,120,77,40,6,17,7,153,117,352,134,0,82,269,197,51,22,93,10,752,260,165,217,98,317,137,365,342,202,901,318,95,341,450,115,48,30,9,128,177,351,125,523,110,498,854,291,237,89,90,8,817,45,59,14,57,86,457,873,326,373,372,72,61,922,139,56,275,482,36,864,391,96,898,386,111,403,144,27,38,509,899,453,70,116,29,58,253,244,76,160,475,437,304,316,210,16,41,569,308,300,203,719,288,221,546,148 }, +{ 217,33,15,13,117,196,153,134,23,51,77,141,0,2,64,115,102,10,4,5,7,6,180,3,1,11,165,352,202,22,9,40,317,269,197,14,128,318,341,237,17,177,16,291,12,95,365,120,125,18,752,28,453,372,59,137,498,349,49,36,31,24,403,32,110,98,210,386,19,457,401,8,391,901,475,44,86,260,342,304,143,247,308,730,93,275,244,494,164,719,21,864,65,509,57,961,523,25,90,105,546,139,216,55,38,482,569,402,35,29,450,99,873,421,48,670,45,27,26,326,20,37,437,39,629,579,56,203 }, +{ 15,33,77,4,102,117,40,115,134,11,153,13,217,21,1,5,317,196,32,23,3,2,59,12,291,341,365,51,139,120,177,180,372,349,48,141,260,17,342,110,6,197,37,7,72,482,90,165,111,57,352,93,898,752,0,326,457,210,82,854,901,450,269,202,14,36,64,125,523,373,10,137,89,922,203,719,498,730,961,569,244,817,143,44,318,8,76,304,277,403,253,275,31,494,128,386,308,160,22,247,56,899,148,144,453,468,61,638,579,300,96,437,221,116,873,38,485,94,99,237,216,9,27,49,45,19,86,401 }, +{ 15,13,217,2,1,23,0,4,5,3,317,51,341,7,6,8,115,9,365,202,10,11,291,12,22,33,269,31,82,180,308,457,120,28,901,30,18,77,197,450,351,21,961,40,221,372,523,165,730,318,719,854,141,102,64,453,110,260,14,569,93,117,44,16,817,36,32,349,386,498,482,98,403,898,196,134,35,153,24,49,125,752,579,326,899,237,128,137,247,401,342,48,475,177,39,304,661,20,922,509,494,19,116,59,37,203,468,95,329,144,758,55,17,65,244,86,111,391,90,118,437,113,91,122,143,629,864,99 }, +{ 135,66,2,7,192,337,97,52,14,20,673,355,29,43,104,107,331,226,415,376,353,222,294,147,74,112,46,172,560,155,32,5,324,470,609,173,174,21,825,16,64,58,298,145,92,707,38,232,77,35,356,4,10,414,22,525,287,262,171,888,86,632,544,595,635,568,178,90,48,580,87,334,202,597,72,37,60,587,474,6,151,95,307,49,177,59,25,0,142,17,858,61,409,128,1,12,721,583,318,259,362,500,141,126,269,198,102,319,70,494,13,230,853,45,227,54,849,612,400,65,204,186,33,819,246,76,644,279 }, +{ 195,132,146,142,271,167,121,363,878,178,687,647,786,212,354,77,522,929,60,202,411,120,35,234,147,259,101,360,520,626,446,781,98,0,450,668,5,199,55,771,562,23,16,706,777,49,936,18,621,604,48,158,318,639,13,31,407,22,125,21,591,590,465,481,159,534,51,109,198,419,24,126,364,191,141,7,682,551,252,28,20,806,634,156,105,14,447,948,494,107,10,116,39,43,1,269,260,33,265,128,640,291,93,403,137,326,95,203,421,379,102,765,9,82,692,110,416,32,883,664,553,455,694,475,842,523,293,239 }, +{ 202,77,20,318,104,66,269,291,494,102,177,43,128,0,342,216,173,5,2,97,52,450,234,22,7,33,750,29,112,319,74,275,90,337,32,49,198,210,678,544,147,204,58,24,141,789,21,349,64,18,304,16,10,14,580,120,192,194,325,13,416,142,403,500,196,61,59,137,115,86,712,153,113,12,226,174,415,40,23,81,4,28,70,525,402,1,9,230,72,35,178,214,636,46,11,6,904,37,95,87,48,217,355,597,334,31,798,39,17,38,427,186,222,65,376,117,426,285,36,135,51,208,353,673,155,792,172,260 }, +{ 107,362,612,359,414,356,97,392,683,259,819,43,298,660,465,147,581,729,173,779,7,595,501,20,319,470,534,858,246,376,279,126,230,14,5,178,427,232,493,35,92,49,132,426,885,60,32,104,387,0,786,423,66,38,21,121,878,22,16,146,861,441,95,357,560,830,142,2,199,61,172,10,81,707,150,70,590,422,207,48,140,46,58,929,52,324,603,192,18,508,202,314,77,37,347,33,263,13,135,28,241,12,23,29,125,1,345,124,102,98,74,64,568,24,198,380,40,4,687,626,105,607,117,72,177,577,65,318 }, +{ 6,19,13,26,453,165,457,386,51,23,14,74,401,391,308,758,719,603,47,867,29,138,2,70,730,27,366,309,108,324,197,1,25,196,743,711,78,235,262,130,42,475,133,50,115,145,670,487,112,58,53,52,85,17,421,894,96,34,412,5,331,516,509,163,33,500,569,629,482,388,45,468,153,218,128,64,341,283,594,545,444,65,125,600,217,114,236,754,75,899,73,785,630,137,95,38,801,328,895,103,961,550,901,200,11,350,558,117,4,220,180,54,46,745,3,134,433,766,287,739,122,223,317,226,390,241,21,357 }, +{ 179,205,72,245,317,247,152,180,216,490,76,752,352,79,217,59,864,94,498,4,497,452,89,148,11,875,111,141,405,115,188,21,468,588,873,197,579,471,365,464,37,645,372,482,5,77,64,431,341,237,10,529,349,1,12,23,2,474,128,134,316,339,291,36,32,51,38,413,437,629,954,734,308,99,13,143,48,102,165,14,288,90,377,749,184,401,460,542,33,428,3,7,269,449,961,569,901,350,86,40,257,244,202,0,270,117,6,304,54,241,402,45,137,221,457,403,177,9,164,139,318,17,528,15,453,421,358,769 }, +{ 107,359,7,314,392,298,387,279,581,32,232,60,14,126,97,493,534,150,356,121,423,362,172,92,259,147,441,95,35,501,22,357,21,16,246,590,0,380,786,49,18,465,13,64,132,5,28,146,178,10,508,779,23,140,48,24,71,939,929,660,51,135,607,324,603,115,230,43,46,241,38,192,683,462,247,66,612,568,941,835,819,77,12,550,90,36,560,199,4,312,33,9,893,347,330,65,59,52,20,519,2,278,50,626,58,202,37,345,771,294,117,40,102,70,470,451,156,448,350,316,707,236,173,288,31,75,54,672 }, +{ 156,354,586,271,195,591,668,132,48,360,340,121,23,21,463,446,1,5,13,18,658,296,407,51,146,70,698,883,626,55,60,221,777,163,32,363,379,621,590,562,58,49,167,467,647,522,150,61,118,24,411,781,115,447,223,767,786,7,16,31,87,308,687,22,9,259,279,212,44,17,518,346,71,10,371,45,98,2,919,241,761,33,12,93,64,39,541,37,608,35,774,341,759,75,664,941,663,125,846,581,401,120,638,566,303,68,936,260,0,932,199,105,634,270,706,30,453,141,102,95,86,110,107,771,273,535,82,727 }, +{ 23,51,13,453,4,475,0,12,457,10,2,115,401,15,11,403,5,1,40,99,14,59,961,165,569,629,9,32,77,37,308,3,719,7,57,421,21,64,17,494,6,22,33,102,18,202,177,128,730,197,523,670,139,141,899,16,90,341,8,56,217,210,402,48,24,386,125,27,318,95,45,86,72,775,269,758,50,65,19,76,111,38,317,180,89,62,342,54,46,734,28,247,41,29,36,509,237,26,880,196,352,365,275,468,120,216,153,152,108,25,137,757,349,221,181,117,277,49,477,123,34,291,304,801,82,31,678,597 }, +{ 48,125,221,21,165,23,197,13,763,423,508,193,98,293,457,391,5,867,693,386,441,81,18,16,51,92,60,314,64,683,401,49,237,96,104,43,430,35,397,558,241,180,126,523,105,32,758,140,38,72,510,308,474,356,230,95,279,102,501,784,517,663,858,541,31,633,498,718,149,127,91,422,97,418,118,900,159,144,115,511,44,203,246,366,24,223,480,453,361,350,218,160,71,22,701,719,393,40,173,124,963,421,370,148,69,643,93,743,598,493,298,253,191,170,164,116,7,1,939,730,120,74,33,20,326,63,192,269 }, +{ 202,5,450,77,120,132,494,195,523,318,326,1,260,146,121,271,167,576,203,0,817,615,18,21,403,692,234,604,354,142,49,13,35,23,7,212,20,14,2,682,158,252,147,137,101,102,128,32,33,265,48,16,291,551,342,419,364,60,22,966,475,43,107,9,178,363,51,639,17,10,687,12,821,6,859,159,520,416,97,848,805,31,360,269,109,93,198,329,259,39,55,64,562,786,402,92,82,553,878,70,61,647,455,180,411,95,315,191,4,842,105,239,165,822,638,115,98,634,24,453,346,126,99,156,899,199,522,28 }, +{ 39,166,9,101,404,158,333,30,0,190,310,252,274,68,438,419,100,344,88,49,254,124,694,865,154,530,656,364,577,28,810,265,65,35,131,455,159,857,16,21,24,793,22,539,212,777,105,625,747,677,709,562,95,48,286,1,329,703,18,228,71,125,272,36,109,13,10,289,538,219,676,706,778,51,31,98,557,86,23,175,60,553,406,55,962,671,840,118,224,168,221,83,669,67,213,382,96,570,64,960,346,327,170,613,731,191,242,44,115,759,439,957,627,748,114,634,264,688,593,37,251,137,320,127,7,520,167,518 }, +{ 15,110,4,120,11,5,1,23,13,165,93,21,10,2,32,40,180,82,197,3,51,6,33,0,7,125,351,901,391,352,77,9,115,260,102,341,117,217,317,134,31,141,752,453,12,48,8,153,386,509,873,203,457,401,196,37,898,372,59,326,475,55,14,202,569,57,498,403,719,17,64,308,237,494,318,269,94,90,253,961,22,44,730,36,697,342,177,482,56,474,137,89,72,421,349,38,670,576,139,111,30,28,210,148,96,758,143,734,629,16,244,160,128,18,291,41,805,247,25,19,84,373,245,61,488,579,205,523 }, +{ 2,29,52,1,26,58,6,262,5,50,14,70,103,46,19,38,309,27,96,112,67,516,75,163,133,331,218,145,108,223,17,236,45,83,287,25,487,74,114,171,785,409,357,113,238,24,433,151,53,36,388,220,739,34,545,396,307,532,583,675,61,600,181,42,65,73,764,160,635,21,603,394,12,80,594,186,150,324,894,632,3,7,334,99,54,137,315,891,69,445,37,412,323,48,745,537,18,283,87,458,138,822,308,243,155,765,86,711,895,398,285,28,651,366,226,115,766,849,294,23,480,820,51,221,297,22,732,209 }, +{ 120,77,260,141,51,13,217,23,317,1,450,291,15,202,137,326,373,110,177,180,21,269,165,318,128,197,352,115,349,64,32,203,5,342,351,0,102,48,341,96,854,93,82,523,2,244,457,9,160,752,386,36,922,12,365,372,37,898,7,304,275,403,86,10,210,253,817,16,704,28,83,90,901,498,143,6,615,4,719,22,494,237,18,661,730,473,30,24,308,50,221,40,76,72,55,8,59,35,11,33,391,285,67,89,144,125,61,961,99,39,401,14,3,475,247,402,44,31,70,453,49,509,642,153,208,482,17,216 }, +{ 444,183,291,297,358,196,554,255,56,59,123,269,33,605,108,122,153,177,275,210,77,57,341,117,130,128,475,467,730,152,134,42,403,4,50,880,19,381,315,401,51,65,421,216,630,349,283,21,503,235,133,85,23,11,719,368,46,202,99,494,432,229,40,14,29,561,665,339,670,480,736,588,523,453,102,15,899,650,326,256,249,236,197,125,318,2,775,757,711,624,396,365,328,524,78,64,3,529,194,18,13,0,250,12,6,690,25,445,266,48,511,402,285,26,789,678,260,242,165,120,343,769,543,488,409,390,369,366 }, +{ 23,13,51,12,165,14,120,153,38,197,117,37,99,401,134,386,453,54,128,202,141,196,64,5,328,40,237,21,137,139,15,260,33,2,719,475,125,133,180,457,0,46,403,242,77,236,6,208,1,36,96,32,4,391,361,115,308,52,194,629,17,569,730,477,86,102,546,817,450,19,10,758,961,933,923,903,558,160,11,29,22,18,3,188,111,79,114,108,65,48,95,291,56,349,157,94,41,338,221,89,82,34,59,277,177,49,317,304,506,372,351,50,26,421,217,44,31,7,72,341,352,350,316,312,207,183,143,130 }, +{ 95,64,348,33,467,56,343,174,554,511,77,312,233,120,108,180,0,561,6,355,543,13,306,370,197,165,859,25,18,29,297,256,91,63,899,237,49,770,650,412,235,85,138,19,42,523,65,671,90,102,22,9,32,368,194,40,23,10,4,576,426,416,204,161,153,117,116,86,26,27,104,448,775,721,719,457,450,344,326,275,217,72,24,605,730,283,245,196,98,76,17,5,577,519,123,835,475,192,81,78,353,588,386,365,269,260,222,220,214,179,170,141,134,125,119,105,97,66,51,28,11,881,273,242,172,746,707,643 }, +{ 120,51,260,326,450,202,23,77,141,203,93,13,137,318,21,1,82,165,110,15,523,5,351,269,197,64,102,373,128,33,217,48,180,386,32,291,457,125,817,352,922,854,403,115,144,116,177,349,210,12,96,196,615,475,7,719,372,367,237,40,730,2,342,704,4,98,391,10,275,59,494,453,401,0,37,6,421,317,50,16,90,36,44,752,308,9,498,160,31,393,18,899,221,341,14,3,30,45,402,8,898,304,83,692,99,24,551,72,947,247,216,28,961,153,864,678,661,473,88,509,70,22,285,17,576,300,76,35 }, +{ 15,4,11,13,5,23,21,32,1,64,93,33,2,3,180,40,22,37,141,10,82,0,6,77,102,44,31,352,7,120,117,165,341,12,48,49,110,197,98,134,9,752,17,901,153,498,342,269,196,115,291,365,128,260,36,317,137,51,95,59,217,318,237,202,349,72,8,509,391,14,873,177,16,523,86,922,386,247,143,304,210,125,29,45,57,457,453,90,854,482,403,111,579,160,244,18,569,437,89,61,253,76,27,899,351,864,275,450,719,56,758,116,875,961,277,468,164,148,25,817,401,316,84,139,546,490,216,46 }, +{ 15,341,13,141,23,33,217,4,77,180,1,102,40,317,5,137,0,365,202,51,11,21,351,854,9,269,82,10,115,372,32,64,922,901,22,117,260,352,197,153,128,36,28,196,752,134,165,59,318,349,3,120,2,12,30,177,244,37,450,143,291,31,86,457,48,139,160,16,8,7,898,247,253,125,523,18,49,44,57,403,304,55,730,569,961,6,111,110,14,96,498,494,17,308,719,72,39,237,642,386,475,90,98,24,342,45,401,817,326,873,661,76,277,95,509,105,421,210,93,811,453,717,144,391,99,89,164,221 }, +{ 272,105,131,327,286,320,578,109,22,28,219,239,224,159,9,616,371,49,95,623,538,98,716,910,713,127,258,737,187,185,385,761,424,168,170,64,55,254,347,169,928,916,0,158,164,1,924,31,23,301,51,293,39,627,374,125,913,201,44,836,242,912,36,395,13,116,65,479,634,24,442,654,86,346,284,276,35,312,137,308,512,160,115,194,420,10,175,2,154,7,338,21,128,16,944,83,143,456,12,67,601,202,762,141,908,124,535,289,574,871,688,165,401,900,5,763,96,892,933,384,317,506,237,860,14,37,68,30 }, +{ 16,68,35,71,18,60,118,24,191,126,92,101,150,212,167,154,302,175,9,346,55,0,273,7,124,108,107,375,628,28,566,14,722,149,815,199,589,439,882,575,520,363,121,562,246,467,21,364,1,806,279,140,22,49,48,252,517,695,65,230,345,847,647,97,621,411,69,146,336,46,653,39,10,109,694,604,535,5,189,768,399,446,637,50,441,2,755,419,125,298,608,43,314,423,13,649,158,706,463,398,100,67,818,508,38,12,37,20,826,95,354,264,23,32,169,166,132,271,105,96,221,674,83,51,932,429,356,54 }, +{ 20,470,147,43,904,376,798,427,325,595,142,178,858,198,319,0,97,173,414,22,259,61,422,819,77,945,202,14,32,5,362,49,426,392,107,207,887,725,660,481,263,465,234,104,450,534,494,861,95,28,18,33,120,10,612,64,344,105,13,30,324,39,21,455,817,115,46,146,102,31,132,4,246,356,318,65,158,66,260,40,7,48,523,581,9,35,159,315,113,729,23,230,125,347,112,38,128,878,359,59,36,60,12,239,600,182,237,192,153,342,196,683,98,16,170,2,306,298,357,54,279,101,70,560,501,345,199,845 }, +{ 51,23,13,12,99,453,33,202,128,64,153,102,15,196,37,403,141,40,120,117,475,38,134,115,14,137,77,401,139,10,0,165,318,269,82,308,21,2,5,197,54,3,180,260,22,31,494,421,17,86,93,1,95,44,111,457,277,237,402,450,9,110,18,6,98,719,125,65,351,32,28,217,49,342,326,328,730,629,352,386,285,361,221,11,50,36,19,341,48,569,177,41,59,8,194,27,24,89,79,523,29,775,4,961,365,7,670,291,144,373,210,114,46,317,391,34,116,509,757,203,236,108,30,26,817,55,498,57 }, +{ 383,136,17,62,84,440,119,504,56,240,548,3,80,129,378,123,106,128,555,205,4,184,507,59,162,11,14,183,57,361,249,38,202,469,152,64,179,495,483,90,32,215,257,214,245,130,209,54,161,27,250,503,328,229,618,211,5,73,402,45,12,306,318,40,34,514,790,76,452,77,65,26,86,297,141,19,53,497,742,269,814,283,37,33,255,311,194,436,667,114,177,61,217,803,95,207,266,2,50,432,769,757,236,102,21,527,36,556,46,22,10,72,115,41,494,611,381,29,196,99,216,210,151,248,445,137,0,576 }, +{ 70,652,48,5,638,846,1,21,163,340,888,767,221,125,761,349,260,562,269,303,518,658,591,586,13,698,623,23,883,774,98,87,49,31,9,371,296,223,51,763,850,863,120,541,360,346,141,634,64,535,39,30,2,0,845,7,622,156,318,195,44,95,202,900,32,12,931,379,6,558,768,293,271,115,777,401,58,354,818,61,55,17,132,668,450,308,385,914,351,919,93,922,391,457,128,22,590,212,291,77,807,762,758,252,159,101,663,352,538,372,100,446,75,520,18,937,284,96,146,626,326,127,118,116,771,522,463,69 }, +{ 66,135,74,97,278,6,172,69,324,140,267,808,462,14,550,204,7,357,138,87,189,85,298,75,29,2,500,52,335,38,25,92,582,802,174,571,572,841,563,42,380,1,24,314,21,350,16,451,67,46,280,220,501,443,150,620,230,103,486,423,35,353,622,60,83,226,71,192,32,889,26,22,65,903,95,5,48,232,330,64,108,86,565,792,641,580,36,448,70,509,197,222,43,348,558,426,241,726,125,262,0,877,893,50,872,81,309,63,233,950,37,749,18,388,149,145,12,91,237,10,355,606,294,246,114,508,673,28 }, +{ 51,23,33,102,13,128,40,196,202,77,64,65,139,141,99,12,14,453,117,153,475,403,134,10,86,137,4,11,22,0,318,269,115,401,36,114,108,21,38,5,120,180,421,165,402,59,28,15,95,82,210,37,2,177,494,31,342,9,260,217,277,523,386,3,308,450,6,457,730,17,133,18,719,24,46,361,1,352,49,194,143,111,54,50,351,197,300,94,44,237,341,164,365,221,389,67,32,48,283,19,485,291,29,236,27,854,93,961,758,110,326,817,317,285,125,275,90,52,45,34,26,7,391,181,57,8,752,670 }, +{ 88,264,435,100,166,274,772,921,478,382,909,639,438,960,521,96,897,410,30,1,466,190,530,778,265,321,682,691,418,144,724,329,686,39,9,447,93,31,914,131,404,203,44,411,765,335,593,475,795,367,98,625,254,664,120,213,613,403,0,744,539,116,83,656,363,238,5,48,13,576,77,812,805,110,23,21,141,966,69,125,616,829,326,286,201,82,35,520,225,51,821,127,604,285,284,165,260,217,33,36,310,731,340,842,223,102,137,101,615,64,831,252,228,49,10,67,224,557,219,443,692,406,272,268,910,506,197,351 }, +{ 440,62,136,548,504,56,84,3,555,383,507,129,361,128,123,162,4,17,59,119,184,14,202,183,152,161,402,495,328,57,205,514,527,229,215,80,27,257,38,11,378,73,757,497,472,240,211,130,503,452,803,54,469,77,53,34,494,381,318,283,266,250,106,12,102,33,245,210,432,64,403,19,40,880,236,90,5,556,179,21,412,377,2,32,200,300,99,196,269,585,153,488,141,51,275,216,45,37,117,249,529,194,214,372,76,862,177,134,133,313,26,421,0,139,471,41,305,65,248,483,13,114,678,23,217,50,72,775 }, +{ 911,617,959,332,206,253,244,141,282,120,110,384,951,143,352,260,269,10,160,373,717,531,811,417,940,55,728,661,533,36,434,450,93,137,559,203,473,498,642,116,180,326,855,261,295,44,268,638,922,854,752,31,499,164,318,351,201,535,144,851,564,341,365,64,8,115,165,197,843,1,217,317,704,864,187,699,567,127,202,873,237,251,22,258,574,824,98,86,968,860,489,23,817,82,125,21,169,509,926,219,13,276,15,601,28,345,9,372,51,901,349,943,871,5,367,291,776,308,131,391,96,523,105,83,386,902,338,35 }, +{ 120,260,450,141,77,15,1,23,351,326,137,64,373,82,203,33,13,291,51,21,217,523,269,177,102,128,922,165,110,197,854,5,318,457,180,352,48,32,125,144,93,817,160,202,386,96,50,7,372,36,349,304,210,2,342,730,115,898,719,16,0,196,247,494,59,10,9,473,22,4,403,116,18,86,67,341,752,615,95,75,901,317,275,704,24,475,453,437,367,208,164,163,143,37,90,899,244,98,12,3,365,968,551,300,237,206,55,35,29,6,801,805,678,576,401,393,391,288,268,216,194,99,72,61,58,49,39,242 }, +{ 15,0,1,2,5,51,9,23,7,13,6,901,12,3,8,180,4,141,82,115,14,10,341,120,197,33,93,730,21,40,125,401,260,202,102,22,110,64,569,719,457,165,37,961,898,453,18,351,31,28,203,16,137,352,217,450,77,326,11,403,629,308,128,196,32,30,36,269,44,98,116,318,365,99,475,373,670,237,24,899,854,523,391,95,421,49,48,317,177,221,817,153,55,117,752,39,86,144,38,642,105,922,242,291,54,143,17,134,494,498,244,59,661,96,473,65,160,509,139,170,247,89,114,90,638,20,704,482 }, +{ 104,7,97,107,356,560,66,232,707,359,298,568,289,324,712,392,192,38,14,426,173,65,95,64,172,387,22,43,92,32,357,362,214,20,259,526,90,0,330,380,126,246,501,49,5,86,893,74,500,194,874,147,135,612,230,10,204,779,52,2,729,808,550,140,35,835,21,28,314,77,312,60,16,465,132,715,279,423,414,600,885,802,683,18,81,24,36,13,636,861,150,33,178,29,819,519,288,4,31,58,660,448,121,534,12,168,61,48,581,278,70,37,146,102,441,23,46,199,142,6,751,249,76,319,202,189,124,237 }, +{ 6,66,1,2,74,67,29,14,24,69,83,135,25,458,52,150,108,451,75,38,103,380,267,278,7,87,26,42,324,36,357,138,602,114,97,19,85,238,594,273,65,149,398,335,172,46,160,204,70,18,711,550,50,16,309,220,71,732,96,696,5,133,603,12,891,86,174,28,280,500,418,467,226,32,22,21,222,189,27,60,124,423,486,547,895,302,733,236,532,388,208,64,63,0,35,17,13,298,95,262,45,906,336,646,582,37,145,194,571,20,531,112,23,58,140,516,484,48,886,218,118,115,99,81,462,429,54,55 }, +{ 51,23,13,453,12,115,202,21,403,401,5,4,457,719,475,37,99,165,32,308,64,3,1,2,523,10,730,0,128,17,197,15,141,494,11,22,14,6,269,961,7,318,120,386,77,899,18,247,421,450,817,48,16,117,59,90,33,125,217,9,19,153,180,629,26,758,237,24,177,28,221,95,57,341,40,25,38,54,569,391,27,260,402,29,216,317,36,72,291,102,56,134,365,45,76,49,468,304,352,137,210,203,34,89,196,342,82,275,194,349,437,46,123,326,50,20,8,670,482,86,509,139,498,316,53,61,576,288 }, +{ 57,59,77,4,381,11,412,369,210,291,421,283,803,53,250,542,377,14,339,471,275,108,99,670,19,300,453,403,23,27,401,368,40,51,202,361,775,21,12,554,236,183,402,813,33,342,38,378,475,503,46,37,444,10,736,390,152,90,56,561,285,153,134,123,117,650,73,899,523,281,0,529,494,63,386,880,432,162,514,128,58,605,102,817,743,690,495,349,277,256,196,137,111,79,18,9,801,235,139,78,867,391,200,119,758,130,42,26,480,389,719,714,467,341,80,269,122,730,221,216,188,177,161,133,114,45,29,22 }, +{ 15,1,5,2,0,7,23,6,13,51,9,3,180,115,12,457,4,8,14,141,901,719,197,33,21,82,961,365,22,120,165,341,31,351,64,202,308,77,37,401,260,117,16,153,28,11,110,93,730,10,32,44,269,137,217,569,18,98,102,49,128,317,453,125,30,36,99,523,48,352,134,752,450,196,386,318,326,40,95,24,758,898,17,116,629,39,373,203,86,72,899,237,403,59,177,35,873,90,89,55,291,105,817,144,734,475,244,139,421,65,498,76,247,494,20,38,854,349,160,253,509,372,96,482,221,216,615,143 }, +{ 64,237,180,95,312,197,146,32,90,247,316,929,352,126,165,288,317,132,304,13,60,490,77,217,955,522,92,314,86,22,4,23,7,5,21,626,40,14,11,12,652,498,291,177,232,164,199,33,10,482,51,141,115,150,633,462,579,340,216,16,529,128,37,360,638,388,121,359,143,468,275,59,107,49,534,125,202,658,509,269,888,267,1,598,581,588,76,17,467,451,296,28,751,660,441,349,194,29,31,71,698,279,253,45,640,57,48,546,134,117,18,2,830,647,372,102,65,437,493,351,98,733,622,423,273,241,309,137 }, +{ 1,23,13,51,120,15,202,180,5,21,260,141,0,326,2,137,7,77,197,450,269,33,165,318,9,128,352,110,48,6,102,523,12,115,342,317,4,32,16,386,14,403,373,203,817,36,18,217,64,96,37,457,93,752,82,28,341,494,24,615,3,22,291,351,401,8,475,10,308,453,421,391,901,221,196,59,719,730,854,30,177,90,160,365,402,125,35,498,31,285,99,39,11,244,237,72,20,899,44,40,704,86,17,922,83,50,210,349,569,576,98,95,67,76,372,509,49,143,116,253,961,65,144,89,55,551,661,29 }, +{ 14,46,2,16,24,75,69,35,220,52,7,38,1,140,267,29,71,50,309,60,87,92,70,171,189,67,18,54,163,262,335,108,230,58,366,103,150,5,675,236,181,112,223,278,409,537,21,83,294,48,155,68,12,486,149,37,571,582,96,0,246,334,135,186,443,45,328,28,32,133,641,97,451,151,388,64,307,126,25,9,502,760,394,281,357,22,65,66,774,36,10,55,172,114,61,6,565,462,461,251,552,563,400,74,820,330,238,218,600,72,99,86,606,314,17,380,430,227,587,433,20,13,23,583,516,545,121,115 }, +{ 127,98,31,44,299,276,284,9,935,293,116,599,49,0,456,201,492,28,39,105,144,371,662,22,159,125,272,137,242,131,737,489,393,567,268,395,51,1,761,578,367,202,158,30,109,918,916,685,219,254,203,616,23,434,36,21,55,141,295,95,13,24,16,187,93,385,128,18,96,948,48,269,763,160,318,64,5,165,86,101,244,326,115,518,35,286,836,261,37,512,7,10,68,327,623,716,384,120,403,253,688,110,333,224,2,890,457,143,100,197,12,386,252,301,320,258,963,310,65,14,237,924,221,170,494,421,83,699 }, +{ 53,573,445,297,436,73,6,27,151,113,26,250,491,19,614,145,611,200,315,112,45,396,881,138,80,42,58,70,34,684,25,631,17,222,287,106,74,472,122,61,624,714,690,235,5,90,32,65,255,64,648,29,14,66,95,85,322,2,209,243,549,311,644,22,1,52,665,280,47,161,86,76,87,194,312,651,3,667,133,416,75,307,114,128,78,62,137,51,57,4,226,141,50,136,46,862,483,49,289,884,119,440,632,814,12,21,176,237,148,56,236,283,174,36,135,63,123,337,10,453,33,412,84,469,214,59,108,23 }, +{ 90,788,804,32,115,693,494,81,84,56,725,403,119,21,18,681,99,77,202,526,65,240,214,576,64,817,91,0,784,350,241,102,397,342,690,848,104,61,24,945,318,69,825,453,421,365,210,134,123,117,33,20,707,402,60,293,263,207,194,114,49,888,370,97,43,673,671,523,726,326,125,510,879,773,718,715,701,462,283,249,180,153,59,57,51,11,887,835,814,111,23,4,889,468,289,247,221,95,89,86,66,120,719,325,192,899,730,683,595,422,757,486,484,426,351,312,306,302,285,275,260,238,216,203,196,177,174,165 }, +{ 24,7,14,149,71,16,18,108,65,69,28,154,189,35,2,140,124,92,68,150,118,175,429,302,0,66,273,67,336,38,55,97,251,46,60,36,547,1,267,484,22,458,230,29,83,6,9,388,86,650,172,314,95,109,114,52,135,21,64,886,602,74,505,10,232,5,20,12,596,823,705,398,32,103,49,101,420,570,236,531,289,533,50,298,168,169,48,133,462,451,380,23,882,246,283,51,799,13,43,25,185,797,194,847,75,357,278,158,37,439,346,594,330,733,399,423,610,164,192,535,701,104,345,467,143,443,125,137 }, +{ 68,0,101,9,212,65,124,35,154,189,69,149,114,230,67,39,252,100,1,336,702,329,16,265,520,83,103,191,264,755,64,589,88,562,28,705,30,24,283,167,118,18,777,732,478,12,21,723,71,166,23,49,175,133,398,335,596,55,664,218,237,429,389,532,818,604,364,50,158,115,484,289,246,352,238,410,141,22,759,419,323,375,345,36,13,10,806,128,51,547,796,269,213,5,48,722,140,247,321,96,565,480,164,180,251,330,803,553,37,676,95,143,202,86,75,490,443,7,936,724,99,2,190,694,346,197,782,917 }, +{ 5,2,186,61,29,52,45,58,311,17,171,80,227,209,48,155,1,106,243,496,50,46,334,454,592,21,513,14,502,255,869,666,151,663,262,223,75,207,38,32,270,667,62,6,27,738,659,119,56,3,807,54,780,287,378,84,721,74,220,290,96,163,483,72,263,89,67,549,103,281,136,37,583,76,430,181,536,7,70,408,12,394,64,787,73,675,148,495,469,69,161,400,409,36,833,86,65,34,19,474,587,742,767,221,26,324,128,4,309,115,24,83,306,425,25,22,431,10,241,760,90,141,764,541,133,240,95,383 }, +{ 15,1,13,2,5,3,4,0,341,7,6,23,10,11,14,12,9,33,51,17,165,153,197,365,569,180,77,40,102,8,115,117,21,901,64,217,317,22,141,16,128,32,457,196,31,134,28,36,291,18,177,139,137,237,719,961,37,57,120,111,352,349,386,59,202,453,629,86,752,19,758,38,93,873,269,44,391,372,49,143,95,342,730,30,475,498,509,260,210,318,125,110,304,55,27,29,403,82,48,24,277,72,482,275,116,494,25,450,98,54,351,76,90,326,41,79,373,99,899,546,523,194,144,474,94,56,203,39 }, +{ 13,23,15,51,0,1,10,4,2,5,77,9,115,3,12,14,22,102,11,197,33,457,7,961,165,453,403,40,59,6,21,475,494,18,719,64,180,28,202,569,32,401,31,37,17,16,8,210,177,341,523,120,141,386,730,49,217,99,44,318,57,450,308,36,629,421,125,93,153,342,90,117,24,111,498,139,269,237,30,196,817,291,134,317,326,98,95,365,899,260,352,19,48,82,275,391,72,38,89,110,509,482,86,873,216,76,349,148,247,79,27,54,116,474,65,203,901,615,55,45,351,128,758,137,304,752,94,50 }, +{ 15,13,0,1,23,2,10,102,5,9,33,7,4,3,6,77,51,115,12,11,341,217,196,40,14,117,153,18,317,569,22,8,457,365,523,16,342,180,197,165,120,719,453,961,59,134,730,21,64,141,260,31,901,401,291,899,386,28,139,82,210,177,349,269,49,24,482,202,17,372,817,44,450,93,629,111,32,125,351,326,300,352,37,318,110,128,30,36,475,95,579,468,57,308,19,137,38,98,247,437,304,275,20,65,752,237,498,391,494,758,615,90,86,373,854,116,277,99,72,96,48,421,203,45,216,105,898,89 }, +{ 166,39,274,190,438,310,30,333,530,100,252,656,625,539,265,404,778,88,101,455,9,0,557,960,593,329,254,131,1,676,382,709,724,158,553,840,731,228,98,31,669,23,68,219,264,48,21,748,957,812,406,49,224,127,44,13,344,36,272,286,51,159,520,419,105,96,116,125,613,83,5,93,795,124,213,28,863,22,223,35,478,10,816,352,293,69,67,829,16,827,258,616,364,160,64,242,639,578,120,167,128,65,518,217,321,154,32,137,187,604,180,4,679,435,118,18,251,212,144,86,95,759,141,77,410,793,371,37 }, +{ 734,94,148,308,79,111,413,468,89,37,431,115,179,401,569,197,629,341,188,13,873,474,490,365,72,12,11,134,205,245,317,117,4,247,358,59,40,152,509,51,482,901,961,76,99,528,23,180,10,498,217,216,477,339,77,139,102,38,165,55,749,421,196,743,579,143,33,542,428,391,875,752,471,497,54,1,452,153,177,21,488,588,3,64,141,349,453,485,670,277,291,457,2,128,5,57,403,36,475,529,184,540,202,48,377,90,7,372,14,50,405,210,437,15,758,402,464,386,352,300,157,6,17,0,45,794,9,342 }, +{ 539,228,224,219,190,816,840,871,30,669,530,957,258,748,863,406,93,187,778,531,160,213,88,466,839,36,131,137,116,202,728,679,926,120,44,352,39,321,373,318,274,276,851,31,574,442,860,144,730,217,201,203,613,251,856,55,559,533,944,141,435,1,450,242,230,22,127,86,110,64,800,28,49,326,473,9,260,752,268,254,166,418,717,567,456,98,96,776,902,385,968,100,719,180,269,616,317,918,351,83,827,492,10,625,931,494,125,831,908,197,21,365,372,82,371,35,77,716,854,795,689,295,704,5,332,345,244,291 }, +{ 801,393,125,791,386,730,23,551,51,21,144,116,48,203,98,221,175,165,949,93,575,31,126,13,958,326,697,601,421,345,788,293,367,22,963,541,110,455,60,608,670,273,197,44,463,4,32,677,623,127,33,259,834,35,948,453,375,133,107,120,77,40,223,0,407,342,68,719,121,43,14,446,621,590,523,373,308,102,49,16,899,1,815,475,199,770,725,191,493,804,96,36,319,141,101,92,39,146,690,71,55,7,118,38,805,352,649,735,615,602,533,531,480,323,279,246,208,201,196,180,160,105,64,743,589,132,117,598 }, +{ 13,23,77,51,115,141,33,217,4,2,177,6,0,102,40,7,64,11,10,14,3,1,180,269,22,202,9,59,16,15,17,352,318,128,18,197,291,247,32,165,196,153,117,134,317,19,5,90,341,125,237,24,137,210,36,28,304,349,403,49,12,95,86,25,275,372,453,365,31,308,752,216,342,20,143,139,475,93,27,98,498,57,26,401,21,120,386,391,457,326,8,569,316,494,421,111,65,901,203,110,105,30,260,468,288,164,437,241,45,48,29,35,99,44,482,719,82,402,509,144,37,244,55,546,56,285,961,293 }, +{ 2,52,29,70,112,7,58,14,75,87,46,220,307,186,171,163,151,1,334,262,135,278,66,5,69,155,294,97,38,140,74,16,45,172,287,549,92,227,400,24,849,226,331,113,61,324,25,48,852,32,35,21,37,6,461,67,409,50,19,12,644,315,267,145,26,243,223,311,27,64,60,54,232,122,71,18,83,17,571,583,189,86,36,853,103,72,65,394,380,587,780,774,309,20,43,22,357,42,96,314,298,128,209,335,536,95,474,767,675,270,337,76,80,89,330,222,0,90,721,290,230,10,137,108,246,126,28,448 }, +{ 321,88,213,435,466,100,689,382,30,230,1,795,352,410,96,217,699,921,190,831,521,530,443,36,83,686,144,418,840,264,438,854,128,251,539,957,44,141,180,557,752,335,69,223,317,960,31,265,48,137,855,116,934,201,98,748,160,669,909,93,166,203,812,731,403,21,274,351,593,39,778,206,367,772,219,64,228,131,455,202,9,284,5,372,35,326,238,127,23,735,82,51,656,285,67,158,310,125,639,800,221,187,224,332,269,120,365,576,494,13,897,252,345,822,478,765,349,702,77,268,421,242,208,110,318,859,101,237 }, +{ 363,520,411,354,101,195,668,132,447,9,156,905,364,664,121,146,360,23,18,759,781,1,98,765,271,51,96,676,252,264,13,777,5,31,586,621,591,478,223,167,848,21,100,691,936,551,33,393,857,70,48,883,125,682,77,16,39,687,948,821,44,367,116,93,24,407,265,127,593,834,110,49,842,522,296,4,293,166,626,812,865,64,404,203,333,102,538,212,36,638,40,55,446,50,647,118,291,656,897,144,639,60,771,697,128,403,379,67,35,692,541,165,463,163,604,453,658,199,590,69,791,286,7,32,12,317,217,724 }, +{ 51,23,13,453,401,475,12,403,457,730,719,21,5,308,99,115,2,32,11,4,3,421,961,1,165,15,629,899,0,670,37,10,6,17,197,9,33,18,22,523,569,64,40,202,28,19,56,26,7,57,27,16,72,48,196,194,24,59,494,177,153,45,36,139,77,386,210,128,117,65,758,34,8,391,341,817,468,217,54,29,450,275,221,76,757,509,350,141,134,90,89,46,38,291,180,880,237,102,304,216,775,734,546,402,361,277,137,130,129,67,41,25,14,247,148,62,901,498,477,283,262,260,133,123,74,42,801,365 }, +{ 72,76,89,205,179,90,245,528,148,54,184,37,12,431,38,308,152,4,257,59,474,316,428,401,464,57,460,749,32,288,358,405,229,23,477,645,743,99,11,21,51,115,497,77,217,1,794,79,157,14,5,629,540,488,453,216,45,449,17,155,2,221,770,165,48,670,421,569,328,266,50,452,197,341,181,3,128,769,10,365,137,64,13,317,587,241,36,457,734,188,247,0,339,313,7,536,350,471,9,202,94,468,524,509,721,482,141,46,129,102,773,697,33,432,40,180,270,237,281,619,741,381,86,361,961,543,476,720 }, +{ 376,43,147,470,20,595,173,107,858,97,319,142,427,819,414,178,729,362,426,325,5,259,7,32,861,392,61,798,246,14,104,198,230,560,885,324,77,21,422,904,356,0,465,126,357,48,707,234,38,330,22,49,207,35,501,612,66,13,202,95,534,359,298,2,10,577,76,28,16,70,113,64,132,4,17,481,318,715,102,60,58,18,784,59,120,40,72,11,90,29,500,23,74,279,879,146,33,1,112,660,387,56,52,45,315,81,232,9,494,177,140,36,115,37,153,600,57,199,217,31,12,121,347,51,403,878,671,164 }, +{ 202,269,141,494,318,51,137,403,128,77,453,4,475,217,678,349,421,5,342,352,96,102,291,177,372,317,64,341,180,21,2,40,10,59,32,752,33,11,61,3,515,120,304,36,0,365,6,31,13,22,7,39,30,95,125,260,237,12,717,275,115,28,23,98,244,482,268,105,947,851,402,805,203,194,144,954,576,450,351,48,859,289,283,86,65,55,49,44,795,197,82,90,498,312,285,241,201,182,165,160,57,56,14,411,293,284,9,822,326,899,523,931,921,897,863,854,839,821,735,691,668,579,569,442,360,251,214,207 }, +{ 77,202,318,102,494,33,128,269,23,13,51,196,153,177,117,342,134,291,403,0,141,137,64,15,349,82,22,351,203,49,275,615,373,21,551,393,473,217,95,859,31,210,4,475,402,1,352,65,11,10,450,120,32,180,86,285,36,18,2,7,3,453,12,260,6,28,98,14,125,39,421,48,90,5,372,40,194,59,44,165,817,16,9,115,326,341,523,17,678,216,30,197,317,116,576,96,127,237,61,93,300,24,365,124,70,401,105,730,214,160,114,304,289,110,329,20,704,163,35,386,208,899,144,692,244,67,50,719 }, +{ 253,951,352,110,811,499,244,854,10,638,642,752,559,180,143,141,564,8,260,341,498,417,922,661,901,197,206,165,911,373,137,93,282,873,351,384,15,959,55,332,120,762,717,728,269,160,898,82,473,64,326,164,36,365,203,22,704,533,317,509,31,479,86,968,116,318,115,202,531,1,268,217,33,535,28,44,9,617,237,13,434,4,261,23,77,940,125,5,372,11,851,864,40,32,338,21,102,0,569,386,30,96,482,349,169,824,421,51,105,546,12,401,242,758,576,391,35,127,98,170,2,117,144,844,295,457,24,291 }, +{ 141,23,13,5,4,269,352,51,180,21,317,115,202,217,1,197,2,11,365,318,32,341,3,6,372,137,7,498,77,64,349,291,48,752,33,0,165,237,9,15,22,12,901,221,253,16,144,244,143,403,93,28,401,30,453,110,475,24,304,40,39,120,125,494,421,203,308,72,160,569,18,386,177,35,102,482,31,14,260,44,10,36,391,95,473,373,153,49,468,864,247,117,873,128,100,88,59,134,69,546,241,76,717,89,86,196,17,37,437,166,509,351,164,98,854,67,8,90,704,629,82,851,450,96,811,367,326,284 }, +{ 252,101,18,9,0,68,16,118,329,35,364,24,39,167,60,333,265,109,158,553,71,212,677,28,419,604,100,793,49,286,159,154,191,105,55,310,272,694,327,455,124,810,806,48,22,166,254,593,21,7,374,344,1,520,146,121,538,5,917,65,346,706,857,634,92,562,23,627,404,126,925,13,98,185,51,108,30,14,907,271,169,709,31,942,95,10,446,96,149,628,557,125,375,170,175,67,688,199,363,132,639,239,190,656,107,621,320,12,912,638,137,36,150,44,815,302,50,463,865,221,438,32,37,578,671,439,848,131 }, +{ 28,109,158,9,168,49,39,175,35,159,22,0,55,185,65,289,272,67,95,194,114,346,333,577,169,584,254,1,344,327,105,570,286,336,24,83,86,30,747,68,627,374,124,505,69,101,810,610,837,439,36,154,535,133,103,7,310,16,14,835,131,756,601,345,2,429,874,149,389,50,799,793,252,347,283,208,547,51,251,46,23,100,128,10,189,312,164,424,912,21,484,5,64,688,637,12,190,578,455,96,239,420,13,518,143,634,137,419,533,364,18,398,166,48,709,320,218,538,127,160,170,230,323,125,71,37,98,202 }, +{ 15,13,1,5,2,3,4,341,11,23,0,33,6,51,7,12,40,115,10,9,77,102,14,197,365,180,17,901,21,217,317,196,165,32,569,22,141,8,64,961,453,457,16,153,59,117,18,352,31,202,125,37,139,291,401,629,28,386,269,134,719,177,475,237,93,318,120,730,44,48,372,110,24,111,899,36,210,403,19,57,523,391,349,752,326,49,38,128,308,342,260,494,498,116,95,509,98,137,30,873,304,758,90,801,27,56,86,203,615,144,275,45,482,450,65,670,373,54,41,50,734,94,143,25,82,244,105,79 }, +{ 173,693,18,104,422,20,102,0,77,49,61,5,784,560,526,707,226,32,13,33,397,64,193,344,134,117,91,66,21,153,715,263,81,95,172,232,207,196,31,11,6,65,510,42,25,414,197,180,135,48,29,22,10,43,72,819,4,470,324,40,85,546,86,887,347,51,319,204,57,28,27,426,359,283,498,376,138,128,90,194,392,643,879,701,474,87,74,59,52,38,9,387,681,7,862,597,192,814,847,718,713,334,291,270,217,165,125,83,37,56,23,202,177,141,122,825,241,509,330,942,817,523,370,269,115,98,84,44 }, +{ 23,51,386,308,13,401,221,421,801,949,719,165,468,730,21,770,341,125,697,453,867,14,115,670,457,6,391,403,1,475,958,523,450,117,102,197,629,365,33,569,607,7,2,758,120,66,899,515,743,134,217,791,342,97,16,326,67,733,74,350,150,773,749,260,202,52,29,18,9,501,456,805,809,734,482,56,0,317,135,4,906,458,153,3,380,103,645,579,558,490,24,93,83,388,196,108,817,11,99,903,685,177,69,32,561,267,236,335,5,180,594,696,554,451,642,576,564,559,546,349,291,238,122,89,87,76,75,73 }, +{ 49,0,24,16,105,159,28,9,35,158,68,320,18,109,239,55,65,170,124,7,1,154,301,347,71,95,14,286,518,101,2,344,327,272,127,118,39,21,60,374,890,98,577,623,12,149,22,5,916,338,512,168,36,713,395,23,31,67,51,371,13,48,185,175,125,137,10,424,169,64,202,737,479,30,747,538,6,761,37,108,128,346,242,32,740,293,131,46,50,302,654,69,44,252,419,289,810,86,114,92,83,616,141,385,846,299,164,254,364,506,403,677,310,671,375,191,221,116,938,318,634,100,165,439,115,143,333,96 }, +{ 2,5,29,45,207,58,61,1,76,292,32,655,263,14,476,52,72,6,119,17,306,70,186,7,106,46,179,214,790,90,148,243,720,38,227,50,240,112,151,710,255,592,84,89,64,48,25,464,75,241,209,21,129,74,155,460,358,3,128,454,496,425,36,77,19,22,141,738,10,115,56,26,86,16,123,66,408,311,27,245,0,249,95,65,205,287,519,290,618,40,24,177,549,171,202,87,4,59,163,307,54,334,237,51,23,62,269,12,102,37,18,449,869,137,80,69,113,28,99,33,67,13,135,180,318,315,769,288 }, +{ 125,21,115,95,715,197,49,165,64,56,66,32,6,278,13,33,713,681,808,350,204,237,120,408,263,241,172,135,81,22,324,87,509,74,0,85,97,4,90,86,468,65,888,353,174,558,391,841,192,180,23,950,872,645,571,554,650,580,141,5,2,412,283,467,341,673,59,138,38,108,903,177,91,51,7,511,370,164,75,31,620,475,203,893,170,98,712,104,44,19,885,10,1,561,426,415,308,63,403,196,153,117,102,84,389,128,27,825,569,210,77,347,53,123,386,316,159,143,835,194,900,448,93,11,546,232,18,572 }, +{ 612,325,427,202,107,494,5,403,470,147,518,376,64,362,49,21,392,788,465,98,14,342,125,623,318,178,48,31,845,804,534,858,423,70,690,595,414,278,93,422,269,453,7,660,102,77,33,693,61,953,767,798,819,581,307,298,234,198,116,110,97,39,32,30,10,237,4,671,663,389,289,194,128,43,0,20,904,725,761,711,678,509,501,493,366,319,236,232,220,174,104,99,95,88,87,68,55,44,38,37,18,9,900,293,13,715,441,315,105,291,163,141,391,112,848,397,22,763,713,558,846,835,828,822,757,657,557,546 }, +{ 32,76,21,72,14,241,449,50,292,2,350,5,1,155,48,221,46,38,89,179,270,45,476,90,54,720,214,430,148,464,17,281,129,460,37,205,413,741,181,36,245,519,29,227,52,290,257,184,405,12,123,710,3,528,162,7,773,243,541,10,358,0,288,431,67,57,249,536,316,152,99,96,23,106,171,51,513,4,743,308,618,128,137,6,115,64,474,477,103,408,86,207,769,229,263,9,328,83,133,180,59,183,119,552,794,787,540,114,217,488,425,218,62,11,421,659,77,645,760,721,22,524,202,58,400,401,141,770 }, +{ 24,154,149,28,124,16,35,0,71,7,14,68,175,108,65,18,55,92,109,302,118,9,336,570,484,398,69,140,60,2,420,67,189,22,101,46,150,185,158,346,230,1,439,169,252,273,168,419,289,39,49,38,505,251,83,345,701,535,799,610,637,267,21,36,97,10,650,50,95,12,429,246,103,533,114,388,458,133,5,48,399,314,86,6,671,375,159,66,364,29,236,329,962,703,105,547,23,51,172,601,333,283,64,265,886,126,96,194,52,13,232,722,32,20,389,54,37,677,164,100,143,125,327,602,75,917,344,286 }, +{ 5,14,1,50,48,2,46,38,67,54,45,103,24,270,21,96,513,155,290,83,58,61,281,69,32,36,181,72,502,0,29,171,17,12,16,7,76,263,37,18,28,52,227,35,425,207,89,666,22,221,243,133,541,663,65,10,741,218,408,223,114,536,108,474,75,9,186,6,592,552,51,23,99,238,328,115,309,794,540,3,433,834,86,292,760,477,148,449,428,64,476,128,400,528,119,655,55,236,241,106,202,141,765,766,487,70,13,163,137,366,95,71,587,697,488,720,179,160,19,418,807,308,659,149,27,90,431,4 }, +{ 961,13,569,37,197,23,474,94,148,79,12,629,401,111,901,341,15,51,165,405,734,873,99,4,413,188,134,89,10,11,358,152,179,117,308,115,40,59,72,468,245,139,457,33,153,247,365,477,205,277,339,317,77,758,5,38,498,76,579,453,216,180,0,3,542,762,36,490,2,177,102,143,482,217,196,471,14,452,128,437,55,1,54,304,22,210,9,377,64,638,202,17,21,488,349,431,300,775,528,485,32,7,141,318,372,86,8,509,157,45,291,497,137,184,6,864,402,670,275,880,403,110,543,328,529,875,90,657 }, +{ 102,33,51,77,23,40,128,202,64,13,141,139,196,318,403,153,269,117,99,137,22,4,453,134,59,115,12,10,11,475,0,14,86,65,95,180,15,2,120,1,210,494,342,28,18,165,352,6,36,49,177,217,300,260,82,719,401,421,24,402,386,21,5,457,7,197,730,3,125,37,450,19,291,48,523,17,351,237,27,114,326,93,50,111,38,341,317,25,285,98,26,277,110,54,194,46,9,391,361,275,16,44,31,961,32,308,96,349,899,34,133,854,569,29,485,757,108,105,283,67,144,373,57,509,678,498,221,116 }, +{ 24,35,1,67,0,28,18,16,103,9,68,69,50,65,83,149,12,5,71,133,14,7,22,114,75,96,2,55,189,218,108,48,21,54,223,175,281,251,181,23,46,58,37,124,101,51,336,238,36,70,13,154,118,163,418,10,99,60,745,766,137,537,39,128,38,335,202,141,487,49,361,64,32,45,115,486,155,765,283,109,502,345,230,140,87,430,171,29,269,398,30,267,95,221,543,92,86,820,236,217,6,412,285,17,160,302,77,177,596,61,318,180,458,488,31,52,540,165,352,4,237,105,920,545,125,657,705,273 }, +{ 384,617,940,911,959,855,332,206,282,434,244,253,141,268,352,93,120,144,10,269,137,110,160,201,417,36,143,450,116,203,260,44,811,31,717,951,55,295,318,64,187,261,373,567,202,276,489,258,326,498,98,642,559,180,473,127,22,728,860,217,1,661,219,499,86,23,851,638,8,197,692,341,13,531,165,224,351,523,817,115,9,854,164,125,752,365,28,533,367,51,922,15,564,131,21,96,317,128,82,5,662,699,843,105,871,372,615,237,0,83,386,30,864,509,242,800,901,284,291,551,77,2,776,349,7,704,37,574 }, +{ 93,30,203,473,326,704,137,652,450,31,800,269,848,160,127,190,274,144,254,219,187,625,349,303,166,352,120,372,116,521,224,110,131,752,435,88,217,202,141,260,291,77,367,156,340,228,822,744,5,382,197,296,658,438,180,863,410,44,730,698,578,317,418,1,859,165,850,829,735,494,102,795,616,159,264,921,98,960,373,36,100,23,13,341,128,21,64,258,10,0,523,330,318,39,717,321,778,709,7,968,125,919,942,177,49,86,158,9,365,225,901,478,105,686,531,33,924,888,851,96,2,363,371,442,385,747,691,615 }, +{ 53,73,27,250,26,200,19,297,630,714,472,611,42,122,235,25,17,34,6,436,65,684,106,680,690,80,14,256,113,322,57,813,85,108,64,45,59,648,283,4,161,194,573,445,236,389,128,862,444,114,624,390,469,78,56,51,141,133,2,90,22,84,11,176,491,0,18,255,495,453,416,32,3,412,23,47,145,137,63,29,665,123,95,269,46,378,62,61,614,483,86,361,814,10,5,605,136,396,216,177,112,50,249,619,730,77,129,119,503,13,432,202,179,12,719,285,318,24,597,102,151,183,76,21,130,742,37,209 }, +{ 15,2,1,5,7,3,0,6,141,180,10,4,13,33,11,352,77,197,9,217,14,134,64,12,341,317,365,165,752,40,498,372,269,102,23,17,115,117,291,8,349,22,51,153,196,59,32,237,16,901,36,120,21,260,202,342,961,128,569,143,82,57,864,37,45,318,873,110,93,111,457,18,72,391,386,76,28,86,351,125,137,509,95,31,56,954,326,450,79,48,27,854,139,29,482,19,38,44,546,89,373,99,49,244,90,55,84,719,523,94,403,35,177,54,579,453,277,24,164,922,41,253,30,203,730,61,20,58 }, +{ 254,530,960,613,39,829,688,221,406,190,166,475,827,438,30,9,669,269,180,23,98,51,31,228,21,541,202,274,141,840,318,131,938,105,48,158,127,125,96,44,846,137,453,49,393,219,352,116,13,1,679,421,856,625,286,317,36,308,100,333,310,403,115,890,144,217,791,101,931,616,569,10,386,551,401,0,876,272,910,55,258,88,102,77,327,656,224,629,252,64,468,731,160,385,860,518,926,28,697,344,326,159,33,5,197,93,944,627,128,165,816,293,574,455,187,765,371,364,843,404,242,120,22,284,95,32,345,506 }, +{ 39,9,166,28,158,35,101,30,175,364,68,168,190,0,67,346,194,100,49,88,131,36,333,420,274,310,570,344,404,252,83,289,706,109,55,69,208,1,86,160,137,610,96,65,967,251,438,352,637,336,114,16,577,159,128,254,756,154,345,219,22,64,230,799,228,810,95,24,51,747,224,185,141,818,149,584,768,202,103,419,429,21,826,752,124,530,857,31,656,10,13,169,323,505,237,143,865,562,189,165,793,238,694,535,23,217,874,455,164,116,105,7,197,127,44,547,125,286,180,213,868,539,71,2,703,272,498,115 }, +{ 62,555,548,56,3,507,161,440,34,215,527,136,514,162,361,4,211,17,130,328,383,757,14,84,183,123,205,152,494,11,184,57,585,38,236,202,377,59,54,504,452,129,402,128,176,556,229,880,80,372,300,381,495,40,33,378,37,469,106,266,472,119,12,214,497,248,102,803,403,342,249,73,53,77,245,412,313,51,196,27,153,543,257,485,210,471,76,283,488,99,305,200,421,13,139,157,23,349,432,79,45,90,339,32,117,240,46,179,714,457,292,108,134,250,719,318,41,217,64,21,22,369,710,188,72,133,277,453 }, +{ 126,107,92,356,493,279,359,7,246,97,298,362,392,441,508,60,199,35,423,16,146,132,121,14,43,230,501,232,939,20,649,150,173,5,779,660,414,607,672,314,590,259,534,21,66,140,729,683,387,191,18,71,941,955,953,32,104,49,48,22,38,0,46,319,640,95,819,172,147,167,24,357,28,10,2,13,858,603,324,195,68,598,12,1,345,595,426,61,64,653,522,407,612,470,4,885,77,23,52,236,125,37,33,702,31,687,581,6,118,74,98,711,399,212,40,75,70,376,465,517,360,135,271,105,102,50,192,156 }, +{ 291,141,349,373,372,82,15,260,351,120,922,854,326,217,318,77,450,1,352,898,93,269,523,102,202,21,203,144,13,64,23,304,5,752,137,437,32,51,473,98,704,247,180,177,317,237,197,342,59,457,947,817,494,316,76,33,719,615,300,961,12,36,968,954,475,386,367,268,165,115,86,83,69,67,48,39,22,2,851,341,275,210,201,110,662,576,418,403,391,365,284,241,194,116,105,96,88,54,44,31,7,730,485,205,125,40,117,875,873,864,661,579,498,490,482,468,393,332,308,244,221,190,185,169,160,128,109,100 }, +{ 141,217,352,115,269,180,317,752,341,244,13,291,21,77,23,197,365,5,372,165,51,64,237,349,48,9,4,304,482,102,32,864,28,318,247,137,11,202,308,33,39,98,7,3,1,498,351,125,2,468,437,110,10,82,490,253,120,100,88,954,515,177,93,901,31,12,401,201,0,49,922,72,203,569,55,30,6,342,260,143,22,117,898,717,44,89,35,153,144,854,128,36,386,350,101,68,196,40,373,221,134,96,206,873,391,316,288,241,164,160,105,16,90,579,403,326,645,629,523,421,284,116,65,61,961,59,24,18 }, +{ 78,47,390,108,130,711,813,19,453,412,27,283,730,444,690,196,250,123,236,128,389,503,200,650,183,14,59,4,26,65,472,133,73,34,381,297,153,51,177,57,269,11,53,318,33,216,719,17,194,630,680,322,619,114,113,368,714,46,684,803,432,56,77,29,657,6,480,141,117,3,445,22,603,122,42,235,84,361,90,899,13,64,23,102,249,2,754,524,605,457,99,63,0,475,349,789,40,38,588,210,18,152,106,134,678,436,24,10,25,597,50,529,291,594,401,52,245,95,402,894,129,266,86,471,339,119,523,137 }, +{ 250,297,34,80,472,495,311,64,53,17,667,61,148,27,56,483,469,136,90,73,141,161,45,243,194,3,106,597,527,176,128,751,352,151,436,62,86,874,738,4,209,153,833,491,881,614,396,32,383,84,26,76,445,231,95,5,659,14,887,237,29,378,573,431,947,196,405,58,23,255,119,117,65,11,113,59,33,719,134,814,292,287,57,177,721,240,12,585,611,247,269,51,22,283,200,498,2,583,304,180,19,145,312,165,678,205,202,10,835,349,72,217,114,514,40,555,315,588,137,130,37,875,389,197,207,179,0,13 }, +{ 51,23,551,421,453,13,33,102,77,21,326,153,401,958,308,120,615,196,5,48,202,221,115,692,523,791,403,899,342,4,801,475,210,805,260,107,450,291,966,93,730,576,32,117,842,541,468,18,1,16,203,116,110,697,60,96,126,121,386,68,31,40,2,494,259,125,463,407,137,154,24,704,427,373,218,180,92,10,575,244,35,104,64,175,302,628,351,318,197,160,98,71,817,770,743,670,612,12,859,158,17,590,199,650,7,945,815,752,346,949,851,717,642,597,473,439,402,367,253,252,217,146,56,44,6,3,36,847 }, +{ 98,223,393,363,411,834,478,664,1,691,791,284,156,447,724,914,759,697,293,354,541,807,51,586,421,48,948,668,765,848,264,195,9,163,658,23,801,18,125,551,21,386,96,340,772,909,682,963,730,698,31,453,360,13,371,949,905,770,520,5,621,781,221,744,271,296,116,202,647,857,132,70,118,335,821,44,656,842,367,897,719,121,167,446,32,69,457,450,318,101,100,670,379,638,127,634,144,137,410,761,662,217,846,758,146,401,932,615,75,777,883,538,87,165,33,225,936,591,286,93,166,269,197,812,326,141,105,919 }, +{ 232,7,107,92,14,46,135,172,359,220,314,278,60,5,171,192,2,526,16,620,21,262,52,75,35,32,126,294,29,872,24,132,18,77,246,87,448,571,230,48,1,54,12,58,38,236,50,606,247,86,23,70,177,112,461,298,121,380,97,71,37,888,217,392,66,279,150,356,155,64,13,20,441,108,678,304,751,572,147,226,115,334,140,61,291,785,153,739,579,43,451,178,146,186,947,437,387,394,90,51,330,195,194,875,307,216,352,597,587,357,117,0,269,181,45,603,349,210,199,137,415,128,267,95,366,315,156,31 }, +{ 32,76,2,241,21,14,292,1,476,72,48,5,45,720,50,179,270,214,46,89,90,29,148,129,464,155,17,290,519,38,227,460,205,123,245,350,243,358,52,184,54,257,171,710,249,408,7,400,186,221,405,513,3,36,162,618,12,106,37,288,181,57,502,413,0,263,10,428,316,99,281,207,6,229,4,58,152,64,115,425,430,769,67,741,119,59,22,128,659,308,773,183,23,202,96,86,431,83,75,62,141,9,524,51,16,103,328,645,69,237,497,255,209,217,130,11,24,496,666,28,137,403,528,18,247,536,452,77 }, +{ 15,77,33,102,13,23,51,117,4,32,11,202,40,90,0,1,5,141,153,247,177,128,134,214,288,21,137,269,17,453,3,318,291,403,8,110,82,180,10,59,165,494,22,6,342,197,457,351,64,475,260,9,93,2,120,523,326,48,31,217,115,57,421,386,12,373,44,196,16,19,719,730,25,139,96,352,341,36,961,49,210,317,349,203,125,194,401,18,275,7,24,28,98,817,285,898,365,95,308,901,450,30,99,661,372,86,223,65,854,615,922,402,56,899,697,758,208,103,14,237,116,105,569,37,304,221,704,638 }, +{ 66,74,135,69,6,380,278,267,97,14,2,29,1,75,24,87,324,52,150,38,335,138,357,189,204,172,67,103,25,388,85,7,462,220,83,423,108,550,149,71,603,42,733,571,696,174,26,582,140,36,458,565,16,808,895,802,486,46,238,35,19,70,298,21,18,114,65,226,22,86,60,418,32,251,192,92,64,451,280,273,500,309,95,594,222,501,12,50,5,145,563,398,353,0,889,28,443,48,607,711,641,517,112,262,336,348,37,125,580,596,906,705,622,572,10,160,81,43,63,54,58,133,792,68,620,124,165,294 }, +{ 152,471,4,339,59,188,79,77,11,377,128,94,529,102,33,202,402,111,12,99,51,216,542,452,291,40,474,342,210,196,13,141,184,64,403,37,453,153,134,318,17,177,117,494,23,961,139,5,32,76,431,3,300,257,205,757,497,115,401,275,269,10,229,179,72,475,21,2,86,90,14,57,89,349,1,0,180,157,285,277,148,629,137,266,197,38,36,304,45,217,485,6,498,678,129,405,700,95,569,245,437,734,247,460,22,413,313,352,19,372,775,308,421,292,880,48,237,143,769,503,358,873,488,54,7,618,710,386 }, +{ 15,1,196,0,33,13,2,77,5,10,9,102,217,23,7,6,3,12,117,14,4,134,177,153,40,11,457,291,210,275,22,730,16,115,18,165,21,386,341,719,120,82,180,64,197,51,141,523,317,8,569,365,450,202,32,961,372,260,28,349,342,125,352,95,37,31,899,351,17,128,318,269,48,110,49,403,19,93,901,59,475,401,72,326,24,139,36,65,111,61,237,758,494,90,99,30,854,304,817,44,482,137,391,56,509,898,437,25,308,752,98,38,629,247,76,922,421,86,57,373,670,26,253,70,203,221,801,579 }, +{ 209,106,17,207,45,255,119,655,5,742,306,378,61,62,136,425,263,80,311,84,240,29,790,2,58,56,186,32,3,383,738,243,454,592,869,76,151,14,179,129,290,123,48,72,440,148,21,52,292,64,90,504,287,667,214,46,1,128,54,408,507,50,476,34,27,833,549,57,38,548,155,227,162,86,241,19,70,152,89,205,6,334,171,26,496,483,112,183,181,141,130,400,249,59,245,266,184,555,663,75,270,358,77,229,361,37,215,95,445,4,297,10,211,25,33,666,519,881,11,257,202,73,710,269,237,40,221,180 }, +{ 120,450,260,817,523,15,23,1,51,326,98,13,202,82,125,64,5,351,318,21,31,269,457,32,116,93,115,165,102,77,33,12,95,922,719,30,494,110,44,615,128,48,14,180,141,36,2,730,61,9,137,342,403,899,197,86,49,10,704,551,386,237,8,203,96,83,67,37,7,177,291,352,90,22,18,16,402,196,153,373,179,144,76,39,17,6,961,854,475,898,692,401,241,207,148,105,100,65,50,20,453,349,344,3,217,901,678,341,293,263,247,210,99,88,69,45,40,11,958,801,317,132,126,107,35,24,752,661 }, +{ 116,268,492,918,93,206,203,940,23,51,551,417,523,499,473,959,22,421,8,125,791,692,730,120,31,401,949,10,0,13,899,165,44,386,450,260,867,453,64,9,629,115,36,719,559,341,728,170,55,137,599,299,197,615,569,180,457,28,391,141,1,326,685,301,564,479,475,338,506,86,509,105,638,202,95,817,308,242,253,762,244,2,373,801,670,127,901,21,49,870,951,5,558,237,143,269,37,752,239,12,642,922,403,873,7,352,4,758,365,318,128,18,965,456,32,320,221,14,805,512,317,498,961,16,704,98,33,898 }, +{ 15,13,165,23,197,4,0,1,180,12,11,117,5,8,82,901,719,341,2,120,51,9,523,260,509,7,3,730,141,386,10,450,351,6,33,752,758,134,115,498,352,961,317,365,153,898,14,899,854,64,217,922,873,22,569,326,93,128,817,31,269,237,291,202,21,110,391,37,801,615,28,318,17,457,44,16,77,18,32,98,99,36,49,30,349,401,453,403,102,38,373,958,35,629,116,40,137,125,55,19,482,203,304,242,86,546,474,96,24,144,65,308,475,139,143,247,210,402,89,54,69,177,196,48,485,661,83,734 }, +{ 14,24,69,66,7,108,2,398,267,150,67,97,189,29,149,74,38,71,36,6,83,52,273,388,140,1,135,18,46,172,602,65,28,124,429,302,154,380,336,451,547,16,278,114,732,68,484,324,75,733,92,175,103,118,22,462,0,25,251,357,86,596,55,160,87,705,594,35,60,531,133,467,423,711,236,95,650,109,458,443,298,21,886,5,50,138,26,12,505,238,168,309,314,42,32,10,646,220,49,70,335,192,232,906,420,204,48,20,64,37,43,603,13,19,533,96,85,23,565,51,330,226,550,221,570,208,283,54 }, +{ 330,335,96,839,523,662,367,443,615,418,141,403,717,244,692,576,922,372,1,352,269,217,752,349,64,498,36,854,966,180,822,831,954,873,864,317,284,291,776,201,318,144,69,98,351,678,7,21,5,160,77,203,83,82,442,137,551,2,260,223,622,187,494,44,13,385,128,202,23,475,75,341,901,48,31,437,238,304,247,230,765,93,373,120,393,22,67,251,371,293,125,661,342,859,285,898,163,365,30,32,450,29,110,459,326,934,51,10,197,842,851,399,246,189,800,421,237,0,37,116,221,165,16,579,127,9,321,88 }, +{ 184,257,205,90,245,229,769,524,152,432,497,619,17,57,5,452,32,45,381,266,106,2,59,21,179,4,292,217,313,460,288,1,214,129,14,76,77,3,128,216,48,207,471,339,157,141,710,11,202,38,64,519,369,6,61,209,12,37,119,79,99,123,29,317,72,188,7,62,255,33,58,162,269,247,40,54,102,115,177,51,618,372,476,318,10,89,137,86,249,148,241,263,180,316,352,402,50,403,655,155,19,210,23,94,136,291,308,349,358,237,453,377,111,56,139,425,365,27,341,46,143,277,401,153,588,221,0,186 }, +{ 7,14,16,46,107,32,35,24,70,60,23,307,172,5,18,2,38,87,92,58,13,21,20,10,177,51,202,77,135,48,37,128,0,97,232,115,171,112,126,43,9,220,140,318,12,141,102,71,852,155,4,54,291,22,90,1,269,52,163,33,137,298,192,28,66,64,217,356,61,132,294,278,359,147,349,461,95,29,45,609,448,121,259,186,314,76,474,304,362,17,108,6,150,415,59,400,780,146,36,342,31,275,67,86,246,402,334,279,678,75,247,50,620,30,409,502,39,372,72,49,230,40,494,227,69,465,872,68 }, +{ 140,66,97,172,92,7,267,189,14,314,16,69,298,380,60,135,451,230,150,35,24,71,74,357,423,232,330,38,324,246,192,443,278,563,2,572,877,550,462,126,448,52,893,508,67,501,6,568,29,21,603,46,565,607,83,388,204,633,22,279,18,149,723,733,399,65,48,1,95,64,526,915,5,32,726,28,75,36,841,25,350,87,138,108,68,500,895,10,43,0,251,808,125,104,12,426,49,81,50,20,37,309,517,674,86,802,174,107,103,653,173,582,220,226,85,387,26,55,712,903,241,197,121,237,262,54,711,191 }, +{ 121,167,354,212,132,407,191,107,147,146,271,199,101,446,126,647,195,35,259,18,16,60,55,20,590,465,43,411,68,363,178,198,142,562,9,427,463,92,640,14,346,7,727,798,941,520,364,325,815,5,581,13,1,621,21,23,522,534,0,589,279,158,28,806,706,125,439,109,98,97,118,48,22,694,955,393,604,362,150,932,608,51,105,33,252,165,234,265,108,49,598,156,96,419,818,10,467,197,154,493,12,765,376,120,70,786,169,777,967,102,687,38,202,32,682,246,64,39,31,447,781,612,58,159,61,260,40,450 }, +{ 76,90,460,205,179,257,245,32,288,184,21,45,769,358,316,524,229,241,152,5,57,48,497,2,476,148,720,619,452,266,72,155,1,17,38,432,14,54,243,290,292,227,449,381,12,4,89,247,50,29,313,645,270,59,350,11,129,216,51,217,106,157,221,128,99,58,37,471,64,188,77,214,408,339,141,115,186,3,369,23,52,202,79,46,428,425,308,6,317,464,7,255,405,162,413,33,171,519,496,372,365,341,269,401,10,0,94,36,137,875,318,263,237,62,588,352,123,474,181,431,40,177,291,180,102,61,207,618 }, +{ 147,259,427,178,798,581,878,786,198,534,465,325,929,142,362,20,376,43,107,771,35,481,132,470,234,5,626,146,590,279,97,522,49,70,77,345,21,199,640,450,612,202,13,48,14,102,150,0,33,725,595,846,941,23,22,7,58,195,423,660,501,121,687,126,518,260,117,904,120,858,953,39,342,60,455,1,196,165,125,158,105,159,246,92,28,153,10,31,360,315,346,271,761,683,603,212,18,298,128,711,167,379,318,113,623,817,95,32,291,61,16,134,72,359,108,221,197,115,98,163,767,523,493,191,329,30,87,50 }, +{ 473,778,450,203,855,144,93,617,30,704,141,466,530,330,372,459,201,326,934,321,88,839,254,36,505,403,128,559,83,120,523,217,86,213,131,613,717,110,332,728,344,251,264,352,686,434,82,39,578,317,206,35,625,435,44,795,840,961,539,274,244,116,137,55,662,265,228,863,577,406,96,924,601,564,417,384,351,341,225,95,49,28,800,418,21,831,719,531,367,219,202,31,64,822,224,335,960,968,922,854,829,688,365,197,22,160,410,165,873,752,716,518,456,347,242,125,731,269,180,948,498,478,349,237,98,77,33,9 }, +{ 523,475,899,730,453,51,23,403,719,13,421,457,33,386,196,817,801,4,120,117,153,11,450,260,102,202,515,361,670,165,758,494,125,108,128,961,283,236,99,21,3,880,5,401,32,59,77,543,615,10,6,318,402,221,183,137,650,57,40,7,2,1,90,847,412,247,241,210,207,115,12,208,181,150,133,114,63,42,467,775,389,342,111,56,39,31,30,28,22,9,0,576,558,304,229,216,177,152,123,113,47,29,25,958,554,391,629,968,967,966,965,964,963,962,960,959,957,956,955,954,953,952,951,950,949,948,947,946 }, +{ 1,5,15,2,13,0,7,23,10,3,317,341,6,9,4,365,11,115,33,180,217,77,17,64,197,165,102,117,141,40,14,21,51,32,134,12,8,291,901,752,16,569,22,509,352,237,482,372,143,18,498,153,457,59,128,349,269,125,202,177,961,546,31,391,342,196,45,36,873,57,38,28,37,86,48,386,24,19,139,318,111,95,29,44,403,27,719,304,120,41,110,629,93,72,164,275,61,55,253,99,56,90,49,137,730,210,864,758,35,260,76,50,579,116,94,300,221,26,25,277,326,98,54,475,453,30,79,244 }, +{ 19,119,40,4,27,84,77,56,202,73,102,59,757,33,485,26,300,210,504,494,128,80,862,23,402,63,42,139,880,342,129,32,5,361,25,13,196,51,12,11,2,99,21,6,153,469,123,10,710,53,65,618,64,161,117,736,90,38,22,106,17,803,95,76,0,45,37,14,548,813,250,245,108,297,453,378,162,57,113,460,403,611,255,205,256,383,217,1,235,114,86,742,209,152,292,630,576,240,343,790,667,475,16,48,133,122,18,136,134,85,115,15,283,34,179,436,180,78,29,9,200,605,561,318,49,269,684,495 }, +{ 32,20,13,21,2,38,5,43,29,23,61,12,52,115,90,6,202,37,64,48,95,207,51,81,66,7,25,49,17,74,26,76,178,147,98,46,362,54,22,63,19,14,0,259,128,577,125,97,58,91,77,56,182,65,197,465,376,27,141,427,316,1,241,291,113,878,217,247,312,137,120,4,858,481,142,595,165,31,237,93,230,379,534,482,180,116,86,72,42,11,44,203,263,470,356,352,279,102,84,40,33,687,626,835,786,107,683,260,18,318,24,414,298,468,367,326,304,216,117,105,99,3,933,612,415,347,501,344 }, +{ 339,188,11,377,79,4,99,94,12,542,102,111,474,37,51,33,471,453,152,40,475,342,77,403,59,196,277,139,153,57,134,117,13,775,229,128,401,38,880,23,210,64,184,202,431,115,961,157,300,3,266,72,485,402,89,629,21,54,15,129,177,76,14,162,32,17,216,10,148,275,269,5,757,452,361,477,141,90,205,313,569,494,2,65,179,120,257,381,421,237,197,405,86,488,328,36,318,48,22,137,165,413,50,308,0,1,341,130,82,95,49,457,161,543,245,18,304,260,62,45,285,180,291,41,529,498,125,56 }, +{ 128,283,503,34,318,529,432,176,495,275,231,412,527,291,402,161,381,202,59,3,389,469,177,803,53,585,216,14,269,57,200,17,73,472,27,56,250,136,678,4,152,51,862,361,80,245,11,789,619,194,123,719,401,23,714,84,507,210,77,12,65,322,106,99,436,130,129,46,62,2,13,38,162,369,236,108,33,183,133,457,153,64,483,211,297,741,514,403,114,18,629,961,378,555,440,119,383,597,475,29,453,229,40,165,240,215,196,655,611,556,21,249,117,54,667,134,102,308,814,19,50,86,391,22,0,197,95,26 }, +{ 15,217,13,341,317,141,365,115,23,51,180,349,291,1,120,77,260,269,202,137,21,5,450,352,373,110,0,372,64,33,36,128,177,4,318,351,102,9,197,2,304,854,10,901,7,12,32,165,326,752,40,244,922,160,96,22,523,117,11,48,16,86,661,90,457,82,386,494,403,308,59,28,55,253,247,18,498,134,8,143,153,221,14,6,83,30,196,93,3,37,615,453,401,898,421,817,24,95,961,285,475,719,873,17,35,39,391,730,125,67,237,49,98,811,704,642,717,216,203,69,482,99,342,402,851,50,57,569 }, +{ 13,961,15,4,11,12,457,51,3,37,2,197,5,10,569,99,115,23,6,72,89,14,0,1,134,7,59,33,40,38,165,111,196,76,405,79,139,117,148,498,873,339,719,300,277,485,17,471,157,152,128,21,94,431,32,177,188,509,474,64,45,54,482,730,153,36,629,386,41,22,28,141,901,864,18,180,77,523,9,401,678,437,102,304,210,308,16,775,579,48,31,317,179,413,365,758,352,57,24,341,86,752,546,137,58,318,245,44,27,402,95,899,19,108,269,216,202,49,184,110,93,954,880,56,55,452,358,8 }, +{ 15,13,1,2,0,5,10,23,33,9,7,3,4,6,12,102,115,14,11,217,51,117,77,40,569,153,341,196,317,18,457,22,8,16,961,197,719,180,64,365,165,730,120,134,21,141,899,202,82,31,523,291,125,372,386,28,17,139,93,349,128,304,269,177,110,482,32,342,111,37,318,95,453,579,36,901,59,24,352,450,44,437,137,403,49,260,401,210,237,247,326,817,494,98,99,57,752,19,48,203,30,86,351,485,758,116,402,391,26,898,308,38,27,25,275,801,498,854,65,56,629,76,90,300,922,468,144,35 }, +{ 76,292,5,214,45,32,2,519,710,460,129,179,29,1,90,58,123,249,464,207,205,618,17,14,245,257,72,61,48,263,106,21,358,425,769,241,119,52,184,6,162,186,50,46,38,7,655,148,209,243,128,255,3,155,288,183,290,64,141,454,227,89,77,476,54,115,4,25,59,19,57,229,36,202,269,408,152,99,70,151,130,86,177,75,592,216,720,62,318,12,217,40,26,10,37,27,496,306,33,247,524,311,316,56,497,350,84,51,137,171,790,102,270,23,0,112,11,22,16,452,334,237,432,402,96,180,95,449 }, +{ 76,32,72,21,38,4,54,89,57,17,179,12,14,99,148,45,23,59,51,90,488,3,11,241,401,2,428,37,543,152,205,528,453,128,5,421,13,115,129,77,10,474,245,184,350,670,449,413,1,569,137,79,403,629,475,328,308,221,155,464,0,361,123,743,202,460,214,257,33,40,64,794,292,165,405,770,805,41,476,62,162,270,229,358,86,285,36,402,775,316,341,94,197,50,576,106,431,720,46,29,540,217,139,773,119,838,48,15,216,181,657,177,290,514,288,7,457,227,961,9,22,102,247,828,6,141,365,180 }, +{ 98,223,393,1,834,284,791,264,697,724,293,909,772,905,541,478,51,821,807,363,897,48,682,421,765,447,411,730,801,410,163,948,386,96,9,31,963,23,21,691,664,453,125,5,382,100,13,521,949,551,656,44,116,770,686,670,639,221,39,367,914,265,166,144,719,335,812,848,371,0,101,842,318,321,127,88,252,520,662,329,354,32,759,438,33,698,93,202,593,201,286,156,450,658,281,115,165,49,401,120,604,586,82,2,22,36,225,217,77,744,10,498,141,102,615,180,118,435,69,30,921,404,326,197,433,475,83,70 }, +{ 341,13,23,509,762,638,569,242,901,629,165,8,197,873,10,961,506,456,391,499,116,338,180,457,492,206,12,51,115,268,143,365,951,1,93,965,642,867,417,37,2,253,546,64,5,203,3,498,758,752,719,0,401,15,352,44,31,7,36,244,86,4,141,386,734,237,6,22,308,730,55,844,164,918,473,326,125,82,564,949,898,551,940,791,120,38,9,260,523,137,661,373,559,110,14,854,959,615,317,11,54,33,102,692,269,99,351,903,89,870,740,217,708,170,824,40,801,728,864,817,717,160,128,28,117,776,479,77 }, +{ 818,230,755,443,352,420,1,2,244,50,14,5,38,46,29,36,114,218,65,96,22,133,52,181,58,0,17,28,21,103,75,54,45,86,67,175,48,171,7,12,323,137,24,285,208,51,487,6,283,18,10,70,23,155,32,83,194,361,3,503,163,389,328,128,223,37,803,532,16,19,168,735,69,13,124,61,202,160,186,433,9,115,484,27,236,514,238,782,95,25,754,108,64,657,112,141,281,220,412,289,55,756,401,394,584,151,308,49,545,851,822,4,227,717,866,334,269,646,403,402,26,400,87,35,745,366,99,143 }, +{ 481,878,32,202,5,21,23,269,13,318,494,142,77,51,70,1,182,557,141,137,33,291,58,178,415,465,61,48,590,259,922,115,2,929,640,403,207,884,4,260,120,87,817,626,534,349,342,102,195,0,132,351,59,427,252,109,35,7,961,678,345,247,153,72,845,158,169,49,12,10,6,196,112,798,450,687,279,841,713,475,457,128,40,146,28,3,416,290,265,75,767,854,771,947,795,753,704,637,631,597,592,581,546,509,493,354,352,341,326,316,288,285,241,237,212,197,159,90,54,52,46,38,37,36,17,14,39,9 }, +{ 15,1,5,4,2,13,11,341,0,3,7,12,10,6,21,365,9,180,32,134,317,197,33,23,37,117,40,165,17,77,217,498,8,752,153,901,64,102,569,141,873,51,14,961,196,115,59,110,352,509,22,128,57,111,120,143,125,72,38,48,372,36,291,308,349,99,139,31,90,202,260,269,457,44,16,89,76,49,55,401,342,237,27,93,177,94,82,18,45,29,326,28,19,386,221,351,137,86,277,546,391,41,50,35,403,453,54,164,318,719,474,629,373,203,98,95,475,854,253,304,148,24,450,244,56,758,542,300 }, +{ 25,26,119,42,19,6,27,45,122,84,469,4,17,790,814,113,80,76,59,73,483,2,29,611,128,32,202,40,1,77,90,862,106,56,209,33,240,0,684,136,102,14,292,416,5,311,11,504,196,318,123,680,378,255,12,129,161,22,690,151,53,117,63,179,667,10,85,72,61,115,65,210,402,396,57,141,64,614,134,757,153,137,62,18,99,445,51,269,66,177,7,3,24,710,256,648,36,655,235,38,23,306,58,618,70,491,48,454,21,403,742,361,49,34,86,494,275,383,342,28,300,145,13,74,112,52,297,245 }, +{ 14,7,24,2,1,16,69,6,38,67,108,22,65,28,124,0,46,18,29,86,66,35,83,5,71,398,36,12,168,289,140,95,610,189,150,149,10,21,92,756,52,302,23,109,97,20,584,25,50,267,194,64,49,51,32,60,103,55,505,13,429,172,128,273,420,158,37,458,19,547,118,48,75,115,137,74,135,9,185,164,143,388,154,202,26,701,650,251,133,336,17,114,169,68,230,236,43,54,141,244,671,253,703,105,208,90,3,160,159,278,99,462,314,403,380,87,389,175,357,324,484,318,232,708,125,799,451,886 }, +{ 128,51,202,23,141,120,403,15,64,13,318,82,10,269,99,33,12,197,475,453,260,153,137,165,196,0,3,402,351,5,494,1,22,14,110,117,180,102,93,17,2,31,37,38,125,9,326,450,49,21,86,44,401,457,7,6,36,352,115,18,77,523,237,28,134,95,285,386,421,719,32,48,342,98,11,54,203,730,57,341,961,373,139,8,854,361,757,111,898,45,4,40,308,194,65,16,922,277,41,880,678,116,291,24,498,19,27,391,143,56,217,899,59,569,30,79,365,775,50,503,208,55,144,817,61,105,901,94 }, +{ 16,24,35,18,71,68,9,0,65,189,1,7,133,50,69,149,60,28,103,101,108,537,67,118,230,75,114,23,335,55,167,21,124,92,12,191,181,433,13,39,140,5,14,48,223,64,212,96,51,218,443,281,487,154,141,163,22,217,99,37,70,565,2,115,49,267,58,54,394,766,46,246,545,83,30,128,10,330,820,202,32,361,137,622,125,238,237,100,121,77,165,412,175,87,143,352,399,171,317,86,126,745,146,486,418,177,36,291,269,318,283,336,105,302,398,695,4,98,197,180,31,345,251,271,109,309,430,38 }, +{ 50,2,1,46,14,29,38,52,171,67,5,58,103,96,36,24,218,133,223,83,114,236,45,70,54,181,163,186,108,155,75,28,65,238,334,151,18,433,160,745,328,0,366,112,532,48,516,17,514,61,832,400,281,21,227,22,760,19,6,69,754,766,412,12,7,309,545,409,27,361,283,137,16,220,675,480,55,86,765,822,502,552,32,10,307,99,956,285,25,113,9,398,323,37,51,800,26,388,394,64,891,128,124,243,549,828,3,458,194,208,35,646,95,262,23,311,150,966,820,866,894,149,13,115,87,430,80,287 }, +{ 21,32,5,76,72,14,17,2,3,38,54,89,45,51,1,12,23,4,10,48,90,137,36,148,221,401,22,0,421,179,115,86,99,543,11,453,13,37,128,270,46,241,285,29,290,64,428,57,6,361,202,59,540,50,403,328,114,475,528,65,155,449,77,308,794,569,181,7,805,27,40,141,292,133,33,576,263,129,514,205,341,9,413,350,208,19,838,629,323,28,430,480,119,657,474,214,741,123,245,402,102,720,15,770,476,408,494,56,425,106,269,62,207,775,243,152,477,670,180,318,197,405,165,95,58,281,18,697 }, +{ 434,384,268,144,940,855,617,206,959,911,332,116,93,203,137,489,282,244,141,120,36,44,160,269,253,367,110,450,10,127,202,276,417,219,98,258,326,131,260,31,64,373,201,9,187,318,692,473,22,224,523,817,143,86,352,1,55,30,23,51,28,295,567,105,559,499,261,717,811,0,125,951,180,8,115,13,217,128,551,39,165,49,96,341,284,77,21,851,728,564,662,498,317,386,752,48,351,531,5,642,365,197,83,661,237,615,800,291,242,15,170,164,494,82,95,638,704,349,37,854,228,7,32,24,935,968,35,16 }, +{ 2,5,1,15,7,13,0,10,6,3,180,217,23,9,141,11,317,4,341,17,352,117,197,14,77,33,64,165,134,365,115,12,102,752,237,40,498,153,291,32,372,51,22,21,8,349,901,269,16,196,457,45,569,128,36,143,59,57,509,125,27,38,19,342,86,202,864,873,120,31,546,318,110,37,28,961,29,164,177,95,48,244,111,137,93,391,18,719,139,44,49,82,386,629,54,24,482,56,99,26,453,260,50,579,76,25,304,35,98,253,326,41,55,277,210,72,275,30,730,437,90,523,403,203,351,61,79,450 }, +{ 113,25,2,29,6,833,45,61,145,7,32,74,151,0,42,1,210,128,177,5,19,4,72,14,64,106,655,59,22,122,26,112,174,66,40,77,738,209,525,402,138,90,148,20,483,104,684,141,51,76,17,27,425,18,21,416,23,10,202,95,16,255,52,13,115,624,318,137,102,311,33,269,85,81,49,887,87,746,544,491,275,86,119,790,454,690,65,24,9,222,216,665,291,117,80,204,58,243,134,48,476,814,217,46,349,287,70,28,285,43,348,36,84,342,11,757,194,91,207,315,31,38,73,153,192,355,135,300 }, +{ 116,268,918,551,203,692,31,940,403,791,421,206,417,93,499,523,299,44,8,473,23,51,805,22,13,450,120,475,202,0,959,730,386,125,599,326,137,9,10,401,899,105,1,576,817,559,453,564,165,393,494,21,28,36,456,5,127,949,64,670,728,638,391,242,685,2,260,762,457,197,180,615,569,141,170,253,308,963,49,115,341,492,55,143,719,479,873,37,18,4,86,7,77,506,48,244,801,867,95,318,269,901,512,98,951,33,6,301,958,642,338,30,352,870,39,221,365,12,16,395,373,24,237,629,164,102,159,239 }, +{ 107,612,126,132,362,146,259,199,279,660,493,590,121,20,939,683,534,43,147,941,376,35,595,953,649,581,60,470,640,955,356,522,5,97,195,150,407,49,465,16,92,14,7,687,359,298,22,858,246,0,13,360,21,48,18,427,271,167,423,191,10,441,325,392,32,598,929,28,33,31,178,414,1,77,232,173,55,230,156,125,24,68,23,95,345,4,904,626,105,212,319,98,786,783,70,61,202,142,44,702,58,71,40,314,37,198,51,64,2,623,163,159,819,93,446,158,59,346,357,12,501,118,260,46,663,116,120,102 }, +{ 15,13,1,2,0,23,5,4,3,77,102,33,10,51,6,7,9,115,341,12,11,217,342,317,14,117,40,22,365,180,120,8,569,18,196,165,457,141,21,210,197,64,177,31,291,153,16,961,59,523,817,453,719,450,134,730,93,260,352,44,269,275,49,386,401,32,901,110,82,28,17,629,125,349,139,475,899,24,128,37,326,111,752,95,202,36,318,403,372,498,216,90,308,247,30,98,482,137,86,237,116,615,300,48,65,203,19,57,351,55,391,509,99,38,734,922,468,244,144,221,854,304,579,373,39,143,758,148 }, +{ 53,27,161,17,469,73,378,527,136,250,383,19,862,495,62,26,56,200,297,106,84,585,440,80,34,14,436,128,119,45,4,3,472,123,129,813,504,240,483,361,59,444,205,65,611,5,202,548,108,255,742,514,283,78,814,113,179,162,690,57,402,183,38,555,714,6,245,390,122,54,42,803,184,25,61,33,630,318,209,12,194,64,77,684,11,141,328,757,503,269,99,236,2,102,389,51,22,618,176,152,257,453,47,21,48,210,86,680,40,381,148,133,217,880,650,215,46,10,130,377,18,0,412,497,23,114,13,229 }, +{ 209,45,17,106,207,119,5,255,454,243,263,425,290,655,306,186,84,29,62,61,2,408,136,58,742,378,21,56,311,240,3,592,48,32,383,50,52,80,227,790,270,46,171,14,72,440,148,287,334,76,659,400,666,179,504,496,869,64,155,241,129,1,123,54,38,214,738,75,663,162,90,141,89,221,151,292,57,358,237,507,513,130,34,548,152,70,205,37,128,183,211,184,667,41,229,328,476,266,115,555,181,86,549,405,6,281,163,269,215,12,96,245,11,220,502,720,257,36,313,430,288,180,833,40,202,165,449,27 }, +{ 152,4,452,59,128,471,529,339,79,216,11,188,377,77,291,202,318,94,102,402,32,33,99,5,90,51,269,76,349,12,184,257,542,474,17,177,111,141,37,21,342,210,23,205,275,678,13,72,403,38,285,3,2,40,64,229,588,57,10,769,494,48,134,45,372,196,117,217,129,6,497,1,148,460,757,245,453,475,0,137,153,157,89,139,7,115,961,292,179,498,304,524,266,197,14,629,431,477,405,775,288,437,180,15,165,214,237,86,401,308,119,123,54,22,221,120,9,162,27,619,300,62,317,316,31,488,277,880 }, +{ 15,1,2,5,0,7,3,4,6,13,23,115,9,12,51,180,8,317,197,10,961,901,11,22,77,21,752,33,202,141,110,341,14,16,217,134,120,102,31,165,365,40,93,269,457,352,64,44,28,18,37,351,260,117,569,82,308,125,32,196,49,36,153,719,128,482,318,99,17,401,326,137,450,403,203,111,177,730,386,291,55,873,523,373,98,30,237,24,453,89,48,95,221,475,39,59,116,372,349,105,144,139,509,143,72,96,758,391,898,494,854,86,342,899,210,629,57,468,247,90,304,65,148,83,817,421,160,20 }, +{ 951,752,638,811,642,253,351,180,10,197,341,901,873,352,110,244,143,762,165,8,898,55,564,141,15,365,854,499,82,137,417,498,509,36,535,922,479,559,206,661,373,317,282,115,31,22,338,160,93,569,164,260,717,217,391,86,533,33,44,1,28,9,242,965,728,120,116,77,64,968,21,102,203,125,37,117,506,30,13,386,5,4,531,269,40,911,153,23,0,169,384,2,326,372,105,196,851,170,134,109,704,332,268,349,96,127,48,291,32,758,237,318,24,177,202,35,11,961,401,39,308,83,3,629,51,210,12,434 }, +{ 6,197,350,74,262,841,509,26,47,115,13,196,583,903,165,4,235,138,50,308,21,130,749,324,675,19,38,331,391,145,711,569,33,75,241,453,734,64,153,223,52,558,236,468,99,220,34,70,112,11,117,546,237,125,3,27,32,1,42,134,409,51,78,25,163,29,14,648,23,645,180,820,46,2,85,108,65,773,802,624,122,394,341,785,22,730,95,386,606,57,412,247,923,316,66,498,357,221,630,133,457,59,853,90,53,226,873,632,48,113,719,629,45,889,17,307,141,766,69,12,37,444,83,171,54,600,5,765 }, +{ 125,391,165,867,558,386,221,758,23,457,21,51,13,197,401,308,963,115,961,97,719,77,791,743,451,603,949,48,180,670,770,341,89,120,730,352,291,148,450,426,607,304,7,403,393,66,64,350,316,217,134,135,14,421,74,247,177,50,380,24,696,236,172,87,629,10,141,475,144,35,901,801,523,453,138,509,467,456,241,210,150,98,18,565,357,267,103,582,545,342,301,278,237,216,20,16,99,69,903,650,551,412,389,283,81,32,298,739,543,498,370,365,317,309,300,260,170,140,116,85,52,37,33,30,25,5,273,203 }, +{ 14,1,46,2,24,16,38,50,5,69,58,35,7,75,18,67,54,48,0,155,513,171,163,61,103,45,29,52,430,270,37,223,21,70,12,28,9,780,32,267,60,290,83,227,71,36,666,767,22,189,140,807,10,72,96,65,108,181,64,186,220,309,17,335,92,394,23,592,243,89,536,663,115,281,51,6,474,55,68,112,141,400,128,133,87,13,425,99,741,236,95,675,278,230,76,221,114,86,263,113,820,552,502,27,269,202,49,760,537,149,262,328,408,90,366,137,150,207,77,357,315,307,218,241,19,148,25,66 }, +{ 23,51,13,115,453,12,0,2,4,10,403,1,202,5,401,475,15,21,457,59,77,165,9,3,37,99,32,11,197,719,308,6,14,64,7,569,17,629,961,318,180,22,33,494,120,18,730,141,40,102,269,217,177,57,16,128,523,450,341,8,90,421,386,237,28,48,125,19,117,31,247,402,72,210,899,221,260,291,134,89,342,317,365,509,38,24,391,216,352,468,817,153,54,36,45,49,27,196,56,326,82,65,76,304,349,139,50,25,86,275,44,137,482,372,670,498,26,734,546,62,95,758,29,41,46,93,351,79 }, +{ 129,84,17,27,56,495,80,378,19,548,123,162,161,53,469,618,73,26,504,106,40,257,205,59,3,183,184,862,4,136,62,6,128,202,14,77,11,65,769,5,527,108,45,57,383,361,2,497,250,249,200,130,23,34,22,90,402,483,245,240,12,51,214,38,0,139,25,99,64,318,102,152,32,210,300,10,297,757,21,494,880,775,114,710,111,33,54,29,460,403,452,36,42,133,18,61,86,141,436,177,814,269,13,194,119,179,49,28,342,453,217,95,115,514,229,556,76,137,37,1,742,283,485,401,503,488,475,24 }, +{ 28,109,49,9,22,67,168,158,39,185,159,420,1,55,0,83,35,95,194,272,86,105,69,103,36,114,169,327,50,254,208,175,65,584,286,323,535,346,251,345,797,30,131,756,374,12,333,533,128,2,218,68,96,133,344,160,101,23,64,289,7,597,189,24,646,577,874,896,13,5,601,51,46,503,531,837,16,238,747,627,115,14,347,10,98,310,789,137,124,21,202,127,164,578,54,799,141,154,230,532,547,31,312,708,285,480,37,810,637,596,48,143,336,100,389,835,252,439,237,38,518,912,219,424,44,239,253,868 }, +{ 242,391,456,116,23,13,492,8,51,341,401,165,93,206,499,457,867,338,268,569,417,509,386,22,1,762,479,638,10,629,918,758,64,551,203,730,901,719,12,31,197,791,115,5,86,14,125,949,0,559,37,2,642,951,873,959,237,961,692,55,170,752,870,120,44,180,940,9,141,564,523,3,308,36,7,4,15,899,450,365,728,137,21,473,253,898,558,143,128,453,740,164,801,260,903,6,685,202,403,670,965,54,114,28,854,326,817,844,352,95,82,498,11,923,244,98,299,922,239,110,38,317,105,599,373,661,160,99 }, +{ 211,162,248,130,556,57,507,4,305,266,183,41,152,361,11,229,129,471,62,38,377,313,300,514,77,339,184,157,381,59,128,452,99,3,328,40,202,123,54,210,440,494,369,555,342,136,117,542,402,757,64,548,139,23,196,188,880,457,775,33,153,56,14,102,432,13,177,205,257,497,17,12,37,291,51,89,403,215,961,111,141,90,349,216,488,269,485,803,477,180,165,115,10,475,437,383,79,197,95,21,84,134,503,421,86,453,318,308,1,670,76,194,719,618,106,32,629,15,730,65,22,5,245,94,214,45,482,288 }, +{ 92,7,97,298,140,16,126,232,314,60,246,279,35,173,230,71,107,14,43,508,423,150,779,653,441,607,66,189,359,501,24,362,20,172,104,387,356,21,48,38,18,399,199,330,5,674,192,877,81,191,729,517,74,672,426,939,560,633,0,267,2,649,69,121,149,392,324,135,462,22,95,29,46,52,125,598,37,723,707,49,10,357,68,345,6,32,830,98,64,1,702,380,118,28,900,12,695,251,861,885,493,783,603,146,65,715,61,55,278,36,236,273,138,33,75,25,31,124,175,221,293,83,165,763,712,451,414,319 }, +{ 15,1,2,5,0,7,13,6,23,9,3,12,180,4,51,115,8,901,457,117,14,165,22,341,82,120,141,10,37,197,961,31,21,11,202,351,64,260,77,365,110,16,134,28,217,93,269,33,44,36,569,18,719,308,450,317,128,102,125,137,32,629,153,98,401,55,352,30,318,373,49,116,898,730,48,17,752,523,196,237,386,24,95,86,326,403,291,99,453,40,39,72,38,177,89,203,873,391,144,247,349,498,899,59,734,90,475,372,54,494,421,143,482,304,854,105,758,35,210,65,76,244,160,216,221,83,45,546 }, +{ 403,18,0,102,25,523,64,6,91,85,42,74,342,32,24,13,51,306,95,49,22,33,475,151,681,880,421,128,899,750,397,214,122,757,730,77,28,519,288,247,23,5,817,805,317,879,861,673,273,177,145,21,120,52,283,81,275,701,577,453,104,59,202,193,697,636,401,287,249,216,207,196,180,165,138,125,123,118,90,84,60,48,43,587,260,389,16,10,4,1,351,326,318,933,804,635,498,280,237,197,186,172,153,148,137,134,117,99,61,29,9,671,289,958,838,814,579,312,238,124,65,56,847,719,654,650,457,424 }, +{ 56,65,554,33,561,18,84,123,63,64,343,194,0,90,49,22,6,27,19,289,240,129,73,659,431,214,475,523,370,368,233,899,701,287,257,95,85,28,102,183,736,650,467,256,153,25,207,124,108,80,32,24,120,26,389,874,718,635,51,525,891,752,751,730,648,614,498,496,450,249,237,209,184,177,162,114,59,45,29,235,77,42,817,497,444,137,112,74,53,352,511,681,630,643,196,947,942,847,764,719,696,651,615,610,603,602,543,457,412,386,337,326,312,288,262,260,247,227,226,179,152,139,134,119,117,105,86,76 }, +{ 127,98,31,293,299,395,44,9,105,0,49,599,284,28,276,116,242,685,159,456,22,763,125,935,272,492,158,1,623,393,109,144,201,39,36,95,18,51,24,320,137,23,286,55,16,512,916,489,202,21,662,301,268,367,327,371,35,761,567,13,434,65,7,101,918,616,2,5,141,737,506,870,12,64,131,68,30,48,900,948,86,128,295,10,219,239,269,910,403,627,338,578,143,14,37,124,160,203,318,384,170,244,165,261,96,347,254,713,963,168,457,237,187,93,67,154,421,221,253,401,344,424,164,479,6,386,83,855 }, +{ 1,14,5,2,46,50,38,58,171,61,45,155,7,48,69,270,290,24,21,29,75,52,16,67,54,666,32,663,227,72,502,0,425,223,18,592,89,17,35,243,37,207,76,186,103,263,36,163,96,83,741,6,408,10,400,22,181,28,9,428,12,536,64,221,220,70,262,281,23,267,115,106,65,807,292,309,119,148,474,449,394,128,141,86,241,3,655,430,51,189,476,140,431,541,587,95,334,738,675,90,114,13,780,108,71,720,19,133,27,202,335,413,4,767,112,77,25,405,513,179,659,99,218,787,55,180,528,151 }, +{ 23,51,13,453,457,12,719,401,961,4,629,730,99,475,115,2,11,14,403,17,40,5,15,165,1,3,64,0,10,57,33,21,77,569,32,50,37,308,7,386,9,16,38,670,197,59,41,217,128,494,46,6,758,62,22,775,65,45,18,86,48,29,72,899,514,361,328,139,102,247,153,54,56,421,468,79,523,95,108,757,196,52,19,317,117,482,342,341,24,734,509,210,202,180,177,237,488,402,114,36,134,880,76,498,90,275,111,34,28,291,67,20,474,120,743,125,82,391,130,752,490,437,405,318,277,27,141,89 }, +{ 968,967,966,965,964,963,962,961,960,959,958,957,956,955,954,953,952,951,950,949,948,947,946,945,944,943,942,941,940,939,938,937,936,935,934,933,932,931,930,929,928,927,926,925,924,923,922,921,920,919,918,917,916,915,914,913,912,911,910,909,908,907,906,905,904,903,902,901,900,899,898,897,896,895,894,893,892,891,890,889,888,887,886,885,884,883,882,881,880,879,878,877,876,875,874,873,872,871,870,869,868,867,866,865,864,863,862,861,860,859,858,857,856,855,854,853,852,851,850,849,848,847,846,845,844,843,842,841 }, +{ 2,1,29,103,75,52,14,67,46,309,6,83,70,238,38,24,108,220,218,133,74,96,262,36,114,87,388,26,50,25,366,236,69,160,112,5,65,58,66,394,19,145,226,7,532,135,163,42,18,45,150,545,458,433,891,331,357,594,17,28,412,27,294,418,86,278,21,124,398,149,732,894,324,537,283,223,273,222,71,12,606,739,16,646,547,138,267,48,696,171,137,151,0,175,602,800,22,37,487,181,99,208,32,194,287,785,336,64,23,13,113,55,95,335,54,97,323,154,61,711,128,68,302,118,10,308,600,484 }, +{ 7,92,71,97,140,60,150,16,298,24,189,230,14,149,423,35,508,314,18,43,279,232,66,399,273,246,251,38,607,69,126,172,517,674,2,173,28,375,74,467,104,68,0,809,20,823,336,118,267,175,135,108,191,154,21,345,501,796,36,52,125,653,29,81,330,107,124,362,356,6,387,55,359,46,779,302,192,22,5,575,48,67,877,462,10,388,441,9,566,723,783,221,1,65,49,398,101,37,278,702,83,91,357,705,392,12,109,121,236,426,380,32,212,695,443,86,596,103,868,608,560,165,830,167,13,558,25,541 }, +{ 51,23,202,120,141,13,1,260,128,21,269,450,77,137,318,48,115,165,15,32,102,5,197,64,180,494,82,351,326,125,291,817,12,349,342,98,523,403,203,93,7,33,854,352,2,31,14,719,457,6,110,144,44,4,386,177,730,96,116,308,99,221,9,217,10,153,17,210,922,453,18,16,402,237,90,704,37,36,117,25,421,11,615,95,20,898,373,30,475,40,401,391,19,317,8,3,304,498,576,69,285,901,275,223,293,247,196,86,899,134,83,341,127,59,45,39,365,216,692,372,50,0,801,752,367,163,139,100 }, +{ 77,102,33,13,177,23,51,141,202,64,40,128,115,4,269,59,318,6,217,137,210,291,0,7,2,1,180,196,14,22,10,95,153,11,117,125,165,15,86,352,197,134,90,403,216,275,3,16,9,18,237,453,494,342,49,31,19,139,25,65,28,5,17,317,349,93,36,304,475,26,82,12,98,44,341,27,120,365,57,24,20,110,372,386,21,247,457,719,194,402,498,116,29,730,99,260,8,143,144,523,164,114,569,48,32,111,326,285,208,391,401,244,30,509,312,961,300,752,56,160,105,203,34,450,546,67,482,170 }, +{ 101,9,363,676,264,18,411,682,604,905,520,821,271,167,621,647,364,121,252,404,118,39,166,848,781,265,100,16,382,664,447,212,777,478,354,146,907,812,132,446,360,724,0,60,463,759,24,329,23,1,88,71,35,936,68,857,195,21,48,593,865,639,932,156,897,31,98,96,51,191,13,286,333,125,656,49,694,30,254,105,591,55,806,562,109,158,44,438,419,272,521,124,154,407,274,5,65,310,553,28,144,691,33,116,159,127,93,32,77,22,67,50,410,37,538,108,706,393,115,83,36,92,12,199,327,223,10,418 }, +{ 144,203,326,382,166,96,822,418,438,93,859,88,921,1,367,141,744,269,349,110,576,473,83,77,410,23,966,21,403,120,692,39,494,274,521,317,291,217,615,523,855,303,817,13,639,264,800,32,100,909,691,225,36,478,914,765,506,5,498,652,44,435,265,321,260,160,910,551,404,137,48,772,202,897,453,450,208,101,960,254,31,863,342,286,190,51,30,593,831,616,419,730,682,98,340,372,341,197,69,33,9,625,724,848,686,284,466,704,656,223,180,102,335,125,617,352,285,363,0,662,244,530,919,812,393,374,351,318 }, +{ 21,13,180,23,32,115,48,125,197,191,165,51,5,199,237,146,12,225,18,16,93,901,350,271,22,241,375,0,71,118,408,49,447,264,126,1,167,31,24,522,302,98,65,64,575,864,569,92,566,247,744,86,58,391,352,713,212,141,60,44,9,4,88,562,459,308,303,203,202,100,45,37,17,2,818,463,360,316,919,897,698,586,478,363,293,221,213,103,72,40,691,909,608,558,509,166,68,35,727,340,517,217,724,629,546,467,446,341,304,156,120,108,11,640,288,110,7,734,296,150,591,914,346,354,321,317,269,114 }, +{ 15,13,23,51,102,0,8,77,1,5,12,33,9,4,2,10,180,82,165,197,115,110,18,403,202,22,120,326,457,7,11,351,260,898,141,342,14,373,401,901,961,64,36,386,3,291,453,31,16,40,28,93,21,6,352,59,44,99,27,341,450,217,719,49,117,48,125,475,128,37,391,308,153,95,269,24,318,177,854,730,203,615,421,98,30,32,38,137,922,317,498,704,523,57,817,509,56,569,629,116,899,133,83,365,758,105,752,144,661,196,304,638,494,134,300,670,206,402,221,210,208,86,535,143,65,532,109,35 }, +{ 77,33,102,64,202,141,128,51,40,196,23,13,117,318,269,153,134,1,177,115,10,342,137,180,210,2,0,95,6,139,403,86,14,22,15,7,217,291,4,352,165,197,36,59,237,275,3,11,5,494,65,125,49,9,453,475,16,19,28,18,120,82,216,17,402,31,93,110,260,326,12,341,194,349,401,203,98,25,99,27,24,457,44,317,365,498,372,26,351,285,719,143,386,450,300,21,752,391,116,29,312,38,114,304,111,244,164,961,509,57,247,569,523,144,308,373,901,34,421,96,56,160,437,35,20,678,32,8 }, +{ 174,104,544,151,624,74,525,25,644,66,29,177,636,416,0,204,750,122,216,6,81,45,186,222,319,138,2,145,287,112,665,192,64,59,243,7,77,32,355,22,715,128,784,17,173,20,311,135,789,280,52,33,549,113,879,4,227,21,194,90,5,141,491,102,86,42,95,43,137,58,12,27,496,275,65,529,614,11,348,678,304,651,402,580,712,503,269,422,49,37,14,318,210,673,396,202,792,10,18,500,869,36,148,85,426,247,405,681,19,226,97,825,72,16,196,40,61,609,597,115,24,217,233,51,28,881,91,153 }, +{ 372,141,304,352,947,954,291,177,217,269,349,128,318,437,498,77,678,202,864,64,102,115,86,210,873,137,751,597,247,13,180,5,275,32,16,35,21,950,752,92,197,83,87,7,457,160,776,70,33,24,179,36,317,245,165,126,107,569,288,717,95,402,237,23,263,108,774,156,546,509,340,37,18,12,946,342,872,75,800,244,114,103,851,735,365,341,146,121,99,60,579,312,120,1,195,354,296,140,888,71,51,260,223,418,758,622,537,473,363,196,98,69,10,526,48,820,817,765,704,586,450,316,246,208,148,96,90,50 }, +{ 200,161,714,53,73,27,472,383,17,440,34,585,62,56,136,250,106,78,527,322,19,862,361,4,3,514,80,84,390,14,176,179,236,378,162,377,129,548,202,47,469,495,217,26,11,494,128,757,555,453,402,412,130,880,328,507,257,183,51,45,5,38,300,184,123,497,54,12,57,33,444,59,556,283,205,245,108,485,297,209,803,152,342,40,119,99,318,452,2,46,102,211,23,196,64,229,65,77,215,684,21,814,6,240,0,153,368,403,90,730,475,13,117,133,61,37,317,305,32,255,813,22,504,181,503,29,436,95 }, +{ 32,76,72,21,38,14,241,89,54,428,449,5,45,148,37,181,90,179,2,17,221,350,12,292,46,129,48,476,155,1,794,99,477,205,720,3,770,50,464,773,4,540,308,36,57,460,270,245,413,743,184,214,741,328,115,23,123,474,137,257,10,358,11,0,281,431,29,488,421,405,162,51,288,59,64,401,710,536,430,152,290,128,218,519,22,316,697,552,7,587,86,670,361,487,6,227,13,52,618,133,249,543,77,106,62,165,769,141,243,202,403,229,114,453,263,67,475,745,341,119,197,207,497,285,9,40,180,920 }, +{ 128,141,202,64,102,33,23,77,51,13,196,318,269,153,2,3,180,165,40,137,5,15,1,6,403,10,117,139,197,86,352,134,14,17,0,19,494,210,120,342,22,7,402,237,453,291,177,475,125,115,93,217,95,21,12,82,260,110,36,457,11,65,341,450,31,25,27,194,99,9,4,326,498,275,961,349,26,49,111,401,317,44,203,391,351,277,38,28,386,18,421,37,752,164,16,143,29,285,98,24,48,678,114,116,32,373,509,300,244,208,54,719,56,59,365,57,8,50,546,144,20,523,30,569,372,898,90,308 }, +{ 39,137,96,840,30,202,9,0,613,88,406,669,100,141,180,576,160,28,49,530,403,1,269,22,228,822,829,679,856,190,244,166,219,352,816,966,765,827,36,55,68,83,128,274,418,23,318,98,44,442,35,10,253,258,51,863,77,31,317,251,21,876,158,494,475,213,95,65,116,254,859,268,125,48,13,16,931,187,367,131,805,574,105,5,365,800,102,177,93,115,33,224,127,242,120,110,291,924,217,960,144,64,842,616,165,531,385,351,101,159,276,839,778,203,201,492,109,67,24,284,748,860,345,692,295,421,272,456 }, +{ 180,352,141,752,1,901,269,365,115,5,217,2,15,4,317,23,197,7,13,341,0,244,3,253,6,51,498,202,21,318,31,372,873,165,44,77,98,9,33,10,116,137,237,93,482,125,64,864,105,12,32,48,349,509,128,131,22,120,579,11,143,8,102,569,717,37,391,177,260,127,308,110,28,30,291,450,40,559,49,39,401,160,203,144,14,437,373,564,72,24,453,403,386,546,421,96,326,16,95,36,148,661,951,247,533,494,219,109,201,159,55,961,251,475,728,468,642,117,254,221,134,18,811,153,210,82,345,224 }, +{ 1,67,28,50,46,2,103,83,14,65,114,24,0,38,133,69,36,55,18,75,9,54,124,29,22,283,7,218,5,238,16,154,35,52,96,160,480,109,108,547,12,68,398,429,646,323,181,732,175,220,21,361,171,71,335,236,389,418,70,394,48,49,149,86,58,866,531,87,309,366,37,484,208,328,251,118,194,6,10,302,412,487,420,189,336,23,168,545,800,51,803,433,185,137,128,163,754,39,45,505,169,285,596,486,13,503,533,60,101,155,95,64,32,289,570,223,158,267,927,140,745,516,17,115,514,346,956,99 }, +{ 180,352,365,317,115,217,752,901,341,1,253,141,873,2,15,4,0,5,197,3,244,308,951,31,7,498,318,44,6,372,291,165,269,202,98,137,120,127,160,36,116,373,105,260,482,13,131,33,509,110,51,125,77,39,569,349,304,437,9,11,8,450,96,64,22,21,391,221,23,93,638,717,28,219,12,421,10,403,187,83,17,102,49,661,564,851,401,128,247,811,351,523,117,535,546,468,224,201,86,35,559,48,16,148,494,134,143,579,968,922,854,817,800,551,475,55,801,758,728,615,196,177,153,144,14,32,30,533 }, +{ 32,5,21,347,13,95,49,713,51,48,197,23,107,60,126,64,237,180,153,77,165,241,33,379,850,1,263,296,196,195,4,121,134,132,102,28,115,22,117,217,0,291,16,841,929,928,652,534,660,39,493,247,31,279,18,50,36,626,150,90,76,40,407,883,509,362,349,260,9,356,125,10,177,92,441,340,259,35,24,752,351,199,65,11,71,809,546,953,933,854,312,75,61,56,37,30,7,598,207,44,423,372,298,522,783,590,354,156,645,608,591,939,937,638,498,450,437,391,359,303,273,86,57,342,316,59,640,446 }, +{ 341,365,180,901,317,115,752,15,873,217,564,82,951,197,110,165,0,1,141,351,4,3,482,352,6,372,2,12,269,13,10,559,253,854,5,468,7,244,282,23,535,18,898,14,661,417,349,308,318,102,33,509,125,811,704,36,143,77,964,28,498,326,237,137,51,533,692,638,38,475,31,22,9,642,867,391,30,8,202,120,203,966,758,373,338,206,24,569,291,922,494,403,332,144,116,49,44,697,55,450,386,128,943,842,768,728,706,405,346,299,295,261,260,258,242,160,148,39,27,26,19,17,11,50,48,46,843,634 }, +{ 45,17,106,21,227,209,62,243,5,155,32,3,290,38,255,119,54,270,14,2,207,181,587,48,263,12,794,29,46,552,540,186,659,37,430,408,770,496,721,50,454,136,84,52,221,425,56,76,308,828,99,697,400,328,115,123,741,80,488,1,528,474,401,57,218,281,41,129,541,513,421,36,487,128,10,787,61,241,378,477,543,64,51,742,306,133,240,413,11,72,428,4,165,734,23,152,655,453,211,34,920,311,59,90,236,137,214,58,162,629,431,179,832,341,6,366,583,89,77,202,313,361,383,317,514,86,745,365 }, +{ 16,24,35,18,50,7,71,75,60,14,69,0,9,1,189,108,68,67,21,181,28,12,48,223,92,5,23,140,46,103,51,133,13,2,267,230,54,163,149,65,22,335,70,281,10,32,55,96,87,37,64,171,128,394,114,141,502,58,115,486,236,99,820,98,766,202,38,137,83,309,118,246,269,49,36,95,125,191,155,167,121,430,39,218,101,77,6,150,237,126,641,774,31,318,221,487,180,443,177,433,251,545,220,565,388,29,86,72,352,399,165,217,552,112,61,105,537,17,852,45,44,30,212,175,124,89,307,102 }, +{ 127,308,293,98,165,395,258,219,13,286,23,629,401,51,115,301,569,197,457,276,512,391,509,105,616,239,924,338,22,734,170,55,961,295,31,758,169,910,272,567,116,763,201,320,944,341,143,261,237,506,180,479,873,365,141,185,206,36,242,86,374,762,498,546,913,131,44,64,923,327,843,601,386,332,492,160,125,860,317,654,964,900,284,95,28,634,943,164,137,10,901,282,224,740,468,456,144,109,841,558,719,268,120,417,535,384,299,844,482,903,110,93,9,1,935,662,578,217,253,928,730,187,393,2,752,244,531,434 }, +{ 748,957,840,213,669,539,466,88,30,251,863,321,217,679,190,137,93,144,317,530,352,831,228,230,160,617,800,689,219,203,816,96,418,202,36,473,258,406,141,871,326,83,855,752,120,854,778,82,44,100,187,201,1,435,224,351,345,719,335,116,110,443,274,28,310,55,21,450,332,382,822,574,86,931,494,531,365,31,839,128,39,180,341,367,898,23,613,498,372,731,860,9,410,926,197,704,5,817,131,69,35,125,434,166,22,944,318,924,856,268,64,48,567,244,206,291,922,523,269,32,876,717,98,49,13,349,169,859 }, +{ 5,48,21,14,1,2,54,50,36,430,38,32,181,270,45,281,12,72,17,67,46,0,290,218,99,22,28,83,76,155,24,541,37,10,513,89,114,65,58,133,61,103,96,488,51,221,425,263,3,9,328,29,23,487,697,207,741,115,18,86,745,160,428,474,148,408,6,16,502,7,64,171,137,794,108,52,920,477,842,227,55,236,552,543,13,119,514,361,449,202,238,828,536,128,308,292,476,243,592,90,241,186,179,666,285,4,27,655,663,480,421,401,106,208,141,165,433,528,532,19,834,95,283,197,11,180,720,403 }, +{ 13,23,51,115,217,33,77,0,4,2,9,317,102,141,7,11,1,10,180,5,40,202,22,197,3,6,352,365,12,269,341,165,14,18,16,28,64,15,59,318,177,403,752,31,24,196,308,32,372,125,128,291,498,137,17,247,153,21,49,401,453,349,98,117,44,8,95,237,901,36,86,93,494,342,475,30,482,210,468,457,304,873,569,90,105,143,421,391,386,37,509,39,134,139,110,116,35,275,244,144,120,326,55,961,19,546,203,46,864,27,719,221,111,65,164,253,285,216,127,402,730,50,437,38,67,20,288,54 }, +{ 13,23,165,15,37,54,134,12,117,38,457,51,64,197,99,115,153,89,961,719,33,10,82,509,14,128,120,237,3,196,308,86,141,328,0,1,629,72,450,277,139,102,523,386,351,77,8,401,65,4,546,95,155,202,180,21,2,498,391,40,352,7,5,32,11,6,730,474,31,475,110,137,899,854,453,922,569,291,114,108,22,898,44,9,177,403,148,49,361,342,285,260,514,269,93,17,758,901,210,864,479,59,34,29,28,67,217,494,318,236,179,90,76,56,50,18,242,417,528,488,206,98,413,94,817,789,468,402 }, +{ 5,21,32,14,2,48,17,3,1,12,72,38,45,54,51,10,36,22,76,23,0,89,540,13,137,86,37,4,430,270,50,114,11,221,99,285,115,64,6,61,46,361,29,181,290,65,58,403,208,155,28,133,480,281,148,128,323,453,657,401,514,541,754,421,697,202,90,9,7,475,241,263,40,56,328,308,95,59,207,576,805,165,838,513,57,27,402,19,425,18,775,488,119,283,218,741,428,341,24,141,77,33,794,408,227,197,102,194,52,179,832,55,180,494,269,365,449,164,236,350,745,318,171,859,244,474,108,880 }, +{ 202,318,77,291,128,275,102,33,269,342,177,210,402,678,141,403,494,40,20,196,0,137,7,23,49,32,64,216,4,416,104,139,285,59,352,43,61,66,13,304,234,90,22,475,319,450,11,349,117,300,113,5,153,58,947,17,112,21,6,115,120,70,544,38,16,142,2,315,194,134,95,18,498,9,74,597,237,51,329,884,25,12,453,864,24,789,173,415,639,859,155,277,52,81,86,222,178,10,48,560,14,230,665,198,97,31,355,557,65,1,186,105,817,111,39,226,57,546,121,29,147,28,15,87,60,96,265,523 }, +{ 1,24,46,2,14,67,69,75,103,38,35,50,52,83,29,108,18,16,71,220,149,394,309,236,189,70,96,133,171,54,68,366,28,58,5,238,181,163,87,7,433,0,335,60,218,114,251,487,65,267,537,36,328,418,223,9,486,55,516,262,112,150,155,12,388,48,21,45,675,175,336,22,409,118,37,186,281,140,412,696,6,124,25,514,151,294,61,99,154,10,334,32,17,273,92,135,160,283,760,278,458,227,766,64,307,19,86,361,398,230,552,641,532,400,137,565,23,502,345,51,13,95,765,26,66,72,128,399 }, +{ 15,1,5,2,13,0,7,23,6,3,180,12,51,4,9,115,457,165,197,21,8,14,141,901,37,752,117,16,77,10,32,120,202,11,317,217,110,961,22,33,365,341,82,269,719,93,352,31,102,18,128,153,134,28,260,48,569,64,137,40,318,196,386,351,509,17,44,30,326,125,730,308,450,49,177,36,95,453,89,72,98,99,203,873,523,401,498,403,59,291,116,38,24,629,372,90,349,76,55,391,373,144,758,494,237,244,96,482,475,54,854,39,468,143,45,139,105,221,247,86,899,50,148,253,35,210,304,421 }, +{ 28,65,124,14,0,154,24,67,69,55,175,7,9,429,46,2,109,35,149,336,68,1,189,83,114,251,108,16,133,398,484,103,36,18,38,22,50,267,420,140,283,289,71,570,158,236,389,101,505,230,86,346,185,39,12,169,168,799,194,118,49,596,29,732,782,302,309,5,533,52,252,95,388,419,535,21,439,458,705,75,797,160,412,6,10,54,531,218,92,345,208,96,159,610,48,60,64,323,756,105,37,23,646,238,51,128,329,886,547,278,13,650,637,32,172,135,364,164,143,584,602,115,701,601,137,333,399,443 }, +{ 162,403,56,775,129,880,161,527,99,3,17,40,33,475,23,4,361,128,196,14,200,183,34,202,102,184,548,402,383,53,130,153,757,494,27,257,108,453,38,12,136,117,51,485,123,64,57,65,19,585,141,73,13,139,421,134,229,106,11,80,556,469,670,84,59,152,62,78,714,412,378,77,5,495,21,54,236,488,497,2,6,90,514,86,111,730,22,180,26,46,507,440,95,269,37,472,115,32,401,45,283,452,618,0,328,47,18,29,266,390,10,211,165,899,250,24,300,862,719,504,133,543,197,318,277,50,176,457 }, +{ 151,29,112,2,58,311,186,52,70,113,315,45,66,74,61,631,5,87,287,243,491,209,1,869,6,227,614,135,7,307,75,80,27,145,496,226,25,454,17,14,549,26,845,19,32,46,73,106,294,163,155,64,255,659,849,667,632,644,592,72,220,331,21,334,222,172,42,69,400,48,76,138,396,337,148,635,50,86,611,445,128,171,97,122,141,95,738,119,16,37,38,4,207,67,425,290,409,53,24,65,262,89,90,12,297,278,192,461,137,22,624,36,20,483,881,84,292,684,43,10,833,56,651,655,114,263,204,115 }, +{ 6,74,75,1,70,66,138,29,25,85,26,42,87,220,52,2,135,226,222,802,324,112,145,357,103,19,278,108,380,67,114,309,235,14,500,69,451,133,606,280,38,24,582,83,65,262,163,86,97,394,294,267,486,96,50,36,889,388,603,641,58,256,32,895,238,223,853,45,122,594,46,537,64,21,204,150,27,335,792,102,7,115,337,218,13,418,71,33,160,632,5,189,696,571,308,461,95,565,16,545,331,125,4,137,134,153,113,117,17,35,558,54,287,149,22,171,18,711,174,630,247,63,12,23,0,194,462,90 }, +{ 15,13,23,51,1,120,0,180,202,5,260,9,2,102,450,115,77,7,141,12,21,269,318,197,137,523,403,6,165,326,33,351,341,817,110,901,342,128,365,36,14,4,16,457,308,401,18,494,8,48,32,59,64,82,352,22,475,10,217,386,730,317,28,93,37,3,373,854,453,719,752,31,615,24,44,30,421,291,11,210,221,39,899,99,96,961,55,86,98,40,116,177,402,922,160,898,244,203,35,576,17,569,117,509,144,391,90,49,372,704,349,153,873,285,498,253,275,125,89,143,300,196,72,247,67,95,629,127 }, +{ 5,45,17,14,46,2,50,48,186,181,227,61,29,38,155,281,54,52,80,106,400,209,21,58,3,171,243,487,540,32,328,311,103,218,133,430,255,62,67,12,828,454,36,56,536,236,27,1,207,496,787,119,697,366,114,37,19,108,6,760,513,541,600,587,592,84,745,842,99,920,96,502,151,76,13,26,270,583,263,86,221,115,83,832,666,51,23,136,34,334,65,10,290,72,308,137,663,869,739,361,514,25,721,738,794,4,659,543,89,401,667,11,64,576,378,148,22,24,834,0,474,357,73,483,754,516,41,53 }, +{ 18,16,35,60,68,121,265,158,159,24,329,105,9,132,167,252,327,709,101,55,286,39,21,71,146,49,7,109,374,23,22,126,604,107,419,333,271,14,28,1,48,0,191,120,92,212,20,310,272,890,553,118,5,326,137,199,260,455,51,95,446,320,13,32,450,259,170,627,621,639,2,10,195,647,128,98,364,301,557,463,43,37,239,77,576,848,64,100,351,82,102,125,65,285,202,12,354,6,363,346,178,344,197,165,493,407,147,29,523,242,907,96,538,932,403,33,279,916,97,704,36,31,402,520,318,156,912,846 }, +{ 467,650,389,108,283,56,412,123,177,216,670,619,349,269,33,475,899,775,453,503,789,401,678,65,543,51,196,403,730,128,84,23,194,523,13,421,719,576,457,11,597,153,880,141,249,847,3,801,117,817,57,133,18,0,202,114,59,24,150,32,386,64,40,95,291,4,183,450,130,524,162,5,554,152,90,22,9,361,134,236,102,17,27,120,304,19,961,629,210,432,21,770,86,16,14,10,77,165,46,28,594,381,377,240,137,26,229,494,947,372,602,342,318,275,125,98,630,743,701,605,184,103,97,63,50,49,958,444 }, +{ 514,11,377,328,361,3,4,880,507,403,485,57,130,14,757,152,38,102,300,211,556,215,54,176,236,62,229,56,494,40,585,555,266,34,183,59,342,12,162,440,453,548,51,37,77,402,488,305,184,196,542,421,775,471,123,527,210,369,313,33,457,136,719,23,202,231,13,128,153,381,629,452,803,543,129,412,157,17,248,339,111,84,139,497,475,205,99,119,32,828,188,177,961,349,383,117,46,89,79,730,216,504,277,401,161,134,308,291,322,76,249,283,72,65,64,21,2,22,670,503,241,41,257,90,108,618,472,94 }, +{ 3,555,62,266,507,215,130,440,99,514,229,152,471,40,57,139,403,12,56,548,305,33,475,38,313,775,361,14,123,211,880,328,196,102,23,556,381,184,136,757,377,77,277,54,183,494,453,421,4,11,205,349,291,129,162,452,34,236,84,17,369,37,59,485,497,111,401,402,51,153,157,477,585,13,670,128,117,339,176,161,41,488,248,202,383,300,457,249,119,76,432,46,342,134,79,188,89,214,2,474,72,527,961,21,32,308,719,543,165,177,257,730,412,133,413,64,283,216,210,245,106,618,803,90,15,629,115,460 }, +{ 120,318,450,260,77,15,202,13,817,51,269,5,33,494,922,128,1,326,102,23,403,523,137,141,21,177,351,40,342,48,291,82,854,153,125,64,7,615,32,196,22,704,210,402,98,4,475,12,373,115,93,2,96,453,285,44,275,349,36,61,31,116,216,859,197,117,49,28,16,899,678,203,165,59,90,180,139,50,24,6,144,217,95,898,692,170,110,45,18,17,10,0,730,352,72,37,207,457,576,341,237,35,20,9,661,372,194,961,223,214,958,949,811,805,791,551,424,391,365,244,242,221,208,160,127,99,89,76 }, +{ 23,1,15,51,13,2,5,0,7,6,180,12,9,115,21,3,197,165,4,457,386,120,141,33,202,453,14,730,523,719,401,37,40,32,341,8,31,403,260,82,450,352,16,48,110,269,317,77,217,308,44,137,22,102,18,365,318,901,93,351,421,117,475,752,11,326,28,391,49,98,153,498,128,99,64,30,569,10,899,509,36,196,961,24,221,59,39,89,177,758,854,134,494,116,17,629,90,817,670,468,86,247,72,95,35,105,96,203,482,55,373,125,372,873,144,210,922,291,38,244,237,898,54,50,20,349,615,65 }, +{ 15,180,351,317,82,115,365,217,141,898,10,854,901,197,143,77,23,752,341,352,33,110,13,36,64,102,51,4,1,260,253,244,120,9,21,5,22,40,498,55,165,137,117,28,11,873,372,922,482,134,59,0,72,153,196,160,32,48,202,3,2,961,90,12,35,811,164,291,177,349,31,86,30,308,7,125,509,642,450,128,6,139,17,96,210,237,89,951,523,342,457,93,730,57,37,39,661,16,83,437,373,546,269,49,18,14,531,8,717,318,111,45,24,569,247,76,533,719,221,67,326,282,468,386,203,52,44,38 }, +{ 104,289,707,66,712,173,97,214,90,64,426,20,874,414,568,43,65,32,194,715,7,204,312,560,74,500,192,835,324,0,38,376,819,861,147,319,95,636,22,86,729,21,470,879,288,5,107,526,52,81,178,2,751,49,10,519,142,595,427,247,77,356,232,249,4,750,237,597,28,885,784,36,889,858,51,202,802,14,135,298,115,13,59,524,808,1,330,325,23,92,180,359,392,31,24,583,681,61,18,259,172,48,177,123,825,798,37,357,12,208,33,174,387,362,140,102,35,76,40,17,137,198,11,216,600,16,671,91 }, +{ 84,65,56,18,194,249,0,108,123,643,847,554,63,524,416,141,453,24,26,403,22,511,467,630,475,128,73,137,33,9,80,899,95,64,370,76,45,16,133,42,289,19,650,214,27,240,730,719,210,196,119,114,49,494,402,304,102,90,32,11,10,588,561,283,235,202,523,183,25,736,609,580,576,500,457,433,357,349,343,209,124,60,57,39,28,3,1,757,150,23,368,670,51,597,947,813,667,659,529,431,291,287,243,236,233,216,179,177,153,134,122,117,112,89,85,72,31,30,6,421,389,165,125,895,874,619,519,361 }, +{ 21,350,308,13,346,197,826,352,101,841,570,68,165,509,23,115,100,694,749,569,903,51,212,401,9,0,221,734,391,154,777,252,88,124,610,265,237,39,558,125,48,30,217,230,421,35,289,468,64,55,535,475,213,546,175,909,1,403,382,166,589,28,645,812,419,180,32,706,98,593,410,703,759,141,317,629,65,241,83,194,818,773,22,321,752,689,923,341,962,96,671,699,158,95,16,329,429,854,264,724,190,439,31,722,316,72,900,144,10,93,247,49,831,676,372,24,223,36,553,269,293,69,365,490,191,5,639,251 }, +{ 92,16,60,24,7,71,126,18,35,140,330,14,246,46,50,267,121,146,236,108,75,220,199,571,394,68,309,150,132,107,314,448,230,54,232,633,5,366,118,2,21,9,278,38,388,37,87,64,1,181,328,12,641,55,70,672,582,726,48,526,0,622,172,516,563,86,69,32,103,10,133,36,156,167,28,65,101,135,195,52,171,950,149,22,830,189,99,649,191,451,67,13,29,262,294,606,83,545,58,517,462,271,23,572,95,163,696,128,675,594,620,392,514,77,785,45,155,192,217,653,335,279,522,212,237,51,177,565 }, +{ 15,82,898,365,33,77,341,180,115,901,21,10,102,197,55,5,4,351,13,165,117,36,11,1,217,23,317,141,40,752,120,153,450,134,253,12,2,260,143,196,873,51,89,457,32,3,177,352,349,854,372,244,160,59,7,719,961,64,202,96,6,110,291,137,523,498,111,0,210,482,28,31,30,17,951,125,318,22,128,509,139,811,730,386,169,304,9,391,37,164,48,326,269,203,93,373,237,148,535,342,72,569,704,308,247,38,533,49,98,922,86,734,109,14,45,275,216,95,817,403,44,437,57,899,661,41,39,968 }, +{ 16,24,35,71,18,68,108,140,189,69,103,60,267,50,149,118,230,7,1,133,191,92,46,167,9,75,246,0,2,443,309,236,486,335,14,54,212,330,218,516,65,67,38,394,641,21,181,55,28,101,48,83,399,366,563,412,545,114,220,696,388,51,328,13,23,5,64,458,273,124,126,12,238,487,52,345,37,537,87,121,29,915,723,150,175,32,302,154,163,361,146,375,674,22,10,171,271,96,514,251,86,433,70,336,36,571,622,223,906,796,237,726,398,602,283,39,262,115,702,565,891,58,695,562,199,128,894,49 }, +{ 60,20,16,43,7,71,18,92,118,14,35,628,608,68,154,28,375,126,175,107,0,279,150,173,22,356,97,149,566,55,153,169,49,140,69,33,13,230,117,38,23,10,362,51,2,77,783,414,421,109,298,246,359,196,125,124,446,102,104,386,722,66,21,1,601,575,621,326,439,429,12,392,134,32,882,192,74,345,551,533,419,185,336,191,4,232,37,273,595,81,189,791,314,202,158,917,576,467,570,6,5,302,48,422,115,801,319,197,165,677,535,925,420,387,9,423,399,251,517,515,403,291,199,260,694,553,64,40 }, +{ 187,258,871,295,434,489,219,201,224,268,839,384,699,940,110,261,116,160,131,44,36,574,228,144,141,93,137,567,406,244,926,120,98,253,260,373,64,442,206,269,127,908,318,55,31,911,959,855,617,10,1,531,332,523,202,613,203,661,326,352,860,217,717,367,276,21,51,143,180,96,23,105,13,450,22,385,533,284,662,197,851,86,77,251,30,115,83,9,48,816,164,282,811,317,365,39,856,165,351,843,669,473,899,341,125,922,902,752,291,817,372,918,345,417,177,728,82,293,242,951,498,968,854,386,559,15,349,49 }, +{ 66,97,7,172,192,712,232,204,324,387,74,426,448,526,104,173,107,568,560,43,356,825,808,500,729,135,359,52,707,92,32,95,330,20,636,64,65,22,140,38,138,81,298,2,289,715,885,5,802,392,29,49,14,174,0,889,91,86,226,348,90,750,861,6,357,280,314,312,126,214,246,792,353,10,36,24,380,580,21,835,37,28,414,58,230,69,222,595,362,194,673,16,278,12,77,85,33,46,874,18,819,61,60,681,147,858,888,612,600,13,241,25,501,102,48,35,67,189,87,71,40,4,583,519,779,1,237,150 }, +{ 15,1,5,341,4,13,0,3,2,134,33,12,11,7,10,77,6,9,21,23,40,197,8,32,365,37,17,901,111,102,51,117,180,317,961,153,217,165,59,14,22,16,82,141,31,457,94,202,115,291,453,403,196,57,36,372,475,318,719,28,349,18,401,72,269,99,48,386,110,498,64,494,120,352,93,351,54,139,27,509,474,177,45,44,30,670,90,421,326,76,56,89,128,898,642,629,304,260,450,19,482,137,29,55,391,873,342,24,49,730,203,62,373,143,210,79,752,41,39,758,661,817,157,152,98,523,579,402 }, +{ 0,24,35,28,124,68,9,154,65,16,109,149,55,175,158,71,39,252,7,419,14,108,101,346,168,22,185,289,429,49,18,420,169,67,439,671,703,336,302,1,159,92,610,962,484,118,333,95,69,2,677,398,344,100,364,810,272,345,105,46,329,114,60,535,265,327,577,30,10,189,21,12,254,286,133,194,83,23,140,793,553,86,36,50,570,637,13,103,5,722,310,51,374,230,48,38,64,32,747,706,505,701,273,251,150,164,601,455,166,627,143,634,125,283,424,239,458,799,128,246,267,388,547,6,137,96,37,538 }, +{ 7,92,14,16,46,140,220,60,35,24,2,126,38,87,75,278,71,172,262,135,52,314,107,54,294,246,394,150,18,50,330,29,309,267,230,171,1,70,232,108,21,5,121,620,97,236,69,622,32,572,563,950,366,409,58,199,12,48,64,328,37,571,189,146,448,132,66,68,155,872,112,192,461,67,441,181,675,279,13,298,28,226,0,451,23,163,423,606,9,582,128,20,86,526,36,334,307,55,380,462,888,357,335,61,43,10,22,45,83,337,331,186,353,359,103,726,133,633,95,51,65,202,72,74,785,114,141,149 }, +{ 92,7,126,16,314,172,60,140,35,135,278,14,232,2,107,246,46,150,330,24,66,38,71,230,52,380,97,298,279,448,563,192,357,262,199,121,87,18,582,309,462,441,29,75,74,132,220,5,146,451,526,324,423,50,21,550,69,32,68,226,508,1,70,37,633,64,12,108,606,267,48,572,493,54,189,726,366,0,392,359,22,95,43,58,571,603,28,10,20,86,236,55,171,600,36,9,388,163,65,607,387,6,67,49,294,649,830,583,356,362,90,622,394,620,167,259,939,149,443,83,580,114,25,103,118,672,61,45 }, +{ 235,26,53,297,6,436,73,113,27,445,42,25,250,611,90,19,65,214,648,614,85,624,289,64,122,200,491,684,416,32,17,194,45,665,145,34,80,95,573,151,112,322,86,680,714,315,630,106,690,14,29,472,255,141,396,56,312,57,22,247,76,209,4,128,61,288,123,84,352,249,11,874,108,3,138,5,217,256,70,119,59,74,0,835,283,161,114,751,269,597,525,389,136,77,51,10,40,115,287,47,2,52,78,176,881,62,13,524,519,23,137,33,133,28,46,177,746,311,18,236,12,63,180,453,237,631,179,243 }, +{ 352,141,752,854,36,1,351,217,230,244,661,110,816,258,160,224,180,219,82,201,269,567,144,295,260,373,922,93,120,203,489,64,35,202,406,317,206,699,137,116,268,871,717,10,839,251,434,228,864,253,326,96,21,131,9,30,83,384,44,442,39,450,574,69,332,48,318,418,728,898,55,127,187,642,365,86,276,88,28,341,831,498,22,901,443,100,367,523,128,531,940,213,5,689,748,190,860,679,0,31,811,843,559,164,7,669,143,662,851,77,564,372,165,335,98,800,261,2,959,349,284,170,115,291,824,345,50,855 }, +{ 126,60,16,35,107,18,191,121,68,92,279,446,598,463,375,43,167,493,7,20,118,199,212,566,14,150,97,28,575,608,589,55,407,101,246,154,146,24,346,21,0,175,48,71,362,815,354,49,628,132,939,5,467,22,649,10,9,1,356,259,147,271,149,783,439,140,23,108,32,109,230,376,683,125,13,621,345,441,363,31,51,647,612,273,124,562,173,695,768,105,38,252,2,727,169,818,640,195,755,590,637,158,722,364,104,37,953,535,12,44,64,66,359,33,202,806,298,46,419,98,221,95,77,185,660,399,653,520 }, +{ 1,15,2,5,4,3,13,0,23,11,7,6,341,115,77,51,10,9,12,33,180,197,102,40,217,165,141,365,901,21,317,32,202,8,14,64,177,22,269,352,59,17,291,31,569,318,125,210,16,93,386,453,196,457,401,18,494,403,153,752,37,28,475,961,117,110,498,120,342,523,139,116,629,44,326,134,349,203,98,372,49,128,275,57,308,48,237,391,719,30,509,24,95,36,86,19,421,260,758,247,90,730,615,216,137,373,450,873,111,482,144,29,899,304,817,670,25,300,143,801,55,20,244,82,45,27,39,242 }, +{ 51,23,13,202,21,5,403,137,32,141,318,128,1,120,165,125,12,48,15,475,269,180,453,197,115,64,401,33,2,7,450,6,523,308,260,421,221,4,494,37,386,99,16,14,196,457,730,237,93,817,102,77,61,82,352,9,719,98,110,10,20,899,326,19,18,3,117,90,17,391,402,95,0,341,31,11,217,25,961,629,351,96,134,72,49,153,30,26,569,801,203,372,40,509,24,50,317,285,27,758,116,349,342,70,59,58,76,39,44,291,89,57,45,29,854,28,22,144,177,35,194,576,86,670,54,365,678,247 }, +{ 131,716,371,224,737,385,219,254,616,924,836,187,258,98,761,916,944,127,39,105,442,578,9,49,272,31,688,44,116,242,137,871,908,159,395,518,890,28,293,284,574,202,623,51,160,23,0,201,276,36,827,938,839,22,333,125,456,299,286,144,109,438,158,13,95,910,64,30,829,228,327,166,101,1,860,926,613,96,86,512,846,310,21,295,10,406,55,318,252,320,93,843,128,301,627,567,203,165,48,662,492,100,268,37,531,457,221,190,434,403,68,384,421,239,393,261,902,35,533,169,170,120,110,260,244,308,5,506 }, +{ 15,5,1,2,3,4,7,0,6,11,13,10,180,197,12,217,341,141,33,134,77,17,165,9,352,40,365,32,317,64,498,752,102,21,117,901,59,14,237,8,23,291,349,36,864,269,372,153,57,37,82,961,22,115,569,196,120,509,873,342,202,48,51,351,110,16,93,45,31,457,125,19,76,72,111,244,27,260,128,143,318,79,546,56,139,28,18,86,44,98,90,391,94,61,55,854,95,38,386,29,482,898,49,99,89,253,210,177,137,730,450,35,221,84,25,304,954,758,326,922,474,403,203,20,373,50,247,523 }, +{ 66,74,192,173,222,226,174,7,29,712,52,204,353,43,20,500,2,138,145,97,104,673,426,355,6,64,560,87,0,580,331,172,414,90,32,25,337,65,22,49,135,825,861,112,280,5,287,81,95,525,86,21,707,42,38,792,415,85,750,889,356,36,324,819,10,632,232,45,526,330,1,107,544,91,319,140,746,151,294,194,58,92,28,14,67,289,4,636,115,37,17,12,262,715,470,16,155,59,27,61,233,387,298,18,376,568,216,26,122,69,77,113,24,23,888,70,13,114,51,75,448,729,11,609,102,348,312,33 }, +{ 786,259,5,534,590,493,465,929,581,21,279,941,49,13,612,132,32,362,23,147,61,48,35,121,939,626,683,146,178,107,771,687,408,347,713,345,58,427,126,70,18,60,4,197,878,150,344,640,379,1,195,841,33,120,263,356,51,509,522,260,28,22,0,115,55,10,376,663,207,350,199,16,423,142,407,221,156,246,623,595,241,105,31,903,298,11,71,68,95,92,64,17,40,450,441,90,167,308,165,518,44,783,316,247,953,360,351,98,30,102,82,65,159,955,290,87,817,134,20,182,39,24,230,117,59,501,315,569 }, +{ 278,14,135,2,140,16,267,69,92,24,7,46,35,189,38,52,71,29,60,75,357,172,87,309,66,380,262,74,324,230,462,220,1,451,150,335,226,571,108,18,97,50,443,606,563,103,67,246,550,6,641,126,330,70,388,366,5,83,149,68,21,486,48,314,25,12,54,565,298,394,600,622,32,423,294,232,37,582,236,222,572,28,65,251,603,36,192,64,58,145,0,171,331,55,950,853,95,133,86,22,10,114,112,399,620,138,448,26,163,353,508,500,583,96,45,877,238,42,726,9,785,121,279,181,696,72,19,223 }, +{ 165,13,308,391,197,23,401,509,758,457,569,51,629,734,180,115,873,317,901,961,3,453,719,29,46,546,80,34,2,482,217,468,181,867,48,106,45,341,52,17,14,287,297,5,730,445,386,552,428,62,221,186,15,11,171,56,50,12,38,365,250,328,133,61,211,540,153,215,119,53,41,903,670,58,743,311,99,305,231,176,27,236,4,54,130,881,403,151,6,600,57,136,84,40,764,787,114,475,862,472,469,73,32,26,33,400,227,137,21,1,255,196,270,281,155,65,752,635,440,405,326,161,110,549,477,430,396,592 }, +{ 1,14,22,2,28,7,67,168,65,24,49,0,35,46,55,50,95,69,12,159,36,105,16,114,109,158,5,83,194,103,38,133,239,169,9,289,164,185,18,424,6,21,10,708,124,170,320,283,312,389,29,68,51,23,420,143,189,347,505,336,37,175,835,892,86,149,108,64,874,54,13,577,251,48,32,654,756,547,96,71,115,301,286,128,154,202,236,344,160,253,484,638,52,75,208,230,747,610,308,39,218,533,137,140,267,141,374,3,345,31,127,237,799,98,601,597,244,272,323,125,398,401,118,17,327,99,412,101 }, +{ 34,453,130,196,322,3,14,236,361,47,51,377,11,730,514,711,4,412,153,57,161,440,485,102,176,59,162,108,17,62,283,757,202,56,136,38,328,880,77,494,184,12,719,128,402,403,200,23,78,117,27,475,21,300,40,381,54,472,33,53,183,152,129,99,2,714,452,13,585,803,80,210,862,555,383,73,46,123,37,139,84,670,556,503,548,6,507,421,5,111,527,29,19,342,229,457,26,775,134,318,469,133,115,90,106,257,277,401,250,497,205,1,543,266,211,542,629,899,45,488,215,217,65,72,275,339,432,32 }, +{ 48,18,23,21,35,60,16,24,156,51,13,71,121,221,5,132,46,141,163,7,1,43,271,202,115,92,411,178,340,137,447,308,32,363,150,698,125,223,195,781,541,318,147,142,28,22,0,108,360,621,401,241,2,463,354,49,658,586,67,303,269,97,20,761,50,296,146,70,65,763,867,691,638,182,647,93,82,10,767,167,31,914,670,290,128,107,75,61,225,98,64,4,120,14,12,758,110,29,949,457,316,165,105,95,293,30,668,932,180,39,446,724,743,666,421,391,372,351,114,96,86,66,591,352,33,942,922,459 }, +{ 13,165,629,457,961,569,23,197,341,401,41,758,901,719,17,509,51,115,38,421,62,54,157,12,32,45,117,57,37,339,328,106,188,14,365,734,99,546,488,477,76,873,2,453,308,542,248,72,10,184,40,721,214,211,4,386,305,479,474,152,3,243,90,139,11,5,1,153,313,21,468,134,471,217,148,129,123,179,77,89,670,255,162,130,94,7,391,136,59,102,111,536,196,828,247,237,743,428,6,514,277,556,128,33,475,155,266,229,29,528,209,720,413,241,64,361,476,183,9,0,519,405,317,202,181,805,775,431 }, +{ 77,141,2,102,33,1,64,6,5,3,7,269,202,128,180,23,318,14,0,10,13,291,352,153,40,197,165,137,237,51,17,177,15,217,117,115,196,9,86,4,139,134,11,19,22,12,210,403,16,342,95,125,36,457,317,21,498,752,349,275,143,59,341,120,27,93,82,18,28,111,494,110,164,38,25,365,901,475,391,57,8,203,509,260,31,961,49,453,386,48,678,351,326,56,37,719,402,99,401,546,372,569,44,65,304,864,32,730,300,194,26,45,244,873,277,29,285,41,208,597,20,253,160,523,24,98,54,312 }, +{ 212,68,154,124,562,101,191,0,9,375,118,520,167,149,818,65,16,722,302,21,777,35,24,71,604,350,100,806,252,478,346,264,664,841,1,759,265,48,13,695,429,55,701,329,51,23,724,398,589,18,936,115,882,484,755,88,749,69,903,125,189,410,22,221,535,382,108,308,166,917,411,39,28,223,67,92,509,32,10,197,64,5,694,650,114,558,95,246,60,909,7,83,241,96,165,363,391,593,98,230,321,103,364,826,553,925,639,49,458,734,628,419,336,447,768,399,140,105,175,37,886,682,905,674,821,404,109,812 }, +{ 48,23,51,98,125,541,598,259,293,13,807,126,21,115,221,493,963,223,35,31,670,386,121,0,107,770,165,144,90,203,116,719,949,783,727,279,590,197,32,326,10,284,146,49,401,407,132,64,199,16,955,342,97,39,834,1,194,453,191,522,427,114,105,92,30,14,7,465,393,763,271,50,725,615,195,108,22,77,44,9,640,291,20,202,269,941,767,671,591,498,467,360,147,128,28,704,551,389,289,33,150,141,60,43,697,534,362,589,58,325,621,523,475,403,260,237,218,210,140,137,127,109,102,87,83,46,36,867 }, +{ 21,23,13,5,1,586,32,48,167,51,781,31,647,33,271,165,49,141,591,44,115,522,77,197,221,22,360,18,93,146,391,558,105,932,217,447,118,153,961,352,60,900,317,761,196,459,0,363,260,241,82,4,12,698,463,7,291,98,27,247,815,156,120,36,623,35,10,191,628,95,65,46,17,50,922,341,202,45,411,64,521,372,102,16,934,308,269,663,410,351,326,14,116,686,349,225,110,457,29,2,509,71,621,854,701,475,354,342,159,158,132,127,24,478,446,321,246,199,640,848,777,759,371,318,316,273,223,126 }, +{ 2,29,61,52,7,1,5,14,58,70,45,425,6,290,112,738,32,207,46,72,66,186,87,76,655,38,243,263,74,151,21,75,16,227,25,50,135,17,148,64,89,255,292,128,24,106,155,141,315,476,209,226,90,26,833,19,113,27,306,115,48,454,549,592,18,4,163,307,0,20,119,77,10,86,36,270,54,177,35,171,720,22,65,137,496,202,40,887,59,179,95,294,790,23,69,269,220,172,631,334,9,67,449,28,408,318,483,311,145,13,97,845,84,287,240,214,51,37,43,241,405,33,49,102,663,80,12,180 }, +{ 39,265,9,333,100,310,411,254,363,101,447,404,18,272,98,639,264,166,1,286,203,327,682,676,31,905,156,520,821,16,93,656,593,30,625,354,105,24,438,44,664,688,23,116,51,557,0,326,329,21,812,195,49,190,159,35,759,60,478,125,118,121,48,364,132,627,13,167,33,110,921,242,68,274,158,96,127,252,137,668,77,5,731,578,692,102,795,865,131,435,165,22,604,586,271,473,455,382,146,120,10,88,144,65,64,966,212,71,67,128,83,691,897,160,576,551,36,724,615,223,82,50,647,7,95,197,621,115 }, +{ 6,26,2,25,74,1,29,19,42,138,51,108,114,70,324,14,23,386,133,103,5,96,85,13,719,75,453,52,27,66,730,602,220,38,309,65,388,457,58,17,112,122,50,128,323,357,64,235,280,238,670,421,135,165,150,475,7,523,197,32,145,278,87,500,899,401,550,3,218,273,758,208,113,86,83,603,532,222,115,711,12,137,21,895,394,46,24,163,53,45,97,67,125,283,28,458,236,117,34,11,262,294,90,36,801,792,141,516,484,341,302,33,802,297,204,57,95,4,756,594,226,256,134,480,891,545,99,450 }, +{ 20,43,356,414,49,595,858,359,819,107,392,319,97,7,422,470,376,612,173,5,246,0,427,14,683,147,197,22,660,95,230,347,945,713,32,344,92,61,830,362,325,259,33,31,21,12,4,904,707,623,126,509,18,2,77,357,232,165,140,105,102,729,196,153,426,117,408,841,518,98,64,10,17,16,501,663,560,76,44,104,38,558,125,391,23,324,178,134,46,54,29,13,40,51,330,120,493,279,168,581,263,180,158,116,241,455,159,81,28,903,298,90,900,66,465,441,423,202,198,30,534,237,58,24,3,52,887,845 }, +{ 68,35,0,101,65,9,124,154,175,114,336,67,28,69,149,189,103,133,1,24,39,83,50,230,55,345,16,429,251,7,283,218,252,346,18,389,547,71,118,364,100,2,238,140,646,109,46,22,12,439,166,289,36,23,49,484,30,399,14,51,732,13,86,930,532,398,64,96,54,323,694,88,21,722,158,265,5,75,38,48,329,181,705,212,194,952,480,361,419,443,208,302,868,782,520,10,95,108,503,128,191,115,246,237,335,267,637,37,167,160,137,723,702,141,806,565,309,105,264,831,826,701,604,535,60,330,562,375 }, +{ 23,13,51,115,15,5,202,12,1,165,2,0,21,197,453,457,4,318,269,10,32,7,141,9,6,401,3,180,14,403,37,11,341,77,22,719,120,569,217,475,308,177,33,18,260,365,17,961,64,59,99,16,317,237,48,28,629,128,450,730,90,117,137,386,352,523,31,40,494,291,102,247,8,421,509,72,24,498,125,391,196,76,49,44,57,221,36,93,468,203,326,30,45,153,210,899,89,304,216,482,372,38,110,95,82,19,275,134,402,758,342,139,349,98,901,678,752,670,873,546,734,27,56,351,65,817,61,86 }, +{ 121,195,407,126,60,271,146,199,167,16,107,493,98,132,191,223,35,279,1,212,20,362,727,92,48,43,18,21,150,522,446,259,393,467,5,783,590,598,360,640,612,939,649,354,71,246,7,156,834,68,49,125,293,24,0,147,55,608,591,163,14,376,534,31,660,541,463,683,807,97,13,345,589,23,953,668,562,22,32,818,221,108,955,118,284,96,581,595,10,50,28,470,765,695,575,346,116,2,37,61,356,535,566,95,12,51,105,101,70,281,64,273,423,230,202,441,44,9,755,75,697,653,465,38,768,173,175,77 }, +{ 31,44,299,116,393,492,144,268,918,367,456,434,105,489,22,948,127,384,963,9,98,28,0,49,125,242,293,206,395,940,36,512,55,51,203,1,855,93,911,617,159,95,272,23,959,332,763,301,137,21,13,141,64,109,86,282,10,170,120,286,320,551,202,417,599,239,165,685,7,2,616,5,128,730,143,457,352,719,48,39,8,253,160,37,692,326,327,386,450,421,158,269,12,276,18,506,791,473,115,24,16,244,391,164,558,318,403,338,623,131,219,14,523,401,284,30,197,499,900,951,308,479,221,260,728,169,910,935 }, +{ 23,457,51,401,13,758,719,165,629,453,961,730,197,901,386,569,308,670,391,3,29,14,12,739,231,34,52,153,832,828,115,341,2,40,46,514,176,365,5,21,33,0,838,181,4,328,45,54,555,130,509,494,540,734,552,583,215,196,507,227,11,211,99,117,361,180,38,10,1,351,894,134,27,26,186,50,48,543,152,749,369,202,62,236,421,102,600,468,403,171,161,155,57,9,528,17,880,753,36,477,19,440,903,488,377,22,585,108,37,7,6,697,899,757,523,475,576,326,67,479,469,281,867,805,801,659,657,587 }, +{ 105,131,22,36,127,115,180,341,201,219,272,31,365,169,98,1,44,317,9,64,239,187,141,197,498,143,873,320,752,286,901,352,86,164,160,258,327,244,224,185,109,159,217,13,535,253,538,144,116,0,374,276,261,776,170,28,83,634,531,2,569,533,269,616,95,896,251,824,482,165,37,55,128,282,10,5,578,49,546,654,947,913,371,384,295,208,8,860,21,137,202,954,312,284,30,23,567,509,125,574,39,285,318,268,206,203,843,623,33,708,12,77,716,385,837,7,638,120,237,301,254,308,293,16,951,3,395,15 }, +{ 6,1,2,29,14,25,52,38,74,66,26,65,67,114,42,19,108,5,69,83,46,388,75,86,324,135,103,7,17,27,85,380,36,24,70,150,278,87,138,97,594,886,357,267,50,51,18,484,650,23,458,45,646,21,732,398,95,208,64,96,273,13,238,0,124,22,711,550,12,532,323,302,28,220,160,37,335,63,32,194,421,133,262,451,602,283,386,309,730,10,172,467,453,235,168,3,401,782,115,610,670,48,719,81,145,16,20,500,137,226,58,280,165,603,244,866,141,308,222,197,189,112,547,53,99,73,475,180 }, +{ 51,453,386,23,719,730,670,13,758,6,457,401,899,475,629,19,2,29,569,47,26,165,14,894,421,130,801,236,197,108,412,27,74,1,308,754,5,50,17,961,133,45,52,285,523,711,657,78,324,196,128,137,65,34,115,25,99,138,357,59,480,42,114,46,361,867,53,739,58,4,743,403,603,366,11,859,38,262,12,594,202,22,235,153,64,391,218,0,516,487,10,145,200,3,33,444,70,117,901,57,223,134,54,745,390,112,283,95,123,309,96,21,66,803,220,86,341,18,365,402,176,37,328,77,488,73,322,250 }, +{ 252,121,18,101,16,9,167,132,271,60,146,419,364,35,265,363,212,0,158,604,329,682,68,647,109,848,907,191,520,463,39,24,333,28,446,159,821,55,621,553,118,126,593,411,49,71,407,23,286,634,105,195,354,107,404,857,13,676,374,310,259,22,538,562,92,100,31,10,21,793,199,1,327,639,108,48,98,806,51,7,709,346,522,932,166,147,5,590,96,137,254,465,272,20,150,694,64,706,12,14,203,169,95,36,124,77,2,116,360,44,865,402,125,154,128,33,627,576,185,810,455,156,822,777,37,326,127,842 }, +{ 283,503,128,432,269,529,63,26,275,789,193,678,318,389,102,122,291,77,59,177,256,6,862,342,25,18,235,57,216,445,27,4,573,605,349,65,11,85,403,523,643,84,813,630,494,397,233,40,56,73,475,202,138,416,210,718,42,32,133,415,381,736,453,412,511,19,619,91,240,255,80,22,64,114,23,289,194,0,17,123,561,87,174,152,343,81,436,66,300,297,148,95,78,3,217,51,803,510,370,341,139,137,130,49,45,119,396,372,90,237,544,141,74,476,129,86,21,650,421,378,352,209,196,33,288,247,402,701 }, +{ 2,75,29,52,87,74,226,69,220,1,278,135,46,262,70,267,14,380,6,66,324,38,357,294,7,394,222,140,145,97,331,25,335,189,24,67,92,16,112,853,571,26,42,309,163,50,138,35,550,582,103,172,83,96,337,451,71,108,150,5,58,486,785,537,21,60,298,19,462,583,600,461,171,32,230,48,65,366,45,500,606,54,774,12,18,36,149,223,114,37,443,641,133,632,287,563,64,409,85,22,764,388,314,238,151,950,95,61,27,307,155,86,28,415,565,17,246,423,43,572,113,0,186,609,251,396,10,802 }, +{ 97,298,172,140,69,66,7,189,267,92,501,314,60,423,135,24,232,81,71,16,43,150,462,74,14,330,192,517,173,426,733,149,251,35,885,273,6,279,38,18,221,67,278,508,83,607,2,91,380,52,125,448,124,29,387,458,87,20,36,443,230,861,108,915,711,302,104,21,568,526,723,324,12,68,48,5,362,1,336,335,0,28,22,46,541,126,357,103,25,451,877,726,246,398,565,50,138,879,175,963,65,86,165,809,391,715,197,705,191,118,117,42,712,386,204,160,823,674,54,107,467,399,441,633,831,572,563,236 }, +{ 475,421,805,899,403,453,958,615,817,51,801,523,120,401,670,730,450,326,494,23,576,202,386,629,569,260,115,365,697,77,165,110,153,351,318,24,117,13,317,0,341,221,16,704,137,5,196,342,308,757,543,22,719,197,11,4,457,20,9,302,484,758,300,10,7,217,6,193,901,391,91,361,1,791,515,862,291,273,118,102,66,38,36,2,402,125,114,661,643,352,474,134,82,33,133,756,642,511,48,373,240,847,735,608,480,172,135,52,43,21,14,859,244,116,29,370,124,754,180,35,42,898,886,851,842,811,770,558 }, +{ 7,128,20,14,177,97,16,112,43,202,269,77,107,66,415,318,2,135,141,275,147,38,18,58,35,52,307,173,10,356,298,29,210,414,172,32,6,0,137,192,24,291,70,22,102,494,9,87,334,13,104,60,115,64,40,678,342,46,49,186,33,217,5,121,48,90,23,21,4,155,86,232,403,59,28,74,132,37,227,324,319,61,362,402,36,126,95,92,431,337,178,400,609,1,376,71,51,294,665,631,392,151,549,105,81,359,353,304,230,196,67,349,15,134,544,311,285,278,884,352,259,76,427,262,194,50,496,171 }, +{ 24,14,7,28,2,16,0,22,124,1,65,35,108,168,149,67,109,69,71,18,46,55,158,49,289,12,92,95,185,38,6,169,5,420,83,10,189,154,159,584,140,150,36,68,429,164,21,671,484,50,398,60,105,175,29,302,143,703,239,103,86,23,64,344,424,32,51,9,336,251,230,273,577,114,747,133,37,118,194,66,13,48,267,97,128,835,505,52,170,137,320,892,253,115,236,570,388,347,374,125,286,54,20,345,202,458,314,638,246,654,610,25,75,708,17,172,312,96,135,677,141,19,221,3,650,799,547,601 }, +{ 26,80,122,73,27,25,42,684,19,209,445,573,667,17,680,690,106,6,255,297,611,483,4,495,59,119,250,45,84,378,113,469,65,436,128,311,85,64,29,53,200,56,648,396,235,61,742,11,136,76,383,77,0,86,32,161,62,22,814,361,256,14,12,5,137,123,40,389,194,491,503,813,283,269,862,21,3,95,112,454,179,63,141,129,33,177,233,57,202,803,2,102,70,10,34,240,402,18,416,624,275,145,605,614,52,358,504,665,527,343,133,114,108,139,50,881,151,58,205,51,790,24,210,38,174,49,216,285 }, +{ 107,259,465,362,376,595,534,660,683,470,581,147,612,20,858,43,427,49,5,178,246,786,0,35,97,356,279,878,21,423,929,61,142,14,230,126,70,132,146,904,590,325,319,493,22,199,48,32,501,392,298,953,95,77,414,640,347,345,359,798,31,13,198,7,173,58,64,121,105,711,28,125,150,344,12,518,10,941,713,603,4,60,33,450,1,481,92,202,98,120,687,55,207,23,16,18,626,197,102,522,819,163,232,771,113,577,17,318,37,65,357,263,40,324,422,260,623,59,44,663,408,702,494,441,68,455,845,237 }, +{ 131,30,190,856,228,406,224,530,88,863,219,778,274,944,613,539,816,258,187,100,435,871,39,160,321,840,44,116,31,166,93,625,137,36,957,531,127,442,213,669,466,716,385,1,144,839,492,202,827,829,96,382,908,242,662,731,9,254,120,367,276,456,371,960,203,795,201,98,730,574,83,13,924,410,800,926,326,21,217,851,318,523,836,717,268,473,931,352,533,418,23,49,141,28,260,110,77,22,86,310,567,494,457,64,10,55,244,737,251,373,728,128,299,125,105,0,51,48,679,822,489,5,616,265,295,284,615,102 }, +{ 113,311,611,6,491,80,667,25,209,45,26,27,684,42,122,73,85,396,255,145,106,17,614,29,648,297,690,19,454,61,64,624,4,5,416,445,112,32,2,138,76,65,74,151,483,90,174,66,665,119,22,287,1,59,86,378,128,833,194,573,881,141,70,52,0,525,742,214,315,243,544,680,14,87,216,469,11,746,179,250,495,887,95,12,10,222,21,348,814,289,280,204,84,72,436,77,123,56,33,114,177,235,53,137,102,81,161,631,136,46,790,503,58,240,292,208,200,153,36,202,63,7,186,50,135,57,49,37 }, +{ 15,0,1,5,23,9,51,13,2,7,12,120,115,77,260,82,180,341,202,4,450,141,10,8,351,197,21,901,6,817,403,137,102,14,64,22,165,342,457,269,93,16,3,32,11,110,37,128,318,177,401,40,494,18,365,523,854,453,33,36,421,352,475,217,28,210,922,31,569,898,317,125,44,719,30,730,59,86,144,24,48,203,961,17,49,373,116,98,99,308,326,117,752,386,576,153,55,291,39,629,899,95,221,196,139,642,661,402,237,143,244,134,160,90,509,670,391,65,498,349,89,54,127,57,805,275,253,758 }, +{ 219,127,258,98,395,924,421,276,293,697,944,567,201,284,453,401,242,512,308,51,860,475,23,105,295,131,137,272,770,301,843,670,116,299,578,386,935,125,261,13,763,31,576,456,791,115,44,492,403,221,662,268,9,730,801,269,202,49,365,964,55,805,616,159,699,943,22,141,506,224,327,206,541,21,551,144,39,393,165,326,0,842,535,203,36,743,910,28,170,332,318,282,494,949,716,253,569,197,1,143,10,341,533,5,160,615,457,391,916,317,911,187,737,286,384,93,24,599,109,371,180,900,783,244,352,12,623,48 }, +{ 15,352,752,317,180,217,854,141,351,82,1,898,36,341,260,115,23,13,365,21,120,110,10,33,291,922,64,901,372,77,349,160,143,244,51,137,32,498,661,269,5,4,202,304,197,48,253,40,237,102,450,457,373,318,11,22,35,482,251,67,55,9,719,165,59,117,72,153,177,196,12,83,28,961,579,247,326,45,96,17,864,69,523,2,468,125,0,86,730,811,128,817,134,93,90,148,144,437,37,111,403,342,76,57,546,230,704,345,308,139,89,58,873,29,203,164,531,50,30,3,275,559,127,855,629,473,8,56 }, +{ 129,123,257,184,162,17,205,249,183,769,80,119,497,229,106,5,45,130,84,90,59,152,3,99,128,4,618,27,57,77,245,40,62,452,556,378,19,214,460,136,14,12,240,56,26,2,202,432,6,33,61,266,11,209,402,403,64,21,269,102,381,25,141,29,504,76,139,318,54,73,305,34,217,619,179,1,10,32,177,38,361,207,475,383,37,483,22,210,255,115,494,58,196,524,65,23,710,775,53,306,153,742,86,180,421,36,469,137,117,15,51,216,48,134,313,0,111,72,161,285,288,7,757,250,880,503,151,372 }, +{ 102,33,128,64,77,23,51,202,141,269,13,137,40,10,196,22,0,86,117,153,403,318,342,210,65,1,115,139,15,95,134,475,453,180,165,2,177,217,14,6,494,291,197,99,36,4,59,49,28,5,7,11,402,120,12,114,194,3,18,9,19,31,125,237,82,352,17,16,21,110,275,401,44,260,24,285,719,349,25,93,326,457,164,351,111,300,216,27,317,421,133,26,37,203,143,312,116,108,8,277,498,730,365,678,341,98,244,20,386,523,308,105,29,752,372,32,485,450,901,391,361,57,283,48,30,208,96,38 }, +{ 7,14,172,107,92,2,16,135,46,35,232,294,60,97,87,5,278,24,126,29,220,52,38,21,262,66,192,202,58,20,70,48,43,171,359,54,32,448,356,337,37,353,226,112,75,298,1,526,18,12,872,132,64,409,140,22,155,387,334,128,121,392,357,318,307,461,331,0,150,314,49,146,61,415,86,69,71,620,673,230,494,380,324,6,362,355,330,45,259,77,888,137,10,13,246,95,186,141,74,23,50,279,147,194,28,25,51,9,4,609,151,177,55,849,145,199,31,115,102,550,597,59,36,216,90,17,441,222 }, +{ 576,403,615,805,523,475,326,817,494,421,120,51,450,859,137,202,453,260,670,402,77,23,551,401,386,33,958,318,704,342,269,197,196,0,165,480,373,323,65,153,899,753,629,10,803,697,102,7,569,59,4,2,351,90,12,13,962,677,110,9,801,118,40,6,95,5,128,28,143,730,446,124,122,114,14,917,306,207,82,621,407,86,16,164,115,154,64,842,886,848,735,661,484,397,302,247,174,149,141,71,60,1,719,216,104,81,925,628,457,208,168,49,25,22,844,824,685,338,175,109,259,810,236,933,932,854,804,788 }, +{ 141,352,202,269,137,217,180,372,349,9,18,0,51,115,23,13,16,365,221,318,165,317,2,494,752,7,125,120,77,98,20,10,64,49,341,291,22,901,95,260,854,351,308,55,30,28,403,144,93,44,922,873,326,223,82,48,39,35,21,14,197,203,24,153,33,102,753,498,473,156,88,65,386,32,717,275,268,31,196,177,817,730,704,678,661,482,450,437,393,373,288,241,195,132,121,118,110,105,101,36,1,947,475,237,5,253,244,206,201,168,164,158,143,128,961,954,864,751,615,576,551,546,523,509,489,453,442,421 }, +{ 23,202,51,141,13,165,1,21,5,180,197,269,318,137,48,128,15,7,403,120,12,102,125,64,2,33,14,326,523,450,260,93,37,16,386,32,9,4,237,6,115,352,77,203,457,153,196,82,18,117,0,110,421,494,453,401,40,24,817,98,351,475,99,221,730,144,391,31,3,44,96,291,30,719,308,36,39,341,342,11,217,35,8,899,50,20,402,854,615,922,116,160,72,28,17,22,45,10,373,317,89,88,61,59,285,509,752,365,372,58,19,901,46,139,70,349,25,177,65,86,293,90,247,498,54,576,758,898 }, +{ 25,151,145,6,122,174,29,138,74,665,42,416,113,614,45,746,525,287,348,311,396,544,85,66,26,81,280,243,624,355,52,222,32,64,65,680,4,59,19,0,491,2,22,90,7,204,194,104,77,216,112,445,1,61,5,128,86,177,651,91,214,17,95,209,611,141,648,297,80,415,21,102,87,233,454,33,27,43,881,503,20,137,636,573,10,18,14,117,289,76,58,869,202,153,337,496,186,196,789,106,315,11,40,28,135,49,667,269,192,36,13,57,12,115,134,750,70,208,63,72,73,46,597,529,51,48,684,173 }, +{ 166,190,382,254,30,100,731,829,438,264,274,88,795,131,613,578,716,625,9,93,921,616,435,404,265,1,530,203,31,44,960,36,39,827,160,127,272,326,98,924,96,473,224,23,410,116,252,77,144,310,137,856,105,219,101,33,83,0,863,110,800,13,812,51,128,406,478,228,125,521,120,639,21,49,836,102,593,217,242,28,897,772,931,5,688,957,286,115,64,141,691,269,656,317,321,10,494,159,187,197,291,86,363,576,944,67,22,450,201,523,55,411,373,82,822,557,260,456,704,329,367,225,276,48,202,268,213,32 }, +{ 132,21,379,5,32,13,23,195,626,51,48,121,70,1,850,296,687,883,156,771,61,49,407,95,146,125,105,55,652,4,98,761,77,58,33,518,260,18,623,586,349,340,120,82,523,522,354,163,24,16,0,293,45,87,786,165,929,75,64,888,763,535,308,102,31,698,40,269,202,159,37,35,9,845,622,207,663,153,117,900,608,386,817,591,351,347,310,241,221,199,170,158,115,76,65,59,28,22,706,223,774,640,629,461,415,116,101,71,303,60,941,638,427,421,401,391,372,197,196,127,299,937,854,768,475,453,450,403 }, +{ 254,9,272,0,49,688,39,101,578,131,159,518,158,327,333,105,286,68,716,224,252,28,890,344,616,310,846,829,219,827,228,613,24,35,364,16,30,18,938,371,406,166,419,65,455,22,95,627,793,709,98,910,124,154,51,100,31,127,48,1,21,385,190,23,320,242,137,187,374,347,258,36,44,13,301,404,109,856,116,170,125,118,96,160,442,656,424,865,438,931,67,168,64,55,239,623,128,737,265,924,553,221,202,10,71,677,86,83,88,916,60,329,293,538,7,577,512,5,761,395,912,421,212,144,816,944,506,346 }, +{ 16,35,60,20,7,18,126,68,14,43,92,107,118,101,55,71,28,121,9,154,0,97,109,24,621,150,2,191,419,252,5,202,279,363,917,22,21,124,364,169,439,604,199,49,346,446,175,158,12,167,575,48,38,13,493,246,185,10,362,32,95,51,259,375,1,39,598,628,932,566,421,6,23,64,29,108,146,925,61,46,356,494,318,132,140,345,694,149,359,147,65,407,329,376,125,403,697,273,302,212,96,69,137,50,848,25,467,298,77,453,173,230,570,826,221,66,70,143,677,535,265,608,551,58,815,128,907,100 }, +{ 15,1,13,2,341,5,0,11,4,3,10,7,33,23,12,6,117,21,9,40,17,901,197,8,134,77,22,37,365,14,32,165,317,153,102,180,217,457,202,51,961,569,141,128,115,318,38,31,64,19,16,291,137,269,196,372,111,59,44,36,25,352,349,57,99,18,509,72,30,27,752,120,93,54,45,41,342,48,110,49,453,498,79,177,28,719,94,403,402,386,89,82,474,29,285,139,86,482,56,237,361,95,55,391,26,277,116,873,34,210,76,758,326,50,39,143,90,328,260,308,247,125,898,164,24,494,401,421 }, +{ 78,444,47,19,26,390,813,130,108,453,711,27,412,730,65,122,680,283,690,113,51,235,236,73,128,630,196,297,14,250,123,53,194,183,200,133,64,445,368,90,719,3,381,42,23,389,269,6,472,650,249,56,475,32,59,4,57,45,34,648,605,624,503,114,17,25,736,256,22,803,141,318,153,315,95,214,0,684,119,99,18,432,216,899,85,289,46,457,243,33,11,436,480,50,322,177,29,152,129,54,13,657,304,285,84,52,401,117,881,255,714,202,665,597,2,961,12,339,38,361,77,524,115,58,24,145,670,402 }, +{ 2,29,7,52,66,61,45,112,738,113,74,14,5,151,6,315,20,592,70,128,32,425,16,25,1,222,87,135,177,43,64,491,186,59,38,655,21,72,76,46,290,90,243,141,115,77,631,58,106,19,337,207,145,137,4,24,454,833,97,0,26,40,227,311,402,192,36,27,89,210,35,292,269,48,86,10,202,209,496,18,217,22,102,226,138,17,887,204,122,65,318,33,28,104,172,51,255,13,23,42,148,644,216,790,307,287,174,180,92,69,291,95,49,415,75,416,483,549,179,275,263,270,107,9,334,869,214,155 }, +{ 145,112,74,66,26,6,29,70,396,287,138,87,135,222,226,25,644,151,42,19,122,307,651,624,635,337,648,45,2,113,294,58,85,632,849,5,416,75,52,172,61,573,445,27,1,315,884,665,64,7,53,204,32,461,95,17,97,297,174,163,436,220,280,525,192,65,792,73,14,186,86,609,881,353,36,311,549,72,243,22,194,331,148,500,235,80,69,46,680,278,38,312,48,90,21,106,37,409,491,128,10,114,614,631,209,67,415,227,50,108,237,250,580,155,76,141,171,544,262,24,620,12,43,133,611,4,334,389 }, +{ 92,126,60,16,7,24,35,232,71,14,150,140,121,246,314,146,172,132,199,107,18,267,46,278,572,230,108,451,330,236,380,388,462,135,68,38,830,633,392,279,97,2,448,309,649,517,672,32,357,21,5,75,9,118,22,55,167,87,582,192,526,594,366,156,359,298,191,195,64,653,28,50,189,324,563,13,220,0,1,66,467,12,10,423,441,149,733,52,262,877,48,29,70,95,49,516,133,36,54,508,407,360,354,598,550,101,69,37,58,65,271,640,711,212,571,86,345,895,696,273,125,522,23,90,603,72,739,163 }, +{ 13,115,569,734,219,341,127,365,197,509,629,23,98,538,873,901,286,762,55,206,258,165,253,332,170,169,638,535,180,391,116,276,844,31,44,12,546,0,395,164,1,293,10,752,911,36,964,143,282,37,384,512,237,498,308,616,301,740,5,141,352,8,261,9,2,943,654,317,120,284,38,338,913,601,295,244,105,7,3,201,468,924,125,923,910,144,239,21,4,479,482,242,6,86,131,417,961,185,22,64,758,374,110,841,533,401,93,160,15,944,434,82,951,567,843,268,14,564,837,299,272,719,28,860,109,11,351,935 }, +{ 151,58,396,53,287,74,27,73,297,549,29,651,145,70,445,112,113,315,436,26,331,6,573,250,75,45,334,52,307,17,5,34,80,163,2,138,19,491,61,881,220,409,631,262,1,614,632,226,171,106,611,186,32,200,66,50,62,311,25,46,845,767,500,21,135,644,243,223,87,14,48,42,64,3,472,108,324,76,122,161,635,684,65,294,56,38,136,95,72,255,114,849,780,278,209,37,90,852,84,714,7,51,89,148,624,237,383,36,207,236,502,22,12,133,86,322,659,227,119,69,222,11,4,96,309,263,179,33 }, +{ 214,289,90,874,104,751,64,835,312,249,204,65,750,288,875,348,519,174,247,194,74,715,81,138,32,280,524,784,192,636,319,437,879,0,95,85,6,681,217,173,954,91,29,177,86,597,792,77,317,671,422,22,115,864,888,52,202,752,216,673,588,712,18,123,180,233,306,43,355,304,352,20,76,693,579,66,4,5,25,51,21,343,59,237,2,28,61,426,235,577,33,10,397,316,707,287,145,370,24,102,49,291,17,108,84,945,222,97,57,208,56,401,42,526,560,13,730,40,402,23,117,207,474,7,484,72,494,36 }, +{ 9,39,166,28,35,158,49,30,101,175,439,0,346,1,364,64,88,274,100,168,36,67,404,310,333,952,159,55,345,505,190,706,254,420,86,237,23,336,68,22,251,344,51,69,194,114,164,131,570,208,180,756,10,799,143,399,109,83,50,115,141,967,438,768,584,868,128,752,105,95,103,189,286,252,352,5,323,2,230,65,596,289,137,498,7,702,165,13,12,577,503,535,160,125,202,48,547,455,244,610,96,21,16,253,169,857,217,154,797,646,656,228,197,530,747,149,810,124,930,272,865,597,98,185,31,24,389,625 }, +{ 341,901,15,1,365,10,569,0,2,5,180,4,3,115,6,31,7,197,9,13,22,317,951,165,44,629,143,23,253,401,116,244,762,55,93,242,479,752,30,217,51,37,141,28,873,137,638,36,202,203,12,21,86,386,421,77,24,758,11,268,453,318,269,110,33,576,64,811,352,326,164,16,494,506,498,308,670,82,717,642,351,206,120,338,170,261,32,125,40,851,805,260,102,859,8,403,54,661,961,291,144,105,965,98,35,898,482,391,373,153,509,492,958,117,17,499,615,38,824,559,456,384,854,457,282,89,564,237 }, +{ 202,450,120,77,260,318,494,128,102,817,15,269,51,13,342,403,23,291,5,523,137,326,21,141,33,1,922,32,82,351,48,854,177,859,402,64,196,70,615,31,475,40,4,153,285,59,0,12,22,10,2,9,95,98,61,90,28,210,30,17,453,194,117,139,8,352,96,49,275,35,678,899,113,349,165,65,180,6,730,93,692,115,58,704,217,37,203,719,116,576,125,50,457,75,44,421,163,216,36,134,7,39,3,416,14,67,197,25,373,110,341,207,112,86,386,87,56,127,99,11,223,551,365,300,105,16,19,237 }, +{ 241,32,13,115,197,180,165,316,64,288,125,21,23,237,247,141,95,16,22,92,167,522,191,546,498,391,341,28,752,177,586,4,48,509,447,118,459,90,5,352,59,901,264,225,304,350,35,199,126,363,18,217,24,410,468,691,246,841,744,10,478,102,77,649,386,117,86,49,317,308,302,212,146,33,71,954,156,72,46,674,93,31,0,640,411,923,903,645,686,271,698,2,521,140,602,591,120,36,375,68,12,864,321,695,873,758,340,336,318,269,179,143,65,897,772,446,880,839,682,366,190,57,30,818,781,303,953,388 }, +{ 16,24,35,71,60,14,267,18,46,140,69,1,7,108,189,2,92,50,75,230,309,68,236,38,335,220,394,54,366,52,486,21,150,149,246,48,29,87,67,5,571,388,9,181,133,0,103,443,28,163,537,171,55,223,126,545,121,70,12,96,262,328,565,83,32,118,65,516,58,218,37,191,330,563,64,167,22,114,13,51,23,238,251,622,281,278,487,294,399,99,696,115,36,10,582,135,514,86,6,128,517,950,675,674,273,98,101,594,172,49,72,146,95,314,451,155,45,409,212,433,221,345,141,66,247,97,733,125 }, +{ 15,898,180,197,901,341,638,165,33,10,115,77,365,1,4,217,317,5,102,117,253,13,951,752,3,134,2,762,153,569,37,21,0,196,40,11,244,23,6,82,7,120,143,291,32,141,137,51,31,873,55,12,351,44,260,349,352,401,372,479,177,93,22,342,116,36,9,629,308,59,758,450,386,210,854,139,110,111,482,457,164,17,922,421,961,202,719,269,203,373,247,523,28,125,160,48,437,64,326,242,57,704,509,304,14,318,730,498,403,506,148,817,670,8,90,453,494,282,144,72,127,275,579,221,206,899,54,89 }, +{ 523,193,18,84,730,817,90,56,65,240,214,475,453,196,33,719,4,233,202,32,51,153,289,152,123,421,11,194,403,129,99,96,386,249,135,102,40,27,23,361,847,352,59,511,91,457,177,370,134,128,117,510,13,561,75,753,643,388,278,247,204,115,494,450,415,304,77,524,217,216,64,6,5,3,174,701,880,659,609,437,433,432,381,287,260,257,165,139,120,111,87,74,66,1,402,372,318,269,21,899,183,63,141,650,605,770,743,735,718,667,629,611,569,544,543,348,306,288,209,207,162,95,93,86,61,57,49,48 }, +{ 151,29,112,74,222,66,145,2,287,624,52,6,416,45,7,113,186,25,122,665,549,337,87,204,243,5,135,644,311,58,884,226,138,396,61,32,192,70,42,525,415,614,315,19,64,491,651,26,4,227,174,609,544,20,21,43,14,27,128,22,172,632,0,59,209,65,353,97,631,72,1,85,580,86,17,445,80,454,307,104,90,334,81,496,177,46,635,141,255,48,37,77,75,10,155,869,659,76,294,106,49,73,11,95,38,36,115,673,69,18,216,712,148,173,792,33,331,102,280,12,16,24,137,881,89,297,91,28 }, +{ 13,2,23,0,77,5,217,7,1,6,33,3,15,51,10,115,141,102,180,64,4,9,40,317,11,197,14,117,165,153,341,22,352,237,17,365,134,269,291,125,16,202,12,196,372,59,349,177,752,498,128,28,18,32,318,8,36,95,457,19,86,49,210,143,391,901,24,342,21,304,569,31,509,137,139,120,27,386,57,25,164,98,29,111,401,403,45,26,244,864,482,546,110,44,961,308,38,275,453,37,35,93,48,402,247,629,20,50,46,719,873,55,475,65,56,30,72,579,203,523,99,253,494,468,170,54,116,76 }, +{ 28,67,0,65,1,114,103,83,69,50,9,55,2,109,124,46,133,24,14,35,22,154,36,68,38,547,389,218,7,283,323,16,54,18,12,160,194,420,49,251,175,5,75,185,238,39,289,429,158,96,208,168,532,29,86,480,505,531,484,189,503,169,149,797,782,361,21,101,570,52,346,71,181,336,927,533,48,95,37,108,51,596,10,252,23,159,128,799,105,285,418,64,118,535,335,398,732,6,70,803,419,137,220,13,866,171,756,394,30,32,309,328,140,115,87,60,230,433,345,141,58,439,831,402,610,366,99,754 }, +{ 121,271,132,167,146,18,363,101,411,621,354,212,520,60,9,647,932,446,806,16,195,407,463,777,364,562,35,360,522,68,55,1,98,118,31,252,706,694,191,0,24,107,936,664,676,604,199,48,126,781,23,590,156,28,591,150,21,447,39,125,5,109,264,49,759,265,96,22,404,33,13,10,100,44,51,905,259,71,346,857,682,116,223,848,941,7,92,154,93,105,108,478,77,467,286,821,166,64,638,907,765,691,628,279,178,14,203,102,12,30,120,393,158,159,593,834,724,419,147,50,293,163,815,786,367,70,634,2 }, +{ 26,6,85,122,396,624,42,25,573,445,174,416,665,19,680,648,138,145,348,881,64,436,214,113,235,65,297,544,194,90,45,746,525,280,112,289,74,233,32,53,27,355,29,222,287,389,17,151,86,80,95,813,81,73,256,5,249,141,283,91,597,0,343,76,22,66,87,204,415,874,209,312,690,524,611,255,288,63,644,123,243,70,614,216,4,128,2,77,119,61,370,106,52,491,315,58,10,56,651,21,12,519,18,14,835,59,250,352,247,114,49,179,636,205,684,619,311,57,84,28,337,667,177,108,11,208,503,240 }, +{ 146,16,199,24,71,18,126,60,92,121,271,156,360,953,640,108,132,674,35,246,118,273,32,354,195,649,7,314,150,458,522,95,517,167,446,191,21,140,340,463,22,388,68,107,566,575,241,727,10,345,591,359,296,48,586,14,407,28,5,608,149,672,594,602,660,1,467,363,212,13,9,823,49,267,101,225,124,55,232,37,653,0,392,877,50,447,330,702,12,809,462,441,230,508,46,668,189,77,303,236,733,23,698,621,115,423,411,399,298,97,350,247,72,796,451,64,658,217,69,589,309,51,928,264,168,102,163,133 }, +{ 51,23,13,453,475,730,719,899,403,202,401,21,15,64,523,115,95,457,33,12,141,308,32,102,4,128,40,19,11,421,5,117,386,3,99,22,153,125,26,817,120,25,6,961,165,1,180,196,17,197,494,57,134,221,0,194,2,237,260,7,670,48,27,365,37,629,450,49,170,65,14,569,137,342,236,38,352,10,56,29,20,16,468,316,241,402,391,77,177,350,84,34,283,269,217,82,9,247,546,351,318,42,59,372,903,841,558,317,129,86,47,46,41,28,18,326,615,341,90,291,164,801,509,119,76,63,54,24 }, +{ 151,396,53,113,73,445,145,6,27,297,573,26,287,315,112,436,74,58,138,491,45,70,881,19,614,34,250,61,29,549,611,80,17,631,632,5,307,2,200,644,32,222,64,25,52,106,42,1,243,87,66,75,845,226,311,186,334,849,95,122,472,322,294,21,651,714,255,684,48,171,331,194,65,161,209,14,128,86,72,141,46,624,50,135,22,635,262,227,85,108,136,7,220,90,76,163,235,176,114,312,280,62,409,10,337,4,148,56,454,283,237,12,469,37,51,780,214,667,236,3,767,133,36,89,495,155,0,23 }, +{ 223,774,1,888,385,260,98,863,202,269,421,730,96,349,697,453,141,393,622,834,318,751,87,418,791,765,801,922,163,21,335,352,5,7,120,13,291,854,64,23,717,851,293,30,284,372,31,678,371,217,947,351,70,51,32,137,48,77,128,82,442,450,44,49,36,752,125,386,541,931,304,873,0,498,22,2,201,276,807,317,10,670,180,102,6,75,237,39,373,33,69,770,144,177,95,17,16,160,116,100,842,203,197,968,949,221,115,275,165,494,475,127,898,58,963,523,403,12,954,537,45,50,433,872,652,526,268,241 }, +{ 60,16,126,92,121,35,150,246,7,598,279,199,191,167,441,107,71,97,146,195,271,18,298,24,407,356,517,230,1,14,98,508,423,140,674,132,359,223,653,212,48,68,399,783,345,21,314,108,607,43,467,232,362,649,118,392,189,20,5,0,149,702,727,55,22,695,28,446,672,69,66,49,493,10,50,388,809,273,2,522,31,46,640,293,125,9,13,95,101,267,173,501,393,834,877,38,575,67,32,75,37,796,346,779,608,12,156,589,236,566,163,96,221,104,360,375,535,64,711,463,23,175,755,172,414,562,953,354 }, +{ 22,105,28,1,239,95,55,170,320,301,127,36,98,31,49,109,9,2,0,168,35,67,185,169,12,14,86,512,7,44,395,159,5,194,293,312,114,64,83,928,713,740,65,24,23,623,21,299,10,338,16,51,242,50,125,141,933,420,13,237,37,164,844,286,143,69,175,584,892,202,48,6,46,371,103,133,269,116,685,39,916,137,115,160,599,208,272,128,96,284,158,737,762,638,180,244,276,187,763,308,165,841,761,479,505,401,347,424,318,389,30,352,870,18,131,32,197,219,965,327,538,54,456,900,506,253,385,874 }, +{ 2,292,6,119,29,207,76,61,306,45,5,790,17,240,32,58,106,1,151,476,710,14,214,209,25,179,84,52,70,64,90,7,112,26,311,19,618,72,128,129,27,255,123,655,460,59,249,141,86,4,80,40,113,22,115,46,10,245,464,205,145,243,263,358,77,56,36,74,65,315,504,454,148,3,186,95,0,519,50,177,75,202,21,269,38,257,66,42,137,23,16,769,51,738,48,136,33,162,18,184,62,241,99,227,24,318,194,87,491,37,11,12,57,425,833,180,402,49,237,89,287,216,13,720,102,54,631,138 }, +{ 51,221,23,115,254,438,48,421,530,541,13,21,401,613,308,39,688,386,125,840,228,551,453,960,827,1,166,96,406,326,393,627,670,158,49,697,656,829,846,770,333,856,404,5,180,30,863,190,202,669,518,890,219,83,159,98,50,131,33,102,310,217,165,137,743,77,32,101,31,752,679,15,105,615,468,391,341,317,0,224,9,498,352,258,286,455,364,187,778,197,344,44,865,539,457,482,272,128,116,37,28,949,403,876,385,963,373,709,931,719,64,574,68,35,160,274,268,616,345,442,95,492,450,293,843,839,22,261 }, +{ 5,1,22,21,2,12,14,36,48,0,54,86,32,10,28,50,65,37,38,23,51,17,7,208,3,9,114,45,281,13,4,137,323,46,24,6,99,95,18,49,58,55,115,480,72,202,96,745,285,194,181,67,64,16,270,89,133,218,83,168,403,11,430,29,61,155,128,160,503,361,540,223,77,244,221,389,318,757,164,103,141,283,76,402,502,401,59,859,920,40,341,543,290,31,803,269,513,735,124,165,308,33,75,253,421,143,838,754,69,90,180,197,125,102,19,494,453,475,966,105,27,289,109,584,576,569,765,148 }, +{ 182,23,363,284,296,447,340,98,1,291,698,367,93,668,658,156,144,21,269,70,433,379,31,318,478,354,203,44,691,335,180,13,223,125,116,937,586,411,326,110,107,48,18,421,664,724,273,197,141,51,692,195,87,5,67,914,687,486,759,349,551,386,375,268,232,149,102,60,35,33,115,795,251,69,65,49,415,364,77,771,626,163,453,281,165,127,121,24,10,360,806,791,393,336,39,475,372,217,850,662,942,682,518,484,361,359,221,196,146,133,128,117,75,64,22,12,7,883,591,457,132,16,647,153,120,68,801,670 }, +{ 45,498,17,106,546,115,32,62,873,41,197,180,509,54,129,468,243,255,123,752,165,155,38,341,13,241,292,217,720,449,57,136,536,734,569,148,51,476,248,428,214,139,76,369,221,482,328,237,542,365,72,89,339,181,23,227,350,64,90,211,117,11,519,270,290,405,721,587,457,21,901,50,128,741,710,141,552,313,430,162,2,540,130,202,15,102,528,247,488,317,209,157,77,48,14,3,391,152,431,308,629,4,618,743,281,179,5,183,33,40,12,37,358,361,266,46,86,961,828,471,773,372,421,543,249,507,119,10 }, +{ 32,95,64,237,92,180,246,22,241,197,125,115,312,652,126,638,49,316,13,21,5,165,288,534,7,4,48,0,28,23,498,392,296,107,888,340,90,303,658,626,247,70,441,10,16,365,953,468,260,230,546,18,24,774,12,379,883,98,490,482,863,31,877,508,391,141,51,830,933,354,9,517,347,150,314,385,177,132,65,146,645,40,653,76,33,2,341,217,14,269,44,698,263,156,195,850,649,633,199,120,360,359,563,923,509,216,128,86,60,733,873,267,35,1,442,168,330,293,929,545,11,622,591,87,77,641,437,660 }, +{ 15,33,341,217,13,77,141,4,317,102,23,40,115,180,365,351,117,21,5,352,854,1,137,197,11,10,153,51,82,901,32,134,59,64,202,196,36,244,269,22,922,165,2,291,260,177,752,143,0,120,898,48,3,318,12,9,372,253,128,457,31,569,28,37,160,30,247,86,139,55,44,72,7,57,349,110,90,237,498,342,304,111,719,579,450,96,8,730,403,308,811,49,523,164,386,35,125,482,437,17,6,14,961,39,98,494,116,93,275,642,401,210,95,221,76,277,105,717,373,203,216,38,873,899,18,817,326,509 }, +{ 120,260,1,15,141,217,352,13,77,82,93,351,110,23,180,317,349,51,202,21,854,326,165,64,269,128,137,5,291,304,752,36,373,372,922,450,318,177,203,197,115,48,457,10,342,2,0,898,102,160,12,16,901,22,125,386,86,9,144,32,96,35,719,28,7,365,341,244,275,494,210,730,18,95,83,661,4,403,237,523,498,247,143,864,473,90,14,961,437,33,817,40,37,8,678,482,253,579,569,98,72,24,50,475,391,67,69,954,717,288,164,65,49,6,206,216,55,17,134,947,899,576,308,76,316,196,490,402 }, +{ 23,13,51,115,77,217,141,177,33,202,4,64,269,102,0,128,10,2,7,318,40,59,32,14,6,11,352,22,9,291,90,247,180,237,137,1,165,16,317,21,210,197,117,153,196,18,125,49,403,3,95,15,17,349,341,304,12,372,216,365,342,19,36,134,453,86,98,28,308,24,31,244,494,93,275,143,475,57,401,44,48,5,498,457,241,120,203,20,8,105,144,221,25,326,110,752,29,65,523,164,37,55,30,719,421,402,139,39,160,27,116,260,26,96,35,300,437,961,82,569,38,45,901,99,72,253,678,316 }, +{ 478,264,724,520,682,98,1,772,905,664,759,821,9,223,21,48,411,604,909,447,363,23,265,100,13,410,897,166,5,907,293,31,88,329,252,39,101,0,51,125,639,848,32,167,96,647,691,807,781,541,686,382,284,521,44,321,777,393,621,274,118,212,18,676,116,163,69,271,936,834,221,593,812,16,24,914,30,10,127,765,115,37,49,354,335,217,144,68,93,386,105,404,586,22,33,4,83,70,806,165,553,697,932,60,77,50,744,463,71,64,286,421,254,281,435,102,35,12,656,371,191,225,963,446,121,213,201,763 }, +{ 29,20,128,7,43,77,174,74,2,23,32,416,52,102,66,491,104,113,81,33,13,6,51,342,222,202,173,14,0,21,525,59,137,45,192,141,319,5,318,64,10,210,22,291,631,18,72,122,90,145,269,196,151,86,61,58,16,665,4,177,40,355,204,153,134,402,28,285,42,738,544,135,48,216,25,275,115,85,24,65,217,9,12,87,76,833,415,226,179,198,38,138,114,49,97,84,243,337,315,311,287,36,426,869,422,172,89,255,17,209,784,112,454,317,425,35,349,117,95,27,494,208,91,194,503,232,30,11 }, +{ 2,1,5,14,58,7,52,29,46,61,290,45,75,38,592,425,50,270,70,16,32,163,24,155,21,186,171,72,6,227,69,334,263,207,220,17,243,663,48,18,89,76,0,67,400,655,738,35,408,54,112,87,148,36,64,449,66,23,106,22,307,10,262,128,292,74,409,115,119,135,9,476,90,65,141,278,37,767,103,83,86,28,720,140,95,780,255,96,25,405,27,77,3,241,51,12,13,306,20,97,666,179,223,40,19,177,4,428,92,151,496,209,172,26,502,113,84,202,790,137,60,431,833,240,659,331,217,324 }, +{ 80,483,209,106,6,26,17,495,255,833,378,469,113,742,27,25,19,814,119,445,161,887,45,42,76,667,61,64,491,151,90,573,73,235,84,29,65,32,136,614,179,383,128,112,145,297,122,2,527,396,214,62,56,240,85,5,53,862,194,648,123,311,611,624,207,141,58,86,315,95,14,22,306,292,34,4,454,436,59,684,790,0,1,289,440,250,129,738,205,70,416,361,3,249,245,57,269,287,665,52,108,402,202,46,12,177,11,114,216,21,137,36,10,200,33,115,72,180,74,138,50,28,318,247,312,51,585,148 }, +{ 98,223,393,834,1,354,195,791,697,447,293,284,360,541,781,807,51,664,591,156,421,411,48,801,163,883,948,668,765,386,18,586,132,121,23,963,363,125,21,446,551,759,31,621,949,770,407,777,271,658,146,730,167,670,13,116,936,453,5,367,296,478,144,371,221,96,70,9,44,202,105,719,127,687,379,49,118,55,60,698,101,842,626,318,771,217,647,212,691,137,281,638,340,165,75,522,463,706,724,32,93,401,39,364,269,16,520,562,35,141,77,50,265,914,450,33,203,197,268,498,264,69,857,335,22,317,103,905 }, +{ 679,876,36,816,141,144,93,137,752,406,669,228,180,269,96,251,332,21,1,48,352,203,351,202,855,160,831,318,345,498,83,5,116,187,120,617,201,64,317,902,258,261,840,23,839,613,473,110,864,466,190,574,219,32,860,13,873,418,450,326,539,926,748,856,260,44,51,384,704,143,50,295,531,197,489,843,661,206,10,944,778,530,217,567,871,88,82,268,901,800,128,822,125,372,365,86,957,31,30,165,37,442,244,728,224,768,851,373,854,505,625,863,386,367,276,55,827,237,115,922,349,420,274,523,223,169,72,61 }, +{ 15,13,2,1,341,5,23,3,0,4,7,11,10,6,51,12,14,9,33,165,115,569,197,180,17,365,217,153,77,64,196,102,22,21,40,453,317,8,32,901,141,457,117,961,134,31,18,37,16,386,629,291,719,110,28,44,475,177,120,93,269,202,86,237,372,24,95,19,125,59,49,403,57,401,352,318,48,349,730,36,111,326,137,128,98,38,82,391,27,139,65,30,873,275,242,203,54,260,29,45,494,55,25,342,210,450,99,56,46,116,509,498,482,752,373,50,351,899,523,308,247,90,143,35,437,76,72,26 }, +{ 202,13,23,51,403,21,494,5,141,128,48,269,450,125,120,523,64,12,318,180,165,453,95,475,15,33,817,32,197,1,137,115,102,7,260,899,4,37,10,99,2,98,326,93,49,196,730,719,221,457,77,16,237,9,31,22,401,6,421,14,386,308,0,117,134,18,352,40,82,20,19,177,615,59,44,61,402,17,391,203,116,110,27,25,90,341,351,153,30,28,285,105,217,3,291,8,958,854,96,24,50,805,922,54,961,758,576,39,26,801,247,347,509,46,757,342,317,365,498,11,194,72,670,210,38,139,275,170 }, +{ 16,24,71,146,60,18,92,199,126,118,246,35,121,108,140,167,132,230,649,271,360,267,7,9,640,388,150,156,232,191,133,522,273,68,236,101,107,212,0,672,55,446,953,14,149,458,674,330,46,67,314,566,95,189,602,633,392,562,195,64,591,103,21,467,39,354,69,463,407,114,247,98,32,5,50,172,10,1,733,399,278,366,49,36,653,309,412,65,823,22,28,915,288,877,316,124,75,345,340,264,37,12,594,516,135,563,598,451,225,86,38,572,830,125,31,30,359,517,115,571,363,164,726,398,48,237,116,251 }, +{ 269,141,177,678,202,77,318,947,128,349,33,291,40,102,352,210,498,137,954,120,205,864,216,64,196,597,304,275,217,494,461,23,402,115,342,90,13,403,450,300,95,49,197,111,14,326,22,139,237,10,0,125,873,372,182,751,86,117,615,7,44,195,36,31,83,67,752,356,153,98,46,96,59,252,109,97,800,357,285,774,523,550,208,609,569,546,391,247,116,93,66,24,19,18,17,15,6,5,3,2,30,922,414,373,180,159,147,105,20,485,75,859,854,392,376,317,298,288,277,260,143,134,107,39,28,735,415,409 }, +{ 16,71,24,92,35,60,18,191,167,108,246,126,150,118,140,68,7,273,121,149,212,21,388,14,399,314,517,267,796,230,48,146,823,199,271,458,1,467,189,695,877,674,345,9,55,97,46,702,101,575,602,594,733,841,0,350,22,375,107,95,232,28,236,462,32,566,69,298,50,672,13,2,5,727,133,451,154,302,125,653,463,23,446,124,10,589,223,132,64,67,175,38,37,49,98,65,354,423,398,103,649,172,562,755,75,66,336,221,197,903,508,915,809,363,359,51,380,411,309,608,237,330,412,241,12,640,509,36 }, +{ 2,14,75,46,29,52,1,70,171,69,163,220,58,38,112,24,16,7,409,67,262,223,35,334,155,186,5,151,267,394,54,307,87,140,103,309,50,45,83,189,400,18,71,60,92,335,760,227,502,48,21,181,108,61,96,537,12,820,25,278,6,852,113,549,66,357,366,32,287,587,17,37,19,536,27,606,36,150,135,97,74,64,26,380,486,65,0,552,583,28,230,281,600,294,787,582,849,68,149,133,675,22,315,311,236,72,474,243,114,10,324,571,238,86,226,764,9,55,780,218,145,209,80,462,328,95,430,767 }, +{ 265,166,252,100,404,9,329,382,520,593,812,39,88,274,604,101,264,0,553,1,639,676,438,865,664,333,310,68,30,656,167,821,118,363,411,96,23,682,18,158,48,21,478,364,190,105,286,51,98,49,254,435,759,724,647,13,212,16,907,272,124,921,159,31,223,419,125,905,557,5,447,93,154,321,44,393,83,410,327,455,848,35,67,621,293,271,127,191,71,530,354,344,32,24,60,625,213,418,242,109,131,36,69,33,221,144,765,28,121,806,65,50,777,116,22,238,960,146,834,781,897,697,778,165,163,466,115,948 }, +{ 16,35,60,18,24,68,158,71,0,7,55,118,109,14,49,22,159,105,9,28,329,126,344,92,20,107,10,154,553,265,2,191,101,95,424,23,21,5,327,121,13,1,286,239,43,747,51,419,48,455,108,374,168,39,272,677,137,169,124,149,12,199,310,150,46,128,38,279,320,37,709,170,346,6,64,98,167,202,31,185,252,67,810,65,36,125,917,175,577,97,212,32,942,44,518,29,925,628,86,301,69,146,375,132,538,575,913,890,566,403,634,439,333,61,33,50,326,147,165,120,66,446,102,273,421,96,493,116 }, +{ 13,15,23,51,0,1,2,5,77,4,10,115,3,6,9,197,7,177,202,165,961,22,11,12,457,318,217,180,31,14,21,141,33,403,40,102,32,120,453,269,8,341,59,18,16,28,44,17,64,291,93,210,719,37,352,401,110,569,49,317,134,117,90,203,475,260,365,30,450,386,494,36,730,523,125,326,196,153,24,498,98,275,901,111,99,421,308,137,349,817,48,139,752,82,72,95,116,237,86,304,391,247,873,19,509,76,372,216,482,629,57,342,899,128,373,39,758,89,65,864,351,437,105,55,221,38,144,96 }, +{ 160,251,137,93,317,36,180,1,345,120,352,752,617,318,217,332,202,96,365,531,269,498,10,901,141,83,851,341,55,143,64,816,35,968,679,800,260,473,351,230,144,21,373,244,717,82,831,201,876,533,110,372,295,559,258,418,206,203,50,28,704,855,237,349,22,669,86,261,48,898,115,860,253,926,482,9,406,748,197,67,854,873,574,7,434,564,839,69,661,450,15,902,164,228,2,219,843,268,125,187,98,5,728,16,922,165,221,613,335,109,224,442,367,384,868,77,539,840,871,291,822,417,579,116,31,918,44,326 }, +{ 42,25,6,59,85,611,233,128,122,26,4,27,19,343,91,269,614,318,45,177,283,503,138,680,77,80,73,11,216,573,145,102,445,297,0,402,235,210,275,209,174,63,202,389,84,14,803,311,18,33,529,396,255,648,416,280,40,65,256,483,10,64,2,57,678,1,667,624,250,81,24,348,304,17,196,76,194,5,544,454,114,789,151,285,133,90,74,106,51,29,690,12,349,141,61,123,119,152,137,32,355,9,52,56,7,153,525,21,237,28,13,881,36,22,87,436,111,576,300,117,605,495,370,361,291,53,23,494 }, +{ 95,64,81,91,32,237,51,65,180,7,347,74,343,207,204,511,498,577,38,197,348,56,312,128,23,20,370,49,104,43,18,138,22,233,124,86,0,90,554,28,10,681,453,21,14,280,87,750,202,141,25,546,561,29,306,115,63,16,636,241,172,165,147,85,52,24,11,467,650,580,353,192,84,6,13,713,194,673,500,283,9,368,718,151,145,72,57,33,355,263,19,544,475,412,324,318,269,235,173,140,125,108,102,4,933,174,899,519,42,643,879,751,525,403,278,247,221,217,148,123,120,112,111,97,75,73,61,59 }, +{ 326,202,120,817,260,450,494,318,403,137,704,859,128,523,77,576,5,615,553,51,342,291,23,13,1,421,234,475,142,15,48,269,178,968,147,16,21,33,639,922,285,20,49,351,7,854,682,70,58,363,265,373,198,252,402,401,158,82,416,60,132,55,455,354,0,68,102,24,2,329,141,35,101,64,18,6,121,43,95,325,165,31,9,848,798,341,36,12,805,195,32,14,411,10,146,107,75,912,569,116,96,793,424,374,167,156,98,125,17,670,692,163,604,465,25,965,629,349,115,907,427,61,457,65,621,86,71,520 }, +{ 43,20,107,356,362,595,126,92,7,359,319,858,392,493,422,246,441,259,173,683,414,49,97,5,819,279,21,104,60,16,230,35,945,232,0,612,376,48,660,121,32,199,147,132,649,22,18,71,14,663,61,423,470,13,146,672,81,623,298,1,105,693,125,159,408,58,427,98,51,165,501,263,729,95,68,4,24,12,325,779,140,55,23,953,426,28,560,72,804,715,241,581,767,314,939,885,202,118,40,204,102,33,37,17,955,192,713,70,221,598,397,77,2,387,251,344,64,44,31,10,941,75,6,465,603,534,46,761 }, +{ 42,25,6,77,210,483,690,29,102,33,122,342,0,27,4,59,177,40,19,91,300,680,18,21,648,153,196,26,475,202,117,494,128,119,790,48,22,2,343,85,145,56,36,24,32,757,81,1,684,106,292,269,28,833,9,814,151,402,137,84,45,134,70,64,23,139,112,464,396,73,655,115,52,20,614,14,10,403,50,216,63,13,358,233,370,86,7,5,76,37,17,12,485,72,65,397,476,291,57,51,80,611,209,881,665,491,179,99,74,49,416,11,667,624,453,174,148,113,95,235,138,275,61,742,544,341,510,746 }, +{ 31,44,299,116,599,393,456,144,492,125,22,268,242,367,28,963,9,0,105,489,948,434,301,918,36,127,384,1,95,55,49,170,98,512,109,506,206,51,320,23,940,93,558,13,900,86,203,2,10,239,64,5,959,457,141,395,143,7,293,282,855,911,137,202,12,253,165,8,417,159,338,21,24,332,115,401,498,327,551,286,719,197,352,16,791,617,269,391,128,120,870,37,763,244,180,479,14,168,386,308,65,164,39,421,473,160,6,18,692,841,403,276,499,326,730,48,951,272,685,523,713,365,169,903,450,424,559,35 }, +{ 410,521,686,367,321,662,201,772,144,335,88,934,1,98,96,921,264,284,897,274,435,443,909,744,692,203,225,551,120,393,33,960,639,44,418,382,190,217,260,93,64,523,442,197,77,9,100,30,237,166,102,948,244,31,326,765,475,438,165,615,82,10,791,473,717,351,238,206,125,12,805,498,466,213,69,842,617,268,778,899,576,127,116,110,37,5,318,187,0,699,530,303,230,855,854,822,817,613,403,269,39,35,32,21,2,489,141,23,291,704,160,478,131,966,539,905,851,768,730,352,272,247,180,175,137,36,22,922 }, +{ 878,142,178,234,786,132,195,929,416,202,146,147,77,639,522,259,687,167,271,450,481,771,626,212,590,465,49,534,455,427,198,5,315,407,120,0,360,318,48,640,325,23,125,329,113,35,883,22,562,163,346,70,581,13,21,31,98,591,1,61,121,199,107,798,279,150,818,159,20,260,379,668,354,446,44,557,494,269,43,32,10,371,293,95,55,105,141,386,58,33,344,884,64,158,467,116,768,102,93,18,16,362,342,817,60,30,518,191,296,128,711,99,223,39,535,87,170,291,777,97,51,75,402,783,7,156,363,347 }, +{ 254,39,131,578,272,9,716,310,827,829,0,224,518,166,616,333,613,846,228,938,101,30,49,252,105,890,100,219,404,406,371,159,190,265,98,286,158,688,127,68,438,385,455,931,327,910,31,242,856,1,187,709,28,924,737,258,23,329,16,21,557,51,137,96,656,625,125,44,442,116,24,18,48,35,36,13,160,88,65,731,124,863,274,22,95,293,344,395,5,93,109,553,816,128,299,627,530,916,364,761,836,301,154,284,871,118,202,676,201,144,83,276,165,419,944,456,203,10,55,512,32,7,320,724,520,60,115,593 }, +{ 699,854,230,855,473,450,831,704,351,137,217,498,352,800,251,202,160,144,253,203,201,418,206,317,332,752,443,141,1,96,36,180,326,82,822,372,93,244,83,494,335,35,365,817,69,859,237,689,898,21,617,864,318,901,44,702,384,922,954,349,345,341,98,10,48,64,824,367,187,128,295,873,284,120,67,531,579,269,7,86,5,22,678,268,2,261,840,927,957,930,28,735,13,291,31,559,947,116,143,30,851,669,373,723,23,16,260,959,661,125,868,717,403,9,748,437,110,50,213,115,223,539,55,615,466,946,285,533 }, +{ 403,475,202,453,77,318,51,402,494,23,13,33,342,102,128,576,269,141,137,450,120,899,421,523,196,4,117,40,90,275,153,365,349,59,177,291,65,210,64,217,84,0,134,670,15,372,95,197,401,817,1,180,805,341,237,96,260,194,3,285,139,114,99,18,873,326,615,503,393,386,317,293,125,24,11,389,165,70,216,800,752,745,730,719,697,678,657,277,115,108,87,83,69,36,32,21,859,111,457,901,788,323,300,283,266,130,118,86,76,57,12,352,351,9,7,6,2,842,725,541,361,329,312,221,168,124,49,945 }, +{ 144,23,291,268,197,182,202,116,98,44,264,284,415,96,70,100,125,367,141,203,39,110,905,411,1,107,93,363,120,180,296,658,82,310,447,692,897,238,361,190,77,664,260,105,88,520,48,478,166,682,118,576,340,30,18,966,51,865,13,349,379,403,795,551,921,326,687,301,254,581,223,101,676,457,404,156,812,195,242,213,208,9,165,364,323,269,65,60,615,498,21,765,621,271,137,128,917,914,890,855,481,217,154,102,68,232,883,593,523,354,131,948,318,219,691,842,846,771,272,252,0,626,382,149,87,824,822,791 }, +{ 15,23,13,77,1,51,202,120,180,115,141,260,5,0,21,9,137,450,269,128,12,2,318,365,7,197,326,351,48,102,341,177,342,352,523,217,291,403,165,6,64,110,32,373,4,317,18,16,37,36,901,22,14,10,494,90,457,28,854,453,82,24,386,817,40,33,308,8,11,475,401,752,96,922,93,3,244,30,275,719,730,349,210,421,86,160,99,17,898,285,31,961,50,39,569,44,221,59,704,49,117,35,372,237,153,55,143,899,391,253,203,116,134,615,576,144,196,402,65,125,629,98,247,482,83,20,873,509 }, +{ 0,95,18,577,32,207,64,193,29,784,65,887,715,102,52,61,671,138,49,91,74,180,104,701,237,693,474,280,403,241,804,847,22,263,6,174,344,583,453,862,475,77,85,643,500,397,38,37,306,498,494,312,289,2,81,33,5,681,942,510,370,27,283,422,316,192,25,155,347,84,901,319,113,576,24,835,355,348,43,933,814,353,72,194,240,204,42,19,298,650,523,125,86,718,173,247,51,721,389,124,879,490,707,291,153,141,58,54,17,889,202,97,402,1,546,342,134,482,36,511,421,805,750,673,426,196,120,117 }, +{ 101,9,0,252,68,364,166,100,265,124,154,329,39,16,419,212,24,404,71,118,191,676,158,35,88,18,274,553,520,382,65,562,694,28,962,677,671,60,55,30,333,302,706,149,167,604,375,49,109,857,21,703,967,917,865,1,264,593,806,344,310,438,346,190,48,254,96,105,439,23,22,701,812,13,125,175,777,67,925,51,159,656,83,589,570,7,455,95,628,289,108,98,31,286,10,5,221,429,69,810,826,336,36,435,92,131,557,639,722,32,168,793,638,272,273,14,44,128,126,114,50,170,146,37,238,127,484,634 }, +{ 16,24,191,71,167,118,212,18,35,68,149,375,101,108,302,589,60,92,755,9,21,562,674,124,154,246,0,273,48,1,126,363,398,411,55,7,447,146,458,350,841,695,140,65,818,150,388,199,628,345,478,264,22,13,189,647,95,271,602,32,69,823,267,121,28,50,67,796,14,346,23,650,49,175,5,621,520,664,51,882,399,10,903,133,815,777,252,98,100,197,649,64,115,781,46,847,314,517,566,221,509,223,103,575,12,953,125,114,236,230,354,37,336,2,39,96,107,308,640,749,463,936,165,724,462,886,604,237 }, +{ 69,14,2,24,46,267,71,189,38,29,67,278,52,35,135,1,103,108,149,75,309,16,388,83,150,7,60,87,18,236,74,66,220,335,68,251,262,6,50,140,582,357,451,324,133,28,226,366,238,516,172,565,65,36,25,486,114,70,336,0,92,55,594,5,443,458,273,175,54,418,96,571,97,394,906,733,21,26,124,380,12,118,9,218,58,22,154,641,606,398,86,230,48,222,160,37,19,705,42,596,331,550,112,10,412,138,95,45,399,181,294,171,163,145,64,462,32,831,600,603,345,696,517,711,602,545,894,302 }, +{ 13,23,1,4,115,51,2,0,5,3,11,180,33,7,77,10,15,9,341,141,6,365,12,102,217,202,197,317,40,22,165,269,352,318,59,403,64,901,17,21,14,32,752,28,31,49,177,308,457,401,498,453,8,18,873,128,291,494,16,125,117,475,569,196,95,509,36,93,237,153,24,98,372,137,961,386,349,37,139,44,30,326,210,134,342,48,719,482,391,90,120,55,111,86,110,247,203,39,421,116,523,304,260,450,19,546,629,65,105,734,730,27,275,57,468,402,758,143,35,864,351,38,54,144,244,216,300,373 }, +{ 447,1,698,411,125,98,31,21,363,5,919,848,48,44,691,144,759,293,225,914,459,120,13,478,354,156,4,116,922,32,23,127,64,668,163,857,371,202,49,82,30,839,284,586,70,17,223,93,865,664,621,340,165,87,51,39,421,321,260,897,110,551,88,724,330,264,335,318,221,77,3,2,821,772,744,442,190,242,195,634,520,360,201,682,963,916,898,854,685,372,351,349,291,269,217,180,141,105,102,96,95,75,59,40,686,622,949,938,687,658,228,909,100,931,867,638,446,407,761,558,463,456,342,310,237,197,166,90 }, +{ 854,351,180,82,217,352,141,752,898,317,15,244,1,922,21,36,10,64,77,115,260,372,365,35,110,22,291,28,13,341,40,48,120,901,349,4,864,5,661,32,23,160,304,498,237,137,33,11,269,51,202,143,373,93,144,59,164,96,326,98,83,450,318,165,203,102,253,230,55,45,197,2,247,201,67,128,579,17,125,86,76,177,69,37,57,0,16,31,44,728,117,72,27,9,52,116,251,482,342,817,457,7,523,811,367,559,50,719,12,134,961,717,494,187,127,105,49,3,90,873,569,899,418,196,18,316,6,61 }, +{ 13,1,5,0,4,10,33,23,9,2,82,11,3,77,120,6,21,7,40,12,102,8,51,31,117,260,351,134,22,16,153,110,64,450,93,32,196,457,523,115,28,165,18,719,98,59,44,730,30,17,326,386,116,197,898,854,217,961,180,177,291,36,49,817,125,48,342,95,141,90,317,341,922,57,758,202,373,899,139,14,365,352,349,24,203,37,372,901,801,615,128,275,318,269,210,453,39,144,111,237,401,391,72,55,137,105,752,403,86,38,569,494,642,704,99,475,509,498,661,304,811,277,61,247,65,873,308,551 }, +{ 51,403,475,23,13,21,12,494,453,115,99,1,5,523,817,202,7,421,49,22,64,450,899,95,221,32,0,120,308,730,6,180,37,141,48,2,20,10,401,128,44,31,14,753,125,402,3,719,260,11,9,318,801,40,33,19,17,4,386,289,237,105,90,86,16,457,326,36,361,269,170,102,76,39,38,30,165,26,25,961,341,958,576,365,247,240,197,117,98,89,77,61,35,34,350,137,93,82,805,782,756,701,671,670,569,503,484,468,413,405,352,317,241,217,216,214,208,179,134,8,281,316,270,144,83,68,945,901 }, +{ 752,180,352,864,498,317,141,217,237,39,365,115,901,30,88,930,579,230,0,83,101,9,197,372,482,873,128,546,64,100,341,36,1,166,437,927,702,35,213,96,23,13,175,285,68,252,269,349,251,28,689,190,69,868,443,735,304,21,562,723,457,137,399,759,509,244,831,419,10,274,77,321,539,165,818,67,530,201,219,194,228,840,418,345,410,93,131,144,86,570,143,48,154,854,247,646,224,866,49,12,699,669,402,596,954,212,203,208,160,158,800,31,177,694,358,24,117,51,957,406,382,202,22,346,134,7,438,16 }, +{ 16,24,35,71,7,0,18,28,60,14,22,158,109,68,154,118,124,92,168,2,55,149,159,49,747,185,169,424,1,108,105,95,10,577,150,344,175,126,20,239,65,9,677,69,5,67,302,6,12,21,671,46,329,38,107,97,164,23,51,43,286,375,170,48,50,125,140,327,64,320,39,420,29,36,701,374,289,83,101,273,570,37,143,32,13,347,137,191,345,189,230,86,66,553,265,638,128,202,429,455,252,54,272,703,403,246,535,103,52,221,421,654,398,279,98,194,121,114,310,336,467,584,298,165,25,453,346,96 }, +{ 15,341,23,13,0,51,77,1,141,202,33,4,137,9,260,115,120,180,102,269,351,40,11,291,5,318,82,7,2,21,10,901,197,12,22,128,854,922,165,450,16,117,352,59,8,177,217,28,3,64,457,349,90,32,36,403,37,110,18,30,14,401,6,17,523,134,898,365,317,453,48,752,57,31,719,386,817,308,196,421,153,93,24,244,139,86,143,475,730,569,39,99,494,961,373,55,642,44,49,498,285,96,210,253,275,661,125,342,35,237,203,372,95,899,326,144,402,247,629,160,98,391,61,304,576,221,216,208 }, +{ 68,35,24,149,18,71,16,118,189,108,14,7,101,154,0,9,230,175,140,336,69,124,65,267,28,114,67,133,302,46,55,398,251,375,345,2,1,236,458,103,388,83,399,596,60,50,283,38,92,346,732,412,602,36,22,212,309,21,273,39,650,722,246,12,109,48,172,429,29,218,191,906,75,52,364,443,5,86,167,547,54,10,135,252,49,64,238,95,330,37,278,723,96,23,705,516,520,439,628,891,13,51,366,565,158,915,930,232,562,30,868,6,335,637,696,150,952,194,451,484,32,220,100,694,702,886,389,168 }, +{ 308,13,197,115,391,165,546,509,125,629,569,237,749,468,23,9,558,28,903,338,217,801,734,317,352,401,740,254,341,49,36,180,22,386,51,39,159,901,873,95,365,490,506,530,168,961,498,131,166,438,64,482,247,219,579,83,185,109,93,752,656,187,345,439,613,857,457,688,316,101,86,21,158,627,258,843,89,829,637,312,10,55,679,105,967,224,170,251,574,332,406,221,175,228,48,758,902,261,960,505,44,31,876,116,37,12,868,840,72,424,347,1,371,98,15,518,274,141,32,827,333,77,190,892,816,272,253,143 }, +{ 90,64,217,32,115,128,141,216,77,312,86,597,95,59,4,33,247,875,13,172,352,197,147,237,177,288,102,437,210,22,97,5,194,137,202,37,57,11,182,208,153,76,61,14,304,134,117,65,40,751,23,291,947,10,864,342,196,21,362,49,356,178,60,45,874,317,0,54,48,612,165,107,51,259,588,752,324,192,819,298,275,180,20,678,372,307,289,173,43,120,112,415,285,207,164,72,36,35,707,44,7,359,89,46,802,414,156,2,789,729,579,168,123,104,98,92,55,24,712,524,125,87,70,66,470,387,465,148 }, +{ 1,22,28,105,36,95,67,49,2,55,239,0,5,12,83,170,50,9,159,312,86,109,7,114,320,21,208,14,103,69,35,168,301,31,164,64,194,23,892,127,169,323,160,654,98,51,141,65,48,158,10,96,143,133,37,505,13,218,584,38,6,46,751,54,115,24,185,244,347,128,424,44,824,202,253,503,597,16,269,32,237,238,39,137,286,180,512,420,3,352,740,533,29,646,165,638,251,242,318,338,623,175,125,4,18,776,395,797,480,285,713,197,531,116,532,30,928,68,341,401,293,371,99,933,124,789,844,272 }, +{ 18,9,16,101,159,68,252,35,24,105,0,60,310,265,49,39,890,329,320,71,455,118,272,557,7,55,167,28,327,121,286,1,137,170,98,364,271,100,518,333,301,65,14,520,51,23,254,13,212,553,21,604,5,363,109,202,938,128,239,709,30,31,127,95,419,64,22,125,578,846,132,191,616,2,154,158,146,124,371,48,647,395,92,67,621,12,242,627,10,916,411,344,424,116,44,403,32,108,512,338,446,737,374,326,166,86,149,793,36,120,688,421,69,827,318,93,293,126,346,731,20,463,37,260,639,450,848,264 }, +{ 129,123,249,618,214,257,460,205,769,184,17,5,245,162,106,45,90,119,76,183,128,2,209,229,61,80,179,497,6,59,130,1,64,202,99,3,152,27,77,19,710,14,207,84,4,306,40,12,29,141,255,57,240,62,26,452,10,790,58,25,269,177,619,556,21,524,38,266,32,742,217,56,136,86,102,519,7,137,115,432,318,33,292,311,11,151,22,402,48,0,216,51,37,378,288,23,210,54,655,667,381,95,36,34,113,65,72,194,403,139,50,305,111,361,504,483,46,833,285,15,494,180,475,317,112,16,263,275 }, +{ 51,719,23,453,899,457,730,13,475,386,670,4,523,15,401,961,11,12,196,99,153,403,32,3,57,117,21,33,450,59,775,165,40,115,130,421,236,77,308,202,128,120,134,758,108,6,65,391,217,90,64,125,177,197,0,361,5,34,26,260,2,19,1,629,300,183,47,216,54,141,328,817,78,123,22,17,180,342,801,7,95,27,37,241,210,214,269,221,14,10,56,237,275,242,194,494,317,558,412,25,743,73,38,247,48,102,28,488,381,318,9,82,29,326,291,711,288,137,53,304,129,46,277,402,339,283,266,24 }, +{ 173,192,66,204,104,74,636,560,426,825,20,7,43,289,750,707,712,97,861,414,214,348,65,715,81,500,90,138,95,64,835,32,312,174,319,22,526,194,280,874,792,52,0,580,91,681,232,29,6,819,330,889,673,879,5,888,86,77,568,519,422,85,376,288,135,729,387,172,370,2,222,33,38,61,10,21,784,355,49,353,107,249,324,25,69,24,18,42,36,577,226,28,356,102,140,76,448,59,92,751,207,115,671,40,325,4,237,31,359,247,524,343,180,470,145,147,397,16,392,153,117,13,120,26,177,597,125,45 }, +{ 23,51,13,202,21,141,5,1,165,120,269,180,48,12,197,32,15,2,318,115,403,125,128,260,450,137,7,9,523,64,82,33,352,93,386,326,0,6,308,4,453,401,421,102,237,37,457,475,31,14,110,351,77,16,3,221,341,391,99,494,30,44,18,117,8,11,817,203,98,730,17,217,39,719,153,899,373,40,196,24,10,61,498,402,72,365,509,50,90,854,569,317,116,28,144,247,134,19,291,59,96,752,45,285,961,89,615,922,342,58,49,25,35,36,22,349,177,20,546,241,57,670,88,54,29,105,576,65 }, +{ 200,78,34,322,472,27,390,714,161,136,19,59,283,444,250,128,236,176,862,108,47,62,527,14,57,412,53,813,73,3,381,17,453,711,56,585,210,4,46,361,77,196,440,26,65,129,51,153,130,432,383,730,216,183,297,803,690,402,401,45,469,202,133,389,123,529,5,495,162,33,90,275,318,754,194,12,378,177,291,32,257,102,38,719,117,184,114,789,480,13,23,11,106,48,503,814,2,61,629,84,684,54,475,245,21,657,555,231,40,678,152,99,300,507,137,119,80,0,436,113,457,369,650,6,403,86,22,523 }, +{ 347,33,204,498,66,546,681,56,174,5,426,95,135,348,97,172,353,864,49,22,928,923,873,808,73,263,241,10,568,370,27,197,180,77,554,207,81,580,102,21,42,237,368,32,751,526,192,134,117,19,0,350,86,63,715,448,468,115,380,123,76,25,4,29,64,44,31,36,6,91,7,511,40,645,387,85,74,861,408,298,80,736,69,173,872,13,501,355,108,712,138,153,87,61,28,17,901,18,467,72,673,59,620,343,232,161,233,312,800,509,324,278,125,45,30,14,650,636,90,3,451,415,577,500,65,561,165,70 }, +{ 131,224,219,187,385,442,258,836,371,944,871,908,737,924,254,127,98,31,827,716,574,44,39,829,116,201,613,276,839,616,242,860,926,284,137,228,395,144,293,36,96,9,1,578,406,30,456,0,299,567,93,21,13,125,202,23,843,160,166,49,51,64,856,105,846,902,203,761,935,938,662,492,128,295,159,83,48,916,438,268,190,100,115,269,5,403,310,272,318,489,367,110,77,141,931,28,10,531,55,326,165,918,688,32,86,576,22,699,88,158,120,717,530,261,244,143,421,341,434,217,2,512,197,960,625,164,37,333 }, +{ 1,4,5,2,13,180,3,15,7,141,6,115,23,352,901,341,51,0,217,317,197,77,752,365,33,21,11,165,12,269,32,9,202,102,291,177,318,93,40,372,247,10,137,31,349,498,22,120,8,308,403,44,17,873,569,110,401,203,116,59,125,36,457,28,326,196,48,304,14,37,494,386,373,98,144,134,153,128,90,64,117,475,758,260,509,72,18,16,206,55,49,523,86,237,210,95,961,629,421,482,453,30,391,253,450,951,719,342,139,638,730,576,39,864,275,268,579,241,19,82,221,24,546,437,89,57,127,811 }, +{ 370,91,681,636,397,718,510,74,81,240,355,66,84,582,278,289,214,511,701,138,90,18,782,6,104,288,5,65,64,32,693,117,247,77,63,192,56,0,814,306,750,673,312,233,85,40,453,847,671,415,11,643,317,207,134,72,61,42,33,102,4,942,519,343,123,115,27,1,86,25,348,249,22,580,537,461,396,352,153,75,484,784,475,403,304,194,21,10,235,29,3,193,119,583,287,196,114,76,59,52,319,256,124,26,23,13,874,579,389,610,462,302,238,17,710,817,597,353,129,96,51,48,217,164,89,835,804,751 }, +{ 15,13,23,4,197,51,165,1,2,120,180,341,0,260,386,5,8,82,12,7,9,3,141,450,317,153,11,10,391,217,6,351,326,115,64,77,14,457,117,901,498,523,854,509,291,110,134,730,401,758,33,961,237,352,22,202,898,125,922,93,21,365,308,196,31,44,615,269,128,817,99,453,801,28,203,899,116,373,873,752,629,18,40,55,349,137,98,37,318,372,403,36,49,475,569,32,38,86,546,95,16,661,143,704,102,719,30,342,59,39,35,17,642,304,494,482,48,24,638,144,177,300,194,139,958,29,54,492 }, +{ 32,76,292,2,5,476,45,214,72,29,1,241,14,519,464,460,21,179,48,129,290,90,17,710,148,205,123,263,249,50,58,358,52,425,186,243,408,46,257,618,207,38,245,184,89,227,155,769,162,270,171,350,3,7,288,119,61,6,106,57,316,64,54,400,449,128,183,229,255,75,4,141,36,496,115,152,524,655,99,209,720,334,497,62,12,202,59,77,37,86,10,405,0,56,51,221,130,666,23,25,40,592,22,181,237,269,11,247,432,137,16,217,454,84,27,452,428,24,663,619,19,513,318,177,659,26,67,341 }, +{ 13,569,115,165,509,197,629,734,17,873,23,659,106,457,180,45,41,32,961,901,38,536,341,428,62,155,587,474,391,54,21,431,99,546,255,51,243,528,308,365,136,241,37,468,405,89,123,129,14,482,181,2,211,401,139,72,12,148,542,719,221,117,794,214,76,749,498,449,350,317,292,157,743,540,29,758,328,152,552,188,162,11,3,119,720,488,339,770,413,237,227,179,50,248,48,209,697,313,90,741,476,130,4,477,128,1,773,519,277,40,421,507,46,266,57,249,33,245,361,137,153,202,453,369,471,64,133,358 }, +{ 68,101,24,35,71,16,154,124,9,0,149,118,175,65,302,18,108,375,346,28,55,92,252,364,212,429,191,7,439,60,694,39,520,14,398,806,100,22,109,329,166,167,484,273,336,604,67,69,419,189,562,21,826,589,1,701,695,345,95,140,230,265,246,49,10,264,48,158,114,637,755,168,103,917,133,46,628,2,64,722,126,650,399,88,404,535,125,768,570,289,150,458,13,706,83,30,50,36,388,32,420,23,267,12,185,5,882,674,818,96,169,51,676,925,37,363,283,602,86,105,38,221,333,967,159,286,942,553 }, +{ 0,9,68,35,1,65,101,230,69,28,124,23,83,39,141,154,67,13,21,352,212,217,51,30,100,252,88,16,336,115,48,175,864,103,24,317,189,5,180,114,166,128,96,443,36,399,10,12,238,64,329,562,264,478,177,32,18,265,752,77,55,22,321,372,291,218,160,702,149,520,167,50,437,304,202,498,247,137,118,269,99,49,596,365,589,221,759,486,349,197,165,382,346,323,410,2,664,480,223,419,213,777,604,433,418,75,7,4,335,482,15,547,532,37,251,363,237,125,936,72,143,755,341,553,308,190,109,201 }, +{ 909,265,100,410,382,812,88,593,321,213,1,30,252,166,676,639,264,435,466,230,689,39,9,48,724,352,478,21,98,553,96,329,190,223,101,23,274,51,217,13,83,5,921,310,699,438,795,125,69,821,905,530,293,752,759,35,36,656,557,128,144,393,443,520,0,541,284,521,604,137,419,32,682,831,141,455,317,418,664,855,854,251,31,165,772,221,404,386,93,201,180,203,33,686,421,335,539,840,115,55,127,44,957,160,285,158,28,344,68,67,367,77,202,345,254,697,102,669,562,897,807,702,765,286,10,351,64,269 }, +{ 113,61,904,43,0,204,848,453,389,315,788,198,174,5,22,899,222,59,37,102,33,207,422,290,288,128,97,329,306,46,31,30,77,470,817,523,159,58,40,942,122,65,725,690,324,291,104,64,263,450,426,20,54,337,304,247,205,196,153,134,117,105,95,49,408,757,615,351,326,194,115,82,28,18,9,177,137,32,350,887,372,347,331,325,217,90,48,2,701,344,342,320,316,158,317,804,376,341,819,319,849,685,666,600,580,579,553,501,498,403,392,365,357,349,330,301,270,262,242,237,180,112,76,44,39,36,7,147 }, +{ 24,16,141,71,18,0,352,269,75,108,140,7,60,35,330,12,199,217,65,9,486,28,498,864,87,246,64,92,68,50,318,267,126,954,118,115,55,230,70,5,146,177,950,545,13,372,197,752,271,101,98,14,133,77,180,641,349,317,99,36,726,458,23,537,487,156,102,437,22,10,622,165,21,563,516,832,202,2,341,149,48,565,86,457,304,273,220,237,116,44,674,526,117,100,39,33,120,49,37,365,360,830,58,137,103,291,135,522,181,166,121,88,54,51,412,167,284,223,46,15,394,1,696,852,463,361,264,212 }, +{ 271,167,121,60,199,146,191,463,18,446,212,132,575,126,598,354,407,16,955,727,640,566,1,608,195,35,562,279,522,21,48,107,98,71,118,783,223,493,150,467,68,589,24,5,360,781,92,156,363,591,411,668,447,55,13,534,818,101,23,9,108,346,581,647,777,590,49,621,0,259,125,362,936,664,939,7,273,28,31,22,51,163,32,807,10,535,834,221,147,520,246,33,293,541,50,37,586,14,815,375,393,4,116,12,105,96,70,2,44,77,39,93,252,149,281,441,46,158,75,61,759,154,97,649,95,423,364,140 }, +{ 15,115,217,317,365,341,180,13,141,33,23,260,120,4,82,110,102,351,51,40,854,77,372,137,352,21,64,1,5,32,36,10,197,117,898,752,11,901,269,202,922,165,59,9,160,244,0,661,373,134,2,143,22,48,457,349,153,253,450,12,386,196,318,482,247,326,128,308,177,55,72,90,498,523,7,125,961,719,93,28,37,86,3,291,811,509,237,96,57,873,16,437,89,579,391,730,111,203,31,864,18,6,615,35,468,210,216,14,569,275,139,164,304,17,342,76,899,403,221,494,642,316,817,251,30,531,717,95 }, +{ 173,97,356,7,43,387,107,426,104,729,414,359,232,20,560,392,595,885,858,861,707,819,66,81,612,5,49,22,362,319,126,192,230,32,660,330,0,74,357,92,246,147,784,715,14,324,298,172,470,879,95,263,2,422,259,16,427,38,314,207,683,61,376,140,21,681,35,6,29,397,91,60,18,241,10,279,28,64,52,77,24,830,500,493,31,636,33,37,501,12,4,86,779,204,135,58,577,370,65,568,441,40,199,48,526,13,98,581,712,105,534,125,325,17,102,72,44,347,750,138,120,70,59,46,465,25,45,30 }, +{ 15,23,13,82,120,51,110,93,31,33,116,98,95,196,453,4,165,40,197,260,117,0,386,2,180,217,12,1,351,11,77,5,8,134,102,9,141,326,457,115,341,291,3,153,10,401,21,450,317,523,854,202,352,14,7,391,898,6,64,961,373,719,22,125,475,901,28,922,615,403,18,177,269,498,203,237,44,349,99,758,509,32,30,318,128,37,817,16,899,629,308,57,365,670,36,421,49,139,275,661,730,111,569,137,24,39,48,86,704,144,801,752,35,17,65,109,494,342,558,38,372,551,221,216,170,46,55,638 }, +{ 100,9,120,260,30,827,795,373,264,77,137,166,202,326,127,578,1,39,254,82,704,318,217,450,18,101,395,737,351,0,731,291,265,317,156,349,341,31,716,105,102,93,141,197,55,33,968,98,269,5,296,128,478,131,24,851,252,371,342,32,859,938,921,44,616,411,403,404,385,924,144,109,165,40,456,274,180,10,494,836,16,512,854,410,299,195,110,68,28,7,518,442,36,438,286,242,13,244,167,96,363,850,379,656,521,284,95,523,125,64,658,615,340,116,67,922,212,115,447,187,937,935,916,724,936,856,822,372 }, +{ 14,24,2,67,69,46,28,108,1,65,38,83,7,398,18,0,124,154,114,103,36,50,267,133,29,55,236,189,149,35,16,547,52,68,429,175,283,71,336,9,160,118,309,22,302,251,109,458,646,75,6,140,388,86,135,484,278,412,12,596,5,389,650,172,531,54,238,60,218,420,602,96,21,66,208,87,886,220,194,505,782,150,185,169,92,64,10,891,168,95,25,101,797,335,289,533,570,532,74,906,37,230,48,357,49,273,262,323,366,696,346,158,23,516,443,39,32,799,70,565,58,705,137,51,13,439,418,128 }, +{ 66,69,14,267,189,24,71,7,150,172,140,97,149,16,60,380,135,462,2,35,67,74,388,92,38,18,451,278,108,29,83,68,251,6,357,52,46,1,230,443,36,324,423,298,458,65,273,28,336,517,314,823,232,192,398,330,711,118,594,103,87,0,75,565,175,55,335,399,705,124,22,86,25,21,603,448,906,568,204,95,48,12,50,236,5,563,309,43,550,10,154,138,64,32,345,302,37,596,893,20,133,572,54,467,114,126,607,42,26,160,246,220,733,375,809,226,429,526,501,723,9,895,49,808,70,500,602,915 }, +{ 15,1,13,5,2,341,4,365,3,0,23,10,11,7,12,180,6,117,9,17,33,21,134,115,77,14,32,217,197,102,317,165,8,141,457,153,64,40,901,37,51,128,22,961,569,291,202,196,16,31,269,177,352,36,137,38,873,372,28,93,19,351,59,55,349,111,44,509,342,498,752,18,48,125,318,99,304,139,120,386,143,237,116,308,72,401,86,391,110,30,95,54,629,27,482,210,76,45,164,24,89,79,29,90,453,403,25,719,57,275,203,216,82,98,41,758,579,277,247,46,260,49,523,244,26,285,326,144 }, +{ 1,22,12,5,28,36,0,21,2,86,49,48,95,55,37,23,10,50,9,7,96,13,202,32,51,105,14,54,208,168,65,115,128,24,83,16,160,67,4,141,137,31,64,99,318,3,269,194,109,6,323,18,164,159,17,114,35,170,239,281,402,285,180,11,238,745,69,584,103,197,165,480,158,45,341,181,169,403,77,244,44,46,38,218,143,98,433,289,401,30,223,58,717,125,657,503,352,217,851,33,177,185,29,946,597,757,708,39,365,312,317,72,800,253,75,789,102,678,124,418,133,237,59,956,90,127,308,430 }, +{ 123,605,630,63,108,736,444,65,650,368,19,561,619,389,122,216,25,114,183,177,26,53,27,813,133,42,102,194,84,445,249,899,297,56,421,349,90,401,33,597,588,250,137,78,73,130,11,730,51,283,45,524,629,235,59,57,14,141,196,153,32,40,343,255,719,134,117,467,304,119,76,17,13,0,152,6,436,77,390,4,323,511,678,475,457,136,64,594,342,23,403,256,12,129,503,218,208,86,62,61,5,416,233,372,52,3,469,184,275,381,106,947,789,554,214,112,680,450,95,309,217,18,9,529,432,291,269,80 }, +{ 127,39,9,254,98,395,371,31,0,385,836,44,1,30,299,284,100,166,116,578,131,187,272,28,935,49,293,276,21,125,23,16,219,310,599,51,737,442,827,48,242,616,137,18,101,908,5,144,13,846,24,265,456,716,35,512,96,252,93,88,202,22,201,68,159,36,158,7,77,55,224,924,938,141,492,203,128,190,688,269,518,258,32,333,64,37,318,228,2,65,829,326,274,244,761,165,12,115,67,286,120,931,217,110,367,404,105,839,33,102,567,83,268,916,662,95,438,14,86,50,944,109,574,557,69,327,625,10 }, +{ 2,29,61,45,151,6,655,112,207,52,25,425,32,833,76,7,70,106,1,113,14,119,292,790,58,26,72,5,887,64,209,128,17,90,255,315,66,19,145,4,186,306,243,476,115,59,483,27,77,74,21,177,311,38,87,86,40,263,141,738,46,290,36,23,148,454,287,10,240,95,42,22,84,16,137,0,179,202,135,33,631,491,814,75,227,51,269,89,50,210,65,214,20,12,80,222,48,318,24,28,49,13,11,216,18,155,358,102,99,56,464,122,37,644,138,549,710,54,180,337,205,117,496,67,172,869,123,720 }, +{ 2,17,5,29,27,3,6,401,45,58,51,26,23,19,53,52,14,34,46,453,151,133,366,13,61,236,50,218,114,1,73,99,308,487,603,108,21,25,181,670,287,421,297,80,115,396,48,74,56,137,171,412,764,445,202,38,281,62,457,42,65,629,516,480,475,341,113,549,64,573,600,386,57,403,894,250,106,730,54,436,651,491,86,145,12,334,208,155,832,128,328,614,361,262,165,283,84,32,719,323,745,200,90,141,37,36,711,657,631,67,760,754,583,739,635,569,7,594,488,315,161,10,285,59,402,758,243,430 }, +{ 22,170,31,301,127,1,98,44,28,36,239,105,55,299,512,293,86,395,116,685,242,841,9,95,125,338,599,900,2,0,5,654,23,320,169,109,13,456,870,49,64,185,763,10,51,7,237,12,141,144,164,479,143,965,312,35,137,923,21,268,115,14,933,492,128,168,393,284,506,67,286,762,276,83,37,244,6,114,202,160,180,928,24,352,634,194,367,201,197,159,308,165,269,253,558,844,401,538,48,65,208,272,935,391,584,50,420,341,365,131,203,913,318,16,498,3,489,327,96,4,457,374,317,892,386,32,434,638 }, +{ 14,21,50,48,5,2,1,32,270,46,38,290,76,72,45,155,54,17,263,181,408,207,425,281,29,430,221,67,36,96,292,89,449,52,428,37,476,513,241,83,103,119,0,171,7,541,720,528,3,12,10,24,227,148,22,58,179,61,536,502,214,243,655,6,413,90,9,350,23,218,106,51,16,86,69,129,65,186,28,133,115,114,99,431,552,400,760,794,464,64,474,128,433,123,328,460,18,405,137,487,306,84,108,477,245,710,35,236,205,4,13,787,27,238,308,587,309,770,141,540,19,56,790,240,95,223,488,202 }, +{ 17,119,106,378,240,383,136,84,62,80,306,790,56,504,742,3,440,207,209,128,255,483,123,45,5,667,61,32,57,64,179,27,129,14,205,548,297,4,245,2,214,311,141,90,11,76,833,655,184,151,29,361,59,469,152,249,26,38,162,19,58,215,328,257,73,495,161,34,54,229,269,202,250,266,292,21,12,402,514,555,216,113,194,887,130,1,445,503,507,183,6,25,318,237,186,72,52,814,710,618,99,10,86,211,148,452,263,243,65,137,37,40,41,23,36,33,155,497,13,403,53,95,313,227,494,180,77,738 }, +{ 13,1,2,15,23,5,115,0,51,10,4,3,6,341,7,11,365,217,180,317,9,33,197,77,165,40,22,12,14,102,64,141,117,153,196,453,457,8,202,901,17,21,269,18,128,28,125,569,31,386,59,318,32,16,134,349,352,291,372,237,36,719,403,752,475,873,961,730,509,391,177,137,24,401,95,57,44,37,93,498,120,308,139,494,110,98,326,111,247,86,304,30,482,49,143,48,55,629,210,260,758,523,19,351,65,450,72,116,46,76,342,29,275,203,50,170,105,164,89,82,734,242,27,38,54,144,899,90 }, +{ 772,335,662,96,367,744,897,1,303,686,264,521,652,340,116,520,141,31,919,201,966,260,888,203,44,64,905,321,144,225,269,98,691,658,349,284,410,698,692,363,120,88,848,717,863,187,551,914,909,418,576,202,646,443,850,639,523,69,404,336,958,293,128,730,131,615,274,382,296,166,960,948,258,228,224,219,751,486,160,125,82,411,191,765,244,223,475,453,352,326,100,318,676,596,67,351,899,703,403,389,435,947,589,498,102,33,954,291,265,156,922,854,402,93,759,664,447,372,212,137,478,329,724,562,530,286,217,942 }, +{ 1,28,5,0,36,24,65,83,50,14,67,22,12,96,2,48,218,114,281,54,18,21,9,133,55,103,46,181,37,58,160,38,16,7,99,10,223,69,238,32,430,433,502,45,35,51,766,49,108,86,23,124,361,155,487,765,532,283,75,137,270,115,17,838,163,109,480,95,13,61,6,543,154,754,513,70,29,72,202,540,822,657,323,920,398,89,68,64,141,966,3,221,208,285,128,290,956,547,488,269,236,175,168,429,194,474,800,646,171,39,412,775,52,308,531,866,149,880,389,4,180,403,318,842,834,402,217,185 }, +{ 138,174,348,42,25,6,145,81,544,280,525,74,85,26,648,204,355,287,396,91,233,66,636,104,122,746,416,29,64,65,90,45,0,235,194,681,87,22,222,651,95,624,573,32,214,289,750,415,343,445,192,52,112,86,17,370,19,5,135,881,7,151,2,337,113,605,243,63,389,256,49,59,10,4,673,680,77,18,297,61,312,76,614,97,72,249,283,11,524,70,353,33,27,28,216,114,874,173,311,57,43,21,14,597,36,1,141,102,58,24,217,12,436,665,80,172,715,792,148,123,619,56,133,20,491,75,784,117 }, +{ 24,16,35,68,0,18,158,28,71,159,49,7,55,154,109,14,22,60,105,124,344,65,118,424,9,239,95,1,320,2,149,577,286,170,92,169,108,347,12,21,327,374,175,185,67,10,272,5,101,51,48,23,302,455,39,6,671,301,46,13,69,310,20,518,64,150,36,346,50,32,137,202,709,677,191,126,98,125,375,168,538,289,164,38,37,128,638,30,703,747,890,273,127,634,31,419,140,143,439,86,403,114,252,83,962,654,221,762,623,338,115,29,212,103,701,570,308,107,512,189,54,97,167,230,479,345,312,913 }, +{ 854,699,230,352,93,689,144,251,160,137,855,202,617,203,217,36,669,332,450,120,473,351,831,201,213,752,326,800,206,141,258,748,82,418,345,30,180,816,957,318,840,190,443,228,44,35,863,968,10,1,219,871,704,317,64,22,679,83,466,539,498,224,55,96,898,31,116,406,851,384,86,244,295,28,873,98,817,531,187,822,864,373,494,131,559,372,530,901,574,365,69,127,839,735,128,268,67,533,442,868,860,922,88,269,927,859,9,367,613,253,564,930,567,261,260,728,39,237,109,284,276,164,730,489,166,926,125,776 }, +{ 15,13,5,1,2,23,3,0,317,51,115,4,10,11,7,6,217,33,9,77,17,14,341,165,102,117,180,365,134,40,197,153,64,22,12,32,196,21,8,141,391,110,752,372,291,498,352,125,569,16,36,901,202,59,260,28,237,482,349,18,269,457,961,120,318,93,57,509,37,29,128,177,49,31,19,401,48,453,342,38,719,873,45,55,629,111,24,44,143,468,386,50,54,403,86,139,27,308,304,95,210,546,730,475,46,137,98,247,35,72,90,99,82,76,437,494,864,30,326,758,96,52,275,116,402,277,164,56 }, +{ 104,173,20,319,43,66,426,355,712,77,97,0,202,7,198,74,580,204,174,500,32,5,59,2,102,337,90,325,226,234,4,52,22,450,904,155,222,376,861,21,750,33,192,414,194,147,324,342,889,58,544,636,18,291,416,112,784,81,334,64,707,95,331,422,639,715,36,400,14,141,560,792,65,29,177,49,37,315,427,28,57,10,120,24,1,40,48,107,673,11,494,318,230,61,524,128,196,16,12,470,632,232,138,115,329,455,113,142,186,153,819,294,17,525,526,70,117,87,25,247,587,105,269,583,588,158,171,348 }, +{ 23,13,51,5,15,1,2,115,0,141,12,7,4,21,6,165,32,3,269,9,10,457,202,180,197,14,77,11,37,453,22,318,352,120,33,719,217,341,401,403,16,961,17,40,308,18,31,28,8,48,64,475,569,730,260,365,59,128,247,317,137,177,90,93,237,102,99,629,523,44,386,117,36,450,110,153,30,752,899,38,349,72,134,98,509,498,49,326,901,125,24,391,196,421,57,82,291,76,95,19,203,494,89,45,817,304,468,221,139,210,758,351,546,65,373,372,96,54,482,734,144,116,86,39,29,216,402,288 }, +{ 15,1,13,0,2,5,4,23,3,317,115,51,7,6,341,9,8,365,217,22,10,33,77,31,457,197,44,901,18,12,28,180,11,120,165,202,961,102,719,569,40,308,21,730,20,260,351,523,141,36,401,64,482,82,55,49,450,453,403,269,93,318,16,30,498,468,342,14,372,352,110,61,817,125,137,386,117,70,899,25,898,291,509,196,494,475,24,629,854,39,153,349,98,32,134,221,391,416,234,758,59,37,237,95,86,19,91,48,27,177,247,326,903,17,734,873,89,128,421,105,922,57,111,143,638,300,304,90 }, +{ 15,1,3,2,0,4,10,5,9,13,82,12,8,11,16,7,31,23,351,898,365,93,44,854,22,64,21,457,217,180,6,141,317,730,110,318,18,752,719,352,341,51,961,28,269,33,260,77,922,120,202,291,98,55,372,197,349,901,105,165,30,450,14,817,494,523,403,899,128,125,453,95,36,115,116,475,386,326,49,401,111,94,811,642,758,479,474,391,373,203,201,187,153,144,137,38,37,24,102,59,421,282,206,48,569,342,275,216,210,864,846,801,795,692,661,597,559,442,253,244,230,196,177,170,143,127,123,89 }, +{ 2,5,14,1,29,50,38,46,45,17,52,58,114,133,171,218,21,181,48,186,36,6,155,3,19,65,487,12,32,54,27,61,480,323,70,22,51,86,361,137,96,0,208,115,285,227,283,151,23,412,10,281,28,108,37,236,112,328,7,334,163,400,25,4,223,26,67,75,657,194,18,103,128,24,13,514,745,99,401,202,308,532,59,803,389,16,760,11,243,72,64,80,106,9,502,83,832,113,453,56,552,421,403,503,402,95,735,341,956,69,124,782,366,90,141,409,77,57,160,822,433,89,209,244,40,76,177,484 }, +{ 68,101,0,9,212,124,154,65,149,35,16,100,118,24,252,71,562,589,189,336,114,167,265,191,39,329,398,88,67,429,1,264,478,69,166,484,55,30,777,18,399,520,759,13,818,722,175,419,230,48,283,664,796,115,23,28,375,724,346,140,133,103,410,21,705,806,64,51,701,604,83,246,7,345,158,389,60,36,382,302,14,2,108,50,755,5,695,694,237,702,547,917,92,639,411,936,732,213,267,238,32,404,190,10,364,321,289,49,180,553,447,247,650,72,218,46,593,925,468,458,96,905,596,217,95,546,223,439 }, +{ 14,2,1,22,46,67,7,65,28,24,0,69,38,168,50,36,83,289,5,12,16,29,35,55,86,114,103,133,109,49,18,158,95,108,6,194,584,124,185,610,52,169,10,159,189,105,51,23,21,484,283,9,505,389,236,128,239,267,420,164,13,547,143,54,32,64,71,115,149,75,37,140,251,68,48,208,160,253,708,309,137,96,154,244,312,170,782,202,320,412,577,175,308,424,25,141,336,429,218,344,60,892,835,874,347,398,401,531,230,17,278,388,92,135,797,638,732,237,3,323,39,19,286,99,747,4,66,403 }, +{ 23,13,51,15,0,10,115,1,4,2,9,961,457,77,11,5,453,12,33,3,403,14,40,102,197,7,22,165,59,475,64,6,37,401,21,569,719,18,308,99,32,17,177,730,16,141,523,8,341,31,629,217,180,117,386,202,153,196,120,57,28,49,111,125,95,139,899,494,128,421,72,65,210,317,36,342,391,90,19,93,89,44,86,269,365,24,291,237,110,76,318,873,509,482,54,48,300,498,247,134,450,82,275,260,352,98,27,137,326,38,304,758,148,50,79,817,45,670,372,30,179,29,203,734,152,116,349,216 }, +{ 15,1,0,2,5,9,7,23,13,51,901,8,6,12,3,4,180,10,719,341,120,14,31,115,22,141,898,197,82,260,93,21,28,44,457,37,217,125,202,16,153,351,64,110,401,18,11,33,36,961,569,30,77,49,352,450,98,269,139,317,117,116,32,40,453,326,308,128,523,318,365,203,137,730,24,629,854,403,102,39,237,165,55,291,99,475,95,196,48,86,498,134,752,899,373,391,817,244,38,105,242,421,922,59,144,386,57,143,35,349,54,509,482,372,65,253,221,177,304,494,247,638,17,170,72,127,164,114 }, +{ 100,252,265,88,724,101,382,410,48,676,213,909,321,9,593,0,812,329,553,21,352,1,30,230,166,39,419,520,23,51,264,217,221,478,689,435,190,664,13,604,466,677,694,125,752,777,36,98,699,639,83,759,96,35,158,68,128,562,141,223,344,274,310,69,455,115,5,180,404,317,656,364,203,293,831,438,175,308,443,401,333,31,144,570,154,854,105,137,212,346,49,857,530,418,840,855,201,55,921,28,539,421,557,806,821,127,124,67,251,10,634,165,936,22,610,795,16,286,957,167,541,32,962,905,682,686,241,44 }, +{ 58,171,2,46,5,50,14,29,186,1,52,45,334,151,400,38,155,61,103,96,67,227,502,281,223,54,48,17,83,181,552,69,70,309,75,163,24,549,21,311,27,366,80,536,243,113,218,787,106,36,112,433,765,430,209,133,12,6,236,487,19,780,675,394,766,238,587,545,32,37,767,807,834,7,108,114,328,287,315,65,262,820,16,496,583,26,18,454,513,0,3,600,220,25,474,86,307,73,28,35,255,869,537,631,22,72,89,491,409,357,64,270,828,267,189,845,160,221,10,592,137,119,99,659,128,516,541,785 }, +{ 23,202,120,141,51,13,318,269,21,128,260,165,137,197,180,326,1,450,5,77,33,82,15,48,93,64,110,351,32,125,403,203,102,523,854,386,352,457,922,115,7,2,12,494,373,817,615,196,342,153,221,217,16,6,210,144,402,453,36,4,391,14,37,730,9,96,475,291,98,0,99,901,3,421,551,177,18,40,401,237,752,349,31,898,86,719,341,24,704,285,117,11,308,393,116,35,61,160,8,30,65,90,59,44,275,10,241,50,39,216,509,372,67,72,961,247,22,899,28,569,293,83,139,801,473,76,95,46 }, +{ 341,197,901,10,13,569,23,638,15,479,8,873,961,180,165,143,12,115,0,1,951,509,116,37,642,365,499,498,242,253,5,36,898,4,752,2,352,141,268,206,51,55,401,391,7,22,3,417,506,492,82,9,93,11,137,456,338,244,457,64,317,120,110,629,351,546,431,33,21,386,31,86,260,217,164,6,758,965,28,762,474,918,661,326,551,153,125,14,719,94,421,854,203,801,373,269,44,16,730,202,615,237,844,791,811,523,450,40,18,128,864,282,117,111,148,824,940,102,959,17,139,559,170,32,958,867,968,38 }, +{ 23,1,21,51,202,13,15,141,120,5,180,2,197,165,7,269,352,48,12,318,260,326,137,33,386,403,9,450,0,32,6,4,115,128,14,16,523,457,102,37,110,82,93,18,217,3,64,221,752,421,203,453,237,125,77,153,351,494,308,475,196,401,719,31,44,391,373,817,24,730,8,342,30,36,11,40,341,901,96,50,99,615,98,116,117,39,10,22,498,317,17,59,35,160,144,86,28,20,854,961,291,244,177,899,72,402,509,90,922,350,349,95,29,247,285,19,127,661,365,372,49,569,758,65,576,241,898,61 }, +{ 2,29,58,50,262,52,53,27,6,151,14,1,171,5,287,34,324,17,74,46,26,113,309,396,45,223,61,334,96,73,635,445,583,38,19,75,67,103,80,357,70,331,181,573,112,785,236,675,163,281,549,145,366,54,108,315,760,218,220,491,453,297,12,138,62,250,133,436,51,409,200,487,600,128,502,37,64,106,114,651,48,83,394,24,25,820,433,59,766,307,23,155,36,614,311,65,66,137,57,4,765,186,69,21,99,202,56,13,3,587,165,767,7,631,238,86,780,115,283,161,322,545,221,42,32,739,400,47 }, +{ 13,51,23,141,202,115,217,77,317,4,269,33,5,11,318,352,0,102,180,2,64,10,341,7,21,9,137,3,40,128,32,6,22,291,752,15,197,12,365,1,165,31,125,28,498,177,16,403,494,237,18,308,44,59,372,98,349,24,93,48,244,386,49,90,30,342,95,901,475,39,120,196,14,117,457,116,453,17,247,391,153,8,143,482,36,304,203,110,509,326,450,260,37,134,144,210,468,523,86,221,401,569,873,546,719,139,253,35,160,127,285,105,373,421,961,864,576,82,367,437,351,55,579,19,216,275,402,164 }, +{ 1,24,67,50,69,103,35,18,16,14,28,0,5,83,9,54,223,2,96,58,181,12,46,68,48,65,108,133,71,281,149,22,7,163,21,114,36,75,38,55,155,502,238,37,189,99,70,218,45,10,430,433,236,60,765,251,171,61,175,540,23,820,32,51,418,270,29,487,513,52,124,118,336,17,64,49,920,154,13,141,115,545,72,267,221,537,745,290,86,488,309,128,335,39,227,89,328,160,95,834,361,6,101,486,514,543,112,137,474,394,186,202,388,109,150,140,552,807,412,283,307,345,87,780,366,398,77,516 }, +{ 13,23,51,141,202,115,77,269,64,217,102,128,318,33,32,291,177,180,137,10,352,4,21,16,197,0,11,22,9,7,165,90,40,494,125,2,210,247,14,18,153,49,59,31,6,95,317,28,196,349,24,304,5,341,403,342,98,237,117,120,372,44,3,275,35,86,48,1,93,752,36,15,241,12,475,144,30,19,17,216,110,365,260,116,326,134,82,105,143,308,203,20,39,402,386,221,901,127,72,498,437,244,453,76,401,65,38,96,285,316,160,55,351,25,288,482,164,57,139,457,678,490,201,523,509,391,83,817 }, +{ 115,365,180,317,873,498,752,482,341,569,217,901,13,197,352,546,468,1,864,457,509,579,165,23,143,21,15,2,185,36,7,148,12,134,332,22,351,9,261,51,16,5,10,0,346,93,30,141,868,734,372,253,345,116,474,94,77,876,76,28,896,679,384,203,160,39,37,6,98,14,391,109,530,187,843,177,86,629,33,637,11,437,18,4,902,574,434,144,120,44,31,837,72,613,295,169,349,505,228,190,102,95,49,48,706,406,405,96,83,961,617,597,254,237,926,903,717,531,420,258,164,110,860,268,661,477,464,449 }, +{ 184,257,229,205,432,497,152,619,452,17,381,57,266,524,5,45,90,106,313,471,245,32,128,129,59,4,214,2,339,119,769,77,369,12,123,21,14,99,157,3,202,38,710,1,618,216,64,217,292,188,162,76,11,40,249,141,62,51,33,19,372,102,179,37,209,23,27,6,111,318,29,61,403,86,460,349,207,54,269,402,10,48,139,115,36,136,79,137,7,255,72,80,177,519,291,453,529,401,288,58,0,153,475,377,247,306,25,56,26,94,210,22,84,494,50,790,89,775,474,361,328,148,241,588,285,317,678,277 }, +{ 13,23,1,2,0,51,10,5,115,4,15,3,365,7,9,33,11,180,77,6,217,341,22,102,317,40,197,14,12,64,141,165,18,8,17,31,202,28,125,16,269,21,117,901,453,196,177,59,153,36,128,475,318,569,32,24,352,291,403,134,93,401,98,44,752,237,391,372,49,509,457,961,873,308,498,386,95,342,349,116,137,37,139,494,19,30,210,247,143,304,86,629,48,203,111,55,57,719,523,110,482,546,120,38,65,54,326,421,216,730,50,99,899,758,402,260,105,275,39,72,450,96,144,35,25,242,29,437 }, +{ 626,70,687,771,379,767,846,518,878,49,937,591,82,761,31,786,481,407,845,195,590,351,98,44,163,557,13,120,125,48,87,883,371,623,360,817,450,260,178,522,21,5,854,523,116,326,105,291,142,4,296,929,884,259,127,0,132,922,615,77,713,293,217,197,165,22,146,64,931,608,465,457,349,196,32,941,455,279,621,315,202,201,126,110,40,16,11,10,391,666,467,446,373,354,346,144,58,33,581,763,512,916,535,795,768,658,558,447,344,150,92,51,28,24,9,265,212,93,586,562,180,156,147,134,117,1,783,663 }, +{ 264,909,410,897,772,1,686,521,478,914,98,335,96,284,691,639,382,44,744,321,724,100,765,438,223,662,88,144,475,367,31,265,125,116,921,9,682,656,166,363,127,225,21,201,842,0,447,905,393,48,443,421,5,82,329,252,120,805,411,51,821,13,919,69,834,948,934,664,33,23,435,551,274,77,217,131,268,7,93,854,418,520,340,110,30,213,141,453,165,101,39,791,260,922,403,238,698,898,351,102,593,433,64,203,83,303,286,293,197,32,960,812,697,523,466,285,180,692,404,658,35,873,254,163,352,553,190,615 }, +{ 13,23,2,51,1,5,115,0,10,77,15,217,7,6,180,33,3,317,40,4,141,102,9,197,11,341,14,64,165,22,365,17,117,196,352,202,12,269,153,16,291,237,453,128,457,498,752,32,18,134,177,59,21,125,386,318,901,28,8,372,31,349,391,403,95,475,36,137,569,49,308,961,401,509,482,143,98,19,24,44,730,86,120,719,139,546,402,342,93,304,110,29,210,421,873,45,38,629,57,260,326,247,111,275,30,523,55,90,450,46,116,253,50,37,244,65,494,105,99,468,758,25,170,48,96,216,35,27 }, +{ 141,269,77,115,13,318,64,202,177,23,137,217,102,291,5,51,180,48,21,352,0,32,7,16,33,18,11,2,197,128,4,15,10,752,24,244,14,494,317,165,96,9,3,349,247,237,93,35,28,12,6,49,44,1,421,60,20,403,36,341,95,22,475,372,326,308,275,196,144,90,40,39,117,31,678,954,901,304,284,268,221,203,110,98,89,68,46,365,153,134,76,67,576,453,432,402,381,342,179,125,118,86,72,71,69,59,50,17,498,160,164,143,120,111,82,961,873,851,401,377,335,288,285,241,223,210,121,116 }, +{ 23,13,51,15,0,10,453,2,115,1,40,961,33,11,14,4,9,457,22,401,77,102,7,5,569,475,197,12,64,3,21,165,59,719,629,6,196,18,177,386,37,32,17,111,153,57,117,139,31,16,28,730,308,99,38,141,8,403,36,128,670,391,217,210,72,90,523,79,482,341,202,237,45,474,180,125,41,509,46,494,304,275,48,54,95,94,899,29,277,134,120,76,758,65,44,247,498,24,291,148,89,468,86,49,437,82,56,30,402,143,365,349,317,93,50,757,269,734,342,98,352,450,678,62,188,19,152,328 }, +{ 1,22,36,5,12,0,105,28,2,49,31,21,95,9,86,55,13,23,128,7,141,98,170,44,115,239,37,48,127,83,160,4,180,164,51,202,10,269,3,96,6,208,159,137,67,244,320,197,312,50,318,352,64,285,301,125,341,32,165,109,116,217,14,402,708,39,365,16,654,35,30,242,317,169,168,99,253,15,678,11,69,751,569,54,531,752,8,901,947,338,735,77,24,238,143,323,498,158,65,401,17,237,293,946,18,717,740,597,93,512,638,286,403,395,892,144,347,308,299,424,457,185,418,713,194,221,757,824 }, +{ 100,252,101,88,265,0,382,759,329,410,724,9,213,321,553,676,419,593,166,39,21,30,909,694,562,520,68,13,812,264,23,435,677,230,35,352,478,48,190,154,689,212,1,217,570,51,466,639,124,221,83,806,604,175,699,826,703,125,98,308,55,671,664,346,32,158,610,706,96,962,274,31,317,289,344,69,438,49,28,831,917,115,656,455,936,404,165,116,208,777,310,5,854,857,16,201,128,36,333,752,194,67,24,71,144,795,391,197,589,141,818,364,921,131,44,86,203,251,748,105,65,22,180,557,149,702,350,855 }, +{ 539,88,840,190,30,321,530,957,435,748,669,778,144,96,100,466,418,863,410,203,228,213,382,274,795,406,613,131,36,822,1,83,326,856,219,352,335,494,251,230,679,31,224,960,44,831,855,141,859,944,217,9,367,160,201,137,625,128,166,93,258,662,120,800,521,403,116,98,187,28,576,752,816,269,202,557,39,931,21,265,686,616,443,921,10,180,731,438,689,523,473,125,871,317,23,77,197,457,827,55,264,35,617,692,254,33,719,260,86,966,817,32,829,206,276,127,242,475,456,284,51,615,252,0,854,238,492,551 }, +{ 7,97,173,92,232,298,314,107,387,729,356,43,359,126,246,140,362,441,501,426,392,230,560,20,14,707,885,104,16,66,330,779,172,683,60,35,493,861,22,357,5,0,95,49,81,279,38,568,18,24,21,74,192,71,414,830,423,259,324,2,121,526,125,633,508,32,672,52,319,10,150,48,28,147,29,46,715,347,6,64,199,380,189,61,858,69,660,33,204,135,649,713,36,595,1,98,37,879,31,146,132,75,819,263,784,443,408,607,448,54,12,663,138,68,58,117,102,70,13,267,65,55,712,91,153,77,399,165 }, +{ 14,2,7,58,46,1,38,16,75,5,70,52,24,155,29,45,220,35,163,69,50,171,61,186,87,227,18,270,92,48,666,54,32,290,140,21,278,592,513,307,67,112,262,6,66,60,37,0,135,243,97,767,64,425,23,89,71,72,409,400,128,845,113,17,334,36,22,172,20,10,315,115,76,141,9,28,51,12,663,103,86,74,77,207,13,65,177,90,263,83,267,202,95,137,43,269,151,294,189,27,25,431,19,49,428,430,68,40,223,536,852,106,738,324,226,655,474,780,96,502,496,217,114,108,318,230,102,148 }, +{ 447,411,664,363,647,478,936,621,354,271,98,781,759,223,777,1,360,18,691,668,48,932,167,156,132,121,212,195,591,446,724,520,118,586,146,21,23,463,31,293,9,264,393,16,51,914,13,125,807,101,49,834,284,44,60,163,682,24,848,221,658,541,5,105,35,71,68,55,96,39,116,562,407,32,905,604,22,252,772,0,33,765,522,69,10,963,67,191,93,100,638,676,166,340,364,120,281,698,608,286,821,404,50,115,382,144,77,265,697,64,28,102,909,126,410,30,628,82,662,95,367,7,815,127,744,335,40,296 }, +{ 14,2,1,46,67,65,38,7,69,36,29,24,83,28,50,0,22,103,5,6,52,124,108,484,168,12,114,86,75,133,208,18,16,194,236,283,289,389,21,610,10,109,756,160,25,267,35,23,51,95,32,309,55,505,135,584,71,13,185,66,547,128,189,37,732,54,96,48,169,646,17,49,412,9,420,158,87,19,323,115,278,244,26,64,218,164,70,143,253,74,238,140,220,398,172,45,137,58,149,262,797,141,92,308,4,3,503,302,202,60,68,388,154,159,118,650,531,90,516,366,150,285,105,532,335,251,671,429 }, +{ 386,421,51,791,801,697,958,730,453,23,165,551,221,670,615,326,401,391,576,403,13,102,457,899,805,523,842,770,48,24,450,475,0,203,125,949,541,719,566,77,193,115,308,197,21,18,398,153,33,393,317,117,43,202,137,743,120,300,7,124,467,5,91,108,9,71,342,291,118,42,32,16,97,134,85,279,61,260,173,289,281,517,494,14,859,817,196,60,809,758,692,36,882,25,194,388,20,373,302,140,65,547,429,273,851,717,458,412,122,104,95,509,233,81,492,318,6,362,832,110,69,92,49,149,35,508,298,608 }, +{ 319,104,945,422,81,20,715,43,0,879,693,681,306,32,784,74,173,207,61,7,22,52,397,671,414,904,887,636,240,95,6,115,835,192,5,707,91,426,18,2,76,29,819,330,316,263,56,85,138,84,28,232,577,365,64,97,113,519,312,725,526,17,344,370,204,49,202,214,329,24,38,560,403,750,66,494,10,804,500,241,25,105,289,718,159,587,523,77,124,102,86,861,348,498,450,292,51,288,90,117,140,65,899,510,168,347,158,16,448,45,817,237,107,324,33,9,194,180,120,318,92,790,40,280,21,356,320,874 }, +{ 2,29,70,1,52,262,75,112,26,145,46,163,309,58,103,67,14,50,6,220,96,74,38,394,223,331,357,19,83,238,45,69,5,324,171,287,27,409,151,25,366,307,24,583,218,537,133,108,632,42,267,396,451,53,36,433,87,114,65,17,113,635,186,764,550,545,226,600,138,675,388,66,37,21,61,54,48,181,122,516,12,606,294,236,418,73,35,189,18,80,86,486,487,651,135,155,150,7,32,16,137,644,243,739,281,222,445,334,278,380,573,149,849,106,227,582,603,160,335,34,64,283,696,648,765,624,297,72 }, +{ 771,929,786,941,590,626,687,259,465,178,70,878,132,5,13,21,534,146,49,518,279,48,107,35,379,493,31,147,125,767,105,108,87,195,221,481,126,121,44,163,22,623,23,127,61,581,407,362,0,150,165,937,427,58,846,345,371,142,883,467,167,761,120,33,10,640,98,75,591,360,391,1,663,271,77,30,199,4,845,763,522,60,185,102,291,7,349,159,156,137,128,246,450,51,308,296,293,239,32,11,158,423,558,557,342,269,116,39,260,112,17,386,232,502,441,281,196,153,95,37,12,783,953,612,535,401,197,15 }, +{ 5,186,45,2,61,29,50,227,52,400,58,17,46,48,171,209,14,155,106,243,80,311,38,1,430,281,496,54,502,536,255,181,454,513,103,96,592,760,3,334,207,21,666,67,119,552,587,869,663,62,151,541,27,32,583,309,721,84,56,37,659,218,133,366,221,136,83,540,6,834,72,36,223,270,667,290,738,12,328,34,807,89,287,263,474,19,487,262,236,238,148,76,75,115,69,425,240,378,99,26,394,24,766,433,483,128,114,306,70,549,65,324,600,675,828,357,764,53,780,108,545,73,137,161,7,833,90,765 }, +{ 0,95,453,64,32,389,494,817,342,207,312,365,577,690,194,403,848,237,202,316,180,671,5,482,757,61,490,805,102,289,498,450,65,835,475,523,113,49,401,241,887,115,120,263,329,21,17,18,576,22,33,137,344,13,318,402,77,3,1,899,11,48,347,4,210,141,118,125,90,51,933,942,260,23,645,874,306,308,117,134,597,615,27,247,12,196,24,122,19,6,2,751,697,743,317,468,291,25,16,288,177,730,629,28,86,84,349,770,421,214,611,592,491,483,476,425,56,36,670,300,275,153,217,621,350,39,71,60 }, +{ 23,13,51,202,115,15,5,1,12,4,2,77,403,165,0,21,10,318,453,32,457,33,128,197,9,7,6,141,3,401,475,59,177,269,14,11,308,17,37,494,22,719,217,99,64,341,180,117,18,90,40,102,120,16,317,730,961,569,48,365,28,421,386,352,629,8,38,523,450,237,31,291,402,125,210,137,247,216,19,391,196,57,221,36,509,326,260,72,93,24,349,275,153,203,49,95,498,342,304,899,45,134,82,44,76,30,468,372,98,89,27,817,25,139,86,110,758,65,54,29,111,546,351,116,241,46,20,482 }, +{ 119,292,6,45,306,76,2,26,240,209,17,61,710,106,5,80,29,19,27,25,214,84,113,32,64,618,129,255,128,1,179,90,123,4,59,65,151,14,58,667,40,460,311,56,504,22,245,86,249,207,0,790,141,205,42,95,77,483,3,833,10,112,115,202,7,23,18,887,137,194,11,52,57,36,62,136,269,476,177,162,99,33,491,21,257,73,769,454,12,70,38,28,402,13,24,145,16,48,72,318,184,196,614,445,122,102,53,114,49,117,153,210,548,285,46,54,464,134,180,51,396,50,297,183,315,243,237,814 }, +{ 15,1,23,13,51,180,0,2,120,5,7,9,450,523,33,12,115,260,197,102,165,6,202,77,4,21,141,14,457,351,403,341,16,901,8,326,82,308,365,3,269,18,36,137,93,318,48,128,386,59,31,37,719,217,453,401,730,817,22,110,44,475,64,317,352,10,32,28,421,494,40,30,116,98,11,899,342,373,752,196,24,615,221,177,86,291,49,854,203,39,99,509,961,96,144,569,898,55,922,35,391,210,117,244,629,125,349,498,873,17,50,247,372,89,160,758,237,670,300,95,127,143,153,65,285,402,90,801 }, +{ 6,138,222,280,74,85,66,226,337,87,42,204,235,25,145,294,64,135,95,174,609,29,112,415,256,26,65,525,792,461,353,32,580,22,52,122,746,172,630,544,289,70,348,416,237,287,19,278,49,312,86,605,75,10,108,2,0,194,192,5,620,1,7,21,90,97,736,220,63,45,632,500,114,214,61,355,36,151,233,396,180,58,69,24,125,141,72,28,14,648,27,519,673,889,872,624,241,444,288,18,343,197,48,426,33,207,133,665,263,232,113,73,347,91,17,568,448,316,103,208,165,128,104,53,380,12,81,498 }, +{ 39,9,333,101,0,158,252,310,254,272,455,68,49,627,327,344,159,286,419,364,18,16,709,329,24,688,105,265,109,30,100,553,118,374,35,557,166,124,190,154,677,131,65,578,912,71,793,22,60,518,1,538,51,167,21,23,98,28,212,48,95,438,604,625,13,404,7,31,96,55,127,520,36,731,137,890,857,125,320,616,694,656,806,716,44,577,5,10,170,224,67,83,829,168,242,219,228,128,191,14,239,827,88,86,301,347,12,424,160,747,810,37,115,64,846,346,371,613,69,910,221,33,149,2,562,93,865,676 }, +{ 21,32,14,5,38,76,72,2,48,54,270,45,1,17,50,46,221,290,181,89,36,430,3,741,428,218,408,155,37,540,281,449,0,10,12,148,179,90,241,263,207,29,292,133,425,22,477,328,99,51,697,421,114,67,770,487,115,476,23,4,528,227,65,28,6,119,243,488,214,720,552,541,86,474,24,52,350,64,61,7,9,137,11,186,103,536,401,129,745,413,106,58,83,96,920,308,236,13,57,513,123,18,842,464,543,361,245,160,56,59,205,128,655,431,514,358,828,285,171,108,460,55,62,400,27,16,453,40 }, +{ 137,269,141,202,120,450,260,318,494,922,351,291,82,77,5,326,678,352,704,854,128,523,1,817,21,15,64,349,180,342,32,13,475,90,177,947,7,372,61,51,49,23,165,95,403,11,207,115,312,102,4,48,197,237,402,719,203,50,96,308,30,6,2,373,205,86,70,69,67,36,210,241,105,898,859,851,615,208,194,217,901,285,25,453,216,182,163,87,65,46,45,8,0,457,31,307,139,112,58,37,12,3,117,968,158,127,20,730,386,273,199,178,168,147,126,108,60,28,18,16,10,9,954,795,597,275,247,134 }, +{ 16,68,71,24,149,35,191,118,167,212,18,124,101,246,108,399,189,154,140,92,267,9,60,375,65,458,695,302,133,67,398,589,7,0,69,230,114,562,702,1,705,103,55,915,755,283,21,388,602,336,412,48,14,175,273,650,50,345,823,674,411,46,121,146,28,363,236,447,39,10,64,672,22,664,478,796,264,309,330,271,100,520,647,37,95,218,199,12,906,23,565,36,83,32,252,777,88,166,628,126,5,13,125,49,75,2,366,51,96,86,732,486,346,54,815,237,733,429,98,891,759,516,633,818,115,443,723,238 }, +{ 28,109,0,9,67,22,1,55,65,114,103,158,39,49,83,194,168,69,35,420,185,289,36,50,208,24,68,133,2,124,505,251,218,175,86,46,7,389,323,154,95,169,159,346,12,547,160,14,756,101,646,16,570,105,30,5,799,189,533,38,531,96,503,238,596,252,128,64,535,23,54,18,21,344,51,782,272,336,610,419,283,532,345,333,480,13,100,10,37,137,327,115,789,584,149,286,230,361,48,75,285,181,202,29,254,374,164,429,927,141,71,896,143,671,930,577,32,237,140,810,244,484,439,31,131,601,402,310 }, +{ 325,147,427,198,178,142,798,202,259,5,376,20,534,43,465,450,904,318,234,470,858,77,725,455,120,581,329,315,70,97,61,929,105,878,786,113,362,260,58,557,481,403,660,14,639,21,173,0,170,49,159,494,319,269,48,23,344,523,128,107,301,595,1,845,518,416,33,884,817,324,320,13,326,199,22,475,402,158,37,270,132,51,40,38,35,32,7,95,590,121,4,422,239,141,104,66,146,347,112,615,263,230,126,75,28,307,76,207,704,414,360,265,195,9,922,453,356,298,19,17,137,72,342,290,102,87,50,395 }, +{ 28,0,65,109,9,35,55,175,124,67,289,24,39,158,68,114,14,336,570,154,420,1,22,7,185,168,69,133,194,49,16,429,149,101,46,505,83,189,2,103,169,346,50,252,484,36,547,389,610,283,18,756,95,419,159,535,345,251,86,71,105,12,108,398,100,230,30,140,439,333,533,344,584,703,21,208,272,286,671,38,5,327,267,10,64,601,23,254,51,96,118,810,13,48,164,782,265,128,364,236,29,143,160,837,329,374,677,54,577,218,310,637,399,60,37,962,797,92,166,323,793,705,32,238,732,75,6,596 }, +{ 141,180,115,269,13,23,4,1,352,5,202,318,51,317,2,217,21,752,365,77,3,7,165,341,197,32,0,137,11,308,10,6,901,33,15,9,31,22,177,102,403,64,401,12,30,44,498,237,291,48,143,244,93,349,569,40,494,28,8,39,253,125,372,90,221,98,453,304,386,482,873,509,203,120,110,116,18,59,49,457,144,128,95,247,391,864,326,117,16,421,37,153,14,196,475,36,629,134,105,210,260,961,373,160,164,55,719,546,437,216,734,35,468,350,201,17,139,96,89,579,473,72,758,717,111,24,743,275 }, +{ 15,0,1,2,9,23,13,5,7,51,12,6,4,8,901,33,3,180,14,197,10,341,115,77,102,93,120,141,260,22,21,82,457,899,31,64,453,28,165,16,450,18,523,11,351,475,202,36,110,37,203,401,125,30,352,898,44,403,961,730,719,116,128,569,421,365,196,49,40,98,32,217,137,373,269,39,308,237,144,55,854,153,177,318,317,86,326,24,17,117,95,629,48,817,752,59,300,670,498,99,391,494,386,291,134,38,105,90,642,342,922,873,242,143,244,253,393,473,221,50,247,372,57,349,139,65,111,661 }, +{ 6,74,138,66,75,85,25,324,42,380,278,135,26,500,87,226,1,220,97,29,70,222,889,841,52,350,19,606,280,235,294,394,112,571,69,853,21,38,145,335,903,267,582,65,550,309,14,172,792,509,32,2,197,64,749,262,237,174,241,357,122,95,461,486,808,67,337,256,537,96,103,115,774,546,204,63,125,27,391,22,558,462,83,451,7,238,630,5,308,802,24,165,108,734,46,163,140,950,648,641,92,45,13,298,189,416,583,525,150,72,923,86,600,48,114,53,331,221,388,12,620,180,468,426,90,645,746,348 }, +{ 51,23,13,453,12,115,403,4,457,401,165,475,15,0,1,10,11,37,59,5,99,40,3,308,64,197,32,2,33,202,17,9,719,77,629,730,7,14,22,6,961,21,569,523,494,421,386,18,120,141,57,125,177,318,269,102,237,128,90,38,899,341,45,450,111,76,16,180,217,19,36,31,134,117,247,49,670,139,72,28,210,95,291,196,402,153,41,25,24,89,509,216,260,8,93,86,54,221,82,137,65,468,758,26,56,44,27,317,391,352,817,365,304,62,349,123,498,48,34,326,275,152,775,342,114,372,300,757 }, +{ 788,180,319,21,5,83,32,498,314,547,526,17,693,61,817,48,11,4,27,510,33,12,848,77,288,104,24,160,0,814,120,64,3,804,153,134,117,56,519,342,196,102,207,725,326,690,523,450,69,40,403,95,899,306,60,958,90,961,942,801,500,232,174,155,84,43,38,115,945,457,386,595,475,615,247,887,715,671,494,482,365,192,13,312,202,165,10,9,81,51,566,65,71,119,113,861,835,802,770,757,756,746,743,729,692,683,629,587,583,551,550,525,449,426,422,418,414,324,291,260,221,217,214,186,170,125,123,105 }, +{ 15,1,2,13,23,4,5,3,0,11,7,6,341,51,10,9,12,33,77,115,102,40,217,14,197,180,165,141,365,901,569,317,202,64,22,21,8,16,59,32,403,31,17,269,177,318,475,18,196,386,453,352,153,93,401,120,125,117,28,291,457,494,210,110,37,961,629,326,128,391,237,260,139,49,44,349,98,372,116,719,342,36,523,95,57,86,111,137,19,24,203,450,308,752,30,275,38,730,134,90,509,304,373,247,300,144,48,498,27,45,20,758,482,65,143,72,105,55,99,35,670,76,873,402,615,82,29,817 }, +{ 101,520,18,167,9,118,212,604,364,16,60,694,252,0,264,917,24,68,146,55,363,562,35,191,121,166,265,806,329,71,676,100,706,647,411,271,39,907,628,621,925,21,419,848,404,28,682,942,48,1,815,154,777,446,109,132,124,5,821,463,49,857,158,13,199,905,967,23,932,126,88,108,22,346,96,382,354,759,51,575,125,105,98,92,32,522,65,286,333,31,447,812,639,7,553,664,566,727,159,593,30,10,149,150,865,156,375,14,897,936,407,95,638,274,478,175,439,272,67,221,634,302,50,2,12,107,144,44 }, +{ 13,23,51,115,33,217,77,141,64,0,4,102,202,9,2,317,7,269,180,21,291,352,32,16,10,128,5,11,318,6,177,40,341,3,18,22,165,197,137,15,14,153,247,237,125,28,24,12,59,196,365,31,349,117,90,752,49,403,372,98,221,93,308,17,95,44,86,342,48,494,1,304,210,498,30,36,120,475,453,134,401,241,244,386,143,275,19,391,901,72,110,35,39,203,144,326,116,260,164,20,437,457,37,402,509,421,8,482,55,523,105,82,96,316,65,350,450,864,139,216,25,76,285,29,27,579,546,127 }, +{ 66,135,172,74,97,204,278,6,138,324,7,174,87,192,85,448,140,353,29,232,280,620,500,52,802,92,25,226,808,38,568,380,889,42,298,69,426,580,792,314,571,330,2,872,348,95,26,572,622,43,563,32,526,222,893,22,14,65,5,21,81,64,673,24,75,267,950,1,355,885,220,70,357,726,145,104,86,63,888,91,387,189,16,46,289,294,126,71,501,20,107,233,60,19,48,462,335,67,173,28,45,194,49,241,550,235,230,37,90,0,312,83,18,415,61,58,36,262,12,35,112,633,10,72,150,712,246,343 }, +{ 97,24,2,69,66,423,298,6,29,7,267,172,74,52,14,189,67,38,25,607,150,149,83,71,1,36,18,135,733,467,81,0,140,501,426,517,21,33,398,278,160,118,124,809,42,154,26,19,462,85,273,92,20,46,429,302,117,60,336,568,508,204,28,192,715,232,770,705,165,65,16,153,596,173,102,279,50,91,87,175,43,23,448,45,12,861,386,37,13,63,421,104,48,51,324,388,314,197,134,711,138,32,531,526,330,681,712,443,22,451,75,608,185,4,949,697,221,882,636,236,370,196,54,420,5,309,885,458 }, +{ 158,9,0,68,39,333,109,344,49,101,24,16,35,159,124,154,254,272,310,793,252,327,419,65,627,286,71,22,364,455,18,374,105,577,747,28,30,168,912,118,677,55,95,185,709,100,688,149,60,175,671,131,190,346,166,265,518,578,538,329,169,703,424,1,212,21,7,694,962,289,706,439,347,191,108,51,810,48,10,634,23,67,14,616,239,553,170,302,557,98,320,125,31,2,570,857,625,13,5,36,12,128,375,86,137,127,114,37,716,88,44,913,420,92,83,69,96,50,64,224,638,562,242,301,167,890,731,160 }, +{ 15,10,33,77,197,4,180,341,365,115,13,102,23,317,141,117,217,5,1,901,11,40,253,165,134,153,21,752,244,143,32,36,352,51,638,137,2,196,12,55,3,873,569,951,372,82,37,120,291,177,7,59,898,349,6,64,0,509,31,342,269,22,351,498,260,308,160,93,14,139,854,44,202,28,86,48,457,17,482,90,401,450,111,719,72,203,116,125,110,523,128,961,164,57,304,922,9,386,318,38,730,326,49,762,535,275,391,277,629,210,242,373,99,98,148,96,734,817,95,89,237,717,247,30,479,45,758,54 }, +{ 100,382,166,478,265,264,404,274,593,438,88,39,921,724,98,639,682,1,363,411,447,435,905,812,821,9,96,30,897,31,656,23,223,252,254,310,664,410,116,190,51,144,329,691,21,520,393,44,127,101,0,909,48,125,13,625,333,284,557,521,418,286,367,960,772,5,93,77,321,118,105,83,948,616,272,530,33,293,203,795,156,765,676,68,466,102,67,551,131,604,120,242,49,35,16,354,848,421,18,32,553,730,69,158,335,165,759,791,110,731,914,163,613,115,10,386,217,24,36,778,834,65,395,4,578,238,842,364 }, +{ 19,283,436,297,53,26,813,122,42,432,503,27,605,25,736,73,390,235,389,128,630,123,250,529,63,256,80,65,108,445,690,573,269,789,106,444,216,113,381,412,6,14,133,680,200,78,318,650,177,678,17,194,57,114,619,368,4,349,84,472,59,112,85,275,291,56,18,378,714,40,32,396,183,102,11,152,33,416,136,495,341,236,46,403,130,161,90,243,561,255,184,24,129,597,0,742,86,45,469,76,145,862,401,285,249,141,947,665,13,179,51,524,287,50,527,803,233,117,684,12,304,148,205,29,719,23,139,61 }, +{ 202,128,494,141,33,269,137,36,51,0,13,102,180,6,2,1,196,65,4,86,402,95,29,475,403,117,59,40,457,77,450,15,210,177,134,49,22,21,18,291,153,12,3,260,114,90,817,386,318,120,25,16,32,23,11,961,922,576,237,217,194,165,115,14,7,453,342,216,873,373,197,164,64,719,874,854,789,757,751,704,597,558,391,372,326,304,301,300,285,275,208,203,159,133,110,105,99,93,81,74,70,66,52,48,47,42,41,34,28,26,24,10,5,139,76,958,899,801,730,615,551,160,963,901,752,657,584,421 }, +{ 18,60,16,68,167,191,101,118,212,121,35,126,199,146,647,520,55,9,628,806,621,71,24,107,575,346,363,132,446,463,364,0,566,92,562,28,271,411,252,1,727,21,815,48,407,150,604,598,694,279,932,154,608,49,589,493,439,22,5,7,124,109,706,419,10,108,13,354,14,23,640,467,375,96,273,158,848,302,955,535,175,195,39,818,534,105,125,100,221,522,676,264,777,12,51,50,159,329,32,265,65,259,362,917,98,20,826,783,149,37,31,581,95,169,43,67,97,46,223,147,907,166,590,64,246,36,2,967 }, +{ 352,230,531,160,36,748,854,217,93,669,728,137,251,689,871,699,373,228,574,258,202,752,351,717,559,120,144,268,318,260,219,203,269,201,831,533,839,567,539,187,840,213,816,489,679,82,1,317,851,332,44,141,55,295,855,206,30,617,863,418,83,345,926,96,180,443,800,473,116,10,143,326,110,35,406,564,131,224,22,860,276,64,450,28,98,9,21,190,957,466,822,968,244,164,31,434,856,169,384,661,69,898,0,365,730,824,284,125,442,253,128,372,873,498,88,530,922,776,261,165,494,48,237,86,68,940,39,927 }, +{ 15,13,51,23,0,77,8,4,5,1,202,33,10,11,165,180,82,22,12,110,115,9,102,197,40,59,342,403,141,120,351,326,7,453,373,31,386,18,93,457,260,49,2,401,318,475,128,28,901,64,269,291,44,494,36,854,719,21,177,14,30,523,961,16,898,57,3,349,421,125,922,99,341,32,730,98,137,203,56,217,317,450,117,615,76,391,498,275,24,352,569,365,95,6,105,308,144,37,196,899,86,65,153,39,535,90,210,629,116,704,247,83,208,237,48,661,752,638,509,17,758,402,133,551,143,139,817,244 }, +{ 101,9,100,0,88,217,252,68,39,35,352,562,175,30,115,230,752,213,265,419,13,317,197,166,180,154,237,83,212,158,124,64,321,777,382,208,1,336,410,65,194,759,329,694,36,141,826,289,23,365,724,341,429,128,509,69,165,570,345,676,909,96,346,756,553,21,593,372,854,702,498,55,799,264,399,67,86,190,28,468,589,768,51,364,308,144,677,755,689,323,125,722,482,610,547,391,333,137,789,812,189,546,49,32,952,310,247,274,131,72,16,344,98,10,671,351,435,386,251,478,285,244,901,167,160,484,706,164 }, +{ 32,64,95,147,288,21,90,5,519,470,49,61,0,356,22,48,115,362,97,247,312,141,835,387,560,57,56,4,182,128,20,237,178,59,18,11,31,13,107,214,202,28,298,217,44,76,316,7,65,43,259,180,819,874,51,40,23,216,173,330,207,197,150,25,2,86,729,324,120,376,279,140,612,392,595,104,72,66,29,6,352,37,12,210,678,414,172,683,779,490,482,317,291,165,134,102,81,77,58,45,33,26,195,864,795,304,858,87,54,660,427,707,878,465,357,501,232,753,205,177,170,126,117,91,19,597,230,212 }, +{ 24,16,14,35,7,18,69,1,50,46,75,5,2,58,163,67,54,70,0,71,28,502,60,48,38,12,9,21,189,103,155,140,267,223,281,108,37,171,430,92,394,65,68,22,230,513,83,10,23,181,32,55,309,87,45,36,236,51,335,29,220,149,307,99,61,133,112,141,64,13,780,52,6,115,128,227,270,72,89,852,537,328,17,150,474,49,807,114,767,221,552,186,96,290,95,20,246,366,77,443,400,137,202,86,269,486,666,388,237,540,25,278,477,217,4,536,218,765,177,19,125,180,165,126,113,318,251,39 }, +{ 195,18,354,265,252,411,39,9,363,167,101,682,271,132,16,121,60,1,333,203,21,593,35,146,520,156,364,447,639,360,212,5,24,327,23,627,668,310,404,13,48,664,286,100,538,0,777,676,77,98,821,7,68,33,692,446,865,93,158,576,159,116,115,647,966,883,551,407,272,107,51,687,120,591,463,326,137,71,102,857,31,781,421,37,586,30,44,329,379,50,125,374,166,105,92,96,621,709,142,65,36,127,562,475,109,403,14,126,118,70,346,223,479,199,805,450,190,43,20,191,936,905,656,128,254,12,2,202 }, +{ 4,115,13,5,23,141,51,180,2,202,1,217,11,269,318,3,77,341,7,6,317,33,365,0,21,12,352,197,165,9,15,32,102,10,137,40,177,308,752,64,291,31,22,901,349,372,28,8,59,403,90,494,30,237,498,44,120,37,401,125,48,39,14,93,17,244,49,457,569,509,128,153,16,386,98,143,304,36,873,475,196,391,117,482,342,253,210,203,110,453,116,247,373,221,326,24,216,18,144,72,421,260,95,55,134,450,961,576,86,139,719,105,468,35,164,82,57,127,160,89,864,678,523,351,88,275,67,546 }, +{ 7,71,24,14,16,35,140,92,189,149,150,108,60,68,18,230,97,69,66,314,273,267,458,388,336,38,2,65,232,251,175,399,118,46,398,172,67,28,462,246,36,55,375,0,705,1,21,124,154,22,298,302,135,95,451,733,877,126,594,423,345,64,467,101,9,74,517,29,48,86,602,236,6,20,191,83,596,52,330,380,32,357,43,5,10,674,50,12,133,49,429,723,103,711,212,346,104,192,114,107,915,278,167,387,37,443,324,309,121,823,54,125,96,633,566,221,796,484,75,109,547,603,13,23,289,809,575,607 }, +{ 1,22,31,5,36,12,105,44,2,86,21,170,98,180,127,0,55,141,64,23,7,352,28,13,9,128,116,125,164,239,4,301,49,115,6,95,197,37,3,160,242,51,341,752,202,83,498,269,10,96,165,144,48,253,244,285,901,217,320,365,208,569,137,8,338,299,318,395,293,109,654,93,512,143,32,50,237,317,159,402,864,11,15,708,776,873,169,201,14,35,99,67,638,39,954,30,844,531,479,678,77,69,456,740,533,16,403,308,268,120,751,951,33,961,947,457,286,238,401,276,482,203,601,17,506,312,509,18 }, +{ 97,66,192,7,560,52,20,2,135,74,43,173,324,104,580,414,226,107,147,750,204,29,174,500,376,568,825,707,222,0,356,470,77,32,331,194,90,38,729,16,819,298,92,172,355,22,60,64,888,595,357,232,24,18,259,712,202,353,426,81,5,362,262,874,427,526,49,330,14,178,95,885,387,21,10,138,37,861,142,6,33,102,86,28,889,4,359,65,312,36,858,126,59,1,112,792,673,337,58,151,177,91,35,113,319,291,9,115,145,13,636,501,342,448,278,140,12,87,61,71,583,294,751,465,237,246,230,325 }, +{ 101,0,68,9,252,154,124,364,166,35,39,100,24,65,419,16,149,694,71,265,329,28,439,158,346,88,30,289,212,404,55,671,703,562,570,49,274,175,429,21,706,589,18,553,118,375,1,722,67,302,22,109,962,190,677,382,333,108,60,23,967,191,168,95,69,48,344,14,51,336,114,254,676,610,484,13,398,10,83,92,7,520,310,857,818,125,264,593,189,64,133,185,826,438,12,32,159,865,221,103,535,50,194,695,286,105,36,604,96,169,420,230,283,701,167,241,131,140,2,350,656,115,272,5,239,637,812,98 }, +{ 39,100,127,30,737,836,9,254,856,31,166,190,98,395,0,385,88,931,625,131,373,264,863,93,827,28,228,120,44,125,1,219,116,137,110,382,371,55,13,101,731,299,260,144,908,442,21,77,265,23,456,64,203,51,599,242,33,187,49,326,310,22,224,578,202,5,450,36,272,18,276,16,141,795,82,105,916,284,165,274,318,48,95,512,944,35,716,478,24,935,258,201,616,851,32,557,102,96,252,109,68,269,128,351,435,492,83,724,86,67,7,10,704,293,772,59,921,329,846,156,924,286,197,438,717,4,291,244 }, +{ 17,5,45,21,14,2,48,3,32,155,106,227,186,181,38,29,61,209,62,46,328,133,400,80,243,54,56,52,1,51,832,23,19,50,99,255,114,430,6,84,543,536,12,514,401,236,27,37,137,361,552,453,119,136,34,311,58,218,171,221,76,72,4,754,115,281,108,13,285,496,65,454,629,513,41,207,308,540,421,26,290,805,480,541,488,920,657,202,475,11,487,787,128,86,89,569,57,739,151,838,502,36,270,59,403,208,90,10,7,721,474,22,263,745,576,0,457,659,592,663,587,25,161,129,165,148,323,894 }, +{ 131,613,224,856,228,406,716,274,827,30,100,219,190,39,166,863,88,931,924,829,944,31,382,44,625,9,127,1,442,385,187,98,116,731,93,578,258,254,530,816,137,871,160,616,960,96,36,310,265,0,371,203,144,836,410,438,264,435,795,125,242,21,202,120,201,531,276,908,51,921,128,23,101,49,839,846,28,737,48,326,5,83,778,13,110,64,284,105,35,492,272,10,557,33,938,115,299,77,252,158,456,367,268,669,217,260,165,213,32,177,22,800,352,473,86,102,69,197,574,321,318,567,141,935,593,403,55,180 }, +{ 352,217,752,141,954,864,64,372,437,269,180,115,498,177,349,776,579,291,317,247,77,947,873,717,304,318,678,237,179,23,197,128,33,0,35,165,13,275,68,210,457,341,459,1,67,410,32,143,365,65,244,202,102,9,160,140,137,225,569,12,36,18,125,75,51,134,93,751,15,546,509,86,708,482,928,713,330,312,201,164,144,100,10,7,521,268,246,44,24,21,16,558,55,851,682,342,260,245,120,117,101,98,39,28,726,363,116,110,30,189,72,478,83,744,953,841,824,672,563,358,166,114,92,31,5,386,196,69 }, +{ 141,217,317,180,352,365,115,341,5,372,23,13,752,498,253,244,15,1,237,2,51,197,269,0,7,165,21,202,64,349,77,6,137,143,4,318,3,9,901,546,33,177,308,11,32,10,160,12,48,49,482,30,22,125,468,98,373,247,120,102,93,31,864,110,509,260,531,391,28,44,494,437,36,450,569,90,40,490,453,326,221,219,203,16,128,96,82,386,164,72,873,291,251,224,187,117,403,401,210,39,131,116,24,18,473,144,86,37,629,148,105,8,533,951,758,475,421,228,139,170,134,95,65,35,734,704,617,275 }, +{ 5,2,45,17,14,29,48,1,21,58,181,38,50,61,3,133,46,155,171,186,114,52,32,27,281,19,6,218,36,236,227,54,361,151,51,12,754,209,26,400,80,137,514,243,65,106,552,487,13,480,334,23,285,86,412,328,108,4,283,502,311,37,56,99,323,22,745,657,208,202,25,62,72,128,115,838,760,59,430,7,34,536,64,70,454,11,76,10,28,255,119,803,194,787,67,421,0,576,57,859,496,103,84,96,18,532,75,165,89,453,389,223,24,920,401,163,73,113,308,828,402,77,739,112,287,148,457,513 }, +{ 6,25,2,119,790,29,113,76,26,45,483,655,887,42,292,32,19,4,59,128,151,207,1,306,84,17,814,106,240,90,112,209,61,145,14,177,77,64,65,52,833,27,122,179,491,210,70,0,72,311,115,40,255,58,614,74,85,7,214,202,710,22,5,57,469,21,141,11,123,80,476,95,36,396,33,10,24,269,38,137,102,66,425,23,416,49,194,86,275,504,13,216,56,402,318,46,358,18,138,28,460,624,9,148,50,174,129,618,51,205,87,75,16,291,186,12,217,249,222,287,454,20,54,99,243,315,117,114 }, +{ 23,13,51,115,2,4,5,0,141,180,7,11,217,3,33,77,6,1,202,9,317,10,102,197,21,269,40,352,341,32,12,165,16,22,64,318,365,28,128,15,14,18,752,137,59,24,291,308,177,125,31,17,403,498,237,494,372,98,49,117,901,93,196,30,44,153,457,349,8,37,120,134,90,116,247,342,36,482,401,95,35,210,143,221,86,453,260,203,144,475,326,48,244,110,391,386,55,304,873,39,19,569,961,421,105,509,719,546,450,253,864,216,20,402,29,523,72,57,50,139,25,730,373,468,275,65,82,629 }, +{ 23,13,51,202,21,141,115,5,165,318,32,12,403,197,453,1,269,120,15,128,2,180,475,125,308,457,401,7,48,6,386,64,0,730,4,9,719,137,3,10,523,18,33,14,37,421,16,99,494,11,260,450,341,221,17,196,93,77,40,217,22,117,90,95,237,899,31,391,247,352,326,28,24,102,19,153,30,317,98,961,817,134,82,44,25,59,8,241,110,49,365,20,26,291,27,61,177,36,351,498,509,569,402,39,203,758,29,72,57,45,629,350,54,116,316,96,752,50,38,349,67,901,65,46,342,304,285,58 }, +{ 39,9,100,30,31,127,44,88,0,276,98,131,1,385,254,442,166,49,908,116,187,190,935,201,219,284,827,299,28,224,144,829,96,228,36,274,137,141,101,21,265,716,382,48,51,258,202,23,352,22,125,836,93,856,613,128,839,158,371,264,578,395,13,55,16,180,662,244,269,252,217,567,492,110,310,35,64,77,272,83,268,410,931,203,120,326,752,260,68,318,18,489,293,574,625,160,24,33,115,86,159,924,242,373,165,438,5,450,69,102,616,213,197,918,863,321,295,717,291,82,731,177,456,317,406,7,599,737 }, +{ 22,109,49,28,159,185,95,9,105,131,272,327,254,1,67,286,36,39,35,168,86,83,55,169,505,158,224,374,420,127,584,208,98,219,312,578,31,347,535,601,0,69,708,424,44,114,103,30,160,627,346,64,141,194,187,518,175,96,239,345,616,892,10,128,164,143,896,116,137,50,12,5,2,237,228,913,533,13,23,7,21,371,320,597,688,538,751,912,352,323,251,716,165,115,634,202,258,197,498,637,37,531,180,797,874,51,253,768,48,101,890,16,189,201,613,24,752,385,14,170,285,365,406,789,244,218,46,133 }, +{ 5,1,21,2,48,14,12,32,22,36,0,17,54,10,38,3,37,86,50,45,65,28,51,72,281,23,4,6,58,114,89,46,137,13,270,99,430,11,7,208,76,202,181,61,115,403,155,9,133,18,540,64,361,221,29,323,480,285,49,128,24,95,218,401,657,421,290,745,19,576,194,55,308,754,59,453,513,920,148,880,96,341,502,52,16,475,77,67,842,40,283,859,318,197,402,494,171,141,474,244,543,757,165,775,90,541,27,33,180,57,83,227,164,217,428,328,269,108,425,569,514,207,31,143,223,263,102,503 }, +{ 141,352,269,372,351,217,854,82,752,922,318,180,954,260,317,15,349,1,202,64,120,898,717,77,67,35,864,291,69,365,137,851,437,36,22,5,247,86,373,4,457,450,244,165,189,163,140,68,13,237,901,115,128,304,23,21,341,98,125,177,51,93,32,28,961,160,96,494,110,95,10,0,719,253,661,523,326,767,83,730,275,44,386,418,40,12,817,210,19,17,102,59,45,18,7,579,498,482,615,403,144,11,6,3,203,76,822,475,49,48,31,33,293,284,268,228,187,947,899,587,583,485,474,367,342,300,245,100 }, +{ 144,613,203,406,669,418,326,137,228,96,679,494,160,816,1,817,822,36,317,859,840,83,856,876,855,217,251,219,863,831,944,202,576,365,539,93,800,5,345,530,77,128,44,957,748,141,13,839,30,23,21,778,143,341,115,473,617,332,201,64,120,190,492,456,829,531,349,367,716,258,98,48,578,116,180,924,403,187,31,515,966,692,574,442,131,86,931,719,523,450,9,224,351,291,860,752,82,28,10,244,51,371,22,276,39,102,125,730,261,50,851,269,827,335,318,871,704,916,268,110,898,69,67,498,206,177,615,805 }, +{ 15,13,23,51,202,1,21,33,5,269,180,217,2,141,308,12,120,0,352,165,7,221,115,117,48,32,6,318,197,4,153,9,260,82,196,453,134,457,3,40,386,523,730,110,14,719,77,401,31,403,450,137,326,37,102,341,16,351,8,128,752,11,475,93,18,498,317,44,365,391,64,30,98,237,72,10,49,421,22,99,901,494,509,28,24,899,17,125,39,817,569,854,116,203,59,291,177,89,961,95,36,244,629,758,105,247,90,372,241,864,349,546,670,898,96,35,144,86,65,350,373,50,139,304,61,160,922,615 }, +{ 23,115,13,51,77,0,1,4,365,2,141,341,5,33,202,217,11,10,317,9,180,102,3,7,6,15,269,22,318,197,165,64,352,12,40,494,403,21,28,31,128,308,125,32,453,59,177,18,291,16,401,475,901,14,24,752,237,93,342,137,349,457,569,44,8,17,372,30,153,98,120,95,49,210,36,498,196,117,110,509,482,421,116,247,386,873,304,37,391,39,629,244,48,139,90,203,143,134,55,86,523,450,326,468,260,275,57,961,144,719,65,35,402,216,730,221,19,253,373,46,50,734,437,678,576,96,758,551 }, +{ 531,373,728,160,943,559,717,260,93,269,332,206,533,244,352,384,261,535,964,564,120,110,10,253,295,137,365,318,141,55,143,959,180,617,36,851,911,843,197,661,203,873,282,1,752,940,341,699,968,901,82,417,326,21,144,450,22,351,317,434,64,642,498,855,824,574,202,926,473,860,800,896,164,23,28,898,8,51,13,258,15,116,35,816,567,127,187,237,776,9,951,219,601,268,115,811,165,217,201,864,131,98,406,854,77,523,251,902,922,125,48,345,44,31,16,704,96,499,86,83,489,871,367,299,177,72,817,24 }, +{ 1,31,36,170,55,86,22,44,127,5,301,64,98,164,2,116,740,105,299,12,10,242,237,125,169,338,9,0,21,143,7,512,23,28,841,128,141,13,239,51,395,180,654,208,293,685,37,144,870,923,95,6,599,83,197,115,160,456,900,352,67,498,506,253,165,638,49,3,268,492,137,965,4,479,14,393,763,269,244,185,708,202,109,341,96,365,50,762,509,933,276,48,284,951,367,505,864,751,752,546,320,601,597,35,8,569,634,312,323,217,558,201,391,824,317,401,308,901,457,32,837,159,535,93,873,54,114,38 }, +{ 13,23,51,115,32,141,77,177,202,33,64,269,90,4,102,318,128,40,59,21,217,291,137,180,352,210,95,10,48,0,22,5,196,494,15,7,237,14,117,49,18,216,197,125,342,98,31,304,11,9,165,153,403,317,247,86,752,134,28,275,349,16,24,116,365,341,2,6,76,44,453,17,12,20,30,300,221,93,39,143,139,36,1,19,3,402,326,386,312,105,457,65,244,194,8,576,498,901,308,110,99,72,372,120,401,203,50,25,241,144,61,26,208,96,678,450,160,615,421,391,127,114,57,46,37,35,27,947 }, +{ 202,260,120,450,318,51,269,77,23,351,1,326,13,128,82,137,141,21,33,15,494,102,523,817,5,403,110,165,922,64,203,197,854,125,32,180,177,291,48,153,196,93,116,12,342,98,352,373,40,4,115,7,475,144,349,36,217,90,2,453,386,16,0,285,95,44,615,237,59,49,31,457,704,6,898,210,24,58,96,86,30,719,117,70,401,216,8,275,28,22,14,402,17,247,50,39,29,18,421,99,37,20,10,391,304,61,25,752,341,730,678,9,365,859,576,473,139,45,961,692,293,661,498,317,214,132,35,76 }, +{ 899,523,102,730,33,153,196,117,719,23,475,51,817,13,15,403,453,5,4,342,77,494,40,120,21,11,450,202,421,59,457,12,805,165,139,134,26,19,17,2,1,300,386,801,961,57,32,27,7,6,3,880,197,99,361,757,670,128,125,72,58,56,48,45,37,14,318,64,49,770,247,82,576,260,884,775,635,629,509,485,456,402,391,180,177,141,95,89,84,76,70,62,61,54,53,38,29,25,758,401,269,262,583,409,365,341,331,217,52,968,967,966,965,964,963,962,960,959,958,957,956,955,954,953,952,951,950,949 }, +{ 202,494,403,475,523,817,453,450,318,402,120,576,51,13,77,102,342,33,260,128,23,326,5,899,15,4,82,615,210,269,137,351,291,59,196,141,90,730,40,386,285,214,177,21,719,389,49,11,65,61,30,22,48,153,117,457,114,12,3,98,64,44,39,31,1,922,194,216,84,349,165,95,32,28,10,0,757,197,421,474,123,38,961,887,805,690,629,551,401,283,263,207,139,125,118,113,58,848,503,115,41,880,275,24,17,422,319,104,942,854,803,801,704,671,509,416,400,393,372,334,237,227,217,186,180,151,134,96 }, +{ 2,29,52,112,66,87,70,151,135,7,226,58,74,307,186,294,172,287,549,644,334,5,14,97,46,75,45,227,331,113,145,6,25,315,155,337,222,1,61,192,32,243,163,311,64,220,38,400,43,262,171,69,21,37,624,461,20,884,122,849,631,416,26,16,48,86,27,24,42,22,19,278,138,92,353,635,36,609,232,0,128,140,10,500,324,50,17,72,665,59,12,95,76,90,409,209,35,4,396,491,614,65,18,496,415,54,721,568,592,67,632,49,141,137,80,28,89,204,659,869,60,106,426,845,448,177,207,115 }, +{ 1,349,652,5,260,291,77,39,342,102,120,23,100,888,13,269,64,340,264,51,303,698,32,2,202,21,9,296,33,98,70,385,163,638,318,137,327,87,293,58,50,128,48,195,69,774,141,75,121,7,658,850,326,96,371,284,223,931,863,759,132,126,92,71,221,678,203,82,551,961,937,615,575,563,494,105,83,67,55,36,30,27,17,771,418,115,90,31,156,914,687,393,372,12,6,3,622,144,922,898,854,731,691,478,403,367,363,352,351,333,310,286,170,146,0,950,230,93,95,49,919,954,947,865,851,765,751,719 }, +{ 1,5,2,13,4,23,7,3,15,0,6,180,51,115,141,341,11,77,269,352,21,901,217,197,365,33,12,32,177,752,317,202,318,165,40,9,102,10,291,93,8,569,31,22,349,498,120,90,44,110,401,59,37,304,326,48,17,64,372,403,196,117,16,98,14,457,210,453,125,494,28,36,386,629,247,153,475,30,308,260,134,873,116,253,373,450,18,237,244,482,203,49,128,961,275,137,144,216,509,523,421,391,143,342,24,719,105,95,55,72,76,89,39,206,437,139,468,57,579,758,730,864,546,127,221,96,734,19 }, +{ 14,7,16,46,24,2,35,70,92,58,5,38,75,18,140,60,87,171,220,54,1,155,69,307,50,21,163,48,71,32,112,0,37,12,23,278,780,502,126,9,61,52,186,172,135,45,28,64,29,13,67,227,20,107,22,115,97,513,51,10,267,72,68,270,128,230,89,314,666,330,246,141,6,232,189,36,400,177,66,108,290,150,17,309,55,430,767,334,77,474,121,262,103,243,409,223,137,83,43,113,202,592,217,461,49,95,315,571,65,181,394,357,86,281,269,774,294,236,380,852,536,845,76,90,25,102,298,4 }, +{ 226,135,87,2,29,66,74,52,294,278,222,220,75,7,172,145,331,70,324,262,97,6,25,112,138,337,140,42,1,92,461,26,69,38,500,58,357,14,380,5,287,16,46,571,232,620,808,632,267,163,32,24,35,583,853,774,43,314,609,45,171,21,298,353,19,802,95,60,151,415,448,409,64,67,192,22,65,396,85,525,37,174,307,189,872,204,20,71,50,12,330,86,622,61,48,27,36,186,394,764,113,54,335,563,114,108,309,150,950,72,155,17,10,572,122,635,544,103,96,606,28,893,246,18,49,230,550,334 }, +{ 15,33,77,117,134,153,102,4,40,196,1,217,21,11,291,13,32,5,177,202,51,115,3,23,141,2,48,317,180,349,59,137,372,128,17,269,342,210,341,96,57,64,365,120,247,12,216,82,221,139,318,110,6,260,93,90,352,898,450,165,10,36,31,197,275,523,7,37,72,494,203,244,457,56,351,579,125,111,8,237,817,326,403,0,752,98,922,961,901,160,277,22,719,730,144,44,206,14,386,899,86,45,482,437,304,373,143,89,569,9,116,453,475,308,253,300,61,105,76,27,638,164,95,49,490,29,18,94 }, +{ 217,15,317,82,351,141,260,854,13,77,23,120,51,922,115,1,21,180,110,137,365,341,352,372,269,349,898,291,36,202,64,5,32,450,318,373,177,128,752,96,304,523,93,33,48,165,326,197,102,0,10,40,901,9,4,160,498,247,90,244,661,203,22,59,482,2,12,143,86,437,386,83,457,28,473,30,67,253,961,11,35,16,221,24,125,117,391,39,7,811,494,88,37,8,69,719,559,3,817,704,237,216,76,72,61,14,873,403,18,642,31,899,210,164,45,730,717,49,179,134,139,851,475,421,251,223,100,56 }, +{ 190,373,31,30,863,908,120,88,110,127,260,442,856,318,254,326,717,935,131,836,228,93,187,44,39,385,299,100,968,274,219,203,82,166,224,197,116,661,276,77,1,217,98,269,86,450,51,371,36,128,180,829,137,372,341,160,704,141,64,435,202,49,395,144,9,23,918,410,28,22,730,778,244,242,351,55,737,523,827,177,851,625,944,382,272,530,317,115,349,352,96,613,492,291,954,32,931,744,716,125,268,258,284,253,686,48,615,515,367,247,21,33,456,165,321,795,10,567,466,225,83,839,102,578,521,919,817,752 }, +{ 23,13,308,115,401,51,165,9,391,21,629,254,125,159,773,197,743,569,49,468,217,438,656,627,341,89,39,558,221,32,317,386,509,350,28,95,530,228,457,867,109,166,406,876,679,48,669,364,219,158,365,346,168,912,810,101,170,105,72,64,143,30,347,258,967,237,148,90,688,274,131,670,272,185,749,843,33,12,10,187,55,175,141,4,734,758,242,196,190,453,261,518,224,902,747,286,482,164,37,333,241,2,439,102,0,424,420,393,706,613,338,153,67,372,351,68,40,310,120,816,634,332,840,35,320,88,86,289 }, +{ 49,5,165,125,21,173,43,623,104,193,422,102,13,7,91,18,95,22,0,192,141,64,48,197,900,693,558,105,51,23,32,232,391,387,314,98,31,116,20,779,202,81,92,319,408,241,16,126,38,77,494,33,784,643,474,11,221,28,712,138,862,663,595,403,350,879,29,510,27,633,180,140,729,397,172,44,4,858,237,61,718,501,359,71,60,58,511,448,370,356,750,490,482,347,344,316,308,177,93,37,24,498,293,115,158,145,72,65,40,830,246,207,63,85,107,841,569,468,414,352,330,326,269,203,69,14,12,2 }, +{ 4,1,2,5,13,23,77,115,15,3,0,341,7,51,6,11,33,202,102,217,12,180,10,141,9,40,21,317,318,177,365,901,197,269,32,165,352,22,59,8,64,31,291,14,494,403,93,17,401,569,752,16,453,37,342,210,110,153,275,18,475,44,125,196,90,28,308,326,386,98,120,117,116,372,457,128,349,36,95,629,49,421,237,48,139,203,260,244,450,498,137,134,304,30,24,523,144,247,373,719,216,57,391,961,86,482,143,253,39,730,509,111,55,221,817,96,615,19,65,873,351,758,99,670,437,72,50,734 }, +{ 843,295,93,120,160,206,36,943,567,373,384,332,268,137,261,141,201,260,110,10,203,531,144,55,64,617,434,197,258,699,116,244,282,318,559,564,964,269,44,352,911,717,253,860,202,180,31,326,533,1,940,143,473,417,728,661,276,351,959,187,22,341,851,535,219,871,855,28,367,127,82,131,115,450,365,86,901,752,926,317,21,51,98,48,77,165,23,105,224,96,968,662,217,13,8,902,574,489,125,817,349,800,523,515,83,704,49,811,498,164,494,39,5,393,228,32,291,251,128,9,12,898,642,576,69,67,873,839 }, +{ 192,81,43,173,426,879,7,715,172,104,712,91,636,526,232,825,568,97,560,5,95,681,448,66,49,861,32,387,370,74,20,750,33,204,22,707,330,729,718,140,61,0,6,356,397,69,21,117,422,347,135,359,38,92,102,263,348,64,174,4,414,153,888,237,138,319,76,298,40,13,885,52,2,107,86,500,25,196,784,595,77,819,241,180,134,58,207,85,29,42,31,355,65,577,72,18,28,1,343,48,392,23,10,126,89,324,37,189,344,233,314,11,933,71,14,511,16,408,115,673,46,498,45,671,125,60,858,246 }, +{ 475,453,403,51,33,102,494,23,196,13,202,153,117,77,0,318,128,757,421,22,342,730,899,817,18,805,65,15,958,450,134,4,402,24,36,59,269,40,49,210,401,1,28,697,670,64,11,114,291,48,16,576,108,386,523,141,57,177,21,20,86,165,133,95,90,120,365,317,326,260,221,180,137,31,10,115,752,99,498,457,391,361,352,70,50,32,349,113,9,6,3,864,838,770,743,373,351,338,268,242,206,125,116,109,5,283,253,84,17,961,801,791,546,372,341,237,217,214,205,194,163,143,96,72,69,68,30,14 }, +{ 141,269,260,318,352,202,120,351,349,137,854,82,1,851,922,5,180,372,291,64,32,947,21,15,77,752,494,13,48,304,33,7,51,717,23,217,373,177,128,678,450,115,237,326,317,70,898,36,403,704,312,4,160,102,86,90,968,247,95,87,196,49,275,244,197,22,165,67,96,35,288,203,817,735,125,342,144,93,16,216,163,50,44,31,83,954,2,69,597,457,241,59,153,961,221,110,98,39,30,9,8,901,661,551,523,473,442,386,367,284,210,864,117,61,12,0,800,29,24,863,859,730,719,475,453,385,316,293 }, +{ 15,1,2,13,5,4,3,0,23,7,6,115,217,12,180,197,9,51,21,11,352,961,8,10,165,77,457,341,141,317,22,14,901,33,31,117,93,120,102,40,134,752,202,365,260,16,37,269,569,110,32,44,28,318,64,18,17,48,351,719,153,386,177,82,291,36,196,98,873,450,49,125,59,128,498,403,72,326,482,30,523,401,99,854,308,203,24,453,89,137,95,391,509,111,349,86,139,730,372,247,144,55,210,116,342,494,304,475,373,148,922,90,105,237,661,35,579,899,143,221,39,19,629,275,421,758,244,468 }, +{ 166,39,274,404,101,252,190,30,333,9,310,0,100,438,656,158,265,88,68,625,329,530,553,419,344,539,254,455,793,778,21,48,759,228,49,676,1,131,960,709,557,731,520,154,23,35,382,13,124,364,604,677,105,28,272,16,286,406,212,31,51,18,613,219,224,593,840,159,167,125,36,98,65,518,669,865,118,24,44,96,213,748,264,777,115,83,175,22,86,538,957,221,127,55,327,5,10,857,694,688,137,258,795,410,806,627,95,71,577,289,128,116,578,32,50,242,69,724,187,352,562,346,616,67,33,827,846,191 }, +{ 28,0,1,9,22,65,12,83,67,55,109,50,24,5,36,49,39,96,35,238,16,18,2,21,114,124,69,37,7,218,48,23,323,103,158,160,168,54,51,128,285,154,13,68,185,137,14,194,99,141,95,169,181,418,289,420,202,433,86,30,75,480,175,10,505,105,115,32,402,281,223,389,269,208,646,503,745,64,133,46,180,657,159,800,531,547,251,956,101,429,4,318,31,149,163,6,70,346,58,532,822,533,484,757,797,165,335,252,197,735,570,352,283,361,71,98,29,118,3,535,927,766,221,217,38,799,237,308 }, +{ 15,1,2,0,23,5,51,13,7,6,9,180,12,115,3,457,197,8,719,21,730,4,120,901,141,202,14,33,165,341,453,386,82,31,260,351,365,523,308,64,37,22,44,401,450,32,40,16,93,77,110,10,98,961,403,36,102,899,28,217,11,125,352,196,48,318,137,317,475,153,18,269,49,569,116,752,99,326,421,128,24,30,221,95,39,203,117,873,144,817,629,758,177,55,86,35,494,509,898,373,59,237,105,17,65,291,96,89,498,670,482,247,253,134,468,38,143,54,244,72,90,372,160,854,127,210,391,801 }, +{ 9,39,166,49,30,28,0,158,22,131,180,100,219,35,352,190,345,228,1,752,88,498,115,141,274,317,482,109,83,128,930,251,36,217,95,365,230,55,101,160,254,165,224,159,168,23,341,13,105,31,208,187,258,927,310,197,69,137,333,901,864,364,64,185,269,86,344,505,252,202,404,68,286,873,539,372,96,669,438,51,10,164,67,5,868,346,244,637,439,2,7,21,748,323,406,418,318,16,237,44,272,50,840,706,420,265,127,98,946,735,793,768,579,169,125,530,175,148,327,857,702,678,238,116,12,48,533,335 }, +{ 61,311,80,209,45,29,5,58,2,151,454,106,17,6,667,243,255,738,52,592,70,496,287,74,483,1,833,112,549,27,207,119,26,315,32,227,378,19,64,14,138,25,84,263,75,742,186,631,113,21,136,56,48,887,62,46,7,307,469,72,76,145,50,73,66,161,128,495,148,425,814,651,491,4,34,95,869,86,38,87,3,334,240,290,383,396,845,42,53,306,12,171,65,141,163,445,135,155,11,22,54,297,90,331,179,226,655,632,37,614,361,292,663,89,400,13,36,23,10,137,294,666,99,659,250,220,59,51 }, +{ 31,44,299,22,125,599,456,685,116,28,492,393,170,242,144,268,963,301,506,1,95,558,367,36,239,55,489,0,918,109,206,23,105,9,10,434,127,51,384,13,86,286,948,479,98,64,841,5,338,2,93,12,203,498,164,7,512,168,21,143,165,49,903,940,320,401,391,137,8,37,900,417,352,141,115,128,546,253,457,959,237,14,185,197,308,169,202,395,282,421,374,911,180,740,332,293,386,6,24,312,855,538,509,752,244,473,65,928,762,160,638,617,341,269,961,867,949,730,654,403,551,499,965,523,48,719,16,453 }, +{ 187,258,926,839,574,860,93,219,406,228,871,160,531,224,137,902,201,120,116,36,203,144,669,268,318,131,442,567,816,295,434,908,851,533,843,44,384,717,202,800,559,373,489,728,141,332,855,206,261,276,1,260,269,251,617,326,180,317,385,940,110,613,217,959,55,31,450,352,968,365,115,197,64,699,679,244,98,96,83,23,10,840,341,77,492,473,899,856,831,661,143,127,190,918,752,539,21,284,418,13,943,748,662,911,564,530,48,165,291,523,704,128,345,125,822,351,169,954,86,349,367,922,776,535,177,51,824,22 }, +{ 7,107,24,60,349,232,16,51,18,75,9,291,87,23,71,269,92,126,77,141,64,177,307,150,461,35,220,14,330,37,121,0,46,279,115,947,267,132,32,12,172,55,112,309,13,10,448,278,202,21,70,2,372,210,852,678,441,304,28,5,328,217,147,54,48,786,660,259,359,318,155,90,334,181,180,140,872,108,22,163,102,31,409,314,394,352,341,281,171,68,30,622,294,236,20,423,49,626,33,760,186,58,687,415,50,39,407,128,43,771,365,197,237,1,400,929,498,888,590,366,342,270,192,135,100,76,61,675 }, +{ 15,1,2,0,5,7,13,6,3,4,115,23,180,9,12,901,51,8,341,961,365,197,10,22,141,82,33,351,14,11,77,120,31,202,457,165,217,308,134,352,28,64,102,21,269,569,110,18,260,317,40,44,16,37,36,719,93,318,237,137,99,177,450,30,125,128,386,49,752,153,55,498,17,391,98,24,111,403,32,39,196,117,401,116,373,898,730,523,326,291,453,95,854,509,304,247,86,59,372,546,482,349,143,475,899,203,244,494,139,35,48,642,253,811,144,105,210,160,758,421,148,629,221,90,164,65,127,638 }, +{ 23,51,13,202,5,12,115,21,141,165,1,32,2,318,197,15,403,180,453,7,6,3,401,269,4,0,128,308,37,10,99,457,14,11,9,120,64,22,48,341,137,386,494,475,17,77,16,719,18,217,125,31,352,523,421,59,730,90,153,365,391,237,177,317,28,40,450,260,72,221,33,8,569,93,509,961,44,19,89,102,291,98,247,326,498,76,24,49,817,899,758,30,57,629,117,61,36,110,29,139,20,210,402,82,304,196,95,45,351,752,38,285,116,203,134,349,241,96,468,54,216,901,482,576,546,25,275,342 }, +{ 2,1,77,64,141,6,3,7,0,33,102,5,10,13,23,14,269,180,15,217,165,291,352,40,117,197,9,17,115,202,237,4,128,11,22,341,12,153,349,134,196,16,51,86,318,317,177,36,19,125,137,95,342,18,752,8,28,365,31,210,457,143,139,498,59,372,21,164,57,304,82,120,45,27,38,275,24,49,110,391,386,111,93,44,244,901,260,509,56,32,41,450,98,65,99,351,30,961,55,37,403,864,569,494,29,678,48,312,453,326,546,203,20,25,54,401,79,373,402,61,253,26,46,62,719,76,475,523 }, +{ 345,531,332,269,717,260,373,317,728,752,351,180,352,533,10,365,498,82,160,251,244,36,901,143,217,341,93,55,1,141,873,864,898,35,9,564,64,851,951,22,417,137,253,28,617,169,67,69,120,559,854,197,601,482,318,546,115,768,21,96,83,661,261,876,110,372,237,164,144,535,574,203,800,206,16,86,349,31,824,699,50,48,831,902,843,860,434,968,125,221,579,959,700,679,384,926,922,295,7,51,23,291,148,418,230,202,24,943,468,896,201,5,776,77,839,44,258,954,816,13,811,940,844,637,473,868,822,308 }, +{ 92,16,189,7,77,60,388,140,33,153,196,102,35,117,230,134,150,733,314,24,14,71,21,915,246,1,108,594,97,18,32,48,66,126,69,517,121,462,64,22,98,13,399,723,65,5,291,95,67,451,674,267,232,217,653,298,2,23,38,223,104,711,83,0,197,90,36,423,149,46,125,49,167,28,68,195,20,172,120,251,86,12,289,214,508,115,386,633,236,133,10,50,350,458,191,165,330,51,107,31,260,6,43,55,271,841,450,457,273,326,796,146,509,221,603,380,237,702,9,194,4,202,199,103,52,357,29,74 }, +{ 234,142,178,202,639,5,49,450,77,70,786,416,929,48,259,455,21,0,878,147,315,481,198,329,427,318,1,125,105,120,61,113,534,846,58,344,12,132,95,518,465,325,22,31,163,557,494,13,159,32,761,767,128,590,146,37,798,195,269,711,371,291,402,265,50,342,158,362,260,39,98,221,884,687,30,64,279,137,2,167,10,771,165,35,640,626,522,403,293,310,102,23,817,347,170,28,581,99,141,236,127,150,107,51,271,87,763,623,845,212,7,18,423,194,17,523,112,345,663,33,44,376,239,199,121,391,116,75 }, +{ 81,715,192,712,681,636,104,173,750,91,370,0,74,95,718,22,7,825,879,20,49,560,43,64,422,172,397,66,138,207,784,86,500,65,28,18,707,204,414,10,577,174,319,426,32,38,312,888,348,330,4,526,289,52,355,61,511,861,347,33,237,29,102,232,448,31,21,353,835,124,5,6,2,643,36,85,97,117,153,77,306,59,134,819,140,673,671,24,40,120,165,729,568,240,135,280,324,105,125,98,344,519,233,387,194,288,196,693,474,241,214,701,44,107,583,314,260,450,847,287,69,25,872,587,343,84,9,817 }, +{ 23,13,51,15,0,10,9,115,1,453,2,961,4,77,5,457,11,40,33,401,3,7,475,197,102,14,569,165,22,59,12,6,719,32,64,21,99,730,57,17,177,18,37,8,217,386,403,196,28,308,16,31,141,139,111,341,523,120,125,180,153,117,629,391,210,36,45,237,72,899,49,95,202,128,485,247,38,482,24,48,44,509,90,27,260,450,30,19,137,317,365,41,65,291,269,89,134,342,86,304,498,421,474,82,79,148,54,277,758,318,352,46,76,56,326,468,29,670,349,494,275,351,437,300,93,50,546,873 }, +{ 64,297,5,80,445,61,95,311,250,312,472,34,237,86,45,180,738,17,151,58,22,667,869,247,2,14,73,288,194,106,53,21,128,197,352,177,32,29,186,469,833,217,52,165,287,255,3,1,495,391,396,243,176,137,90,546,125,56,161,141,136,592,48,10,209,27,0,231,76,751,62,11,437,315,119,887,115,334,179,23,84,498,651,207,77,4,864,145,13,881,389,304,6,59,49,631,372,65,16,240,164,153,112,378,549,483,584,527,316,26,862,509,409,752,51,7,875,18,933,171,269,196,457,283,241,148,114,19 }, +{ 71,16,24,18,60,35,7,92,118,154,68,149,150,14,175,28,124,55,302,97,0,273,126,108,429,140,230,43,375,2,246,109,20,628,69,336,189,9,101,66,38,298,107,65,439,22,517,346,279,345,1,467,419,21,67,169,399,49,48,46,158,847,420,10,570,185,232,251,6,653,29,252,441,314,12,566,637,191,5,535,51,52,508,423,364,533,722,36,32,398,172,74,882,674,917,168,121,95,39,23,621,83,221,159,105,50,505,356,13,701,96,37,484,694,962,173,608,604,135,267,86,104,64,826,329,103,363,236 }, +{ 195,360,156,591,687,771,163,626,70,883,146,132,586,371,407,379,354,48,846,121,293,13,296,31,761,98,18,767,49,105,385,44,279,522,668,21,1,55,23,125,5,518,271,127,590,878,340,10,608,223,33,807,167,259,77,447,116,75,60,658,102,446,265,929,115,128,35,457,221,87,786,301,284,4,95,51,165,395,39,481,698,541,781,291,178,664,372,150,252,777,557,64,30,24,16,153,120,40,558,535,281,107,465,763,638,783,663,393,101,937,9,467,58,196,217,144,61,401,212,199,117,299,941,32,22,817,260,118 }, +{ 13,77,202,318,23,51,33,269,141,64,137,32,291,0,128,102,21,494,4,10,403,217,177,342,5,196,9,349,117,22,153,134,98,95,115,59,31,120,753,18,16,40,48,28,90,372,317,237,49,450,1,86,65,244,352,475,194,11,180,165,142,100,44,125,76,12,116,93,523,275,127,121,24,20,453,365,341,61,859,401,144,82,402,210,198,178,147,88,37,17,2,351,234,105,7,6,326,197,110,30,203,143,922,854,851,427,325,259,118,107,101,72,55,704,421,260,114,36,208,329,265,38,164,864,752,717,558,498 }, +{ 192,81,172,173,7,426,97,232,861,715,43,879,66,712,104,387,330,568,825,74,526,893,91,298,885,448,636,681,140,92,49,560,6,204,135,779,22,5,95,572,707,64,125,726,750,14,370,563,314,20,324,10,362,29,174,246,713,0,718,356,107,138,25,397,85,63,18,38,71,21,441,98,58,500,230,31,501,32,319,408,69,729,189,13,663,422,24,784,359,241,858,165,16,347,263,77,357,623,673,26,888,2,12,353,900,141,23,52,126,37,33,622,278,830,197,48,233,40,443,355,44,42,45,267,87,19,61,237 }, +{ 14,2,1,67,6,24,69,66,7,29,38,108,36,65,83,124,46,52,150,86,25,484,28,302,74,22,388,18,267,398,458,103,50,273,168,97,12,5,16,0,650,135,26,19,160,75,172,189,21,10,208,32,289,278,380,547,782,95,610,140,51,602,118,37,114,451,429,357,42,71,23,324,505,194,149,420,48,143,92,87,17,13,421,115,60,54,70,35,584,96,756,462,20,238,109,185,27,164,64,45,220,244,253,594,3,154,99,138,43,283,335,701,133,309,128,403,797,49,58,732,550,202,169,646,401,423,218,847 }, +{ 202,77,33,13,102,128,51,318,23,64,494,4,141,196,59,0,115,403,40,22,269,210,177,153,137,117,32,90,10,475,291,21,342,15,11,134,352,95,18,65,49,217,86,16,180,36,197,453,165,275,57,1,402,9,194,48,24,341,719,28,105,6,123,349,317,285,523,125,120,372,216,14,450,365,20,457,2,237,7,82,576,98,3,421,12,5,260,247,110,730,116,44,31,901,752,300,8,208,30,498,351,96,93,139,678,164,46,19,401,386,308,817,615,214,50,35,961,758,859,326,160,17,503,391,293,242,221,203 }, +{ 269,318,141,291,77,202,349,217,947,304,33,177,102,851,372,352,753,260,351,120,5,137,854,752,494,275,403,32,922,22,180,475,21,317,30,10,954,31,64,44,418,365,49,28,48,450,39,23,95,341,661,373,82,11,4,36,93,13,61,128,7,6,3,2,859,51,0,197,800,576,96,59,901,69,165,40,203,144,247,1,86,898,12,76,70,160,498,437,342,237,125,9,433,330,238,103,98,67,453,312,864,367,326,253,87,58,361,221,99,90,888,717,678,579,65,774,241,115,50,45,968,951,704,615,473,277,244,134 }, +{ 6,74,138,85,66,222,226,87,42,280,25,135,26,792,500,294,75,29,220,204,70,174,337,145,235,112,278,853,461,19,52,97,1,32,122,38,808,2,256,172,64,889,69,324,380,774,620,802,609,525,7,95,353,21,571,5,65,580,746,415,22,108,140,96,14,241,24,331,63,45,544,287,67,237,267,125,262,92,394,348,103,86,163,632,426,90,194,606,165,630,550,58,53,36,233,76,91,192,357,28,27,17,141,189,416,72,582,486,81,49,114,16,622,113,78,115,10,928,444,537,872,462,46,605,83,350,335,150 }, +{ 9,0,105,39,101,18,16,68,310,24,333,272,252,127,98,518,846,938,28,371,1,916,35,158,286,737,455,31,301,265,327,100,395,616,49,30,254,7,578,55,23,827,118,512,109,44,329,21,65,890,60,320,242,116,137,709,170,51,385,125,48,761,166,14,5,2,13,71,293,131,520,627,154,159,299,557,344,836,12,553,364,93,202,96,167,88,623,128,36,124,506,64,688,212,604,924,910,931,120,284,50,144,10,419,22,165,219,32,37,95,77,110,121,326,67,403,404,203,442,197,187,6,141,676,276,260,239,33 }, +{ 2,14,1,67,46,24,108,29,83,69,38,103,52,75,133,236,309,36,114,28,50,18,398,135,6,65,458,278,7,238,74,87,160,388,124,220,732,0,267,262,66,149,532,335,283,25,412,71,16,5,96,55,547,154,70,273,602,22,302,418,429,218,516,366,646,150,336,357,86,696,175,26,189,54,12,68,118,226,35,172,324,58,582,19,486,208,9,21,594,109,531,112,45,484,140,596,251,60,95,323,17,10,32,37,194,394,64,650,48,168,163,145,42,571,97,222,23,420,505,27,181,92,389,533,606,171,361,99 }, +{ 22,1,28,105,95,49,55,67,168,159,239,65,14,320,35,0,2,36,114,7,170,109,83,12,169,347,194,50,301,69,9,24,5,424,164,185,103,133,654,46,312,420,16,127,10,175,158,64,584,21,23,51,98,143,31,86,286,13,37,289,6,336,389,48,283,505,96,124,68,38,638,512,160,208,39,141,202,18,115,189,128,395,54,623,874,338,237,713,547,44,272,308,740,137,149,371,125,251,32,30,518,345,844,535,180,3,293,928,756,916,242,29,835,165,538,708,327,323,99,737,484,221,401,218,533,374,253,154 }, +{ 66,7,172,97,232,92,314,568,298,140,192,380,135,330,74,324,387,448,357,14,526,126,38,246,204,16,426,107,572,52,2,808,712,501,359,60,69,278,29,230,32,779,441,500,35,95,550,5,21,22,893,6,43,563,392,104,267,46,24,150,362,64,726,138,189,423,173,65,825,71,356,20,462,279,0,12,802,87,86,174,560,10,81,18,49,37,226,830,633,25,48,28,90,289,58,36,67,75,707,91,508,241,312,1,85,451,220,70,443,199,214,636,50,108,83,61,54,222,121,353,262,125,280,45,888,750,237,42 }, +{ 2,29,52,50,46,14,5,1,6,26,133,114,58,218,366,70,19,108,45,27,112,17,236,137,75,38,262,25,74,13,283,516,53,487,223,151,145,208,96,48,51,412,287,163,23,401,323,285,86,65,171,61,36,220,21,480,594,42,128,80,331,73,103,754,181,115,12,739,113,3,532,4,194,54,602,635,186,99,202,409,675,745,34,308,583,307,357,309,782,396,150,57,361,7,764,165,66,735,324,64,966,457,453,90,24,386,445,11,484,32,389,141,629,59,87,244,155,956,711,670,421,22,545,832,758,334,328,573 }, +{ 6,74,1,25,29,42,75,26,66,2,70,138,52,19,85,220,103,388,38,14,226,87,135,324,67,357,108,112,235,69,238,603,222,65,550,500,96,114,145,594,83,309,133,516,27,36,150,451,218,294,262,532,711,51,58,602,280,13,163,50,380,63,137,97,802,23,122,278,458,64,5,394,86,53,606,696,792,46,891,160,461,267,732,12,7,204,582,113,308,453,24,545,889,386,331,45,21,165,398,486,391,115,32,423,401,95,337,758,632,17,208,3,853,457,256,537,335,78,630,141,307,189,641,37,646,444,670,10 }, +{ 22,28,109,49,9,105,131,95,1,36,159,39,86,185,31,98,272,169,127,55,44,219,83,254,286,208,141,128,35,327,352,160,30,180,116,0,224,202,115,239,13,535,187,137,5,96,12,374,317,269,2,244,837,312,752,67,531,21,533,253,237,197,64,217,51,143,168,158,578,251,318,505,37,258,165,285,365,10,7,23,498,201,538,371,901,320,50,424,347,678,48,69,164,776,708,601,341,597,616,345,228,170,873,238,634,6,947,3,482,93,125,144,518,242,946,913,864,716,4,735,8,627,221,420,100,688,910,323 }, +{ 203,822,77,859,326,576,23,403,39,817,137,100,102,473,494,691,411,291,33,177,704,70,523,217,447,96,367,478,18,373,160,13,363,265,1,658,615,93,966,520,310,144,30,692,800,578,342,182,180,120,90,51,254,296,40,158,682,333,9,354,921,349,273,127,121,101,83,60,59,24,731,264,115,821,364,44,268,260,752,857,810,272,196,166,153,131,118,48,16,457,156,67,506,481,450,415,230,15,0,593,968,914,212,937,829,395,365,351,242,225,224,219,194,187,146,141,132,117,110,87,82,49,36,35,22,905,901,656 }, +{ 15,33,117,77,102,134,153,4,115,196,13,40,217,11,341,1,23,5,317,3,365,2,291,21,32,12,349,569,177,59,51,342,0,6,372,139,7,37,901,210,10,180,17,90,111,629,48,275,82,120,197,244,304,141,14,253,137,57,202,247,401,638,308,457,300,9,719,961,482,437,260,277,351,579,31,44,93,216,165,269,36,125,450,72,523,453,89,38,352,94,730,854,116,752,18,817,143,98,386,64,56,96,318,16,468,55,160,148,61,54,76,22,485,110,403,99,221,922,19,474,79,127,65,105,588,27,490,128 }, +{ 15,13,23,51,0,8,197,180,1,165,9,33,82,5,4,10,12,120,2,102,386,115,260,475,7,351,141,110,77,901,326,14,21,18,11,217,22,457,40,93,898,453,373,36,450,341,16,6,125,31,64,854,352,719,401,117,32,391,28,730,3,291,177,203,24,961,523,202,59,317,403,99,49,44,210,922,615,37,237,111,801,153,128,498,342,629,196,509,30,899,569,421,304,752,48,758,817,276,258,137,269,130,393,98,365,57,116,65,338,144,55,704,134,349,105,206,661,551,308,242,38,95,494,275,86,546,318,56 }, +{ 23,51,1,13,21,141,5,180,15,2,202,120,7,0,197,165,12,9,6,4,115,48,352,269,403,386,33,260,318,93,3,32,457,110,37,137,14,450,475,16,82,128,523,453,102,31,18,326,125,421,8,77,44,221,391,64,308,730,401,341,217,153,11,117,98,719,498,196,30,351,99,40,752,494,24,237,317,39,72,28,36,10,59,203,49,373,365,17,116,817,90,899,96,509,22,569,35,901,144,961,615,342,45,50,291,177,86,89,244,661,55,134,20,54,854,65,873,801,402,160,95,247,38,350,629,127,105,29 }, +{ 15,1,0,2,5,3,7,4,6,8,13,10,341,23,9,180,51,82,120,77,31,110,197,961,115,12,22,93,116,165,569,730,202,217,365,752,457,453,719,102,125,44,351,30,403,141,352,33,11,260,523,317,291,475,28,21,450,318,64,898,401,98,899,386,203,36,210,40,177,269,16,242,638,421,326,153,349,372,18,817,494,854,117,275,342,59,111,196,14,137,629,49,134,55,39,143,70,32,37,139,95,758,244,958,498,801,87,24,922,86,670,253,144,170,208,90,105,615,373,873,391,308,247,482,216,61,393,304 }, +{ 559,661,922,564,373,141,260,533,244,332,269,317,642,143,10,93,110,295,728,752,261,876,531,351,206,843,120,345,203,352,180,811,253,384,36,197,144,434,717,901,959,365,498,55,567,1,943,9,28,535,817,22,160,873,902,341,326,911,35,82,601,860,39,30,679,489,824,704,417,926,217,251,940,699,574,137,617,854,201,816,116,282,898,115,44,372,855,258,237,473,662,509,187,169,864,499,349,284,125,31,468,224,21,669,64,318,164,546,951,395,964,839,450,8,219,170,776,638,268,851,23,131,98,482,367,299,48,730 }, +{ 15,5,1,2,23,0,13,7,6,51,3,180,12,9,115,4,165,719,197,457,21,8,14,33,901,22,37,141,82,341,120,10,730,202,16,110,32,31,386,11,317,153,117,752,260,351,453,217,401,18,352,77,308,93,961,48,28,44,134,569,365,391,49,269,102,523,128,98,196,758,137,99,498,36,40,30,450,64,403,17,318,509,24,89,95,475,629,854,72,125,221,177,86,873,326,247,96,899,817,898,39,38,421,139,116,291,482,55,494,59,105,203,210,144,65,468,29,20,237,54,349,90,148,372,244,734,35,45 }, +{ 198,234,5,0,325,77,416,202,61,32,147,49,639,20,43,21,315,22,450,113,95,455,142,427,48,318,230,207,342,18,494,13,329,904,577,725,64,178,28,10,70,58,344,470,102,403,128,819,269,263,104,137,1,319,112,246,17,23,347,291,7,65,887,798,120,12,241,4,36,858,107,237,66,76,376,817,39,422,316,72,97,33,945,105,2,51,90,141,290,884,557,253,9,518,251,671,11,173,86,31,115,27,159,158,194,3,24,312,289,362,260,259,192,859,414,426,16,14,306,523,37,126,475,712,576,310,453,98 }, +{ 447,411,264,363,676,9,664,682,821,812,759,478,897,166,100,905,354,156,1,382,98,265,404,724,39,18,691,656,668,101,520,195,23,144,223,21,865,271,438,593,639,848,31,96,13,5,51,521,125,586,48,127,604,88,909,30,252,765,393,647,360,77,33,121,167,781,367,44,621,132,93,0,410,274,286,118,203,254,120,272,105,102,293,446,116,83,32,658,68,310,371,284,777,115,364,4,834,16,948,69,333,163,24,212,190,40,340,329,551,914,117,49,110,153,70,165,146,35,296,418,10,67,842,242,883,326,697,238 }, +{ 24,71,35,14,69,149,189,108,267,18,16,68,46,2,7,67,140,388,60,38,236,83,251,1,133,118,309,230,336,52,103,29,458,278,28,65,135,175,150,50,172,92,273,55,0,154,75,443,114,9,705,124,399,66,565,398,412,602,335,366,36,101,823,596,451,74,220,345,375,302,594,330,696,516,87,238,6,891,21,218,5,12,54,262,48,96,86,22,582,357,324,97,191,64,70,232,283,723,95,10,37,160,831,732,346,246,563,380,32,25,109,486,733,167,58,314,212,226,192,13,429,99,547,23,181,126,572,394 }, +{ 35,16,7,20,14,60,18,121,24,43,107,68,109,126,199,326,92,120,77,907,2,147,23,259,265,475,403,260,553,1,13,523,132,252,12,146,71,55,33,0,5,859,191,318,817,38,6,450,82,202,848,402,9,286,51,21,329,159,494,419,351,28,465,327,102,10,158,48,682,374,576,198,178,97,32,421,272,621,269,615,590,279,128,941,22,446,167,142,70,493,4,310,604,581,19,105,640,463,453,407,153,694,64,810,150,108,90,29,534,427,212,346,285,709,638,557,793,137,101,39,37,25,291,165,118,95,58,50 }, +{ 30,131,276,187,613,442,44,228,39,31,190,839,935,224,116,856,219,88,9,406,201,908,574,100,244,127,567,137,36,98,110,144,1,93,202,863,258,141,829,260,28,284,49,120,269,295,318,716,21,827,254,661,166,160,203,373,299,55,385,0,22,662,352,944,13,82,530,77,253,86,268,23,96,717,489,64,180,51,326,274,778,918,48,351,492,5,752,197,83,206,125,128,450,115,217,860,32,242,931,578,293,213,102,924,494,851,95,10,101,836,105,272,143,291,699,371,35,434,165,843,864,367,403,159,177,418,261,68 }, +{ 98,223,1,393,812,834,421,697,48,265,593,791,51,410,100,382,293,284,21,23,125,96,541,213,656,88,801,453,31,321,230,765,730,386,221,13,689,9,264,670,639,163,217,5,909,807,116,144,44,352,137,286,551,30,770,948,39,252,699,466,438,435,201,401,127,93,842,475,203,165,921,478,180,166,949,724,367,963,831,36,128,404,455,805,141,676,854,202,2,317,318,772,840,190,32,418,251,855,105,35,333,77,83,197,102,335,49,443,576,957,719,351,539,308,69,55,82,310,115,0,120,557,752,329,403,269,686,669 }, +{ 98,616,219,127,258,51,293,512,924,395,105,421,272,276,308,201,401,284,763,116,23,301,295,453,327,567,944,31,44,843,261,13,268,860,170,770,115,125,569,900,131,386,144,935,456,55,578,365,320,143,341,662,137,109,28,403,434,242,221,36,203,670,286,141,10,326,22,629,21,943,95,9,743,685,160,384,623,506,180,49,206,949,533,719,734,558,282,299,185,159,244,64,8,0,110,964,911,169,32,4,224,551,202,475,11,187,910,617,492,901,253,841,716,1,489,269,959,940,165,699,615,374,855,332,237,713,86,371 }, +{ 253,951,352,110,811,244,206,141,180,332,854,642,282,10,143,638,417,752,559,533,498,260,55,661,911,499,717,120,351,959,535,93,564,160,873,531,137,341,269,197,922,384,373,36,365,728,261,617,901,8,44,82,116,165,31,317,164,64,203,217,509,824,115,473,968,268,144,326,704,434,295,601,86,15,345,851,864,237,943,251,450,169,1,843,201,762,13,372,22,258,308,125,898,96,98,202,127,855,940,4,33,489,21,28,187,9,40,546,117,83,569,338,964,51,5,32,479,391,276,23,102,318,482,349,219,153,128,817 }, +{ 49,254,272,159,9,158,627,131,327,39,518,688,0,578,28,286,68,105,101,347,424,374,364,344,224,22,333,616,65,219,35,24,124,154,716,890,95,577,16,371,320,109,810,538,228,168,310,793,747,127,30,419,613,829,827,187,385,239,846,170,21,1,98,18,36,71,938,406,910,252,31,55,346,175,23,289,51,190,48,258,86,185,83,912,100,623,301,166,128,149,125,67,118,96,44,137,64,242,13,737,857,160,703,671,694,455,202,442,169,60,856,10,761,924,221,709,116,706,634,114,439,677,194,479,7,570,212,395 }, +{ 105,272,22,131,327,374,286,320,109,224,219,28,239,95,98,578,9,169,127,185,538,159,187,616,55,258,371,36,634,623,64,164,49,713,86,910,716,385,168,654,170,420,424,1,10,312,737,201,35,254,293,284,51,23,143,13,44,761,141,601,160,395,933,31,928,916,276,301,924,208,116,67,346,237,137,347,535,39,194,242,0,442,836,83,762,165,584,338,638,505,892,244,251,175,345,114,740,12,391,944,837,128,158,202,197,479,261,253,908,352,912,125,531,96,308,295,144,24,21,30,7,269,268,2,751,323,228,5 }, +{ 691,478,340,724,658,914,698,1,363,744,772,156,411,447,682,909,303,284,296,264,354,919,335,98,9,21,686,664,225,223,586,410,96,367,382,897,51,13,521,33,848,765,125,144,23,32,120,759,48,69,662,260,44,31,166,40,93,77,5,4,551,668,35,269,30,82,191,167,163,318,351,87,404,371,102,88,812,438,165,70,39,385,293,116,65,64,656,364,101,622,286,948,254,271,393,321,141,75,11,18,854,842,443,433,118,100,418,274,202,421,16,774,67,326,329,905,149,922,110,37,386,201,12,197,127,49,203,907 }, +{ 16,24,71,35,18,108,140,60,92,267,68,189,7,230,191,246,149,14,118,167,388,46,69,236,458,399,674,212,273,9,133,1,126,150,21,309,330,50,101,55,2,48,103,121,67,906,602,5,0,345,723,412,232,172,271,146,565,28,516,696,702,75,38,65,451,32,796,12,37,594,633,154,278,733,375,366,302,199,124,314,36,336,398,443,823,64,695,54,135,114,29,22,95,97,462,915,52,563,582,251,705,575,891,589,175,10,83,566,572,13,220,223,23,467,218,830,163,363,394,66,562,132,107,446,641,517,49,86 }, +{ 9,127,0,395,371,98,39,31,737,49,512,385,272,44,28,293,299,101,836,761,158,252,254,16,242,1,284,159,116,18,518,35,276,310,333,24,187,51,21,599,137,30,301,22,131,68,286,23,219,327,202,125,616,48,442,935,456,578,916,5,109,166,685,55,265,7,65,100,688,128,105,201,36,890,623,96,144,13,908,329,12,2,846,64,37,95,141,344,455,318,403,124,93,492,154,32,404,14,203,269,938,627,67,258,118,224,170,244,326,110,268,165,367,763,86,60,827,221,716,160,924,553,120,419,489,662,10,83 }, +{ 16,18,60,68,35,101,252,0,118,71,9,419,28,24,109,364,604,191,126,167,55,121,329,92,7,158,265,39,212,22,346,14,925,49,107,694,185,169,621,146,439,333,628,124,199,150,942,21,159,48,154,553,706,175,108,575,279,677,10,962,20,105,100,848,917,815,446,363,907,132,5,793,271,375,43,149,23,65,13,566,520,806,286,810,95,166,593,374,302,51,1,97,634,598,404,407,12,31,2,272,493,46,467,727,463,562,589,125,326,327,310,50,967,96,682,168,37,344,140,608,203,98,38,647,821,246,362,67 }, +{ 116,268,203,692,93,206,940,31,551,417,473,959,499,44,202,523,559,8,137,120,450,728,299,494,403,22,51,576,0,326,564,817,10,260,13,23,127,1,899,9,105,421,125,615,318,492,638,98,386,918,141,393,341,269,253,21,791,5,28,2,144,64,37,244,805,762,373,180,128,401,599,55,901,242,352,30,165,197,453,642,730,475,170,873,115,49,569,36,4,859,7,143,391,498,86,48,308,922,752,39,395,719,365,951,285,6,457,456,958,12,110,402,704,384,367,95,512,949,18,24,16,515,479,221,32,948,801,282 }, +{ 225,1,744,919,21,459,914,48,691,284,330,385,141,96,98,335,622,166,5,293,51,32,120,223,948,340,260,443,203,88,286,30,831,372,50,363,351,269,82,64,934,70,658,9,190,127,403,352,13,115,418,682,411,371,87,144,393,909,521,922,776,272,102,90,69,61,839,23,15,4,774,349,327,321,268,244,202,197,100,93,551,75,848,662,523,442,478,373,206,201,180,125,76,59,45,36,33,963,538,410,274,237,163,156,821,303,264,772,724,450,382,367,958,954,899,898,865,864,859,854,765,752,730,668,664,506,494,475 }, +{ 5,1,14,2,36,50,28,0,48,281,21,67,24,54,22,83,218,12,38,18,65,181,58,45,114,133,430,32,17,46,96,10,9,103,37,160,502,61,155,99,270,55,72,7,29,513,16,51,108,487,238,23,543,745,86,3,290,6,540,89,361,115,834,13,52,202,221,433,842,488,480,137,236,76,69,328,223,64,838,514,49,532,35,666,474,128,171,283,766,536,227,124,966,308,75,19,552,95,70,208,775,141,323,27,541,822,697,425,754,765,4,285,207,148,657,109,318,412,243,263,77,592,832,663,741,186,807,576 }, +{ 450,137,704,202,326,120,260,851,318,968,494,269,457,182,403,291,351,349,77,678,141,23,310,373,817,859,576,661,523,890,60,128,82,64,795,110,854,70,515,96,5,159,285,1,961,341,13,717,9,421,922,203,180,95,244,55,379,658,577,347,105,75,49,822,687,115,363,800,557,301,160,36,937,475,411,67,59,237,18,16,354,195,864,771,615,520,424,415,344,83,68,51,28,0,805,447,386,364,268,232,107,101,90,86,7,668,481,342,271,786,735,901,897,846,751,731,719,638,621,586,518,402,296,253,239,208,197,165 }, +{ 15,4,33,77,40,13,102,11,23,5,32,21,110,117,217,51,93,153,59,1,247,134,115,141,64,202,120,2,372,180,3,10,12,31,82,291,177,116,139,125,269,196,8,317,17,22,165,137,98,351,318,36,44,128,203,197,28,0,352,48,260,349,898,144,57,403,450,437,6,719,341,72,304,111,457,523,90,365,494,9,326,49,37,730,7,210,39,86,30,14,475,95,386,453,638,961,854,373,76,401,901,237,277,752,56,342,160,817,244,758,402,308,899,143,89,206,216,569,421,615,61,535,45,18,316,127,164,579 }, +{ 23,13,51,1,15,5,2,7,0,21,180,6,115,12,141,9,165,3,197,457,202,4,14,352,719,48,33,32,16,269,37,217,341,8,11,401,120,318,308,22,386,77,31,18,128,752,40,110,260,10,28,453,730,93,137,498,901,403,391,153,82,317,365,117,44,102,17,523,961,569,64,450,509,72,99,49,134,36,758,59,98,221,24,629,89,30,351,475,196,326,125,177,494,291,90,421,237,29,899,203,35,39,247,864,817,95,372,96,349,20,116,854,65,38,54,160,19,144,57,86,244,304,873,55,342,373,350,316 }, +{ 219,258,127,276,98,944,395,201,567,284,131,293,935,860,116,662,295,224,737,105,578,576,242,403,843,371,137,551,272,456,512,421,51,31,475,716,202,697,261,44,492,187,924,616,268,9,49,326,206,254,144,299,39,385,22,115,916,805,93,699,308,203,943,159,160,761,836,763,125,23,13,0,332,453,401,386,36,120,28,770,141,21,327,615,384,393,282,958,221,318,494,367,365,143,217,128,434,64,692,940,10,244,110,617,301,911,55,964,730,320,5,966,523,86,719,623,457,96,95,1,269,317,24,670,197,859,842,286 }, +{ 16,35,60,18,7,92,20,14,118,0,68,126,71,28,154,24,107,43,158,22,2,109,49,55,677,168,185,1,97,6,121,12,21,175,10,5,159,703,150,202,169,105,191,942,95,38,494,279,37,137,23,13,9,329,230,140,628,48,69,420,32,553,124,326,167,128,403,120,747,101,74,51,108,925,31,65,66,621,246,475,29,46,36,576,344,52,419,25,575,81,104,98,375,173,570,421,346,39,265,199,86,50,671,269,424,362,58,318,54,450,44,149,125,143,817,566,615,302,61,439,260,453,170,165,493,402,67,286 }, +{ 728,531,160,93,373,574,559,717,120,860,533,295,269,260,318,926,851,434,258,36,902,137,251,332,617,141,201,261,699,206,384,940,968,843,816,345,352,244,187,839,564,55,776,661,144,959,871,116,64,219,44,473,489,268,535,203,10,567,31,911,498,143,896,110,679,450,523,224,824,800,197,164,276,601,351,406,662,202,873,752,943,317,365,169,855,228,704,282,131,180,253,326,82,954,1,669,125,854,367,901,98,217,165,417,817,341,86,442,831,8,898,642,284,13,127,876,237,21,947,864,22,83,23,748,418,115,946,868 }, +{ 28,9,0,1,22,109,49,39,83,55,12,158,67,96,69,5,35,30,65,95,168,323,159,128,185,238,21,50,36,105,2,24,160,23,194,208,103,7,68,169,137,218,141,48,37,505,16,420,51,13,202,86,251,285,18,114,269,31,115,531,124,10,289,418,101,402,797,154,433,32,99,175,64,866,735,252,180,646,272,100,286,480,503,54,333,533,244,14,344,131,352,44,318,127,98,327,6,346,217,570,254,197,237,181,657,800,535,745,374,4,335,75,317,165,281,756,143,584,757,419,532,345,956,365,223,831,403,341 }, +{ 23,13,51,5,141,21,1,165,202,2,15,32,12,197,115,180,7,0,48,269,120,9,4,6,453,386,403,318,308,401,37,457,14,33,137,352,64,3,125,128,523,16,31,93,391,260,730,719,475,341,450,237,99,18,82,110,11,10,44,77,326,421,8,217,494,40,28,90,102,59,49,17,117,36,98,30,221,899,247,317,22,365,72,153,509,24,196,351,39,498,569,629,752,89,116,134,177,203,20,373,96,961,901,372,817,241,291,45,86,57,19,61,76,304,38,758,468,65,50,160,105,144,55,402,29,244,216,25 }, +{ 5,21,13,49,23,43,32,20,48,14,7,51,97,107,61,115,38,713,22,24,1,12,70,46,652,955,142,58,16,590,0,626,197,2,640,147,64,279,581,132,350,150,121,303,81,493,340,888,841,104,36,60,87,18,95,345,92,241,296,221,509,98,349,308,622,91,202,195,638,141,125,35,408,407,156,379,269,146,66,28,31,9,786,534,17,128,903,929,518,178,29,354,4,108,105,263,522,687,247,65,259,850,126,44,237,199,54,774,535,271,260,50,347,6,446,318,159,90,10,288,137,783,360,76,223,598,55,586 }, +{ 9,28,0,39,101,30,49,35,68,1,67,166,175,83,22,158,100,252,141,55,88,69,65,109,36,23,180,217,323,115,64,269,345,103,21,124,10,317,13,251,289,238,364,498,154,352,230,5,419,131,190,31,7,51,194,48,50,346,96,128,439,159,160,105,202,24,274,143,952,95,16,168,12,646,341,254,752,86,868,365,637,596,244,127,137,570,433,318,418,114,864,208,44,37,503,404,372,2,32,344,197,333,116,532,218,77,98,187,237,164,125,723,535,443,480,169,265,901,189,310,221,420,336,873,797,403,402,285 }, +{ 260,120,450,351,854,82,269,922,5,32,13,125,33,23,202,291,165,21,197,77,137,1,141,203,457,349,318,51,4,326,177,144,180,753,730,275,386,523,817,237,116,217,373,719,403,98,93,31,372,128,241,115,12,899,704,341,304,196,102,44,40,391,48,2,342,898,954,864,801,494,284,208,110,76,59,365,352,285,207,947,758,663,615,599,558,492,482,456,408,350,263,210,201,160,64,57,49,19,18,16,14,11,10,7,6,961,317,361,37,968,752,661,498,475,453,402,323,300,293,268,244,206,154,127,105,96,95,86 }, +{ 121,16,60,363,35,18,101,20,167,68,621,259,126,191,604,407,107,132,55,364,43,146,199,252,7,14,92,419,590,147,212,71,9,326,5,463,520,21,694,917,465,24,354,446,647,109,13,271,682,0,28,22,120,203,10,97,806,821,48,169,77,279,727,362,2,346,195,581,640,932,178,589,118,115,102,125,23,202,51,439,941,907,848,411,450,33,857,427,634,165,553,154,108,180,39,494,325,185,373,329,142,475,265,818,49,342,158,967,403,260,1,523,374,612,110,962,12,534,955,37,615,376,150,793,692,562,137,638 }, +{ 23,13,51,5,1,12,2,141,15,21,115,0,202,180,7,32,197,3,165,4,6,9,401,37,269,14,308,457,352,11,318,453,341,386,120,403,10,16,33,22,8,719,18,391,40,31,77,48,217,28,137,17,99,365,523,475,569,128,730,44,93,59,260,102,498,450,90,49,509,24,30,317,110,752,421,64,247,125,72,82,237,221,177,629,98,351,961,494,153,36,89,19,117,758,901,373,196,326,57,38,39,29,20,65,546,304,134,116,95,899,817,139,372,76,35,55,316,241,291,468,482,203,144,210,45,402,873,54 }, +{ 201,144,206,443,418,332,203,435,330,96,494,326,473,372,335,269,434,268,187,403,822,817,459,1,88,498,564,384,839,382,617,367,83,264,934,559,295,276,30,717,344,521,141,831,321,274,44,202,576,31,9,686,709,190,100,921,699,812,252,55,230,137,208,450,616,457,284,180,128,93,28,859,410,966,228,265,456,352,69,523,318,244,158,795,961,747,735,662,584,531,421,855,213,168,960,225,478,959,899,716,578,577,489,466,417,291,223,116,36,35,23,13,954,952,237,800,349,285,77,744,866,772,752,346,197,166,98,32 }, +{ 44,276,31,116,201,284,662,567,131,489,144,268,295,434,918,30,9,39,98,137,187,219,299,224,935,367,49,384,385,36,93,22,28,0,244,261,141,127,492,699,203,110,254,1,202,836,160,442,253,258,105,96,64,269,393,51,128,371,125,23,716,55,86,318,326,10,908,120,206,940,855,77,143,190,827,13,21,228,352,217,100,35,159,48,165,115,272,944,373,948,260,617,829,102,197,166,578,737,83,16,332,293,95,717,450,24,523,88,180,403,109,18,177,37,164,5,899,242,959,613,730,285,291,15,7,616,911,473 }, +{ 520,664,478,604,759,264,167,1,724,777,9,647,411,682,48,806,936,363,101,223,265,410,21,68,118,252,100,907,848,447,772,98,96,781,0,212,88,905,16,821,39,925,917,23,329,909,382,18,166,942,125,191,639,221,13,24,51,676,124,932,321,897,621,628,521,5,71,154,69,31,30,815,686,293,541,49,284,271,60,593,765,55,32,812,404,435,335,807,163,562,44,834,553,35,691,65,364,763,105,83,146,28,127,274,10,158,7,190,393,64,238,213,419,67,701,421,354,33,22,254,697,149,116,272,201,115,77,144 }, +{ 70,23,87,21,60,75,163,182,267,92,291,120,115,107,146,379,195,132,446,795,937,246,126,121,98,71,48,18,7,415,931,566,232,133,51,24,125,371,821,668,535,411,401,340,318,308,221,116,77,44,40,32,11,4,281,850,293,563,537,407,273,217,202,199,140,13,5,807,197,64,591,385,33,883,386,626,687,891,823,820,770,766,754,743,670,658,633,627,615,598,551,545,541,458,394,392,372,364,361,349,342,338,333,330,301,284,283,268,264,216,210,105,102,100,95,49,35,31,866,774,597,498,335,244,238,237,160,2 }, +{ 39,9,737,127,0,310,98,827,846,395,100,31,371,916,254,265,385,105,272,101,18,30,836,1,242,166,44,512,16,557,116,252,131,578,938,931,137,93,301,28,125,68,333,24,51,404,23,120,286,616,856,35,299,21,55,13,64,202,593,716,128,96,48,326,329,219,260,158,7,110,264,5,688,456,77,203,165,36,49,373,924,761,442,118,863,639,144,518,318,284,228,88,438,60,327,363,12,450,33,190,82,10,411,731,102,65,293,109,455,95,170,908,599,623,494,115,478,187,141,2,14,22,812,685,276,403,935,197 }, +{ 107,126,279,20,43,356,362,92,7,359,16,598,683,595,246,441,60,392,939,653,399,35,199,319,125,649,97,259,414,71,0,493,121,858,230,150,140,232,191,49,48,14,702,173,575,68,95,298,422,674,18,64,98,590,147,22,612,118,28,24,672,104,819,407,345,146,77,660,695,10,953,375,423,31,945,314,293,33,640,23,115,93,158,44,167,149,132,154,21,783,5,175,81,807,508,376,105,109,59,13,40,391,779,387,237,124,589,470,55,426,4,330,727,729,51,427,169,120,796,223,91,189,446,117,153,541,463,755 }, +{ 206,417,93,959,728,559,499,473,137,120,8,564,141,244,260,253,450,31,44,10,269,352,203,318,373,143,341,202,638,116,752,180,144,951,940,326,268,110,160,851,115,922,127,98,717,642,384,125,434,64,13,36,51,282,615,704,365,661,197,498,23,901,817,30,762,489,276,692,15,873,165,22,968,86,1,854,128,386,299,105,217,811,55,0,242,421,317,351,523,367,237,911,21,170,49,77,9,349,391,28,509,479,187,177,82,201,576,285,164,898,492,401,96,456,291,569,494,800,338,33,32,5,39,372,12,261,295,293 }, +{ 259,465,147,581,534,132,590,687,146,427,199,279,941,195,955,640,786,107,178,522,798,121,929,362,150,5,198,325,626,142,35,21,878,376,407,360,167,48,271,1,423,10,70,20,13,126,77,22,125,98,493,31,163,49,212,202,0,105,43,783,33,14,156,345,883,102,612,767,28,97,660,346,470,221,23,450,60,12,771,92,191,379,120,591,2,467,318,9,32,61,4,535,128,153,117,116,562,95,953,18,115,595,159,494,17,371,44,293,818,58,165,51,7,68,354,246,234,269,87,342,845,196,260,72,6,134,481,93 }, +{ 523,403,817,202,15,899,450,120,51,730,494,421,719,128,457,453,13,23,342,102,401,318,64,196,33,475,141,180,49,5,115,269,308,197,237,221,165,99,4,77,137,95,260,0,757,576,365,316,125,65,48,615,402,326,159,11,671,389,312,289,283,247,210,203,194,148,105,22,21,386,835,12,958,749,743,697,485,351,350,341,300,177,170,158,155,151,136,133,129,127,123,122,119,114,113,112,90,89,86,84,80,72,62,61,59,58,56,45,40,34,27,26,25,19,17,3,901,752,153,134,117,961,922,968,967,966,965,964 }, +{ 141,559,244,10,661,253,564,143,365,533,752,180,55,110,901,160,922,373,341,317,93,535,352,206,260,531,36,197,332,269,82,642,282,964,498,911,717,261,728,873,943,351,137,64,417,854,120,1,811,9,115,217,898,169,28,165,164,86,384,203,22,15,83,21,959,96,617,499,318,35,31,8,482,295,951,251,345,372,902,5,473,601,144,32,546,843,800,237,13,864,44,509,109,824,67,268,450,391,308,349,23,258,77,567,851,291,202,116,949,615,125,926,954,638,551,569,457,51,326,102,59,434,817,418,958,719,629,523 }, +{ 219,258,276,127,284,98,935,860,943,843,567,201,137,295,964,131,261,116,535,662,492,44,160,253,31,224,206,203,615,268,144,332,293,692,924,918,384,244,944,326,36,128,434,395,716,737,367,456,187,55,96,403,551,318,911,617,616,385,699,533,115,940,202,365,10,836,576,966,523,959,77,28,21,93,9,120,489,141,1,260,48,371,531,217,143,282,564,125,110,180,51,704,421,299,39,23,64,363,254,393,442,242,494,417,105,822,473,317,578,269,272,697,22,855,102,805,475,13,948,341,0,373,33,285,82,49,932,574 }, +{ 422,319,0,945,207,887,32,577,693,43,95,20,904,22,344,61,104,804,707,306,426,124,5,725,7,241,153,325,316,49,715,414,113,671,115,239,263,329,173,198,180,102,18,365,117,83,24,33,376,510,942,355,324,140,134,69,21,9,232,77,76,240,237,196,189,177,160,158,36,10,835,292,341,526,334,331,168,92,48,16,330,37,25,204,64,901,595,416,392,347,858,362,244,174,164,149,97,86,60,58,39,31,30,27,790,770,222,65,2,350,40,11,4,814,13,933,424,159,819,397,697,623,610,491,403,387,315,288 }, +{ 1,22,12,5,2,0,36,21,28,49,105,86,95,37,55,9,7,48,23,32,141,83,10,51,31,96,269,202,13,128,50,4,160,239,208,318,14,168,159,6,3,170,44,67,164,54,115,285,99,35,109,98,244,180,64,137,402,65,24,127,16,352,320,18,197,69,323,30,158,11,169,301,708,678,238,312,77,717,597,39,143,165,584,194,125,17,253,217,341,735,281,114,116,218,654,181,403,237,424,103,347,317,185,177,45,401,15,776,242,29,46,72,68,418,498,433,223,33,569,901,480,531,40,657,365,800,851,8 }, +{ 15,13,2,1,5,23,3,0,4,7,6,51,115,9,10,12,197,11,14,77,22,217,269,8,165,31,961,33,457,202,32,180,21,341,40,141,120,102,177,16,569,453,28,318,317,17,260,291,44,365,93,37,117,134,110,30,352,18,403,719,153,196,49,401,59,475,901,36,326,98,64,304,386,125,498,730,349,494,450,137,48,247,95,90,523,308,752,24,128,210,111,99,82,139,372,203,873,57,76,116,237,342,72,629,351,391,482,509,19,421,39,144,373,35,55,216,89,275,437,817,20,86,105,56,899,96,38,65 }, +{ 23,202,77,51,13,120,1,141,15,326,180,269,260,137,318,102,450,5,128,21,110,217,291,165,197,352,115,317,373,2,48,12,7,0,523,33,203,386,403,9,96,64,93,342,6,351,82,32,14,457,177,16,36,817,349,752,494,37,4,475,18,210,901,854,341,285,615,59,275,90,498,50,244,160,391,453,99,308,86,10,365,401,22,719,922,8,221,24,730,28,704,402,421,11,125,83,67,237,661,3,40,898,30,153,35,961,31,196,65,253,39,576,17,44,247,20,569,300,95,49,899,116,509,473,117,143,70,372 }, +{ 15,1,0,2,51,13,23,5,7,180,9,6,12,4,115,33,197,523,21,120,3,8,14,457,901,165,351,141,450,260,202,365,341,82,16,40,730,31,37,308,719,401,77,93,44,18,10,899,64,453,403,32,137,317,386,217,36,48,110,98,475,102,326,28,22,128,269,30,11,116,569,421,352,318,817,752,24,196,961,221,99,39,49,144,153,629,55,89,17,203,373,35,117,59,801,898,291,873,177,509,86,125,494,244,95,160,482,134,498,854,72,372,96,615,349,468,38,143,758,237,90,127,391,54,342,670,734,247 }, +{ 16,24,18,92,35,71,60,7,75,126,140,108,50,132,9,21,68,121,14,246,13,0,146,23,267,1,48,128,220,107,70,230,150,32,12,199,118,5,394,181,87,137,537,46,51,133,269,189,141,54,64,22,167,10,202,156,2,330,281,820,171,77,99,291,774,217,177,349,58,65,39,37,103,69,163,28,95,67,622,318,309,633,86,236,101,360,372,6,563,36,195,304,115,38,641,314,30,149,522,232,20,591,352,354,49,545,55,98,571,271,317,526,649,407,672,278,100,640,586,45,223,114,31,678,430,237,388,328 }, +{ 180,341,901,15,1,365,5,2,0,4,197,7,6,115,3,752,10,13,569,317,873,23,165,8,55,141,9,143,44,93,31,498,217,51,638,253,509,308,352,12,22,401,244,36,116,33,21,11,206,64,144,120,951,391,629,137,16,37,86,372,269,125,734,386,134,110,351,40,18,421,417,260,77,282,117,326,268,499,102,457,164,318,482,373,237,203,170,127,95,35,661,642,82,202,177,559,468,261,201,196,160,221,105,961,32,28,854,551,169,24,349,811,762,728,564,338,14,242,717,291,109,153,139,128,403,312,437,851 }, +{ 9,0,101,175,35,28,39,68,364,67,252,65,124,289,158,336,154,166,83,55,100,114,439,103,419,69,49,194,346,1,30,189,345,570,109,88,22,168,64,251,50,16,547,36,230,96,596,133,389,868,265,238,149,86,429,24,694,21,128,218,637,399,141,703,23,646,51,826,13,671,208,677,159,706,95,137,7,797,505,610,237,12,115,756,10,404,484,131,768,190,2,333,71,164,18,799,329,323,344,967,283,202,274,420,782,930,48,105,286,140,217,702,480,143,212,54,37,962,269,14,857,185,310,532,254,535,197,118 }, +{ 64,115,180,197,237,165,391,247,217,352,386,316,304,32,90,13,21,468,95,72,317,76,498,89,365,291,141,125,22,509,349,288,179,86,546,98,372,23,341,225,437,49,116,569,645,796,923,459,18,411,308,177,48,640,4,586,490,16,5,12,591,312,241,933,117,35,65,134,482,752,672,269,164,77,156,302,71,1,264,873,410,321,118,446,360,271,102,59,24,682,674,246,953,88,149,751,51,521,92,823,447,144,864,37,7,11,695,702,166,781,698,662,647,588,458,403,401,363,283,239,216,194,170,153,57,33,28,17 }, +{ 15,13,1,2,5,23,0,4,7,3,115,6,51,217,9,12,197,10,141,21,11,961,457,180,8,341,77,33,165,22,14,32,31,317,202,120,40,37,177,260,16,102,93,269,901,365,352,28,44,247,318,18,117,110,134,17,386,569,372,719,752,59,48,30,36,498,153,403,196,49,450,291,82,72,125,137,304,128,453,391,730,401,98,873,349,373,523,139,509,24,64,326,39,90,475,111,99,308,899,116,95,89,482,203,351,210,86,922,144,437,629,55,57,421,148,494,342,854,35,76,20,179,817,758,275,105,237,216 }, +{ 132,199,146,121,407,60,493,279,640,598,534,522,195,581,590,955,360,126,259,107,150,783,362,35,5,156,271,49,167,939,18,16,147,612,941,591,467,21,883,465,423,929,0,10,191,92,22,298,441,356,446,13,70,48,7,31,626,28,77,24,32,296,178,97,212,33,354,108,608,786,623,68,345,586,727,660,71,649,687,102,163,125,9,105,115,683,55,4,463,379,75,23,87,98,14,953,293,159,50,44,818,761,376,61,246,40,64,763,713,109,1,120,117,767,359,427,95,101,20,344,58,43,607,221,575,663,142,153 }, +{ 28,1,0,22,9,24,65,55,12,5,67,36,96,83,114,50,18,16,2,14,35,103,21,109,49,48,7,218,160,54,124,69,433,37,281,238,23,10,181,51,223,133,137,39,154,745,68,58,99,480,202,13,95,86,75,128,657,115,283,532,285,46,32,163,323,822,38,141,175,547,30,389,766,108,45,168,646,64,194,429,158,169,185,155,361,505,418,70,420,800,531,105,208,502,269,430,6,101,71,866,318,765,402,289,838,398,149,31,251,221,29,484,757,543,4,3,533,308,180,503,17,403,72,754,171,118,217,89 }, +{ 93,120,957,968,459,77,30,160,352,217,473,110,102,372,202,373,613,291,137,260,190,752,704,141,317,31,318,961,269,177,44,326,203,851,330,863,450,264,321,265,228,224,728,457,304,247,88,924,116,840,800,219,144,365,197,115,28,187,717,49,39,944,559,908,829,406,934,349,213,916,244,131,64,225,36,98,82,9,730,403,342,275,210,180,109,100,86,33,938,855,55,831,521,367,719,10,661,165,922,935,258,839,918,864,669,539,351,274,196,166,83,341,15,959,822,772,617,285,897,531,410,716,686,478,871,251,901,836 }, +{ 15,0,1,13,9,23,2,5,51,7,12,6,120,4,8,10,102,197,523,901,341,180,14,260,115,82,77,141,33,165,3,16,21,18,202,59,450,22,403,457,110,817,93,475,64,351,11,453,137,37,401,898,421,128,28,40,719,31,961,217,36,48,569,365,30,125,269,308,318,373,203,317,210,32,494,98,44,116,730,352,24,86,49,326,386,117,342,854,95,629,17,153,144,55,391,177,922,899,99,291,237,143,196,39,805,134,221,96,576,670,139,752,35,253,244,661,300,50,57,127,402,65,638,349,19,498,206,111 }, +{ 206,417,244,499,141,253,44,8,137,559,269,144,93,10,31,728,116,564,203,143,268,352,717,638,120,260,160,752,951,318,384,341,180,282,373,959,434,127,110,197,202,125,851,64,36,901,642,473,498,326,332,115,165,450,201,98,873,242,922,23,22,1,217,261,276,762,55,13,489,86,661,51,317,365,15,940,898,811,82,855,854,704,9,295,0,21,372,164,351,37,968,187,569,367,911,5,576,28,617,401,237,170,615,128,776,349,7,48,105,421,479,386,16,96,95,299,291,12,258,824,864,308,817,2,30,403,49,692 }, +{ 530,840,254,228,406,829,669,613,827,96,21,48,51,31,23,960,137,224,219,1,166,131,39,98,679,438,310,190,856,116,93,403,274,221,144,127,258,846,36,202,180,938,688,120,318,765,421,385,931,317,475,13,77,816,876,105,44,187,30,115,5,625,203,125,752,442,141,32,367,308,365,284,924,778,341,842,50,28,268,333,242,217,860,160,100,22,616,539,110,88,871,159,37,345,9,165,33,839,332,299,83,574,351,576,68,404,371,10,518,326,82,748,716,863,492,578,401,265,456,102,269,656,128,926,557,531,498,494 }, +{ 15,13,197,457,0,719,23,8,730,1,82,165,120,134,9,10,5,180,2,141,7,12,115,51,260,901,4,899,351,6,341,352,33,3,22,386,450,31,202,11,117,569,523,269,128,93,18,898,44,110,758,28,752,373,365,64,30,961,77,318,498,873,21,854,111,49,102,37,16,40,99,137,125,317,14,391,55,217,24,116,326,98,403,474,36,494,482,817,509,372,35,661,277,139,922,615,38,801,203,143,291,153,475,86,453,253,629,304,148,437,402,237,48,642,954,564,864,431,244,95,242,144,39,401,72,17,196,958 }, +{ 68,0,16,24,35,9,252,71,419,18,28,101,154,158,109,124,118,60,39,55,329,364,333,49,65,677,346,22,7,185,265,149,159,175,169,191,810,302,553,100,14,92,344,108,439,671,703,793,105,168,375,286,272,327,374,21,694,706,1,10,67,126,254,634,310,95,212,289,701,2,48,167,150,455,166,627,577,30,747,420,273,538,46,69,962,36,51,23,424,13,12,64,857,429,593,96,5,570,925,86,917,199,37,125,31,50,83,826,628,912,107,239,604,98,638,114,688,221,967,131,709,137,170,336,140,20,589,128 }, +{ 51,1,23,13,15,180,120,2,5,197,202,141,0,7,21,165,260,326,33,9,4,450,12,102,6,523,48,386,115,403,269,137,457,352,14,318,16,128,110,77,3,40,196,32,18,93,217,82,317,37,341,8,817,96,31,401,453,36,752,342,351,44,719,203,901,28,475,221,421,365,64,730,24,391,153,30,308,373,10,494,22,615,59,11,39,99,98,50,116,899,498,961,177,372,291,35,854,144,509,244,17,49,922,569,86,72,247,65,349,125,160,210,482,127,117,402,20,134,55,873,38,83,898,67,275,88,285,237 }, +{ 535,253,352,564,365,110,82,180,854,341,10,533,873,55,244,898,752,901,143,642,141,559,498,36,317,951,638,160,661,115,197,282,964,137,531,165,634,351,64,308,164,217,169,206,417,811,86,499,482,28,332,125,373,509,15,569,93,546,83,728,762,965,96,22,468,601,260,911,269,717,9,349,922,109,345,800,291,734,31,23,338,170,1,372,538,629,221,943,8,120,261,44,21,318,743,494,401,128,202,13,822,579,403,251,617,959,719,770,67,864,219,185,127,117,48,286,384,299,730,475,453,402,350,69,421,391,98,39 }, +{ 31,125,44,116,338,64,242,55,164,36,299,1,237,86,456,10,22,558,506,144,498,492,13,23,762,170,268,143,206,685,93,870,180,844,599,5,903,546,197,115,2,203,509,169,479,165,141,127,0,352,253,393,752,740,8,137,12,51,28,341,391,638,7,244,9,457,160,367,873,98,128,384,951,963,282,202,918,21,269,37,6,105,569,629,434,365,120,301,4,708,318,3,417,489,923,901,719,317,308,401,386,535,217,14,15,734,95,551,634,499,208,533,332,49,758,83,824,961,730,239,776,601,523,751,948,717,864,654 }, +{ 23,13,51,4,115,202,5,217,77,141,1,11,180,2,317,0,3,7,33,269,318,15,365,341,21,9,102,10,32,6,40,12,352,177,22,197,403,64,165,128,901,59,752,31,494,137,308,291,28,8,18,349,401,16,125,90,30,14,237,498,372,93,37,98,153,49,453,17,36,873,44,475,457,39,342,196,210,24,48,326,569,386,421,247,95,203,120,509,275,116,391,961,117,244,110,143,57,304,144,216,482,719,134,139,468,86,523,55,221,450,67,76,50,253,35,105,260,65,437,373,730,72,859,629,46,692,576,111 }, +{ 39,9,166,364,68,101,158,333,0,154,562,28,404,30,65,124,252,35,175,274,344,310,190,706,49,289,570,100,168,438,694,419,346,703,826,55,16,24,439,21,88,149,254,577,429,810,109,159,962,857,671,212,455,656,22,610,95,194,1,336,747,13,125,67,36,131,530,865,48,71,625,793,10,589,23,64,841,265,484,539,86,224,558,350,69,237,420,51,835,96,272,105,406,677,165,228,83,18,31,141,114,286,557,221,347,115,137,169,722,778,7,391,98,818,816,308,840,634,709,44,185,128,960,777,143,258,669,60 }, +{ 15,341,13,33,23,77,141,4,0,351,1,260,102,51,82,9,40,349,854,11,115,217,269,137,180,202,922,5,901,22,10,117,21,365,318,197,120,352,64,12,7,153,177,59,291,32,128,2,165,196,372,36,403,317,457,28,18,8,16,304,30,14,450,31,898,37,3,752,48,134,139,494,421,6,453,401,719,90,86,569,523,110,24,55,475,210,49,44,386,17,730,95,247,244,961,143,125,308,342,817,629,98,498,93,96,76,39,275,509,326,99,285,373,57,237,35,402,160,111,253,105,391,221,116,899,72,127,661 } diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 9c3c24ac27..1355bf2a20 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -57,6 +57,7 @@ option( LIBKTX_FEATURE_KTX2 "Enable KTX 2 support." ON ) option( LIBKTX_FEATURE_VK_UPLOAD "Enable Vulkan texture upload." ON ) option( LIBKTX_FEATURE_GL_UPLOAD "Enable OpenGL texture upload." ON ) option( LIBKTX_FEATURE_ETC_UNPACK "ETC decoding support." ON ) +option( LIBKTX_FEATURE_BCN_DECODER "BCn decoding support." ON ) # Intentionally override the BASISU options, only making them visible # when they are useful. @@ -135,6 +136,7 @@ endif() set(LIBKTX_MAIN_SRC include/ktx.h src/astc_codec.cpp + src/bcn_codec.cpp src/basis_sgd.h src/basis_transcode.cpp src/miniz_wrapper.cpp @@ -178,6 +180,20 @@ if (LIBKTX_FEATURE_ETC_UNPACK) list( APPEND LIBKTX_MAIN_SRC ../external/etcdec/etcdec.cxx ) endif() +if (LIBKTX_FEATURE_BCN_DECODER) + list( APPEND LIBKTX_MAIN_SRC + ../external/bc7enc_rdo/rgbcx.h # BC1, BC3, BC4 and BC5 encoders/decoders + ../external/bc7enc_rdo/rgbcx.cpp + ../external/bc7enc_rdo/bc7decomp.h # BC7 decoder + ../external/bc7enc_rdo/bc7decomp.cpp + ../external/bc7enc_rdo/bc7enc.h # BC7 encoder + ../external/bc7enc_rdo/bc7enc.cpp + ../external/bc7enc_rdo/ert.h # RDO post processing step + ../external/bc7enc_rdo/ert.cpp + # ../external/bc7enc_rdo/bc7e.ispc # SIMD (i.e., fast) BC7 encoder + ) +endif() + if(LIBKTX_FEATURE_GL_UPLOAD) list(APPEND LIBKTX_MAIN_SRC src/gl_funclist.inl diff --git a/lib/include/ktx.h b/lib/include/ktx.h index 03da76f5e1..3b06dde4c6 100644 --- a/lib/include/ktx.h +++ b/lib/include/ktx.h @@ -1389,6 +1389,95 @@ typedef struct ktxAstcParams { */ } ktxAstcParams; +/** + * @~English + * @brief Options specifiying BC1/BC3 encoding/decoding approximation modes. + */ +typedef enum ktx_bc1_approx_mode_e { + KTX_PACK_BC1_BLOCK_APPROX_MODE_IDEAL = 0, + /*!< The default mode. No rounding for 4-color colors 2,3. This matches + the D3D10 docs on BC1. + */ + KTX_PACK_BC1_BLOCK_APPROX_MODE_NVIDIA = 1, + /*!< NVidia GPU mode. May produce artifacts on non-NVidia GPUs. */ + KTX_PACK_BC1_BLOCK_APPROX_MODE_AMD = 2, + /*!< AMD GPU mode. May produce artifacts on non-AMD GPUs. */ + KTX_PACK_BC1_BLOCK_APPROX_MODE_IDEAL_ROUND_4 = 3, + /*!< Matches AMD Compressonator's output. Rounds 4-color colors 2,3 (not + 3-color color 2). This matches the D3D9 docs on DXT1. + */ +} ktx_bc1_approx_mode_e; + +/** + * @~English + * @brief Options specifiying BC1/BC3 encoding quality levels. + */ +typedef enum ktx_pack_bc1_quality_levels_e { + KTX_PACK_BC1_QUALITY_LEVEL_FASTEST = 0U, + /*!< Fastest compression. */ + KTX_PACK_BC1_QUALITY_LEVEL_FAST = 5U, + /*!< Fast compression. */ + KTX_PACK_BC1_QUALITY_LEVEL_MEDIUM = 10U, + /*!< Medium compression. */ + KTX_PACK_BC1_QUALITY_LEVEL_THOROUGH = 15U, + /*!< Slower compression. */ + KTX_PACK_BC1_QUALITY_LEVEL_EXHAUSTIVE = 19U, + /*!< Very slow compression. */ + KTX_PACK_BC1_QUALITY_LEVEL_MAX = KTX_PACK_BC1_QUALITY_LEVEL_EXHAUSTIVE, + /*!< Maximum supported quality level. */ +} ktx_pack_bc1_quality_levels_e; +typedef ktx_uint32_t ktx_pack_bc1_quality_levels; + +/** + * @memberof ktxTexture + * @~English + * @brief Structure for passing extended parameters to + * ktxTexture2_CompressBCnEx. + * + * Since it makes no sense to set the target BCn format to some default value, + * this struct does not have a default initializer. I.e., initializing this 0 + * (e.g. " = {0};") is not supported. + */ +typedef struct ktxBCnParams { + ktx_uint32_t structSize; + /*!< Size of this struct. Used so library can tell which version + of struct is being passed. + */ + + // TODO: add comment about RDO (because RDO has its own integrated MT...) + ktx_uint32_t threadCount; + /*!< Number of threads used for compression. Default is 1. */ + + khr_df_model_e bcn; + /*!< BCn format to compress to. E.g., for BC7 this should be set to: + KHR_DF_MODEL_BC7. Only options related to the provided target BCn + format are used. + */ + + ktx_bc1_approx_mode_e bc1ApproxMode; + /*!< BC1/BC3 approximation mode (for both: encoding and decoding). + Default is KTX_PACK_BC1_BLOCK_APPROX_MODE_IDEAL. + + If you encode textures for a specific vendor's GPU's, beware that + using that texture data on other GPU's may result in ugly artifacts. + Encode to KTX_PACK_BC1_BLOCK_APPROX_MODE_IDEAL unless you know the + texture data will only be deployed or used on a specific vendor's + GPU. + */ + + ktx_uint32_t bc1CompressionQuality; + /*!< BC1/BC3 compression quality. Range is [0,19]. Default is 5. + Lower values give faster compression speed but potentially lower + quality. Higher values give slower compression speed but potentially + better quality. + */ + + ktx_bool_t normalMap; + /*!< Currently un-used (added for same code structure with ASTC + * encoder). */ + +} ktxBCnParams; + KTX_API KTX_error_code KTX_APIENTRY ktxTexture2_CompressAstcEx(ktxTexture2* This, ktxAstcParams* params); @@ -1398,6 +1487,17 @@ ktxTexture2_CompressAstc(ktxTexture2* This, ktx_uint32_t quality); KTX_API KTX_error_code KTX_APIENTRY ktxTexture2_DecodeAstc(ktxTexture2* This); +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_DecodeBCn(ktxTexture2* This); + +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_CompressBCnEx(ktxTexture2* This, ktxBCnParams* params); + +#if 0 +KTX_API KTX_error_code KTX_APIENTRY +ktxTexture2_CompressBCn(ktxTexture2* This /*, ktx_bcn_compression_e bcn, ktx_uint32_t quality */); +#endif + /** * @~English * @brief Options specifiying basis codec. diff --git a/lib/src/bcn_codec.cpp b/lib/src/bcn_codec.cpp new file mode 100644 index 0000000000..eac0a42186 --- /dev/null +++ b/lib/src/bcn_codec.cpp @@ -0,0 +1,816 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab: */ + +/* + * Copyright (c) 2021, Arm Limited and Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @internal + * @file + * @~English + * + * @brief Functions for compressing a texture to BCn format and decoding one in + * BCn format. Currently supported BCn formats are: BC1, BC3, BC4, BC5, + * and BC7. + * + * @author Walid Chtioui , individual contributor (walid.chtioui.main@gmail.com) + */ + +#include "bcn_codec.h" +#include +#include +#include +#include + +#include "bc7enc_rdo/bc7enc.h" /* for BC7 encoder */ +#include "bc7enc_rdo/bc7decomp.h" /* for BC7 decoder */ +#include "bc7enc_rdo/rgbcx.h" /* for BC1-BC5 encoders/decoders */ + +#include "vkformat_enum.h" +#include "ktx.h" +#include "ktxint.h" +#include "texture2.h" + +//************************************************************************ +//* Functions common to decoder and encoder * +//************************************************************************ + +#if !defined(_WIN32) || defined(WIN32_HAS_PTHREADS) + #include +#else + // Provide pthreads support on windows + #define WIN32_LEAN_AND_MEAN + #include + +typedef HANDLE pthread_t; +typedef int pthread_attr_t; + +/* Public function, see header file for detailed documentation */ +static int +pthread_create(pthread_t* thread, const pthread_attr_t* attribs, void* (*threadfunc)(void*), + void* thread_arg) { + (void)attribs; + #ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wcast-function-type-mismatch" + #endif + LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)(threadfunc); + #ifdef __clang__ + #pragma clang diagnostic pop + #endif + *thread = CreateThread(nullptr, 0, func, thread_arg, 0, nullptr); + return 0; +} + +/* Public function, see header file for detailed documentation */ +static int +pthread_join(pthread_t thread, void** value) { + (void)value; + WaitForSingleObject(thread, INFINITE); + return 0; +} +#endif + +//************************************************************************ +//* Decoder functions * +//************************************************************************ + +/* + * Cannot use DECLARE_PRIVATE macro declared in texture.h because it calls the + * variable `private` which is obviously a no-no in c++. TODO: consider changing. + * Declare our own similar macros. Cognizant that the using functions handle both + * This and a prototype object, pass the object as a parameter. + */ +#define DECLARE_PRIVATE_EX(n, t2) ktxTexture2_private& n = *(t2->_private) +#define DECLARE_PROTECTED_EX(n, t2) ktxTexture_protected& n = *(t2->_protected) + +/** + * @ingroup reader + * @brief Decodes a ktx2 texture object, if it is BCn encoded (i.e., BC1, BC3, + * BC4, BC5, or BC7 encoded). + * + * The decompressed format is calculated from corresponding BCn format. + * For BC1, BC3, and BC7 the decompressed VkFormat is: + * VK_FORMAT_R8G8B8A8_[UNORM|SRGB] depending on the original color space. + * For BC4: VK_FORMAT_R8_UNORM + * For BC5: VK_FORMAT_R8G8_UNORM + * + * + * Updates @p This with the decoded image. + * + * @param This The texture to decode + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_FILE_DATA_ERROR + * DFD is incorrect: supercompression scheme or + * sample's channelId do not match BCn colorModel. + * @exception KTX_INVALID_OPERATION + * The texture's images are not in BCn format + * (i.e., either color model is not set to BCn or + * This->vkFormat does not correspond to the set + * BCn color model). + * @exception KTX_INVALID_OPERATION + * The texture object does not contain any data + * (i.e., This->pData is NULL and there is no + * pending data load). + * @exception KTX_OUT_OF_MEMORY + * Not enough memory to carry out decoding. + * @exception KTX_UNSUPPORTED_FEATURE + * The texture's images are supercompressed with an + * unsupported scheme. + */ +KTX_error_code +ktxTexture2_DecodeBCn(ktxTexture2* This) { + // Decompress This using bc7enc_rdo + uint32_t* BDB = This->pDfd + 1; + khr_df_model_e colorModel = (khr_df_model_e)KHR_DFDVAL(BDB, MODEL); + uint32_t channelId = KHR_DFDSVAL(BDB, 0, CHANNELID); + ktx_size_t nchannels; + ktx_uint32_t decompressedVkFormat; + + switch (colorModel) { + case KHR_DF_MODEL_BC1A: + if (!(channelId == KHR_DF_CHANNEL_BC1A_COLOR || channelId == KHR_DF_CHANNEL_BC1A_ALPHA)) { + return KTX_FILE_DATA_ERROR; + } + nchannels = BC1_OUTPUT_NCHANNELS; /* 4 */ + // further sanity check on vkFormat + switch (This->vkFormat) { + // TODO: encode BC1 RGB (no Alpha) into RGB + case VK_FORMAT_BC1_RGB_UNORM_BLOCK: + case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: + decompressedVkFormat = VK_FORMAT_R8G8B8A8_UNORM; + break; + case VK_FORMAT_BC1_RGB_SRGB_BLOCK: + case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: + decompressedVkFormat = VK_FORMAT_R8G8B8A8_SRGB; + break; + default: + return KTX_INVALID_OPERATION; // invalid vkFormat (should be BC1) + } + // TODO: expose as parameter + rgbcx::init(rgbcx::bc1_approx_mode::cBC1Ideal); + break; + + case KHR_DF_MODEL_BC3: + nchannels = BC3_OUTPUT_NCHANNELS; /* 4 */ + switch (This->vkFormat) { + case VK_FORMAT_BC3_UNORM_BLOCK: + decompressedVkFormat = VK_FORMAT_R8G8B8A8_UNORM; + break; + case VK_FORMAT_BC3_SRGB_BLOCK: + decompressedVkFormat = VK_FORMAT_R8G8B8A8_SRGB; + break; + default: + return KTX_INVALID_OPERATION; // invalid vkFormat (should be BC3) + } + rgbcx::init(rgbcx::bc1_approx_mode::cBC1Ideal); + break; + + case KHR_DF_MODEL_BC4: + nchannels = BC4_OUTPUT_NCHANNELS; /* 1 */ + switch (This->vkFormat) { + case VK_FORMAT_BC4_UNORM_BLOCK: + decompressedVkFormat = VK_FORMAT_R8_UNORM; + break; + case VK_FORMAT_BC4_SNORM_BLOCK: + decompressedVkFormat = VK_FORMAT_R8_SNORM; + break; + default: + return KTX_INVALID_OPERATION; // invalid vkFormat (should be BC4) + } + rgbcx::init(rgbcx::bc1_approx_mode::cBC1Ideal); + break; + + case KHR_DF_MODEL_BC5: + nchannels = BC5_OUTPUT_NCHANNELS; /* 2 */ + switch (This->vkFormat) { + case VK_FORMAT_BC5_UNORM_BLOCK: + decompressedVkFormat = VK_FORMAT_R8G8_UNORM; + break; + case VK_FORMAT_BC5_SNORM_BLOCK: + decompressedVkFormat = VK_FORMAT_R8G8_SNORM; + break; + default: + return KTX_INVALID_OPERATION; // invalid vkFormat (should be BC5) + } + rgbcx::init(rgbcx::bc1_approx_mode::cBC1Ideal); + break; + +#if 0 + case KHR_DF_MODEL_BC6H: + break; +#endif + + case KHR_DF_MODEL_BC7: + nchannels = BC7_OUTPUT_NCHANNELS; /* 4 */ + switch (This->vkFormat) { + case VK_FORMAT_BC7_UNORM_BLOCK: + decompressedVkFormat = VK_FORMAT_R8G8B8A8_UNORM; + break; + case VK_FORMAT_BC7_SRGB_BLOCK: + decompressedVkFormat = VK_FORMAT_R8G8B8A8_SRGB; + break; + default: + return KTX_INVALID_OPERATION; // invalid vkFormat (should be BC7) + } + break; + + default: + return KTX_INVALID_OPERATION; // Not in BCn decodable format + } + + if (This->supercompressionScheme == KTX_SS_BASIS_LZ || + This->supercompressionScheme == KTX_SS_UASTC_HDR_6x6_INTERMEDIATE) { + return KTX_FILE_DATA_ERROR; // Not a valid file. + } + // Safety check. + if (This->supercompressionScheme > KTX_SS_END_RANGE) { + return KTX_UNSUPPORTED_FEATURE; // Unsupported scheme. + } + // Other schemes are decoded in ktxTexture2_LoadImageData. + + DECLARE_PRIVATE_EX(priv, This); + + // Create a prototype texture to use for calculating sizes in the target + // format and, as useful side effects, provide us with a properly sized + // data allocation and the DFD for the target format. + ktxTextureCreateInfo createInfo; + createInfo.glInternalformat = 0; + createInfo.vkFormat = decompressedVkFormat; + createInfo.baseWidth = This->baseWidth; + createInfo.baseHeight = This->baseHeight; + createInfo.baseDepth = This->baseDepth; + createInfo.generateMipmaps = This->generateMipmaps; + createInfo.isArray = This->isArray; + createInfo.numDimensions = This->numDimensions; + createInfo.numFaces = This->numFaces; + createInfo.numLayers = This->numLayers; + createInfo.numLevels = This->numLevels; + createInfo.pDfd = nullptr; + + KTX_error_code result; + ktxTexture2* prototype; + result = ktxTexture2_Create(&createInfo, KTX_TEXTURE_CREATE_ALLOC_STORAGE, &prototype); + + if (result != KTX_SUCCESS) { + assert(result == KTX_OUT_OF_MEMORY); // The only run time error + return result; + } + + if (!This->pData) { + if (ktxTexture_isActiveStream((ktxTexture*)This)) { + // Load pending. Complete it. + result = ktxTexture2_LoadImageData(This, NULL, 0); + if (result != KTX_SUCCESS) { + ktxTexture2_Destroy(prototype); + return result; + } + } else { + // No data to decode. + ktxTexture2_Destroy(prototype); + return KTX_INVALID_OPERATION; + } + } + + // Create intermediate storage to store decoded blocks. Not all blocks + // necessarily decode to 4x4x4 but this is enough to hold all possible + // combinations (at least for LDR - i.e., not for BC6H formats). + const ktx_size_t rgba_pitch = BCN_BLOCK_SIZE * BC1_OUTPUT_NCHANNELS; + ktx_uint8_t rgba[BCN_BLOCK_SIZE * rgba_pitch]; /* 64 bytes */ + + for (uint32_t levelIndex = 0; levelIndex < This->numLevels; ++levelIndex) { + const uint32_t imageWidth = std::max(This->baseWidth >> levelIndex, 1u); + const uint32_t imageHeight = std::max(This->baseHeight >> levelIndex, 1u); + const uint32_t imageDepths = std::max(This->baseDepth >> levelIndex, 1u); + + for (uint32_t layerIndex = 0; layerIndex < This->numLayers; ++layerIndex) { + for (uint32_t faceIndex = 0; faceIndex < This->numFaces; ++faceIndex) { + for (uint32_t depthSliceIndex = 0; depthSliceIndex < imageDepths; + ++depthSliceIndex) { + ktx_size_t imageOffsetIn; + ktx_size_t imageOffsetOut; + + // TODO: are we sure these can't fail? (i.e., return != KTX_SUCCESS) + ktxTexture2_GetImageOffset(This, levelIndex, layerIndex, + faceIndex + depthSliceIndex, &imageOffsetIn); + ktxTexture2_GetImageOffset(prototype, levelIndex, layerIndex, + faceIndex + depthSliceIndex, &imageOffsetOut); + + const ktx_uint8_t* imageDataIn = This->pData + imageOffsetIn; + ktx_uint8_t* imageDataOut = prototype->pData + imageOffsetOut; + + // Probably very little benefit of using multithreading here + + const ktx_size_t dst_pitch = imageWidth * nchannels; + const ktx_uint8_t* src_blocks = imageDataIn; + + for (size_t y{0}; y < imageHeight; y += BCN_BLOCK_SIZE) { + for (size_t x{0}; x < imageWidth; x += BCN_BLOCK_SIZE) { + switch (colorModel) { + case KHR_DF_MODEL_BC1A: + // BC1: 8 bytes -> 4 x 4 x 4 = 64 bytes + // TODO: BC1 with punchthrough alpha should already be supported, + // right? (since we already write to 4x4x4 block and then to an RGBA + // texture)? + rgbcx::unpack_bc1(src_blocks, rgba, true); + src_blocks += BC1_BLOCK_SIZE; + break; + + case KHR_DF_MODEL_BC3: + // BC3: 16 bytes -> 4 x 4 x 4 = 64 bytes + rgbcx::unpack_bc3(src_blocks, rgba); + src_blocks += BC3_BLOCK_SIZE; + break; + + case KHR_DF_MODEL_BC4: + // BC4: 8 bytes -> 4 x 4 x 1 = 16 bytes + rgbcx::unpack_bc4(src_blocks, rgba, + /* stride */ BC4_OUTPUT_NCHANNELS); + src_blocks += BC4_BLOCK_SIZE; + break; + + case KHR_DF_MODEL_BC5: + // BC5: 16 bytes -> 4 x 4 x 2 = 32 bytes + rgbcx::unpack_bc5(src_blocks, rgba, 0, 1, + /* stride */ BC5_OUTPUT_NCHANNELS); + src_blocks += BC5_BLOCK_SIZE; + break; + + case KHR_DF_MODEL_BC7: + // BC7: 16 bytes -> 4 x 4 x 4 = 64 bytes + bc7decomp::unpack_bc7( + src_blocks, reinterpret_cast(rgba)); + src_blocks += BC7_BLOCK_SIZE; + break; + + default: + break; // should never occur + } + + // now we copy the decoded block into the actual + // texture image while taking into consideration + // that dimenions may not be a multiple of 4. + const ktx_uint8_t* pSrc = rgba; + ktx_uint8_t* pDst = imageDataOut + y * dst_pitch + nchannels * x; + ktx_size_t cols = fmin(BCN_BLOCK_SIZE, imageWidth - x); + for (ktx_size_t py{0}; py < BCN_BLOCK_SIZE && y + py < imageHeight; + ++py) { + memcpy(pDst, pSrc, cols * nchannels); + pSrc += rgba_pitch; + pDst += dst_pitch; + } + } // x blocks + } // y blocks + } // depth slices + } // faces + } // layers + } + + if (result == KTX_SUCCESS) { + // Fix up the current texture + DECLARE_PROTECTED_EX(thisPrtctd, This); + DECLARE_PRIVATE_EX(protoPriv, prototype); + DECLARE_PROTECTED_EX(protoPrtctd, prototype); + memcpy(&thisPrtctd._formatSize, &protoPrtctd._formatSize, sizeof(ktxFormatSize)); + This->vkFormat = decompressedVkFormat; + This->isCompressed = prototype->isCompressed; + This->supercompressionScheme = KTX_SS_NONE; + priv._requiredLevelAlignment = protoPriv._requiredLevelAlignment; + + // Copy the levelIndex from the prototype to This. + memcpy(priv._levelIndex, protoPriv._levelIndex, + This->numLevels * sizeof(ktxLevelIndexEntry)); + + // Move the DFD and data from the prototype to This. + free(This->pDfd); + This->pDfd = prototype->pDfd; + prototype->pDfd = 0; + free(This->pData); + This->pData = prototype->pData; + This->dataSize = prototype->dataSize; + prototype->pData = 0; + prototype->dataSize = 0; + + // Free SGD data + This->_private->_sgdByteLength = 0; + if (This->_private->_supercompressionGlobalData) { + free(This->_private->_supercompressionGlobalData); + This->_private->_supercompressionGlobalData = NULL; + } + } + ktxTexture2_Destroy(prototype); + return result; +} + +//************************************************************************ +//* Encoder functions * +//************************************************************************ + +/** + * @memberof ktxTexture2 + * @ingroup writer + * @~English + * @brief Encode and compress a ktx texture with uncompressed images to provided + * BCn format. Currently, only BC1, BC3, BC4, BC5, and BC7 target formats + * are supported. + * + * The images are encoded to BCn block-compressed format. The encoded images + * replace the original images and the texture's fields including the DFD are + * modified to reflect the new state. + * + * Such textures can be directly uploaded to a GPU via a graphics API. + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * @param[in] params pointer to BCn params object. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_OPERATION + * The texture's images are supercompressed. + * @exception KTX_INVALID_OPERATION + * The texture's images are already in a block + * compressed format (i.e., This->isCompressed is + * true). + * @exception KTX_INVALID_OPERATION + * The texture image's format is a packed format + * (e.g. RGB565). + * @exception KTX_INVALID_OPERATION + * The texture image format's component size is not + * 8-bits. + * @exception KTX_INVALID_OPERATION + * The texture's images are 1D. Only 2D images can + * be block compressed. + * @exception KTX_INVALID_OPERATION + * Transfer function of @c This is not sRGB or + * Linear. + * @exception KTX_INVALID_OPERATION + * @c params->mode is HDR but transfer function + * of @c This is sRGB. + * @exception KTX_INVALID_OPERATION + * This->generateMipmaps is set. + * @exception KTX_OUT_OF_MEMORY Not enough memory to carry out compression. + * @exception KTX_UNSUPPORTED_FEATURE + * @c params->mode is HDR mode which is not + * yet implemented. + */ +extern "C" KTX_error_code +ktxTexture2_CompressBCnEx(ktxTexture2* This, ktxBCnParams* params) { + assert(This->classId == ktxTexture2_c && "Only support ktx2 BCn."); + + ktx_error_code_e result; + + if (!params) return KTX_INVALID_VALUE; + + if (params->structSize != sizeof(struct ktxBCnParams)) return KTX_INVALID_VALUE; + + // TODO: why? + if (This->generateMipmaps) return KTX_INVALID_OPERATION; + + if (This->supercompressionScheme != KTX_SS_NONE) + return KTX_INVALID_OPERATION; // Can't apply multiple schemes. + + if (This->isCompressed) + return KTX_INVALID_OPERATION; // Only non-block compressed formats + // can be encoded into a BCn format. + + if (This->_protected->_formatSize.flags & KTX_FORMAT_SIZE_PACKED_BIT) + return KTX_INVALID_OPERATION; + + // Basic descriptor block begins after the total size field. + const uint32_t* BDB = This->pDfd + 1; + ktx_uint8_t alphaMode = KHR_DFDVAL(BDB, FLAGS); + size_t nchannels; + VkFormat compressedVkFormat; + bc7enc_compress_block_params bc7_cmp_params; + + switch (params->bcn) { + case KHR_DF_MODEL_BC1A: + // Currently we can only encode RGBA uncompressed textures into BC1 + // (TODO: I think this makes sense, if we have an R8 channel then using + // BC1 makes no sense in the first place). + switch (This->vkFormat) { + case VK_FORMAT_R8G8B8_UNORM: + compressedVkFormat = VK_FORMAT_BC1_RGB_UNORM_BLOCK; + break; + case VK_FORMAT_R8G8B8_SRGB: + compressedVkFormat = VK_FORMAT_BC1_RGB_SRGB_BLOCK; + break; + case VK_FORMAT_R8G8B8A8_UNORM: + compressedVkFormat = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + break; + case VK_FORMAT_R8G8B8A8_SRGB: + compressedVkFormat = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; + break; + default: + return KTX_INVALID_OPERATION; // Not a valid decompressed vkformat for BC1 + } + nchannels = BC1_OUTPUT_NCHANNELS; + rgbcx::init(static_cast(params->bc1ApproxMode)); + break; + + case KHR_DF_MODEL_BC3: + switch (This->vkFormat) { + case VK_FORMAT_R8G8B8A8_UNORM: + compressedVkFormat = VK_FORMAT_BC3_UNORM_BLOCK; + break; + case VK_FORMAT_R8G8B8A8_SRGB: + compressedVkFormat = VK_FORMAT_BC3_SRGB_BLOCK; + break; + default: + return KTX_INVALID_OPERATION; // Not a valid decompressed vkformat for BC3 + } + nchannels = BC3_OUTPUT_NCHANNELS; + rgbcx::init(static_cast(params->bc1ApproxMode)); + break; + + case KHR_DF_MODEL_BC4: + switch (This->vkFormat) { + case VK_FORMAT_R8_UNORM: + compressedVkFormat = VK_FORMAT_BC4_UNORM_BLOCK; + break; + case VK_FORMAT_R8_SNORM: + compressedVkFormat = VK_FORMAT_BC4_SNORM_BLOCK; + break; + default: + return KTX_INVALID_OPERATION; // Not a valid decompressed vkformat for BC4 + } + nchannels = BC4_OUTPUT_NCHANNELS; + rgbcx::init(static_cast(params->bc1ApproxMode)); + break; + + case KHR_DF_MODEL_BC5: + switch (This->vkFormat) { + case VK_FORMAT_R8G8_UNORM: + compressedVkFormat = VK_FORMAT_BC5_UNORM_BLOCK; + break; + case VK_FORMAT_R8G8_SNORM: + compressedVkFormat = VK_FORMAT_BC5_SNORM_BLOCK; + break; + default: + return KTX_INVALID_OPERATION; // Not a valid decompressed vkformat for BC5 + } + nchannels = BC5_OUTPUT_NCHANNELS; + rgbcx::init(static_cast(params->bc1ApproxMode)); + break; + + case KHR_DF_MODEL_BC7: + switch (This->vkFormat) { + case VK_FORMAT_R8G8B8A8_UNORM: + compressedVkFormat = VK_FORMAT_BC7_UNORM_BLOCK; + break; + case VK_FORMAT_R8G8B8A8_SRGB: + compressedVkFormat = VK_FORMAT_BC7_SRGB_BLOCK; + break; + default: + return KTX_INVALID_OPERATION; // Not a valid decompressed vkformat for BC7 + } + nchannels = BC7_OUTPUT_NCHANNELS; + // MUST be called before calling bc7enc_compress_block() (or you'll get artifacts). + bc7enc_compress_block_init(); + bc7enc_compress_block_params_init(&bc7_cmp_params); + break; + + default: + return KTX_INVALID_VALUE; // Provided color model is not BCn + } + + if (This->pData == NULL) { + result = ktxTexture2_LoadImageData((ktxTexture2*)This, nullptr, 0); + if (result != KTX_SUCCESS) return result; + } + + ktx_uint32_t threadCount = params->threadCount; + if (threadCount < 1) threadCount = 1; + + // This->numLevels = 0 not allowed for block compressed formats + // But just in case make sure it's not zero + This->numLevels = MAX(1, This->numLevels); + + // Create a prototype texture to use for calculating sizes in the target + // format and, as useful side effects, provide us with a properly sized + // data allocation and the DFD for the target format. + ktxTextureCreateInfo createInfo; + createInfo.glInternalformat = 0; + createInfo.vkFormat = compressedVkFormat; + createInfo.baseWidth = This->baseWidth; + createInfo.baseHeight = This->baseHeight; + createInfo.baseDepth = This->baseDepth; + createInfo.generateMipmaps = This->generateMipmaps; + createInfo.isArray = This->isArray; + createInfo.numDimensions = This->numDimensions; + createInfo.numFaces = This->numFaces; + createInfo.numLayers = This->numLayers; + createInfo.numLevels = This->numLevels; + createInfo.pDfd = nullptr; + + ktxTexture2* prototype; + result = ktxTexture2_Create(&createInfo, KTX_TEXTURE_CREATE_ALLOC_STORAGE, &prototype); + + if (result != KTX_SUCCESS) { + assert(result == KTX_OUT_OF_MEMORY && "Out of memory allocating texture."); + return result; + } + + assert(prototype->dataSize && "Prototype texture size not initialized.\n"); + + if (!prototype->pData) { + return KTX_OUT_OF_MEMORY; + } + + // This is where the decoded LDR BCn block is saved. + const size_t pixels_pitch{BCN_BLOCK_SIZE * 4}; // 4 x 4 + uint8_t pPixels[BCN_BLOCK_SIZE * pixels_pitch]; // 4 x 4 x 4 + +#if 0 + uint16_t pPixelsHdr [BCN_BLOCK_SIZE * BCN_BLOCK_SIZE * 4]; // 4 x 4 x 4 +#endif + + // TODO: why in reverse? + for (int32_t level = This->numLevels - 1; level >= 0; --level) { + uint32_t width = MAX(1, This->baseWidth >> level); + uint32_t height = MAX(1, This->baseHeight >> level); + uint32_t depth = MAX(1, This->baseDepth >> level); + ktx_size_t levelImageSizeIn = 0; + ktx_size_t levelImageSizeOut = 0; + const ktx_uint32_t levelImages = This->numLayers * This->numFaces * depth; + + levelImageSizeIn = + ktxTexture_calcImageSize(ktxTexture(This), level, KTX_FORMAT_VERSION_TWO); + levelImageSizeOut = + ktxTexture_calcImageSize(ktxTexture(prototype), level, KTX_FORMAT_VERSION_TWO); + + const size_t levelDataOffsetIn = ktxTexture2_levelDataOffset(This, level); + + // Points to start of raw source/destination compressed blocks image + // data within this miplevl (e.g., for 3D texture and for miplevel 0, + // this initially points to start of first depth slice image data, then + // this gets update to point to next slice and so on until we exit this + // loop and this gets initialized again to point to start of depth slice + // 0 withing next mip level) + const ktx_uint8_t* pSrcLevelImage = This->pData + levelDataOffsetIn; + + // points to start of destination image within this miplevel + ktx_uint8_t* pDstLevelImage = prototype->pData /* + levelDataOffset */; + const size_t nbrBlocksX = (width + BCN_BLOCK_SIZE - 1) / BCN_BLOCK_SIZE; + + // TODO: add and profile multithreading (contrary to decoding, encoding + // BC7 takes singnificantly much longer). + + for (uint32_t image = 0; image < levelImages; image++) { + // Row-major loop over blocks + for (size_t y{0}; y < height; y += BCN_BLOCK_SIZE) { + for (size_t x{0}; x < width; x += BCN_BLOCK_SIZE) { + // Extract/Copy source block + for (size_t i{0}; i < BCN_BLOCK_SIZE; ++i) { + // copy 4 pixels (32bpp) to pPixels + memcpy(pPixels + i * pixels_pitch, + pSrcLevelImage + (y + i) * width * nchannels + x * nchannels, + pixels_pitch); + } + + const auto xBlock = x / BCN_BLOCK_SIZE; + const auto yBlock = y / BCN_BLOCK_SIZE; + + switch (params->bcn) { + case KHR_DF_MODEL_BC1A: + // BC1: 4 x 4 x 4 = 64 bytes -> 8 bytes + rgbcx::encode_bc1( + params->bc1CompressionQuality, + pDstLevelImage + (yBlock * nbrBlocksX + xBlock) * BC1_BLOCK_SIZE, + reinterpret_cast(pPixels), true, false); + break; + + case KHR_DF_MODEL_BC3: + // BC3: 4 x 4 x 4 = 64 bytes -> 16 bytes + rgbcx::encode_bc3( + params->bc1CompressionQuality, + pDstLevelImage + (yBlock * nbrBlocksX + xBlock) * BC3_BLOCK_SIZE, + reinterpret_cast(pPixels)); + break; + + case KHR_DF_MODEL_BC4: + // BC4: 4 x 4 x 1 = 16 bytes -> 8 bytes + rgbcx::encode_bc4( + pDstLevelImage + (yBlock * nbrBlocksX + xBlock) * BC4_BLOCK_SIZE, + reinterpret_cast(pPixels), + /* stride */ BC4_OUTPUT_NCHANNELS); + break; + + case KHR_DF_MODEL_BC5: + // BC5: 4 x 4 x 2 = 32 bytes -> 16 bytes + rgbcx::encode_bc5( + pDstLevelImage + (yBlock * nbrBlocksX + xBlock) * BC5_BLOCK_SIZE, + reinterpret_cast(pPixels), 0, 1, + /* stride */ BC5_OUTPUT_NCHANNELS); + break; + + case KHR_DF_MODEL_BC7: + // BC7: 4 x 4 x 4 = 64 bytes -> 16 bytes + bc7enc_compress_block( + pDstLevelImage + (yBlock * nbrBlocksX + xBlock) * BC7_BLOCK_SIZE, + reinterpret_cast(pPixels), &bc7_cmp_params); + break; + + default: + return KTX_INVALID_VALUE; // should never occur + } + } // x blocks + } // y blocks + + pDstLevelImage += levelImageSizeOut; // next destination image within this miplevel + pSrcLevelImage += levelImageSizeIn; // next source image within this miplevel + } + } + + assert(KHR_DFDVAL(prototype->pDfd + 1, MODEL) == params->bcn && + "Invalid dfd generated for BCn image\n"); + // assert((transfer == KHR_DF_TRANSFER_SRGB + // ? KHR_DFDVAL(prototype->pDfd + 1, TRANSFER) == KHR_DF_TRANSFER_SRGB && + // KHR_DFDVAL(prototype->pDfd + 1, PRIMARIES) == KHR_DF_PRIMARIES_SRGB + // : true) && + // "Not a valid sRGB image\n"); + +// Fix up the current (This) texture +#undef DECLARE_PRIVATE +#undef DECLARE_PROTECTED +#define DECLARE_PRIVATE(n, t2) ktxTexture2_private& n = *(t2->_private) +#define DECLARE_PROTECTED(n, t2) ktxTexture_protected& n = *(t2->_protected) + + DECLARE_PROTECTED(thisPrtctd, This); + DECLARE_PRIVATE(protoPriv, prototype); + DECLARE_PROTECTED(protoPrtctd, prototype); + memcpy(&thisPrtctd._formatSize, &protoPrtctd._formatSize, sizeof(ktxFormatSize)); + This->vkFormat = prototype->vkFormat; + This->isCompressed = prototype->isCompressed; + This->supercompressionScheme = KTX_SS_NONE; + This->_private->_requiredLevelAlignment = protoPriv._requiredLevelAlignment; + + // Copy the levelIndex from the prototype to This. + memcpy(This->_private->_levelIndex, protoPriv._levelIndex, + This->numLevels * sizeof(ktxLevelIndexEntry)); + + // Move the DFD and data from the prototype to This. + free(This->pDfd); + This->pDfd = prototype->pDfd; + prototype->pDfd = 0; + free(This->pData); + This->pData = prototype->pData; + This->dataSize = prototype->dataSize; + prototype->pData = 0; + prototype->dataSize = 0; + + ktxTexture2_Destroy(prototype); + + KHR_DFDSETVAL(This->pDfd + 1, FLAGS, alphaMode); // Restore alphaMode flags + return KTX_SUCCESS; +} + +/** + * @memberof ktxTexture2 + * @ingroup writer + * @~English + * @brief Encode and compress a ktx texture with uncompressed images to astc. + * + * The images are either encoded to ASTC block-compressed format. The encoded images + * replace the original images and the texture's fields including the DFD are modified to reflect + the new + * state. + * + * Such textures can be directly uploaded to a GPU via a graphics API. + * + * @param[in] This pointer to the ktxTexture2 object of interest. + * @param[in] quality Compression quality, a value from 0 - 100. + Higher=higher quality/slower speed. + Lower=lower quality/faster speed. + Negative values for quality are considered > 100. + * + * @return KTX_SUCCESS on success, other KTX_* enum values on error. + * + * @exception KTX_INVALID_OPERATION + * The texture's images are supercompressed. + * @exception KTX_INVALID_OPERATION + * The texture's image are in a block compressed + * format. + * @exception KTX_INVALID_OPERATION + * The texture image's format is a packed format + * (e.g. RGB565). + * @exception KTX_INVALID_OPERATION + * The texture image format's component size is not 8-bits. + * @exception KTX_INVALID_OPERATION + * The texture's images are 1D. Only 2D images can + * be supercompressed. + * @exception KTX_OUT_OF_MEMORY Not enough memory to carry out supercompression. + */ +extern "C" KTX_error_code +ktxTexture2_CompressBcnEx(ktxTexture2*, ktxBCnParams) { + return KTX_INVALID_OPERATION; +} + +extern "C" KTX_error_code +ktxTexture2_CompressBcn(ktxTexture2*, ktx_uint32_t) { + return KTX_INVALID_OPERATION; +} diff --git a/lib/src/bcn_codec.h b/lib/src/bcn_codec.h new file mode 100644 index 0000000000..3ff3b20f60 --- /dev/null +++ b/lib/src/bcn_codec.h @@ -0,0 +1,29 @@ +/* -*- tab-width: 4; -*- */ +/* vi: set sw=2 ts=4 expandtab textwidth=70: */ + +/* + * Copyright 2019-2020 The Khronos Group Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BCN_CODEC_H_ +#define _BCN_CODEC_H_ + +#define BCN_BLOCK_SIZE 4 + +#define BC1_BLOCK_SIZE 8 +#define BC2_BLOCK_SIZE 16 +#define BC3_BLOCK_SIZE 16 +#define BC4_BLOCK_SIZE 8 +#define BC5_BLOCK_SIZE 16 +#define BC6H_BLOCK_SIZE 16 +#define BC7_BLOCK_SIZE 16 + +#define BC1_OUTPUT_NCHANNELS 4 +#define BC3_OUTPUT_NCHANNELS 4 +#define BC4_OUTPUT_NCHANNELS 1 +#define BC5_OUTPUT_NCHANNELS 2 +#define BC6H_OUTPUT_NCHANNELS 4 +#define BC7_OUTPUT_NCHANNELS 4 + +#endif diff --git a/tests/cts b/tests/cts index c8e3003317..82b5b1b9de 160000 --- a/tests/cts +++ b/tests/cts @@ -1 +1 @@ -Subproject commit c8e30033171b6c3bd69681796d8f2f6ae2d95322 +Subproject commit 82b5b1b9de29d6779f5b48b004f1a045360a48af diff --git a/tests/resources/ktx2/color_grid_bc1.ktx2 b/tests/resources/ktx2/color_grid_bc1.ktx2 new file mode 100644 index 0000000000..34998283f1 --- /dev/null +++ b/tests/resources/ktx2/color_grid_bc1.ktx2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:faffeeb7a27bd8459a9376be999e5d000f9cafaf7807e27b4111889aa62e60d6 +size 699520 diff --git a/tests/resources/ktx2/color_grid_bc3.ktx2 b/tests/resources/ktx2/color_grid_bc3.ktx2 new file mode 100644 index 0000000000..6090050824 --- /dev/null +++ b/tests/resources/ktx2/color_grid_bc3.ktx2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:40d3e9bea33e83c7c88b3d2b5b41959397b8b7bdc91e40962bd49a37e9dfb042 +size 1048816 diff --git a/tests/resources/ktx2/color_grid_bc4.ktx2 b/tests/resources/ktx2/color_grid_bc4.ktx2 new file mode 100644 index 0000000000..23ae66cf05 --- /dev/null +++ b/tests/resources/ktx2/color_grid_bc4.ktx2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9a067f0720e15c8d7f348c2868eb2f3d49fe9193626cdb4aca746a427d405f0 +size 524504 diff --git a/tests/resources/ktx2/color_grid_bc5.ktx2 b/tests/resources/ktx2/color_grid_bc5.ktx2 new file mode 100644 index 0000000000..8da322f87f --- /dev/null +++ b/tests/resources/ktx2/color_grid_bc5.ktx2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5362589abf538de1f0502ac319d3f7361e9b4470cecedecd595534053607d1e8 +size 1048816 diff --git a/tests/resources/ktx2/color_grid_bc7.ktx2 b/tests/resources/ktx2/color_grid_bc7.ktx2 new file mode 100644 index 0000000000..a451176a85 --- /dev/null +++ b/tests/resources/ktx2/color_grid_bc7.ktx2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9219e847f2a4c0438e5420b8085937aea5511181d2fcc8966d5a2d7700b99cac +size 1048800 diff --git a/tests/texturetests/texturetests.cc b/tests/texturetests/texturetests.cc index 933aef9c0a..73e13f28f2 100644 --- a/tests/texturetests/texturetests.cc +++ b/tests/texturetests/texturetests.cc @@ -3257,8 +3257,305 @@ TEST_F(ktxTexture2AstcDecodeTestBase, Decode_astc_8x8_unorm_array_7) { runTest(u8"astc_8x8_unorm_array_7.ktx2"); } -} // namespace +//------------------------------------------------------------ +// Template for base fixture for BCn encode and decode tests. +//------------------------------------------------------------ + +template +class ktxTexture2BCnEncodeDecodeTestBase + : public ktxTexture2TestBase { + protected: + using ktxTextureTestBase::helper; + using ktxTextureTestBase::ktxMemFile; + using ktxTextureTestBase::ktxMemFileLen; + + public: + void runTest(khr_df_model_e bcn) { + ktxTexture2* texture; + KTX_error_code result; + auto tmpDir = fs::temp_directory_path(); + + result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen, + KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &texture); + ASSERT_TRUE(result == KTX_SUCCESS); + ASSERT_TRUE(texture != NULL) + << "ktxTexture_CreateFromMemory failed: " << ktxErrorString(result); + ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded"; + + ktx_uint32_t compressedFormat; + ktx_uint32_t expectedDecompressedFormat; + + const bool isSRGB = KHR_DFDVAL(texture->pDfd + 1, TRANSFER) == KHR_DF_TRANSFER_SRGB; + + fs::path ktxdiffOut = tmpDir / "ktxdiffOut.txt"; + fs::path original; + fs::path decoded; + + switch (bcn) { + case KHR_DF_MODEL_BC1A: + original = tmpDir / "CompressToBC1ThenDecode_original.ktx2"; + decoded = tmpDir / "CompressToBC1ThenDecode_decoded.ktx2"; + if (isSRGB) { + compressedFormat = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; + expectedDecompressedFormat = VK_FORMAT_R8G8B8A8_SRGB; + } else { + compressedFormat = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + expectedDecompressedFormat = VK_FORMAT_R8G8B8A8_UNORM; + } + break; + + case KHR_DF_MODEL_BC3: + original = tmpDir / "CompressToBC3ThenDecode_original.ktx2"; + decoded = tmpDir / "CompressToBC3ThenDecode_decoded.ktx2"; + if (isSRGB) { + compressedFormat = VK_FORMAT_BC3_SRGB_BLOCK; + expectedDecompressedFormat = VK_FORMAT_R8G8B8A8_SRGB; + } else { + compressedFormat = VK_FORMAT_BC3_UNORM_BLOCK; + expectedDecompressedFormat = VK_FORMAT_R8G8B8A8_UNORM; + } + break; + + case KHR_DF_MODEL_BC4: + original = tmpDir / "CompressToBC4ThenDecode_original.ktx2"; + decoded = tmpDir / "CompressToBC4ThenDecode_decoded.ktx2"; + ASSERT_FALSE(isSRGB); // should never occur + if (texture->vkFormat == VK_FORMAT_R8_UNORM) { + compressedFormat = VK_FORMAT_BC4_UNORM_BLOCK; + expectedDecompressedFormat = VK_FORMAT_R8_UNORM; + } else { /* this is tested below */ + compressedFormat = VK_FORMAT_BC4_SNORM_BLOCK; + expectedDecompressedFormat = VK_FORMAT_R8_SNORM; + } + break; + + case KHR_DF_MODEL_BC5: + original = tmpDir / "CompressToBC5ThenDecode_original.ktx2"; + decoded = tmpDir / "CompressToBC5ThenDecode_decoded.ktx2"; + ASSERT_FALSE(isSRGB); // should never occur + if (texture->vkFormat == VK_FORMAT_R8G8_UNORM) { + compressedFormat = VK_FORMAT_BC5_UNORM_BLOCK; + expectedDecompressedFormat = VK_FORMAT_R8G8_UNORM; + } else { /* this is tested below */ + compressedFormat = VK_FORMAT_BC5_SNORM_BLOCK; + expectedDecompressedFormat = VK_FORMAT_R8G8_SNORM; + } + break; + + case KHR_DF_MODEL_BC7: + original = tmpDir / "CompressToBC7ThenDecode_original.ktx2"; + decoded = tmpDir / "CompressToBC7ThenDecode_decoded.ktx2"; + if (isSRGB) { + compressedFormat = VK_FORMAT_BC7_SRGB_BLOCK; + expectedDecompressedFormat = VK_FORMAT_R8G8B8A8_SRGB; + } else { + compressedFormat = VK_FORMAT_BC7_UNORM_BLOCK; + expectedDecompressedFormat = VK_FORMAT_R8G8B8A8_UNORM; + } + break; + + default: + return; + } + + ASSERT_EQ(texture->vkFormat, expectedDecompressedFormat); + + if (ktxMemFile == NULL) { + return; + } + + result = ktxTexture2_WriteToNamedFile(texture, original.string().c_str()); + ASSERT_TRUE(result == KTX_SUCCESS); + + auto depth = texture->baseDepth; + auto height = texture->baseHeight; + auto width = texture->baseWidth; + auto dataSize = texture->dataSize; + + ASSERT_TRUE(depth == 1); + + ktxBCnParams params; + params.structSize = sizeof(params); + params.threadCount = 1; + params.bcn = bcn; + params.bc1CompressionQuality = KTX_PACK_BC1_QUALITY_LEVEL_MEDIUM; + result = ktxTexture2_CompressBCnEx(texture, ¶ms); + + EXPECT_EQ(result, KTX_SUCCESS); + EXPECT_TRUE(texture->vkFormat == compressedFormat); + + uint32_t* pBdb = texture->pDfd + 1; + if (isSRGB) { + EXPECT_TRUE(KHR_DFDVAL(pBdb, TRANSFER) == KHR_DF_TRANSFER_SRGB); + } + khr_df_model_e model = static_cast(KHR_DFDVAL(pBdb, MODEL)); + EXPECT_EQ(model, bcn); + EXPECT_EQ(texture->supercompressionScheme, KTX_SS_NONE); + EXPECT_TRUE(texture->_private->_supercompressionGlobalData == (ktx_uint8_t*)0); + EXPECT_EQ(texture->numLevels, helper.numLevels); + EXPECT_EQ(texture->baseDepth, depth); + EXPECT_EQ(texture->baseHeight, height); + EXPECT_EQ(texture->baseWidth, width); + EXPECT_LT(texture->dataSize, dataSize); + + result = ktxTexture2_DecodeBCn(texture); + ASSERT_EQ(result, KTX_SUCCESS) << format("ktxTexture2_DecodeBCn failed with error code: {}", ktxErrorString(result)); + EXPECT_EQ(texture->vkFormat, expectedDecompressedFormat); + model = static_cast(KHR_DFDVAL(texture->pDfd + 1, MODEL)); + EXPECT_EQ(model, KHR_DF_MODEL_RGBSDA); + EXPECT_EQ(depth, texture->baseDepth); + result = ktxTexture2_WriteToNamedFile(texture, decoded.string().c_str()); + EXPECT_EQ(texture->baseHeight, height); + EXPECT_EQ(texture->baseWidth, width); + if (texture) { + ktxTexture_Destroy(ktxTexture(texture)); + fs::remove(original); + fs::remove(decoded); + fs::remove(ktxdiffOut); + } + } +}; +// Test fixtures for BCn encode and decode tests. + +class ktxTexture2_BCnEncodeDecodeTestRGBA8_SRGB + : public ktxTexture2BCnEncodeDecodeTestBase {}; +class ktxTexture2_BC4EncodeDecodeTestR8_UNORM + : public ktxTexture2BCnEncodeDecodeTestBase {}; +class ktxTexture2_BC5EncodeDecodeTestR8G8_UNORM + : public ktxTexture2BCnEncodeDecodeTestBase {}; + +//////////////////////////////////////////// +// BCn encode & decode tests +/////////////////////////////////////////// + +TEST_F(ktxTexture2_BCnEncodeDecodeTestRGBA8_SRGB, CompressToBC1ThenDecode) { runTest(KHR_DF_MODEL_BC1A); } +TEST_F(ktxTexture2_BCnEncodeDecodeTestRGBA8_SRGB, CompressToBC3ThenDecode) { runTest(KHR_DF_MODEL_BC3); } +TEST_F(ktxTexture2_BC4EncodeDecodeTestR8_UNORM, CompressToBC4ThenDecode) { runTest(KHR_DF_MODEL_BC4); } +TEST_F(ktxTexture2_BC5EncodeDecodeTestR8G8_UNORM, CompressToBC5ThenDecode) { runTest(KHR_DF_MODEL_BC5); } +TEST_F(ktxTexture2_BCnEncodeDecodeTestRGBA8_SRGB, CompressToBC7ThenDecode) { runTest(KHR_DF_MODEL_BC7); } +// TODO: BCn RDO tests (also some tests with some parameters) + +//------------------------------------------------- +// Template for base fixture for BCn decode tests. +//------------------------------------------------- + +class ktxTexture2BCnDecodeTestBase : public ::testing::Test { + public: + void runTest(const std::u8string& bcnFileName) { + ktxTexture2* texture; + KTX_error_code result; + ktx_uint32_t expectedDecompressedFormat; + fs::path bcnPath = ktx2Path; + bcnPath.replace_filename(bcnFileName); + + result = ktxTexture2_CreateFromNamedFile( + reinterpret_cast(bcnPath.u8string().c_str()), + KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &texture); + + ASSERT_EQ(result, KTX_SUCCESS) + << format("ktxTexture2_CreateFromNamedFile \"{}\" failed: {}", + from_u8string(bcnPath.u8string()), ktxErrorString(result)); + ASSERT_NE(texture, nullptr); + + // Check the input file is valid BCn (TODO) + khr_df_model_e colormodel = ktxTexture2_GetColorModel_e(texture); + ASSERT_TRUE(colormodel == KHR_DF_MODEL_BC1A || colormodel == KHR_DF_MODEL_BC3 || + colormodel == KHR_DF_MODEL_BC4 || colormodel == KHR_DF_MODEL_BC5 || + colormodel == KHR_DF_MODEL_BC7) + << format( + "Color model of \"{}\" {} is not a BC1, BC3, BC4, BC5, or BC7 encoded ktx test file", + from_u8string(bcnPath.u8string()), dfdToStringColorModel(colormodel)); + + switch (texture->vkFormat) { + case VK_FORMAT_BC1_RGB_UNORM_BLOCK: + case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: + case VK_FORMAT_BC3_UNORM_BLOCK: + case VK_FORMAT_BC7_UNORM_BLOCK: + expectedDecompressedFormat = VK_FORMAT_R8G8B8A8_UNORM; + break; + + case VK_FORMAT_BC1_RGB_SRGB_BLOCK: + case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: + case VK_FORMAT_BC3_SRGB_BLOCK: + case VK_FORMAT_BC7_SRGB_BLOCK: + expectedDecompressedFormat = VK_FORMAT_R8G8B8A8_SRGB; + break; + + case VK_FORMAT_BC4_UNORM_BLOCK: + expectedDecompressedFormat = VK_FORMAT_R8_UNORM; + break; + + case VK_FORMAT_BC4_SNORM_BLOCK: + expectedDecompressedFormat = VK_FORMAT_R8_SNORM; + break; + + case VK_FORMAT_BC5_UNORM_BLOCK: + expectedDecompressedFormat = VK_FORMAT_R8G8_UNORM; + break; + + case VK_FORMAT_BC5_SNORM_BLOCK: + expectedDecompressedFormat = VK_FORMAT_R8G8_SNORM; + break; + + default: + ASSERT_TRUE(false) << + format("VkFormat {} is not of a supported BCn block compression format.", texture->vkFormat); + break; // should never occur because of colormodel check above + } + + ASSERT_TRUE(texture->isCompressed); + ASSERT_FALSE(ktxTexture2_NeedsTranscoding(texture)); + ASSERT_TRUE(texture->pDfd != nullptr); + + auto height = texture->baseHeight; + auto width = texture->baseWidth; + auto depth = texture->baseDepth; + ASSERT_TRUE(depth == 1); + auto numLayers = texture->numLayers; + auto isArray = texture->isArray; + auto isHdr = ktxTexture2_IsHDR(texture); + auto isPremultipliedAlpha = ktxTexture2_GetPremultipliedAlpha(texture); + + result = ktxTexture2_DecodeBCn(texture); + + ASSERT_EQ(result, KTX_SUCCESS) + << format("ktxTexture2_DecodeBCn failed: {}", ktxErrorString(result)); + // Get the pointer to the updated DFD + ASSERT_FALSE(ktxTexture2_NeedsTranscoding(texture)); + ASSERT_FALSE(texture->isCompressed); + ASSERT_TRUE(texture->pDfd != nullptr); + uint32_t* pBdb = texture->pDfd + 1; + EXPECT_EQ(texture->vkFormat, expectedDecompressedFormat); + khr_df_model_e model = static_cast(KHR_DFDVAL(pBdb, MODEL)); + EXPECT_EQ(model, KHR_DF_MODEL_RGBSDA); + EXPECT_EQ(height, texture->baseHeight); + EXPECT_EQ(width, texture->baseWidth); + EXPECT_EQ(depth, texture->baseDepth); + EXPECT_EQ(numLayers, texture->numLayers); + EXPECT_EQ(isArray, texture->isArray); + EXPECT_EQ(isHdr, ktxTexture2_IsHDR(texture)); + EXPECT_EQ(isPremultipliedAlpha, ktxTexture2_GetPremultipliedAlpha(texture)); + + if (texture) { + ktxTexture2_Destroy(texture); + } + } +}; + +// Test fixtures for BCn decode tests. + +//////////////////////////////////////////// +// BCn decode tests +/////////////////////////////////////////// + +TEST_F(ktxTexture2BCnDecodeTestBase, Decode_color_grid_bc1) { runTest(u8"color_grid_bc1.ktx2"); } +TEST_F(ktxTexture2BCnDecodeTestBase, Decode_color_grid_bc3) { runTest(u8"color_grid_bc3.ktx2"); } +TEST_F(ktxTexture2BCnDecodeTestBase, Decode_color_grid_bc4) { runTest(u8"color_grid_bc4.ktx2"); } +TEST_F(ktxTexture2BCnDecodeTestBase, Decode_color_grid_bc5) { runTest(u8"color_grid_bc5.ktx2"); } +TEST_F(ktxTexture2BCnDecodeTestBase, Decode_color_grid_bc7) { runTest(u8"color_grid_bc7.ktx2"); } + +} // namespace GTEST_API_ int main(int argc, char* argv[]) { testing::InitGoogleTest(&argc, argv); diff --git a/tools/ktx/command_create.cpp b/tools/ktx/command_create.cpp index 3d7a502b31..a58d8aff31 100644 --- a/tools/ktx/command_create.cpp +++ b/tools/ktx/command_create.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "command.h" +#include "encode_utils_bcn.h" #include "encode_utils_common.h" #include "platform_utils.h" #include "metrics_utils.h" @@ -151,7 +152,7 @@ struct OptionsCreate { "\n R16G16B16_SFLOAT" "\n R16G16B16A16_SFLOAT" "\nIf the format is an ASTC format the ASTC encoder specific options become valid," - " otherwise they are ignored." + " otherwise they are ignored. Likewise for a BCn format." "\nThe format will be used to verify and load all input files into a texture before encoding." " Case insensitive. Required.", cxxopts::value(), "") (k1D, "Create a 1D texture. If not set the texture will be a 2D or 3D texture.") @@ -580,6 +581,16 @@ struct OptionsCreate { VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_FORMAT_A8B8G8R8_SRGB_PACK32, + VK_FORMAT_BC1_RGB_UNORM_BLOCK, + VK_FORMAT_BC1_RGB_SRGB_BLOCK, + VK_FORMAT_BC1_RGBA_UNORM_BLOCK, + VK_FORMAT_BC1_RGBA_SRGB_BLOCK, + VK_FORMAT_BC3_UNORM_BLOCK, + VK_FORMAT_BC3_SRGB_BLOCK, + VK_FORMAT_BC4_UNORM_BLOCK, + VK_FORMAT_BC5_UNORM_BLOCK, + VK_FORMAT_BC7_UNORM_BLOCK, + VK_FORMAT_BC7_SRGB_BLOCK, VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_ASTC_4x4_SRGB_BLOCK, VK_FORMAT_ASTC_5x4_UNORM_BLOCK, @@ -1142,6 +1153,7 @@ Create a KTX2 file from various input files. encoder has been selected. Common encoder options become valid when an encoder they apply to has been selected. Otherwise they are ignored. @snippet{doc} ktx/encode_utils_astc.h command options_encode_astc + @snippet{doc} ktx/encode_utils_bcn.h command options_encode_bcn @snippet{doc} ktx/encode_utils_basis.h command options_encode_basis @snippet{doc} ktx/encode_utils_common.h command options_encode_common @snippet{doc} ktx/metrics_utils.h command options_metrics @@ -1242,7 +1254,7 @@ Transfer function handling proceeds as follows: */ class CommandCreate : public Command { private: - Combine, OptionsEncodeCommon, OptionsMetrics, OptionsDeflate, OptionsMultiInSingleOut, OptionsGeneric> options; + Combine, OptionsEncodeCommon, OptionsMetrics, OptionsDeflate, OptionsMultiInSingleOut, OptionsGeneric> options; uint32_t targetChannelCount = 0; // Derived from VkFormat @@ -1263,6 +1275,7 @@ class CommandCreate : public Command { void executeCreate(); void encodeBasis(KTXTexture2& texture, OptionsEncodeBasis& opts); void encodeASTC(KTXTexture2& texture, OptionsEncodeASTC& opts); + void encodeBCn(KTXTexture2& texture, OptionsEncodeBCn& opts); void compress(KTXTexture2& texture, const OptionsDeflate& opts); private: @@ -1289,6 +1302,8 @@ class CommandCreate : public Command { void checkNumInputImages(); void checkSpecsMatch(const ImageInput& current, const ImageSpec& firstSpec); + + VkFormat decompressedBCnFormat(VkFormat format) const; }; // ------------------------------------------------------------------------------------------------- @@ -1345,14 +1360,25 @@ void CommandCreate::processOptions(cxxopts::Options& opts, cxxopts::ParseResult& checkNumInputImages(); } - if (!isFormatAstc(options.vkFormat)) { + const bool isASTC = isFormatAstc(options.vkFormat); + const bool isBCn = isFormatBCn(options.vkFormat); + + if (!isASTC && !isBCn) { for (const char* astcOption : OptionsEncodeASTC::kAstcOptions) if (args[astcOption].count()) fatal_usage("--{} can only be used with ASTC formats.", astcOption); - } else { + for (const char* bcnOption : OptionsEncodeBCn::kBCnOptions) + if (args[bcnOption].count()) + fatal_usage("--{} can only be used with BCn formats.", bcnOption); + } else if (isASTC) { fillOptionsCodecAstc(options); if (options.OptionsEncodeCommon::noSSE) fatal_usage("--{} is not allowed with ASTC encode", OptionsEncodeCommon::kNoSse); + } else /* isBCn */ { + // TODO: I have just copied this from ASTC above - need to verify this + fillOptionsCodecBCn(options); + if (options.OptionsEncodeCommon::noSSE) + fatal_usage("--{} is not allowed with BCn encode", OptionsEncodeCommon::kNoSse); } if (options.selectedCodec == BasisCodec::BasisLZ) { @@ -1415,8 +1441,7 @@ void CommandCreate::processOptions(cxxopts::Options& opts, cxxopts::ParseResult& options.selectedCodec == BasisCodec::UASTC_LDR_4x4 || options.selectedCodec == BasisCodec::UASTC_HDR_4x4 || options.selectedCodec == BasisCodec::UASTC_HDR_6x6i; - const auto astcCodec = isFormatAstc(options.vkFormat); - const auto canCompare = basisCodec || astcCodec; + const auto canCompare = basisCodec || isASTC || isBCn; if (basisCodec) fillOptionsCodecBasis(options); @@ -1426,7 +1451,7 @@ void CommandCreate::processOptions(cxxopts::Options& opts, cxxopts::ParseResult& if (options.compare_psnr && !canCompare) fatal_usage("--compare-psnr can only be used with BasisLZ, UASTC or ASTC encoding."); - if (isFormatAstc(options.vkFormat) && !options.raw) { + if (isASTC && !options.raw) { options.encodeASTC = true; switch (options.vkFormat) { @@ -1506,8 +1531,50 @@ void CommandCreate::processOptions(cxxopts::Options& opts, cxxopts::ParseResult& } } - if (options._1d && options.encodeASTC) - fatal_usage("ASTC format {} cannot be used for 1 dimensional textures (indicated by --1d).", + if (isBCn && !options.raw) { + options.encodeBCn = true; + + switch (options.vkFormat) { + case VK_FORMAT_BC1_RGB_UNORM_BLOCK: [[fallthrough]]; + case VK_FORMAT_BC1_RGB_SRGB_BLOCK: [[fallthrough]]; + case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: [[fallthrough]]; + case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: + options.bcn = KHR_DF_MODEL_BC1A; + break; +#if 0 + case VK_FORMAT_BC2_UNORM_BLOCK: [[fallthrough]]; + case VK_FORMAT_BC2_SRGB_BLOCK: + options.bcn = KHR_DF_MODEL_BC2; + break; +#endif + case VK_FORMAT_BC3_UNORM_BLOCK: [[fallthrough]]; + case VK_FORMAT_BC3_SRGB_BLOCK: + options.bcn = KHR_DF_MODEL_BC3; + break; + case VK_FORMAT_BC4_UNORM_BLOCK: + options.bcn = KHR_DF_MODEL_BC4; + break; + case VK_FORMAT_BC5_UNORM_BLOCK: + options.bcn = KHR_DF_MODEL_BC5; + break; +#if 0 + case VK_FORMAT_BC6H_UFLOAT_BLOCK: [[fallthrough]]; + case VK_FORMAT_BC6H_SFLOAT_BLOCK: + options.bcn = KHR_DF_MODEL_BC6H; + break; +#endif + case VK_FORMAT_BC7_UNORM_BLOCK: [[fallthrough]]; + case VK_FORMAT_BC7_SRGB_BLOCK: + options.bcn = KHR_DF_MODEL_BC7; + break; + default: + fatal(rc::NOT_SUPPORTED, "{} is unsupported for BCn encoding.", toString(options.vkFormat)); + break; + } + } + + if (options._1d && (options.encodeASTC || options.encodeBCn)) + fatal_usage("{} format {} cannot be used for 1 dimensional textures (indicated by --1d).", options.encodeASTC ? "ASTC" : "BCn", toString(options.vkFormat)); } @@ -1673,8 +1740,12 @@ void CommandCreate::executeCreate() { checkNumInputImages(); + // Overwrite options' vkFormat because ASTC/BCn encoding is performed by first creating an RGBA8 texture + // then encoding it using ktxTexture2_CompressAstcEx/ktxTexture2_CompressBCnEx if (options.encodeASTC) selectASTCMode(inputImageFile->spec().format().largestChannelBitLength()); + if (options.encodeBCn) + options.vkFormat = decompressedBCnFormat(options.vkFormat); firstImageSpec = inputImageFile->spec(); @@ -2034,13 +2105,15 @@ void CommandCreate::executeCreate() { encodeBasis(texture, options); if (options.encodeASTC) encodeASTC(texture, options); + if (options.encodeBCn) + encodeBCn(texture, options); metrics.decodeAndCalculateMetrics(texture, options, *this); compress(texture, options); - // Add KTXwriterScParams metadata if ASTC encoding, BasisU encoding, or other supercompression was used - const auto writerScParams = fmt::format("{}{}{}{}", options.astcOptions, options.codecOptions, options.commonOptions, options.compressOptions); + // Add KTXwriterScParams metadata if ASTC encoding, BCn encoding, BasisU encoding, or other supercompression was used + const auto writerScParams = fmt::format("{}{}{}{}{}", options.astcOptions, options.bcnOptions, options.codecOptions, options.commonOptions, options.compressOptions); if (writerScParams.size() > 0) { // Options always contain a leading space assert(writerScParams[0] == ' '); @@ -2073,6 +2146,12 @@ void CommandCreate::encodeASTC(KTXTexture2& texture, OptionsEncodeASTC& opts) { fatal(rc::KTX_FAILURE, "Failed to encode KTX2 file with codec ASTC. KTX Error: {}", ktxErrorString(ret)); } +void CommandCreate::encodeBCn(KTXTexture2& texture, OptionsEncodeBCn& opts) { + const auto ret = ktxTexture2_CompressBCnEx(texture, &opts); + if (ret != KTX_SUCCESS) + fatal(rc::KTX_FAILURE, "Failed to encode KTX2 file with codec BCn. KTX Error: {}", ktxErrorString(ret)); +} + void CommandCreate::compress(KTXTexture2& texture, const OptionsDeflate& opts) { if (opts.zstd) { const auto ret = ktxTexture2_DeflateZstd(texture, *opts.zstd); @@ -2345,6 +2424,20 @@ std::vector CommandCreate::convert(const std::unique_ptr& image, // Input files that have 16-bit components must be truncated to // 8 bits with a right-shift and a warning must be generated in the stderr. + case VK_FORMAT_BC1_RGB_UNORM_BLOCK: + case VK_FORMAT_BC1_RGB_SRGB_BLOCK: + case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: + case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: + case VK_FORMAT_BC3_UNORM_BLOCK: + case VK_FORMAT_BC3_SRGB_BLOCK: + case VK_FORMAT_BC4_UNORM_BLOCK: + case VK_FORMAT_BC5_UNORM_BLOCK: + case VK_FORMAT_BC7_UNORM_BLOCK: + case VK_FORMAT_BC7_SRGB_BLOCK: + requireUNORM(8); + assert(false && "Internal error"); + return {}; + case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: [[fallthrough]]; case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: [[fallthrough]]; case VK_FORMAT_ASTC_5x4_UNORM_BLOCK: [[fallthrough]]; @@ -3119,6 +3212,33 @@ void CommandCreate::checkSpecsMatch(const ImageInput& currentFile, const ImageSp } } +VkFormat CommandCreate::decompressedBCnFormat(VkFormat format) const { + switch (format) { + case VK_FORMAT_BC1_RGB_UNORM_BLOCK: + case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: + return VK_FORMAT_R8G8B8A8_UNORM; + case VK_FORMAT_BC1_RGB_SRGB_BLOCK: + case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: + return VK_FORMAT_R8G8B8A8_SRGB; + case VK_FORMAT_BC2_UNORM_BLOCK: + case VK_FORMAT_BC2_SRGB_BLOCK: + return VK_FORMAT_UNDEFINED; + case VK_FORMAT_BC3_UNORM_BLOCK: + return VK_FORMAT_R8G8B8A8_UNORM; + case VK_FORMAT_BC3_SRGB_BLOCK: + return VK_FORMAT_R8G8B8A8_SRGB; + case VK_FORMAT_BC4_UNORM_BLOCK: + return VK_FORMAT_R8_UNORM; + case VK_FORMAT_BC5_UNORM_BLOCK: + return VK_FORMAT_R8G8_UNORM; + case VK_FORMAT_BC7_UNORM_BLOCK: + return VK_FORMAT_R8G8B8A8_UNORM; + case VK_FORMAT_BC7_SRGB_BLOCK: + return VK_FORMAT_R8G8B8A8_SRGB; + default: return VK_FORMAT_UNDEFINED; + } +} + } // namespace ktx KTX_COMMAND_ENTRY_POINT(ktxCreate, ktx::CommandCreate) diff --git a/tools/ktx/command_encode.cpp b/tools/ktx/command_encode.cpp index 15f6b8d767..c9d3e48088 100644 --- a/tools/ktx/command_encode.cpp +++ b/tools/ktx/command_encode.cpp @@ -4,6 +4,7 @@ #include "command.h" #include "encode_utils_astc.h" +#include "encode_utils_bcn.h" #include "encode_utils_common.h" #include "platform_utils.h" #include "metrics_utils.h" @@ -49,6 +50,10 @@ Encode a KTX2 file. For universal and ASTC LDR formats, the input file must be R8, R8G8, R8G8B8 or R8G8B8A8 (or their sRGB variants). + For BC1, BC3 and BC7 formats, the input file must be R8G8B8A8 (or their SRGB variants). + For BC4 format, the input file must be R8. + For BC5 format, the input file must be R8G8. + For universal HDR formats, the input file must be R16G16B16_SFLOAT or R16G16B16A16_SFLOAT.