131 lines
3.0 KiB
C
131 lines
3.0 KiB
C
#include "main.h"
|
|
|
|
#include <math.h>
|
|
|
|
#ifndef MAX
|
|
#define max( a,b ) ( ((a) > (b) ) ? (a) : (b) )
|
|
#endif
|
|
|
|
//variables
|
|
int width, height, size;
|
|
float corner_value[4];
|
|
|
|
//functions
|
|
int closest_pow_2(int);
|
|
void init_height_map(float**);
|
|
void start_diamond_square(float**);
|
|
void diamond_square(float**,int,int,int,int);
|
|
float average(float,float);
|
|
float average_noisy(float,float);
|
|
float average_t(float*, int);
|
|
void apply_noise(float*);
|
|
|
|
void create_map(int w, int h){
|
|
width = w;
|
|
height = h;
|
|
|
|
int i;
|
|
float** height_map;
|
|
|
|
size=closest_pow_2(max(w,h));
|
|
|
|
height_map = (float**) malloc(sizeof(float*)*(size+1));
|
|
for(i=0;i<=size;i++)
|
|
height_map[i]=malloc(sizeof(float)*(size+1));
|
|
|
|
printf("init height map...\n");
|
|
init_height_map(height_map);
|
|
|
|
printf("generate height map...\n");
|
|
//generate height map
|
|
start_diamond_square(height_map);
|
|
|
|
printf("erosion\n");
|
|
|
|
|
|
|
|
printf("finished generation! \n");
|
|
|
|
}
|
|
|
|
int closest_pow_2(int x){
|
|
return pow(2,floor(log(x)/log(2))+1);
|
|
}
|
|
|
|
void init_height_map(float** h_map){
|
|
h_map[0][0]=0.7;
|
|
h_map[size][0]=0.3;
|
|
h_map[size][size]=0.9;
|
|
h_map[0][size]=0.8;
|
|
}
|
|
|
|
void start_diamond_square(float ** h_map){
|
|
diamond_square(h_map,0,size,0,size);
|
|
}
|
|
|
|
void dummy(int x1, int y1, int x2, int y2, int avg_x,int avg_y){
|
|
}
|
|
|
|
void diamond_square(float** h_map,int x1,int x2,int y1, int y2){
|
|
int avg_x, avg_y;
|
|
float avg_value;
|
|
|
|
//get value of corner from h_map
|
|
corner_value[0] = h_map[x1][y1]; //up_left
|
|
corner_value[1] = h_map[x2][y1]; //up_right
|
|
corner_value[2] = h_map[x2][y2]; //down_right
|
|
corner_value[3] = h_map[x1][y2]; //down_left
|
|
|
|
//process coordinate of center
|
|
avg_x = average(x1,x2);
|
|
avg_y = average(y1,y2);
|
|
|
|
//dummy(x1,y1,x2,y2,avg_x,avg_y);
|
|
//Diamond Step
|
|
//process average value of the corner
|
|
avg_value = average_t(corner_value,4);
|
|
|
|
apply_noise(&avg_value);
|
|
//affect value
|
|
h_map[avg_x][avg_y]=avg_value;
|
|
|
|
// Square Step
|
|
//update value of the four mid-point between corner, following clockwise orde, and adding noise
|
|
h_map[avg_x][y1] = average_noisy(corner_value[0], corner_value[1]); // up
|
|
h_map[x2][avg_y] = average_noisy(corner_value[1], corner_value[2]); // right
|
|
h_map[avg_x][y2] = average_noisy(corner_value[2], corner_value[3]); // down
|
|
h_map[x1][avg_y] = average_noisy(corner_value[3], corner_value[0]); // left
|
|
|
|
//recursive call to diamond_square
|
|
int offset = x2-x1;
|
|
|
|
if (offset > 2){
|
|
diamond_square(h_map, x1, avg_x, y1, avg_y); //up_left square
|
|
diamond_square(h_map, avg_x, x2, y1, avg_y); // up_right square
|
|
diamond_square(h_map, avg_x, x2, avg_y, y2); // down_right square
|
|
diamond_square(h_map, x1, avg_x, avg_y, y2); // down_left square
|
|
}
|
|
}
|
|
|
|
float average(float a, float b){
|
|
return (a+b)/2;
|
|
}
|
|
|
|
float average_noisy(float a, float b){
|
|
float value = average(a,b);
|
|
apply_noise(&value);
|
|
return value;
|
|
}
|
|
|
|
float average_t(float* tab, int size){
|
|
int i;
|
|
float avg_value=0;
|
|
for(i=0;i<size;i++)
|
|
avg_value += tab[i];
|
|
return avg_value/size;
|
|
}
|
|
|
|
void apply_noise(float* value){
|
|
float noise = (float)rand()/(float)RAND_MAX;
|
|
*value = *value + noise - 1;
|
|
} |