Advertisement
Guest User

Untitled

a guest
Jan 21st, 2015
149
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.70 KB | None | 0 0
  1. /*
  2.  * perlin.c - Creates an image of Perlin (gradient) noise. Optionally writes it
  3.  * to a csv file.
  4.  *
  5.  * Compilling:
  6.  * gcc perlin.c -std=c99 -o out
  7.  *
  8.  * Running:
  9.  * ./out [FNAME] [W] [H] [HSIZE] [SEED]
  10.  *
  11.  * Generate a WxH B&W image consisting of Perlin noise. Writes to a csv file
  12.  * called FNAME only if FNAME is passed and valid (e.g. of invalid in *nix:
  13.  * "/"). 8 different gradients are used, that is hardcoded. Assign one gradient
  14.  * for each point using a "hashtable" of size HSIZE, consisting of random
  15.  * numbers used to map points to gradients. Use SEED in srand(). See main()
  16.  * for defaults.
  17.  *
  18.  */
  19.  
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <time.h>
  23.  
  24. #define floor(x) x >= 0 ? (int)x : (int)x-1  /* avoids linking math */
  25.  
  26. double fade(double x) {
  27.   /* The fade function, 6x^5 - 15x^4 + 10x^3 */
  28.   return x*x*x*(x*(x*6-15)+10);
  29. }
  30.  
  31. double dot(int *g, double y, double x) {
  32.   /* dot product between the gradient [gy, gx] and [y, x] */
  33.   return g[0]*y + g[1]*x;
  34. }
  35.  
  36. double lerp(double a, double b, double w) {
  37.   /* Linear interpolation of a and b with weight w */
  38.   return (1-w)*a + w*b;
  39. }
  40.  
  41. int *grad(size_t *hashes, size_t hsize, int grads[][2], int i, int j) {
  42.   /* Given the "hashetable" of size hsize, determine the gradient for (i, j) */
  43.   return grads[hashes[i%hsize + hashes[j%hsize]] % 8];
  44. }
  45.  
  46. double interpol(size_t *hashes, size_t hsize, int grads[][2], double y,
  47.     double x) {
  48.   /*
  49.    * Bilinear interpol on (y, x) using 4 gradients instead
  50.    * of 4 values, and a fade function as weight. Grads is a list of
  51.    * gradients, hashes the "hashtable" used to pick gradients from the list and
  52.    * hsize the table's size. Returns the interpolated noise value at (y, x)
  53.    * (in -1, 1).
  54.    */
  55.  
  56.   /* Get the coord of the top-left gradient of the grid (y, x) falls in */
  57.   int j = floor(x);
  58.   int i = floor(y);
  59.   /* Get the distance (y, x) is from it */
  60.   double dx = x-j;
  61.   double dy = y-i;
  62.   /* Influence of (g)radient(i)(j) (starting at the top-left one) */
  63.   double g00 = dot(grad(hashes, hsize, grads, i, j), dy, dx);
  64.   double g01 = dot(grad(hashes, hsize, grads, i, j+1), dy, dx-1);
  65.   double g10 = dot(grad(hashes, hsize, grads, i+1, j), dy-1, dx);
  66.   double g11 = dot(grad(hashes, hsize, grads, i+1, j+1), dy-1, dx-1);
  67.   /* Interpolate the influences using the blending function */
  68.   /* Linear interpol the top 2 */
  69.   double lt = lerp(g00, g01, fade(dx));
  70.   /* Linear interpol the bottom 2 */
  71.   double lb = lerp(g10, g11, fade(dx));
  72.   /* Linear interpol lb lt, completing the bilienear interpol */
  73.   return lerp(lt, lb, fade(dy));
  74. }
  75.  
  76. int main (int argc, char **argv) {
  77.  
  78.   //
  79.   // Create 8 "gradients" (up, down, left, right, diagonals)
  80.   //
  81.   // Create a "hash table" with random numbers that a function will use to
  82.   // map coordinates to a gradient pseudo-randomly.
  83.   //
  84.   // Allocate space for image
  85.   //
  86.   // For each px in image
  87.   //  map it to [0, 1] (why?)
  88.   //  interpolate the noise value at that point
  89.   //  scale to 255
  90.   //  write to img
  91.   //
  92.   // Write to file if requesred, cleanup and exit
  93.   //
  94.  
  95.   /* Default and user-defined parameters */
  96.   char const *fname = NULL;
  97.   size_t w = 800, h = 600, hsize = 256;
  98.   double seed = time(NULL);
  99.   if (argc >= 3) w = atoi(argv[2]);
  100.   if (argc >= 4) h = atoi(argv[3]);
  101.   if (argc >= 5) hsize = atoi(argv[4]);
  102.   if (argc >= 6) seed = atof(argv[5]);
  103.   srand(seed);
  104.   int grads[8][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1,
  105.     0}, {1, 1}};
  106.  
  107.   /* Generate the hashes */
  108.   size_t *hashes = (size_t*)malloc(hsize*sizeof(size_t));
  109.   for (size_t i = 0; i < hsize; ++i) {
  110.     hashes[i] = i;
  111.   }
  112.   /* Knuth shuffle */
  113.   for (size_t i = hsize-1; i > 0; --i) {
  114.     size_t j = rand() % i;
  115.     size_t tmp = hashes[j];
  116.     hashes[j] = hashes[i];
  117.     hashes[i] = tmp;
  118.   }
  119.  
  120.   /* Allocate space for the img */
  121.   unsigned int **img = (unsigned int**)malloc(h*sizeof(unsigned int*));
  122.   for (size_t i = 0; i < h; ++i) {
  123.     img[i] = (unsigned int*)malloc(w*sizeof(unsigned int));
  124.     /* Populate the image with noisw */
  125.     for (size_t j = 0; j < w; ++j) {
  126.       /* Map (i, j) to a point in [0, 1]  */
  127.       double x = j/(double)w;
  128.       double y = i/(double)h;
  129.       /* Scale the noise (which goes from -1 to 1) to [0, 255] */
  130.       img[i][j] = ((interpol(hashes, hsize, grads, y, x)+1)*255)/2;
  131.     }
  132.   }
  133.   free(hashes);
  134.  
  135.   /* Print to file if requested and free */
  136.   if (argc >= 2) fname = argv[1];
  137.   FILE *f = fopen(fname, "w");
  138.   for (size_t i = 0; i < h; ++i) {
  139.     if (f) {
  140.       for (size_t j = 0; j < w; ++j) {
  141.         fprintf(f, "%d,", img[i][j]);
  142.       }
  143.       fprintf(f, "\n");
  144.     }
  145.     free(img[i]);
  146.   }
  147.   free(img);
  148.   if (f) fclose(f);
  149.  
  150.   return EXIT_SUCCESS;
  151. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement