2 #include "quakedef.h"
4 void fractalnoise(unsigned char *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)]
10         for (sizepower = 0;(1 << sizepower) < size;sizepower++);
11         if (size != (1 << sizepower))
12         {
13                 Con_Printf("fractalnoise: size must be power of 2\n");
14                 return;
15         }
17         for (gridpower = 0;(1 << gridpower) < startgrid;gridpower++);
18         if (startgrid != (1 << gridpower))
19         {
20                 Con_Printf("fractalnoise: grid must be power of 2\n");
21                 return;
22         }
24         startgrid = bound(0, startgrid, size);
26         amplitude = 0xFFFF; // this gets halved before use
27         noisebuf = (int *)Mem_Alloc(tempmempool, size*size*sizeof(int));
28         memset(noisebuf, 0, size*size*sizeof(int));
30         for (g2 = startgrid;g2;g2 >>= 1)
31         {
32                 // brownian motion (at every smaller level there is random behavior)
33                 amplitude >>= 1;
34                 for (y = 0;y < size;y += g2)
35                         for (x = 0;x < size;x += g2)
36                                 n(x,y) += (rand()&amplitude);
38                 g = g2 >> 1;
39                 if (g)
40                 {
41                         // subdivide, diamond-square algorithm (really this has little to do with squares)
42                         // diamond
43                         for (y = 0;y < size;y += g2)
44                                 for (x = 0;x < size;x += g2)
45                                         n(x+g,y+g) = (n(x,y) + n(x+g2,y) + n(x,y+g2) + n(x+g2,y+g2)) >> 2;
46                         // square
47                         for (y = 0;y < size;y += g2)
48                                 for (x = 0;x < size;x += g2)
49                                 {
50                                         n(x+g,y) = (n(x,y) + n(x+g2,y) + n(x+g,y-g) + n(x+g,y+g)) >> 2;
51                                         n(x,y+g) = (n(x,y) + n(x,y+g2) + n(x-g,y+g) + n(x+g,y+g)) >> 2;
52                                 }
53                 }
54         }
55         // find range of noise values
56         min = max = 0;
57         for (y = 0;y < size;y++)
58                 for (x = 0;x < size;x++)
59                 {
60                         if (n(x,y) < min) min = n(x,y);
61                         if (n(x,y) > max) max = n(x,y);
62                 }
63         max -= min;
64         max++;
65         // normalize noise and copy to output
66         for (y = 0;y < size;y++)
67                 for (x = 0;x < size;x++)
68                         *noise++ = (unsigned char) (((n(x,y) - min) * 256) / max);
69         Mem_Free(noisebuf);
70 #undef n
71 }
73 // unnormalized, used for explosions mainly, does not allocate/free memory (hence the name quick)
74 void fractalnoisequick(unsigned char *noise, int size, int startgrid)
75 {
76         int x, y, g, g2, amplitude, size1 = size - 1, sizepower, gridpower;
77 #define n(x,y) noise[((y)&size1)*size+((x)&size1)]
79         for (sizepower = 0;(1 << sizepower) < size;sizepower++);
80         if (size != (1 << sizepower))
81         {
82                 Con_Printf("fractalnoise: size must be power of 2\n");
83                 return;
84         }
86         for (gridpower = 0;(1 << gridpower) < startgrid;gridpower++);
87         if (startgrid != (1 << gridpower))
88         {
89                 Con_Printf("fractalnoise: grid must be power of 2\n");
90                 return;
91         }
93         startgrid = bound(0, startgrid, size);
95         amplitude = 255; // this gets halved before use
96         memset(noise, 0, size*size);
98         for (g2 = startgrid;g2;g2 >>= 1)
99         {
100                 // brownian motion (at every smaller level there is random behavior)
101                 amplitude >>= 1;
102                 for (y = 0;y < size;y += g2)
103                         for (x = 0;x < size;x += g2)
104                                 n(x,y) += (rand()&amplitude);
106                 g = g2 >> 1;
107                 if (g)
108                 {
109                         // subdivide, diamond-square algorithm (really this has little to do with squares)
110                         // diamond
111                         for (y = 0;y < size;y += g2)
112                                 for (x = 0;x < size;x += g2)
113                                         n(x+g,y+g) = (unsigned char) (((int) n(x,y) + (int) n(x+g2,y) + (int) n(x,y+g2) + (int) n(x+g2,y+g2)) >> 2);
114                         // square
115                         for (y = 0;y < size;y += g2)
116                                 for (x = 0;x < size;x += g2)
117                                 {
118                                         n(x+g,y) = (unsigned char) (((int) n(x,y) + (int) n(x+g2,y) + (int) n(x+g,y-g) + (int) n(x+g,y+g)) >> 2);
119                                         n(x,y+g) = (unsigned char) (((int) n(x,y) + (int) n(x,y+g2) + (int) n(x-g,y+g) + (int) n(x+g,y+g)) >> 2);
120                                 }
121                 }
122         }
123 #undef n
124 }