diff --git a/code/projects/ao.cpp b/code/projects/ao.cpp new file mode 100644 index 0000000000000000000000000000000000000000..265a2780a1079d77bd299e88c7d00f0dacc99e88 --- /dev/null +++ b/code/projects/ao.cpp @@ -0,0 +1,265 @@ + +#include <omp.h> +#include <chrono> +#include <random> +#include <stdint.h> + +#include "options.h" + +#include "vec.h" +#include "mat.h" + +#include "color.h" +#include "image.h" +#include "image_io.h" + +#include "gltf/gltf.h" +#include "gltf/scene.h" +#include "orbiter.h" + +#include "sampler.h" +#include "sampler_sobol.h" + +//~ typedef Squares Sampler; +typedef LCG Sampler; +//~ typedef Sobol Sampler; +//~ typedef SobolGray Sampler; +//~ typedef Owen Sampler; +//~ typedef OwenFast Sampler; +//~ typedef FCRNG Sampler; + +Options options; + + +Vector sample_k( const float u2, const float u3 ) +{ + // genere une direction ~ 1 / 2pi + float phi= float(2*M_PI) * u2; + float cos_theta= u3; + float sin_theta= std::sqrt(1 - std::min(float(1.0), cos_theta*cos_theta)); + return Vector(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta); +} + +float pdf_k( const Vector&n, const Vector& v ) // global +{ + if(dot(n, v) < 0) return 0; + return 1 / float(2*M_PI); +} + +Vector sample_cos( const float u2, const float u3 ) +{ + // genere une direction ~ cos theta / pi + float phi= float(2*M_PI) * u2; + float cos_theta= std::sqrt(u3); + float sin_theta= std::sqrt(1 - std::min(float(1.0), cos_theta*cos_theta)); + return Vector(std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta); +} + +float pdf_cos( const Vector&n, const Vector& v ) // global +{ + return std::max(float(0), dot(n, v)) / float(M_PI); +} + + +struct alpha_filter +{ + const Scene& scene; + FCRNG& rng; + + alpha_filter( const Scene& _scene, FCRNG& _rng ) : scene(_scene), rng(_rng) {} + + bool operator() ( const Hit& hit ) const + { + const GLTFMaterial& material= scene.material(hit); + if(material.color_texture == -1) + return true; + if(scene.textures[material.color_texture].opaque) + return true; + + vec3 uv_lod= scene.texcoords_lod(hit); + Color diffuse= scene.textures[material.color_texture].sample(uv_lod.x, uv_lod.y, uv_lod.z); + + return (rng.sample() <= diffuse.a); + } +}; + + + +int main( const int argc, const char **argv ) +{ + options= Options(argv, argv + argc); + + Scene scene= read_scene(options.filename); + if(scene.gltf.nodes.empty()) + return 1; // pas de geometrie, pas d'image + + // transformations + Transform view; + Transform view_inv; + Transform projection; + float aspect= 1; + + if(options.orbiter_filename) + { + Orbiter camera; + if(camera.read_orbiter(options.orbiter_filename) == false) + return 1; // pas de camera, pas d'image + + view= camera.view(); + view_inv= Inverse(view); + projection= camera.projection(); + aspect= camera.aspect(); + } + else if(scene.gltf.cameras.size()) + { + view= scene.camera.view; + view_inv= Inverse(scene.camera.view); + projection= scene.camera.projection; + aspect= scene.camera.aspect; + } + else + return 1; // pas de camera, pas d'image + + // proportions largeur/hauteur de la camera gltf + int samples= options.samples; + int width= 1024; + int height= width / aspect; + Image image(width, height); + Image aov_normal(width, height); + Image aov_albedo(width, height); + + // charge les textures + parametres de filtrage en fonction de l'image + read_textures(options.filename, scene, width, height); + //~ read_textures(options.filename, scene, 256, 256); + + // + printf("glTF lights %d\n", int(scene.gltf.lights.size())); + + + // + Transform viewport= Viewport(image.width(), image.height()); + Transform inv= Inverse(viewport * projection * view); + + int lines= 0; + auto cpu_start= std::chrono::high_resolution_clock::now(); + + // c'est parti ! parcours tous les pixels de l'image +#pragma omp parallel for schedule(dynamic, 1) + for(int py= 0; py < image.height(); py++) + { + #pragma omp atomic + lines++; + + if(omp_get_thread_num() == 0) + { + printf("%d/%d %d%%...\r", lines, image.height(), 100 * lines / image.height()); + fflush(stdout); + } + + for(int px= 0; px < image.width(); px++) + { + const unsigned seed= (py * image.width() + px) * samples * 127; + Sampler rng( seed ); + FCRNG alpha_rng( seed ); + + Color color; + Vector normal; + Color albedo; + + for(int i= 0; i < samples; i++) + { + rng.index(i); + float x= rng.sample(); + float y= rng.sample(); + + // generer le rayon + Point origine= inv(Point(px + x, py + y, 0)); + Point extremite= inv(Point(px + x, py + y, 1)); + Ray ray(origine, extremite); + + // calculer les intersections avec tous les triangles + if(Hit hit= scene.bvh.intersect(ray, alpha_filter(scene, alpha_rng))) + { + Point p= scene.position(hit, ray); + Vector pn= scene.normal(hit); + + // matiere emissive, si la source est orientee vers la camera + if(dot(pn, ray.d) < 0) + { + const GLTFMaterial& material= scene.material(hit); + color= color + material.emission; + // suppose que les normales des sources sont correctes... + } + + if(dot(pn, ray.d) > 0) + // mais ce n'est pas toujours le cas pour le reste de la geometrie... + pn= -pn; + + // eclairage ambiant + Brdf brdf= scene.brdf(hit, pn); + { + World world(pn); + // genere une direction ~ cos / pi + Vector l= world( sample_cos(rng.sample(), rng.sample()) ); + float pdf= pdf_cos(pn, l); + + //~ // genere une direction ~ 1/2pi + //~ Vector l= world( sample_k(rng.sample(), rng.sample()) ); + //~ float pdf= pdf_k(pn, l); + + //~ // genere la direction en fonction de la matiere + //~ Vector l= brdf.sample(rng.sample(), rng.sample(), rng.sample(), normalize(ray.o - p)); + //~ float pdf= brdf.pdf(l, normalize(ray.o - p)); + + if(pdf == 0) + { + color= color + Black(); + //~ color= color + Red(); // compte les echantillons qui n'ont pas reussit a generer une direction "valide" + } + else + if( dot(l, Vector(0, 1, 0)) > 0 && scene.visible( offset_point(p, pn), l) ) + { + // V= 1; + Color fr= brdf.f(l, normalize(ray.o - p)); + float cos_theta= std::max(float(0), dot(pn, l)); + + color= color + fr * cos_theta / pdf; + //~ color= color + Black(); + } + } + + normal= normal + pn; + albedo= albedo + brdf.f(pn, normalize(ray.o - p)); + } + } + + image(px, py)= Color(color / float(samples), 1); // force une couleur opaque... + aov_normal(px, py)= Color(normal / float(samples), 1); // force une couleur opaque... + aov_albedo(px, py)= Color(albedo / float(samples), 1); // force une couleur opaque... + } + } + + auto cpu_stop= std::chrono::high_resolution_clock::now(); + auto cpu_time= std::chrono::duration_cast<std::chrono::milliseconds>(cpu_stop - cpu_start).count(); + printf("cpu %ds %03dms\n", int(cpu_time / 1000), int(cpu_time % 1000)); + + char tmp[1024]; + //~ sprintf(tmp, "%s-%05u-%04u.png", options.prefix, unsigned(cpu_time), samples); + sprintf(tmp, "%s-%04u.png", options.prefix, samples); + printf("writing '%s'...\n", tmp); + write_image_preview(image, tmp); + + //~ sprintf(tmp, "%s-%05u-%04u.pfm", options.prefix, unsigned(cpu_time), samples); + sprintf(tmp, "%s-%04u.pfm", options.prefix, samples); + printf("writing '%s'...\n", tmp); + write_image_pfm(image, tmp); + + sprintf(tmp, "%s-normals-%04u.pfm", options.prefix, samples); + write_image_pfm(aov_normal, tmp); + + sprintf(tmp, "%s-albedo-%04u.pfm", options.prefix, samples); + write_image_pfm(aov_albedo, tmp); + printf("\n"); + + return 0; +} diff --git a/code/projects/errors.cpp b/code/projects/errors.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e27b825d0647a0092d51580a696f5f43bbe5342 --- /dev/null +++ b/code/projects/errors.cpp @@ -0,0 +1,326 @@ + +#include <cstdio> +#include <cstring> +#include <cfloat> +#include <algorithm> + + +#include "image.h" +#include "image_io.h" + + +struct cell +{ + Image image; + + const char *filename; + const char *title; + + int x, y; + int nspp; + int time; +}; + + +// +int render_nspp( const char *filename ) +{ + int n= -1; + + // suppose que le nom de fichier est de la forme 'prefix-nspp.[pfm|png]' + const char *ext= strrchr(filename, '.'); + if(ext) + { + if(strcmp(ext, ".pfm") == 0 || strcmp(ext, ".png") == 0 ) + { + const char *last= strrchr(filename, '-'); + if(sscanf(last, "-%d.", &n) == 1) + return n; + } + } + + printf("\n[error] filename '%s'... doesn't match 'prefix-nspp.[pfm|png]'\n", filename); + return 0; +} + + +unsigned render_time( const char *filename ) +{ + unsigned d= 0; + + // suppose que le nom de fichier est de la forme 'prefix-time-nspp.[pfm|png]' + const char *ext= strrchr(filename, '.'); + if(ext) + { + if(strcmp(ext, ".pfm") == 0 || strcmp(ext, ".png") == 0 ) + { + char tmp[1024]; + strcpy(tmp, filename); + char *last= strrchr(tmp, '-'); + if(last) + { + *last= 0; + const char *prev= strrchr(tmp, '-'); + if(prev) + { + if(sscanf(prev, "-%d", &d) == 1) + return d; + } + } + } + } + + //~ printf("\n[warning] filename '%s'... doesn't match 'prefix-time-nspp.[pfm|png]'\n", filename); + return 0; +} + + +// mse d'une vignette +std::pair<double, double> Mlocal( /* ref */ const Image &A, /* image */ const Image &B, + int mX, int mY, + int MX, int MY , + double &vmin, double &vmax) +{ + double val= 0.0; + double var= 0.0; + vmax= -1.0; + vmin= 100000.0; + + int cpt= 0; + for(int i=mX; i <= MX; ++i) + for(int j=mY; j <= MY; ++j) + { + Color d= A(i, j) - B(i, j); + double v= (std::abs(d.r) + std::abs(d.g) + std::abs(d.b)) / 3; + + vmax= std::max(vmax, v); + // ne compte pas les pixels noirs + Color pixel= A(i, j); + if(pixel.r + pixel.g + pixel .b > 0) + vmin= std::min(vmin, v); + + val += v; + var += v*v; + cpt++; + } + + val /= double(cpt); + var /= double(cpt); + var= (var - val*val); + return std::make_pair(val, var); +} + + +Image read( const char *filename ) +{ + if(pfm_image(filename)) + return read_image_pfm(filename); + + return read_image(filename); +} + + +/*! renvoie le chemin d'acces a un fichier. le chemin est toujours termine par / + pathname("path/to/file") == "path/to/" + pathname("file") == "./" + */ +std::string path_name( const std::string& filename ) +{ + std::string path= filename; +#ifndef WIN32 + std::replace(path.begin(), path.end(), '\\', '/'); // linux, macos : remplace les \ par /. + size_t slash = path.find_last_of( '/' ); + if(slash != std::string::npos) + return path.substr(0, slash +1); // inclus le slash + else + return "./"; +#else + std::replace(path.begin(), path.end(), '/', '\\'); // windows : remplace les / par \. + size_t slash = path.find_last_of( '\\' ); + if(slash != std::string::npos) + return path.substr(0, slash +1); // inclus le slash + else + return ".\\"; +#endif +} + + +std::string normalize_path( const std::string& file ) +{ + std::string tmp= file; + +#ifndef WIN32 + std::replace(tmp.begin(), tmp.end(), '\\', '/'); // linux, macos : remplace les \ par /. +#else + std::replace(tmp.begin(), tmp.end(), '/', '\\'); // windows : remplace les / par \. +#endif + return tmp; +} + +std::string base_name( const std::string& filename ) +{ + std::string nfilename= normalize_path(filename); + size_t slash = nfilename.find_last_of( '/' ); + if(slash != std::string::npos) + return nfilename.substr(slash +1); + else + return nfilename; +} + +std::string change_extension( const std::string& filename, const std::string& ext ) +{ + size_t pos= filename.rfind("."); + + return filename.substr(0, pos).append(ext); +} + +std::string change_prefix( const std::string& prefix, const std::string& filename ) +{ + std::string path= path_name(filename); + std::string file= base_name(filename); + + path.append(prefix).append(file); + return path; +} + + +int main( int argc, const char *argv[] ) +{ + if(argc < 2) + { + printf("usage: %s reference.[pfm|png] --line 1 [--title \"...\"] image.[pfm|png] [--line 2 images --line 3 images] \n", argv[0]); + return 0; + } + + // + Image reference; + if(argc > 1) + reference= read(argv[1]); + + if(reference.size() == 0) + { + printf("[error] loading reference image '%s'...\n", argv[1]); + return 1; + } + + // charge les images + int rows= 0; + int columns= 0; + std::vector< std::vector<cell> > grid; + { + std::vector<cell> cells; + + int x= 0; + int y= -1; + int last_row= -1; + const char *last_title= nullptr; + + for(int option= 2; option < argc; ) + { + if(argv[option][0] == '-') + { + // nouvelle ligne + if(strcmp(argv[option], "--line") == 0 && option +1 < argc) + { + int row= 0; + if(sscanf(argv[option+1], "%d", &row) != 1) + break; + + x= 0; + //~ y++; + y= row -1; + option+= 2; + + printf("line %d\n", row); + } + else if(strcmp(argv[option], "--title") == 0 && option +1 < argc) + { + last_title= argv[option+1]; + option+= 2; + } + else + { + printf("[error] parsing option '%s'...\n", argv[option]); + return 1; + } + } + else + { + const char *filename= argv[option]; + int n= render_nspp(filename); + int render= render_time(filename); + cells.push_back( {Image(), filename, last_title, x, y, n, render} ); + + printf("x %d y %d: '%s' %s, nspp %d, render %dms\n", x, y, last_title, filename, n, render); + + x++; + option++; + } + } + + // chargement parallele des images + #pragma omp parallel for + for(int i= 0; i < int(cells.size()); i++) + cells[i].image= read(cells[i].filename); + + // dimensions de la grille + for(auto const & cell : cells) + { + rows= std::max(rows, cell.y +1); + columns= std::max(columns, cell.x +1); + } + + // cree la grille + grid.resize(rows); + for(int i= 0; i < rows; i++) + grid[i].resize(columns); + + // copie les images a leur place + for(auto const & cell : cells) + { + int x= cell.x; + int y= cell.y; + assert(x < columns); + assert(y < rows); + grid[y][x]= cell; // move ? + } + } + + // mse global +#pragma omp parallel for schedule(dynamic, 1) + for(int r= 0; r < rows; r++) + { + if(!grid[r][0].title) + continue; + + printf("mse %s\n", grid[r][0].title); + char filename[1024]; + sprintf(filename, "%smse_%s.txt", path_name(grid[r][0].filename).c_str(), grid[r][0].title); + + //~ printf("mse file '%s'\n", filename); + FILE *out= fopen(filename, "wt"); + if(out) + { + printf("writing '%s'...\n", filename); + + //~ fprintf(out, "# %s\n", grid[r][0].title); + fprintf(out, "#Nbpts #Mean #Min #Max\n"); + for(int c= 0; c < columns; c++) + { + if(grid[r][c].image.size() == 0) + continue; + + double vmin, vmax; + std::pair<double, double> stat= Mlocal(reference, grid[r][c].image, 0, 0, grid[r][c].image.width()-1, grid[r][c].image.height()-1, vmin, vmax); + + double mse= stat.first; + fprintf(out, "%d %.15f %.15f %.15f\n", grid[r][c].nspp, mse, vmin, vmax); + //~ fprintf(out, "%d %.15f %.15f %.15f\n", grid[r][c].time, mse, vmin, vmax); + } + + fclose(out); + } + } + + return 0; +} diff --git a/code/projects/options.h b/code/projects/options.h new file mode 100644 index 0000000000000000000000000000000000000000..42b04ca17072f467d6dd481b06b462ac1618f519 --- /dev/null +++ b/code/projects/options.h @@ -0,0 +1,167 @@ + +#ifndef _OPTIONS_H +#define _OPTIONS_H + +#include <cassert> +#include <cstdlib> +#include <cstring> +#include <string> +#include <vector> + + +struct Options +{ + const char *filename= nullptr; + const char *orbiter_filename= nullptr; + const char *prefix= "image"; + int samples= 32; + int depth= 1; + + Options( const char **begin, const char **end ) : options(begin, end) + { + if(options.size() > 1) + { + filename= option(1, filename); + filename= value("--scene", filename); + orbiter_filename= value("--camera", orbiter_filename); + + prefix= value("--prefix", prefix); + samples= value_int("-s", "32"); + depth= value_int("--lenght", "1"); + } + + if(options.size() == 1 || flag("--help") || flag("-h") || flag("--verbose") || flag("-v")) + { + printf("filename: '%s'\n", filename); + printf("camera: '%s'\n", orbiter_filename); + printf("output prefix: '%s'\n", prefix); + printf("samples: %u\n", samples); + printf("path lenght: %u\n", depth); + } + } + + + Options() = default; + Options( const Options& ) = delete; + Options& operator= ( const Options& ) = default; + + // option placee + const char *option( const unsigned position, const char *default_value ) + { + if(position >= options.size()) + return default_value; + if(options[position] == nullptr) + return default_value; + + const char *value= options[position]; + if(value[0] == '-') + { + printf("invalid option: [%u] = '%s'\n", position, value); + exit(1); + } + + options[position]= nullptr; + return value; + } + + // recherche des options + int find( const char *name ) + { + for(int i= 0; i < int(options.size()); i++) + if(options[i] && std::string(options[i]) == std::string(name)) + return i; + return -1; + } + + // cherche un flag, renvoie un bool + bool flag( const char *name ) + { + int index= find(name); + if(index != -1) + options[index]= nullptr; + + return (index != -1); + } + + int find_value( const char *name, const int n= 1 ) + { + int index= find(name); + if(index < 0 || index + n >= int(options.size())) + return -1; + + for(int i= index; i <= index + n; i++) + if(options[i] == nullptr) + return -1; + return index; + } + + // cherche une option et renvoie sa valeur ou la valeur par defaut + const char *value( const char *name, const char *default_value ) + { + int index= find_value(name, 1); + if(index < 0) + return default_value; + + const char *tmp= options[index+1]; + options[index]= nullptr; + options[index+1]= nullptr; + return tmp; + } + + // cherche une option, renvoie un int + int value_int( const char *name, const char *default_value ) + { + const char *str= value(name, default_value); + + int v= 0; + if(sscanf(str, "%d", &v) == 1) + return v; + + // erreur parametre invalide. + printf("invalid int parameter: %s = '%s'\n", name, str); + + exit(1); + return 0; + } + + // cherche une option, renvoie un unsigned long int + size_t value_long( const char *name, const char *default_value ) + { + const char *str= value(name, default_value); + + unsigned long int v= 0; + if(sscanf(str, "%lu", &v) == 1) + return v; + + // erreur parametre invalide. + printf("invalid int parameter: %s = '%s'\n", name, str); + + exit(1); + return 0; + } + + // cherche une option, renvoie un bool + bool value_bool( const char *name, const char *default_value ) + { + const char *str= value(name, default_value); + if(std::string(str) == "true" || std::string(str) == "on" || std::string(str) == "1") + return true; + if(std::string(str) == "false" || std::string(str) == "off" || std::string(str) == "0") + return false; + + // erreur parametre invalide. + printf("invalid bool parameter: %s = '%s'\n", name, str); + + exit(1); + return false; + } + +protected: + std::vector<const char *> options = std::vector<const char *>(); +}; + +extern Options options; + +#endif + + diff --git a/code/projects/owen_fast.h b/code/projects/owen_fast.h new file mode 100644 index 0000000000000000000000000000000000000000..17f93d18e2edebbdf82332060f1f3f37a33e920b --- /dev/null +++ b/code/projects/owen_fast.h @@ -0,0 +1,115 @@ + +#ifndef OWEN_FAST_H +#define OWEN_FAST_H + +#include <cstdint> + + +// renvoie 0 ou 1, valeur du ieme bit de x +inline unsigned owen_bit( const unsigned x, const unsigned position ) +{ + return (x >> position) & 1u; +} + + +// permute les bits 0 .. 31 de a +// meme construction que OwenScrambler de pbrt 4, mais plus decompose, plus lisible et plus rapide... +// cf https://github.com/mmp/pbrt-v4/blob/39e01e61f8de07b99859df04b271a02a53d9aeb2/src/pbrt/util/lowdiscrepancy.h#L240 +unsigned owen_scramble( const unsigned a, const unsigned seed ) +{ + FCRNG rng(seed); + + // + unsigned node_index= 0; + unsigned flip= rng.index(node_index).sample_range(2); + unsigned digit= owen_bit(a, 31); + unsigned b= (digit ^ flip) << 31; + + for(unsigned i= 1; i < 32; i++) + { + node_index= 2*node_index + digit +1; + // heap layout, root i= 0, left 2i+1, right 2i+2 + + flip= rng.index(node_index).sample_range(2); + digit= owen_bit(a, 31 - i); + b= b | (digit ^ flip) << (31 - i); + } + + return b; +} + +// permutation inverse +unsigned owen_inverse_scramble( const unsigned b, const unsigned seed ) +{ + FCRNG rng(seed); + + // + unsigned node_index= 0; + unsigned flip= rng.index(node_index).sample_range(2); + unsigned digit= owen_bit(b, 31) ^ flip; + unsigned a= digit << 31; + + for(unsigned i= 1; i < 32; i++) + { + node_index= 2*node_index + digit +1; + // heap layout, root i= 0, left 2i+1, right 2i+2 + + unsigned flip= rng.index(node_index).sample_range(2); + digit= owen_bit(b, 31 - i) ^ flip; + a= a | digit << (31 - i); + } + + return a; +} + + +// permute les bits 0 .. nbits de a +unsigned owen_scramble( const unsigned a, const unsigned seed, const unsigned nbits ) +{ + FCRNG rng(seed); + + // + unsigned node_index= 0; + unsigned flip= rng.index(node_index).sample_range(2); + unsigned digit= owen_bit(a, nbits); + unsigned b= (digit ^ flip) << nbits; + + for(unsigned i= 1; i < nbits+1; i++) + { + node_index= 2*node_index + digit +1; + // heap layout, root i= 0, left 2i+1, right 2i+2 + + unsigned flip= rng.index(node_index).sample_range(2); + digit= owen_bit(a, nbits - i); + b= b | (digit ^ flip) << (nbits - i); + } + + return b; +} + + +// cf FastOwenScrambler, pbrt 4 +// https://github.com/mmp/pbrt-v4/blob/39e01e61f8de07b99859df04b271a02a53d9aeb2/src/pbrt/util/lowdiscrepancy.h#L221 +inline unsigned reverse_bits( unsigned n ) +{ + n = (n << 16) | (n >> 16); + n = ((n & 0x00ff00ff) << 8) | ((n & 0xff00ff00) >> 8); + n = ((n & 0x0f0f0f0f) << 4) | ((n & 0xf0f0f0f0) >> 4); + n = ((n & 0x33333333) << 2) | ((n & 0xcccccccc) >> 2); + n = ((n & 0x55555555) << 1) | ((n & 0xaaaaaaaa) >> 1); + return n; +} + +// permute tous les bits directement. +unsigned owen_scramble_fast4( const unsigned a, const unsigned seed ) +{ + unsigned v= reverse_bits(a); + v ^= v * 0x3d20adea; + v += seed; + v *= (seed >> 16) | 1; + v ^= v * 0x05526c56; + v ^= v * 0x53a22864; + return reverse_bits(v); +} + +#endif diff --git a/code/projects/path.cpp b/code/projects/path.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8b4cc7692e6b66bcc823604f227a8f61f86fe68d --- /dev/null +++ b/code/projects/path.cpp @@ -0,0 +1,372 @@ + + +#include <omp.h> +#include <chrono> +#include <random> +#include <stdint.h> + +#include "options.h" + +#include "vec.h" +#include "mat.h" + +#include "color.h" +#include "image.h" +#include "image_io.h" + +#include "gltf/gltf.h" +#include "gltf/scene.h" +#include "orbiter.h" + +#include "sampler.h" +#include "sampler_sobol.h" + +//~ typedef Squares Sampler; +typedef LCG Sampler; +//~ typedef Sobol Sampler; +//~ typedef SobolGray Sampler; +//~ typedef Owen Sampler; +//~ typedef OwenFast Sampler; +//~ typedef FCRNG Sampler; + +Options options; + + +Color direct( const Point& o, const Point& p, const Brdf& pbrdf, const Scene& scene, Sampler& rng ) +{ + Color color; + + /* strategie 1 : genere un point sur une source + */ + const Source& source= scene.sources.sample( rng.sample() ); + Point s= source.sample( rng.sample(), rng.sample() ); + Vector sn= source.n; + + Vector l= normalize( Vector(p, s) ); + float cos_theta= std::max(float(0), dot(pbrdf.world.n, l)); + float cos_theta_s= std::max(float(0), dot(sn, -l)); + float G= cos_theta_s / distance2(p, s); + float pdf= source.pdf(s) * scene.sources.pdf(source); + + if(pdf * cos_theta * cos_theta_s > 0 + && scene.visible( offset_point(p, pbrdf.world.n), offset_point(s, sn) )) + { + Color fr= pbrdf.f(l, normalize(o - p)); + color= color + source.emission * G * fr * cos_theta / pdf; + } + + /* strategie 2 : genere une direction en fonction de la matiere + + Vector l= pbrdf.sample( rng.sample(), rng.sample(), rng.sample(), normalize(o - p)); + float pdf= pbrdf.pdf( l, normalize(o - p) ); + float cos_theta= std::max(float(0), dot(pbrdf.world.n, l)); + if(pdf * cos_theta > 0 + && scene.visible(offset_point(p, pbrdf.world.n), l)) + { + Color fr= pbrdf.f(l, normalize(o - p)); + color= color + Color(0.02) * fr * cos_theta / pdf; + } + */ + + return color; +} + +// mis multi-sample, evalue les 2 integrales + ponderation de chaque echantillon +Color direct_mis( const Point& o, const Point& p, const Brdf& pbrdf, Hit& qhit, const Scene& scene, Sampler& rng ) +{ + Color color; + + // strategie 1 : selectionne une source + un point sur la source + { + const Source& source= scene.sources.sample( rng.sample() ); + Point s= source.sample( rng.sample(), rng.sample() ); + + Vector sn= source.n; + Vector l= normalize( Vector(p, s) ); + float cos_theta= std::max(float(0), dot(pbrdf.world.n, l)); + float cos_theta_s= std::max(float(0), dot(sn, -l)); + float G= cos_theta_s / distance2(p, s); + if(G * cos_theta > 0) + { + float pdf1= source.pdf(s) * scene.sources.pdf(source); + if(pdf1 > 0) + { + if(scene.visible( offset_point(p, pbrdf.world.n), offset_point(s, sn) ) ) + { + float pdf2= pbrdf.pdf(l, normalize( Vector(p, o) )) * G; + float w= (pdf1*pdf1) / (pdf1*pdf1 + pdf2*pdf2); // pdf1 et pdf2 sur les aires, power heuristic + + Color fr= pbrdf.f(l, normalize(o - p)); + color= color + w * source.emission * fr * G * cos_theta / pdf1; + } + } + } + } + + // strategie 2 : selectionne un terme de la brdf et genere une direcion + { + Vector l= pbrdf.sample( rng.sample(), rng.sample(), rng.sample(), normalize(o - p) ); + float pdf2= pbrdf.pdf(l, normalize(o - p) ); + if(pdf2 > 0) + { + Ray ray( offset_point(p, pbrdf.world.n), l ); + if(Hit hit= scene.intersect(ray)) + { + Color emission= scene.material(hit).emission; + if(emission.max() > 0) + { + Point s= ray.o + ray.d * hit.t; + Vector sn= scene.normal(hit); + float cos_theta= std::max(float(0), dot(pbrdf.world.n, l)); + float cos_theta_s= std::max(float(0), dot(sn, -l)); + float G= cos_theta_s / distance2(p, s); + if(G * cos_theta > 0) + { + pdf2= pdf2 * G; + float pdf1= 1 / scene.sources.area; + float w= (pdf2*pdf2) / (pdf1*pdf1 + pdf2*pdf2); // pdf1 et pdf2 sur les aires, power heuristic + + Color fr= pbrdf.f(l, normalize(o - p)); + color= color + w * emission * fr * G * cos_theta / pdf2; + } + } + else + // conserve le point pour prolonger le chemin... + qhit= hit; + } + } + } + + return color; +} + + +Color path( const int depth, const Point& o, const Point& p, const Brdf& pbrdf, const Scene& scene, Sampler& rng ) +{ + Hit qhit; + + //~ Color color= direct(o, p, pbrdf, scene, rng ); + Color color= direct_mis(o, p, pbrdf, qhit, scene, rng ); + if(depth == 0) + return color; + + // recuperer l'intersection mis du direct... cf direct_mis, elimine un rayon par rebond + if(qhit) + { + Point q= scene.position(qhit); + Vector l= normalize(q - p); + float pdf= pbrdf.pdf(l, normalize(o - p)); + if(pdf > 0) // ne devrait pas arriver... + { + Vector qn= scene.normal(qhit); + Brdf qbrdf= scene.brdf(qhit, qn); + + float cos_theta= std::max(float(0), dot(pbrdf.world.n, l)); + Color fr= pbrdf.f(l, normalize(o - p)); + return color + path(depth -1, p, q, qbrdf, scene, rng) * fr * cos_theta / pdf; + } + } + + /* sinon genere une direction pour prolonger le chemin... + Vector l= pbrdf.sample( rng.sample(), rng.sample(), rng.sample(), normalize(o - p) ); + float pdf= pbrdf.pdf(l, normalize(Vector(p, o))); + if(pdf > 0) + { + Ray ray( offset_point(p, pbrdf.world.n), l ); + if(Hit hit= scene.intersect(ray)) + { + Point q= scene.position(hit, ray); + Vector qn= scene.normal(hit); + Brdf qbrdf= scene.brdf(hit, qn); + + float cos_theta= std::max(float(0), dot(pbrdf.world.n, l)); + Color fr= pbrdf.f(l, normalize(o - p)); + return color + path(depth -1, p, q, qbrdf, scene, rng) * fr * cos_theta / pdf; + } + } + */ + + return color; +} + + + +struct alpha_filter +{ + const Scene& scene; + FCRNG& rng; + + alpha_filter( const Scene& _scene, FCRNG& _rng ) : scene(_scene), rng(_rng) {} + + bool operator() ( const Hit& hit ) const + { + const GLTFMaterial& material= scene.material(hit); + if(material.color_texture == -1) + return true; + if(scene.textures[material.color_texture].opaque) + return true; + + vec3 uv_lod= scene.texcoords_lod(hit); + Color diffuse= scene.textures[material.color_texture].sample(uv_lod.x, uv_lod.y, uv_lod.z); + + return (rng.sample() <= diffuse.a); + } +}; + + + +int main( const int argc, const char **argv ) +{ + options= Options(argv, argv + argc); + + Scene scene= read_scene(options.filename); + if(scene.gltf.nodes.empty()) + return 1; // pas de geometrie, pas d'image + + // transformations + Transform view; + Transform view_inv; + Transform projection; + float aspect= 1; + + if(options.orbiter_filename) + { + Orbiter camera; + if(camera.read_orbiter(options.orbiter_filename) == false) + return 1; // pas de camera, pas d'image + + view= camera.view(); + view_inv= Inverse(view); + projection= camera.projection(); + aspect= camera.aspect(); + } + else if(scene.gltf.cameras.size()) + { + view= scene.camera.view; + view_inv= Inverse(scene.camera.view); + projection= scene.camera.projection; + aspect= scene.camera.aspect; + } + else + return 1; // pas de camera, pas d'image + + // proportions largeur/hauteur de la camera gltf + int samples= options.samples; + int width= 1024; + int height= width / aspect; + Image image(width, height); + Image aov_normal(width, height); + Image aov_albedo(width, height); + + // charge les textures + parametres de filtrage en fonction de l'image + read_textures(options.filename, scene, width, height); + //~ read_textures(options.filename, scene, 256, 256); + + // + printf("glTF lights %d\n", int(scene.gltf.lights.size())); + + + // + Transform viewport= Viewport(image.width(), image.height()); + Transform inv= Inverse(viewport * projection * view); + + unsigned maxdims= 0; + unsigned lines= 0; + auto cpu_start= std::chrono::high_resolution_clock::now(); + + // c'est parti ! parcours tous les pixels de l'image +#pragma omp parallel for schedule(dynamic, 1) + for(int py= 0; py < image.height(); py++) + { + #pragma omp atomic + lines++; + + if(omp_get_thread_num() == 0) + { + printf("%d/%d %d%%...\r", lines, image.height(), 100 * lines / image.height()); + fflush(stdout); + } + + for(int px= 0; px < image.width(); px++) + { + const unsigned seed= (py * image.width() + px) * samples * 127; + Sampler rng( seed ); + FCRNG alpha_rng( seed ); + + Color color; + Vector normal; + Color albedo; + + for(int i= 0; i < samples; i++) + { + rng.index(i); + float x= rng.sample(); + float y= rng.sample(); + + // generer le rayon + Point origine= inv(Point(px + x, py + y, 0)); + Point extremite= inv(Point(px + x, py + y, 1)); + Ray ray(origine, extremite); + + // calculer les intersections avec tous les triangles + //~ if(Hit hit= scene.bvh.intersect(ray)) + if(Hit hit= scene.bvh.intersect(ray, alpha_filter(scene, alpha_rng))) + { + Point p= scene.position(hit, ray); + Vector pn= scene.normal(hit); + + // matiere emissive, si la source est orientee vers la camera + if(dot(pn, ray.d) < 0) + { + const GLTFMaterial& material= scene.material(hit); + color= color + material.emission; + // suppose que les normales des sources sont correctes... + } + + if(dot(pn, ray.d) > 0) + // mais ce n'est pas toujours le cas pour le reste de la geometrie... + pn= -pn; + + Brdf brdf= scene.brdf(hit, pn); + //~ color= color + direct(origine, p, brdf, scene, rng); + color= color + path(options.depth, origine, p, brdf, scene, rng); + + normal= normal + pn; + albedo= albedo + brdf.f(pn, normalize(ray.o - p)); + } + } + + image(px, py)= Color(color / float(samples), 1); // force une couleur opaque... + aov_normal(px, py)= Color(normal / float(samples), 1); // force une couleur opaque... + aov_albedo(px, py)= Color(albedo / float(samples), 1); // force une couleur opaque... + + maxdims= std::max(rng.d, maxdims); + } + } + + printf("sampler dimensions %u\n", maxdims); + + auto cpu_stop= std::chrono::high_resolution_clock::now(); + auto cpu_time= std::chrono::duration_cast<std::chrono::milliseconds>(cpu_stop - cpu_start).count(); + printf("cpu %ds %03dms\n", int(cpu_time / 1000), int(cpu_time % 1000)); + + char tmp[1024]; + //~ sprintf(tmp, "%s-%05u-%04u.png", options.prefix, unsigned(cpu_time), samples); + sprintf(tmp, "%s-%04u.png", options.prefix, samples); + printf("writing '%s'...\n", tmp); + write_image_preview(image, tmp); + + //~ sprintf(tmp, "%s-%05u-%04u.pfm", options.prefix, unsigned(cpu_time), samples); + sprintf(tmp, "%s-%04u.pfm", options.prefix, samples); + printf("writing '%s'...\n", tmp); + write_image_pfm(image, tmp); + + sprintf(tmp, "%s-normals-%04u.pfm", options.prefix, samples); + write_image_pfm(aov_normal, tmp); + + sprintf(tmp, "%s-albedo-%04u.pfm", options.prefix, samples); + write_image_pfm(aov_albedo, tmp); + printf("\n"); + + return 0; +} diff --git a/code/projects/sampler.h b/code/projects/sampler.h new file mode 100644 index 0000000000000000000000000000000000000000..9f0444262c1bf188fc7d2afb637fb5184ba5b4ef --- /dev/null +++ b/code/projects/sampler.h @@ -0,0 +1,129 @@ + +#ifndef _SAMPLER_H +#define _SAMPLER_H + + +inline float uint_to_float( const unsigned x ) +{ + return float(x >> 8) / float(1u << 24); +} + +inline double uint_to_double( const unsigned x ) +{ + return double(uint64_t(x) << 20) / double(uint64_t(1) << 52); +} + + +struct Squares +{ + uint64_t n; + + Squares( ) : n(0) {} + Squares( const uint64_t first ) : n(first) {} + + Squares& index( const unsigned i ) { return *this; } + float sample( ) { return uint_to_float( squares32(n++) ); } + float sample( const uint64_t id ) { return uint_to_float( squares32(id) ); } + + inline unsigned squares32( const uint64_t n, const uint64_t key= 0xc8e4fd154ce32f6d ) + { + uint64_t x, y, z; + + y = x = n * key; + z = y + key; + x = x*x + y; x = (x>>32) | (x<<32); /* round 1 */ + x = x*x + z; x = (x>>32) | (x<<32); /* round 2 */ + x = x*x + y; x = (x>>32) | (x<<32); /* round 3 */ + + return (x*x + z) >> 32; /* round 4 */ + } +}; + + +struct LCG +{ + std::default_random_engine rng; + std::uniform_real_distribution<float> uniform; + unsigned d; + + LCG( ) : rng(), uniform(), d(0) {} + LCG( const unsigned seed ) : rng( hash(seed) ), uniform(), d(0) {} + // seed est un compteur, pas du tout adapte comme init du lcg, mais hash(seed) est suffisament uniforme + + LCG& index( const unsigned i ) { d= 0; return *this; } + float sample( ) { d++; return uniform(rng); } + + static unsigned hash( unsigned x ) + { + x ^= x >> 16; + x *= 0x21f0aaad; + x ^= x >> 15; + x *= 0xd35a2d97; + x ^= x >> 15; + return x; + } +}; + + +// counter based rng, cf "Parallel Random Numbers: As Easy as 1, 2, 3" +// https://www.thesalmons.org/john/random123/ +// le code est quand meme bien degueu et l'etat interne des generateurs est un peu trop gros. +// openrand a serieusement nettoye l'implem. cf https://github.com/msu-sparta/OpenRAND/blob/main/include/openrand/philox.h + +// du coup, plus simple et de qualite raisonnable : +// "PRNS with 32 bits of state" +// https://marc-b-reynolds.github.io/shf/2017/09/27/LPRNS.html +// pas les memes constantes que dans le blog, mais small crush passe sans probleme, donc j'imagine que ca suffit. +// et c'est mieux que std::default_random_engine qui echoue a la moitiee des tests de small crush... +struct FCRNG +{ + unsigned n; + unsigned key; + + FCRNG( ) : n(0), key(123451) {} + FCRNG( const unsigned s ) : n(), key() { seed(s); } + + void seed( const unsigned s ) { n= 0; key= (s << 1) | 1u; } + + FCRNG& index( const unsigned i ) { n= i; return *this;} + + unsigned sample_int( ) { return hash(n++ * key); } + // \todo pour le premier point n= 0 et 0*key == 0 aussi, marche pas tres bien avant d'avoir quelques bits a 1 dans n... + // cf utilisation dans owen... + + float sample( ) { return uint_to_float( sample_int() ); } + + unsigned sample_range( const unsigned range ) + { + // Efficiently Generating a Number in a Range + // cf http://www.pcg-random.org/posts/bounded-rands.html + unsigned divisor= (uint64_t(1) << 32) / range; + if(divisor == 0) return 0; + + while(true) + { + unsigned x= sample_int() / divisor; + if(x < range) return x; + } + } + + // c++ interface + unsigned operator() ( ) { return sample_int(); } + static constexpr unsigned min( ) { return 0; } + static constexpr unsigned max( ) { return (uint64_t(1) << 32) -1 ;} + typedef unsigned result_type; + + static unsigned hash( unsigned x ) + { + x ^= x >> 16; + x *= 0x21f0aaad; + x ^= x >> 15; + x *= 0xd35a2d97; + x ^= x >> 15; + return x; + } + // cf "hash prospector" https://github.com/skeeto/hash-prospector/blob/master/README.md +}; + + +#endif diff --git a/code/projects/sampler_sobol.h b/code/projects/sampler_sobol.h new file mode 100644 index 0000000000000000000000000000000000000000..57f1f52f73c1bcf5dbee8d5dd93351972c15887d --- /dev/null +++ b/code/projects/sampler_sobol.h @@ -0,0 +1,159 @@ + +#ifndef _SAMPLER_SOBOL_H +#define _SAMPLER_SOBOL_H + +#include <array> + +#include "sampler.h" +#include "owen_fast.h" +#include "sobol_matrices.h" + + +struct Sobol +{ + Sobol( ) = default; + + Sobol( const unsigned seed ) : n(0), d(0), scrambles() + { + FCRNG rng(seed); + for(unsigned d= 0; d < sobol_matrices_size; d++) + scrambles[d]= rng.sample_int(); + } + + Sobol& index( const unsigned i ) + { + n= i; + d= 0; + return *this; + } + + float sample( ) + { + float x= sobol_sample_float(d, n, scrambles[d]); + d++; + return x; + } + + unsigned n; + unsigned d; + +protected: + std::array<unsigned, sobol_matrices_size> scrambles; +}; + + +struct SobolGray +{ + SobolGray( ) = default; + + SobolGray( const unsigned seed ) : n(0), d(0), scrambles(), points(), code(0), bit(0) + { + FCRNG rng(seed); + for(unsigned d= 0; d < sobol_matrices_size; d++) + scrambles[d]= rng.sample_int() ; + } + + SobolGray& index( const unsigned i ) + { + assert(i == 0 || i == n+1); + + n= i; + d= 0; + + // previous state + if(i == 0) + return *this; + + unsigned ncode= graycode(i); + bit= trailing_zeroes(code ^ ncode); + code= ncode; + return *this; + } + + float sample( ) + { + if(n > 0) + points[d]= points[d] ^ sobol_matrices[d][bit]; + + float x= uint_to_float(points[d] ^ scrambles[d]); + d++; + return x; + } + + unsigned n; + unsigned d; + +protected: + std::array<unsigned, sobol_matrices_size> scrambles; + std::array<unsigned, sobol_matrices_size> points; + unsigned code; + unsigned bit; +}; + + +struct Owen +{ + Owen( ) = default; + + Owen( const unsigned seed ) : n(0), d(0), scrambles() + { + FCRNG rng(seed); + for(unsigned d= 0; d < sobol_matrices_size; d++) + scrambles[d]= rng.sample_int(); + } + + Owen& index( const unsigned i ) + { + n= i; + d= 0; + return *this; + } + + float sample( ) + { + float x= uint_to_float( owen_scramble( sobol_sample(d, n), scrambles[d]) ); + d++; + return x; + } + + unsigned n; + unsigned d; + +protected: + std::array<unsigned, sobol_matrices_size> scrambles; +}; + + +struct OwenFast +{ + OwenFast( ) = default; + + OwenFast( const unsigned seed ) : n(0), d(0), scrambles() + { + FCRNG rng(seed); + for(unsigned d= 0; d < sobol_matrices_size; d++) + scrambles[d]= rng.sample_int(); + } + + OwenFast& index( const unsigned i ) + { + n= i; + d= 0; + return *this; + } + + float sample( ) + { + float x= uint_to_float( owen_scramble_fast4( sobol_sample(d, n), scrambles[d]) ); + d++; + return x; + } + + unsigned n; + unsigned d; + +protected: + std::array<unsigned, sobol_matrices_size> scrambles; +}; + +#endif diff --git a/code/projects/sobol_matrices.cpp b/code/projects/sobol_matrices.cpp new file mode 100644 index 0000000000000000000000000000000000000000..988dd0544b8b7dd8641d366d5aabfd2384c676bd --- /dev/null +++ b/code/projects/sobol_matrices.cpp @@ -0,0 +1,133 @@ + +#include <array> + +std::array<unsigned, 32> sobol_matrices[128] { + { 0x80000000, 0x40000000, 0x20000000, 0x10000000, 0x08000000, 0x04000000, 0x02000000, 0x01000000, 0x00800000, 0x00400000, 0x00200000, 0x00100000, 0x00080000, 0x00040000, 0x00020000, 0x00010000, 0x00008000, 0x00004000, 0x00002000, 0x00001000, 0x00000800, 0x00000400, 0x00000200, 0x00000100, 0x00000080, 0x00000040, 0x00000020, 0x00000010, 0x00000008, 0x00000004, 0x00000002, 0x00000001 }, + { 0x80000000, 0xc0000000, 0xa0000000, 0xf0000000, 0x88000000, 0xcc000000, 0xaa000000, 0xff000000, 0x80800000, 0xc0c00000, 0xa0a00000, 0xf0f00000, 0x88880000, 0xcccc0000, 0xaaaa0000, 0xffff0000, 0x80008000, 0xc000c000, 0xa000a000, 0xf000f000, 0x88008800, 0xcc00cc00, 0xaa00aa00, 0xff00ff00, 0x80808080, 0xc0c0c0c0, 0xa0a0a0a0, 0xf0f0f0f0, 0x88888888, 0xcccccccc, 0xaaaaaaaa, 0xffffffff }, + { 0x80000000, 0xc0000000, 0x60000000, 0x90000000, 0xe8000000, 0x5c000000, 0x8e000000, 0xc5000000, 0x68800000, 0x9cc00000, 0xee600000, 0x55900000, 0x80680000, 0xc09c0000, 0x60ee0000, 0x90550000, 0xe8808000, 0x5cc0c000, 0x8e606000, 0xc5909000, 0x6868e800, 0x9c9c5c00, 0xeeee8e00, 0x5555c500, 0x8000e880, 0xc0005cc0, 0x60008e60, 0x9000c590, 0xe8006868, 0x5c009c9c, 0x8e00eeee, 0xc5005555 }, + { 0x80000000, 0xc0000000, 0x20000000, 0x50000000, 0xf8000000, 0x74000000, 0xa2000000, 0x93000000, 0xd8800000, 0x25400000, 0x59e00000, 0xe6d00000, 0x78080000, 0xb40c0000, 0x82020000, 0xc3050000, 0x208f8000, 0x51474000, 0xfbea2000, 0x75d93000, 0xa0858800, 0x914e5400, 0xdbe79e00, 0x25db6d00, 0x58800080, 0xe54000c0, 0x79e00020, 0xb6d00050, 0x800800f8, 0xc00c0074, 0x200200a2, 0x50050093 }, + { 0x80000000, 0x40000000, 0x20000000, 0xb0000000, 0xf8000000, 0xdc000000, 0x7a000000, 0x9d000000, 0x5a800000, 0x2fc00000, 0xa1600000, 0xf0b00000, 0xda880000, 0x6fc40000, 0x81620000, 0x40bb0000, 0x22878000, 0xb3c9c000, 0xfb65a000, 0xddb2d000, 0x78022800, 0x9c0b3c00, 0x5a0fb600, 0x2d0ddb00, 0xa2878080, 0xf3c9c040, 0xdb65a020, 0x6db2d0b0, 0x800228f8, 0x400b3cdc, 0x200fb67a, 0xb00ddb9d }, + { 0x80000000, 0x40000000, 0x60000000, 0x30000000, 0xc8000000, 0x24000000, 0x56000000, 0xfb000000, 0xe0800000, 0x70400000, 0xa8600000, 0x14300000, 0x9ec80000, 0xdf240000, 0xb6d60000, 0x8bbb0000, 0x48008000, 0x64004000, 0x36006000, 0xcb003000, 0x2880c800, 0x54402400, 0xfe605600, 0xef30fb00, 0x7e48e080, 0xaf647040, 0x1eb6a860, 0x9f8b1430, 0xd6c81ec8, 0xbb249f24, 0x80d6d6d6, 0x40bbbbbb }, + { 0x80000000, 0xc0000000, 0xa0000000, 0xd0000000, 0x58000000, 0x94000000, 0x3e000000, 0xe3000000, 0xbe800000, 0x23c00000, 0x1e200000, 0xf3100000, 0x46780000, 0x67840000, 0x78460000, 0x84670000, 0xc6788000, 0xa784c000, 0xd846a000, 0x5467d000, 0x9e78d800, 0x33845400, 0xe6469e00, 0xb7673300, 0x20f86680, 0x104477c0, 0xf8668020, 0x4477c010, 0x668020f8, 0x77c01044, 0x8020f866, 0xc0104477 }, + { 0x80000000, 0x40000000, 0xa0000000, 0x50000000, 0x88000000, 0x24000000, 0x12000000, 0x2d000000, 0x76800000, 0x9e400000, 0x08200000, 0x64100000, 0xb2280000, 0x7d140000, 0xfea20000, 0xba490000, 0x1a248000, 0x491b4000, 0xc4b5a000, 0xe3739000, 0xf6800800, 0xde400400, 0xa8200a00, 0x34100500, 0x3a280880, 0x59140240, 0xeca20120, 0x974902d0, 0x6ca48768, 0xd75b49e4, 0xcc95a082, 0x87639641 }, + { 0x80000000, 0x40000000, 0xa0000000, 0x50000000, 0x28000000, 0xd4000000, 0x6a000000, 0x71000000, 0x38800000, 0x58400000, 0xea200000, 0x31100000, 0x98a80000, 0x08540000, 0xc22a0000, 0xe5250000, 0xf2b28000, 0x79484000, 0xfaa42000, 0xbd731000, 0x18a80800, 0x48540400, 0x622a0a00, 0xb5250500, 0xdab28280, 0xad484d40, 0x90a426a0, 0xcc731710, 0x20280b88, 0x10140184, 0x880a04a2, 0x84350611 }, + { 0x80000000, 0x40000000, 0xe0000000, 0xb0000000, 0x98000000, 0x94000000, 0x8a000000, 0x5b000000, 0x33800000, 0xd9c00000, 0x72200000, 0x3f100000, 0xc1b80000, 0xa6ec0000, 0x53860000, 0x29f50000, 0x0a3a8000, 0x1b2ac000, 0xd392e000, 0x69ff7000, 0xea380800, 0xab2c0400, 0x4ba60e00, 0xfde50b00, 0x60028980, 0xf006c940, 0x7834e8a0, 0x241a75b0, 0x123a8b38, 0xcf2ac99c, 0xb992e922, 0x82ff78f1 }, + { 0x80000000, 0x40000000, 0xa0000000, 0x10000000, 0x08000000, 0x6c000000, 0x9e000000, 0x23000000, 0x57800000, 0xadc00000, 0x7fa00000, 0x91d00000, 0x49880000, 0xced40000, 0x880a0000, 0x2c0f0000, 0x3e0d8000, 0x3317c000, 0x5fb06000, 0xc1f8b000, 0xe18d8800, 0xb2d7c400, 0x1e106a00, 0x6328b100, 0xf7858880, 0xbdc3c2c0, 0x77ba63e0, 0xfdf7b330, 0xd7800df8, 0xedc0081c, 0xdfa0041a, 0x81d00a2d }, + { 0x80000000, 0x40000000, 0x20000000, 0x30000000, 0x58000000, 0xac000000, 0x96000000, 0x2b000000, 0xd4800000, 0x09400000, 0xe2a00000, 0x52500000, 0x4e280000, 0xc71c0000, 0x629e0000, 0x12670000, 0x6e138000, 0xf731c000, 0x3a98a000, 0xbe449000, 0xf83b8800, 0xdc2dc400, 0xee06a200, 0xb7239300, 0x1aa80d80, 0x8e5c0ec0, 0xa03e0b60, 0x703701b0, 0x783b88c8, 0x9c2dca54, 0xce06a74a, 0x87239795 }, + { 0x80000000, 0xc0000000, 0xa0000000, 0x50000000, 0xf8000000, 0x8c000000, 0xe2000000, 0x33000000, 0x0f800000, 0x21400000, 0x95a00000, 0x5e700000, 0xd8080000, 0x1c240000, 0xba160000, 0xef370000, 0x15868000, 0x9e6fc000, 0x781b6000, 0x4c349000, 0x420e8800, 0x630bcc00, 0xf7ad6a00, 0xad739500, 0x77800780, 0x6d4004c0, 0xd7a00420, 0x3d700630, 0x2f880f78, 0xb1640ad4, 0xcdb6077a, 0x824706d7 }, + { 0x80000000, 0xc0000000, 0x60000000, 0x90000000, 0x38000000, 0xc4000000, 0x42000000, 0xa3000000, 0xf1800000, 0xaa400000, 0xfce00000, 0x85100000, 0xe0080000, 0x500c0000, 0x58060000, 0x54090000, 0x7a038000, 0x670c4000, 0xb3842000, 0x094a3000, 0x0d6f1800, 0x2f5aa400, 0x1ce7ce00, 0xd5145100, 0xb8000080, 0x040000c0, 0x22000060, 0x33000090, 0xc9800038, 0x6e4000c4, 0xbee00042, 0x261000a3 }, + { 0x80000000, 0x40000000, 0x20000000, 0xf0000000, 0xa8000000, 0x54000000, 0x9a000000, 0x9d000000, 0x1e800000, 0x5cc00000, 0x7d200000, 0x8d100000, 0x24880000, 0x71c40000, 0xeba20000, 0x75df0000, 0x6ba28000, 0x35d14000, 0x4ba3a000, 0xc5d2d000, 0xe3a16800, 0x91db8c00, 0x79aef200, 0x0cdf4100, 0x672a8080, 0x50154040, 0x1a01a020, 0xdd0dd0f0, 0x3e83e8a8, 0xaccacc54, 0xd52d529a, 0xd91d919d }, + { 0x80000000, 0xc0000000, 0x20000000, 0xd0000000, 0xd8000000, 0xc4000000, 0x46000000, 0x85000000, 0xa5800000, 0x76c00000, 0xada00000, 0x6ab00000, 0x2da80000, 0xaabc0000, 0x0daa0000, 0x7ab10000, 0xd5a78000, 0xbebd4000, 0x93a3e000, 0x3bb51000, 0x3629b800, 0x4d727c00, 0x9b836200, 0x27c4d700, 0xb629b880, 0x8d727cc0, 0xbb836220, 0xf7c4d7d0, 0x6e29b858, 0x49727c04, 0xfd836266, 0x72c4d755 }, + { 0x80000000, 0x40000000, 0x20000000, 0xf0000000, 0x38000000, 0x14000000, 0xf6000000, 0x67000000, 0x8f800000, 0x50400000, 0x8aa00000, 0x0ff00000, 0x12a80000, 0xabf40000, 0xfcaa0000, 0x28fb0000, 0xbd298000, 0x0bba4000, 0x4e06e000, 0x330c3000, 0x59861800, 0xc74d3400, 0x3d2cb200, 0x4bb2cb00, 0x6e061880, 0xc30d3440, 0x618cb220, 0xd342cbf0, 0xcb2e18b8, 0x2cb93454, 0xe186b2d6, 0x9349cb97 }, + { 0x80000000, 0xc0000000, 0x20000000, 0xf0000000, 0x68000000, 0x64000000, 0x36000000, 0x6d000000, 0x41800000, 0xe0400000, 0xd2e00000, 0x9bf00000, 0x0ce80000, 0x52fc0000, 0x5b6a0000, 0x2fb30000, 0xa00c8000, 0x30054000, 0x4807e000, 0x940f9000, 0x5e01f800, 0x090e9400, 0x778a5600, 0x8d416b00, 0x9369f880, 0x7bb294c0, 0xde005620, 0xc9026bf0, 0x578d78e8, 0x7d4bd4a4, 0xfb6db616, 0x1fbefb9d }, + { 0x80000000, 0x40000000, 0xa0000000, 0x50000000, 0x98000000, 0xf4000000, 0xae000000, 0xbb000000, 0xe7800000, 0x95c00000, 0x1c200000, 0xd0300000, 0xdba80000, 0x55f40000, 0xff820000, 0x21c10000, 0x12238000, 0x3b3a4000, 0xa42b6000, 0x3430f000, 0x4da69800, 0x4af3ec00, 0x2e043a00, 0xfb0a1f00, 0x47851880, 0xc5c9ac40, 0x842f5aa0, 0x243aef50, 0x75a38018, 0xeefa40b4, 0x180b600e, 0xb400f0eb }, + { 0x80000000, 0xc0000000, 0xe0000000, 0xb0000000, 0xb8000000, 0x3c000000, 0xce000000, 0x41000000, 0x21800000, 0x51c00000, 0x09600000, 0x85700000, 0xf2780000, 0x8e9c0000, 0x60020000, 0x70030000, 0x58038000, 0x8c02c000, 0x7602e000, 0x7d00f000, 0xef833800, 0x10c10400, 0x28e08600, 0xd4b14700, 0xfb182580, 0x0bee15c0, 0x9279c9e0, 0xfe9d3a70, 0x38000008, 0xfc00000c, 0x2e00000e, 0xf100000b }, + { 0x80000000, 0xc0000000, 0xe0000000, 0xd0000000, 0x68000000, 0x3c000000, 0x8a000000, 0x51000000, 0xa9800000, 0xddc00000, 0x5ba00000, 0x39d00000, 0x95f80000, 0x56d40000, 0x0a020000, 0x91030000, 0x49838000, 0x0dc34000, 0x33a1a000, 0x05d0f000, 0x1ffa2800, 0x07d54400, 0xa380a600, 0x4cc07700, 0x1222ee80, 0x3413a740, 0xa65bf7e0, 0x5305ab50, 0x15f80008, 0x96d4000c, 0xea02000e, 0x4103000d }, + { 0x80000000, 0x40000000, 0x60000000, 0xd0000000, 0x38000000, 0x8c000000, 0x7e000000, 0x71000000, 0xc8800000, 0x04c00000, 0x1ba00000, 0xbb700000, 0x4a980000, 0xc3bc0000, 0xa6020000, 0x6d010000, 0xee818000, 0x29c34000, 0x9520e000, 0x42b23000, 0xe7b9f800, 0x0d0dc400, 0x3fb92200, 0x110d1300, 0x19bbee80, 0x3c0cadc0, 0x973a4a60, 0xc5cf7ef0, 0x3a180008, 0x0b7c0004, 0xa3a20006, 0x7771000d }, + { 0x80000000, 0xc0000000, 0xa0000000, 0x90000000, 0x08000000, 0x64000000, 0x6a000000, 0x89000000, 0xa5800000, 0xcb400000, 0x18200000, 0xad900000, 0xaf880000, 0x72f40000, 0x25820000, 0x0b430000, 0xb8228000, 0x3d924000, 0xa7882000, 0x16f59000, 0x4f83a800, 0x82412400, 0x1da01600, 0xf6d16d00, 0xbfa84080, 0xbb672640, 0xe0091620, 0xf0b4efd0, 0x38228008, 0xfd92400c, 0x0788200a, 0x86f59009 }, + { 0x80000000, 0xc0000000, 0x20000000, 0xd0000000, 0x48000000, 0x8c000000, 0xd6000000, 0x39000000, 0xd5800000, 0x32400000, 0xb2a00000, 0x72100000, 0x53d80000, 0x82cc0000, 0xcb820000, 0x47430000, 0x91208000, 0xa9534000, 0x7cf92000, 0x4e9e3000, 0xfcf95800, 0x8e9fe400, 0xdcf9d600, 0x5e9c8900, 0x94f96a80, 0xd29fb840, 0x42f9b760, 0xeb9c9f30, 0x97788008, 0xd9df400c, 0x25db2002, 0xabcd300d }, + { 0x80000000, 0xc0000000, 0x20000000, 0x50000000, 0xd8000000, 0xf4000000, 0x3e000000, 0x95000000, 0x8f800000, 0x3d400000, 0xf3200000, 0x2ef00000, 0xadc80000, 0x0a0c0000, 0x8b220000, 0x4af30000, 0x6bc88000, 0x3b0d4000, 0xe2a16000, 0x16b0d000, 0x29687800, 0xbdbf1400, 0x33cb5e00, 0x0f0c2500, 0xfca1b480, 0xd3b0afc0, 0x7eeb6920, 0x74fe4d30, 0xfee87808, 0xb4ff140c, 0xdeeb5e02, 0xe4fc2505 }, + { 0x80000000, 0x40000000, 0xa0000000, 0xb0000000, 0x98000000, 0xa4000000, 0x7a000000, 0xd5000000, 0x02800000, 0x60400000, 0x51e00000, 0x88700000, 0x8c280000, 0x47c40000, 0x0be20000, 0xad710000, 0xb6aa8000, 0x3386c000, 0xb8006000, 0x54039000, 0x42036800, 0xc1019400, 0xe0826a00, 0x11431100, 0x2960af80, 0x3d3175c0, 0xdf4a3aa0, 0xaff49e10, 0xd62b6808, 0x62c59404, 0x31606a0a, 0xd932110b }, + { 0x80000000, 0xc0000000, 0xa0000000, 0x30000000, 0x18000000, 0x34000000, 0x8a000000, 0x9d000000, 0x67800000, 0x82400000, 0x40e00000, 0x60f00000, 0x91480000, 0x29440000, 0x2d620000, 0xbfb30000, 0x162a8000, 0xfbf4c000, 0xe4ca6000, 0xc207d000, 0x2002a800, 0xf001b400, 0xb8037e00, 0x04021900, 0x92034b80, 0xa90327c0, 0xed81f320, 0x1f40d810, 0x27602808, 0xe2b1740c, 0xd1ab1e0a, 0x49b6c903 }, + { 0x80000000, 0x40000000, 0xe0000000, 0xd0000000, 0x08000000, 0x4c000000, 0x02000000, 0xb5000000, 0x36800000, 0xc2c00000, 0x14200000, 0x07500000, 0x1bf80000, 0x50340000, 0x48a20000, 0xac910000, 0xd35b8000, 0xbca74000, 0x7bfa2000, 0xc0343000, 0xa0a18800, 0x30909400, 0xd95b7a00, 0x45a57b00, 0x4f7a7880, 0xb7f6f940, 0x82013de0, 0xf502dfd0, 0xd6820808, 0x12c3d404, 0x1c235a0e, 0x4b504b0d }, + { 0x80000000, 0xc0000000, 0xe0000000, 0x50000000, 0x68000000, 0x4c000000, 0x76000000, 0xf7000000, 0x36800000, 0xd7400000, 0x87e00000, 0xef300000, 0xa3a80000, 0xd5440000, 0x23aa0000, 0x15470000, 0xc3a98000, 0x45464000, 0xaba82000, 0x09477000, 0xdda9f800, 0xfe44ac00, 0xeb292200, 0x2907f100, 0x6ccb3d80, 0xc6344dc0, 0xcf61b320, 0x137318d0, 0xeccb3d88, 0x06344dcc, 0x2f61b32e, 0x437318d5 }, + { 0x80000000, 0x40000000, 0x60000000, 0x90000000, 0xc8000000, 0x74000000, 0x52000000, 0x03000000, 0xeb800000, 0x6f400000, 0x64600000, 0xdaf00000, 0x17980000, 0x297c0000, 0xa59a0000, 0xfa7d0000, 0xe61b8000, 0x713f4000, 0x1878a000, 0xdcce9000, 0xb661e800, 0x99f29c00, 0x9c184600, 0xd63e2100, 0x09fa5780, 0x548e0ac0, 0xa380a9e0, 0x5b413f30, 0x56625788, 0x49f20ac4, 0x341aa9e6, 0x323c3f39 }, + { 0x80000000, 0xc0000000, 0xa0000000, 0xd0000000, 0xb8000000, 0x04000000, 0x6e000000, 0x97000000, 0xf2800000, 0xedc00000, 0x13600000, 0x5c900000, 0xdb580000, 0x31e40000, 0x09da0000, 0xcc270000, 0x02b88000, 0x44b44000, 0x0fe26000, 0xe6505000, 0x9ab9d800, 0x50b50c00, 0x79e29200, 0xa552fb00, 0xbe38bf80, 0x2e77d940, 0xf6000ae0, 0x830112d0, 0x84803f88, 0xaec3994c, 0x37e26aea, 0x225142dd }, + { 0x80000000, 0xc0000000, 0xe0000000, 0x30000000, 0x68000000, 0xec000000, 0x22000000, 0x2b000000, 0x36800000, 0x9d400000, 0x6a200000, 0x16700000, 0x4de80000, 0x330c0000, 0x936a0000, 0x824f0000, 0x3b498000, 0x8f3fc000, 0x28202000, 0xcd707000, 0xf36aa800, 0x724fdc00, 0xb34bf200, 0x533e6900, 0x62207a80, 0x0a7140c0, 0xe7ea6520, 0xc40d90f0, 0xefe9fa88, 0xd80e80cc, 0x45ea452e, 0x2f0de0f3 }, + { 0x80000000, 0xc0000000, 0x20000000, 0x30000000, 0x28000000, 0xd4000000, 0x8a000000, 0xff000000, 0x84800000, 0x73c00000, 0x13200000, 0xc2b00000, 0xfb380000, 0x361c0000, 0x401a0000, 0xe0af0000, 0x11228000, 0x19b3c000, 0xfdb82000, 0x5edf9000, 0x75b88800, 0x7adfac00, 0xf7baba00, 0x61ddf300, 0xd1387e80, 0x391e55c0, 0xcc9ba860, 0x776cbeb0, 0xa000f688, 0xf001f9cc, 0x08011262, 0xe4014db3 }, + { 0x80000000, 0x40000000, 0xa0000000, 0x50000000, 0xb8000000, 0x84000000, 0x1a000000, 0xaf000000, 0xbd800000, 0xdfc00000, 0x14e00000, 0x43500000, 0xda380000, 0x4e1c0000, 0x4cda0000, 0x364d0000, 0x29608000, 0xdc904000, 0x6ed86000, 0x5d4f5000, 0x2ee08800, 0xfc51ac00, 0x7fb81e00, 0x45dc8300, 0xfa3a4580, 0x5e1d6240, 0x54dbd360, 0xe24ec930, 0x8b62cd88, 0xf790ce44, 0xc959cd6a, 0x2d8f4a35 }, + { 0x80000000, 0x40000000, 0xe0000000, 0x70000000, 0x08000000, 0xf4000000, 0xf6000000, 0x8b000000, 0xc9800000, 0x55400000, 0x67200000, 0xf3f00000, 0x34780000, 0x57440000, 0x1ada0000, 0xb1f50000, 0xa9818000, 0x6540c000, 0x8f23a000, 0x77f21000, 0xca7bf800, 0x2845fc00, 0x255afe00, 0x6fb67900, 0x07233a80, 0xc3f25ac0, 0xdc7aed60, 0xd34482d0, 0xe4d94288, 0xcef766c4, 0x9603b36e, 0xbb00ebd7 }, + { 0x80000000, 0x40000000, 0xe0000000, 0x90000000, 0x68000000, 0xf4000000, 0x62000000, 0xdf000000, 0x79800000, 0xdd400000, 0x76e00000, 0x2cf00000, 0xcfb80000, 0x51ec0000, 0xc8da0000, 0x845d0000, 0x9b818000, 0x42434000, 0xef622000, 0x61b19000, 0xd1582800, 0x891cac00, 0x65626e00, 0x0ab10900, 0x2adbbd80, 0x1b5d86c0, 0x02014560, 0x0f032470, 0xf1821588, 0xb9426ac4, 0x7ce10b6e, 0x07f3bd79 }, + { 0x80000000, 0xc0000000, 0x60000000, 0x50000000, 0x18000000, 0xdc000000, 0x42000000, 0x37000000, 0x20800000, 0xf1400000, 0x28600000, 0x94900000, 0x87880000, 0xa83c0000, 0x556a0000, 0xe6ef0000, 0xf8038000, 0x4c024000, 0x3a01e000, 0xbb023000, 0x7a816800, 0x1a43ac00, 0x4ae18a00, 0x52d31900, 0x8f682380, 0xcded9740, 0xfa80bfa0, 0xda43f2b0, 0x2ae2cb88, 0x02d07b4c, 0x976ad5a6, 0x11eddbb5 }, + { 0x80000000, 0xc0000000, 0x20000000, 0xf0000000, 0xf8000000, 0x34000000, 0x62000000, 0xf5000000, 0xa8800000, 0xfcc00000, 0x8e200000, 0x53f00000, 0xc7780000, 0x95740000, 0xb8020000, 0xd4e50000, 0xb2808000, 0xfdc0c000, 0x64a02000, 0xaa30f000, 0x19d8f800, 0x0e443400, 0x935a6200, 0xe761f500, 0x657a2880, 0x40913cc0, 0xe0022e20, 0xd0e563f0, 0x08809f78, 0xccc09174, 0x56200202, 0x97f0e5e5 }, + { 0x80000000, 0xc0000000, 0xa0000000, 0xf0000000, 0xf8000000, 0xec000000, 0x7e000000, 0x61000000, 0x5c800000, 0xe6c00000, 0xdda00000, 0x2a700000, 0x93380000, 0x13cc0000, 0xd3ce0000, 0x73790000, 0x83a08000, 0x7b70c000, 0x97b8a000, 0xe90cf000, 0x886ef800, 0xd409ec00, 0x3218fe00, 0xef7ca100, 0xc556fc80, 0x56c516c0, 0x4556a5a0, 0x96c50670, 0xe556cd38, 0x66c542cc, 0x1d56574e, 0x8ac549b9 }, + { 0x80000000, 0xc0000000, 0x20000000, 0xb0000000, 0x58000000, 0x2c000000, 0x9a000000, 0xf9000000, 0x3c800000, 0xb2c00000, 0xad200000, 0x3a300000, 0x89980000, 0x448c0000, 0x2eea0000, 0x6f810000, 0xef208000, 0x2f30c000, 0x0f182000, 0xbf4cb000, 0xe74a5800, 0xcb712c00, 0x51981a00, 0xa88c3900, 0x94ea1c80, 0x268102c0, 0x8ba07520, 0xb1f0d630, 0x38383398, 0x7c7c0d8c, 0x52524a6a, 0x3d3df141 }, + { 0x80000000, 0xc0000000, 0x20000000, 0xb0000000, 0xd8000000, 0xac000000, 0x8e000000, 0x09000000, 0x9e800000, 0xa1c00000, 0xcaa00000, 0x33700000, 0x95780000, 0x085c0000, 0x24b60000, 0x6a350000, 0x43788000, 0x6d5cc000, 0x14362000, 0x72f5b000, 0xcf585800, 0x53ec6c00, 0xc5eeae00, 0x40d9b900, 0xe016c680, 0x9045cdc0, 0x6880e4a0, 0x74c04a70, 0x2220f3f8, 0x87b0b59c, 0x9758b816, 0x3fecfc45 }, + { 0x80000000, 0x40000000, 0xe0000000, 0xf0000000, 0xa8000000, 0x2c000000, 0xa2000000, 0x2d000000, 0xda800000, 0xf9400000, 0xec600000, 0x02b00000, 0x3d480000, 0x825c0000, 0x7d4a0000, 0x62610000, 0x8dc88000, 0xca1c4000, 0xa1aae000, 0x6891f000, 0x8c602800, 0xb2b06c00, 0x75484200, 0x5e5cdd00, 0x774a7280, 0x6361d540, 0xf548ce60, 0x1e5c6fb0, 0x974a07c8, 0x93618b1c, 0x5d48b92a, 0x325c0cd1 }, + { 0x80000000, 0xc0000000, 0xe0000000, 0x30000000, 0xc8000000, 0x7c000000, 0x82000000, 0x4f000000, 0xbe800000, 0xedc00000, 0x21600000, 0xab700000, 0x78680000, 0x746c0000, 0x1e9a0000, 0xfdcb0000, 0x39088000, 0x2f1cc000, 0x4ef2e000, 0xc5a73000, 0x6d924800, 0xe1d7bc00, 0x4b7ae200, 0x487bbf00, 0xbc801680, 0x62c061c0, 0x7fe08b60, 0x76b0a870, 0x91088ce8, 0xa31caaac, 0xe4f2037a, 0xc6a7f47b }, + { 0x80000000, 0xc0000000, 0x20000000, 0x10000000, 0x98000000, 0x2c000000, 0x06000000, 0xcd000000, 0x8a800000, 0x1bc00000, 0xffa00000, 0xad500000, 0x7af80000, 0xb3dc0000, 0x5b2e0000, 0x1f290000, 0x9d588000, 0xf28cc000, 0x07d62000, 0x71f51000, 0xd4f61800, 0xda65ec00, 0x632ea600, 0xe3291d00, 0x2358b280, 0x038ce7c0, 0x135641a0, 0x8b355c50, 0xa7d6ee78, 0xa1f5891c, 0x6cf6880e, 0xe665b4b9 }, + { 0x80000000, 0x40000000, 0xa0000000, 0x90000000, 0x98000000, 0x54000000, 0x3a000000, 0x9d000000, 0x7e800000, 0x7f400000, 0x17200000, 0xab500000, 0x6df80000, 0x96a40000, 0x83d20000, 0x71e10000, 0xc0d88000, 0xe0f44000, 0x30aaa000, 0x08059000, 0xcc2a1800, 0x6e451400, 0xa78a1a00, 0xe3554d00, 0x01d2c680, 0x68e1fb40, 0xbc589520, 0xc6b4b250, 0xfb0a1178, 0x1515b0e4, 0xf272c872, 0xb1f12cf1 }, + { 0x80000000, 0xc0000000, 0xe0000000, 0xb0000000, 0x08000000, 0x84000000, 0xb2000000, 0xb9000000, 0xbe800000, 0x4fc00000, 0x55600000, 0xf8f00000, 0xac280000, 0x66d40000, 0xb30a0000, 0x8bb50000, 0xc7c88000, 0x11e4c000, 0xaa42e000, 0xa591b000, 0xd0ea8800, 0x78854400, 0x6c80d200, 0x86c0c900, 0x03e05680, 0x83307bc0, 0x4348ef60, 0xa324c5f0, 0x13a2a0a8, 0x1ba19014, 0x9f22d8ea, 0x2d61fc85 }, + { 0x80000000, 0xc0000000, 0x60000000, 0x30000000, 0x78000000, 0x24000000, 0x9e000000, 0x47000000, 0x67800000, 0xf7400000, 0xdf200000, 0xb3100000, 0x71680000, 0x8c4c0000, 0x32520000, 0xe5d50000, 0xaa528000, 0x31d5c000, 0x2c52e000, 0x62d5f000, 0xadd29800, 0xf695d400, 0x8b720600, 0xf5c59300, 0x42ba6180, 0x3dd96440, 0xdea0bea0, 0xe750d750, 0x37c84fc8, 0xbf1c9b1c, 0x839a1d9a, 0x09c94ec9 }, + { 0x80000000, 0xc0000000, 0xe0000000, 0xb0000000, 0x78000000, 0x9c000000, 0xee000000, 0x1b000000, 0xcb800000, 0xc3400000, 0xc7a00000, 0x05100000, 0x88680000, 0xc4740000, 0x225a0000, 0x3da10000, 0x345a8000, 0x7aa1c000, 0xf1da6000, 0x12e17000, 0x85fa1800, 0x48b1ec00, 0x2432f600, 0x92d5f700, 0x45803d80, 0xa8403440, 0x94207a20, 0xea50f150, 0xd9c81248, 0x46648524, 0x8fb24812, 0x21952485 }, + { 0x80000000, 0x40000000, 0x60000000, 0x10000000, 0x58000000, 0x7c000000, 0xc2000000, 0xe1000000, 0x0d800000, 0xd7c00000, 0x2aa00000, 0xf5300000, 0x9ba80000, 0xc0f40000, 0x20c60000, 0x702f0000, 0x48668000, 0x241f4000, 0xbe4ee000, 0x232b5000, 0xec28b800, 0xda342c00, 0xfde6fa00, 0xdfdf8d00, 0x6eee1780, 0x5b1b0ac0, 0xe0000520, 0x500093f0, 0x38008488, 0x6c008e04, 0x9a000bce, 0x9d00d8eb }, + { 0x80000000, 0x40000000, 0x20000000, 0x30000000, 0xb8000000, 0xac000000, 0x72000000, 0xb1000000, 0x03800000, 0xd2c00000, 0xc1600000, 0x9b900000, 0x4e480000, 0x0b740000, 0x864e0000, 0x3f0b0000, 0x68068000, 0x447f4000, 0x7648a000, 0xe7747000, 0xd44e9800, 0xbe0b9c00, 0xd3864a00, 0x3abf5d00, 0xc528d180, 0xcde413c0, 0x99865ae0, 0x67bfd550, 0x94a8c528, 0x9e24cde4, 0xe3669986, 0x82ef67bf }, + { 0x80000000, 0xc0000000, 0xe0000000, 0x70000000, 0x88000000, 0x44000000, 0x4a000000, 0x47000000, 0xdd800000, 0x42400000, 0xc3200000, 0x77100000, 0x75b80000, 0x966c0000, 0x715e0000, 0xfc950000, 0xa6e68000, 0xd9f9c000, 0x28386000, 0x142cb000, 0x527e6800, 0xfb853400, 0x5b5e4200, 0x0b95c300, 0x1366f780, 0xafb9b540, 0x2918f6a0, 0x603cc150, 0xb0469498, 0x68a9927c, 0x34a09b66, 0xc250ebb9 }, + { 0x80000000, 0xc0000000, 0x20000000, 0x50000000, 0xd8000000, 0xfc000000, 0xf6000000, 0xd5000000, 0xbf800000, 0x2c400000, 0xeee00000, 0x09700000, 0x19080000, 0x21640000, 0xad6a0000, 0xd3130000, 0x22828000, 0x9707c000, 0x98e0a000, 0x1c709000, 0x8688f800, 0x5d24ac00, 0x9b8a2e00, 0x26632900, 0xcd8ac980, 0x63633940, 0x8a0af160, 0xe323b530, 0x4aea8fe8, 0xc3534414, 0x1a623a62, 0x1b774b77 }, + { 0x80000000, 0x40000000, 0x60000000, 0x50000000, 0x58000000, 0xac000000, 0x6a000000, 0x85000000, 0xfb800000, 0xa8c00000, 0x84200000, 0xae300000, 0x4b080000, 0xe0740000, 0x10860000, 0x388f0000, 0xfc2e8000, 0x320b4000, 0x2980e000, 0x91c01000, 0x2da03800, 0x7ff0fc00, 0x06a83200, 0xcf842900, 0x4e2e9180, 0x5b0b2dc0, 0xd800ffa0, 0xec0046f0, 0x0a00af28, 0xd5001e44, 0xa380038e, 0x04c074fb }, + { 0x80000000, 0xc0000000, 0xa0000000, 0x50000000, 0xe8000000, 0x44000000, 0x5e000000, 0xad000000, 0xef800000, 0x68400000, 0x84600000, 0xfe500000, 0xfd280000, 0x07f40000, 0x2c620000, 0xda4f0000, 0x53068000, 0x12dfc000, 0x6f802000, 0xa8403000, 0x24602800, 0xae501400, 0x15283a00, 0x43f41100, 0x72621780, 0x774f2b40, 0xbc86bbe0, 0x7a9fda10, 0xebe00118, 0x56100f94, 0xd948174a, 0xa9a415fd }, + { 0x80000000, 0xc0000000, 0x60000000, 0xb0000000, 0x18000000, 0x04000000, 0xda000000, 0x09000000, 0x22800000, 0xe8400000, 0xbc600000, 0x0e300000, 0x7b580000, 0x378c0000, 0x14c20000, 0x874d0000, 0x99d48000, 0xbfb94000, 0x18802000, 0x91403000, 0xe6e01800, 0x52702c00, 0x05380600, 0x34bc0100, 0x971a3680, 0x51810240, 0x13f688a0, 0xde847a10, 0x466c8f18, 0x1745738c, 0x91fa26d6, 0x73f111e3 }, + { 0x80000000, 0x40000000, 0x20000000, 0x50000000, 0x88000000, 0x9c000000, 0x2e000000, 0x05000000, 0xab800000, 0x1c400000, 0x6e200000, 0x25100000, 0xfba80000, 0x94040000, 0xf26e0000, 0x0b070000, 0xfeaa8000, 0x3fd1c000, 0xee202000, 0x65101000, 0xdba80800, 0xc4041400, 0x7a6e2200, 0x97072700, 0xd0aa8b80, 0x3ad1c140, 0x45a00ae0, 0x79501710, 0xb5881388, 0xe1141d44, 0x81c61cea, 0x03030201 }, + { 0x80000000, 0xc0000000, 0x20000000, 0x50000000, 0xc8000000, 0x3c000000, 0x3e000000, 0x67000000, 0xf9800000, 0xcc400000, 0x66600000, 0xb3100000, 0xaba80000, 0x5d240000, 0xc4fe0000, 0xb8cf0000, 0x66bb8000, 0x71a8c000, 0x10602000, 0x28103000, 0x4c280800, 0xa6641400, 0x931e3200, 0xfb9f0f00, 0x95738f80, 0xf89cd9c0, 0x86b61e60, 0x01bb0310, 0x880d9198, 0xdc13f8c4, 0x4e6db8ea, 0xff03e849 }, + { 0x80000000, 0x40000000, 0x20000000, 0xb0000000, 0x58000000, 0x44000000, 0x7e000000, 0x69000000, 0x5b800000, 0xdc400000, 0x5a200000, 0x87100000, 0xdad80000, 0x9bec0000, 0xbc420000, 0xca0f0000, 0x6f7c8000, 0xc6d9c000, 0xa1a02000, 0xab501000, 0xf8f80800, 0xe8fc2c00, 0x409a1600, 0x7ce31100, 0xf6be9f80, 0xb996da40, 0xcf7cb6e0, 0x36d9e710, 0xd9a03e88, 0x5f501dc4, 0xdef828b6, 0xc5fc1bfb }, + { 0x80000000, 0x40000000, 0xa0000000, 0xb0000000, 0x48000000, 0x74000000, 0xc2000000, 0xe7000000, 0xb5800000, 0xba400000, 0x9b200000, 0xa3d00000, 0x2f180000, 0x81840000, 0xd82a0000, 0xcc190000, 0x5e078000, 0xe138c000, 0xd8982000, 0x9cc41000, 0x568a2800, 0x65892c00, 0xa23f9200, 0xb76cdd00, 0xedaa1080, 0x365929c0, 0x65278560, 0xf2e8c290, 0xbf8014c8, 0x694025f4, 0x4ca01346, 0x4e9035a1 }, + { 0x80000000, 0x40000000, 0xa0000000, 0xf0000000, 0x98000000, 0xb4000000, 0x52000000, 0x07000000, 0xbf800000, 0x5a400000, 0x3b200000, 0x91d00000, 0xd3380000, 0xfdec0000, 0x954a0000, 0x58f10000, 0xb5df8000, 0x091dc000, 0x86b82000, 0xa4ac1000, 0x7bea2800, 0xd0613c00, 0x2847a600, 0x8c61ed00, 0x166a3480, 0xcd2111c0, 0x0ce787e0, 0xb7f1ea90, 0x667208c8, 0x151d1974, 0x1895884e, 0x15ecc2bb }, + { 0x80000000, 0xc0000000, 0xe0000000, 0x70000000, 0xf8000000, 0x4c000000, 0xa6000000, 0x89000000, 0x6e800000, 0x1a400000, 0x17600000, 0x4bf00000, 0xa2f80000, 0x7c5c0000, 0x7e360000, 0x551b0000, 0x40808000, 0x272d4000, 0x93982000, 0x7eac3000, 0x524e3800, 0x43071c00, 0xd1d6be00, 0x75c65300, 0xd7e08980, 0xacdd5240, 0xd16003a0, 0x72f02a90, 0xd47803d8, 0x5a1c1dfc, 0x37563f3e, 0xdbeb2e57 }, + { 0x80000000, 0x40000000, 0x20000000, 0x30000000, 0xb8000000, 0x3c000000, 0xde000000, 0xdf000000, 0x29800000, 0x32400000, 0xe9200000, 0x62900000, 0x71d80000, 0x5e3c0000, 0x9f2e0000, 0x09e70000, 0x026b8000, 0x5176c000, 0x5ef82000, 0xafac1000, 0x81760800, 0xb69b0c00, 0x3be5ae00, 0xeb41cf00, 0x33eb9780, 0x2f36e7c0, 0xf1d82260, 0x1e3c1090, 0xbf2e1c48, 0x39e71ba4, 0xba6b85f6, 0x6d76ef4f }, + { 0x80000000, 0x40000000, 0xa0000000, 0xd0000000, 0xf8000000, 0x3c000000, 0x6e000000, 0x19000000, 0x50800000, 0xca400000, 0x7b200000, 0xafd00000, 0x97a80000, 0x4b9c0000, 0x55ae0000, 0x64ef0000, 0xf0288000, 0x68524000, 0x64082000, 0x820c1000, 0x8f262800, 0x75a33400, 0xf4aebe00, 0xa8614f00, 0x842ebb80, 0xf2215640, 0xa70e9c20, 0xb1f15690, 0xa6a6a8c8, 0xdf6d40f4, 0xcd88886a, 0x68c27fa7 }, + { 0x80000000, 0x40000000, 0x60000000, 0xd0000000, 0xc8000000, 0xbc000000, 0x4e000000, 0x57000000, 0x80800000, 0x0a400000, 0xfd200000, 0x8db00000, 0xffa80000, 0xa6840000, 0x110e0000, 0x4bdf0000, 0x74d78000, 0xb8724000, 0x84082000, 0x8a741000, 0xbd061800, 0xedab3400, 0x2fd1b200, 0x6ed96f00, 0xad59b380, 0x05ed45c0, 0x23ff9820, 0x38b66690, 0x8e263548, 0x771b286c, 0x30f9866a, 0x121d6761 }, + { 0x80000000, 0x40000000, 0x20000000, 0xb0000000, 0xa8000000, 0xd4000000, 0xfa000000, 0xf9000000, 0x92800000, 0x19400000, 0x42a00000, 0x21500000, 0x8ef80000, 0xa7040000, 0x59920000, 0x36f90000, 0x2b2e8000, 0xffd04000, 0x51922000, 0x12f91000, 0x592e8800, 0x62d06c00, 0x91120a00, 0x26b92500, 0x730eb680, 0xa3c05240, 0xcfca2ea0, 0xb9ad2350, 0xe6c4a628, 0x136d5a14, 0x338e8d1e, 0xd7804a91 }, + { 0x80000000, 0x40000000, 0xe0000000, 0xb0000000, 0x58000000, 0x1c000000, 0x72000000, 0x4f000000, 0xa1800000, 0x77400000, 0x4da00000, 0xbd300000, 0xaef80000, 0x369c0000, 0x8ab60000, 0xa8850000, 0x0fe18000, 0xea0dc000, 0xf3362000, 0x83c51000, 0xd041b800, 0xa83dec00, 0xa44e3600, 0xde191700, 0x6557a480, 0xf288ffc0, 0xa4d79e60, 0x75c8cad0, 0x517797e8, 0x64f8c08c, 0xd58f8dde, 0x0164eb77 }, + { 0x80000000, 0x40000000, 0xa0000000, 0x50000000, 0x88000000, 0x34000000, 0xa2000000, 0x03000000, 0x41800000, 0xf7400000, 0x03a00000, 0x04100000, 0x9a080000, 0x4f140000, 0x0fb20000, 0xea550000, 0xd73b8000, 0x13a1c000, 0x2c122000, 0xfe451000, 0x6533a800, 0x38b5d400, 0x09a00200, 0x23101d00, 0x51880080, 0xdf5414c0, 0x67923260, 0x2e0530d0, 0xad13a868, 0xace5c1c4, 0xfb8816e2, 0xa8543e15 }, + { 0x80000000, 0x40000000, 0xe0000000, 0xd0000000, 0xb8000000, 0x1c000000, 0x82000000, 0xfb000000, 0xed800000, 0x87400000, 0xffa00000, 0x24300000, 0xde480000, 0x992c0000, 0xc6e60000, 0xd2dd0000, 0x64938000, 0x59a7c000, 0x01462000, 0xaaed1000, 0xd8dbb800, 0xeb8bf400, 0x92200e00, 0xe3701700, 0xc1e81880, 0x6d1c0ac0, 0xa0ae1560, 0x57f126d0, 0x20759f68, 0x707af7cc, 0x8855acf2, 0x740ad79b }, + { 0x80000000, 0xc0000000, 0xa0000000, 0x10000000, 0x48000000, 0xac000000, 0x06000000, 0x95000000, 0x05800000, 0xc9400000, 0x3be00000, 0x08100000, 0xcc680000, 0xb6740000, 0xcd5e0000, 0xe1a70000, 0x635c8000, 0xa8e1c000, 0x98be2000, 0x00b73000, 0x44b4a800, 0xfed5c400, 0x25803200, 0x19401b00, 0xd3e02980, 0xb4102140, 0x82681360, 0x8f741950, 0xcede0f78, 0xbde72744, 0x5d3cb27a, 0x69b1dfcd }, + { 0x80000000, 0x40000000, 0x60000000, 0xd0000000, 0xf8000000, 0x34000000, 0x1a000000, 0xff000000, 0xf3800000, 0x93400000, 0x2da00000, 0x3e700000, 0x3d480000, 0x88cc0000, 0x52b20000, 0x8d910000, 0xce358000, 0x750cc000, 0x94922000, 0x84a11000, 0x5cdd9800, 0xd8b0f400, 0xeae81e00, 0xd9bc1d00, 0x047a1e80, 0x721d0bc0, 0x532782e0, 0x0dede9d0, 0x8e6fade8, 0x1521e05c, 0x44dd8bb2, 0x7cb0e2e3 }, + { 0x80000000, 0xc0000000, 0x60000000, 0x10000000, 0x28000000, 0xfc000000, 0xb2000000, 0x5b000000, 0x3f800000, 0x7f400000, 0x89e00000, 0x22700000, 0xb3680000, 0xa3a40000, 0xdd360000, 0xfaad0000, 0xe1a38000, 0x7e6ec000, 0x71562000, 0xc09d3000, 0x36ab9800, 0xcbfac400, 0x81682a00, 0x38a40f00, 0x82b63480, 0x95ed12c0, 0x404385e0, 0xa01ee0d0, 0x703e2ef8, 0x38392e5c, 0xd41dbb3a, 0x4e17f339 }, + { 0x80000000, 0x40000000, 0x60000000, 0x30000000, 0x08000000, 0x4c000000, 0xf6000000, 0x7f000000, 0x76800000, 0x19400000, 0x11a00000, 0x7bf00000, 0x8af80000, 0xa7540000, 0x42ae0000, 0xcb170000, 0xe4a58000, 0x8c124000, 0xd6562000, 0x2f431000, 0x4e8b9800, 0x5d454c00, 0xabd3a200, 0xf2e14300, 0x83058580, 0xc8e243c0, 0x4a2e27a0, 0xa1570950, 0x1585a3e8, 0xa1a25e3c, 0x338e209e, 0xa6a73345 }, + { 0x80000000, 0x40000000, 0xa0000000, 0x70000000, 0xb8000000, 0x7c000000, 0x4a000000, 0xf3000000, 0x90800000, 0x81400000, 0x5fa00000, 0xfb900000, 0x5dd80000, 0x8cec0000, 0x5b360000, 0xc4b10000, 0xdf338000, 0x52974000, 0x166e2000, 0x891d1000, 0x7ba5a800, 0x1db65c00, 0x2c858e00, 0x2b664f00, 0x7cfd9a80, 0xa31a70c0, 0x18938220, 0xe5077350, 0x19b62368, 0xfaf11124, 0x4213a7d6, 0xd7477cab }, + { 0x80000000, 0x40000000, 0xa0000000, 0xb0000000, 0x88000000, 0xd4000000, 0xea000000, 0xb7000000, 0xf5800000, 0xa5400000, 0xfea00000, 0x7e900000, 0x3eb80000, 0x9ef40000, 0x2e820000, 0xa6d90000, 0x729d8000, 0x98c9c000, 0x2fba2000, 0xda6d1000, 0x7f3fa800, 0x81c0ec00, 0xff3f8200, 0xc1c0e500, 0x5f3fb280, 0x71c0d1c0, 0xd73f9760, 0xa5c0e050, 0x3d3faf28, 0x12c0fb64, 0xc8bfa24e, 0xb780ea2d }, + { 0x80000000, 0x40000000, 0x20000000, 0x50000000, 0x08000000, 0x34000000, 0x1a000000, 0xd1000000, 0xac800000, 0x57400000, 0x43a00000, 0x18d00000, 0x0d480000, 0xb2b40000, 0xe4620000, 0x52010000, 0xc5668000, 0xe6e94000, 0x8e0a2000, 0xdb251000, 0x55ec8800, 0x9f8c5400, 0x06c6a200, 0xbe395d00, 0xa3422e80, 0x39913040, 0xb98ea120, 0xf98d4cd0, 0xd9a03468, 0x89d02f74, 0x81c826f2, 0xb5f4193d }, + { 0x80000000, 0x40000000, 0x60000000, 0xf0000000, 0x08000000, 0xe4000000, 0xe6000000, 0x07000000, 0x10800000, 0x7d400000, 0x5da00000, 0x08f00000, 0x21180000, 0x37940000, 0xfdfa0000, 0xd8ef0000, 0xb9258000, 0x2be14000, 0xf7c22000, 0xddcb1000, 0x48e79800, 0x412a7c00, 0xc7a5a200, 0xf5a16900, 0x3ce20180, 0x5f7b2dc0, 0x2cdf9e20, 0xe70e5a50, 0xa0e78ce8, 0x152a6afc, 0x49a58de6, 0xe6a17f75 }, + { 0x80000000, 0xc0000000, 0x20000000, 0xb0000000, 0x38000000, 0xac000000, 0xa2000000, 0xcf000000, 0x57800000, 0x2fc00000, 0x63a00000, 0x51b00000, 0x16e80000, 0xd5740000, 0xf4e20000, 0xfa130000, 0x33448000, 0x5dc74000, 0xc4c4a000, 0x02077000, 0xbf64a800, 0x4fb75c00, 0x338ca600, 0xf9c37700, 0x32ee8e80, 0xe31044c0, 0x358a1b60, 0xc0a70f30, 0x8406a388, 0x46646b5c, 0xd9680e32, 0x26b40201 }, + { 0x80000000, 0xc0000000, 0x20000000, 0x10000000, 0x78000000, 0x6c000000, 0x7e000000, 0xff000000, 0x18800000, 0xc0c00000, 0x7ca00000, 0x5ab00000, 0xd9b80000, 0xc7040000, 0x94f20000, 0x8eed0000, 0xebe28000, 0x5676c000, 0x0b62a000, 0x3ab6f000, 0x29c2a800, 0x8f06f400, 0x90fab600, 0xe4c2ef00, 0x06a8a980, 0xcf9fd0c0, 0x2c722fa0, 0x9e2d20f0, 0xcf429088, 0x70c6c65c, 0xd4da8ee6, 0x6eb2c39d }, + { 0x80000000, 0xc0000000, 0xa0000000, 0x30000000, 0xd8000000, 0xf4000000, 0xd2000000, 0xab000000, 0x98800000, 0x90c00000, 0xeca00000, 0x82f00000, 0xe7e80000, 0x2a040000, 0xaf3e0000, 0x32b70000, 0xfff28000, 0x7e46c000, 0x4d72a000, 0x4186f000, 0x93528800, 0x3cb6fc00, 0x0a9abe00, 0x5b82c100, 0xe46c8a80, 0xfa01ebc0, 0x27682ca0, 0x8ec40ff0, 0x319e3788, 0x2b471f4c, 0x589aa672, 0x3082d9cd }, + { 0x80000000, 0x40000000, 0xa0000000, 0x30000000, 0x08000000, 0x0c000000, 0x72000000, 0xf9000000, 0x4a800000, 0x86c00000, 0x14e00000, 0x7db00000, 0x0f280000, 0x8dec0000, 0xe70a0000, 0x11830000, 0xad578000, 0xecdec000, 0x99b7a000, 0xe16ed000, 0x3e9f8800, 0x5082dc00, 0xa3958a00, 0xb401df00, 0x36421680, 0x271f2140, 0xf195a420, 0x3d01d0f0, 0xd4c22918, 0x9ddf139c, 0x9f75a0d2, 0xb5b1efe7 }, + { 0x80000000, 0x40000000, 0x60000000, 0x50000000, 0x28000000, 0xe4000000, 0x1e000000, 0x0d000000, 0x4f800000, 0x03c00000, 0xb9e00000, 0xcad00000, 0xd8780000, 0xbc2c0000, 0xe27e0000, 0x8f410000, 0x90ef8000, 0xbb1c4000, 0xe68fa000, 0x320c5000, 0xe717b800, 0x14f04400, 0xf511b200, 0xc39d7d00, 0x99803580, 0xfac03e40, 0xa0600660, 0x70102eb0, 0x18183018, 0x9c3c0804, 0xd2660c06, 0xf77d1e0f }, + { 0x80000000, 0x40000000, 0x20000000, 0xb0000000, 0x38000000, 0x2c000000, 0xd2000000, 0x8d000000, 0x70800000, 0x14c00000, 0xb2e00000, 0x51f00000, 0xf6280000, 0x0b740000, 0x23c20000, 0x8b7b0000, 0x63858000, 0xab51c000, 0xd3e5a000, 0x9361d000, 0xffada800, 0x4125fc00, 0x72a7a600, 0x31daf700, 0x66481280, 0x83441440, 0x378a2ea0, 0x753f0170, 0x3c8f8a18, 0x56aef90c, 0xb78a1992, 0x353f20d1 }, + { 0x80000000, 0xc0000000, 0x60000000, 0x50000000, 0xd8000000, 0xec000000, 0xf2000000, 0x65000000, 0x87800000, 0x05c00000, 0x48a00000, 0xcb100000, 0x58f80000, 0xb3340000, 0x84d20000, 0xc9130000, 0xd5f58000, 0x50944000, 0x470da000, 0xfaa07000, 0x0e5fb800, 0xef736400, 0x3e8a0e00, 0xf8371f00, 0x1c5f9280, 0x1a737640, 0x010a0b60, 0x41f71330, 0x7eff9748, 0x58637ef4, 0x2c7233f6, 0x92031479 }, + { 0x80000000, 0xc0000000, 0xa0000000, 0x90000000, 0x58000000, 0xc4000000, 0x66000000, 0x3b000000, 0x39800000, 0xd7c00000, 0x10a00000, 0xbb700000, 0xf9f80000, 0x77f40000, 0x80a60000, 0xe30d0000, 0x3db48000, 0x11c64000, 0xbbcca000, 0xdaf27000, 0xea4a8800, 0x014f5400, 0x00a61e00, 0x230d2500, 0x9db4a780, 0x81c65bc0, 0xe3cca1e0, 0x1ef27a30, 0x8c4a9bc8, 0x3a4f41ec, 0x39262a36, 0xf4cd23d1 }, + { 0x80000000, 0x40000000, 0xe0000000, 0x10000000, 0xb8000000, 0xb4000000, 0xfa000000, 0x47000000, 0xd1800000, 0x1fc00000, 0xe2e00000, 0x94100000, 0x4a580000, 0x0f240000, 0xcd8e0000, 0xe9bb0000, 0xebe48000, 0xf8a64000, 0xc35ca000, 0x23925000, 0xa48a9800, 0xd50d5400, 0x3ae03600, 0x70103900, 0xe8582880, 0xec2438c0, 0x5e0e24e0, 0x057b3b30, 0x2284b258, 0x34767334, 0xba64be4e, 0xa766713d }, + { 0x80000000, 0x40000000, 0x60000000, 0x50000000, 0xb8000000, 0x14000000, 0xd2000000, 0x6d000000, 0x25800000, 0x73c00000, 0x54e00000, 0x38500000, 0x54380000, 0xb2440000, 0x3d7e0000, 0x9dbf0000, 0x67958000, 0x86ad4000, 0x554da000, 0x71b95000, 0xc18bb800, 0x69824400, 0xa5801600, 0x33c00100, 0x34e00280, 0x68500a40, 0xec3813e0, 0xa64402b0, 0xef7e28d8, 0xf0bf09a4, 0x42158956, 0xf56d7e75 }, + { 0x80000000, 0x40000000, 0xe0000000, 0xf0000000, 0x38000000, 0x2c000000, 0x86000000, 0x79000000, 0xe2800000, 0xd8c00000, 0xafe00000, 0xc0100000, 0xa0280000, 0x10140000, 0xc8720000, 0x14490000, 0xaa698000, 0xff0ec000, 0x9ba1a000, 0x3a0ad000, 0x777b9800, 0x6f97ec00, 0x60001600, 0xb0002700, 0xd8001780, 0xdc002940, 0xbe001720, 0x55002370, 0x648032d8, 0xa1c01874, 0x4d603b52, 0x18d00231 }, + { 0x80000000, 0xc0000000, 0xe0000000, 0x30000000, 0x48000000, 0x34000000, 0x3e000000, 0x1b000000, 0xe0800000, 0xe2c00000, 0xd3a00000, 0xc6500000, 0xa7080000, 0x0acc0000, 0xf7e60000, 0x60010000, 0xf0188000, 0xa80ac000, 0x0430a000, 0x7656f000, 0x2f7e9800, 0xdecbfc00, 0xf9880a00, 0x330c3100, 0x24c62580, 0x749107c0, 0xccb0a5a0, 0x5096f370, 0x6adea348, 0x079bffe4, 0xc8003d0a, 0xf4003797 }, + { 0x80000000, 0xc0000000, 0x20000000, 0xf0000000, 0x98000000, 0x9c000000, 0x4e000000, 0x59000000, 0x07800000, 0xddc00000, 0xdea00000, 0x1a300000, 0x23080000, 0x34a40000, 0xa13a0000, 0x8bc50000, 0xdb958000, 0x73d04000, 0x57bda000, 0x75847000, 0xfaafa800, 0x38154c00, 0xac280e00, 0xf6542b00, 0x35123d80, 0xd1910d40, 0x1887b460, 0x97414630, 0x9eba05c8, 0xfa0517bc, 0xf335b68a, 0x5ce040d5 }, + { 0x80000000, 0x40000000, 0x20000000, 0x10000000, 0x08000000, 0x84000000, 0x92000000, 0x91000000, 0xbd800000, 0x8cc00000, 0x61600000, 0xc5b00000, 0x30d80000, 0x6f6c0000, 0x4af60000, 0x0a530000, 0x5d2d8000, 0x8bc04000, 0x9fdba000, 0x45935000, 0x70f62800, 0x4f531400, 0x5aad8a00, 0x02006500, 0xd93b8680, 0x19e35540, 0x0ece23e0, 0xf84f1370, 0xfc63bd38, 0x2e4f775c, 0x9f5812ee, 0x32ac3ff7 }, + { 0x80000000, 0xc0000000, 0x20000000, 0xf0000000, 0x78000000, 0xac000000, 0x3a000000, 0x0d000000, 0xf1800000, 0x6cc00000, 0xf5200000, 0x9df00000, 0x76a80000, 0x08640000, 0x141a0000, 0xb6230000, 0xc75f8000, 0x84944000, 0x3145a000, 0xa3b77000, 0x659a2800, 0x1ae30c00, 0x127f9600, 0xe9645700, 0x3fedb080, 0x07d35840, 0x4b801ae0, 0xa1c01470, 0x24a01728, 0x01302b4c, 0xfb883062, 0x39940d25 }, + { 0x80000000, 0x40000000, 0xe0000000, 0x30000000, 0x98000000, 0x6c000000, 0xaa000000, 0x83000000, 0xd7800000, 0xc0c00000, 0xa1600000, 0x30d00000, 0x99280000, 0x8cf40000, 0x9b4a0000, 0xfbdb0000, 0x8ae88000, 0x12644000, 0x7f42a000, 0x35af5000, 0x87e21800, 0x28ef1c00, 0xb5429e00, 0xc6af5700, 0x28622c80, 0xb42f2bc0, 0x2622a760, 0x197f5cf0, 0xccca1bb8, 0x7b1b3704, 0xcb889c92, 0x12b443c9 }, + { 0x80000000, 0xc0000000, 0x60000000, 0x30000000, 0x28000000, 0x8c000000, 0x2e000000, 0xc3000000, 0xae800000, 0x79c00000, 0x9d200000, 0xe5d00000, 0x0b680000, 0xd2ec0000, 0x1fa20000, 0xe2690000, 0x4d328000, 0x3dd8c000, 0xcf30a000, 0x40a1f000, 0xdaca3800, 0x03853c00, 0xb4109200, 0x1a71ef00, 0x19222180, 0xd7a923c0, 0x9e12b820, 0x2b08e2b0, 0x42d8a6e8, 0x678df404, 0x76481612, 0xc73c010f }, + { 0x80000000, 0xc0000000, 0x60000000, 0x70000000, 0x48000000, 0x6c000000, 0x4e000000, 0x3b000000, 0x94800000, 0xc1c00000, 0xbe200000, 0xb3500000, 0x98880000, 0xffdc0000, 0xcd320000, 0x4bc10000, 0x17728000, 0x7aabc000, 0xeac8a000, 0x12b6f000, 0x56883800, 0x04dc2c00, 0x39b20a00, 0xfa010700, 0xe1528180, 0xa5fbd5c0, 0x3c4096a0, 0xd66aceb0, 0x0f3a32a8, 0x8edd30a4, 0x90e083aa, 0x33fad423 }, + { 0x80000000, 0x40000000, 0x60000000, 0x90000000, 0x58000000, 0x44000000, 0x1a000000, 0xf1000000, 0x4e800000, 0xf5c00000, 0x32600000, 0x3d100000, 0x28f80000, 0xcaa40000, 0xcfee0000, 0x337f0000, 0xbbad8000, 0xc14bc000, 0xa6bba000, 0x1990d000, 0xa4783800, 0xca643400, 0xc90e0e00, 0x9aaf3500, 0xb7b59080, 0x873fed40, 0x69cdb520, 0x2c5bd130, 0xb643a738, 0x0734c634, 0x299628a6, 0x4c1b18ed }, + { 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xc8000000, 0xe4000000, 0x42000000, 0xbd000000, 0x6a800000, 0x05c00000, 0x2a200000, 0x89100000, 0xf0880000, 0x64dc0000, 0x2eb60000, 0x97830000, 0x4f578000, 0x3fe7c000, 0x9b69a000, 0x55b8f000, 0x32081800, 0xb51c0c00, 0x6e960a00, 0xb7930500, 0x5f5fa280, 0x07fbd640, 0xb77faa20, 0xf3ebde30, 0xcd778828, 0x62f7ef34, 0x01e19caa, 0x9864ce73 }, + { 0x80000000, 0x40000000, 0xe0000000, 0x10000000, 0x48000000, 0xdc000000, 0x92000000, 0x53000000, 0x6c800000, 0x85c00000, 0x36600000, 0xe5500000, 0xc9f80000, 0xac6c0000, 0x8a6a0000, 0x27570000, 0x32e88000, 0x0cfbc000, 0xd5faa000, 0x9e00d000, 0x29181800, 0x13fc1400, 0x23722a00, 0x74ab3300, 0xf19ab680, 0x6850e3c0, 0x6c601fa0, 0x2a5025b0, 0xd7782eb8, 0x6aac1c24, 0x988a2de6, 0x9bc7254f }, + { 0x80000000, 0xc0000000, 0x60000000, 0xd0000000, 0x98000000, 0x6c000000, 0x2e000000, 0x71000000, 0x7c800000, 0xebc00000, 0xd2200000, 0x67500000, 0xd1d80000, 0xf1640000, 0xbc9a0000, 0x8bd10000, 0x02678000, 0xff1ac000, 0xbda5a000, 0xdf6ff000, 0xcdf83800, 0xf7340400, 0xe9c23e00, 0x2d752f00, 0xdaddad80, 0x0e9bc740, 0x3c9a34a0, 0x4bd116b0, 0x6267b3a8, 0x2f1ad724, 0x25a586fe, 0xb36fce8d }, + { 0x80000000, 0xc0000000, 0xa0000000, 0x30000000, 0xb8000000, 0xac000000, 0x06000000, 0xfd000000, 0xef800000, 0xf8c00000, 0x8c200000, 0xf6300000, 0xe5480000, 0x73c40000, 0x46ca0000, 0xdd750000, 0x1fcd8000, 0xe0814000, 0x106fa000, 0x48007000, 0xb4200800, 0x9a303c00, 0x43480600, 0xbec42700, 0x114a2f80, 0x89b51440, 0x95edba60, 0xebb14170, 0x1aa7b8e8, 0xc30473bc, 0x7eca125a, 0xb1751d7d }, + { 0x80000000, 0x40000000, 0xa0000000, 0x50000000, 0x58000000, 0x14000000, 0x5a000000, 0x75000000, 0x6c800000, 0x87c00000, 0xdc600000, 0xf6700000, 0xcb780000, 0x4b840000, 0xd2660000, 0x79070000, 0x82c78000, 0xf8e4c000, 0x9db9a000, 0x0917d000, 0xcae00800, 0x14b00400, 0x83983e00, 0x7e341100, 0xc77e0080, 0xa5f31840, 0xad598da0, 0x38a7fcb0, 0x7df80c38, 0xf9440c6c, 0xc2862dc6, 0x58b73b7d }, + { 0x80000000, 0xc0000000, 0x60000000, 0x70000000, 0xe8000000, 0x94000000, 0x42000000, 0x7b000000, 0x49800000, 0x3cc00000, 0x90200000, 0x58500000, 0x1c080000, 0xa64c0000, 0xd13e0000, 0xa6eb0000, 0x375c8000, 0xd7f94000, 0x81caa000, 0x78ce7000, 0x2a003800, 0x2f002c00, 0x6b802200, 0x37c03900, 0x31a02a80, 0xf0903bc0, 0xce2802e0, 0x851c11f0, 0x84b63668, 0x3c671924, 0x7642a30a, 0x29427f87 }, + { 0x80000000, 0xc0000000, 0x20000000, 0xf0000000, 0x28000000, 0x14000000, 0x4a000000, 0xe3000000, 0x6f800000, 0x72c00000, 0x70200000, 0xe8300000, 0x34080000, 0xba3c0000, 0xcb0a0000, 0x7b850000, 0x38d28000, 0x9318c000, 0x87abe000, 0x46d4b000, 0xca000800, 0x23000c00, 0x4f800200, 0x82c00f00, 0x58200280, 0xfc300140, 0x7e0804a0, 0x593c0e30, 0xa48a06f8, 0x0945072c, 0x48f28702, 0x7b28ce83 }, + { 0x80000000, 0x40000000, 0xe0000000, 0x50000000, 0x28000000, 0x9c000000, 0x7e000000, 0xff000000, 0x43800000, 0x79c00000, 0xb8200000, 0x14100000, 0x52380000, 0xf9140000, 0x088a0000, 0xd8670000, 0x40ff8000, 0x108fc000, 0x7c78e000, 0x6ad27000, 0x5d800800, 0x96c00400, 0x33a00e00, 0xa1d00500, 0xbc180280, 0x8e0409c0, 0x673207e0, 0xa7b30ff0, 0xb3d58438, 0xa538c79c, 0xd69f6b82, 0x9759b141 }, + { 0x80000000, 0xc0000000, 0x20000000, 0x70000000, 0x48000000, 0x1c000000, 0xae000000, 0xf9000000, 0x6c800000, 0x95c00000, 0x7c200000, 0x3e300000, 0xe1080000, 0x489c0000, 0x6fd20000, 0x37270000, 0x059b8000, 0xe1764000, 0xcde72000, 0xb8277000, 0x94200800, 0x92300c00, 0x27080200, 0xdd9c0700, 0xe5520480, 0x47e701c0, 0xbb3b8ae0, 0xb3864f90, 0x3c4f26c8, 0x5b4b795c, 0x66da0fc2, 0xd3bb0fe3 }, + { 0x80000000, 0x40000000, 0x60000000, 0xd0000000, 0x48000000, 0xbc000000, 0x0e000000, 0xe1000000, 0xb5800000, 0x3dc00000, 0x8c200000, 0xd6100000, 0x75180000, 0xd7b40000, 0x9ad20000, 0x648f0000, 0x50538000, 0x25c04000, 0x38296000, 0x04157000, 0x4a200800, 0xcb100400, 0xae980600, 0xdb740d00, 0xeb720480, 0x335f0bc0, 0xa76b80e0, 0xc5644e10, 0x62636b58, 0x8aee73dc, 0x0c8180c2, 0x5c4f4961 }, + { 0x80000000, 0xc0000000, 0xe0000000, 0xd0000000, 0x98000000, 0x34000000, 0x12000000, 0x43000000, 0x04800000, 0xb8400000, 0x46200000, 0x41300000, 0x3fb80000, 0x58f40000, 0x74460000, 0x701d0000, 0x680c8000, 0x9c1cc000, 0x6e132000, 0xfd051000, 0x61980800, 0xedc40c00, 0xb9fe0e00, 0xbbe90d00, 0x80ca8980, 0x6041c340, 0x523fa120, 0x6329d430, 0x34b32848, 0xf0751784, 0xea000262, 0x67000513 }, + { 0x80000000, 0xc0000000, 0xa0000000, 0x50000000, 0x98000000, 0xec000000, 0x0e000000, 0x29000000, 0x9f800000, 0xa9400000, 0x52200000, 0x8f300000, 0x32a80000, 0x1cd40000, 0xa8460000, 0x89ab0000, 0xac5b8000, 0x63964000, 0x5f65e000, 0x673f5000, 0xd6880800, 0xc6e40c00, 0x336e0a00, 0xa93f0500, 0x5fbd8980, 0x094d4ec0, 0x023660e0, 0x170d1290, 0xdea3e1f8, 0x12d45694, 0x81738722, 0x160241f3 }, + { 0x80000000, 0x40000000, 0xa0000000, 0x30000000, 0xf8000000, 0xfc000000, 0x1e000000, 0x2b000000, 0x67800000, 0xc5400000, 0xab200000, 0x27900000, 0x65680000, 0x9b2c0000, 0xdfae0000, 0x99570000, 0x852b8000, 0xf4a4c000, 0xfecee000, 0x405ad000, 0x5fae0800, 0xd9570400, 0x252b8a00, 0xc4a4c300, 0x06ceef80, 0xbc5adfc0, 0x41ae09e0, 0xf25706b0, 0x42ab8c78, 0x01e4cf54, 0xadeee532, 0x9bcaddb9 }, + { 0x80000000, 0x40000000, 0xe0000000, 0x90000000, 0x68000000, 0x9c000000, 0x06000000, 0x2f000000, 0xf8800000, 0x2a400000, 0x7f200000, 0x30900000, 0xc6780000, 0x81040000, 0xeb8a0000, 0xa4df0000, 0x82458000, 0x4321c000, 0x46b12000, 0x11571000, 0x8d8a0800, 0x5bdf0400, 0xf2c58e00, 0x6561c900, 0x57912680, 0x92c719c0, 0xb5720860, 0xdf9b06f0, 0x9eef8188, 0xdb6ecba4, 0x6c8ca172, 0x6072dac9 }, + { 0x80000000, 0xc0000000, 0x20000000, 0x70000000, 0xa8000000, 0x44000000, 0xc2000000, 0x13000000, 0xcf800000, 0xe2400000, 0x71200000, 0x6cb00000, 0xa5c80000, 0xa77c0000, 0x77ba0000, 0x9e690000, 0x0f048000, 0x2182c000, 0x5740e000, 0x1fa51000, 0xfa720800, 0xbd150c00, 0x9abe8200, 0xdcebc700, 0x3fc46a80, 0x9867d440, 0x1e12e420, 0xdd001d30, 0x0a8486f8, 0x24c2c524, 0xa3e0ef92, 0xb655158b }, + { 0x80000000, 0xc0000000, 0xe0000000, 0x10000000, 0x18000000, 0x7c000000, 0x8e000000, 0x6f000000, 0x52800000, 0x1fc00000, 0x59200000, 0x71b00000, 0x2b780000, 0x5de40000, 0x90160000, 0xd8170000, 0x9c1f8000, 0x9e19c000, 0x770da000, 0x2ebb7000, 0x91ee0800, 0x36330c00, 0x23298e00, 0x34bec100, 0x04ea2180, 0xe186b7c0, 0xf355a0e0, 0xc1ef7af0, 0x0e000328, 0xaf000cfc, 0xb2800a12, 0x0fc001db }, + { 0x80000000, 0x40000000, 0xa0000000, 0xb0000000, 0x08000000, 0xf4000000, 0xa6000000, 0x77000000, 0x65800000, 0xd3c00000, 0x45200000, 0xe4900000, 0xd9680000, 0xbf4c0000, 0x28720000, 0x5de50000, 0x361d8000, 0x8f0bc000, 0x39a26000, 0x31ce7000, 0x9c3a0800, 0x02390400, 0xc9078a00, 0x5ea2cb00, 0xec4de080, 0xb3e0bf40, 0x1525e260, 0xfcacb370, 0x9557e458, 0xe549b23c, 0x0d4a66d2, 0xe9427e09 }, + { 0x80000000, 0xc0000000, 0x60000000, 0xd0000000, 0x48000000, 0xf4000000, 0x26000000, 0x61000000, 0x17800000, 0x08c00000, 0xbb200000, 0x04b00000, 0xe8580000, 0x5d540000, 0x1cc20000, 0x8d350000, 0x4d958000, 0xdbe64000, 0x3bbee000, 0x32d4b000, 0xb83a0800, 0xcc110c00, 0x2a2f8600, 0x2b374d00, 0xecb16480, 0xac53ff40, 0xe3536a60, 0xc1d6fa10, 0x489eef78, 0x0264b18c, 0x16620132, 0x20450e0b }, + { 0x80000000, 0x40000000, 0xe0000000, 0x70000000, 0x78000000, 0x74000000, 0x7e000000, 0x5f000000, 0xd0800000, 0x75400000, 0x7d200000, 0x2d900000, 0x18f80000, 0x85fc0000, 0xd86e0000, 0xb8950000, 0x496b8000, 0xef0dc000, 0x08bb2000, 0x9179d000, 0x0b360800, 0x7eb90400, 0xc25d8e00, 0xd1b4c700, 0x2ae6a780, 0x30cd1740, 0x59d0afe0, 0x3a7411f0, 0xe58d2b08, 0xb4c0d454, 0x1feb8652, 0xf14dc699 }, + { 0x80000000, 0xc0000000, 0x20000000, 0x90000000, 0xc8000000, 0x24000000, 0x8e000000, 0x39000000, 0x6a800000, 0x60400000, 0x5aa00000, 0xf8700000, 0x96a80000, 0xc2540000, 0xe99a0000, 0xb5dd0000, 0x6d798000, 0xb6334000, 0xa5332000, 0xb8b35000, 0xab798800, 0x6b334c00, 0x61b32200, 0x71f35900, 0x53598480, 0xd7034e40, 0x23bb2ae0, 0x72d75a90, 0x46eb8228, 0xc0ca4844, 0xfdf8af4a, 0x89491517 }, + { 0x80000000, 0xc0000000, 0xa0000000, 0xd0000000, 0xf8000000, 0xbc000000, 0xca000000, 0x39000000, 0x13800000, 0x55400000, 0xbba00000, 0xd1700000, 0x6d880000, 0xf2440000, 0xbf360000, 0x08ab0000, 0x9be48000, 0x5b754000, 0x34986000, 0x91ec1000, 0xc2648800, 0xf7354c00, 0x3cb86a00, 0xc5dc1d00, 0xec4c8780, 0x680147c0, 0x240666a0, 0x06331e90, 0xdb1e06b8, 0x6e9f0294, 0x30da8d1a, 0x1dda4387 }, + { 0x80000000, 0x40000000, 0x60000000, 0x30000000, 0xf8000000, 0xe4000000, 0xfa000000, 0xad000000, 0xb6800000, 0x89c00000, 0x92a00000, 0x53d00000, 0x6fb80000, 0x2d5c0000, 0xfa460000, 0xa1c50000, 0xfea88000, 0xd5d64000, 0xec992000, 0x34d23000, 0x8c088800, 0xf6064400, 0x1b212600, 0xcd8e3300, 0x744e8780, 0x1ec34a40, 0xa909a9a0, 0x3c9879d0, 0xbcf7ace8, 0xf00172dc, 0xd819288a, 0xb41238ed }, + { 0x80000000, 0xc0000000, 0xe0000000, 0x10000000, 0x68000000, 0xe4000000, 0x86000000, 0x9d000000, 0xe1800000, 0xb0c00000, 0xeda00000, 0x12f00000, 0x16980000, 0x7e740000, 0x2fc20000, 0xc72d0000, 0x56b38000, 0x5e624000, 0xdfe7e000, 0xbf387000, 0xda938800, 0x3c524c00, 0xc4dfee00, 0xc3bc7100, 0x8bc98e80, 0x610b4240, 0x3bae6660, 0xc7f338d0, 0xe31de098, 0x3091794c, 0xd37a00ba, 0x566905ff }, + { 0x80000000, 0x40000000, 0x20000000, 0x70000000, 0xa8000000, 0x34000000, 0xd2000000, 0x59000000, 0xd6800000, 0xf1400000, 0x9aa00000, 0x8f500000, 0xada80000, 0x96cc0000, 0xa9420000, 0x46a10000, 0x49468000, 0x56af4000, 0xb1672000, 0xbaa51000, 0xff668800, 0x05bf4400, 0xa2ef2200, 0x7b791700, 0x1fac8280, 0x9fc24740, 0xa7e3af20, 0x2beb5290, 0x35e72fe8, 0x52e51854, 0x93468e8a, 0x0baf4e65 }, + { 0x80000000, 0x40000000, 0xa0000000, 0x90000000, 0x88000000, 0xcc000000, 0x5a000000, 0x77000000, 0x4e800000, 0x23400000, 0xd4a00000, 0xb4500000, 0xaa080000, 0x8f340000, 0x3a8a0000, 0xad570000, 0xbd948000, 0x1bfec000, 0xeacd2000, 0x41411000, 0x379c8800, 0x44cac400, 0xf8472a00, 0xb0161900, 0x58080080, 0xe43408c0, 0x060a0fa0, 0xa5170e70, 0xf5b48c68, 0x37eecef4, 0x80e528ea, 0x2e651c35 }, + { 0x80000000, 0xc0000000, 0xe0000000, 0x70000000, 0x68000000, 0xb4000000, 0xb6000000, 0x09000000, 0x40800000, 0xb9400000, 0x3ea00000, 0x54700000, 0x30180000, 0x482c0000, 0x24220000, 0xae310000, 0xd5378000, 0x42af4000, 0x067da000, 0x770c1000, 0xadaf8800, 0xb7c34c00, 0x22ffae00, 0x404d1700, 0xd6000e80, 0xb9000740, 0xc8800560, 0x7d400790, 0xe0a00288, 0xe97000d4, 0xc698088a, 0xf86c05d7 }, + { 0x80000000, 0xc0000000, 0xe0000000, 0x10000000, 0xb8000000, 0xe4000000, 0x86000000, 0x8d000000, 0x4b800000, 0x8ec00000, 0x79a00000, 0x1df00000, 0xab180000, 0xf6b40000, 0x8d560000, 0xbb5d0000, 0xbe5f8000, 0x59f24000, 0x1d1f6000, 0x33a2f000, 0x8ae78800, 0xefb64c00, 0x28d16e00, 0x048bf100, 0xfe4e0380, 0x79e90240, 0xed098660, 0x9baf49d0, 0xd6c0ef38, 0x8d90b6ac, 0x23d8e7fa, 0xc224b50f }, + { 0x80000000, 0x40000000, 0x60000000, 0xb0000000, 0x88000000, 0xbc000000, 0xba000000, 0x6b000000, 0xbb800000, 0x27400000, 0x30a00000, 0x6cd00000, 0xfff80000, 0x505c0000, 0xa10a0000, 0x788b0000, 0xf0f88000, 0x95dbc000, 0x037d6000, 0x2eba9000, 0x59f28800, 0x1150c400, 0x2985e600, 0x60615b00, 0x690fe080, 0xa4aa5fc0, 0xfad765a0, 0x76e199b0, 0x04f20d38, 0xb3d706b4, 0x0272862a, 0xc610c0bd }, + { 0x80000000, 0xc0000000, 0x60000000, 0x50000000, 0x58000000, 0x54000000, 0x56000000, 0x33000000, 0x54800000, 0xe4c00000, 0x17a00000, 0x18700000, 0xcf780000, 0x05c40000, 0xbe1e0000, 0xaf290000, 0x6e8f8000, 0x85dbc000, 0x7e23a000, 0xcf057000, 0x3e918800, 0xddf2cc00, 0x2a2c2600, 0x991eb500, 0x0d922d80, 0x8947b940, 0xcee5ab60, 0x8e987a30, 0x15f80ec8, 0x4604020c, 0xcb3e079a, 0x309902f7 }, + { 0x80000000, 0x40000000, 0xa0000000, 0x30000000, 0x78000000, 0xdc000000, 0xca000000, 0x43000000, 0xe3800000, 0x9c400000, 0xb8a00000, 0x73d00000, 0x06c80000, 0x1c7c0000, 0xf8860000, 0xd3c30000, 0x36e88000, 0x6445c000, 0x24bb6000, 0x19c65000, 0x75ee8800, 0x87c6c400, 0xb8f3ea00, 0xa1539300, 0x061def80, 0x813c99c0, 0xa4bb6ea0, 0x59c65330, 0xd5ee8bb8, 0xb7c6c304, 0xc0f3eaaa, 0x7d539dcd }, + { 0x80000000, 0xc0000000, 0xa0000000, 0x90000000, 0x08000000, 0x5c000000, 0x3a000000, 0x2f000000, 0xac800000, 0x94c00000, 0x5fa00000, 0xc2700000, 0x44480000, 0xa1740000, 0x1afa0000, 0xe68b0000, 0x43f08000, 0x9732c000, 0xa8a4a000, 0x5add7000, 0x86aa8800, 0x73c9cc00, 0x0f1c2a00, 0xfc9bb900, 0x3cf42880, 0x939fb9c0, 0xf04621a0, 0x3760b7f0, 0x37cca848, 0xa119798c, 0x15b884da, 0x1546ce17 }, + { 0x80000000, 0xc0000000, 0xe0000000, 0x70000000, 0x28000000, 0xc4000000, 0x3a000000, 0x9b000000, 0xa1800000, 0x93400000, 0xa0a00000, 0xf9f00000, 0x2a580000, 0x560c0000, 0xa5020000, 0xe0950000, 0xd9d88000, 0xba7dc000, 0x0e07e000, 0x49049000, 0x1e828800, 0x78e4cc00, 0x80dd6e00, 0x3cec5700, 0x7addea80, 0x47dd9040, 0xab7805a0, 0xfcbc02b0, 0xcffa0698, 0x3f690274, 0x7e828b2a, 0xc8e4ca6f }, + { 0x80000000, 0xc0000000, 0x60000000, 0x70000000, 0x28000000, 0xa4000000, 0xfe000000, 0x3d000000, 0x82800000, 0xb3400000, 0x05a00000, 0x42f00000, 0x41780000, 0xa28c0000, 0x63620000, 0x3d8d0000, 0xbed98000, 0x33544000, 0xc5ba2000, 0x22fe1000, 0x31638800, 0x8aa54c00, 0xc779a600, 0xc3ab5700, 0x83e22a80, 0xb1c21640, 0x76d981e0, 0x275448d0, 0x73ba2ca8, 0xcbfe1674, 0x65e3853a, 0xa0e541bf }, +}; diff --git a/code/projects/sobol_matrices.h b/code/projects/sobol_matrices.h new file mode 100644 index 0000000000000000000000000000000000000000..53aa319ea875004e099b59b79ac239beb80cc66d --- /dev/null +++ b/code/projects/sobol_matrices.h @@ -0,0 +1,78 @@ + +#pragma once + +#include <cassert> +#include <cstdint> +#include <array> + + +unsigned sobol_sample( const std::array<unsigned, 32>& m, unsigned n ) +{ + unsigned x= 0; + for(unsigned i= 0; n; i++, n>>= 1) + { + if(n & 1) + x ^= m[i]; + } + + return x; +} + +unsigned graycode( const unsigned i ) +{ + return i ^ (i >> 1); +} +unsigned trailing_zeroes( const unsigned i ) +{ + assert(i > 0); + return __builtin_ctz(i); +} + +unsigned sobol_sample_graycode( const std::array<unsigned, 32>& m, unsigned n, const unsigned prev ) +{ + assert(n > 0); + unsigned g= trailing_zeroes(graycode(n-1) ^ graycode(n)); + return prev ^ m[g]; +} + + +//~ constexpr unsigned sobol_matrices_size= 16; +constexpr unsigned sobol_matrices_size= 128; +extern std::array<unsigned, 32> sobol_matrices[sobol_matrices_size]; + +unsigned sobol_sample( const unsigned d, const unsigned index ) +{ + assert(d < sobol_matrices_size); + return sobol_sample(sobol_matrices[d], index); +} + +float sobol_sample_float( const unsigned d, const unsigned index ) +{ + assert(d < sobol_matrices_size); + return uint_to_float( sobol_sample(d, index) ); +} + +double sobol_sample_double( const unsigned d, const unsigned index ) +{ + assert(d < sobol_matrices_size); + return uint_to_double( sobol_sample(d, index) ); +} + +unsigned sobol_sample( const unsigned d, const unsigned index, const unsigned scramble ) +{ + assert(d < sobol_matrices_size); + return sobol_sample(sobol_matrices[d], index) ^ scramble; +} + +float sobol_sample_float( const unsigned d, const unsigned index, const unsigned scramble ) +{ + assert(d < sobol_matrices_size); + return uint_to_float( sobol_sample(d, index, scramble) ); +} + +double sobol_sample_double( const unsigned d, const unsigned index, const unsigned scramble ) +{ + assert(d < sobol_matrices_size); + return uint_to_double( sobol_sample(d, index, scramble) ); +} + diff --git a/code/scripts/ao.txt b/code/scripts/ao.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6159f9ce1b67cc5f83dbf5980d64db248fdd0a8 --- /dev/null +++ b/code/scripts/ao.txt @@ -0,0 +1,81 @@ +scene="emission.glb" +prefix="emission" +mkdir $prefix + + +#~ bin/ao $scene --prefix $prefix/ref -s 16384 +ref=$prefix/ref-16384.pfm + +#~ return + +rm $prefix/test*.pfm $prefix/test*.png + + +#~ samples="" +samples="1 2 4 8 16 32 64 128 256" +for spp in $samples +do +#~ bin/ao $scene --prefix $prefix/ao-rng -s $spp +#~ bin/ao $scene --prefix $prefix/ao-owen4 -s $spp +#~ bin/ao $scene --prefix $prefix/ao-owen -s $spp +#~ bin/ao $scene --prefix $prefix/ao-sobol -s $spp +#~ bin/ao $scene --prefix $prefix/ao-sobolg -s $spp + +bin/ao $scene --prefix $prefix/test -s $spp + +done + +#~ return + +## erreurs +bin/errors $ref \ + --line 1 --title "sobol" $prefix/ao-sobol-*.pfm \ + --line 2 --title "owen" $prefix/ao-owen-*.pfm \ + --line 3 --title "rng" $prefix/ao-rng-*.pfm + + +## filtrer avec oidn a installer a cote... + +samples="" +#~ samples="0001 0002 0004 0008 0016 0032 0064 0128 0256" +for spp in $samples +do +../../oidn/build/oidnDenoise -o $prefix/denoised-$spp.pfm --filter RT --quality high --type float --hdr $prefix/test-$spp.pfm --alb $prefix/test-albedo-$spp.pfm --nrm $prefix/test-normals-$spp.pfm + +done + +bin/errors $ref \ + --line 1 --title "sobol" $prefix/mf-sobol-????.pfm \ + --line 2 --title "owen" $prefix/mf-owen4-????.pfm \ + --line 3 --title "rng" $prefix/mf-rng-????.pfm + +## visualize mse with gnuplot +gnuplot <<EOF +set term pdfcairo enhanced size 10cm,10cm +set term pdfcairo font "Arial,14" +# set term pdfcairo linewidth 2 +set output "${prefix}/mse.pdf" +set size square +set logscale xy +set format y "10^{%L}" +set xtics 4 +set grid +set style line 11 lc rgb '#808080' lt 1 +set border 3 back ls 11 +set tics nomirror + +# parula palette +set style line 1 lt 1 lw 1.5 lc rgb '#0072bd' # blue +set style line 2 lt 1 lw 1.5 lc rgb '#d95319' # orange +set style line 3 lt 1 lw 1.5 lc rgb '#edb120' # yellow +set style line 4 lt 1 lw 1.5 lc rgb '#7e2f8e' # purple +set style line 5 lt 1 lw 1.5 lc rgb '#77ac30' # green +set style line 6 lt 1 lw 1.5 lc rgb '#4dbeee' # light-blue +set style line 7 lt 1 lw 1.5 lc rgb '#a2142f' # red + +plot \ + 1 / (x**0.5) w lines ls 11 dt 2 t "",\ + "./${prefix}/mse_rng.txt" u 1:2 w linespoints ls 1 t "RNG", \ + "./${prefix}/mse_sobol.txt" u 1:2 w linespoints ls 2 t "Sobol+RDS", \ + "./${prefix}/mse_owen.txt" u 1:2 w linespoints ls 3 t "Sobol+Owen" +EOF