Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * perlin.c - Creates an image of Perlin (gradient) noise. Optionally writes it
- * to a csv file.
- *
- * Compilling:
- * gcc perlin.c -std=c99 -o out
- *
- * Running:
- * ./out [FNAME] [W] [H] [HSIZE] [SEED]
- *
- * Generate a WxH B&W image consisting of Perlin noise. Writes to a csv file
- * called FNAME only if FNAME is passed and valid (e.g. of invalid in *nix:
- * "/"). 8 different gradients are used, that is hardcoded. Assign one gradient
- * for each point using a "hashtable" of size HSIZE, consisting of random
- * numbers used to map points to gradients. Use SEED in srand(). See main()
- * for defaults.
- *
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <time.h>
- #define floor(x) x >= 0 ? (int)x : (int)x-1 /* avoids linking math */
- double fade(double x) {
- /* The fade function, 6x^5 - 15x^4 + 10x^3 */
- return x*x*x*(x*(x*6-15)+10);
- }
- double dot(int *g, double y, double x) {
- /* dot product between the gradient [gy, gx] and [y, x] */
- return g[0]*y + g[1]*x;
- }
- double lerp(double a, double b, double w) {
- /* Linear interpolation of a and b with weight w */
- return (1-w)*a + w*b;
- }
- int *grad(size_t *hashes, size_t hsize, int grads[][2], int i, int j) {
- /* Given the "hashetable" of size hsize, determine the gradient for (i, j) */
- return grads[hashes[i%hsize + hashes[j%hsize]] % 8];
- }
- double interpol(size_t *hashes, size_t hsize, int grads[][2], double y,
- double x) {
- /*
- * Bilinear interpol on (y, x) using 4 gradients instead
- * of 4 values, and a fade function as weight. Grads is a list of
- * gradients, hashes the "hashtable" used to pick gradients from the list and
- * hsize the table's size. Returns the interpolated noise value at (y, x)
- * (in -1, 1).
- */
- /* Get the coord of the top-left gradient of the grid (y, x) falls in */
- int j = floor(x);
- int i = floor(y);
- /* Get the distance (y, x) is from it */
- double dx = x-j;
- double dy = y-i;
- /* Influence of (g)radient(i)(j) (starting at the top-left one) */
- double g00 = dot(grad(hashes, hsize, grads, i, j), dy, dx);
- double g01 = dot(grad(hashes, hsize, grads, i, j+1), dy, dx-1);
- double g10 = dot(grad(hashes, hsize, grads, i+1, j), dy-1, dx);
- double g11 = dot(grad(hashes, hsize, grads, i+1, j+1), dy-1, dx-1);
- /* Interpolate the influences using the blending function */
- /* Linear interpol the top 2 */
- double lt = lerp(g00, g01, fade(dx));
- /* Linear interpol the bottom 2 */
- double lb = lerp(g10, g11, fade(dx));
- /* Linear interpol lb lt, completing the bilienear interpol */
- return lerp(lt, lb, fade(dy));
- }
- int main (int argc, char **argv) {
- //
- // Create 8 "gradients" (up, down, left, right, diagonals)
- //
- // Create a "hash table" with random numbers that a function will use to
- // map coordinates to a gradient pseudo-randomly.
- //
- // Allocate space for image
- //
- // For each px in image
- // map it to [0, 1] (why?)
- // interpolate the noise value at that point
- // scale to 255
- // write to img
- //
- // Write to file if requesred, cleanup and exit
- //
- /* Default and user-defined parameters */
- char const *fname = NULL;
- size_t w = 800, h = 600, hsize = 256;
- double seed = time(NULL);
- if (argc >= 3) w = atoi(argv[2]);
- if (argc >= 4) h = atoi(argv[3]);
- if (argc >= 5) hsize = atoi(argv[4]);
- if (argc >= 6) seed = atof(argv[5]);
- srand(seed);
- int grads[8][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1,
- 0}, {1, 1}};
- /* Generate the hashes */
- size_t *hashes = (size_t*)malloc(hsize*sizeof(size_t));
- for (size_t i = 0; i < hsize; ++i) {
- hashes[i] = i;
- }
- /* Knuth shuffle */
- for (size_t i = hsize-1; i > 0; --i) {
- size_t j = rand() % i;
- size_t tmp = hashes[j];
- hashes[j] = hashes[i];
- hashes[i] = tmp;
- }
- /* Allocate space for the img */
- unsigned int **img = (unsigned int**)malloc(h*sizeof(unsigned int*));
- for (size_t i = 0; i < h; ++i) {
- img[i] = (unsigned int*)malloc(w*sizeof(unsigned int));
- /* Populate the image with noisw */
- for (size_t j = 0; j < w; ++j) {
- /* Map (i, j) to a point in [0, 1] */
- double x = j/(double)w;
- double y = i/(double)h;
- /* Scale the noise (which goes from -1 to 1) to [0, 255] */
- img[i][j] = ((interpol(hashes, hsize, grads, y, x)+1)*255)/2;
- }
- }
- free(hashes);
- /* Print to file if requested and free */
- if (argc >= 2) fname = argv[1];
- FILE *f = fopen(fname, "w");
- for (size_t i = 0; i < h; ++i) {
- if (f) {
- for (size_t j = 0; j < w; ++j) {
- fprintf(f, "%d,", img[i][j]);
- }
- fprintf(f, "\n");
- }
- free(img[i]);
- }
- free(img);
- if (f) fclose(f);
- return EXIT_SUCCESS;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement