X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=fractalnoise.c;h=c161f12b7c4eaf87387272beea954ee3ff2233e9;hb=94111fd0728fed089c8a74f9471e61f38bafbe0c;hp=e9899a47f84771e4bc3e22c2514ad20d514d0575;hpb=4ee1d4780706dc1ed70ec4f7aa8b7712518a5c4f;p=xonotic%2Fdarkplaces.git diff --git a/fractalnoise.c b/fractalnoise.c index e9899a47..c161f12b 100644 --- a/fractalnoise.c +++ b/fractalnoise.c @@ -3,46 +3,54 @@ void fractalnoise(unsigned char *noise, int size, int startgrid) { - int x, y, g, g2, amplitude, 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)] - if (startgrid > size) - startgrid = size; - noisebuf = qmalloc(size*size*sizeof(int)); - memset(noisebuf, 0, size*size*sizeof(int)); - amplitude = 32767; - // quick 1x1 case which the rest of the code can't handle - if (startgrid < 2) + for (sizepower = 0;(1 << sizepower) < size;sizepower++); + if (size != (1 << sizepower)) { - for (x = 0;x < size*size;x++) - *noise++ = (rand()&255); + Con_Printf("fractalnoise: size must be power of 2\n"); return; } - g2 = startgrid; - // clear the starting grid (the rest does not need to be cleared, it will simply be overwritten) - for (y = 0;y < size;y += g2) - for (x = 0;x < size;x += g2) - n(x,y) = 0; - for (;(g = g2 >> 1) >= 1;g2 >>= 1) + + for (gridpower = 0;(1 << gridpower) < startgrid;gridpower++); + if (startgrid != (1 << gridpower)) { - // 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 + Con_Printf("fractalnoise: grid must be power of 2\n"); + return; + } + + startgrid = bound(0, startgrid, size); + + amplitude = 0xFFFF; // this gets halved before use + noisebuf = (int *)Mem_Alloc(tempmempool, size*size*sizeof(int)); + memset(noisebuf, 0, size*size*sizeof(int)); + + 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+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; - for (y = 0;y < size;y += g) - for (x = 0;x < size;x += g) 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; @@ -53,10 +61,65 @@ void fractalnoise(unsigned char *noise, int size, int startgrid) 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; - qfree(noisebuf); + *noise++ = (unsigned char) (((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(unsigned char *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)) + { + Con_Printf("fractalnoise: size must be power of 2\n"); + return; + } + + for (gridpower = 0;(1 << gridpower) < startgrid;gridpower++); + if (startgrid != (1 << gridpower)) + { + Con_Printf("fractalnoise: grid must be power of 2\n"); + return; + } + + 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) = (unsigned char) (((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) = (unsigned char) (((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) = (unsigned char) (((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 +} +