PerlinNoise.cpp

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         // push a first element onto the stack
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         // set default values and allocate memory
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         // free top element 
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         // calculate a random offset in order to get a different noise
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                         // sum up all 
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 

Generated on Sun Jul 2 13:20:39 2006 for Demo by  doxygen 1.4.6-NO