fractalnoise enhancements, better smoke textures, better bubble explosions, blood...
[xonotic/darkplaces.git] / fractalnoise.c
1
2 #include <stdlib.h>
3
4 void fractalnoise(unsigned char *noise, int size, int startgrid)
5 {
6         int x, y, g, g2, amplitude, min, max, size1 = size - 1;
7         int *noisebuf;
8 #define n(x,y) noisebuf[((y)&size1)*size+((x)&size1)]
9         if (startgrid > size)
10                 startgrid = size;
11         noisebuf = calloc(size*size, sizeof(int));
12
13         amplitude = 32767;
14         // quick 1x1 case which the rest of the code can't handle
15         if (startgrid < 2)
16         {
17                 for (x = 0;x < size*size;x++)
18                         *noise++ = (rand()&255);
19                 return;
20         }
21         g2 = startgrid;
22         // clear the starting grid (the rest does not need to be cleared, it will simply be overwritten)
23         for (y = 0;y < size;y += g2)
24                 for (x = 0;x < size;x += g2)
25                         n(x,y) = 0;
26         for (;(g = g2 >> 1) >= 1;g2 >>= 1)
27         {
28                 // subdivide, diamond-square algorythm (really this has little to do with squares)
29                 // diamond
30                 for (y = 0;y < size;y += g2)
31                         for (x = 0;x < size;x += g2)
32                                 n(x+g,y+g) = (n(x,y) + n(x+g2,y) + n(x,y+g2) + n(x+g2,y+g2)) >> 2;
33                 // square
34                 for (y = 0;y < size;y += g2)
35                         for (x = 0;x < size;x += g2)
36                         {
37                                 n(x+g,y) = (n(x,y) + n(x+g2,y) + n(x+g,y-g) + n(x+g,y+g)) >> 2;
38                                 n(x,y+g) = (n(x,y) + n(x,y+g2) + n(x-g,y+g) + n(x+g,y+g)) >> 2;
39                         }
40                 // brownian motion theory
41                 amplitude >>= 1;
42                 for (y = 0;y < size;y += g)
43                         for (x = 0;x < size;x += g)
44                                 n(x,y) += (rand()&amplitude);
45         }
46         // find range of noise values
47         min = max = 0;
48         for (y = 0;y < size;y++)
49                 for (x = 0;x < size;x++)
50                 {
51                         if (n(x,y) < min) min = n(x,y);
52                         if (n(x,y) > max) max = n(x,y);
53                 }
54         max -= min;
55         // normalize noise and copy to output
56         for (y = 0;y < size;y++)
57                 for (x = 0;x < size;x++)
58                         *noise++ = (n(x,y) - min) * 255 / max;
59         free(noisebuf);
60 #undef n
61 }