////////////////////////////////////////////////////////////////////// // This file is part of Wavelet Turbulence. // // Wavelet Turbulence is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Wavelet Turbulence is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Wavelet Turbulence. If not, see . // // Copyright 2008 Theodore Kim and Nils Thuerey // ////////////////////////////////////////////////////////////////////////////////////////// // Wavelet noise functions // // This code is based on the C code provided in the appendices of: // // @article{1073264, // author = {Robert L. Cook and Tony DeRose}, // title = {Wavelet noise}, // journal = {ACM Trans. Graph.}, // volume = {24}, // number = {3}, // year = {2005}, // issn = {0730-0301}, // pages = {803--811}, // doi = {http://doi.acm.org/10.1145/1073204.1073264}, // publisher = {ACM}, // address = {New York, NY, USA}, // } // ////////////////////////////////////////////////////////////////////////////////////////// #ifndef WAVELET_NOISE_H #define WAVELET_NOISE_H #include // Tile file header, update revision upon any change done to the noise generator static const char tilefile_headerstring[] = "Noise Tile File rev. "; static const char tilefile_revision[] = "001"; #define NOISE_TILE_SIZE 128 static const int noiseTileSize = NOISE_TILE_SIZE; // warning - noiseTileSize has to be 128^3! #define modFast128(x) ((x) & 127) #define modFast64(x) ((x) & 63) #define DOWNCOEFFS 0.000334f,-0.001528f, 0.000410f, 0.003545f,-0.000938f,-0.008233f, 0.002172f, 0.019120f, \ -0.005040f,-0.044412f, 0.011655f, 0.103311f,-0.025936f,-0.243780f, 0.033979f, 0.655340f, \ 0.655340f, 0.033979f,-0.243780f,-0.025936f, 0.103311f, 0.011655f,-0.044412f,-0.005040f, \ 0.019120f, 0.002172f,-0.008233f,-0.000938f, 0.003546f, 0.000410f,-0.001528f, 0.000334f ////////////////////////////////////////////////////////////////////////////////////////// // Wavelet downsampling -- periodic boundary conditions ////////////////////////////////////////////////////////////////////////////////////////// static void downsampleX(float *from, float *to, int n){ // if these values are not local incorrect results are generated float downCoeffs[32] = { DOWNCOEFFS }; const float *a = &downCoeffs[16]; for (int i = 0; i < n / 2; i++) { to[i] = 0; for (int k = 2 * i - 16; k <= 2 * i + 16; k++) to[i] += a[k - 2 * i] * from[modFast128(k)]; } } static void downsampleY(float *from, float *to, int n){ // if these values are not local incorrect results are generated float downCoeffs[32] = { DOWNCOEFFS }; const float *a = &downCoeffs[16]; for (int i = 0; i < n / 2; i++) { to[i * n] = 0; for (int k = 2 * i - 16; k <= 2 * i + 16; k++) to[i * n] += a[k - 2 * i] * from[modFast128(k) * n]; } } static void downsampleZ(float *from, float *to, int n){ // if these values are not local incorrect results are generated float downCoeffs[32] = { DOWNCOEFFS }; const float *a = &downCoeffs[16]; for (int i = 0; i < n / 2; i++) { to[i * n * n] = 0; for (int k = 2 * i - 16; k <= 2 * i + 16; k++) to[i * n * n] += a[k - 2 * i] * from[modFast128(k) * n * n]; } } ////////////////////////////////////////////////////////////////////////////////////////// // Wavelet downsampling -- Neumann boundary conditions ////////////////////////////////////////////////////////////////////////////////////////// static void downsampleNeumann(const float *from, float *to, int n, int stride) { // if these values are not local incorrect results are generated float downCoeffs[32] = { DOWNCOEFFS }; const float *const aCoCenter= &downCoeffs[16]; for (int i = 0; i < n / 2; i++) { to[i * stride] = 0; for (int k = 2 * i - 16; k < 2 * i + 16; k++) { // handle boundary float fromval; if (k < 0) { fromval = from[0]; } else if(k > n - 1) { fromval = from[(n - 1) * stride]; } else { fromval = from[k * stride]; } to[i * stride] += aCoCenter[k - 2 * i] * fromval; } } } static void downsampleXNeumann(float* to, const float* from, int sx,int sy, int sz) { for (int iy = 0; iy < sy; iy++) for (int iz = 0; iz < sz; iz++) { const int i = iy * sx + iz*sx*sy; downsampleNeumann(&from[i], &to[i], sx, 1); } } static void downsampleYNeumann(float* to, const float* from, int sx,int sy, int sz) { for (int ix = 0; ix < sx; ix++) for (int iz = 0; iz < sz; iz++) { const int i = ix + iz*sx*sy; downsampleNeumann(&from[i], &to[i], sy, sx); } } static void downsampleZNeumann(float* to, const float* from, int sx,int sy, int sz) { for (int ix = 0; ix < sx; ix++) for (int iy = 0; iy < sy; iy++) { const int i = ix + iy*sx; downsampleNeumann(&from[i], &to[i], sz, sx*sy); } } ////////////////////////////////////////////////////////////////////////////////////////// // Wavelet upsampling - periodic boundary conditions ////////////////////////////////////////////////////////////////////////////////////////// static float _upCoeffs[4] = {0.25f, 0.75f, 0.75f, 0.25f}; static void upsampleX(float *from, float *to, int n) { const float *p = &_upCoeffs[2]; for (int i = 0; i < n; i++) { to[i] = 0; for (int k = i / 2; k <= i / 2 + 1; k++) to[i] += p[i - 2 * k] * from[modFast64(k)]; } } static void upsampleY(float *from, float *to, int n) { const float *p = &_upCoeffs[2]; for (int i = 0; i < n; i++) { to[i * n] = 0; for (int k = i / 2; k <= i / 2 + 1; k++) to[i * n] += p[i - 2 * k] * from[modFast64(k) * n]; } } static void upsampleZ(float *from, float *to, int n) { const float *p = &_upCoeffs[2]; for (int i = 0; i < n; i++) { to[i * n * n] = 0; for (int k = i / 2; k <= i / 2 + 1; k++) to[i * n * n] += p[i - 2 * k] * from[modFast64(k) * n * n]; } } ////////////////////////////////////////////////////////////////////////////////////////// // Wavelet upsampling - Neumann boundary conditions ////////////////////////////////////////////////////////////////////////////////////////// static void upsampleNeumann(const float *from, float *to, int n, int stride) { static const float *const pCoCenter = &_upCoeffs[2]; for (int i = 0; i < n; i++) { to[i * stride] = 0; for (int k = i / 2; k <= i / 2 + 1; k++) { float fromval; if(k>n/2) { fromval = from[(n/2) * stride]; } else { fromval = from[k * stride]; } to[i * stride] += pCoCenter[i - 2 * k] * fromval; } } } static void upsampleXNeumann(float* to, const float* from, int sx, int sy, int sz) { for (int iy = 0; iy < sy; iy++) for (int iz = 0; iz < sz; iz++) { const int i = iy * sx + iz*sx*sy; upsampleNeumann(&from[i], &to[i], sx, 1); } } static void upsampleYNeumann(float* to, const float* from, int sx, int sy, int sz) { for (int ix = 0; ix < sx; ix++) for (int iz = 0; iz < sz; iz++) { const int i = ix + iz*sx*sy; upsampleNeumann(&from[i], &to[i], sy, sx); } } static void upsampleZNeumann(float* to, const float* from, int sx, int sy, int sz) { for (int ix = 0; ix < sx; ix++) for (int iy = 0; iy < sy; iy++) { const int i = ix + iy*sx; upsampleNeumann(&from[i], &to[i], sz, sx*sy); } } ////////////////////////////////////////////////////////////////////////////////////////// // load in an existing noise tile ////////////////////////////////////////////////////////////////////////////////////////// static bool loadTile(float* const noiseTileData, std::string filename) { FILE* file; char headerbuffer[64]; size_t headerlen; size_t bread; int endiantest = 1; char endianness; file = fopen(filename.c_str(), "rb"); if (file == NULL) { printf("loadTile: No noise tile '%s' found.\n", filename.c_str()); return false; } //Check header headerlen = strlen(tilefile_headerstring) + strlen(tilefile_revision) + 2; bread = fread((void*)headerbuffer, 1, headerlen, file); if (*((unsigned char*)&endiantest) == 1) endianness = 'L'; else endianness = 'B'; if ((bread != headerlen) || (strncmp(headerbuffer, tilefile_headerstring, strlen(tilefile_headerstring))) || (strncmp(headerbuffer+ strlen(tilefile_headerstring), tilefile_revision, strlen(tilefile_revision))) || (headerbuffer[headerlen-2] != endianness) || (headerbuffer[headerlen-1] != (char)((char)sizeof(long)+'0'))) { printf("loadTile : Noise tile '%s' was generated on an incompatible platform.\n",filename.c_str()); return false; } // dimensions size_t gridSize = noiseTileSize * noiseTileSize * noiseTileSize; // noiseTileData memory is managed by caller bread = fread((void*)noiseTileData, sizeof(float), gridSize, file); fclose(file); printf("Noise tile file '%s' loaded.\n", filename.c_str()); if (bread != gridSize) { printf("loadTile: Noise tile '%s' is wrong size %d.\n", filename.c_str(), (int)bread); return false; } return true; } ////////////////////////////////////////////////////////////////////////////////////////// // write out an existing noise tile ////////////////////////////////////////////////////////////////////////////////////////// static void saveTile(float* const noiseTileData, std::string filename) { FILE* file; file = fopen(filename.c_str(), "wb"); int endiantest=1; char longsize; if (file == NULL) { printf("saveTile: Noise tile '%s' could not be saved.\n", filename.c_str()); return; } //Write file header fwrite(tilefile_headerstring, strlen(tilefile_headerstring), 1, file); fwrite(tilefile_revision, strlen(tilefile_revision), 1, file); //Endianness if (*((unsigned char*)&endiantest) == 1) fwrite("L", 1, 1, file); //Little endian else fwrite("B",1,1,file); //Big endian //32/64bit longsize = (char)sizeof(long)+'0'; fwrite(&longsize, 1, 1, file); fwrite((void*)noiseTileData, sizeof(float), noiseTileSize * noiseTileSize * noiseTileSize, file); fclose(file); printf("saveTile: Noise tile file '%s' saved.\n", filename.c_str()); } ////////////////////////////////////////////////////////////////////////////////////////// // create a new noise tile if necessary ////////////////////////////////////////////////////////////////////////////////////////// static void generateTile_WAVELET(float* const noiseTileData, std::string filename) { // if a tile already exists, just use that if (loadTile(noiseTileData, filename)) return; const int n = noiseTileSize; const int n3 = n*n*n; std::cout <<"Generating new 3d noise tile size="<