ShLibNoiseImpl.hpp

00001 // Sh: A GPU metaprogramming language.
00002 //
00003 // Copyright 2003-2005 Serious Hack Inc.
00004 // 
00005 // This library is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 //
00010 // This library is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with this library; if not, write to the Free Software
00017 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
00018 // MA  02110-1301, USA
00020 #ifndef SHLIBNOISEIMPL_HPP
00021 #define SHLIBNOISEIMPL_HPP
00022 
00023 #include "ShLibNoise.hpp"
00024 #include "ShArray.hpp"
00025 #include "ShImage3D.hpp"
00026 
00027 namespace SH {
00028 
00029 static const int MRG_REPS = 2; // total instructions for hashmrg will be MRG_REPS * N * 2 + 2 
00030 
00031 template<int N, int M, typename T>
00032 ShGeneric<N, T> hash(const ShGeneric<M, T>& p)
00033 {
00034   ShAttrib<N, SH_TEMP, T> result = cast<N>(frac(p * 0.01));
00035   ShGeneric<N, T> a = fillcast<N>(ShConstAttrib4f(M_PI * M_PI * M_PI * M_PI, 
00036                                                   std::exp(4.0), 
00037                                                   std::pow(13.0, M_PI / 2.0), 
00038                                                   std::sqrt(1997.0)));
00039 
00040   for(int i = 0; i < MRG_REPS; ++i) {
00041     for(int j = 0; j < N; ++j) { 
00042       result(j) = frac(dot(result, a));
00043     }
00044   }
00045   return result;
00046 }
00047 
00048 template<int N, int M, typename T>
00049 ShGeneric<N, T> texhash(const ShGeneric<M, T>& p)
00050 {
00051   return hash<N>(p);
00052 }
00053 
00058 template<int M, typename T, int P = 16>
00059 class ShNoise 
00060 {
00061 public:
00066   template<int K>
00067   static ShGeneric<M, T> noise(const ShGeneric<K, T> &p, bool useTexture);
00068 
00073   template<int K>
00074   static ShGeneric<M, T> perlin(const ShGeneric<K, T> &p, bool useTexture);
00075   
00077   template<int K>
00078   static ShGeneric<M, T> cellnoise(const ShGeneric<K, T> &p, bool useTexture);
00079   
00081   template<int K>
00082   static ShGeneric<M, T> linnoise(const ShGeneric<K, T> &p, bool useTexture);
00083 
00084 private:
00085   static ShAttrib<1, SH_CONST, T> constP, invP;
00086   static bool m_init;
00087   static ShArray3D<ShAttrib<M, SH_TEMP, T, SH_COLOR> > noiseTex; 
00088   
00089   static void init();
00090 };
00091 
00092 template<int M, typename T, int P>
00093 ShArray3D<ShAttrib<M, SH_TEMP, T, SH_COLOR> > ShNoise<M, T, P>::noiseTex(P, P, P); // pseudorandom 3D noise texture
00094 
00095 template<int M, typename T, int P>
00096 bool ShNoise<M, T, P>::m_init = false; // whether Perlin is initialized. 
00097 
00098 template<int M, typename T, int P>
00099 ShAttrib<1, SH_CONST, T> ShNoise<M, T, P>::constP(P);
00100 
00101 template<int M, typename T, int P>
00102 ShAttrib<1, SH_CONST, T> ShNoise<M, T, P>::invP(1.0 / P);
00103 
00104 template<int M, typename T, int P>
00105 void ShNoise<M, T, P>::init() {
00106   if(m_init) return;
00107 
00108   int i, j, k, l;
00109 
00110   // generate pseudorand noise noiseImage[x + y * P][z] holds the four
00111   // 1D gradient components for lattice points (x, y, z), (x, y, z + 1), (x, y + 1, z),
00112   // and (x, y + 1, z + 1)
00113 #ifdef WIN32
00114   srand(13);
00115 #else
00116   srand48(13);
00117 #endif
00118   ShImage3D noiseImage(P, P, P, M);
00119   for(k = 0; k < P; ++k) {
00120    for(i = 0; i < P; ++i) for(j = 0; j < P; ++j) for(l = 0; l < M; ++l) {
00121 #ifdef WIN32
00122      noiseImage(i, j, k, l) = ((float)rand())/(RAND_MAX+1.0);
00123 #else
00124      noiseImage(i, j, k, l) = drand48();
00125 #endif
00126     }
00127   }
00128   noiseTex.memory(noiseImage.memory());
00129 }
00130 
00131 template<int M, typename T>
00132 ShGeneric<M, T> _psmootht(const ShGeneric<M, T> &t) 
00133 {
00134   return t * t * t * mad(t, mad(t, 6.0f, fillcast<M>(-15.0f)), fillcast<M>(10.0f)); 
00135 }
00136 
00137 template<int M, typename T, int P>
00138 template<int K>
00139 ShGeneric<M, T> ShNoise<M, T, P>::noise(const ShGeneric<K, T> &p, bool useTexture) 
00140 {
00141   // TODO: implement the real algorithm
00142   return perlin(p, useTexture);
00143 }
00144 
00145 template<int M, typename T, int P>
00146 template<int K>
00147 ShGeneric<M, T> ShNoise<M, T, P>::perlin(const ShGeneric<K, T> &p, bool useTexture) 
00148 {
00149   init();
00150   int i, j;
00151   typedef ShAttrib<K, SH_TEMP, T> TempType;
00152   typedef ShAttrib<M, SH_TEMP, T> ResultType;
00153   typedef ShAttrib<K, SH_CONST, T> ConstTempType;
00154   static const int NUM_SAMPLES = 1 << K;
00155 
00156   TempType rp = frac(p); // offset from integer lattice point
00157   TempType p0, p1; // positive coordinates in [0, P)^3
00158   TempType ip0, ip1; // integer lattice point in [0,P)^3 for hash, [0,1)^3 for tex lookup
00159 
00160   p0 = frac(p * invP) * constP; 
00161   p1 = frac(mad(p, invP, fillcast<K>(invP))) * constP;
00162   ip0 = floor(p0);
00163   ip1 = floor(p1);
00164   if(useTexture) { // convert to tex coordiantes (TODO remove when we have RECT textures)
00165     ip0 = (ip0 + 0.5f) * invP; 
00166     ip1 = (ip1 + 0.5f) * invP; 
00167   } 
00168 
00169   // find gradients at the NUM_SAMPLES adjacent grid points (NUM_SAMPLES = 2^K for dimension K lookup)
00170   ResultType grad[NUM_SAMPLES]; 
00171 
00172   typename TempType::host_type flip[K];
00173   for(i = 0; i < NUM_SAMPLES; ++i) {
00174     for(j = 0; j < K; ++j) {
00175       if(j == 0) flip[j] = i & 1;
00176       else flip[j] = (i >> j) & 1;
00177     }
00178     ConstTempType offsets(flip);
00179     TempType intLatticePoint = lerp(offsets, ip1, ip0);
00180     if(useTexture) {
00181       grad[i] = noiseTex(fillcast<3>(intLatticePoint)); // lookup 3D texture
00182     } else {
00183       grad[i] = hash<M>(intLatticePoint); 
00184     }
00185   }
00186 
00187   TempType t = _psmootht(rp); //ShNoise's improved polynomial interpolant 
00188   for(i = K - 1; i >= 0; --i) {
00189     int offset = 1 << i; 
00190     for(j = 0; j < offset; ++j) {
00191       grad[j] = lerp(t(i), grad[j+offset], grad[j]); 
00192     }
00193   }
00194 
00195   return grad[0];
00196 }
00197 
00198 template<int M, typename T, int P>
00199 template<int K>
00200 ShGeneric<M, T> ShNoise<M, T, P>::cellnoise(const ShGeneric<K, T> &p, bool useTexture)
00201 {
00202   init();
00203   ShAttrib<K, SH_TEMP, T> ip;
00204 
00205   ip = floor(p);
00206 
00207   if( useTexture ) {
00208     ip = frac(ip * invP);
00209     return noiseTex(fillcast<3>(ip));
00210   } 
00211   return hash<M>(ip);
00212 }
00213 
00214 template<int M, typename T, int P>
00215 template<int K>
00216 ShGeneric<M, T> ShNoise<M, T, P>::linnoise(const ShGeneric<K, T> &p, bool useTexture)
00217 {
00218   // TODO: implement the real algorithm
00219   return cellnoise(p, useTexture);
00220 }
00221 
00222 #ifdef WIN32
00223 #define SHNOISE_WITH_AMP(name) \
00224 template<int N, int M, int K, typename T1, typename T2>\
00225   ShGeneric<N, CT1T2> name(const ShGeneric<M, T1> &p, const ShGeneric<K, T2> &amp, bool useTexture=true) {\
00226     ShAttrib<N, SH_TEMP, CT1T2> result; \
00227     int freq = 1;\
00228     result *= ShDataTypeInfo<CT1T2, SH_HOST>::Zero; \
00229     for(int i = 0; i < K; ++i, freq *= 2) {\
00230       result = mad(name<N>(p * freq, useTexture), amp(i), result);\
00231     }\
00232     return result;\
00233   }
00234 #else
00235 #define SHNOISE_WITH_AMP(name) \
00236 template<int N, int M, int K, typename T1, typename T2>\
00237   ShGeneric<N, CT1T2> name(const ShGeneric<M, T1> &p, const ShGeneric<K, T2> &amp, bool useTexture) {\
00238     ShAttrib<N, SH_TEMP, CT1T2> result; \
00239     int freq = 1;\
00240     result *= ShDataTypeInfo<CT1T2, SH_HOST>::Zero; \
00241     for(int i = 0; i < K; ++i, freq *= 2) {\
00242       result = mad(name<N>(p * freq, useTexture), amp(i), result);\
00243     }\
00244     return result;\
00245   }
00246 #endif
00247 
00248 template<int N, int M, typename T>
00249 #ifdef WIN32
00250 ShGeneric<N, T> noise(const ShGeneric<M, T> &p, bool useTexture=true) {
00251 #else
00252 ShGeneric<N, T> noise(const ShGeneric<M, T> &p, bool useTexture) {
00253 #endif
00254   return ShNoise<N, T>::noise(p, useTexture);
00255 }
00256 SHNOISE_WITH_AMP(noise);
00257 
00258 template<int N, int M, typename T>
00259 #ifdef WIN32
00260 ShGeneric<N, T> snoise(const ShGeneric<M, T> &p, bool useTexture=true) {
00261 #else
00262 ShGeneric<N, T> snoise(const ShGeneric<M, T> &p, bool useTexture) {
00263 #endif
00264   return mad( noise<N>(p, useTexture), 2.0f, fillcast<N>(-1.0f));
00265 }
00266 SHNOISE_WITH_AMP(snoise);
00267 
00268 template<int N, int M, typename T>
00269 #ifdef WIN32
00270 ShGeneric<N, T> perlin(const ShGeneric<M, T> &p, bool useTexture=true) {
00271 #else
00272 ShGeneric<N, T> perlin(const ShGeneric<M, T> &p, bool useTexture) {
00273 #endif
00274   return ShNoise<N, T>::perlin(p, useTexture);
00275 }
00276 SHNOISE_WITH_AMP(perlin);
00277 
00278 template<int N, int M, typename T>
00279 #ifdef WIN32
00280 ShGeneric<N, T> sperlin(const ShGeneric<M, T> &p, bool useTexture=true) {
00281 #else
00282 ShGeneric<N, T> sperlin(const ShGeneric<M, T> &p, bool useTexture) {
00283 #endif
00284   return mad( perlin<N>(p, useTexture), 2.0f, fillcast<N>(-1.0f));
00285 }
00286 SHNOISE_WITH_AMP(sperlin);
00287 
00288 template<int N, int M, typename T>
00289 #ifdef WIN32
00290 ShGeneric<N, T> cellnoise(const ShGeneric<M, T> &p, bool useTexture=true) {
00291 #else
00292 ShGeneric<N, T> cellnoise(const ShGeneric<M, T> &p, bool useTexture) {
00293 #endif
00294   return ShNoise<N, T>::cellnoise(p, useTexture);
00295 }
00296 SHNOISE_WITH_AMP(cellnoise);
00297 
00298 template<int N, int M, typename T>
00299 #ifdef WIN32
00300 ShGeneric<N, T> scellnoise(const ShGeneric<M, T> &p, bool useTexture=true) {
00301 #else
00302 ShGeneric<N, T> scellnoise(const ShGeneric<M, T> &p, bool useTexture) {
00303 #endif
00304   return mad( cellnoise<N>(p, useTexture), 2.0f, fillcast<N>(-1.0f));
00305 }
00306 SHNOISE_WITH_AMP(scellnoise);
00307 
00308 template<int N, int M, typename T>
00309 #ifdef WIN32
00310 ShGeneric<N, T> linnoise(const ShGeneric<M, T> &p, bool useTexture=true) {
00311 #else
00312 ShGeneric<N, T> linnoise(const ShGeneric<M, T> &p, bool useTexture) {
00313 #endif
00314   return ShNoise<N, T>::linnoise(p, useTexture);
00315 }
00316 SHNOISE_WITH_AMP(linnoise);
00317 
00318 template<int N, int M, typename T>
00319 #ifdef WIN32
00320 ShGeneric<N, T> slinnoise(const ShGeneric<M, T> &p, bool useTexture=true) {
00321 #else
00322 ShGeneric<N, T> slinnoise(const ShGeneric<M, T> &p, bool useTexture) {
00323 #endif
00324   return mad( linnoise<N>(p, useTexture), 2.0f, fillcast<N>(-1.0f));
00325 }
00326 SHNOISE_WITH_AMP(slinnoise);
00327 
00328 template<int N, int M, typename T>
00329 #ifdef WIN32
00330 ShGeneric<N, T> turbulence(const ShGeneric<M, T> &p, bool useTexture=true) {
00331 #else
00332 ShGeneric<N, T> turbulence(const ShGeneric<M, T> &p, bool useTexture) {
00333 #endif
00334   return abs(sperlin<N>(p, useTexture));
00335 }
00336 SHNOISE_WITH_AMP(turbulence);
00337 
00338 template<int N, int M, typename T>
00339 #ifdef WIN32
00340 ShGeneric<N, T> sturbulence(const ShGeneric<M, T> &p, bool useTexture=true) {
00341 #else
00342 ShGeneric<N, T> sturbulence(const ShGeneric<M, T> &p, bool useTexture) {
00343 #endif
00344   return mad(abs(sperlin<N>(p, useTexture)), 2.0f, fillcast<N>(-1.0f));
00345 }
00346 SHNOISE_WITH_AMP(sturbulence);
00347 
00348 } // namespace SH
00349 
00350 #endif // SHLIBNOISEIMPL_HPP

Generated on Wed Nov 9 15:29:35 2005 for Sh by  doxygen 1.4.5