/* Worley noise generator. ./worley_noise > output.pgm https://en.wikipedia.org/wiki/Worley_noise */ #include #include #include #include #ifdef _WIN32 #include #include #endif /* Size of each cell in pixels. Cell sizes are fixed, so a larger output image results in denser noise patterns. */ #define CELL_SIZE 128 /* Maximum distance from a pixel to any point. */ #define MAX_DISTANCE (CELL_SIZE * sqrt(2.0)) typedef struct { double x, y; } XY; int main(int argc, char **argv) { int width, height, grid_width, grid_height, x, y, gx, gy, dx, dy; XY *points, *p; double d, min_d; if( argc != 3 || (width = atoi(argv[1])) <= 0 || (height = atoi(argv[2])) <= 0 ) { return printf("%s \n", *argv); } if( width >= 0x8000 || height >= 0x8000 ) return !puts("Output size too large."); #ifdef _WIN32 setmode(STDOUT_FILENO, O_BINARY); #endif srand(time(NULL)); /* Initialize random grid cells. We need enough cells to cover each edge plus extra margin cells just outside of the output area, so +1 to account for integer truncation, and +2 for the margins. */ grid_width = width / CELL_SIZE + 3; grid_height = height / CELL_SIZE + 3; if( (points = (XY*)malloc(grid_width * grid_height * sizeof(XY))) == NULL ) return !puts("Not enough memory"); for(y = 0; y < grid_height; y++) { for(x = 0; x < grid_width; x++) { points[y * grid_width + x].x = (double)rand() / (RAND_MAX + 1u) * CELL_SIZE; points[y * grid_width + x].y = (double)rand() / (RAND_MAX + 1u) * CELL_SIZE; } } /* Generate pixels. */ printf("P5\n%d %d\n255\n", width, height); for(y = 0; y < height; y++) { gy = y / CELL_SIZE + 1; for(x = 0; x < width; x++) { gx = x / CELL_SIZE + 1; /* Find minimum distance to all nearby points. */ min_d = MAX_DISTANCE; for(dy = -1; dy <= 1; dy++) { for(dx = -1; dx <= 1; dx++) { p = &points[(gy + dy) * grid_width + (gx + dx)]; d = hypot((x % CELL_SIZE) - (p->x + dx * CELL_SIZE), (y % CELL_SIZE) - (p->y + dy * CELL_SIZE)); if( min_d > d ) min_d = d; } } /* Generate pixel value based on normalized distance. */ d = min_d / MAX_DISTANCE; fputc((int)(d * 255), stdout); } } free(points); return 0; }