├── PerlinNoise.cpp ├── PerlinNoise.h ├── README.md ├── movie_async.cpp ├── movie_async_ctrl_threads.cpp ├── movie_serial.cpp ├── ppm.cpp └── ppm.h /PerlinNoise.cpp: -------------------------------------------------------------------------------- 1 | #include "PerlinNoise.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // 99% OF THIS CODE IS A DIRECT TRANSLATION TO C++11 FROM THE REFERENCE 8 | // JAVA IMPLEMENTATION OF THE IMPROVED PERLIN FUNCTION (see http://mrl.nyu.edu/~perlin/noise/) 9 | // THE ORIGINAL JAVA IMPLEMENTATION IS COPYRIGHT 2002 KEN PERLIN 10 | 11 | // I ADDED AN EXTRA METHOD THAT GENERATES A NEW PERMUTATION VECTOR (THIS IS NOT PRESENT IN THE ORIGINAL IMPLEMENTATION) 12 | // 21 OCT 2012 ADDED SOME PREPROCESSORS GUARDS FOR VISUAL STUDIO 2012 13 | 14 | // Initialize with the reference values for the permutation vector 15 | PerlinNoise::PerlinNoise() { 16 | 17 | // Initialize the permutation vector with the reference values 18 | #ifdef _MSC_VER 19 | int pp[] = { 20 | 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142, 21 | 8,99,37,240,21,10,23,190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117, 22 | 35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71, 23 | 134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41, 24 | 55,46,245,40,244,102,143,54, 65,25,63,161,1,216,80,73,209,76,132,187,208, 89, 25 | 18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226, 26 | 250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182, 27 | 189,28,42,223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 28 | 43,172,9,129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246, 29 | 97,228,251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239, 30 | 107,49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, 31 | 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 }; 32 | p.insert(p.begin(), pp, pp + 256); 33 | #else 34 | // More elegant BUT initializer lists are not present in VS2012 at 19 Oct 2012 35 | p = { 36 | 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142, 37 | 8,99,37,240,21,10,23,190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117, 38 | 35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71, 39 | 134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41, 40 | 55,46,245,40,244,102,143,54, 65,25,63,161,1,216,80,73,209,76,132,187,208, 89, 41 | 18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226, 42 | 250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182, 43 | 189,28,42,223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 44 | 43,172,9,129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246, 45 | 97,228,251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239, 46 | 107,49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, 47 | 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 }; 48 | #endif 49 | 50 | // Duplicate the permutation vector 51 | p.insert(p.end(), p.begin(), p.end()); 52 | } 53 | 54 | // Generate a new permutation vector based on the value of seed 55 | PerlinNoise::PerlinNoise(unsigned int seed) { 56 | p.resize(256); 57 | 58 | // Fill p with values from 0 to 255 59 | #ifdef _MSC_VER 60 | int indx = 0; 61 | std::generate(p.begin(), p.end(), [&indx] {return indx++;}); 62 | #else 63 | std::iota(p.begin(), p.end(), 0); // more elegant BUT std::iota not present in VS2012 at 19 Oct 2012 64 | #endif 65 | 66 | // Initialize a random engine with seed 67 | std::default_random_engine engine(seed); 68 | 69 | // Suffle using the above random engine 70 | std::shuffle(p.begin(), p.end(), engine); 71 | 72 | // Duplicate the permutation vector 73 | p.insert(p.end(), p.begin(), p.end()); 74 | } 75 | 76 | double PerlinNoise::noise(double x, double y, double z) { 77 | // Find the unit cube that contains the point 78 | int X = (int) floor(x) & 255; 79 | int Y = (int) floor(y) & 255; 80 | int Z = (int) floor(z) & 255; 81 | 82 | // Find relative x, y,z of point in cube 83 | x -= floor(x); 84 | y -= floor(y); 85 | z -= floor(z); 86 | 87 | // Compute fade curves for each of x, y, z 88 | double u = fade(x); 89 | double v = fade(y); 90 | double w = fade(z); 91 | 92 | // Hash coordinates of the 8 cube corners 93 | int A = p[X] + Y; 94 | int AA = p[A] + Z; 95 | int AB = p[A + 1] + Z; 96 | int B = p[X + 1] + Y; 97 | int BA = p[B] + Z; 98 | int BB = p[B + 1] + Z; 99 | 100 | // Add blended results from 8 corners of cube 101 | double res = lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), grad(p[BA], x-1, y, z)), lerp(u, grad(p[AB], x, y-1, z), grad(p[BB], x-1, y-1, z))), lerp(v, lerp(u, grad(p[AA+1], x, y, z-1), grad(p[BA+1], x-1, y, z-1)), lerp(u, grad(p[AB+1], x, y-1, z-1), grad(p[BB+1], x-1, y-1, z-1)))); 102 | return (res + 1.0)/2.0; 103 | } 104 | 105 | double PerlinNoise::fade(double t) { 106 | return t * t * t * (t * (t * 6 - 15) + 10); 107 | } 108 | 109 | double PerlinNoise::lerp(double t, double a, double b) { 110 | return a + t * (b - a); 111 | } 112 | 113 | double PerlinNoise::grad(int hash, double x, double y, double z) { 114 | int h = hash & 15; 115 | // Convert lower 4 bits of hash inot 12 gradient directions 116 | double u = h < 8 ? x : y, 117 | v = h < 4 ? y : h == 12 || h == 14 ? x : z; 118 | return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); 119 | } 120 | -------------------------------------------------------------------------------- /PerlinNoise.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // THIS CLASS IS A TRANSLATION TO C++11 FROM THE REFERENCE 4 | // JAVA IMPLEMENTATION OF THE IMPROVED PERLIN FUNCTION (see http://mrl.nyu.edu/~perlin/noise/) 5 | // THE ORIGINAL JAVA IMPLEMENTATION IS COPYRIGHT 2002 KEN PERLIN 6 | 7 | // I ADDED AN EXTRA METHOD THAT GENERATES A NEW PERMUTATION VECTOR (THIS IS NOT PRESENT IN THE ORIGINAL IMPLEMENTATION) 8 | 9 | #ifndef PERLINNOISE_H 10 | #define PERLINNOISE_H 11 | 12 | class PerlinNoise { 13 | // The permutation vector 14 | std::vector p; 15 | public: 16 | // Initialize with the reference values for the permutation vector 17 | PerlinNoise(); 18 | // Generate a new permutation vector based on the value of seed 19 | PerlinNoise(unsigned int seed); 20 | // Get a noise value, for 2D images z can have any value 21 | double noise(double x, double y, double z); 22 | private: 23 | double fade(double t); 24 | double lerp(double t, double a, double b); 25 | double grad(int hash, double x, double y, double z); 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | async_tutorial 2 | ============== 3 | 4 | C++11 std::async 5 | Here you could find the code for **C++11 async tutorial**, for more informations visit the project webpage: 6 | 7 | http://solarianprogrammer.com/2012/10/17/cpp-11-async-tutorial/ 8 | 9 | You could use this program under the terms of GPL v3, for more details see: 10 | 11 | http://www.gnu.org/copyleft/gpl.html 12 | 13 | Copyright 2012 Sol from www.solarianprogrammer.com 14 | 15 | -------------------------------------------------------------------------------- /movie_async.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "ppm.h" 8 | #include "PerlinNoise.h" 9 | 10 | // Given z as input generate a 2D image from Perlin noise 11 | // id and id_width are parameters use to generate a unique file name 12 | void make_perlin_noise(int id, int id_width, double z) { 13 | // Define the size of the image 14 | unsigned int width = 1280, height = 720; 15 | 16 | // Create an empty PPM image 17 | ppm image(width, height); 18 | 19 | // Create a PerlinNoise object with a random permutation vector generated with seed 20 | unsigned int seed = 237; 21 | PerlinNoise pn(seed); 22 | 23 | unsigned int kk = 0; 24 | // Visit every pixel of the image and assign a color generated with Perlin noise 25 | for(unsigned int i = 0; i < height; ++i) { // y 26 | for(unsigned int j = 0; j < width; ++j) { // x 27 | double x = (double)j/((double)width); 28 | double y = (double)i/((double)height); 29 | 30 | // Wood like structure 31 | double n = 20 * pn.noise(x, y, z); 32 | n = n - floor(n); 33 | 34 | // Map the values to the [0, 255] interval, for simplicity we use 35 | // tones of grey 36 | image.r[kk] = floor(255 * n); 37 | image.g[kk] = floor(255 * n); 38 | image.b[kk] = floor(255 * n); 39 | kk++; 40 | } 41 | } 42 | 43 | // generate a unique name from id 44 | std::string tmp, name; 45 | tmp = std::to_string(id); 46 | if (int diff = id_width - tmp.length()) { 47 | for(int i = 0; i < diff; ++i) name += "0"; 48 | } 49 | name = "img_" + name + tmp + ".ppm"; 50 | 51 | // Save the image in a PPM file 52 | image.write(name); 53 | } 54 | 55 | int main() { 56 | std::vector> futures; 57 | int frames = 1800; 58 | int id_width = 4; 59 | double delta = 1.0 / (double) frames; 60 | 61 | 62 | auto start = std::chrono::steady_clock::now(); 63 | for(int id = 0; id <= frames; ++id) { 64 | double z = (double) id * delta; 65 | futures.push_back(std::async(make_perlin_noise, id, id_width, z)); 66 | } 67 | 68 | for(auto &e : futures) { 69 | e.get(); 70 | } 71 | auto end = std::chrono::steady_clock::now(); 72 | 73 | auto diff = end - start; 74 | std::cout << std::chrono::duration (diff).count() << " ms" << std::endl; 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /movie_async_ctrl_threads.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "ppm.h" 8 | #include "PerlinNoise.h" 9 | 10 | //Split "mem" into "parts", e.g. if mem = 10 and parts = 4 you will have: 0,2,4,6,10 11 | //if possible the function will split mem into equal chuncks, if not 12 | //the last chunck will be slightly larger 13 | std::vector bounds(int parts, int mem) { 14 | std::vectorbnd; 15 | int delta = mem / parts; 16 | int reminder = mem % parts; 17 | int N1 = 0, N2 = 0; 18 | bnd.push_back(N1); 19 | for (int i = 0; i < parts; ++i) { 20 | N2 = N1 + delta; 21 | if (i == parts - 1) 22 | N2 += reminder; 23 | bnd.push_back(N2); 24 | N1 = N2; 25 | } 26 | return bnd; 27 | } 28 | 29 | 30 | void make_perlin_noise(int id, int id_width, double z) { 31 | // Define the size of the image 32 | unsigned int width = 1280, height = 720; 33 | 34 | // Create an empty PPM image 35 | ppm image(width, height); 36 | 37 | // Create a PerlinNoise object with a random permutation vector generated with seed 38 | unsigned int seed = 237; 39 | PerlinNoise pn(seed); 40 | 41 | unsigned int kk = 0; 42 | // Visit every pixel of the image and assign a color generated with Perlin noise 43 | for(unsigned int i = 0; i < height; ++i) { // y 44 | for(unsigned int j = 0; j < width; ++j) { // x 45 | double x = (double)j/((double)width); 46 | double y = (double)i/((double)height); 47 | 48 | // Wood like structure 49 | double n = 20 * pn.noise(x, y, z); 50 | n = n - floor(n); 51 | 52 | // Map the values to the [0, 255] interval, for simplicity we use 53 | // tones of grey 54 | image.r[kk] = floor(255 * n); 55 | image.g[kk] = floor(255 * n); 56 | image.b[kk] = floor(255 * n); 57 | kk++; 58 | } 59 | } 60 | 61 | // generate a unique name from id, example 62 | std::string tmp, name; 63 | tmp = std::to_string(id); 64 | if (int diff = id_width - tmp.length()) { 65 | for(int i = 0; i < diff; ++i) name += "0"; 66 | } 67 | name = "img_" + name + tmp + ".ppm"; 68 | 69 | // Save the image in a PPM file 70 | image.write(name); 71 | } 72 | 73 | // Control the numbers of threads used 74 | void drive_make_perlin_noise(int left, int right, int id_width, double delta) { 75 | for(int id = left; id < right; ++id) { 76 | double z = (double) id * delta; 77 | make_perlin_noise(id, id_width, z); 78 | } 79 | } 80 | 81 | int main() { 82 | std::vector> futures; 83 | int frames = 1800; 84 | int id_width = 4; 85 | double delta = 1.0 / (double) frames; 86 | 87 | //Number of threads to use 88 | int parts = 2; 89 | 90 | std::vectorbnd = bounds(parts, frames); 91 | 92 | auto start = std::chrono::steady_clock::now(); 93 | for (int i = 0; i < parts; ++i) { 94 | futures.push_back(std::async(drive_make_perlin_noise, bnd[i], bnd[i + 1], id_width, delta)); 95 | } 96 | 97 | for(auto &e : futures) { 98 | e.get(); 99 | } 100 | auto end = std::chrono::steady_clock::now(); 101 | 102 | auto diff = end - start; 103 | std::cout << std::chrono::duration (diff).count() << " ms" << std::endl; 104 | 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /movie_serial.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "ppm.h" 7 | #include "PerlinNoise.h" 8 | 9 | void make_perlin_noise(int id, int id_width, double z) { 10 | // Define the size of the image 11 | unsigned int width = 1280, height = 720; 12 | 13 | // Create an empty PPM image 14 | ppm image(width, height); 15 | 16 | // Create a PerlinNoise object with a random permutation vector generated with seed 17 | unsigned int seed = 237; 18 | PerlinNoise pn(seed); 19 | 20 | unsigned int kk = 0; 21 | // Visit every pixel of the image and assign a color generated with Perlin noise 22 | for(unsigned int i = 0; i < height; ++i) { // y 23 | for(unsigned int j = 0; j < width; ++j) { // x 24 | double x = (double)j/((double)width); 25 | double y = (double)i/((double)height); 26 | 27 | // Wood like structure 28 | double n = 20 * pn.noise(x, y, z); 29 | n = n - floor(n); 30 | 31 | // Map the values to the [0, 255] interval, for simplicity we use 32 | // tones of grey 33 | image.r[kk] = floor(255 * n); 34 | image.g[kk] = floor(255 * n); 35 | image.b[kk] = floor(255 * n); 36 | kk++; 37 | } 38 | } 39 | 40 | // generate a unique name from id 41 | std::string tmp, name; 42 | tmp = std::to_string(id); 43 | if (int diff = id_width - tmp.length()) { 44 | for(int i = 0; i < diff; ++i) name += "0"; 45 | } 46 | name = "img_" + name + tmp + ".ppm"; 47 | 48 | // Save the image in a PPM file 49 | image.write(name); 50 | } 51 | 52 | int main() { 53 | int frames = 1800; 54 | int id_width = 4; 55 | double delta = 1.0 / (double) frames; 56 | 57 | auto start = std::chrono::steady_clock::now(); 58 | for(int id = 0; id <= frames; ++id) { 59 | double z = (double) id * delta; 60 | make_perlin_noise(id, id_width, z); 61 | } 62 | auto end = std::chrono::steady_clock::now(); 63 | 64 | auto diff = end - start; 65 | std::cout << std::chrono::duration (diff).count() << " ms" << std::endl; 66 | //diff_sec = chrono::duration_cast(diff); 67 | //cout << diff_sec.count() << endl; 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /ppm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "ppm.h" 8 | 9 | //init with default values 10 | void ppm::init() { 11 | width = 0; 12 | height = 0; 13 | max_col_val = 255; 14 | } 15 | 16 | //create a PPM object 17 | ppm::ppm() { 18 | init(); 19 | } 20 | 21 | //create a PPM object and fill it with data stored in fname 22 | ppm::ppm(const std::string &fname) { 23 | init(); 24 | read(fname); 25 | } 26 | 27 | //create an "epmty" PPM image with a given width and height;the R,G,B arrays are filled with zeros 28 | ppm::ppm(const unsigned int _width, const unsigned int _height) { 29 | init(); 30 | width = _width; 31 | height = _height; 32 | nr_lines = height; 33 | nr_columns = width; 34 | size = width*height; 35 | 36 | buff.resize(3*size); 37 | 38 | // fill r, g and b with 0 39 | r.resize(size); 40 | g.resize(size); 41 | b.resize(size); 42 | } 43 | 44 | //read the PPM image from fname 45 | void ppm::read(const std::string &fname) { 46 | std::ifstream inp(fname.c_str(), std::ios::in | std::ios::binary); 47 | if (inp.is_open()) { 48 | std::string line; 49 | std::getline(inp, line); 50 | if (line != "P6") { 51 | std::cout << "Error. Unrecognized file format." << std::endl; 52 | return; 53 | } 54 | std::getline(inp, line); 55 | while (line[0] == '#') { 56 | std::getline(inp, line); 57 | } 58 | std::stringstream dimensions(line); 59 | 60 | try { 61 | dimensions >> width; 62 | dimensions >> height; 63 | nr_lines = height; 64 | nr_columns = width; 65 | } catch (std::exception &e) { 66 | std::cout << "Header file format error. " << e.what() << std::endl; 67 | return; 68 | } 69 | 70 | std::getline(inp, line); 71 | std::stringstream max_val(line); 72 | try { 73 | max_val >> max_col_val; 74 | } catch (std::exception &e) { 75 | std::cout << "Header file format error. " << e.what() << std::endl; 76 | return; 77 | } 78 | 79 | size = width*height; 80 | 81 | r.reserve(size); 82 | g.reserve(size); 83 | b.reserve(size); 84 | 85 | char aux; 86 | for (unsigned int i = 0; i < size; ++i) { 87 | inp.read(&aux, 1); 88 | r[i] = (unsigned char) aux; 89 | inp.read(&aux, 1); 90 | g[i] = (unsigned char) aux; 91 | inp.read(&aux, 1); 92 | b[i] = (unsigned char) aux; 93 | } 94 | } else { 95 | std::cout << "Error. Unable to open " << fname << std::endl; 96 | } 97 | inp.close(); 98 | } 99 | 100 | //write the PPM image in fname 101 | void ppm::write(const std::string &fname) { 102 | std::ofstream inp(fname.c_str(), std::ios::out | std::ios::binary); 103 | if (inp.is_open()) { 104 | 105 | inp << "P6\n"; 106 | inp << width; 107 | inp << " "; 108 | inp << height << "\n"; 109 | inp << max_col_val << "\n"; 110 | 111 | unsigned int ps = 0; 112 | for (unsigned int i = 0; i < size; ++i) { 113 | buff[ps] = (char) r[i]; ps++; 114 | buff[ps] = (char) g[i]; ps++; 115 | buff[ps] = (char) b[i]; ps++; 116 | } 117 | inp.write(&buff[0], 3*size); 118 | } else { 119 | std::cout << "Error. Unable to open " << fname << std::endl; 120 | } 121 | inp.close(); 122 | } 123 | -------------------------------------------------------------------------------- /ppm.h: -------------------------------------------------------------------------------- 1 | //Process a binary PPM file 2 | #include 3 | #include 4 | 5 | #ifndef PPM_H 6 | #define PPM_H 7 | 8 | class ppm { 9 | void init(); 10 | //info about the PPM file (height and width) 11 | unsigned int nr_lines; 12 | unsigned int nr_columns; 13 | std::vector buff; 14 | 15 | public: 16 | //arrays for storing the R,G,B values 17 | std::vector r; 18 | std::vector g; 19 | std::vector b; 20 | // 21 | unsigned int height; 22 | unsigned int width; 23 | unsigned int max_col_val; 24 | //total number of elements (pixels) 25 | unsigned int size; 26 | 27 | ppm(); 28 | //create a PPM object and fill it with data stored in fname 29 | ppm(const std::string &fname); 30 | //create an "epmty" PPM image with a given width and height;the R,G,B arrays are filled with zeros 31 | ppm(const unsigned int _width, const unsigned int _height); 32 | //read the PPM image from fname 33 | void read(const std::string &fname); 34 | //write the PPM image in fname 35 | void write(const std::string &fname); 36 | }; 37 | 38 | #endif --------------------------------------------------------------------------------