]> icculus.org git repositories - divverent/darkplaces.git/blob - fractalnoise.c
added a 4D noise function for use by shaders
[divverent/darkplaces.git] / fractalnoise.c
1
2 #include "quakedef.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, 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         {
13                 Con_Printf("fractalnoise: size must be power of 2\n");
14                 return;
15         }
16
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         }
23
24         startgrid = bound(0, startgrid, size);
25
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));
29
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);
37
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 }
72
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)]
78
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         }
85
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         }
92
93         startgrid = bound(0, startgrid, size);
94
95         amplitude = 255; // this gets halved before use
96         memset(noise, 0, size*size);
97
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);
105
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 }
125
126 #define NOISE_SIZE 256
127 #define NOISE_MASK 255
128 float noise4f(float x, float y, float z, float w)
129 {
130         int i;
131         int index[4][2];
132         float frac[4][2];
133         float v[4];
134         static float noisetable[NOISE_SIZE];
135         static int r[NOISE_SIZE];
136         // LordHavoc: this is inspired by code I saw in Quake3, however I think my
137         // version is much cleaner and substantially faster as well
138         //
139         // the following changes were made:
140         // 1. for the permutation indexing (r[] array in this code) I substituted
141         //    the ^ operator (which never overflows) for the original addition and
142         //    masking code, this should not have any effect on quality.
143         // 2. removed the outermost randomization array lookup.
144         //    (it really wasn't necessary, it's fine if X indexes the array
145         //     directly without permutation indexing)
146         // 3. reimplemented the blending using frac[] arrays rather than a macro.
147         //    (the original macro read one parameter twice - not good)
148         // 4. cleaned up the code by using 4 nested loops to make it read nicer
149         //    (but then I unrolled it completely for speed, it still looks nicer).
150         if (!noisetable[0])
151         {
152                 // noisetable is a random-ish series of float values in +/- 1 range
153                 for (i = 0;i < NOISE_SIZE;i++)
154                         noisetable[i] = (rand() / (double)RAND_MAX) * 2 - 1;
155                 // r is a remapping table to make each dimension of the index have different indexing behavior
156                 for (i = 0;i < NOISE_SIZE;i++)
157                         r[i] = (int)(rand() * (double)NOISE_MASK / (double)RAND_MAX);
158         }
159         frac[1][0] = x - floor(x);index[0][0] = (int)floor(x);
160         frac[1][1] = y - floor(y);index[1][0] = (int)floor(y);
161         frac[1][2] = z - floor(z);index[2][0] = (int)floor(z);
162         frac[1][3] = w - floor(w);index[3][0] = (int)floor(w);
163         for (i = 0;i < 4;i++)
164                 frac[i][0] = 1 - frac[i][1];
165         for (i = 0;i < 4;i++)
166                 index[i][1] = (index[i][0] < NOISE_SIZE - 1) ? (index[i][0] + 1) : 0;
167 #if 1
168         // short version
169         v[0] = frac[1][0] * (frac[0][0] * noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][0]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][0]] ^ index[0][1]]) + frac[1][1] * (frac[0][0] * noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][1]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][1]] ^ index[0][1]]);
170         v[1] = frac[1][0] * (frac[0][0] * noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][0]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][0]] ^ index[0][1]]) + frac[1][1] * (frac[0][0] * noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][1]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][1]] ^ index[0][1]]);
171         v[2] = frac[1][0] * (frac[0][0] * noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][0]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][0]] ^ index[0][1]]) + frac[1][1] * (frac[0][0] * noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][1]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][1]] ^ index[0][1]]);
172         v[3] = frac[1][0] * (frac[0][0] * noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][0]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][0]] ^ index[0][1]]) + frac[1][1] * (frac[0][0] * noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][1]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][1]] ^ index[0][1]]);
173         return frac[3][0] * (frac[2][0] * v[0] + frac[2][1] * v[1]) + frac[3][1] * (frac[2][0] * v[2] + frac[2][1] * v[3]);
174 #elif 1
175         // longer version
176         v[ 0] = noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][0]] ^ index[0][0]];
177         v[ 1] = noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][0]] ^ index[0][1]];
178         v[ 2] = noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][1]] ^ index[0][0]];
179         v[ 3] = noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][1]] ^ index[0][1]];
180         v[ 4] = noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][0]] ^ index[0][0]];
181         v[ 5] = noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][0]] ^ index[0][1]];
182         v[ 6] = noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][1]] ^ index[0][0]];
183         v[ 7] = noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][1]] ^ index[0][1]];
184         v[ 8] = noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][0]] ^ index[0][0]];
185         v[ 9] = noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][0]] ^ index[0][1]];
186         v[10] = noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][1]] ^ index[0][0]];
187         v[11] = noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][1]] ^ index[0][1]];
188         v[12] = noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][0]] ^ index[0][0]];
189         v[13] = noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][0]] ^ index[0][1]];
190         v[14] = noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][1]] ^ index[0][0]];
191         v[15] = noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][1]] ^ index[0][1]];
192         v[16] = frac[0][0] * v[ 0] + frac[0][1] * v[ 1];
193         v[17] = frac[0][0] * v[ 2] + frac[0][1] * v[ 3];
194         v[18] = frac[0][0] * v[ 4] + frac[0][1] * v[ 5];
195         v[19] = frac[0][0] * v[ 6] + frac[0][1] * v[ 7];
196         v[20] = frac[0][0] * v[ 8] + frac[0][1] * v[ 9];
197         v[21] = frac[0][0] * v[10] + frac[0][1] * v[11];
198         v[22] = frac[0][0] * v[12] + frac[0][1] * v[13];
199         v[23] = frac[0][0] * v[14] + frac[0][1] * v[15];
200         v[24] = frac[1][0] * v[16] + frac[1][1] * v[17];
201         v[25] = frac[1][0] * v[18] + frac[1][1] * v[19];
202         v[26] = frac[1][0] * v[20] + frac[1][1] * v[21];
203         v[27] = frac[1][0] * v[22] + frac[1][1] * v[23];
204         v[28] = frac[2][0] * v[24] + frac[2][1] * v[25];
205         v[29] = frac[2][0] * v[26] + frac[2][1] * v[27];
206         return frac[3][0] * v[28] + frac[3][1] * v[29];
207 #else
208         // the algorithm...
209         for (l = 0;l < 2;l++)
210         {
211                 for (k = 0;k < 2;k++)
212                 {
213                         for (j = 0;j < 2;j++)
214                         {
215                                 for (i = 0;i < 2;i++)
216                                         v[l][k][j][i] = noisetable[r[r[r[index[l][3]] ^ index[k][2]] ^ index[j][1]] ^ index[i][0]];
217                                 v[l][k][j][2] = frac[0][0] * v[l][k][j][0] + frac[0][1] * v[l][k][j][1];
218                         }
219                         v[l][k][2][2] = frac[1][0] * v[l][k][0][2] + frac[1][1] * v[l][k][1][2];
220                 }
221                 v[l][2][2][2] = frac[2][0] * v[l][0][2][2] + frac[2][1] * v[l][1][2][2];
222         }
223         v[2][2][2][2] = frac[3][0] * v[0][2][2][2] + frac[3][1] * v[1][2][2][2];
224 #endif
225 }