optimized AngleVectors calls (pass NULL for vectors that should not be generated)
[xonotic/darkplaces.git] / fractalnoise.c
1
2 #include "quakedef.h"
3
4 void fractalnoise(byte *noise, int size, int startgrid)
5 {
6         int x, y, g, g2, amplitude, min, max, size1 = size - 1, sizepower, gridpower;
7         int *noisebuf;
8 #define n(x,y) noisebuf[((y)&size1)*size+((x)&size1)]
9
10         for (sizepower = 0;(1 << sizepower) < size;sizepower++);
11         if (size != (1 << sizepower))
12                 Sys_Error("fractalnoise: size must be power of 2\n");
13
14         for (gridpower = 0;(1 << gridpower) < startgrid;gridpower++);
15         if (startgrid != (1 << gridpower))
16                 Sys_Error("fractalnoise: grid must be power of 2\n");
17
18         startgrid = bound(0, startgrid, size);
19
20         amplitude = 32767;
21         noisebuf = qmalloc(size*size*sizeof(int));
22         memset(noisebuf, 0, size*size*sizeof(int));
23
24         for (g2 = startgrid;g2;g2 >>= 1)
25         {
26                 // brownian motion (at every smaller level there is random behavior)
27                 amplitude >>= 1;
28                 for (y = 0;y < size;y += g2)
29                         for (x = 0;x < size;x += g2)
30                                 n(x,y) += (rand()&amplitude);
31
32                 g = g2 >> 1;
33                 if (g)
34                 {
35                         // subdivide, diamond-square algorythm (really this has little to do with squares)
36                         // diamond
37                         for (y = 0;y < size;y += g2)
38                                 for (x = 0;x < size;x += g2)
39                                         n(x+g,y+g) = (n(x,y) + n(x+g2,y) + n(x,y+g2) + n(x+g2,y+g2)) >> 2;
40                         // square
41                         for (y = 0;y < size;y += g2)
42                                 for (x = 0;x < size;x += g2)
43                                 {
44                                         n(x+g,y) = (n(x,y) + n(x+g2,y) + n(x+g,y-g) + n(x+g,y+g)) >> 2;
45                                         n(x,y+g) = (n(x,y) + n(x,y+g2) + n(x-g,y+g) + n(x+g,y+g)) >> 2;
46                                 }
47                 }
48         }
49         // find range of noise values
50         min = max = 0;
51         for (y = 0;y < size;y++)
52                 for (x = 0;x < size;x++)
53                 {
54                         if (n(x,y) < min) min = n(x,y);
55                         if (n(x,y) > max) max = n(x,y);
56                 }
57         max -= min;
58         // normalize noise and copy to output
59         for (y = 0;y < size;y++)
60                 for (x = 0;x < size;x++)
61                         *noise++ = (n(x,y) - min) * 255 / max;
62         qfree(noisebuf);
63 #undef n
64 }