]> icculus.org git repositories - divverent/darkplaces.git/blob - fractalnoise.c
include <> above ""
[divverent/darkplaces.git] / fractalnoise.c
1
2 #include "quakedef.h"
3
4 void fractalnoise(qbyte *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 = 0xFFFF; // this gets halved before use
21         noisebuf = Mem_Alloc(tempmempool, 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 algorithm (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         max++;
59         // normalize noise and copy to output
60         for (y = 0;y < size;y++)
61                 for (x = 0;x < size;x++)
62                         *noise++ = (qbyte) (((n(x,y) - min) * 256) / max);
63         Mem_Free(noisebuf);
64 #undef n
65 }
66
67 // unnormalized, used for explosions mainly, does not allocate/free memory (hence the name quick)
68 void fractalnoisequick(qbyte *noise, int size, int startgrid)
69 {
70         int x, y, g, g2, amplitude, size1 = size - 1, sizepower, gridpower;
71 #define n(x,y) noise[((y)&size1)*size+((x)&size1)]
72
73         for (sizepower = 0;(1 << sizepower) < size;sizepower++);
74         if (size != (1 << sizepower))
75                 Sys_Error("fractalnoise: size must be power of 2\n");
76
77         for (gridpower = 0;(1 << gridpower) < startgrid;gridpower++);
78         if (startgrid != (1 << gridpower))
79                 Sys_Error("fractalnoise: grid must be power of 2\n");
80
81         startgrid = bound(0, startgrid, size);
82
83         amplitude = 255; // this gets halved before use
84         memset(noise, 0, size*size);
85
86         for (g2 = startgrid;g2;g2 >>= 1)
87         {
88                 // brownian motion (at every smaller level there is random behavior)
89                 amplitude >>= 1;
90                 for (y = 0;y < size;y += g2)
91                         for (x = 0;x < size;x += g2)
92                                 n(x,y) += (rand()&amplitude);
93
94                 g = g2 >> 1;
95                 if (g)
96                 {
97                         // subdivide, diamond-square algorithm (really this has little to do with squares)
98                         // diamond
99                         for (y = 0;y < size;y += g2)
100                                 for (x = 0;x < size;x += g2)
101                                         n(x+g,y+g) = (qbyte) (((int) n(x,y) + (int) n(x+g2,y) + (int) n(x,y+g2) + (int) n(x+g2,y+g2)) >> 2);
102                         // square
103                         for (y = 0;y < size;y += g2)
104                                 for (x = 0;x < size;x += g2)
105                                 {
106                                         n(x+g,y) = (qbyte) (((int) n(x,y) + (int) n(x+g2,y) + (int) n(x+g,y-g) + (int) n(x+g,y+g)) >> 2);
107                                         n(x,y+g) = (qbyte) (((int) n(x,y) + (int) n(x,y+g2) + (int) n(x-g,y+g) + (int) n(x+g,y+g)) >> 2);
108                                 }
109                 }
110         }
111 #undef n
112 }
113