00001 #include "PerlinNoise.h"
00002
00003 PerlinNoise::PerlinNoise (int size_x_, int size_y_)
00004 {
00005 size_x = size_x_;
00006 size_y = size_y_;
00007
00008
00009 top = NULL;
00010 Push ();
00011
00012 }
00013
00014 PerlinNoise::~PerlinNoise ()
00015 {
00016 while (!IsEmpty ())
00017 {Pop ();}
00018 }
00019
00020 void PerlinNoise::Push ()
00021 {
00022 StackElem * top_noise;
00023
00024 if (top == NULL)
00025 {
00026 top = new StackElem;
00027 top->next = NULL;
00028 }
00029 else
00030 {
00031 top_noise = new StackElem;
00032 top_noise->next = top;
00033 top = top_noise;
00034 }
00035
00036
00037 SetParameters (1.0, 0.25, 8, true);
00038 SetBackgroundColor (0.0f, 0.0f, 0.0f, 1.0f);
00039 SetForegroundColor (1.0f, 1.0f, 1.0f, 1.0f);
00040
00041 top->interpolation = CUBIC_INTERPOLATION;
00042 top->perlin_buffer = new float[size_x * size_y];
00043 top->color_buffer = new float[size_x * size_y * 4];
00044 }
00045
00046 void PerlinNoise::Pop ()
00047 {
00048 StackElem * old_top;
00049
00050 if (IsEmpty ())
00051 {printf ("PerlinNoise: Cannot pop from empty stack\n"); return;}
00052
00053 old_top = top;
00054 top = top->next;
00055
00056
00057 delete old_top->perlin_buffer;
00058 delete old_top->color_buffer;
00059 delete old_top;
00060 }
00061
00062 bool PerlinNoise::IsEmpty ()
00063 {
00064 return top == NULL;
00065 }
00066
00067 void PerlinNoise::FlushToColorBuffer ()
00068 {
00069 for (int index = 0; index < size_x * size_y; index++)
00070 {
00071 for (int c = 0; c < 4; c++)
00072 {top->color_buffer[4*index + c] = top->background[c] * (1 - top->perlin_buffer[index]) + top->foreground[c] * top->perlin_buffer[index];}
00073 }
00074 }
00075
00076 void PerlinNoise::SetBackgroundColor (float red, float green, float blue, float alpha)
00077 {
00078 top->background[0] = red;
00079 top->background[1] = green;
00080 top->background[2] = blue;
00081 top->background[3] = alpha;
00082 }
00083
00084 void PerlinNoise::SetForegroundColor (float red, float green, float blue, float alpha)
00085 {
00086 top->foreground[0] = red;
00087 top->foreground[1] = green;
00088 top->foreground[2] = blue;
00089 top->foreground[3] = alpha;
00090 }
00091
00092 void PerlinNoise::SetParameters (float frequency_, float persistence_, int octaves_, bool smooth_)
00093 {
00094 top->frequency = frequency_;
00095 top->persistence = persistence_;
00096 top->octaves = octaves_;
00097 top->smooth = smooth_;
00098 }
00099
00100 void PerlinNoise::SetInterpolationMode (int mode)
00101 {
00102 top->interpolation = mode;
00103 }
00104
00105 void PerlinNoise::GetDimensions (int & dim_x, int & dim_y)
00106 {
00107 dim_x = size_x;
00108 dim_y = size_y;
00109 }
00110
00111 void PerlinNoise::GenerateNoise ()
00112 {
00113 float total;
00114 float amplitude;
00115 float base_frequency;
00116 float current_frequency;
00117
00118 base_frequency = top->frequency / sqrt ((float)(size_x*size_x + size_y*size_y)) / 1.414;
00119
00120
00121 float x_rand = (((float)(rand())) / ((float)(RAND_MAX))) * 100.0f;
00122 float y_rand = (((float)(rand())) / ((float)(RAND_MAX))) * 100.0f;
00123
00124 for (int y = 0; y < size_y; y++)
00125 {
00126 for (int x = 0; x < size_x; x++)
00127 {
00128 total = 0.0f;
00129 amplitude = 1.0f;
00130 current_frequency = base_frequency;
00131
00132
00133 for (int k = 0; k < top->octaves; k++)
00134 {
00135 if (!top->smooth)
00136 {total += GetNoiseValue ((x_rand + x) * current_frequency, (y_rand + y) * current_frequency) * amplitude;}
00137 else
00138 {total += GetSmoothedValue ((x_rand + x) * current_frequency, (y_rand + y) * current_frequency) * amplitude;}
00139
00140 amplitude *= top->persistence;
00141 current_frequency *= 2;
00142 }
00143
00144 top->perlin_buffer[x + size_x * y] = total;
00145 }
00146 }
00147 }
00148
00149 void PerlinNoise::TransformXY (float (* processor)(float x, float y, float value))
00150 {
00151 float base_frequency;
00152
00153 base_frequency = top->frequency / sqrt ((float)(size_x*size_x + size_y*size_y)) / 1.414;
00154
00155 for (int y = 0; y < size_y; y++)
00156 {
00157 for (int x = 0; x < size_x; x++)
00158 {
00159 top->perlin_buffer[x + size_x * y] = processor (x * base_frequency, y * base_frequency, top->perlin_buffer[x + size_x * y]);
00160 }
00161 }
00162 }
00163
00164 void PerlinNoise::TransformAB (float a, float b, float (* processor)(float a, float b, float value))
00165 {
00166 for (int index = 0; index < size_x * size_y; index++)
00167 {
00168 top->perlin_buffer[index] = processor (a, b, top->perlin_buffer[index]);
00169 }
00170 }
00171
00172 void PerlinNoise::ExportRGB256 (GLubyte * data_pointer)
00173 {
00174 int byte;
00175
00176 for (int index = 0; index < size_x * size_y * 4; index++)
00177 {
00178 byte = 255.0f * top->color_buffer[index];
00179 if (byte > 255) byte = 255;
00180 if (byte < 0) byte = 0;
00181
00182 if (index%4 != 3)
00183 {data_pointer [(index/4)*3 + index%4] = byte;}
00184 }
00185 }
00186
00187 void PerlinNoise::Export (float * data_pointer)
00188 {
00189 for (int index = 0; index < size_x * size_y; index++)
00190 {
00191 data_pointer[index] = top->perlin_buffer[index];
00192 }
00193 }
00194
00195 void PerlinNoise::CombineColorBuffers (float (* combiner)(float val_1, float val_2))
00196 {
00197 if (top == NULL || top->next == NULL)
00198 {printf ("Perlin Noise: Cannot combine color buffers because there are less than two\n");}
00199
00200 float * buffer_1;
00201 float * buffer_2;
00202
00203 buffer_1 = top->color_buffer;
00204 buffer_2 = top->next->color_buffer;
00205
00206 for (int index = 0; index < size_x * size_y * 4; index++)
00207 {
00208 buffer_2[index] = combiner (buffer_1[index], buffer_2[index]);
00209 }
00210
00211 Pop ();
00212 }
00213
00214 void PerlinNoise::CombineColorBuffersAB (float a, float b, float (* combiner)(float a, float b, float val_1, float val_2))
00215 {
00216 if (top == NULL || top->next == NULL)
00217 {printf ("Perlin Noise: Cannot combine color buffers because there are less than two\n");}
00218
00219 float * buffer_1;
00220 float * buffer_2;
00221
00222 buffer_1 = top->color_buffer;
00223 buffer_2 = top->next->color_buffer;
00224
00225 for (int index = 0; index < size_x * size_y * 4; index++)
00226 {
00227 buffer_2[index] = combiner (a, b, buffer_1[index], buffer_2[index]);
00228 }
00229
00230 Pop ();
00231 }
00232
00233 void PerlinNoise::SmoothBorder (int border)
00234 {
00235 if (border == 0) return;
00236
00237 for (int y = 0; y < size_y; y++)
00238 {
00239 for (int x = 0; x < size_x; x++)
00240 {
00241 if (x < border)
00242 {
00243 top->perlin_buffer[x + y * size_x] *= 1 - ((float)(border - x)) / border;
00244 top->perlin_buffer[x + y * size_x] *= 1 - ((float)(border - x)) / border;
00245 }
00246 if (y < border)
00247 {
00248 top->perlin_buffer[x + y * size_x] *= 1 - ((float)(border - y)) / border;
00249 top->perlin_buffer[x + y * size_x] *= 1 - ((float)(border - y)) / border;
00250 }
00251 if (x > size_x - border - 1)
00252 {
00253 top->perlin_buffer[x + y * size_x] *= 1 - ((float)(border - (size_x - x - 1))) / border;
00254 top->perlin_buffer[x + y * size_x] *= 1 - ((float)(border - (size_x - x - 1))) / border;
00255 }
00256 if (y > size_y - border - 1)
00257 {
00258 top->perlin_buffer[x + y * size_x] *= 1 - ((float)(border - (size_y - y - 1))) / border;
00259 top->perlin_buffer[x + y * size_x] *= 1 - ((float)(border - (size_y - y - 1))) / border;
00260 }
00261 }
00262 }
00263 }
00264
00265 float PerlinNoise::GetSmoothedValue (float x, float y)
00266 {
00267 float weighted_edges;
00268 float weighted_corners;
00269 float weighted_center;
00270
00271 weighted_center = GetNoiseValue (x, y) / 4.0f;
00272 weighted_edges = (GetNoiseValue (x-1, y) + GetNoiseValue (x+1, y)+ GetNoiseValue (x, y-1) + GetNoiseValue (x, y+1)) / 8.0f;
00273 weighted_corners = (GetNoiseValue (x-1, y-1) + GetNoiseValue (x+1, y-1) + GetNoiseValue (x+1, y+1) + GetNoiseValue (x-1, y+1)) / 16.0f;
00274
00275 return weighted_center + weighted_edges + weighted_corners;
00276 }
00277
00278 float PerlinNoise::GetNoiseValue (float x, float y)
00279 {
00280 int x_int, y_int;
00281 float x_resi, y_resi;
00282 float x0y0, x1y0, x0y1, x1y1;
00283 float interpol_y0, interpol_y1;
00284 float result;
00285
00286 x_int = (int)x;
00287 y_int = (int)y;
00288 x_resi = x - x_int;
00289 y_resi = y - y_int;
00290
00291 x0y0 = GetNoise2D (x_int, y_int);
00292 x1y0 = GetNoise2D (x_int + 1, y_int);
00293 x0y1 = GetNoise2D (x_int, y_int + 1);
00294 x1y1 = GetNoise2D (x_int + 1, y_int + 1);
00295
00296 interpol_y0 = Interpolate (x0y0, x1y0, x_resi);
00297 interpol_y1 = Interpolate (x0y1, x1y1, x_resi);
00298 result = Interpolate (interpol_y0, interpol_y1, y_resi);
00299
00300 return result;
00301 }
00302
00303 float PerlinNoise::GetNoise2D (int x, int y)
00304 {
00305 int n;
00306 float res;
00307
00308 n = x + y * 57;
00309 n = (n<<13) ^ n;
00310 res = (float)( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff ) / 1073741824.0);
00311
00312 return res;
00313 }
00314
00315 float PerlinNoise::Interpolate (float value_1, float value_2, float fraction)
00316 {
00317 switch (top->interpolation)
00318 {
00319 case LINEAR_INTERPOLATION: return LinearInterpolation (value_1, value_2, fraction);
00320 break;
00321 case COSINE_INTERPOLATION: return CosineInterpolation (value_1, value_2, fraction);
00322 break;
00323 case CUBIC_INTERPOLATION: return CubicInterpolation (value_1, value_2, fraction);
00324 break;
00325 default: printf ("Unknown interpolation mode\n");
00326 }
00327
00328 return 0.0f;
00329 }
00330
00331 float PerlinNoise::LinearInterpolation (float value_1, float value_2, float fraction)
00332 {
00333 return value_1 * (1 - fraction) + value_2 * fraction;
00334 }
00335
00336 float PerlinNoise::CosineInterpolation (float value_1, float value_2, float fraction)
00337 {
00338 fraction = (1 - cos (fraction * MY_PI)) * 0.5f;
00339 return value_1 * (1 - fraction) + value_2 * fraction;
00340 }
00341
00342 float PerlinNoise::CubicInterpolation (float value_1, float value_2, float fraction)
00343 {
00344 return value_1 * (3*(1-fraction)*(1-fraction) - 2*(1-fraction)*(1-fraction)*(1-fraction)) +
00345 value_2 * (3*fraction*fraction - 2*fraction*fraction*fraction);
00346 }
00347
00348
00349 float PerlinNoise::RangeTransform (float a, float b, float perlin_xy)
00350 {
00351 if (perlin_xy < a) perlin_xy = a;
00352 if (perlin_xy > b) perlin_xy = b;
00353
00354 return perlin_xy;
00355 }
00356
00357 float PerlinNoise::LinearTransform (float a, float b, float perlin_xy)
00358 {
00359 return a * perlin_xy + b;
00360 }
00361
00362 float PerlinNoise::MarblyTransform (float x, float y, float perlin_xy)
00363 {
00364 return cos (x + perlin_xy);
00365 }
00366
00367 float PerlinNoise::GrainyTransform (float x, float y, float perlin_xy)
00368 {
00369 float grain;
00370
00371 grain = perlin_xy * 20;
00372 return (grain - (int)(grain)) + perlin_xy;
00373 }
00374
00375 float PerlinNoise::SumCombiner (float val_1, float val_2)
00376 {
00377 return val_1 + val_2;
00378 }
00379
00380 float PerlinNoise::ProductCombiner (float val_1, float val_2)
00381 {
00382 return val_1 * val_2;
00383 }
00384
00385 float PerlinNoise::MaximumCombiner (float val_1, float val_2)
00386 {
00387 if (val_1 > val_2 ) return val_1; else return val_2;
00388 }
00389
00390 float PerlinNoise::WeightedSumCombiner (float weight_1, float weight_2, float val_1, float val_2)
00391 {
00392 return weight_1 * val_1 + weight_2 * val_2;
00393 }
00394