00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #define __STDC_LIMIT_MACROS
00012 #include <cassert>
00013 #include <math.h>
00014 #include <stdlib.h>
00015 #include <limits.h>
00016 #include <algorithm>
00017 #include <cfloat>
00018 #include "SeExprFunc.h"
00019 #include "SeExprNode.h"
00020 #include "SeVec3d.h"
00021 #include "SeCurve.h"
00022 #include "SeExprBuiltins.h"
00023 #include "SePlatform.h"
00024 #include "SeNoise.h"
00025
00026 namespace SeExpr {
00027
00028
00029 namespace {
00030
00031 inline double fade(double t) { return t*t*t*(t*(t*6-15)+10); }
00032 inline double lerp(double t, double a, double b) { return a+t*(b-a); }
00033 inline double grad(int hash, double x, double y, double z) {
00034 int h = hash & 15;
00035 double u = h<8 ? x : y,
00036 v = h<4 ? y : h==12||h==14 ? x : z;
00037 return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
00038 }
00039 }
00040
00041
00042 static const char* fabs_docstring="float abs(float x)\nabsolute value of x";
00043
00044
00045 static const char* deg_docstring="float deg(float angle)\nradians to degrees";
00046 static const char* rad_docstring="float deg(float angle)\ndegrees to radians";
00047
00048 static const char* cosd_docstring="float cosd(float angle)\ncosine in degrees";
00049 static const char* sind_docstring="float sind(float angle)\nsine in degrees";
00050 static const char* tand_docstring="float tand(float angle)\ntangent in degrees";
00051 static const char* acosd_docstring="float acosd(float angle)\narc cosine in degrees";
00052 static const char* asind_docstring="float asind(float angle)\narc sine in degrees";
00053 static const char* atand_docstring="float atand(float angle)\narc tangent in degrees";
00054 static const char* atan2d_docstring="float atan2d(float y,float x)\narc tangent in degrees of y/x between -180 and 180";
00055
00056 static const char* cos_docstring="float cos(float angle)\ncosine in radians";
00057 static const char* sin_docstring="float sin(float angle)\nsine in radians";
00058 static const char* tan_docstring="float tan(float angle)\ntangent in radians";
00059 static const char* acos_docstring="float acos(float angle)\narc cosine in radians";
00060 static const char* asin_docstring="float asin(float angle)\narc sine in radians";
00061 static const char* atan_docstring="float atan(float angle)\narc tangent in radians";
00062 static const char* atan2_docstring="float atan2(float y,float x)\narc tangent in radians of y/x between -PI and PI";
00063
00064 static const char* cosh_docstring="float cosh(float angle)\nhyperbolic cosine in radians";
00065 static const char* sinh_docstring="float sinh(float angle)\nhyperbolic sine in radians";
00066 static const char* tanh_docstring="float tanh(float angle)\nhyperbolic tangent in radians";
00067 static const char* acosh_docstring="float acosh(float angle)\nhyperbolic arc cosine in radians";
00068 static const char* asinh_docstring="float asinh(float angle)\nhyperbolic arc sine in radians";
00069 static const char* atanh_docstring="float atanh(float angle)\nhyperbolic arc tangent in radians";
00070
00071 static const char* clamp_docstring="float clamp(float x,float lo,float hi)\nconstrain x to range [lo,hi]";
00072 static const char* round_docstring="float round(float x)\nconstrain x to range [lo,hi]";
00073 static const char* max_docstring="float max(float a,float b)\ngreater of a and b";
00074 static const char* min_docstring="float min(float a,float b)\nlesser of a and b";
00075 static const char* trunc_docstring="float trunc(float a)\nnearest integer towards zero";
00076 static const char* floor_docstring="float floor(float a)\nnext lower integer";
00077 static const char* ceil_docstring="float ceil(float a)\nnext higher integer";
00078
00079 static const char* invert_docstring="float invert(float a)\nDefined as 1-x";
00080 static const char* cbrt_docstring="float cbrt(float x)\ncube root";
00081 static const char* sqrt_docstring="float sqrt(float x)\nsquare root";
00082 static const char* exp_docstring="float exp(float x)\nE raised to the x power";
00083 static const char* pow_docstring="float pow(float x)\nx to the y power, also available as ^";
00084 static const char* log_docstring="float log(float x)\nNatural logarithm";
00085 static const char* log10_docstring="float log10(float x)\nBase 10 logarithm";
00086 static const char* fmod_docstring="float fmod(float x,float y)\nremainder of x/y (also available as % operator)";
00087 static const char* turbulence_docstring="float turbulence(vector v,int octaves=6,float lacunarity=2,float gain=.5)\nAbsolute value of each noise term is taken. This gives billowy appearance";
00088 static const char* cturbulence_docstring="color cturbulence(vector v,int octaves=6,float lacunarity=2,float gain=.5)\nAbsolute value of each noise term is taken. This gives billowy appearance";
00089 static const char* vturbulence_docstring="vector vturbulence(vector v,int octaves=6,float lacunarity=2,float gain=.5)\nAbsolute value of each noise term is taken. This gives billowy appearance";
00090
00091
00092
00093
00094 double compress(double x, double lo, double hi)
00095 {
00096 return (hi-lo) * x + lo;
00097 }
00098 static const char* compress_docstring="float compress(float x,float lo,float hi)\nRemaps x in [0,1] to [lo,hi]";
00099
00100
00101 double expand(double x, double lo, double hi)
00102 {
00103 if (lo == hi) return x < lo ? 0 : 1;
00104 return (x-lo) / (hi-lo);
00105 }
00106 static const char* expand_docstring="float expand(float x,float lo,float hi)\nRemaps x in [lo,hi] to [0,1]";
00107
00108
00109 double fit(double x, double a1, double b1, double a2, double b2)
00110 {
00111 return (x*(b2-a2) - a1*b2 + b1*a2) / (b1-a1);
00112 }
00113 static const char* fit_docstring="float fit(float x,float a1,float b1,float a2,float b2)\nLinearly remaps x from the range [a1,b1] to the range [a2,b2]\n\nNote: This extrapolates if x is outside [a1,b1]\nTo clamp the result, use fit(x,a1,b1,a2,b2)->clamp(a2,b2)";
00114
00115
00116
00117 double gamma(double x, double g)
00118 {
00119 return pow(x, 1/g);
00120 }
00121 static const char* gamma_docstring="float gamma(float x, float g)\nGamma correction of x with gamma factor g";
00122
00123
00124 double bias(double x, double b)
00125 {
00126 static double C = 1/log(0.5);
00127 return pow(x, log(b) * C);
00128 }
00129 static const char* bias_docstring="float bias(float x, float g)\nVariation of gamma where values less than 0.5 pull the curve down\nand values greater than 0.5 pull the curve up\npow(x,log(b)/log(0.5))";
00130
00131
00132 double contrast(double x, double c)
00133 {
00134 if (x < 0.5) return 0.5 * bias(1-c, 2*x);
00135 else return 1 - 0.5 * bias(1-c, 2 - 2*x);
00136 }
00137 static const char* contrast_docstring="float contrast(float x,float x)\nAdjust the contrast. For c from 0 to 0.5, the contrast is decreased. For c > 0.5, the contrast is increased.";
00138
00139
00140 double boxstep(double x, double a)
00141 {
00142 return x < a ? 0.0 : 1.0;
00143 }
00144 static const char* boxstep_docstring="float boxstep(float x,float a)\n if x < a then 0 otherwise 1";
00145
00146 double linearstep(double x, double a, double b)
00147 {
00148 if ( a < b ) {
00149 return x < a ? 0 : ( x > b ? 1 : (x - a)/(b - a) );
00150 } else if (a > b) {
00151 return 1 - ( x < b ? 0 : ( x > a ? 1 : (x - b)/(a - b) ) );
00152 }
00153 return boxstep(x, a);
00154 }
00155 static const char* linearstep_docstring="float linearstep(float x,float a,float b)\n if x < a then 0, if x > b then 1, and\nx transitions linearly when < x < b ";
00156
00157
00158 double smoothstep(double x, double a, double b)
00159 {
00160 if ( a < b ) {
00161 if ( x < a ) return 0;
00162 if ( x >= b ) return 1;
00163 x = (x - a)/(b - a);
00164 } else if (a > b) {
00165 if ( x <= b ) return 1;
00166 if ( x > a ) return 0;
00167 x = 1 - (x - b)/(a - b);
00168 }
00169 else return boxstep(x, a);
00170 return x*x * (3 - 2*x);
00171 }
00172 static const char* smoothstep_docstring="float smoothstep(float x,float a,float b)\n if x < a then 0, if x > b then 1, and\nx transitions smoothly (cubic) when < x < b";
00173
00174
00175 double gaussstep(double x, double a, double b)
00176 {
00177 if (a < b) {
00178 if ( x < a ) return 0;
00179 if ( x >= b ) return 1;
00180 x = 1 - (x - a)/(b - a);
00181 } else if (a > b) {
00182 if ( x <= b ) return 1;
00183 if ( x > a ) return 0;
00184 x = (x - b)/(a - b);
00185 }
00186 else return boxstep(x, a);
00187 return pow(2, -8*x*x);
00188 }
00189 static const char* gaussstep_docstring="float gasussstep(float x,float a,float b)\n if x < a then 0, if x > b then 1, and\nx transitions smoothly (exponentially) when < x < b";
00190
00191
00192
00193 double remap(double x, double source, double range, double falloff,
00194 double interp)
00195 {
00196 range = fabs(range);
00197 falloff = fabs(falloff);
00198
00199 if (falloff == 0) return fabs(x-source) < range;
00200
00201 double a, b;
00202 if (x > source) { a = source + range; b = a + falloff; }
00203 else { a = source - range; b = a - falloff; }
00204
00205 switch (int(interp)) {
00206 case 0: return linearstep(x, b, a);
00207 case 1: return smoothstep(x, b, a);
00208 default: return gaussstep(x, b, a);
00209 }
00210 }
00211 static const char* remap_docstring=
00212 "remap(float x, float\n"
00213 "source, float range, float falloff, int interp)\nGeneral remapping function.\n"
00214 "When x is within +/- <i>range</i> of source, the result is one.\n"
00215 "The result falls to zero beyond that range over <i>falloff</i> distance.\n"
00216 "The falloff shape is controlled by <i>interp</i>. Numeric values\n"
00217 "or named constants may be used:\n"
00218 " int <b>linear</b>\n"
00219 "= 0\n"
00220 " int <b>smooth</b> = 1\n"
00221 " int <b>gaussian</b> = 2\n";
00222
00223 double mix(double x, double y, double alpha)
00224 {
00225 return x * (1-alpha) + y * alpha;
00226 }
00227 static const char* mix_docstring="mix(float a,float b,float alpha)\nBlend of a and b according to alpha.";
00228
00229
00230 SeVec3d satAdjust(const SeVec3d& rgb, double s, double i)
00231 {
00232 double x = std::min(std::min(rgb[0],rgb[1]),rgb[2]);
00233 double y = std::max(std::max(rgb[0],rgb[1]),rgb[2]);
00234
00235 if (x==y)
00236 return rgb*i;
00237
00238
00239 double L = 0.5 * (x+y);
00240
00241
00242 double S, y2;
00243 if (L <= .5) {
00244 if (x < 0) S = 1-x;
00245 else S = (y-x)/(y+x);
00246 S *= s;
00247 if (S > 1) y2 = 2*L + S - 1;
00248 else y2 = L + L*S;
00249 } else {
00250 if (y > 1) S = y;
00251 else S = (y-x)/(2-(y+x));
00252 S *= s;
00253 if (S > 1) y2 = S;
00254 else y2 = L + S - L*S;
00255 }
00256 double x2 = 2*L-y2;
00257
00258
00259 double t = i/(y-x);
00260 return ((y2-x2)*t*rgb + SeVec3d((y*x2 - x*y2)*t));
00261 }
00262
00263
00264 SeVec3d hsiAdjust(const SeVec3d& rgb, double h, double s, double i)
00265 {
00266 if (h == 0) {
00267 if (s == 1) return rgb * i;
00268 return satAdjust(rgb, s, i);
00269 }
00270
00271 SeVec3d hsl = rgbtohsl(rgb);
00272 hsl[0] += h * (1.0/360);
00273 hsl[1] *= s;
00274 return hsltorgb(hsl) * i;
00275 }
00276
00277
00278 SeVec3d hsi(int n, const SeVec3d* args)
00279 {
00280 if (n < 4) return 0.0;
00281
00282 double h = args[1][0];
00283 double s = args[2][0];
00284 double i = args[3][0];
00285 if (n >= 5) {
00286
00287 double m = args[4][0];
00288 h *= m;
00289 s = (s - 1) * m + 1;
00290 i = (i - 1) * m + 1;
00291 }
00292 return hsiAdjust(args[0], h, s, i);
00293 }
00294 static const char* hsi_docstring=
00295 "color hsi(color x, float h, float s, float i, float map=1)\n"
00296 "The hsi function shifts the hue by h\n"
00297 "(in degrees) and scales the saturation and intensity by s and i\n"
00298 "respectively. An map may be supplied which will control the shift\n"
00299 "- the full shift will happen when the map is one and no shift will\n"
00300 "happen when the map is zero. The shift will be scaled back for\n"
00301 "values between zero and one.";
00302
00303
00304
00305 SeVec3d midhsi(int n, const SeVec3d* args)
00306 {
00307 if (n < 4) return 0.0;
00308
00309 double h = args[1][0];
00310 double s = args[2][0];
00311 double i = args[3][0];
00312 if (n >= 5) {
00313
00314 double m = args[4][0];
00315
00316 m = m * 2 - 1;
00317
00318 double falloff = 1, interp = 0;
00319 if (n >= 6) falloff = args[5][0];
00320 if (n >= 7) interp = args[6][0];
00321 if (m < 0) m = -remap(-m, 1, 0, falloff, interp);
00322 else m = remap( m, 1, 0, falloff, interp);
00323
00324
00325 h *= m;
00326 float absm = fabs(m);
00327 s = s * absm + 1 - absm;
00328 i = i * absm + 1 - absm;
00329 if (m < 0) {
00330 s = 1/s;
00331 i = 1/i;
00332 }
00333 }
00334 return hsiAdjust(args[0], h, s, i);
00335 }
00336 static const char* midhsi_docstring=
00337 "color midhsi(color x, float h, float s, float i, float map, float falloff=1, int interp=0)\n"
00338 "The midhsi function is just like the hsi function except that\n"
00339 "the control map is centered around the mid point (value of 0.5)\n"
00340 "and can scale the shift in both directions.";
00341
00342 SeVec3d rgbtohsl(const SeVec3d& rgb)
00343 {
00344
00345
00346
00347 double R,G,B,H,S,L,x,y,sum,diff;
00348 R = rgb[0]; G = rgb[1]; B = rgb[2];
00349 x = R<G? (R<B? R:B) : (G<B? G:B);
00350 y = R>G? (R>B? R:B) : (G>B? G:B);
00351
00352
00353 sum = x+y; diff = y-x;
00354 L = sum/2;
00355 if (diff < 1e-6)
00356 return SeVec3d(0,0,L);
00357
00358
00359 if (L <= .5) {
00360 if (x < 0) S = 1-x;
00361 else S = diff/sum;
00362 } else {
00363 if (y > 1) S = y;
00364 else S = diff/(2-sum);
00365 }
00366
00367
00368 if (R == y) H = (G - B) / diff;
00369 else if (G == y) H = (B - R) / diff + 2;
00370 else H = (R - G) / diff + 4;
00371 H *= 1/6.;
00372 if (H < 0 || H > 1)
00373 H -= floor(H);
00374
00375 return SeVec3d(H,S,L);
00376 }
00377 static const char* rgbtohsl_docstring=
00378 "color rgbtohsl(color rgb)\n"
00379 "RGB to HSL color space conversion.\n"
00380 "HSL is Hue, Saturation, Lightness (all in range [0..1] )\n"
00381 "These functions have also been extended to support rgb and hsl values\n"
00382 "outside of the range [0..1] in a reasonable way. For any rgb or\n"
00383 "hsl value (except for negative s values), the conversion is\n"
00384 "well-defined and reversible.";
00385
00386
00387 static inline double hslvalue(double x, double y, double H)
00388 {
00389 if (H < 0 || H > 1)
00390 H -= floor(H);
00391
00392 if (H < 1/6.) return x+(y-x)*H*6;
00393 else if (H < 3/6.) return y;
00394 else if (H < 4/6.) return x+(y-x)*(4/6.-H)*6;
00395 else return x;
00396 }
00397
00398
00399 SeVec3d hsltorgb(const SeVec3d& hsl)
00400 {
00401
00402
00403
00404 double H,S,L,R,G,B,x,y;
00405 H = hsl[0]; S = hsl[1]; L = hsl[2];
00406 if (S <= 0)
00407 return SeVec3d(L,L,L);
00408
00409
00410 if (L < 0.5) {
00411 if (S > 1) y = 2*L + S - 1;
00412 else y = L + L*S;
00413 } else {
00414 if (S > 1) y = S;
00415 else y = L + S - L*S;
00416 }
00417 x = 2*L-y;
00418
00419
00420 R = hslvalue(x,y,H+(1/3.));
00421 G = hslvalue(x,y,H);
00422 B = hslvalue(x,y,H-(1/3.));
00423 return SeVec3d(R,G,B);
00424 }
00425 static const char* hsltorgb_docstring=
00426 "color hsltorgb(color hsl)\n"
00427 "RGB to HSL color space conversion.\n"
00428 "HSL is Hue, Saturation, Lightness (all in range [0..1] )\n"
00429 "These functions have also been extended to support rgb and hsl values\n"
00430 "outside of the range [0..1] in a reasonable way. For any rgb or\n"
00431 "hsl value (except for negative s values), the conversion is\n"
00432 "well-defined and reversible.";
00433
00434
00435 static inline SeVec3d saturate(const SeVec3d& Cin, double amt)
00436 {
00437 const SeVec3d lum(.2126,.7152,.0722);
00438 SeVec3d result = SeVec3d(Cin.dot(lum) * (1-amt)) + Cin * amt;
00439 if (result[0] < 0) result[0] = 0;
00440 if (result[1] < 0) result[1] = 0;
00441 if (result[2] < 0) result[2] = 0;
00442 return result;
00443 }
00444
00445 SeVec3d saturate(int n, const SeVec3d* args)
00446 {
00447 if (n < 2) return 0.0;
00448 return saturate(args[0], args[1][0]);
00449 }
00450 static const char* saturate_docstring=
00451 "color saturate(color val, float amt)\n"
00452 "Scale saturation of color by amt.\n"
00453 "The color is scaled around the rec709 luminance value,\n"
00454 "and negative results are clamped at zero.\n";
00455
00456 double hash(int n, double* args)
00457 {
00458
00459 uint32_t seed = 0;
00460 for (int i = 0; i < n; i++) {
00461
00462 int exp;
00463 double frac = frexp(args[i] * (M_E*M_PI), &exp);
00464 uint32_t s = (uint32_t) (frac * UINT32_MAX) ^ (uint32_t) exp;
00465
00466
00467 static const uint32_t M = 1664525, C = 1013904223;
00468 seed = seed * M + s + C;
00469 }
00470
00471
00472 seed ^= (seed >> 11);
00473 seed ^= (seed << 7) & 0x9d2c5680UL;
00474 seed ^= (seed << 15) & 0xefc60000UL;
00475 seed ^= (seed >> 18);
00476
00477
00478 static unsigned char p[256] = {
00479 148,201,203,34,85,225,163,200,174,137,51,24,19,252,107,173,
00480 110,251,149,69,180,152,141,132,22,20,147,219,37,46,154,114,
00481 59,49,155,161,239,77,47,10,70,227,53,235,30,188,143,73,
00482 88,193,214,194,18,120,176,36,212,84,211,142,167,57,153,71,
00483 159,151,126,115,229,124,172,101,79,183,32,38,68,11,67,109,
00484 221,3,4,61,122,94,72,117,12,240,199,76,118,5,48,197,
00485 128,62,119,89,14,45,226,195,80,50,40,192,60,65,166,106,
00486 90,215,213,232,250,207,104,52,182,29,157,103,242,97,111,17,
00487 8,175,254,108,208,224,191,112,105,187,43,56,185,243,196,156,
00488 246,249,184,7,135,6,158,82,130,234,206,255,160,236,171,230,
00489 42,98,54,74,209,205,33,177,15,138,178,44,116,96,140,253,
00490 233,125,21,133,136,86,245,58,23,1,75,165,92,217,39,0,
00491 218,91,179,55,238,170,134,83,25,189,216,100,129,150,241,210,
00492 123,99,2,164,16,220,121,139,168,64,190,9,31,228,95,247,
00493 244,81,102,145,204,146,26,87,113,198,181,127,237,169,28,93,
00494 27,41,231,248,78,162,13,186,63,66,131,202,35,144,222,223};
00495 union {
00496 uint32_t i;
00497 unsigned char c[4];
00498 } u1, u2;
00499 u1.i = seed;
00500 u2.c[3] = p[u1.c[0]];
00501 u2.c[2] = p[(u1.c[1]+u2.c[3])&0xff];
00502 u2.c[1] = p[(u1.c[2]+u2.c[2])&0xff];
00503 u2.c[0] = p[(u1.c[3]+u2.c[1])&0xff];
00504
00505
00506 return u2.i * (1.0/UINT32_MAX);
00507 }
00508 static const char* hash_docstring=
00509 "float hash(float seed1,[float seed2, ...])\n"
00510 "Like rand, but with no internal seeds. Any number of seeds may be given\n"
00511 "and the result will be a random function based on all the seeds.";
00512
00513
00514 double noise(int n, const SeVec3d* args)
00515 {
00516 if (n < 1) return 0;
00517 if (n == 1) {
00518
00519 double result;
00520 double p[3] = { args[0][0], args[0][1], args[0][2] };
00521 Noise<3,1>(p,&result);
00522 return .5*result+.5;
00523 }
00524
00525 if (n > 4) n = 4;
00526 double p[4];
00527 for (int i = 0; i < n; i++) p[i] = args[i][0];
00528 double result;
00529 switch(n){
00530 case 1: Noise<1,1>(p,&result);break;
00531 case 2: Noise<2,1>(p,&result);break;
00532 case 3: Noise<3,1>(p,&result);break;
00533 case 4: Noise<4,1>(p,&result);break;
00534 default: result=0;break;
00535 }
00536 return .5*result+.5;
00537 }
00538 static const char* noise_docstring=
00539 "float noise ( vector v ) <br>\n"
00540 "float noise ( float x, float y )\n"
00541 "float noise ( float x, float y, float z )\n"
00542 "float noise ( float x, float y, float z, float w )\n"
00543 "Original perlin noise at location (C2 interpolant)";
00544
00545 double snoise(const SeVec3d& p)
00546 {
00547 double result;
00548 double args[3] = { p[0], p[1], p[2] };
00549 Noise<3,1>(args,&result);
00550 return result;
00551 }
00552 static const char* snoise_docstring=
00553 "float snoise ( vector v)\n"
00554 "signed noise w/ range -1 to 1 formed with original perlin noise at location (C2 interpolant)";
00555
00556
00557 SeVec3d vnoise(const SeVec3d& p)
00558 {
00559 SeVec3d result;
00560 double args[3] = { p[0], p[1], p[2] };
00561 Noise<3,3>(args,&result[0]);
00562 return result;
00563 }
00564 static const char* vnoise_docstring=
00565 "vector vnoise ( vector v)\n"
00566 "vector noise formed with original perlin noise at location (C2 interpolant)";
00567
00568
00569 SeVec3d cnoise(const SeVec3d& p)
00570 {
00571 return (.5 * vnoise(p)) + SeVec3d(.5);
00572 }
00573 static const char* cnoise_docstring="color cnoise ( vector v)\n"
00574 "color noise formed with original perlin noise at location (C2 interpolant)";
00575
00576 double snoise4(int , const SeVec3d* args)
00577 {
00578 double result;
00579 double procargs[4] = { args[0][0], args[0][1], args[0][2], args[1][0] };
00580 Noise<4,1>(procargs,&result);
00581 return result;
00582 }
00583 static const char* snoise4_docstring="float snoise4 ( vector v,float t)\n"
00584 "4D signed noise w/ range -1 to 1 formed with original perlin noise at location (C2 interpolant)";
00585
00586
00587 SeVec3d vnoise4(int , const SeVec3d* args)
00588 {
00589 SeVec3d result;
00590 double procargs[4] = { args[0][0], args[0][1], args[0][2], args[1][0] };
00591 Noise<4,3>(procargs,&result[0]);
00592 return result;
00593 }
00594 static const char* vnoise4_docstring="vector vnoise4 ( vector v,float t)\n"
00595 "4D vector noise formed with original perlin noise at location (C2 interpolant)";
00596
00597
00598 SeVec3d cnoise4(int n, const SeVec3d* args)
00599 {
00600 return (.5 * vnoise4(n,args)) + SeVec3d(.5);
00601 }
00602 static const char* cnoise4_docstring="color cnoise4 ( vector v,float t)\n"
00603 "4D color noise formed with original perlin noise at location (C2 interpolant)";
00604
00605 double turbulence(int n, const SeVec3d* args)
00606 {
00607
00608 int octaves = 6;
00609 double lacunarity = 2;
00610 double gain = 0.5;
00611 SeVec3d p = 0.0;
00612
00613 switch (n) {
00614 case 4: gain = args[3][0];
00615 case 3: lacunarity = args[2][0];
00616 case 2: octaves = int(clamp(args[1][0], 1, 8));
00617 case 1: p = args[0];
00618 }
00619
00620 double result = 0;
00621 double P[3] = { p[0], p[1], p[2] };
00622 FBM<3,1,true>(P,&result,octaves,lacunarity,gain);
00623 return .5*result+.5;
00624 }
00625
00626
00627 SeVec3d vturbulence(int n, const SeVec3d* args)
00628 {
00629
00630 int octaves = 6;
00631 double lacunarity = 2;
00632 double gain = 0.5;
00633 SeVec3d p = 0.0;
00634
00635 switch (n) {
00636 case 4: gain = args[3][0];
00637 case 3: lacunarity = args[2][0];
00638 case 2: octaves = int(clamp(args[1][0], 1, 8));
00639 case 1: p = args[0];
00640 }
00641
00642 SeVec3d result;
00643 double P[3] = { p[0], p[1], p[2] };
00644 FBM<3,3,true>(P,&result[0],octaves,lacunarity,gain);
00645 return result;
00646 }
00647
00648
00649 SeVec3d cturbulence(int n, const SeVec3d* args)
00650 {
00651 return (vturbulence(n, args) * .5) + SeVec3d(.5);
00652 }
00653
00654
00655 double fbm(int n, const SeVec3d* args)
00656 {
00657
00658 int octaves = 6;
00659 double lacunarity = 2;
00660 double gain = 0.5;
00661 SeVec3d p = 0.0;
00662
00663 switch (n) {
00664 case 4: gain = args[3][0];
00665 case 3: lacunarity = args[2][0];
00666 case 2: octaves = int(clamp(args[1][0], 1, 8));
00667 case 1: p = args[0];
00668 }
00669
00670 double result = 0.0;
00671 double P[3] = { p[0], p[1], p[2] };
00672 FBM<3,1,false>(P,&result,octaves,lacunarity,gain);
00673 return .5*result+.5;
00674 }
00675 static const char* fbm_docstring=
00676 "float fbm(vector v,int octaves=6,float lacunarity=2,float gain=.5)\n"
00677 "fbm (Fractal Brownian Motion) is a multi-frequency noise function. \n"
00678 "The base frequency is the same as the \"noise\" function. The total \n"
00679 "number of frequencies is controlled by octaves. The lacunarity is the \n"
00680 "spacing between the frequencies - a value of 2 means each octave is \n"
00681 "twice the previous frequency. The gain< controls how much each \n"
00682 "frequency is scaled relative to the previous frequency.";
00683
00684
00685 SeVec3d vfbm(int n, const SeVec3d* args)
00686 {
00687
00688 int octaves = 6;
00689 double lacunarity = 2;
00690 double gain = 0.5;
00691 SeVec3d p = 0.0;
00692
00693 switch (n) {
00694 case 4: gain = args[3][0];
00695 case 3: lacunarity = args[2][0];
00696 case 2: octaves = int(clamp(args[1][0], 1, 8));
00697 case 1: p = args[0];
00698 }
00699
00700 SeVec3d result = 0.0;
00701 double P[3] = { p[0], p[1], p[2] };
00702 FBM<3,3,false>(P,&result[0],octaves,lacunarity,gain);
00703 return result;
00704 }
00705 static const char* vfbm_docstring="vector vfbm(vector vint octaves=6,float lacunarity=2,float gain=.5)";
00706
00707
00708 double fbm4(int n, const SeVec3d* args)
00709 {
00710
00711 int octaves = 6;
00712 double lacunarity = 2;
00713 double gain = 0.5;
00714 SeVec3d p = 0.0;
00715 float time = 0.0;
00716
00717 switch (n) {
00718 case 5: gain = args[4][0];
00719 case 4: lacunarity = args[3][0];
00720 case 3: octaves = int(clamp(args[2][0], 1, 8));
00721 case 2: time = args[1][0];
00722 case 1: p = args[0];
00723 }
00724
00725 double result = 0.0;
00726 double P[4] = { p[0], p[1], p[2],time };
00727 FBM<4,1,false>(P,&result,octaves,lacunarity,gain);
00728 return .5*result+.5;
00729 }
00730 static const char* fbm4_docstring="float fbm4(vector v,float time,int octaves=6,float lacunarity=2,float gain=.5)\n"
00731 "fbm (Fractal Brownian Motion) is a multi-frequency noise function. \n"
00732 "The base frequency is the same as the \"noise\" function. The total \n"
00733 "number of frequencies is controlled by octaves. The lacunarity is the \n"
00734 "spacing between the frequencies - a value of 2 means each octave is \n"
00735 "twice the previous frequency. The gain< controls how much each \n"
00736 "frequency is scaled relative to the previous frequency.";
00737
00738
00739 SeVec3d vfbm4(int n, const SeVec3d* args)
00740 {
00741
00742 int octaves = 6;
00743 double lacunarity = 2;
00744 double gain = 0.5;
00745 SeVec3d p = 0.0;
00746 float time = 0.0;
00747
00748 switch (n) {
00749 case 5: gain = args[4][0];
00750 case 4: lacunarity = args[3][0];
00751 case 3: octaves = int(clamp(args[2][0], 1, 8));
00752 case 2: time = args[1][0];
00753 case 1: p = args[0];
00754 }
00755
00756 SeVec3d result = 0.0;
00757 double P[4] = { p[0], p[1], p[2], time };
00758 FBM<4,3,false>(P,&result[0],octaves,lacunarity,gain);
00759 return result;
00760 }
00761 static const char* vfbm4_docstring="vector vfbm4(vector v,float time,int octaves=6,float lacunarity=2,float gain=.5)";
00762
00763
00764 SeVec3d cfbm(int n, const SeVec3d* args)
00765 {
00766 return (vfbm(n, args) * .5) + SeVec3d(.5);
00767 }
00768 static const char* cfbm_docstring="color cfbm(vector vint octaves=6,float lacunarity=2,float gain=.5)";
00769
00770 SeVec3d cfbm4(int n, const SeVec3d* args)
00771 {
00772 return (vfbm4(n, args) * .5) + SeVec3d(.5);
00773 }
00774 static const char* cfbm4_docstring="color cfbm4(vector v,float time,int octaves=6,float lacunarity=2,float gain=.5)";
00775
00776
00777 double cellnoise(const SeVec3d& p)
00778 {
00779 double result;
00780 double args[3] = { p[0], p[1], p[2] };
00781 CellNoise<3,1>(args,&result);
00782 return result;
00783 }
00784 static const char* cellnoise_docstring=
00785 "float cellnoise(vector v)\n"
00786 "cellnoise generates a field of constant colored cubes based on the integer location.\n"
00787 "This is the same as the prman cellnoise function.";
00788
00789 SeVec3d ccellnoise(const SeVec3d& p)
00790 {
00791 SeVec3d result;
00792 double args[3] = { p[0], p[1], p[2] };
00793 CellNoise<3,3>(args,&result[0]);
00794 return result;
00795 }
00796 static const char* ccellnoise_docstring=
00797 "color cellnoise(vector v)\n"
00798 "cellnoise generates a field of constant colored cubes based on the integer location.\n"
00799 "This is the same as the prman cellnoise function.";
00800
00801
00802 double pnoise(const SeVec3d& p, const SeVec3d& period)
00803 {
00804 double result;
00805 double args[3] = { p[0], p[1], p[2] };
00806 int pargs[3] = { (int)period[0], (int)period[1], (int)period[2] };
00807 PNoise<3,1>(args, pargs, &result);
00808 return result;
00809 }
00810 static const char* pnoise_docstring=
00811 "float pnoise ( vector v, vector period )\n"
00812 "periodic noise";
00813 struct VoronoiPointData : public SeExprFuncNode::Data
00814 {
00815 SeVec3d points[27];
00816 SeVec3d cell;
00817 double jitter;
00818 VoronoiPointData() : jitter(-1) {}
00819 };
00820
00821 static SeVec3d* voronoi_points(VoronoiPointData& data, const SeVec3d& cell, double jitter)
00822 {
00823 if (cell == data.cell && jitter == data.jitter) return data.points;
00824 data.cell = cell;
00825 data.jitter = jitter;
00826
00827 int n = 0;
00828 for (double i = -1; i <= 1; i++) {
00829 for (double j = -1; j <= 1; j++) {
00830 for (double k = -1; k <= 1; k++, n++) {
00831 SeVec3d testcell = cell + SeVec3d(i,j,k);
00832 data.points[n] = testcell + jitter * ccellnoise(testcell - SeVec3d(.5));
00833 }
00834 }
00835 }
00836 return data.points;
00837 }
00838
00839 static void voronoi_f1_3d(VoronoiPointData& data, const SeVec3d& p, double jitter,
00840 double& f1, SeVec3d& pos1)
00841 {
00842
00843 SeVec3d thiscell(floor(p[0])+0.5, floor(p[1])+0.5,
00844 floor(p[2])+0.5);
00845
00846 f1 = 1000;
00847 SeVec3d* pos = voronoi_points(data, thiscell, jitter);
00848 SeVec3d* end = pos + 27;
00849
00850 for (; pos != end; pos++) {
00851 SeVec3d offset = *pos - p;
00852 double dist = offset.dot(offset);
00853 if (dist < f1) {
00854 f1 = dist;
00855 pos1 = *pos;
00856 }
00857 }
00858 f1 = sqrt(f1);
00859 }
00860
00861 static void voronoi_f1f2_3d(VoronoiPointData& data, const SeVec3d& p, double jitter,
00862 double& f1, SeVec3d& pos1,
00863 double& f2, SeVec3d& pos2)
00864 {
00865
00866 SeVec3d thiscell(floor(p[0])+0.5, floor(p[1])+0.5,
00867 floor(p[2])+0.5);
00868 f1 = f2 = 1000;
00869 SeVec3d* pos = voronoi_points(data, thiscell, jitter);
00870 SeVec3d* end = pos + 27;
00871
00872 for (; pos != end; pos++) {
00873 SeVec3d offset = *pos - p;
00874 double dist = offset.dot(offset);
00875 if (dist < f1) {
00876 f2 = f1; pos2 = pos1;
00877 f1 = dist;
00878 pos1 = *pos;
00879 } else if (dist < f2) {
00880 f2 = dist; pos2 = *pos;
00881 }
00882 }
00883 f1 = sqrt(f1); f2 = sqrt(f2);
00884 }
00885
00886 SeVec3d voronoiFn(VoronoiPointData& data, int n, const SeVec3d* args)
00887 {
00888
00889
00890 SeVec3d p;
00891 int type = 1;
00892 double jitter = 0.5;
00893 double fbmScale = 0;
00894 double fbmOctaves = 4;
00895 double fbmLacunarity = 2;
00896 double fbmGain = 0.5;
00897 switch (n) {
00898 case 7: fbmGain = args[6][0];
00899 case 6: fbmLacunarity = args[5][0];
00900 case 5: fbmOctaves = args[4][0];
00901 case 4: fbmScale = args[3][0];
00902 case 3: jitter = clamp(args[2][0], 1e-3, 1);
00903 case 2: type = int(args[1][0]);
00904 case 1: p = args[0];
00905 }
00906
00907 if (fbmScale > 0) {
00908 SeVec3d fbmArgs[4];
00909 fbmArgs[0] = 2*p;
00910 fbmArgs[1] = fbmOctaves;
00911 fbmArgs[2] = fbmLacunarity;
00912 fbmArgs[3] = fbmGain;
00913 p += fbmScale * vfbm(4, fbmArgs);
00914 }
00915
00916 double f1, f2;
00917 SeVec3d pos1, pos2;
00918 if (type >= 3)
00919 voronoi_f1f2_3d(data, p, jitter, f1, pos1, f2, pos2);
00920 else
00921 voronoi_f1_3d(data, p, jitter, f1, pos1);
00922
00923 switch (type) {
00924 case 1: pos1[0] += 10; return cellnoise(pos1);
00925 case 2: return f1;
00926 case 3: return f2;
00927 case 4: return f2-f1;
00928 case 5:
00929 {
00930 float scalefactor =
00931 (pos2-pos1).length() /
00932 ((pos1-p).length() + (pos2-p).length());
00933 return smoothstep(f2-f1, 0, 0.1*scalefactor);
00934 }
00935 }
00936
00937 return 0.0;
00938 }
00939 const static char* voronoi_docstring=
00940 "float voronoi(vector v, int type=1,float jitter=0.5, float fbmScale=0, int fbmOctaves=4,float fbmLacunarity=2, float fbmGain=.5)\n"
00941 "voronoi is a cellular noise pattern. It is a jittered variant of cellnoise.";
00942
00943
00944 SeVec3d cvoronoiFn(VoronoiPointData& data, int n, const SeVec3d* args)
00945 {
00946
00947
00948 SeVec3d p;
00949 int type = 1;
00950 double jitter = 0.5;
00951 double fbmScale = 0;
00952 double fbmOctaves = 4;
00953 double fbmLacunarity = 2;
00954 double fbmGain = 0.5;
00955 switch (n) {
00956 case 7: fbmGain = args[6][0];
00957 case 6: fbmLacunarity = args[5][0];
00958 case 5: fbmOctaves = args[4][0];
00959 case 4: fbmScale = args[3][0];
00960 case 3: jitter = clamp(args[2][0], 1e-3, 1);
00961 case 2: type = int(args[1][0]);
00962 case 1: p = args[0];
00963 }
00964
00965 if (fbmScale > 0) {
00966 SeVec3d fbmArgs[4];
00967 fbmArgs[0] = 2*p;
00968 fbmArgs[1] = fbmOctaves;
00969 fbmArgs[2] = fbmLacunarity;
00970 fbmArgs[3] = fbmGain;
00971 p += fbmScale * vfbm(4, fbmArgs);
00972 }
00973
00974 double f1, f2;
00975 SeVec3d pos1, pos2;
00976 if (type >= 3)
00977 voronoi_f1f2_3d(data, p, jitter, f1, pos1, f2, pos2);
00978 else
00979 voronoi_f1_3d(data, p, jitter, f1, pos1);
00980
00981 SeVec3d color = ccellnoise(pos1);
00982 switch (type) {
00983 case 1: pos1[0] += 10; return color;
00984 case 2: return f1 * color;
00985 case 3: return f2 * color;
00986 case 4: return (f2-f1) * color;
00987 case 5:
00988 {
00989 float scalefactor =
00990 (pos2-pos1).length() /
00991 ((pos1-p).length() + (pos2-p).length());
00992 return smoothstep(f2-f1, 0, 0.1*scalefactor) * color;
00993 }
00994 }
00995
00996 return 0.0;
00997 }
00998 const static char* cvoronoi_docstring=
00999 "color cvoronoi(vector v, int type=1,float jitter=0.5, float fbmScale=0, int fbmOctaves=4,float fbmLacunarity=2, float fbmGain=.5)\n"
01000 "returns color in cellular pattern. It is a jittered variant of cellnoise.";
01001
01002
01003 SeVec3d pvoronoiFn(VoronoiPointData& data, int n, const SeVec3d* args)
01004 {
01005
01006
01007 SeVec3d p;
01008 double jitter = 0.5;
01009 double fbmScale = 0;
01010 double fbmOctaves = 4;
01011 double fbmLacunarity = 2;
01012 double fbmGain = 0.5;
01013 switch (n) {
01014 case 6: fbmGain = args[5][0];
01015 case 5: fbmLacunarity = args[4][0];
01016 case 4: fbmOctaves = args[3][0];
01017 case 3: fbmScale = args[2][0];
01018 case 2: jitter = clamp(args[1][0], 1e-3, 1);
01019 case 1: p = args[0];
01020 }
01021
01022 if (fbmScale > 0) {
01023 SeVec3d fbmArgs[4];
01024 fbmArgs[0] = 2*p;
01025 fbmArgs[1] = fbmOctaves;
01026 fbmArgs[2] = fbmLacunarity;
01027 fbmArgs[3] = fbmGain;
01028 p += fbmScale * vfbm(4, fbmArgs);
01029 }
01030
01031 double f1;
01032 SeVec3d pos1;
01033 voronoi_f1_3d(data, p, jitter, f1, pos1);
01034 return pos1;
01035 }
01036 const static char* pvoronoi_docstring=
01037 "color pvoronoi(vector v, int type=1,float jitter=0.5, float fbmScale=0, int fbmOctaves=4,float fbmLacunarity=2, float fbmGain=.5)\n"
01038 "returns center of voronoi cell.";
01039
01040
01041 class CachedVoronoiFunc : public SeExprFuncX
01042 {
01043 public:
01044 typedef SeVec3d VoronoiFunc(VoronoiPointData& data, int n, const SeVec3d* args);
01045 CachedVoronoiFunc(VoronoiFunc* vfunc) : SeExprFuncX(true),_vfunc(vfunc) {}
01046
01047 virtual bool prep(SeExprFuncNode* node, bool )
01048 {
01049 node->setData(new VoronoiPointData);
01050
01051 return SeExprFuncX::prep(node, true);
01052 }
01053
01054 virtual void eval(const SeExprFuncNode* node, SeVec3d& result) const
01055 {
01056 VoronoiPointData* data = static_cast<VoronoiPointData*>(node->getData());
01057 int nargs = node->numChildren();
01058 SeVec3d* args = (SeVec3d*) alloca(sizeof(SeVec3d) * nargs);
01059 for (int i = 0; i < nargs; i++) node->child(i)->eval(args[i]);
01060 result = _vfunc(*data, nargs, args);
01061 }
01062
01063 private:
01064 VoronoiFunc* _vfunc;
01065 } voronoi(voronoiFn), cvoronoi(cvoronoiFn), pvoronoi(pvoronoiFn);
01066
01067
01068 double dist(double ax, double ay, double az, double bx, double by, double bz)
01069 {
01070 double x = ax-bx;
01071 double y = ay-by;
01072 double z = az-bz;
01073 return sqrt(x*x + y*y + z*z);
01074 }
01075 static const char* dist_docstring=
01076 "float dist(vector a, vector b)\n"
01077 "distance between two points";
01078
01079 double length(const SeVec3d& v)
01080 {
01081 return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
01082 }
01083 static const char* length_docstring=
01084 "float length(vector v)\n"
01085 "length of vector";
01086
01087
01088 double hypot(double x, double y)
01089 {
01090 return sqrt(x*x+y*y);
01091 }
01092 static const char* hypot_docstring=
01093 "float hypot(vector v)\n"
01094 "length of 2d vector [x,y]";
01095
01096 double dot(const SeVec3d& a, const SeVec3d& b)
01097 {
01098 return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
01099 }
01100 static const char* dot_docstring=
01101 "float dot(vector a,vector b)\n"
01102 "vector dot product";
01103
01104
01105 SeVec3d norm(const SeVec3d& a)
01106 {
01107 double len = length(a);
01108 if (len == 0) return 0.0;
01109 else return a / len;
01110 }
01111 static const char* norm_docstring=
01112 "vector norm(vector v)\n"
01113 "vector scaled to unit length";
01114
01115
01116 SeVec3d cross(const SeVec3d& a, const SeVec3d& b)
01117 {
01118 return SeVec3d(a[1]*b[2] - a[2]*b[1],
01119 a[2]*b[0] - a[0]*b[2],
01120 a[0]*b[1] - a[1]*b[0]);
01121 }
01122 static const char* cross_docstring=
01123 "vector cross(vector a,vector b)\n"
01124 "vector cross product";
01125
01126
01127 double angle(const SeVec3d& a, const SeVec3d& b)
01128 {
01129 double len = length(a)*length(b);
01130 if (len == 0) return 0;
01131 return acos(dot(a,b) / len);
01132 }
01133 static const char* angle_docstring=
01134 "float angle(vector a,vector b)\n"
01135 "angle between two vectors (in radians)";
01136
01137
01138
01139 SeVec3d ortho(const SeVec3d& a, const SeVec3d& b)
01140 {
01141 return norm(cross(a,b));
01142 }
01143 static const char* ortho_docstring=
01144 "vector angle(vector a,vector b)\n"
01145 "normalized vector orthogonal to a and b scaled to unit length";
01146
01147
01148 SeVec3d rotate(int n, const SeVec3d* args)
01149 {
01150 if (n != 3) return 0.0;
01151 const SeVec3d& P = args[0];
01152 const SeVec3d& axis = args[1];
01153 float angle = args[2][0];
01154 double len = axis.length();
01155 if (!len) return P;
01156 return P.rotateBy(axis/len, angle);
01157 }
01158 static const char* rotate_docstring=
01159 "vector rotate(vector v,vector axis,float angle)\n"
01160 "rotates v around axis by given angle (in radians)";
01161
01162
01163 SeVec3d up(const SeVec3d& P, const SeVec3d& upvec)
01164 {
01165
01166 SeVec3d yAxis(0,1,0);
01167 return P.rotateBy(ortho(upvec, yAxis), angle(upvec, yAxis));
01168 }
01169 static const char* up_docstring=
01170 "vector up(vector P,vector upvec)\n"
01171 "rotates v such that the Y axis points in the given up direction";
01172
01173 double cycle(double index, double loRange, double hiRange)
01174 {
01175 int lo = int(loRange);
01176 int hi = int(hiRange);
01177 int range = hi - lo + 1;
01178 if (range <= 0) return lo;
01179 int result = int(index) % range;
01180 if (result < 0) result += range;
01181 return lo + result;
01182 }
01183 static const char* cycle_docstring=
01184 "int cycle(int index, int loRange, int hiRange )\n"
01185 "Cycles through values between loRange and hiRange based on supplied index.\n"
01186 "This is an offset \"mod\" function. The result is rotates v such that the\n"
01187 "Y axis points in the given up direction";
01188
01189
01190 double pick(int n, double* params)
01191 {
01192 if (n < 3) return 0;
01193 double index = hash(1, ¶ms[0]);
01194 int loRange = int(params[1]);
01195 int hiRange = int(params[2]);
01196 int range = hiRange-loRange+1;
01197 if (range <= 0) return loRange;
01198 int numWeights = n-3;
01199 if (numWeights > range) numWeights = range;
01200
01201
01202 double* cutoffs = (double*) alloca(sizeof(double)*range);
01203 double* weights = (double*) alloca(sizeof(double)*range);
01204 double total = 0;
01205 for (int i = 0; i < range; i++) {
01206 double weight = i < numWeights ? params[i+3] : 1;
01207 total += weight;
01208 cutoffs[i] = total;
01209 weights[i] = weight;
01210 }
01211
01212 if (total == 0) return loRange;
01213
01214
01215 index *= total;
01216
01217
01218 int lo = 0, hi = range-1;
01219 while (lo < hi) {
01220 int m = (lo+hi)/2;
01221 if (index <= cutoffs[m]) hi = m;
01222 else lo = m+1;
01223 }
01224
01225
01226 if (weights[lo] == 0) {
01227 if (lo > 0 && cutoffs[lo] > 0)
01228 while (--lo > 0 && weights[lo] == 0);
01229 else if (lo < range-1)
01230 while (++lo < range-1 && weights[lo] == 0);
01231 }
01232
01233
01234 return loRange + lo;
01235 }
01236 static const char* pick_docstring=
01237 "int pick(float index, int loRange, int hiRange, [float weights, ...] )\n"
01238 "Picks values randomly between loRange and hiRange based on supplied index (which is\n"
01239 "automatically hashed). The values will be distributed according\n"
01240 "to the supplied weights. Any weights not supplied are assumed to\n"
01241 "be 1.0.";
01242
01243 double choose(int n, double* params)
01244 {
01245 if (n < 3) return 0;
01246 double key = params[0];
01247 int nvals = n - 1;
01248 return params[1+int(clamp(key * nvals, 0, nvals-1))];
01249 }
01250 static const char* choose_docstring=
01251 "float choose(float index,float choice1, float choice2, [...])\n"
01252 "Chooses one of the supplied choices based on the index (assumed to be in range [0..1]).";
01253
01254
01255 double wchoose(int n, double* params)
01256 {
01257 if (n < 5) return 0;
01258 double key = params[0];
01259 int nvals = (n - 1) / 2;
01260
01261
01262 double* cutoffs = (double*) alloca(sizeof(double)*nvals);
01263 double* weights = (double*) alloca(sizeof(double)*nvals);
01264 double total = 0;
01265 for (int i = 0; i < nvals; i++) {
01266 double weight = params[i*2+2];
01267 total += weight;
01268 cutoffs[i] = total;
01269 weights[i] = weight;
01270 }
01271
01272 if (total == 0) return params[1];
01273
01274
01275 key *= total;
01276
01277
01278 int lo = 0, hi = nvals-1;
01279 while (lo < hi) {
01280 int m = (lo+hi)/2;
01281 if (key <= cutoffs[m]) hi = m;
01282 else lo = m+1;
01283 }
01284
01285
01286 if (weights[lo] == 0) {
01287 if (lo > 0 && cutoffs[lo] > 0)
01288 while (--lo > 0 && weights[lo] == 0);
01289 else if (lo < nvals-1)
01290 while (++lo < nvals-1 && weights[lo] == 0);
01291 }
01292
01293
01294 return params[lo*2+1];
01295 }
01296 static const char* wchoose_docstring=
01297 "float wchoose(float index,float choice1, float weight1, float choice2, float weight2, [...] )\n"
01298 "Chooses one of the supplied choices based on the index (assumed to be in range[0..1]).\n"
01299 "The values will be distributed according to the supplied weights.";
01300
01301 double spline(int n, double* params)
01302 {
01303 if (n < 5) return 0;
01304 double u = clamp(params[0], 0, 1);
01305 if (u == 0) return params[2];
01306 if (u == 1) return params[n-2];
01307 int nsegs = n - 4;
01308 double seg;
01309 u = modf(u * nsegs, &seg);
01310 double* p = ¶ms[int(seg) + 1];
01311 double u2 = u*u;
01312 double u3 = u2*u;
01313 return 0.5 * (p[0] * ( -u3 + 2*u2 - u) +
01314 p[1] * ( 3*u3 - 5*u2 + 2) +
01315 p[2] * (-3*u3 + 4*u2 + u) +
01316 p[3] * ( u3 - u2));
01317 }
01318 static const char* spline_docstring=
01319 "float spline(float param,float y1,float y2,float y3,float y4,[...])\n\n"
01320 "Interpolates a set of values to the parameter specified where y1, ..., yn are\n"
01321 "distributed evenly from [0...1]";
01322
01323 template<class T>
01324 struct CurveData:public SeExprFuncNode::Data
01325 {
01326 SeCurve<T> curve;
01327 virtual ~CurveData(){}
01328 };
01329
01330
01331 class CurveFuncX:public SeExprFuncX
01332 {
01333 virtual bool prep(SeExprFuncNode* node, bool )
01334 {
01335
01336 int nargs = node->nargs();
01337 if ((nargs - 1) % 3) {
01338 node->addError("Wrong number of arguments, should be multiple of 3 plus 1");
01339 return false;
01340 }
01341
01342 bool noErrors=true;
01343 noErrors &= node->child(0)->prep(1);
01344
01345 CurveData<double>* data = new CurveData<double>;
01346 for (int i = 1; i < nargs-2; i+=3) {
01347
01348 SeVec3d pos;
01349 if(node->child(i)->prep(0)) node->child(i)->eval(pos);
01350 else noErrors=false;
01351
01352 SeVec3d val;
01353 if(node->child(i+1)->prep(0)) node->child(i+1)->eval(val);
01354 else noErrors=false;
01355
01356 SeVec3d interp;
01357 if(node->child(i+2)->prep(0)) node->child(i+2)->eval(interp);
01358 else noErrors=false;
01359 int interpInt=(int)interp[0];
01360 SeCurve<double>::InterpType interpolant=(SeCurve<double>::InterpType)interpInt;
01361 if(!SeCurve<double>::interpTypeValid(interpolant)){
01362 node->child(i+2)->addError("Invalid interpolation type specified");
01363 noErrors=false;
01364 }
01365
01366 data->curve.addPoint(pos[0], val[0], interpolant);
01367 }
01368
01369 data->curve.preparePoints();
01370
01371 node->setData((SeExprFuncNode::Data*)(data));
01372 return noErrors;
01373 }
01374
01375 virtual void eval(const SeExprFuncNode* node, SeVec3d& result) const
01376 {
01377 SeVec3d param;
01378 node->child(0)->eval(param);
01379 bool processVec = node->child(0)->isVec();
01380
01381 CurveData<double> *data = (CurveData<double> *) node->getData();
01382
01383 if (processVec) {
01384 for(int i=0;i<3;i++) result[i] = data->curve.getChannelValue(param[i], i);
01385 } else {
01386 result[0]=result[1]=result[2]=data->curve.getValue(param[0]);
01387 }
01388 }
01389
01390
01391 public:
01392 CurveFuncX():SeExprFuncX(true){}
01393 virtual ~CurveFuncX() {}
01394
01395
01396 } curve;
01397 static const char *curve_docstring=
01398 "float curve(float param,float pos0,float val0,int interp0,float pos1,float val1,int interp1,[...])\n\n"
01399 "Interpolates a 1D ramp defined by control points at 'param'. Control points are specified \n"
01400 "by triples of parameters pos_i, val_i, and interp_i. Interpolation codes are \n"
01401 "0 - none, 1 - linear, 2 - smooth, 3 - spline, \n"
01402 "4-monotone (non oscillating spline)";
01403
01404 class CCurveFuncX:public SeExprFuncX
01405 {
01406 virtual bool prep(SeExprFuncNode* node, bool )
01407 {
01408
01409 int nargs = node->nargs();
01410 if ((nargs - 1) % 3) {
01411 node->addError("Wrong number of arguments, should be multiple of 3 plus 1");
01412 return false;
01413 }
01414 bool noErrors=true;
01415 noErrors &= node->child(0)->prep(1);
01416
01417 CurveData<SeVec3d>* data = new CurveData<SeVec3d>;
01418 for (int i = 1; i < nargs-2; i+=3) {
01419
01420 SeVec3d pos;
01421 if (node->child(i)->prep(0)) node->child(i)->eval(pos);
01422 else noErrors=false;
01423
01424 SeVec3d val;
01425 if (node->child(i+1)->prep(1)){
01426 node->child(i+1)->eval(val);
01427 if (!node->child(i+1)->isVec()) {
01428 val[1] = val[2] = val[0];
01429 }
01430 }else noErrors=false;
01431
01432 SeVec3d interp;
01433 if (node->child(i+2)->prep(0)) node->child(i+2)->eval(interp);
01434 else noErrors=false;
01435 SeCurve<SeVec3d>::InterpType interpolant=(SeCurve<SeVec3d>::InterpType)(int)interp[0];
01436 if(!SeCurve<SeVec3d>::interpTypeValid(interpolant)){
01437 node->child(i+2)->addError("Invalid interpolation type specified");
01438 noErrors=false;
01439 }
01440
01441 data->curve.addPoint(pos[0], val, interpolant);
01442 }
01443
01444 data->curve.preparePoints();
01445 node->setData((SeExprFuncNode::Data*)(data));
01446 return noErrors;
01447 }
01448
01449 virtual void eval(const SeExprFuncNode* node, SeVec3d& result) const
01450 {
01451 SeVec3d param;
01452 node->child(0)->eval(param);
01453 bool processVec = node->child(0)->isVec();
01454
01455 CurveData<SeVec3d> *data = (CurveData<SeVec3d> *) node->getData();
01456
01457 if(processVec) {
01458 for(int i=0;i<3;i++) result[i] = data->curve.getChannelValue(param[i], i);
01459 } else {
01460 result=data->curve.getValue(param[0]);
01461 }
01462 }
01463
01464 public:
01465 CCurveFuncX():SeExprFuncX(true){}
01466 virtual ~CCurveFuncX() {}
01467 } ccurve;
01468 static const char *ccurve_docstring=
01469 "color curve(float param,float pos0,color val0,int interp0,float pos1,color val1,int interp1,[...])\n\n"
01470 "Interpolates color ramp given by control points at 'param'. Control points are specified \n"
01471 "by triples of parameters pos_i, val_i, and interp_i. Interpolation codes are \n"
01472 "0 - none, 1 - linear, 2 - smooth, 3 - spline, \n"
01473 "4 - monotone (non oscillating spline)";
01474
01475 class PrintFuncX:public SeExprFuncX
01476 {
01477 struct Data : public SeExprFuncNode::Data
01478 {
01479 std::vector<std::pair<int,int> > ranges;
01480 std::string format;
01481 };
01482
01483 virtual bool prep(SeExprFuncNode* node, bool )
01484 {
01485
01486 int nargs = node->nargs();
01487 if(!node->isStrArg(0)){
01488 node->addError("first argument must be format");
01489 return false;
01490 }
01491
01492 bool valid=true;
01493 for(int i=1;i<nargs;i++)
01494 valid&=node->child(i)->prep(1);
01495 if(!valid) return false;
01496
01497
01498 unsigned int bakeStart=0;
01499 int searchStart=0;
01500 int needed=0;
01501 Data* data=new Data;
01502 data->format=node->getStrArg(0);
01503 std::string& format=data->format;
01504 std::vector<std::pair<int,int> >& ranges=data->ranges;
01505
01506 int items=0;
01507 while(1){
01508 std::size_t percentStart=format.find('%',searchStart);
01509 if(percentStart==std::string::npos) break;
01510 if(percentStart+1==format.length()){
01511 node->addError("Unexpected end of format string");
01512 delete data;
01513 return false;
01514 }
01515 else if(format[percentStart+1]=='%'){
01516 searchStart=percentStart+2;
01517 continue;
01518 }else if(format[percentStart+1]=='v' || format[percentStart+1]=='f'){
01519 char c=format[percentStart+1];
01520 int code=(c=='v')?-1:-2;
01521 needed++;
01522 if(bakeStart!=percentStart)
01523 ranges.push_back(std::pair<int,int>(bakeStart,percentStart));
01524 ranges.push_back(std::pair<int,int>(code,code));
01525 items++;
01526 searchStart=percentStart+2;
01527 bakeStart=searchStart;
01528 }else{
01529 node->addError("Invalid format string, only %v is allowed");
01530 delete data;
01531 return false;
01532 }
01533 }
01534 if(bakeStart!=format.length())
01535 ranges.push_back(std::pair<int,int>(bakeStart,format.length()));
01536
01537 if(items!=nargs-1){
01538 node->addError("Wrong number of arguments for format string");
01539 delete data;
01540 return false;
01541 }
01542
01543 node->setData(data);
01544 for(unsigned int i=0;i<data->ranges.size();i++){
01545 const std::pair<int,int>& range=data->ranges[i];
01546 std::cerr<<"range "<<range.first<<","<<range.second<<std::endl;
01547 }
01548 return true;
01549 }
01550
01551 virtual void eval(const SeExprFuncNode* node, SeVec3d& result) const
01552 {
01553 result[0]=result[1]=result[2]=0;
01554
01555 Data* data=(Data*)node->getData();;
01556 int item=1;
01557
01558 for(unsigned int i=0;i<data->ranges.size();i++){
01559 const std::pair<int,int>& range=data->ranges[i];
01560 if(range.first==-2){
01561 SeVec3d param;
01562 node->child(item)->eval(param);
01563 std::cerr<<param[0];
01564 item++;
01565 }else if(range.first==-1){
01566 SeVec3d param;
01567 node->child(item)->eval(param);
01568 std::cerr<<"["<<param[0]<<","<<param[1]<<","<<param[2]<<"]";
01569 item++;
01570 }else{
01571 std::cerr<<data->format.substr(range.first,range.second-range.first);
01572 }
01573 }
01574 std::cerr<<std::endl;
01575 }
01576 public:
01577 PrintFuncX():SeExprFuncX(false){}
01578
01579 } printf;
01580 static const char* printf_docstring=
01581 "printf(string format,[vec0, vec1, ...])\n"
01582 "Prints out a string to STDOUT, Format parameter allowed is %v";
01583
01584 void defineBuiltins(SeExprFunc::Define ,SeExprFunc::Define3 define3)
01585 {
01586
01587
01588 #define FUNCADOC(name, func) define3(name, SeExprFunc(::func),func##_docstring)
01589 #define FUNCDOC(func) define3(#func, SeExprFunc(::func),func##_docstring)
01590 FUNCADOC("abs", fabs);
01591 FUNCDOC(acos);
01592 FUNCDOC(asin);
01593 FUNCDOC(atan);
01594 FUNCDOC(atan2);
01595 FUNCDOC(ceil);
01596 FUNCDOC(cos);
01597 FUNCDOC(cosh);
01598 FUNCDOC(exp);
01599 FUNCDOC(floor);
01600 FUNCDOC(fmod);
01601 FUNCDOC(log);
01602 FUNCDOC(log10);
01603 FUNCDOC(pow);
01604 FUNCDOC(sin);
01605 FUNCDOC(sinh);
01606 FUNCDOC(sqrt);
01607 FUNCDOC(tan);
01608 FUNCDOC(tanh);
01609 #ifndef SEEXPR_WIN32
01610 FUNCDOC(cbrt);
01611 FUNCDOC(asinh);
01612 FUNCDOC(acosh);
01613 FUNCDOC(atanh);
01614 FUNCDOC(trunc);
01615 #endif
01616
01617
01618
01619 #undef FUNCDOC
01620
01621
01622 #define FUNCDOC(func) define3(#func, SeExprFunc(SeExpr::func),func##_docstring)
01623 #define FUNCNDOC(func, min, max) define3(#func, SeExprFunc(SeExpr::func, min, max),func##_docstring)
01624
01625
01626 FUNCDOC(deg);
01627 FUNCDOC(rad);
01628 FUNCDOC(cosd);
01629 FUNCDOC(sind);
01630 FUNCDOC(tand);
01631 FUNCDOC(acosd);
01632 FUNCDOC(asind);
01633 FUNCDOC(atand);
01634 FUNCDOC(atan2d);
01635
01636
01637 FUNCDOC(clamp);
01638 FUNCDOC(round);
01639 FUNCDOC(max);
01640 FUNCDOC(min);
01641
01642
01643 FUNCDOC(invert);
01644 FUNCDOC(compress);
01645 FUNCDOC(expand);
01646 FUNCDOC(fit);
01647 FUNCDOC(gamma);
01648 FUNCDOC(bias);
01649 FUNCDOC(contrast);
01650 FUNCDOC(boxstep);
01651 FUNCDOC(linearstep);
01652 FUNCDOC(smoothstep);
01653 FUNCDOC(gaussstep);
01654 FUNCDOC(remap);
01655 FUNCDOC(mix);
01656 FUNCNDOC(hsi, 4, 5);
01657 FUNCNDOC(midhsi, 5, 7);
01658 FUNCDOC(hsltorgb);
01659 FUNCDOC(rgbtohsl);
01660 FUNCNDOC(saturate, 2, 2);
01661
01662
01663 FUNCNDOC(hash, 1, -1);
01664 FUNCNDOC(noise, 1, 4);
01665 FUNCDOC(snoise);
01666 FUNCDOC(vnoise);
01667 FUNCDOC(cnoise);
01668 FUNCNDOC(snoise4,2,2);
01669 FUNCNDOC(vnoise4,2,2);
01670 FUNCNDOC(cnoise4,2,2);
01671 FUNCNDOC(turbulence, 1, 4);
01672 FUNCNDOC(vturbulence, 1, 4);
01673 FUNCNDOC(cturbulence, 1, 4);
01674 FUNCNDOC(fbm, 1, 4);
01675 FUNCNDOC(vfbm, 1, 4);
01676 FUNCNDOC(cfbm, 1, 4);
01677 FUNCDOC(cellnoise);
01678 FUNCDOC(ccellnoise);
01679 FUNCDOC(pnoise);
01680 FUNCNDOC(voronoi, 1, 7);
01681 FUNCNDOC(cvoronoi, 1, 7);
01682 FUNCNDOC(pvoronoi, 1, 6);
01683 FUNCNDOC(fbm4, 2, 5);
01684 FUNCNDOC(vfbm4, 2, 5);
01685 FUNCNDOC(cfbm4, 2, 5);
01686
01687 FUNCDOC(dist);
01688 FUNCDOC(length);
01689 FUNCDOC(hypot);
01690 FUNCDOC(dot);
01691 FUNCDOC(norm);
01692 FUNCDOC(cross);
01693 FUNCDOC(angle);
01694 FUNCDOC(ortho);
01695 FUNCNDOC(rotate, 3, 3);
01696 FUNCDOC(up);
01697
01698
01699 FUNCDOC(cycle);
01700 FUNCNDOC(pick, 3, -1);
01701 FUNCNDOC(choose, 3, -1);
01702 FUNCNDOC(wchoose, 4, -1);
01703 FUNCNDOC(spline, 5, -1);
01704 FUNCNDOC(curve, 1, -1);
01705 FUNCNDOC(ccurve, 1, -1);
01706 FUNCNDOC(printf,1,-1);
01707
01708 }
01709 }