Created
May 21, 2012 19:04
-
-
Save biomood/2763999 to your computer and use it in GitHub Desktop.
perlin noise in C, uses lodepng library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdio.h> | |
#include <math.h> | |
#include <time.h> | |
#include "lodepng.h" | |
#define WIDTH 400 | |
#define HEIGHT 400 | |
#define PI (3.141592653589793) | |
static void generatewhitenoise(float m[WIDTH][HEIGHT]); | |
static void generatesmoothnoise(float basenoise[WIDTH][HEIGHT], float smooth[WIDTH][HEIGHT], int octave); | |
static void generateperlinnoise(float basenoise[WIDTH][HEIGHT], float perlin[WIDTH][HEIGHT], int octavecount); | |
static float interpolate(float x0, float x1, float alpha); | |
static float cosineinterpolate(float x0, float x1, float alpha); | |
static void setmatrix(float m[WIDTH][HEIGHT], float val); | |
static void printmatrix(float m[WIDTH][HEIGHT], char title[]); | |
static void matrixtoimage(float m[WIDTH][HEIGHT], char filename[]); | |
void matrixtoimage(float m[WIDTH][HEIGHT], char filename[]) { | |
unsigned char* image = malloc(WIDTH*HEIGHT); | |
int j; | |
for (j=0; j<HEIGHT; j++) { | |
int i; | |
for (i=0; i<WIDTH; i++) { | |
image[(WIDTH * j) + i] = floor(m[i][j] == 1.0 ? 255 : m[i][j] * 256.0); | |
} | |
} | |
LodePNGColorType gray = LCT_GREY; | |
lodepng_encode_file(filename, image, WIDTH, HEIGHT, gray, 8); | |
} | |
void printmatrix(float m[WIDTH][HEIGHT], char title[]) { | |
printf("%s \n", title); | |
int i; | |
for (i=0; i<WIDTH; i++) { | |
int j; | |
for (j=0; j<HEIGHT; j++) { | |
printf("%f, ", m[i][j]); | |
} | |
printf("\n"); | |
} | |
} | |
void setmatrix(float m[WIDTH][HEIGHT], float val) { | |
int i; | |
for (i=0; i<WIDTH; i++) { | |
int j; | |
for (j=0; j<HEIGHT; j++) { | |
m[i][j] = val; | |
} | |
} | |
} | |
float interpolate(float x0, float x1, float alpha) { | |
return x0 * (1-alpha)+alpha*x1; | |
} | |
float cosineinterpolate(float x0, float x1, float alpha) { | |
float alpha2 = (1 - cos(alpha * PI)) / 2; | |
return (x0 * (1 - alpha2) + x1 * alpha2); | |
} | |
void generatewhitenoise(float m[WIDTH][HEIGHT]) { | |
int i; | |
for (i=0; i<WIDTH; i++) { | |
int j; | |
for (j=0; j<HEIGHT; j++) { | |
m[i][j] = (float)rand()/(float)RAND_MAX; | |
} | |
} | |
} | |
void generatesmoothnoise(float basenoise[WIDTH][HEIGHT],float smooth[WIDTH][HEIGHT], int octave) { | |
setmatrix(smooth, 0.0f); | |
int sampleperiod = 1 << octave; | |
float samplefrequency = 1.0f/sampleperiod; | |
int i; | |
for (i=0; i<WIDTH; i++) { | |
int samplei0 = (i/sampleperiod)*sampleperiod; | |
int samplei1 = (samplei0+sampleperiod)%WIDTH; | |
float horizontalblend = (i-samplei0)*samplefrequency; | |
int j; | |
for (j=0; j<HEIGHT; j++) { | |
int samplej0 = (j/sampleperiod)*sampleperiod; | |
int samplej1 = (samplej0+sampleperiod)%HEIGHT; | |
float verticalblend = (j-samplej0)*samplefrequency; | |
float top = cosineinterpolate(basenoise[samplei0][samplej0], basenoise[samplei1][samplej0], horizontalblend); | |
float bottom = cosineinterpolate(basenoise[samplei0][samplej1], basenoise[samplei1][samplej1], horizontalblend); | |
smooth[i][j] = cosineinterpolate(top, bottom, verticalblend); | |
} | |
} | |
} | |
void generateperlinnoise(float basenoise[WIDTH][HEIGHT], float perlin[WIDTH][HEIGHT], int octavecount) { | |
float smooth[octavecount][WIDTH][HEIGHT]; | |
float persistence = 0.7f; | |
int i; | |
for (i=0; i<octavecount; i++) { | |
generatesmoothnoise(basenoise, smooth[i], i); | |
} | |
setmatrix(perlin, 0.0f); | |
float amplitude = 1.0f; | |
float totalamplitude = 1.0f; | |
int octave; | |
for (octave = octavecount - 1; octave >= 0; octave--) { | |
amplitude *= persistence; | |
totalamplitude += amplitude; | |
for (i=0; i<WIDTH; i++) { | |
int j; | |
for (j=0; j<HEIGHT; j++) { | |
perlin[i][j] += smooth[octave][i][j] * amplitude; | |
} | |
} | |
} | |
// normalise | |
for (i=0; i<WIDTH; i++) { | |
int j; | |
for (j=0; j<HEIGHT; j++) { | |
perlin[i][j] /= totalamplitude; | |
} | |
} | |
} | |
int main(int argc, char **argv) { | |
srand(time(NULL)); | |
float m[WIDTH][HEIGHT]; | |
generatewhitenoise(m); | |
// printmatrix(m, "random\0"); | |
float perlin[WIDTH][HEIGHT]; | |
generateperlinnoise(m, perlin, 6); | |
matrixtoimage(perlin, "perlinc.png\0"); | |
// int i; | |
// for (i=0; i<7; i++) { | |
// generatesmoothnoise(m, smooth, i); | |
// // printmatrix(smooth, "smooth\0"); | |
// char str[255]; | |
// sprintf(str, "testsmooth%d.png", i); | |
// matrixtoimage(smooth, str); | |
// } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment