-#include <stdlib.h>
+#include "quakedef.h"
-void fractalnoise(unsigned char *noise, int size)
+void fractalnoise(qbyte *noise, int size, int startgrid)
{
- int x, y, g, g2, amplitude, amplitude2, min, max, size1 = size - 1;
+ int x, y, g, g2, amplitude, min, max, size1 = size - 1, sizepower, gridpower;
int *noisebuf;
#define n(x,y) noisebuf[((y)&size1)*size+((x)&size1)]
- noisebuf = calloc(size*size, sizeof(int));
- amplitude = 32767;
- g2 = size;
- n(0,0) = 0;
- for (;(g = g2 >> 1) >= 1;g2 >>= 1)
+ for (sizepower = 0;(1 << sizepower) < size;sizepower++);
+ if (size != (1 << sizepower))
+ Sys_Error("fractalnoise: size must be power of 2\n");
+
+ for (gridpower = 0;(1 << gridpower) < startgrid;gridpower++);
+ if (startgrid != (1 << gridpower))
+ Sys_Error("fractalnoise: grid must be power of 2\n");
+
+ startgrid = bound(0, startgrid, size);
+
+ amplitude = 0xFFFF; // this gets halved before use
+ noisebuf = Mem_Alloc(tempmempool, size*size*sizeof(int));
+ memset(noisebuf, 0, size*size*sizeof(int));
+
+ for (g2 = startgrid;g2;g2 >>= 1)
{
- // subdivide, diamond-square algorythm (really this has little to do with squares)
- // diamond
- for (y = 0;y < size;y += g2)
- for (x = 0;x < size;x += g2)
- n(x+g,y+g) = (n(x,y) + n(x+g2,y) + n(x,y+g2) + n(x+g2,y+g2)) >> 2;
- // square
+ // brownian motion (at every smaller level there is random behavior)
+ amplitude >>= 1;
for (y = 0;y < size;y += g2)
for (x = 0;x < size;x += g2)
- {
- n(x+g,y) = (n(x,y) + n(x+g2,y) + n(x+g,y-g) + n(x+g,y+g)) >> 2;
- n(x,y+g) = (n(x,y) + n(x,y+g2) + n(x-g,y+g) + n(x+g,y+g)) >> 2;
- }
- // brownian motion theory
- amplitude >>= 1;
- amplitude2 = amplitude >> 1;
- for (y = 0;y < size;y += g)
- for (x = 0;x < size;x += g)
- n(x,y) += (rand()&litude) - amplitude2;
+ n(x,y) += (rand()&litude);
+
+ g = g2 >> 1;
+ if (g)
+ {
+ // subdivide, diamond-square algorithm (really this has little to do with squares)
+ // diamond
+ for (y = 0;y < size;y += g2)
+ for (x = 0;x < size;x += g2)
+ n(x+g,y+g) = (n(x,y) + n(x+g2,y) + n(x,y+g2) + n(x+g2,y+g2)) >> 2;
+ // square
+ for (y = 0;y < size;y += g2)
+ for (x = 0;x < size;x += g2)
+ {
+ n(x+g,y) = (n(x,y) + n(x+g2,y) + n(x+g,y-g) + n(x+g,y+g)) >> 2;
+ n(x,y+g) = (n(x,y) + n(x,y+g2) + n(x-g,y+g) + n(x+g,y+g)) >> 2;
+ }
+ }
}
// find range of noise values
min = max = 0;
if (n(x,y) > max) max = n(x,y);
}
max -= min;
+ max++;
// normalize noise and copy to output
for (y = 0;y < size;y++)
for (x = 0;x < size;x++)
- *noise++ = (n(x,y) - min) * 255 / max;
- free(noisebuf);
+ *noise++ = (qbyte) (((n(x,y) - min) * 256) / max);
+ Mem_Free(noisebuf);
+#undef n
+}
+
+// unnormalized, used for explosions mainly, does not allocate/free memory (hence the name quick)
+void fractalnoisequick(qbyte *noise, int size, int startgrid)
+{
+ int x, y, g, g2, amplitude, size1 = size - 1, sizepower, gridpower;
+#define n(x,y) noise[((y)&size1)*size+((x)&size1)]
+
+ for (sizepower = 0;(1 << sizepower) < size;sizepower++);
+ if (size != (1 << sizepower))
+ Sys_Error("fractalnoise: size must be power of 2\n");
+
+ for (gridpower = 0;(1 << gridpower) < startgrid;gridpower++);
+ if (startgrid != (1 << gridpower))
+ Sys_Error("fractalnoise: grid must be power of 2\n");
+
+ startgrid = bound(0, startgrid, size);
+
+ amplitude = 255; // this gets halved before use
+ memset(noise, 0, size*size);
+
+ for (g2 = startgrid;g2;g2 >>= 1)
+ {
+ // brownian motion (at every smaller level there is random behavior)
+ amplitude >>= 1;
+ for (y = 0;y < size;y += g2)
+ for (x = 0;x < size;x += g2)
+ n(x,y) += (rand()&litude);
+
+ g = g2 >> 1;
+ if (g)
+ {
+ // subdivide, diamond-square algorithm (really this has little to do with squares)
+ // diamond
+ for (y = 0;y < size;y += g2)
+ for (x = 0;x < size;x += g2)
+ 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);
+ // square
+ for (y = 0;y < size;y += g2)
+ for (x = 0;x < size;x += g2)
+ {
+ 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);
+ 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);
+ }
+ }
+ }
#undef n
-}
\ No newline at end of file
+}
+