KSeExpr  4.0.4.0
ExprBuiltins.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2011-2019 Disney Enterprises, Inc.
2 // SPDX-License-Identifier: LicenseRef-Apache-2.0
3 // SPDX-FileCopyrightText: 2020 L. E. Segovia <amy@amyspark.me>
4 // SPDX-License-Identifier: GPL-3.0-or-later
5 
6 #include <cassert>
7 #if !defined(_USE_MATH_DEFINES)
8 #define _USE_MATH_DEFINES
9 #endif
10 #include <cmath>
11 #include <cstdlib>
12 #include <limits>
13 #include <algorithm>
14 #include <cfloat>
15 #include <random>
16 
17 #include "ExprFunc.h"
18 #include "ExprNode.h"
19 #include "Vec.h"
20 #include "Curve.h"
21 #include "ExprBuiltins.h"
22 #include "Noise.h"
23 #include "Interpreter.h"
24 
25 namespace KSeExpr {
26 
27 static const char* fabs_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float abs(float x)\nabsolute value of x");
28 
29 // angle conversion functions
30 static const char *deg_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float deg(float angle)\nradians to degrees");
31 static const char *rad_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float rad(float angle)\ndegrees to radians");
32 // trig in degrees
33 static const char* cosd_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float cosd(float angle)\ncosine in degrees");
34 static const char* sind_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float sind(float angle)\nsine in degrees");
35 static const char* tand_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float tand(float angle)\ntangent in degrees");
36 static const char* acosd_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float acosd(float value)\narc cosine in degrees");
37 static const char* asind_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float asind(float value)\narc sine in degrees");
38 static const char* atand_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float atand(float value)\narc tangent in degrees");
39 static const char* atan2d_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float atan2d(float y,float x)\narc tangent in degrees of y/x between -180 and 180");
40 // trig in radians
41 static const char* cos_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float cos(float angle)\ncosine in radians");
42 static const char* sin_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float sin(float angle)\nsine in radians");
43 static const char* tan_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float tan(float angle)\ntangent in radians");
44 static const char* acos_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float acos(float value)\narc cosine in radians");
45 static const char* asin_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float asin(float value)\narc sine in radians");
46 static const char* atan_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float atan(float value)\narc tangent in radians");
47 static const char* atan2_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float atan2(float y,float x)\narc tangent in radians of y/x between -PI and PI");
48 // hyperbolic trig
49 static const char* cosh_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float cosh(float angle)\nhyperbolic cosine in radians");
50 static const char* sinh_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float sinh(float angle)\nhyperbolic sine in radians");
51 static const char* tanh_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float tanh(float angle)\nhyperbolic tangent in radians");
52 static const char* acosh_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float acosh(float value)\nhyperbolic arc cosine in radians");
53 static const char* asinh_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float asinh(float value)\nhyperbolic arc sine in radians");
54 static const char* atanh_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float atanh(float value)\nhyperbolic arc tangent in radians");
55 // clamping/rounding
56 static const char* clamp_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float clamp(float x,float lo,float hi)\nconstrain x to range [lo,hi]");
57 static const char* round_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float round(float x)\nnearest integer to x");
58 static const char* max_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float max(float a,float b)\ngreater of a and b");
59 static const char* min_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float min(float a,float b)\nlesser of a and b");
60 static const char* trunc_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float trunc(float a)\nnearest integer towards zero");
61 static const char* floor_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float floor(float a)\nnext lower integer");
62 static const char* ceil_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float ceil(float a)\nnext higher integer");
63 // misc math
64 static const char* invert_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float invert(float a)\nDefined as 1-x");
65 static const char* cbrt_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float cbrt(float x)\ncube root");
66 static const char* sqrt_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float sqrt(float x)\nsquare root");
67 static const char* exp_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float exp(float x)\nE raised to the x power");
68 static const char* pow_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float pow(float x, float y)\nx to the y power, also available as ^");
69 static const char* log_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float log(float x)\nNatural logarithm");
70 static const char* log10_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float log10(float x)\nBase 10 logarithm");
71 static const char* fmod_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float fmod(float x,float y)\nremainder of x/y (also available as % operator)");
72 static const char* turbulence_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
73  "float turbulence(vector v,int octaves=6,float lacunarity=2,float gain=.5)\nAbsolute value of each noise term is "
74  "taken. This gives billowy appearance");
75 static const char* cturbulence_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
76  "color cturbulence(vector v,int octaves=6,float lacunarity=2,float gain=.5)\nAbsolute value of each noise term is "
77  "taken. This gives billowy appearance");
78 static const char* vturbulence_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
79  "vector vturbulence(vector v,int octaves=6,float lacunarity=2,float gain=.5)\nAbsolute value of each noise term is "
80  "taken. This gives billowy appearance");
81 
82 double compress(double x, double lo, double hi)
83 {
84  return (hi - lo) * x + lo;
85 }
86 static const char *compress_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float compress(float x,float lo,float hi)\nRemaps x in [0,1] to [lo,hi]");
87 
88 double expand(double x, double lo, double hi)
89 {
90  if (lo == hi)
91  return x < lo ? 0 : 1;
92  return (x - lo) / (hi - lo);
93 }
94 static const char* expand_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float expand(float x,float lo,float hi)\nRemaps x in [lo,hi] to [0,1]");
95 
96 double fit(double x, double a1, double b1, double a2, double b2)
97 {
98  return (x * (b2 - a2) - a1 * b2 + b1 * a2) / (b1 - a1);
99 }
100 static const char* fit_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float fit(float x,float a1,float b1,float a2,float b2)\nLinearly remaps x in [a1,b1] to [a2,b2]");
101 
102 double gamma(double x, double g)
103 {
104  return pow(x, 1 / g);
105 }
106 static const char *gamma_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float gamma(float x, float g)\nGamma correction of x with gamma factor g");
107 
108 double bias(double x, double b)
109 {
110  static double C = 1 / log(0.5);
111  return pow(x, log(b) * C);
112 }
113 static const char* bias_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
114  "float bias(float x, float g)\nVariation of gamma where values less than 0.5 pull the curve down\nand values "
115  "greater than 0.5 pull the curve up\npow(x,log(b)/log(0.5))");
116 
117 double contrast(double x, double c)
118 {
119  if (x < 0.5)
120  return 0.5 * bias(1 - c, 2 * x);
121  else
122  return 1 - 0.5 * bias(1 - c, 2 - 2 * x);
123 }
124 static const char* contrast_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
125  "float contrast(float x, float c)\nAdjust the contrast.&nbsp; For c from 0 to 0.5, the contrast is decreased.&nbsp; "
126  "For c &gt; 0.5, the contrast is increased.");
127 
128 double boxstep(double x, double a)
129 {
130  return x < a ? 0.0 : 1.0;
131 }
132 static const char *boxstep_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "float boxstep(float x,float a)\n if x < a then 0 otherwise 1");
133 
134 double linearstep(double x, double a, double b)
135 {
136  if (a < b) {
137  return x < a ? 0 : (x > b ? 1 : (x - a) / (b - a));
138  } else if (a > b) {
139  return 1 - (x < b ? 0 : (x > a ? 1 : (x - b) / (a - b)));
140  }
141  return boxstep(x, a);
142 }
143 static const char* linearstep_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
144  "float linearstep(float x, float a, float b)\n if x &lt; a then 0, if x &gt; b then 1, and\nx transitions linearly "
145  "when a &lt; x &lt; b");
146 
147 double smoothstep(double x, double a, double b)
148 {
149  if (a < b) {
150  if (x < a)
151  return 0;
152  if (x >= b)
153  return 1;
154  x = (x - a) / (b - a);
155  } else if (a > b) {
156  if (x <= b)
157  return 1;
158  if (x > a)
159  return 0;
160  x = 1 - (x - b) / (a - b);
161  } else
162  return boxstep(x, a);
163  return x * x * (3 - 2 * x);
164 }
165 static const char* smoothstep_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
166  "float smoothstep(float x,float a,float b)\n if x &lt; a then 0, if x &gt; b then 1, and\nx transitions smoothly "
167  "(cubic) when a &lt; x &lt; b");
168 
169 double gaussstep(double x, double a, double b)
170 {
171  if (a < b) {
172  if (x < a)
173  return 0;
174  if (x >= b)
175  return 1;
176  x = 1 - (x - a) / (b - a);
177  } else if (a > b) {
178  if (x <= b)
179  return 1;
180  if (x > a)
181  return 0;
182  x = (x - b) / (a - b);
183  } else
184  return boxstep(x, a);
185  return pow(2, -8 * x * x);
186 }
187 static const char* gaussstep_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
188  "float gasussstep(float x,float a,float b)\n if x &lt; a then 0, if x &gt; b then 1, and\nx transitions smoothly "
189  "(exponentially) when a &lt; x &lt; b");
190 
191 double remap(double x, double source, double range, double falloff, double interp)
192 {
193  range = fabs(range);
194  falloff = fabs(falloff);
195 
196  if (falloff == 0)
197  return fabs(x - source) < range;
198 
199  double a = NAN;
200  double b = NAN;
201  if (x > source) {
202  a = source + range;
203  b = a + falloff;
204  } else {
205  a = source - range;
206  b = a - falloff;
207  }
208 
209  switch (int(interp)) {
210  case 0:
211  return linearstep(x, b, a);
212  case 1:
213  return smoothstep(x, b, a);
214  default:
215  return gaussstep(x, b, a);
216  }
217 }
218 static const char* remap_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
219  "remap(float x, float source, float range, float falloff, float interp)\n"
220  "General remapping function.\n"
221  "When x is within +/- <i>range</i> of source, the result is one.\n"
222  "The result falls to zero beyond that range over <i>falloff</i> distance.\n"
223  "The falloff shape is controlled by <i>interp</i>. Numeric values\n"
224  "or named constants may be used:\n"
225  "&nbsp;&nbsp;&nbsp;&nbsp;int <b>linear</b> = 0\n"
226  "&nbsp;&nbsp;&nbsp;&nbsp;int <b>smooth</b> = 1\n"
227  "&nbsp;&nbsp;&nbsp;&nbsp;int <b>gaussian</b> = 2\n");
228 
229 double mix(double x, double y, double alpha)
230 {
231  return x * (1 - alpha) + y * alpha;
232 }
233 static const char *mix_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "mix(float a,float b,float alpha)\nBlend of a and b according to alpha.");
234 
235 Vec3d hsiAdjust(const Vec3d &rgb, double h, double s, double i)
236 {
237  Vec3d hsl = rgbtohsl(rgb);
238  hsl[0] += h * (1.0 / 360);
239  hsl[1] *= s;
240  return hsltorgb(hsl) * i;
241 }
242 
243 Vec3d hsi(int n, const Vec3d *args)
244 {
245  if (n < 4)
246  return 0.0;
247 
248  double h = args[1][0];
249  double s = args[2][0];
250  double i = args[3][0];
251  if (n >= 5) {
252  // apply mask
253  double m = args[4][0];
254  h *= m;
255  s = (s - 1) * m + 1;
256  i = (i - 1) * m + 1;
257  }
258  return hsiAdjust(args[0], h, s, i);
259 }
260 static const char* hsi_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
261  "color hsi(color x, float h, float s, float i, float map=1)\n"
262  "The hsi function shifts the hue by h\n"
263  "(in degrees) and scales the saturation and intensity by s and i\n"
264  "respectively.&nbsp; A map may be supplied which will control the shift\n"
265  "- the full shift will happen when the map is one and no shift will\n"
266  "happen when the map is zero.&nbsp; The shift will be scaled back for\n"
267  "values between zero and one.");
268 
269 Vec3d midhsi(int n, const Vec3d *args)
270 {
271  if (n < 4)
272  return 0.0;
273 
274  double h = args[1][0];
275  double s = args[2][0];
276  double i = args[3][0];
277  if (n >= 5) {
278  // apply mask
279  double m = args[4][0];
280  // remap from [0..1] to [-1..1]
281  m = m * 2 - 1;
282  // add falloff (if specified)
283  double falloff = 1;
284  double interp = 0;
285  if (n >= 6)
286  falloff = args[5][0];
287  if (n >= 7)
288  interp = args[6][0];
289  if (m < 0)
290  m = -remap(-m, 1, 0, falloff, interp);
291  else
292  m = remap(m, 1, 0, falloff, interp);
293 
294  // scale hsi values according to mask (both directions)
295  h *= m;
296  float absm = fabs(static_cast<float>(m));
297  s = s * absm + 1 - absm;
298  i = i * absm + 1 - absm;
299  if (m < 0) {
300  s = 1 / s;
301  i = 1 / i;
302  }
303  }
304  return hsiAdjust(args[0], h, s, i);
305 }
306 static const char* midhsi_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
307  "color midhsi(color x, float h, float s, float i, float map, float falloff=1, int interp=0)\n"
308  "The midhsi function is just like the hsi function except that\n"
309  "the control map is centered around the mid point (value of 0.5)\n"
310  "and can scale the shift in both directions.");
311 
312 Vec3d rgbtohsl(const Vec3d &rgb)
313 {
314  // RGB to HSL color space conversion
315  // This is based on Foley, Van Dam (2nd ed; p. 595)
316  // but extended to allow rgb values outside of 0..1
317  double H = NAN;
318  double S = NAN;
319  double L = NAN;
320  double R = rgb[0];
321  double G = rgb[1];
322  double B = rgb[2];
323  double x = R < G ? (R < B ? R : B) : (G < B ? G : B); // min(R,G,B)
324  double y = R > G ? (R > B ? R : B) : (G > B ? G : B); // max(R,G,B)
325 
326  // compute lightness = avg of min and max rgb vals
327  double sum = x + y;
328  double diff = y - x;
329  L = sum / 2;
330  if (diff < 1e-6) // achromatic
331  return {0, 0, L};
332 
333  // compute saturation
334  if (L <= .5) {
335  if (x < 0)
336  S = 1 - x;
337  else
338  S = diff / sum;
339  } else {
340  if (y > 1)
341  S = y;
342  else
343  S = diff / (2 - sum);
344  }
345 
346  // compute hue
347  if (R == y)
348  H = (G - B) / diff;
349  else if (G == y)
350  H = (B - R) / diff + 2;
351  else
352  H = (R - G) / diff + 4;
353  H *= 1 / 6.;
354  H -= floor(H); // make sure hue is in range 0..1
355 
356  return {H, S, L};
357 }
358 static const char* rgbtohsl_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
359  "color rgbtohsl(color rgb)\n"
360  "RGB to HSL color space conversion.\n"
361  "HSL is Hue, Saturation, Lightness (all in range [0..1] )\n"
362  "These functions have also been extended to support rgb and hsl values\n"
363  "outside of the range [0..1] in a reasonable way.&nbsp; For any rgb or\n"
364  "hsl value (except for negative s values), the conversion is\n"
365  "well-defined and reversible.");
366 
367 static double hslvalue(double x, double y, double H)
368 {
369  H -= floor(H); // make sure hue is in range 0..1
370 
371  if (H < 1 / 6.)
372  return x + (y - x) * H * 6;
373  else if (H < 3 / 6.)
374  return y;
375  else if (H < 4 / 6.)
376  return x + (y - x) * (4 / 6. - H) * 6;
377  else
378  return x;
379 }
380 
381 Vec3d hsltorgb(const Vec3d &hsl)
382 {
383  // HSL to RGB color space conversion
384  // This is based on Foley, Van Dam (2nd ed; p. 596)
385  // but extended to allow rgb values outside of 0..1
386  double y = NAN;
387  double H = hsl[0];
388  double S = hsl[1];
389  double L = hsl[2];
390  if (S <= 0) // achromatic
391  return {L, L, L};
392 
393  // find min/max rgb values
394  if (L < 0.5) {
395  if (S > 1)
396  y = 2 * L + S - 1;
397  else
398  y = L + L * S;
399  } else {
400  if (S > 1)
401  y = S;
402  else
403  y = L + S - L * S;
404  }
405  double x = 2 * L - y;
406 
407  // reconstruct rgb from min,max,hue
408  double R = hslvalue(x, y, H + (1 / 3.));
409  double G = hslvalue(x, y, H);
410  double B = hslvalue(x, y, H - (1 / 3.));
411  return {R, G, B};
412 }
413 static const char* hsltorgb_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
414  "color hsltorgb(color hsl)\n"
415  "HSL to RGB color space conversion.\n"
416  "HSL is Hue, Saturation, Lightness (all in range [0..1] )\n"
417  "These functions have also been extended to support rgb and hsl values\n"
418  "outside of the range [0..1] in a reasonable way.&nbsp; For any rgb or\n"
419  "hsl value (except for negative s values), the conversion is\n"
420  "well-defined and reversible.");
421 
422 static Vec3d saturate(const Vec3d &Cin, double amt)
423 {
424  const Vec3d lum(.2126, .7152, .0722); // rec709 luminance
425  Vec3d result = Vec3d(Cin.dot(lum) * (1 - amt)) + Cin * amt;
426  if (result[0] < 0)
427  result[0] = 0;
428  if (result[1] < 0)
429  result[1] = 0;
430  if (result[2] < 0)
431  result[2] = 0;
432  return result;
433 }
434 
435 Vec3d saturate(int n, const Vec3d *args)
436 {
437  if (n < 2)
438  return 0.0;
439  return saturate(args[0], args[1][0]);
440 }
441 static const char* saturate_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
442  "color saturate(color val, float amt)\n"
443  "Scale saturation of color by amt.\n"
444  "The color is scaled around the rec709 luminance value,\n"
445  "and negative results are clamped at zero.\n");
446 
447 class RandFuncX : public ExprFuncSimple
448 {
449  // The default seed of the Mersenne Twister is as predictable as 0 - amyspark
450 
451  struct Data : public ExprFuncNode::Data { // NOLINT cert-msc32-c
452  std::mt19937 gen;
453  std::uniform_real_distribution<> dis;
454  };
455 
456  ExprType prep(ExprFuncNode *node, bool, ExprVarEnvBuilder &envBuilder) const override
457  {
458  bool valid = true;
459  for (auto i = 0; i < node->numChildren(); i++)
460  valid &= node->checkArg(i, ExprType().FP(1).Varying(), envBuilder);
461  return valid ? ExprType().FP(1).Varying() : ExprType().Error();
462  }
463 
464  ExprFuncNode::Data *evalConstant(const ExprFuncNode *, ArgHandle args) const override
465  {
466  auto *data = new Data();
467  auto a = 0.0;
468  auto b = 1.0;
469 
470  if (args.nargs() >= 1) {
471  a = args.inFp<1>(0)[0];
472  }
473  if (args.nargs() >= 2) {
474  b = args.inFp<1>(1)[0];
475  }
476 
477  if (args.nargs() >= 3) {
478  data->gen = std::mt19937(args.inFp<1>(2)[0]);
479  } else {
480  data->gen = std::mt19937(0); // NOLINT cert-msc32-c
481  }
482 
483  data->dis = std::uniform_real_distribution<>(a, b);
484  return data;
485  }
486 
487  void eval(ArgHandle args) override
488  {
489  auto *data = dynamic_cast<RandFuncX::Data *>(args.data);
490  args.outFp = data->dis(data->gen);
491  }
492 
493 public:
494  RandFuncX() noexcept
495  : ExprFuncSimple(true)
496  {
497  } // Thread Safe
499 static const char *rand_docstring = QT_TRANSLATE_NOOP("builtin",
500  "float rand ( [float min, float max], [float seed] )\n"
501  "Random number between [min, max] (or [0, 1] if unspecified).\n"
502  "If a seed is supplied, it will be used in addition to the internal seeds and may be used to create multiple distinct generators.");
503 
504 double hash(int n, double* args)
505 {
506  // combine args into a single seed
507  uint32_t seed = 0;
508  for (int i = 0; i < n; i++) {
509  // make irrational to generate fraction and combine xor into 32 bits
510  int exp = 0;
511  double frac = frexp(args[i] * double(M_E * M_PI), &exp);
512  uint32_t s = (uint32_t)(frac * UINT32_MAX) ^ (uint32_t)exp;
513 
514  // blend with seed (constants from Numerical Recipes, attrib. from Knuth)
515  static const uint32_t M = 1664525;
516  static const uint32_t C = 1013904223;
517  seed = seed * M + s + C;
518  }
519 
520  // tempering (from Matsumoto)
521  seed ^= (seed >> 11);
522  seed ^= (seed << 7) & 0x9d2c5680UL;
523  seed ^= (seed << 15) & 0xefc60000UL;
524  seed ^= (seed >> 18);
525 
526  // permute
527  static std::array<uint8_t, 256> p{
528  148, 201, 203, 34, 85, 225, 163, 200, 174, 137, 51, 24, 19, 252, 107, 173, 110, 251, 149, 69, 180, 152,
529  141, 132, 22, 20, 147, 219, 37, 46, 154, 114, 59, 49, 155, 161, 239, 77, 47, 10, 70, 227, 53, 235,
530  30, 188, 143, 73, 88, 193, 214, 194, 18, 120, 176, 36, 212, 84, 211, 142, 167, 57, 153, 71, 159, 151,
531  126, 115, 229, 124, 172, 101, 79, 183, 32, 38, 68, 11, 67, 109, 221, 3, 4, 61, 122, 94, 72, 117,
532  12, 240, 199, 76, 118, 5, 48, 197, 128, 62, 119, 89, 14, 45, 226, 195, 80, 50, 40, 192, 60, 65,
533  166, 106, 90, 215, 213, 232, 250, 207, 104, 52, 182, 29, 157, 103, 242, 97, 111, 17, 8, 175, 254, 108,
534  208, 224, 191, 112, 105, 187, 43, 56, 185, 243, 196, 156, 246, 249, 184, 7, 135, 6, 158, 82, 130, 234,
535  206, 255, 160, 236, 171, 230, 42, 98, 54, 74, 209, 205, 33, 177, 15, 138, 178, 44, 116, 96, 140, 253,
536  233, 125, 21, 133, 136, 86, 245, 58, 23, 1, 75, 165, 92, 217, 39, 0, 218, 91, 179, 55, 238, 170,
537  134, 83, 25, 189, 216, 100, 129, 150, 241, 210, 123, 99, 2, 164, 16, 220, 121, 139, 168, 64, 190, 9,
538  31, 228, 95, 247, 244, 81, 102, 145, 204, 146, 26, 87, 113, 198, 181, 127, 237, 169, 28, 93, 27, 41,
539  231, 248, 78, 162, 13, 186, 63, 66, 131, 202, 35, 144, 222, 223};
540  union {
541  uint32_t i;
542  std::array<uint8_t, 4> c;
543  } u1 {}, u2 {};
544  u1.i = seed;
545  u2.c[3] = p[u1.c[0]];
546  u2.c[2] = p[(u1.c[1] + u2.c[3]) & 0xff];
547  u2.c[1] = p[(u1.c[2] + u2.c[2]) & 0xff];
548  u2.c[0] = p[(u1.c[3] + u2.c[1]) & 0xff];
549 
550  // scale to [0.0 .. 1.0]
551  return u2.i * (1.0 / UINT32_MAX);
552 }
553 static const char* hash_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
554  "float hash(float seed1,[float seed2, ...])\n"
555  "Like rand, but with no internal seeds. Any number of seeds may be given\n"
556  "and the result will be a random function based on all the seeds.");
557 
558 double noise(int n, const Vec3d *args)
559 {
560  if (n < 1)
561  return 0;
562  if (n == 1) {
563  // 1 arg = vector arg
564  double result = NAN;
565  std::array<double, 3> p {args[0][0], args[0][1], args[0][2]};
566  Noise<3, 1>(p.data(), &result);
567  return .5 * result + .5;
568  }
569  // scalar args
570  if (n > 4)
571  n = 4;
572  std::array<double, 4> p {};
573  for (int i = 0; i < n; i++)
574  p[i] = args[i][0];
575  double result = NAN;
576  switch (n) {
577  case 1:
578  Noise<1, 1>(p.data(), &result);
579  break;
580  case 2:
581  Noise<2, 1>(p.data(), &result);
582  break;
583  case 3:
584  Noise<3, 1>(p.data(), &result);
585  break;
586  case 4:
587  Noise<4, 1>(p.data(), &result);
588  break;
589  default:
590 
591  result = 0;
592  break;
593  }
594  return .5 * result + .5;
595 }
596 static const char* noise_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
597  "float noise ( vector v )\n"
598  "float noise ( float x, float y )\n"
599  "float noise ( float x, float y, float z )\n"
600  "float noise ( float x, float y, float z, float w )\n"
601  "Original perlin noise at location (C2 interpolant)");
602 
603 double snoise(const Vec3d &p)
604 {
605  double result = NAN;
606  std::array<double, 3> args {p[0], p[1], p[2]};
607  Noise<3, 1>(args.data(), &result);
608  return result;
609 }
610 static const char* snoise_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
611  "float snoise ( vector v)\n"
612  "signed noise w/ range -1 to 1 formed with original perlin noise at location (C2 interpolant)");
613 
615 {
616  Vec3d result;
617  std::array<double, 3> args {p[0], p[1], p[2]};
618  Noise<3, 3>(args.data(), &result[0]);
619  return result;
620 }
621 static const char* vnoise_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
622  "vector vnoise ( vector v)\n"
623  "vector noise formed with original perlin noise at location (C2 interpolant)");
624 
626 {
627  return .5 * vnoise(p) + Vec3d(.5);
628 }
629 static const char* cnoise_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
630  "color cnoise ( vector v)\n"
631  "color noise formed with original perlin noise at location (C2 interpolant)");
632 
633 double snoise4(int, const Vec3d *args)
634 {
635  double result = NAN;
636  std::array<double, 4> procargs {args[0][0], args[0][1], args[0][2], args[1][0]};
637  Noise<4, 1>(procargs.data(), &result);
638  return result;
639 }
640 static const char* snoise4_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
641  "float snoise4 ( vector v,float t)\n"
642  "4D signed noise w/ range -1 to 1 formed with original perlin noise at location (C2 interpolant)");
643 
644 Vec3d vnoise4(int, const Vec3d *args)
645 {
646  Vec3d result;
647  std::array<double, 4> procargs {args[0][0], args[0][1], args[0][2], args[1][0]};
648  Noise<4, 3>(procargs.data(), &result[0]);
649  return result;
650 }
651 static const char* vnoise4_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
652  "vector vnoise4 ( vector v,float t)\n"
653  "4D vector noise formed with original perlin noise at location (C2 interpolant)");
654 
655 Vec3d cnoise4(int n, const Vec3d *args)
656 {
657  return .5 * vnoise4(n, args) + Vec3d(.5);
658 }
659 static const char* cnoise4_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
660  "color cnoise4 ( vector v,float t)\n"
661  "4D color noise formed with original perlin noise at location (C2 interpolant)");
662 
663 double turbulence(int n, const Vec3d *args)
664 {
665  // args: octaves, lacunarity, gain
666  int octaves = 6;
667  double lacunarity = 2;
668  double gain = 0.5;
669  Vec3d p = 0.0;
670 
671  switch (n) {
672  case 4:
673  gain = args[3][0];
674  /* fall through */
675  case 3:
676  lacunarity = args[2][0];
677  /* fall through */
678  case 2:
679  octaves = int(clamp(args[1][0], 1, 8));
680  /* fall through */
681  case 1:
682  p = args[0];
683  }
684 
685  double result = 0;
686  std::array<double, 3> P {p[0], p[1], p[2]};
687  FBM<3, 1, true>(P.data(), &result, octaves, lacunarity, gain);
688  return .5 * result + .5;
689 }
690 
691 Vec3d vturbulence(int n, const Vec3d *args)
692 {
693  // args: octaves, lacunarity, gain
694  int octaves = 6;
695  double lacunarity = 2;
696  double gain = 0.5;
697  Vec3d p = 0.0;
698 
699  switch (n) {
700  case 4:
701  gain = args[3][0];
702  /* fall through */
703  case 3:
704  lacunarity = args[2][0];
705  /* fall through */
706  case 2:
707  octaves = int(clamp(args[1][0], 1, 8));
708  /* fall through */
709  case 1:
710  p = args[0];
711  }
712 
713  Vec3d result;
714  std::array<double, 3> P {p[0], p[1], p[2]};
715  FBM<3, 3, true>(P.data(), &result[0], octaves, lacunarity, gain);
716  return result;
717 }
718 
719 Vec3d cturbulence(int n, const Vec3d *args)
720 {
721  return vturbulence(n, args) * .5 + Vec3d(.5);
722 }
723 
724 double fbm(int n, const Vec3d *args)
725 {
726  // args: octaves, lacunarity, gain
727  int octaves = 6;
728  double lacunarity = 2;
729  double gain = 0.5;
730  Vec3d p = 0.0;
731 
732  switch (n) {
733  case 4:
734  gain = args[3][0];
735  /* fall through */
736  case 3:
737  lacunarity = args[2][0];
738  /* fall through */
739  case 2:
740  octaves = int(clamp(args[1][0], 1, 8));
741  /* fall through */
742  case 1:
743  p = args[0];
744  }
745 
746  double result = 0.0;
747  std::array<double, 3> P {p[0], p[1], p[2]};
748  FBM<3, 1, false>(P.data(), &result, octaves, lacunarity, gain);
749  return .5 * result + .5;
750 }
751 static const char* fbm_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
752  "float fbm(vector v,int octaves=6,float lacunarity=2,float gain=.5)\n"
753  "fbm (Fractal Brownian Motion) is a multi-frequency noise function. \n"
754  "The base frequency is the same as the \"noise\" function. The total "
755  "number of frequencies is controlled by octaves. The lacunarity is the "
756  "spacing between the frequencies - a value of 2 means each octave is "
757  "twice the previous frequency. The gain controls how much each "
758  "frequency is scaled relative to the previous frequency.");
759 
760 Vec3d vfbm(int n, const Vec3d *args)
761 {
762  // args: octaves, lacunarity, gain
763  int octaves = 6;
764  double lacunarity = 2;
765  double gain = 0.5;
766  Vec3d p = 0.0;
767 
768  switch (n) {
769  case 4:
770  gain = args[3][0];
771  /* fall through */
772  case 3:
773  lacunarity = args[2][0];
774  /* fall through */
775  case 2:
776  octaves = int(clamp(args[1][0], 1, 8));
777  /* fall through */
778  case 1:
779  p = args[0];
780  }
781 
782  Vec3d result = 0.0;
783  std::array<double, 3> P {p[0], p[1], p[2]};
784  FBM<3, 3, false>(P.data(), &result[0], octaves, lacunarity, gain);
785  return result;
786 }
787 static const char* vfbm_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "vector vfbm(vector vint octaves=6,float lacunarity=2,float gain=.5)");
788 
789 double fbm4(int n, const Vec3d *args)
790 {
791  // args: octaves, lacunarity, gain
792  int octaves = 6;
793  double lacunarity = 2;
794  double gain = 0.5;
795  Vec3d p = 0.0;
796  float time = 0.0;
797 
798  switch (n) {
799  case 5:
800  gain = args[4][0];
801  /* fall through */
802  case 4:
803  lacunarity = args[3][0];
804  /* fall through */
805  case 3:
806  octaves = int(clamp(args[2][0], 1, 8));
807  /* fall through */
808  case 2:
809  time = static_cast<float>(args[1][0]);
810  /* fall through */
811  case 1:
812  p = args[0];
813  }
814 
815  double result = 0.0;
816  std::array<double, 4> P {p[0], p[1], p[2], time};
817  FBM<4, 1, false>(P.data(), &result, octaves, lacunarity, gain);
818  return .5 * result + .5;
819 }
820 static const char* fbm4_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
821  "float fbm4(vector v,float time,int octaves=6,float lacunarity=2,float gain=.5)\n"
822  "fbm (Fractal Brownian Motion) is a multi-frequency noise function. \n"
823  "The base frequency is the same as the \"noise\" function. The total \n"
824  "number of frequencies is controlled by octaves. The lacunarity is the \n"
825  "spacing between the frequencies - a value of 2 means each octave is \n"
826  "twice the previous frequency. The gain controls how much each \n"
827  "frequency is scaled relative to the previous frequency.");
828 
829 Vec3d vfbm4(int n, const Vec3d *args)
830 {
831  // args: octaves, lacunarity, gain
832  int octaves = 6;
833  double lacunarity = 2;
834  double gain = 0.5;
835  Vec3d p = 0.0;
836  float time = 0.0;
837 
838  switch (n) {
839  case 5:
840  gain = args[4][0];
841  /* fall through */
842  case 4:
843  lacunarity = args[3][0];
844  /* fall through */
845  case 3:
846  octaves = int(clamp(args[2][0], 1, 8));
847  /* fall through */
848  case 2:
849  time = static_cast<float>(args[1][0]);
850  /* fall through */
851  case 1:
852  p = args[0];
853  }
854 
855  Vec3d result = 0.0;
856  std::array<double, 4> P {p[0], p[1], p[2], time};
857  FBM<4, 3, false>(P.data(), &result[0], octaves, lacunarity, gain);
858  return result;
859 }
860 static const char* vfbm4_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "vector vfbm4(vector v,float time,int octaves=6,float lacunarity=2,float gain=.5)");
861 
862 Vec3d cfbm(int n, const Vec3d *args)
863 {
864  return vfbm(n, args) * .5 + Vec3d(.5);
865 }
866 static const char *cfbm_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "color cfbm(vector vint octaves=6,float lacunarity=2,float gain=.5)");
867 
868 Vec3d cfbm4(int n, const Vec3d *args)
869 {
870  return vfbm4(n, args) * .5 + Vec3d(.5);
871 }
872 static const char *cfbm4_docstring = QT_TRANSLATE_NOOP_UTF8("builtin", "color cfbm4(vector v,float time,int octaves=6,float lacunarity=2,float gain=.5)");
873 
874 double cellnoise(const Vec3d &p)
875 {
876  double result = NAN;
877  std::array<double, 3> args {p[0], p[1], p[2]};
878  CellNoise<3, 1>(args.data(), &result);
879  return result;
880 }
881 static const char* cellnoise_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
882  "float cellnoise(vector v)\n"
883  "cellnoise generates a field of constant colored cubes based on the integer location.\n"
884  "This is the same as the prman cellnoise function.");
885 
887 {
888  Vec3d result;
889  std::array<double, 3> args {p[0], p[1], p[2]};
890  CellNoise<3, 3>(args.data(), &result[0]);
891  return result;
892 }
893 static const char* ccellnoise_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
894  "color cellnoise(vector v)\n"
895  "cellnoise generates a field of constant colored cubes based on the integer location.\n"
896  "This is the same as the prman cellnoise function.");
897 
898 double pnoise(const Vec3d &p, const Vec3d &period)
899 {
900  double result = NAN;
901  std::array<double, 3> args {p[0], p[1], p[2]};
902  std::array<int, 3> pargs {std::max((int)1, (int)period[0]), std::max((int)1, (int)period[1]), std::max((int)1, (int)period[2])};
903  PNoise<3, 1>(args.data(), pargs.data(), &result);
904  return result;
905 }
906 static const char* pnoise_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
907  "float pnoise ( vector v, vector period )\n"
908  "periodic noise");
910  std::array<Vec3d, 27> points;
912  double jitter {-1};
913  VoronoiPointData() = default;
914 };
915 
916 static Vec3d *voronoi_points(VoronoiPointData &data, const Vec3d &cell, double jitter)
917 {
918  if (cell == data.cell && jitter == data.jitter)
919  return data.points.data();
920  data.cell = cell;
921  data.jitter = jitter;
922 
923  int n = 0;
924  for (int i = -1; i <= 1; i++) {
925  for (int j = -1; j <= 1; j++) {
926  for (int k = -1; k <= 1; k++, n++) {
927  Vec3d testcell = cell + Vec3d(i, j, k);
928  data.points[n] = testcell + jitter * (ccellnoise(testcell) - Vec3d(.5));
929  }
930  }
931  }
932  return data.points.data();
933 }
934 
935 static void voronoi_f1_3d(VoronoiPointData &data, const Vec3d &p, double jitter, double &f1, Vec3d &pos1)
936 {
937  // from Advanced Renderman, page 257
938  Vec3d thiscell(floor(p[0]) + 0.5, floor(p[1]) + 0.5, floor(p[2]) + 0.5);
939 
940  f1 = 1000;
941  Vec3d *pos = voronoi_points(data, thiscell, jitter);
942  Vec3d *end = pos + 27;
943 
944  for (; pos != end; pos++) {
945  Vec3d offset = *pos - p;
946  double dist = offset.dot(offset);
947  if (dist < f1) {
948  f1 = dist;
949  pos1 = *pos;
950  }
951  }
952  f1 = sqrt(f1);
953 }
954 
955 static void voronoi_f1f2_3d(VoronoiPointData &data, const Vec3d &p, double jitter, double &f1, Vec3d &pos1, double &f2, Vec3d &pos2)
956 {
957  // from Advanced Renderman, page 258
958  Vec3d thiscell(floor(p[0]) + 0.5, floor(p[1]) + 0.5, floor(p[2]) + 0.5);
959  f1 = f2 = 1000;
960  Vec3d *pos = voronoi_points(data, thiscell, jitter);
961  Vec3d *end = pos + 27;
962 
963  for (; pos != end; pos++) {
964  Vec3d offset = *pos - p;
965  double dist = offset.dot(offset);
966  if (dist < f1) {
967  f2 = f1;
968  pos2 = pos1;
969  f1 = dist;
970  pos1 = *pos;
971  } else if (dist < f2) {
972  f2 = dist;
973  pos2 = *pos;
974  }
975  }
976  f1 = sqrt(f1);
977  f2 = sqrt(f2);
978 }
979 
980 Vec3d voronoiFn(VoronoiPointData &data, int n, const Vec3d *args)
981 {
982  // args = p, type, jitter,
983  // fbmScale, fbmOctaves, fbmLacunarity, fbmGain
984  Vec3d p;
985  int type = 1;
986  double jitter = 0.5;
987  double fbmScale = 0;
988  double fbmOctaves = 4;
989  double fbmLacunarity = 2;
990  double fbmGain = 0.5;
991  switch (n) {
992  case 7:
993  fbmGain = args[6][0];
994  /* fall through */
995  case 6:
996  fbmLacunarity = args[5][0];
997  /* fall through */
998  case 5:
999  fbmOctaves = args[4][0];
1000  /* fall through */
1001  case 4:
1002  fbmScale = args[3][0];
1003  /* fall through */
1004  case 3:
1005  jitter = clamp(args[2][0], 1e-3, 1);
1006  /* fall through */
1007  case 2:
1008  type = int(args[1][0]);
1009  /* fall through */
1010  case 1:
1011  p = args[0];
1012  }
1013 
1014  if (fbmScale > 0) {
1015  std::array<Vec3d, 4> fbmArgs;
1016  fbmArgs[0] = 2 * p;
1017  fbmArgs[1] = fbmOctaves;
1018  fbmArgs[2] = fbmLacunarity;
1019  fbmArgs[3] = fbmGain;
1020  p += fbmScale * vfbm(4, fbmArgs.data());
1021  }
1022 
1023  double f1 = NAN;
1024  double f2 = NAN;
1025  Vec3d pos1;
1026  Vec3d pos2;
1027  if (type >= 3)
1028  voronoi_f1f2_3d(data, p, jitter, f1, pos1, f2, pos2);
1029  else
1030  voronoi_f1_3d(data, p, jitter, f1, pos1);
1031 
1032  switch (type) {
1033  case 1:
1034  pos1[0] += 10;
1035  return cellnoise(pos1);
1036  case 2:
1037  return f1;
1038  case 3:
1039  return f2;
1040  case 4:
1041  return f2 - f1;
1042  case 5: {
1043  float scalefactor = static_cast<float>((pos2 - pos1).length() / ((pos1 - p).length() + (pos2 - p).length()));
1044  return smoothstep(f2 - f1, 0, 0.1 * scalefactor);
1045  }
1046  }
1047 
1048  return 0.0;
1049 }
1050 const static char* voronoi_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1051  "float voronoi(vector v, int type=1,float jitter=0.5, float fbmScale=0, int fbmOctaves=4,float fbmLacunarity=2, "
1052  "float fbmGain=.5)\n"
1053  "voronoi is a cellular noise pattern. It is a jittered variant of cellnoise.");
1054 
1055 Vec3d cvoronoiFn(VoronoiPointData &data, int n, const Vec3d *args)
1056 {
1057  // args = p, type, jitter,
1058  // fbmScale, fbmOctaves, fbmLacunarity, fbmGain
1059  Vec3d p;
1060  int type = 1;
1061  double jitter = 0.5;
1062  double fbmScale = 0;
1063  double fbmOctaves = 4;
1064  double fbmLacunarity = 2;
1065  double fbmGain = 0.5;
1066  switch (n) {
1067  case 7:
1068  fbmGain = args[6][0];
1069  /* fall through */
1070  case 6:
1071  fbmLacunarity = args[5][0];
1072  /* fall through */
1073  case 5:
1074  fbmOctaves = args[4][0];
1075  /* fall through */
1076  case 4:
1077  fbmScale = args[3][0];
1078  /* fall through */
1079  case 3:
1080  jitter = clamp(args[2][0], 1e-3, 1);
1081  /* fall through */
1082  case 2:
1083  type = int(args[1][0]);
1084  /* fall through */
1085  case 1:
1086  p = args[0];
1087  }
1088 
1089  if (fbmScale > 0) {
1090  std::array<Vec3d, 4> fbmArgs;
1091  fbmArgs[0] = 2 * p;
1092  fbmArgs[1] = fbmOctaves;
1093  fbmArgs[2] = fbmLacunarity;
1094  fbmArgs[3] = fbmGain;
1095  p += fbmScale * vfbm(4, fbmArgs.data());
1096  }
1097 
1098  double f1 = NAN;
1099  double f2 = NAN;
1100  Vec3d pos1;
1101  Vec3d pos2;
1102  if (type >= 3)
1103  voronoi_f1f2_3d(data, p, jitter, f1, pos1, f2, pos2);
1104  else
1105  voronoi_f1_3d(data, p, jitter, f1, pos1);
1106 
1107  Vec3d color = ccellnoise(pos1);
1108  switch (type) {
1109  case 1:
1110  pos1[0] += 10;
1111  return color;
1112  case 2:
1113  return f1 * color;
1114  case 3:
1115  return f2 * color;
1116  case 4:
1117  return (f2 - f1) * color;
1118  case 5: {
1119  float scalefactor = static_cast<float>((pos2 - pos1).length() / ((pos1 - p).length() + (pos2 - p).length()));
1120  return smoothstep(f2 - f1, 0, 0.1 * scalefactor) * color;
1121  }
1122  }
1123 
1124  return 0.0;
1125 }
1126 const static char* cvoronoi_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1127  "color cvoronoi(vector v, int type=1,float jitter=0.5, float fbmScale=0, int fbmOctaves=4,float fbmLacunarity=2, "
1128  "float fbmGain=.5)\n"
1129  "returns color in cellular pattern. It is a jittered variant of cellnoise.");
1130 
1131 Vec3d pvoronoiFn(VoronoiPointData &data, int n, const Vec3d *args)
1132 {
1133  // args = p, jitter,
1134  // fbmScale, fbmOctaves, fbmLacunarity, fbmGain
1135  Vec3d p;
1136  double jitter = 0.5;
1137  double fbmScale = 0;
1138  double fbmOctaves = 4;
1139  double fbmLacunarity = 2;
1140  double fbmGain = 0.5;
1141  switch (n) {
1142  case 6:
1143  fbmGain = args[5][0];
1144  /* fall through */
1145  case 5:
1146  fbmLacunarity = args[4][0];
1147  /* fall through */
1148  case 4:
1149  fbmOctaves = args[3][0];
1150  /* fall through */
1151  case 3:
1152  fbmScale = args[2][0];
1153  /* fall through */
1154  case 2:
1155  jitter = clamp(args[1][0], 1e-3, 1);
1156  /* fall through */
1157  case 1:
1158  p = args[0];
1159  }
1160 
1161  if (fbmScale > 0) {
1162  std::array<Vec3d, 4> fbmArgs;
1163  fbmArgs[0] = 2 * p;
1164  fbmArgs[1] = fbmOctaves;
1165  fbmArgs[2] = fbmLacunarity;
1166  fbmArgs[3] = fbmGain;
1167  p += fbmScale * vfbm(4, fbmArgs.data());
1168  }
1169 
1170  double f1 = NAN;
1171  Vec3d pos1;
1172  voronoi_f1_3d(data, p, jitter, f1, pos1);
1173  return pos1;
1174 }
1175 const static char* pvoronoi_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1176  "color pvoronoi(vector v, int type=1,float jitter=0.5, float fbmScale=0, int fbmOctaves=4,float fbmLacunarity=2, "
1177  "float fbmGain=.5)\n"
1178  "returns center of voronoi cell.");
1179 
1181 {
1182 public:
1183  using VoronoiFunc = Vec3d(VoronoiPointData &, int, const Vec3d *);
1185  : ExprFuncSimple(true)
1186  , _vfunc(vfunc)
1187  {
1188  }
1189 
1190  ExprType prep(ExprFuncNode *node, bool, ExprVarEnvBuilder &envBuilder) const override
1191  {
1192  // check number of arguments
1193  int nargs = node->numChildren();
1194  if (nargs < 1 || nargs > 7) {
1196  return ExprType().Error();
1197  }
1198 
1199  bool valid = true;
1200  valid &= node->checkArg(0, ExprType().FP(3).Varying(), envBuilder);
1201  for (int i = 1; i < nargs; i++)
1202  valid &= node->checkArg(i, ExprType().FP(1).Constant(), envBuilder);
1203  return valid ? ExprType().FP(3).Varying() : ExprType().Error();
1204  }
1205 
1207  {
1208  return new VoronoiPointData();
1209  }
1210 
1211  void eval(ArgHandle args) override
1212  {
1213  auto *data = dynamic_cast<VoronoiPointData *>(args.data);
1214  int nargs = args.nargs();
1215  auto sevArgs = std::vector<Vec3d>(nargs);
1216 
1217  for (int i = 0; i < nargs; i++)
1218  for (int j = 0; j < 3; j++)
1219  sevArgs[i][j] = args.inFp<3>(i)[j];
1220 
1221  Vec3d result = _vfunc(*data, nargs, sevArgs.data());
1222  double *out = &args.outFp;
1223  for (int i = 0; i < 3; i++)
1224  out[i] = result[i];
1225  }
1226 
1227 private:
1230 
1231 double dist(const Vec3d &a, const Vec3d &b)
1232 {
1233  double x = a[0] - b[0];
1234  double y = a[1] - b[1];
1235  double z = a[2] - b[2];
1236  return sqrt(x * x + y * y + z * z);
1237 }
1238 static const char* dist_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1239  "float dist(vector a, vector b)\n"
1240  "distance between two points");
1241 
1242 double length(const Vec3d &v)
1243 {
1244  return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
1245 }
1246 static const char* length_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1247  "float length(vector v)\n"
1248  "length of vector");
1249 
1250 double hypot(double x, double y)
1251 {
1252  return sqrt(x * x + y * y);
1253 }
1254 static const char* hypot_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1255  "float hypot(vector v)\n"
1256  "length of 2d vector [x,y]");
1257 
1258 double dot(const Vec3d &a, const Vec3d &b)
1259 {
1260  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
1261 }
1262 static const char* dot_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1263  "float dot(vector a,vector b)\n"
1264  "vector dot product");
1265 
1266 Vec3d norm(const Vec3d &a)
1267 {
1268  double len = length(a);
1269  if (len == 0)
1270  return 0.0;
1271  else
1272  return a / len;
1273 }
1274 static const char* norm_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1275  "vector norm(vector v)\n"
1276  "vector scaled to unit length");
1277 
1278 Vec3d cross(const Vec3d &a, const Vec3d &b)
1279 {
1280  return {a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]};
1281 }
1282 static const char* cross_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1283  "vector cross(vector a,vector b)\n"
1284  "vector cross product");
1285 
1286 double angle(const Vec3d &a, const Vec3d &b)
1287 {
1288  double len = length(a) * length(b);
1289  if (len == 0)
1290  return 0;
1291  return acos(dot(a, b) / len);
1292 }
1293 static const char* angle_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1294  "float angle(vector a,vector b)\n"
1295  "angle between two vectors (in radians)");
1296 
1297 Vec3d ortho(const Vec3d &a, const Vec3d &b)
1298 {
1299  return norm(cross(a, b));
1300 }
1301 static const char* ortho_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1302  "vector angle(vector a,vector b)\n"
1303  "normalized vector orthogonal to a and b scaled to unit length");
1304 
1305 Vec3d rotate(int n, const Vec3d *args)
1306 {
1307  if (n != 3)
1308  return 0.0;
1309  const Vec3d &P = args[0];
1310  const Vec3d &axis = args[1];
1311  auto angle = static_cast<float>(args[2][0]);
1312  double len = axis.length();
1313  if (len == 0.0)
1314  return P;
1315  return P.rotateBy(axis / len, angle);
1316 }
1317 static const char* rotate_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1318  "vector rotate(vector v,vector axis,float angle)\n"
1319  "rotates v around axis by given angle (in radians)");
1320 
1321 Vec3d up(const Vec3d &P, const Vec3d &upvec)
1322 {
1323  // rotate vec so y-axis points to upvec
1324  Vec3d yAxis(0, 1, 0);
1325  return P.rotateBy(ortho(upvec, yAxis), angle(upvec, yAxis));
1326 }
1327 static const char* up_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1328  "vector up(vector P,vector upvec)\n"
1329  "rotates v such that the Y axis points in the given up direction");
1330 
1331 double cycle(double index, double loRange, double hiRange)
1332 {
1333  int lo = int(loRange);
1334  int hi = int(hiRange);
1335  int range = hi - lo + 1;
1336  if (range <= 0)
1337  return lo;
1338  int result = int(index) % range;
1339  if (result < 0)
1340  result += range;
1341  return lo + result;
1342 }
1343 static const char* cycle_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1344  "int cycle(int index, int loRange, int hiRange )\n"
1345  "Cycles through values between loRange and hiRange based on supplied index.\n"
1346  "This is an offset \"mod\" function. "
1347  "The result is computed as ``loRange + value % (hiRange-loRange+1)``.");
1348 
1349 double pick(int n, double *params)
1350 {
1351  if (n < 3)
1352  return 0;
1353  double index = hash(1, &params[0]);
1354  int loRange = int(params[1]);
1355  int hiRange = int(params[2]);
1356  int range = hiRange - loRange + 1;
1357  if (range <= 0)
1358  return loRange;
1359  int numWeights = n - 3;
1360  if (numWeights > range)
1361  numWeights = range;
1362 
1363  // build cutoff points based on weights
1364  // note: n is user-controlled; replaced with vector() - amyspark
1365  auto cutoffs = std::vector<double>(range);
1366  auto weights = std::vector<double>(range);
1367  double total = 0;
1368  for (int i = 0; i < range; i++) {
1369  double weight = i < numWeights ? params[i + 3] : 1;
1370  total += weight;
1371  cutoffs[i] = total;
1372  weights[i] = weight;
1373  }
1374 
1375  if (total == 0)
1376  return loRange;
1377 
1378  // scale value from [0..1] to [0..total] range
1379  index *= total;
1380 
1381  // bsearch cutoff table to find index that spans value
1382  int lo = 0;
1383  int hi = range - 1;
1384  while (lo < hi) {
1385  int m = (lo + hi) / 2;
1386  if (index <= cutoffs[m])
1387  hi = m;
1388  else
1389  lo = m + 1;
1390  }
1391 
1392  // skip zero-length intervals
1393  if (weights[lo] == 0) {
1394  if (lo > 0 && cutoffs[lo] > 0) // scan backward if possible
1395  while (--lo > 0 && weights[lo] == 0)
1396  ;
1397  else if (lo < range - 1) // else scan forward if possible
1398  while (++lo < range - 1 && weights[lo] == 0)
1399  ;
1400  }
1401 
1402  // add offset and return result
1403  return loRange + lo;
1404 }
1405 static const char* pick_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1406  "int pick(float index, int loRange, int hiRange, [float weights, ...] )\n"
1407  "Picks values randomly between loRange and hiRange based on supplied index (which is\n"
1408  "automatically hashed).&nbsp; The values will be distributed according\n"
1409  "to the supplied weights.&nbsp; Any weights not supplied are assumed to\n"
1410  "be 1.0.");
1411 
1412 double swatch(int n, double *params)
1413 {
1414  return choose(n, params);
1415 }
1416 static const char* swatch_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1417  "color swatch(float index, color choice0, color choice1, color choice2, [...])\n"
1418  "Chooses one of the supplied color choices based on the index (assumed to be in range [0..1]).");
1419 
1420 double choose(int n, double *params)
1421 {
1422  if (n < 3)
1423  return 0;
1424  double key = params[0];
1425  // NaN protection
1426  if (key != key)
1427  return 0;
1428  int nvals = n - 1;
1429  return params[1 + int(clamp(key * nvals, 0, nvals - 1))];
1430 }
1431 static const char* choose_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1432  "float choose(float index,float choice1, float choice2, [...])\n"
1433  "Chooses one of the supplied choices based on the index (assumed to be in range [0, 1]).");
1434 
1435 double wchoose(int n, double *params)
1436 {
1437  if (n < 5)
1438  return 0;
1439  double key = params[0];
1440  // NaN protection
1441  if (key != key)
1442  return 0;
1443  int nvals = (n - 1) / 2; // nweights = nvals
1444 
1445  // build cutoff points based on weights
1446  // note: n is user-controlled; replaced with vector() - amyspark
1447  auto cutoffs = std::vector<double>(nvals);
1448  auto weights = std::vector<double>(nvals);
1449  double total = 0;
1450  for (int i = 0; i < nvals; i++) {
1451  double weight = params[i * 2 + 2];
1452  total += weight;
1453  cutoffs[i] = total;
1454  weights[i] = weight;
1455  }
1456 
1457  if (total == 0)
1458  return params[1];
1459 
1460  // scale value from [0..1] to [0..total] range
1461  key *= total;
1462 
1463  // bsearch cutoff table to find index that spans value
1464  int lo = 0;
1465  int hi = nvals - 1;
1466  while (lo < hi) {
1467  int m = (lo + hi) / 2;
1468  if (key <= cutoffs[m])
1469  hi = m;
1470  else
1471  lo = m + 1;
1472  }
1473 
1474  // skip zero-length intervals
1475  if (weights[lo] == 0) {
1476  if (lo > 0 && cutoffs[lo] > 0) // scan backward if possible
1477  while (--lo > 0 && weights[lo] == 0)
1478  ;
1479  else if (lo < nvals - 1) // else scan forward if possible
1480  while (++lo < nvals - 1 && weights[lo] == 0)
1481  ;
1482  }
1483 
1484  // return corresponding value
1485  return params[lo * 2 + 1];
1486 }
1487 static const char* wchoose_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1488  "float wchoose(float index,float choice1, float weight1, float choice2, float weight2, [...] )\n"
1489  "Chooses one of the supplied choices based on the index (assumed to be in range [0..1]).\n"
1490  "The values will be distributed according to the supplied weights.");
1491 
1492 double spline(int n, double *params)
1493 {
1494  if (n < 5)
1495  return 0;
1496  double u = clamp(params[0], 0, 1);
1497  if (u == 0)
1498  return params[2];
1499  if (u == 1)
1500  return params[n - 2];
1501  int nsegs = n - 4;
1502  double seg = NAN;
1503  u = modf(u * nsegs, &seg);
1504  double *p = &params[int(seg) + 1];
1505  double u2 = u * u;
1506  double u3 = u2 * u;
1507  return 0.5 * (p[0] * (-u3 + 2 * u2 - u) + p[1] * (3 * u3 - 5 * u2 + 2) + p[2] * (-3 * u3 + 4 * u2 + u) + p[3] * (u3 - u2));
1508 }
1509 static const char* spline_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1510  "float spline(float param,float y1,float y2,float y3,float y4,[...])\n\n"
1511  "Interpolates a set of values to the parameter specified where y1, ..., yn are\n"
1512  "distributed evenly from [0..1]");
1513 
1514 template<class T> struct CurveData : public ExprFuncNode::Data {
1516  CurveData() = default;
1517  ~CurveData() override = default;
1518  CurveData(const CurveData &) = default;
1519  CurveData &operator=(const CurveData &) = default;
1520  CurveData(CurveData &&) noexcept = default;
1521  CurveData &operator=(CurveData &&) noexcept = default;
1522 };
1523 
1525 {
1526 public:
1527  CurveFuncX() noexcept
1528  : ExprFuncSimple(true)
1529  {
1530  }
1531 
1532  ExprType prep(ExprFuncNode *node, bool, ExprVarEnvBuilder &envBuilder) const override
1533  {
1534  // check number of arguments
1535  int nargs = node->numChildren();
1536  if ((nargs - 1) % 3) {
1538  return ExprType().Error();
1539  }
1540 
1541  bool valid = true;
1542  valid &= node->checkArg(0, ExprType().FP(1).Varying(), envBuilder);
1543  for (int i = 1; i < nargs && valid; i += 3) {
1544  valid &= node->checkArg(i, ExprType().FP(1).Constant(), envBuilder);
1545  valid &= node->checkArg(i + 1, ExprType().FP(1).Constant(), envBuilder);
1546  valid &= node->checkArg(i + 2, ExprType().FP(1).Constant(), envBuilder);
1547  if (valid) {
1548  const auto *value = dynamic_cast<ExprNumNode *>(node->child(i + 2));
1549  if (!value) {
1550  node->addError(ErrorCode::Unknown, {QT_TRANSLATE_NOOP_UTF8("builtin", "Unable to validate the interpolant type")});
1551  return ExprType().Error().Varying();
1552  }
1553  else if (!Curve<Vec3d>::interpTypeValid(static_cast<Curve<Vec3d>::InterpType>((int)value->value()))){
1554  node->addError(ErrorCode::Unknown, {QT_TRANSLATE_NOOP_UTF8("builtin", "Invalid interpolant type")});
1555  return ExprType().Error().Varying();
1556  }
1557  }
1558  }
1559  return valid ? ExprType().FP(1).Varying() : ExprType().Error();
1560  }
1561 
1563  {
1564  auto *data = new CurveData<double>;
1565  for (int i = 1; i < args.nargs() - 2; i += 3) {
1566  double pos = args.inFp<1>(i)[0];
1567  double val = args.inFp<1>(i + 1)[0];
1568  double interpDouble = args.inFp<1>(i + 2)[0];
1569  int interpInt = (int)interpDouble;
1570  auto interpolant = (Curve<double>::InterpType)interpInt;
1571  if (!Curve<double>::interpTypeValid(interpolant)) {
1572  assert(false && "ExprFuncNode ERROR: invalid interpolant type!");
1573  }
1574  data->curve.addPoint(pos, val, interpolant);
1575  }
1576  data->curve.preparePoints();
1577  return data;
1578  }
1579 
1580  void eval(ArgHandle args) override
1581  {
1582  auto *data = dynamic_cast<CurveData<double> *>(args.data);
1583  double param = args.inFp<1>(0)[0];
1584  args.outFp = data->curve.getValue(param);
1585  }
1586 
1588 static const char* curve_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1589  "float curve(float param,float pos0,float val0,int interp0,float pos1,float val1,int interp1,[...])\n\n"
1590  "Interpolates a 1D ramp defined by control points at 'param'. Control points are specified \n"
1591  "by triples of parameters pos_i, val_i, and interp_i. Interpolation codes are \n"
1592  "0 - none, 1 - linear, 2 - smooth, 3 - spline, \n"
1593  "4 - monotone (non oscillating spline)");
1594 
1596 {
1597  ExprType prep(ExprFuncNode *node, bool, ExprVarEnvBuilder &envBuilder) const override
1598  {
1599  // check number of arguments
1600  int nargs = node->numChildren();
1601  if ((nargs - 1) % 3) {
1603  return ExprType().Error().Varying();
1604  }
1605 
1606  bool valid = true;
1607  valid &= node->checkArg(0, ExprType().FP(1).Varying(), envBuilder);
1608  for (int i = 1; i < nargs && valid; i += 3) {
1609  valid &= node->checkArg(i, ExprType().FP(1).Constant(), envBuilder);
1610  valid &= node->checkArg(i + 1, ExprType().FP(3).Constant(), envBuilder);
1611  valid &= node->checkArg(i + 2, ExprType().FP(1).Constant(), envBuilder);
1612  if (valid) {
1613  const auto *value = dynamic_cast<ExprNumNode *>(node->child(i + 2));
1614  if (!value) {
1615  node->addError(ErrorCode::Unknown, {QT_TRANSLATE_NOOP_UTF8("builtin", "Unable to validate the interpolant type")});
1616  return ExprType().Error().Varying();
1617  } else if (!Curve<Vec3d>::interpTypeValid(static_cast<Curve<Vec3d>::InterpType>((int)value->value()))) {
1618  node->addError(ErrorCode::Unknown, {QT_TRANSLATE_NOOP_UTF8("builtin", "Invalid interpolant type")});
1619  return ExprType().Error().Varying();
1620  }
1621  }
1622  }
1623  return valid ? ExprType().FP(3).Varying() : ExprType().Error();
1624  }
1625 
1627  {
1628  auto *data = new CurveData<Vec3d>;
1629  for (int i = 1; i < args.nargs() - 2; i += 3) {
1630  double pos = args.inFp<1>(i)[0];
1631  Vec3dRef val(&args.inFp<3>(i + 1)[0]);
1632  double interpDouble = args.inFp<1>(i + 2)[0];
1633  int interpInt = (int)interpDouble;
1634  auto interpolant = (Curve<Vec3d>::InterpType)interpInt;
1635  if (!Curve<Vec3d>::interpTypeValid(interpolant)) {
1636  // TODO: fix error checking!
1637  }
1638  data->curve.addPoint(pos, val, interpolant);
1639  }
1640  data->curve.preparePoints();
1641  return data;
1642  }
1643 
1644  void eval(ArgHandle args) override
1645  {
1646  auto *data = dynamic_cast<CurveData<Vec3d> *>(args.data);
1647  double param = args.inFp<1>(0)[0];
1648  Vec3d result = data->curve.getValue(param);
1649  double *out = &args.outFp;
1650  for (int k = 0; k < 3; k++)
1651  out[k] = result[k];
1652  }
1653 
1654 public:
1655  CCurveFuncX() noexcept
1656  : ExprFuncSimple(true)
1657  {
1658  } // Thread Safe
1660 static const char* ccurve_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1661  "color curve(float param,float pos0,color val0,int interp0,float pos1,color val1,int interp1,[...])\n\n"
1662  "Interpolates color ramp given by control points at 'param'. Control points are specified \n"
1663  "by triples of parameters pos_i, val_i, and interp_i. Interpolation codes are \n"
1664  "0 - none, 1 - linear, 2 - smooth, 3 - spline, \n"
1665  "4 - monotone (non oscillating spline)");
1666 
1667 class GetVar : public ExprFuncSimple
1668 {
1669  struct Data : public ExprFuncNode::Data {
1670  using func = void (*)(double *, double *);
1671  Data(func fIn, int dim)
1672  : f(fIn)
1673  , dim(dim)
1674  {
1675  }
1677  int dim;
1678  };
1679 
1680  ExprType prep(ExprFuncNode *node, bool wantScalar, ExprVarEnvBuilder &envBuilder) const override
1681  {
1682  bool valid = true;
1683  valid &= node->checkArg(0, ExprType().String().Constant(), envBuilder);
1684  std::string varName = node->getStrArg(0);
1685  auto *varNode = new ExprVarNode(node->expr(), varName.c_str());
1686  ExprType varType = varNode->prep(wantScalar, envBuilder);
1687  if (varType.isValid()) {
1688  node->removeLastChild(); // remove the useless default argument from the arugment list
1689  node->removeLastChild(); // remove the useless default argument from the arugment list
1690  node->addChild(varNode);
1691  } else {
1692  delete varNode;
1693  node->swapChildren(0, 1); // move the default argument in the beginning
1694  varType = node->child(0)->prep(wantScalar, envBuilder);
1695  node->removeLastChild(); // remove the useless string argument
1696  }
1697  return varType.isValid() ? varType : ExprType().Error();
1698  }
1699 
1701  {
1702  return new Data(node->type().isFP() ? getTemplatizedOp<Assign, Data::func>(node->type().dim()) : nullptr, node->type().dim());
1703  }
1704 
1705  template<int d> struct Assign {
1706  static void f(double *out, double *in)
1707  {
1708  for (int k = 0; k < d; k++)
1709  out[k] = in[k];
1710  }
1711  };
1712 
1713  void eval(ArgHandle args) override
1714  {
1715  Data *data = dynamic_cast<Data *>(args.data);
1716  assert(data);
1717  double *out = &args.outFp;
1718  // for(int i=0;i<data->dim;i++) std::cerr<<" "<<args.inFp<1>(0)[i];
1719  // std::cerr<<std::endl;
1720  if (data->f)
1721  data->f(out, &args.inFp<1>(0)[0]);
1722  else
1723  throw std::runtime_error("getVar does not support non FP types right now got type");
1724  }
1725 
1726 public:
1727  GetVar() noexcept
1728  : ExprFuncSimple(true)
1729  {
1730  } // Thread Safe
1732 static const char* getVar_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1733  "getVar(string varName,vector defaultValue)\n"
1734  "return value of varName if variable exists, otherwise return defaultValue");
1735 
1737 {
1738  struct Data : public ExprFuncNode::Data {
1739  std::vector<std::pair<int, int>> ranges;
1740  std::string format;
1741  };
1742 
1743 public:
1744  ExprType prep(ExprFuncNode *node, bool, ExprVarEnvBuilder &envBuilder) const override
1745  {
1746  int nargs = node->numChildren();
1747  if (nargs < 1) {
1749  return ExprType().Error();
1750  }
1751 
1752  bool valid = true;
1753  valid &= node->checkArg(0, ExprType().String().Constant(), envBuilder);
1754 
1755  int items = 0;
1756  int searchStart = 0;
1757  auto format = node->getStrArg(0);
1758  while (true) {
1759  std::size_t percentStart = format.find('%', searchStart);
1760  if (percentStart == std::string::npos)
1761  break;
1762  if (percentStart + 1 == format.length()) {
1764  return ExprType().Error();
1765  } else if (format[percentStart + 1] == '%') {
1766  searchStart = static_cast<int>(percentStart + 2);
1767  continue;
1768  } else if (format[percentStart + 1] == 'v' || format[percentStart + 1] == 'f') {
1769  items++;
1770  if (items >= node->numChildren()) {
1771  // TODO: test here, checkArg should not fail
1773  return ExprType().Error();
1774  } else {
1775  valid &= (node->checkArg(items, ExprType().FP(1), envBuilder) || node->checkArg(items, ExprType().FP(3), envBuilder));
1776  searchStart = static_cast<int>(percentStart + 2);
1777  }
1778  } else {
1780  return ExprType().Error();
1781  }
1782  }
1783 
1784  if (!valid) {
1786  return ExprType().Error();
1787  } else if (items != nargs - 1) {
1789  return ExprType().Error();
1790  }
1791 
1792  return ExprType().FP(1).Constant();
1793  }
1794 
1796  {
1797  // parse format string
1798  unsigned int bakeStart = 0;
1799  int searchStart = 0;
1800  int needed = 0;
1801  Data *data = new Data;
1802  data->format = args.inStr(0);
1803  std::string &format = data->format;
1804  std::vector<std::pair<int, int>> &ranges = data->ranges;
1805 
1806  int items = 0;
1807  while (true) {
1808  std::size_t percentStart = format.find('%', searchStart);
1809  if (percentStart == std::string::npos)
1810  break;
1811  if (percentStart + 1 == format.length()) {
1812  // node->addError("Unexpected end of format string");
1813  delete data;
1814  assert(false);
1815  } else if (format[percentStart + 1] == '%') {
1816  searchStart = static_cast<int>(percentStart + 2);
1817  continue;
1818  } else if (format[percentStart + 1] == 'v' || format[percentStart + 1] == 'f') {
1819  char c = format[percentStart + 1];
1820  int code = (c == 'v') ? -1 : -2;
1821  needed++;
1822  if (bakeStart != percentStart)
1823  ranges.emplace_back(bakeStart, static_cast<int>(percentStart));
1824  ranges.emplace_back(code, code);
1825  items++;
1826  searchStart = static_cast<int>(percentStart + 2);
1827  bakeStart = searchStart;
1828  } else {
1829  // node->addError("Invalid format string, only %v is allowed");
1830  delete data;
1831  // TODO: check that this is correct
1832  // return ExprType().Error().Varying();
1833  // return false;
1834  assert(false);
1835  }
1836  }
1837  if (bakeStart != format.length())
1838  ranges.emplace_back(bakeStart, static_cast<int>(format.length()));
1839 
1840  if (items != args.nargs() - 1) {
1841  // node->addError("Wrong number of arguments for format string");
1842  delete data;
1843  // TODO: check that this is correct
1844  // return ExprType().Error().Varying();
1845  // return false;
1846  assert(false);
1847  }
1848 
1849  return data;
1850  }
1851 
1852  void eval(ArgHandle args) override
1853  {
1854  Data *data = dynamic_cast<Data *>(args.data);
1855  int item = 1;
1856  for (unsigned int i = 0; i < data->ranges.size(); i++) {
1857  const std::pair<int, int> &range = data->ranges[i];
1858  if (range.first == -2) {
1859  std::cerr << args.inFp<1>(item)[0];
1860  item++;
1861  } else if (range.first == -1) {
1862  std::cerr << "[" << args.inFp<3>(item)[0] << "," << args.inFp<3>(item)[1] << "," << args.inFp<3>(item)[2] << "]";
1863  item++;
1864  } else {
1865  std::cerr << data->format.substr(range.first, range.second - range.first);
1866  }
1867  }
1868  std::cerr << std::endl;
1869 
1870  args.outFp = 0;
1871  }
1872 
1873  PrintFuncX() noexcept
1874  : ExprFuncSimple(false)
1875  {
1876  } // not thread safe
1877 
1879 static const char* printf_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1880  "float printf(string format,[vec0, vec1, ...])\n"
1881  "Prints out a string to STDOUT, Format parameters allowed are \"%v\" and \"%f\".\n"
1882  "Return parameter is empty, but must be assigned to a variable.");
1883 
1885 {
1886  struct StringData : public KSeExpr::ExprFuncNode::Data, public std::string {
1887  };
1888 
1889  // Format specifier categories for SPrintFuncX
1890  std::string _intSpec {"diouxXc"};
1891  std::string _doubleSpec {"eEfFgGaA"};
1892  std::string _strSpec {"s"};
1893 
1894 public:
1895  SPrintFuncX() noexcept
1896  : ExprFuncSimple(false)
1897  {
1898  } // not thread safe
1899 
1900  ExprType prep(ExprFuncNode *node, bool, ExprVarEnvBuilder &envBuilder) const override
1901  {
1902  int nargs = node->numChildren();
1903  if (nargs < 1) {
1905  return ExprType().Error().Constant();
1906  }
1907  if (!node->checkArg(0, ExprType().String().Constant(), envBuilder)) {
1909  return ExprType().Error().Constant();
1910  }
1911 
1912  const std::string &format = dynamic_cast<const ExprStrNode *>(node->child(0))->str();
1913 
1914  static const std::string strSpec("s");
1915  size_t searchStart = 0;
1916  size_t exprArg = 1;
1917  while (true) {
1918  const size_t specStart = format.find('%', searchStart);
1919  if (specStart == std::string::npos)
1920  break;
1921  if (specStart + 1 == format.length()) {
1923  return ExprType().Error().Constant();
1924  }
1925  if (format[specStart + 1] == '%') {
1926  searchStart = specStart + 2; // Skip "%%"
1927  continue;
1928  }
1929 
1930  const size_t specEnd = format.find_first_of(std::string(_intSpec).append(_doubleSpec).append(_strSpec), specStart);
1931  if (specEnd == std::string::npos) {
1933  return ExprType().Error().Constant();
1934  }
1935  if (_strSpec.find(format[specEnd]) != std::string::npos) {
1936  if (!node->checkArg(exprArg, ExprType().String(), envBuilder)) {
1937  return ExprType().Error().Constant();
1938  }
1939  } else {
1940  if (!node->checkArg(exprArg, ExprType().FP(1), envBuilder)) {
1941  return ExprType().Error().Constant();
1942  }
1943  }
1944  ++exprArg;
1945  searchStart = specEnd + 1;
1946  };
1947  return ExprType().String().Constant();
1948  }
1949 
1951  {
1952  return new StringData();
1953  }
1954 
1955  void eval(ArgHandle args) override
1956  {
1957  auto result = *dynamic_cast<StringData *>(args.data);
1958  result.assign(args.inStr(0));
1959 
1960  std::array<char, 255> fragment {};
1961  size_t searchStart = 0;
1962  size_t exprArg = 1;
1963  while (true) {
1964  const size_t specStart = result.find('%', searchStart);
1965  if (specStart == std::string::npos)
1966  break;
1967  if (result[specStart + 1] == '%') {
1968  result.erase(specStart, 1);
1969  searchStart = specStart + 1;
1970  continue;
1971  }
1972 
1973  const size_t specEnd = result.find_first_of(std::string(_intSpec).append(_doubleSpec).append(_strSpec), specStart);
1974  const std::string &spec = result.substr(specStart, specEnd - specStart + 1);
1975  int fragLen = -1;
1976  if (std::string::npos != _intSpec.find(result[specEnd]))
1977  fragLen = snprintf(fragment.data(), 255, spec.c_str(), int(args.inFp<1>(exprArg++)[0]));
1978  else if (std::string::npos != _doubleSpec.find(result[specEnd]))
1979  fragLen = snprintf(fragment.data(), 255, spec.c_str(), args.inFp<1>(exprArg++)[0]);
1980  else if (std::string::npos != _strSpec.find(result[specEnd]))
1981  fragLen = snprintf(fragment.data(), 255, spec.c_str(), args.inStr(exprArg++));
1982  assert(fragLen >= 0);
1983 
1984  result.replace(specStart, spec.size(), fragment.data());
1985  searchStart += fragLen + 1;
1986  };
1987 
1988  args.outStr = const_cast<char *>(result.c_str());
1989  }
1990 
1992 static const char* sprintf_docstring = QT_TRANSLATE_NOOP_UTF8("builtin",
1993  "sprintf(string format, [double|string, double|string, ...])\n"
1994  "Returns a string formatted from the given values. See 'man sprintf' for format details.");
1995 
1996 #if 0
1997 
1998 class TestFunc:public ExprFuncSimple
1999 {
2000  struct MyData:public ExprFuncNode::Data
2001  {
2002  float foo;
2003  MyData(float foo)
2004  :foo(foo)
2005  {}
2006  };
2007 public:
2008  TestFunc()
2009  :ExprFuncSimple(true)
2010  {}
2011  virtual ExprType prep(ExprFuncNode* node,bool scalarWanted,ExprVarEnvBuilder& envBuilder) const
2012  {
2013  bool valid=true;
2014  valid &= node->checkArg(0,ExprType().FP(3).Varying(),envBuilder);
2015  valid &= node->checkArg(1,ExprType().FP(1).Constant(),envBuilder);
2016  return valid ?ExprType().FP(3).Varying():ExprType().Error();
2017  }
2018  virtual ExprFuncNode::Data* evalConstant(ArgHandle args) const
2019  {
2020  //std::cerr<<"evalling const "<<args.inFp<1>(1)<<std::endl;
2021  return new MyData(args.inFp<1>(1)[0]);
2022  }
2023  virtual void eval(ArgHandle args)
2024  {
2025  MyData* data=static_cast<MyData*>(args.data);
2026 
2027  Vec<double,3,true>(&args.outFp)=args.inFp<3>(0)+Vec<double,3,false>(data->foo);
2028  }
2029 } testfunc;
2030 static const char* testfunc_docstring="fdsA";
2031 
2032 #endif
2033 
2035 // functions from math.h (global namespace)
2036 //#define FUNC(func) define(#func, ExprFunc(::func))
2037 #define FUNCADOC(name, func) define3(name, ExprFunc(::func), func##_docstring)
2038 #define FUNCDOC(func) define3(#func, ExprFunc(::func), func##_docstring)
2039  FUNCADOC("abs", fabs);
2040  FUNCDOC(acos);
2041  FUNCDOC(asin);
2042  FUNCDOC(atan);
2043  FUNCDOC(atan2);
2044  FUNCDOC(ceil);
2045  FUNCDOC(cos);
2046  FUNCDOC(cosh);
2047  FUNCDOC(exp);
2048  FUNCDOC(floor);
2049  FUNCDOC(fmod);
2050  FUNCDOC(log);
2051  FUNCDOC(log10);
2052  FUNCDOC(pow);
2053  FUNCDOC(sin);
2054  FUNCDOC(sinh);
2055  FUNCDOC(sqrt);
2056  FUNCDOC(tan);
2057  FUNCDOC(tanh);
2058  FUNCDOC(cbrt);
2059  FUNCDOC(asinh);
2060  FUNCDOC(acosh);
2061  FUNCDOC(atanh);
2062  FUNCDOC(trunc);
2063 // local functions (KSeExpr namespace)
2064 //#undef FUNC
2065 #undef FUNCDOC
2066 //#define FUNC(func) define(#func, ExprFunc(KSeExpr::func))
2067 //#define FUNCN(func, min, max) define(#func, ExprFunc(KSeExpr::func, min, max))
2068 #define FUNCDOC(func) define3(#func, ExprFunc(KSeExpr::func), func##_docstring)
2069 #define FUNCNDOC(func, min, max) define3(#func, ExprFunc(KSeExpr::func, min, max), func##_docstring)
2070 
2071  // trig
2072  FUNCDOC(deg);
2073  FUNCDOC(rad);
2074  FUNCDOC(cosd);
2075  FUNCDOC(sind);
2076  FUNCDOC(tand);
2077  FUNCDOC(acosd);
2078  FUNCDOC(asind);
2079  FUNCDOC(atand);
2080  FUNCDOC(atan2d);
2081 
2082  // clamping
2083  FUNCDOC(clamp);
2084  FUNCDOC(round);
2085  FUNCDOC(max);
2086  FUNCDOC(min);
2087 
2088  // blending / remapping
2089  FUNCDOC(invert);
2090  FUNCDOC(compress);
2091  FUNCDOC(expand);
2092  FUNCDOC(fit);
2093  FUNCDOC(gamma);
2094  FUNCDOC(bias);
2095  FUNCDOC(contrast);
2096  FUNCDOC(boxstep);
2099  FUNCDOC(gaussstep);
2100  FUNCDOC(remap);
2101  FUNCDOC(mix);
2102  FUNCNDOC(hsi, 4, 5);
2103  FUNCNDOC(midhsi, 5, 7);
2104  FUNCDOC(hsltorgb);
2105  FUNCDOC(rgbtohsl);
2106  FUNCNDOC(saturate, 2, 2);
2107 
2108  // noise
2109  FUNCNDOC(rand, 0, 3);
2110  FUNCNDOC(hash, 1, -1);
2111  FUNCNDOC(noise, 1, 4);
2112  FUNCDOC(snoise);
2113  FUNCDOC(vnoise);
2114  FUNCDOC(cnoise);
2115  FUNCNDOC(snoise4, 2, 2);
2116  FUNCNDOC(vnoise4, 2, 2);
2117  FUNCNDOC(cnoise4, 2, 2);
2118  FUNCNDOC(turbulence, 1, 4);
2119  FUNCNDOC(vturbulence, 1, 4);
2120  FUNCNDOC(cturbulence, 1, 4);
2121  FUNCNDOC(fbm, 1, 4);
2122  FUNCNDOC(vfbm, 1, 4);
2123  FUNCNDOC(cfbm, 1, 4);
2124  FUNCDOC(cellnoise);
2126  FUNCDOC(pnoise);
2127  FUNCNDOC(fbm4, 2, 5);
2128  FUNCNDOC(vfbm4, 2, 5);
2129  FUNCNDOC(cfbm4, 2, 5);
2130 
2131  // vectors
2132  FUNCDOC(dist);
2133  FUNCDOC(length);
2134  FUNCDOC(hypot);
2135  FUNCDOC(dot);
2136  FUNCDOC(norm);
2137  FUNCDOC(cross);
2138  FUNCDOC(angle);
2139  FUNCDOC(ortho);
2140  FUNCNDOC(rotate, 3, 3);
2141  FUNCDOC(up);
2142 
2143  // variations
2144  FUNCDOC(cycle);
2145  FUNCNDOC(pick, 3, -1);
2146  FUNCNDOC(choose, 3, -1);
2147  FUNCNDOC(wchoose, 4, -1);
2148  FUNCNDOC(swatch, 3, -1);
2149  FUNCNDOC(spline, 5, -1);
2150 
2151  // FuncX interface
2152  // noise
2153  FUNCNDOC(voronoi, 1, 7);
2154  FUNCNDOC(cvoronoi, 1, 7);
2155  FUNCNDOC(pvoronoi, 1, 6);
2156  // variations
2157  FUNCNDOC(curve, 1, -1);
2158  FUNCNDOC(ccurve, 1, -1);
2159  FUNCNDOC(getVar, 2, 2);
2160  FUNCNDOC(printf, 1, -1);
2161  // FUNCNDOC(testfunc,2,2);
2162 
2163  FUNCNDOC(sprintf, 1, -1);
2164 }
2165 } // namespace KSeExpr
ExprType prep(ExprFuncNode *node, bool, ExprVarEnvBuilder &envBuilder) const override
Definition: ExprBuiltins.cpp:8
#define FUNCDOC(func)
ExprFuncNode::Data * evalConstant(const ExprFuncNode *, ArgHandle) const override
void eval(ArgHandle args) override
#define FUNCNDOC(func, min, max)
#define FUNCADOC(name, func)
#define QT_TRANSLATE_NOOP(scope, x)
Definition: ExprBuiltins.h:19
#define QT_TRANSLATE_NOOP_UTF8(scope, x)
Definition: ExprBuiltins.h:22
static constexpr std::array< int, 514 > p
Definition: NoiseTables.h:10
ExprFuncNode::Data * evalConstant(const ExprFuncNode *, ArgHandle args) const override
void eval(ArgHandle args) override
ExprType prep(ExprFuncNode *node, bool, ExprVarEnvBuilder &envBuilder) const override
ExprFuncNode::Data * evalConstant(const ExprFuncNode *, ArgHandle) const override
CachedVoronoiFunc(VoronoiFunc *vfunc) noexcept
ExprType prep(ExprFuncNode *node, bool, ExprVarEnvBuilder &envBuilder) const override
Vec3d(VoronoiPointData &, int, const Vec3d *) VoronoiFunc
void eval(ArgHandle args) override
ExprFuncNode::Data * evalConstant(const ExprFuncNode *, ArgHandle args) const override
ExprType prep(ExprFuncNode *node, bool, ExprVarEnvBuilder &envBuilder) const override
void eval(ArgHandle args) override
Interpolation curve class for double->double and double->Vec3D.
Definition: Curve.h:27
InterpType
Supported interpolation types.
Definition: Curve.h:32
Node that calls a function.
Definition: ExprNode.h:654
bool checkArg(int argIndex, const ExprType &type, ExprVarEnvBuilder &envBuilder)
Definition: ExprNode.cpp:631
std::string getStrArg(int n) const
Definition: ExprNode.h:715
ExprFuncNode::Data * data
Definition: ExprFuncX.h:91
Vec< double, d, true > inFp(int i)
Definition: ExprFuncX.h:77
ExprFuncSimple(const bool threadSafe)
Definition: ExprFuncX.h:66
void(*)(const char *, const ExprFunc &, const char *) Define3
Definition: ExprFunc.h:50
void(*)(const char *, const ExprFunc &) Define
Definition: ExprFunc.h:49
virtual ExprType prep(bool dontNeedScalar, ExprVarEnvBuilder &envBuilder)
Definition: ExprNode.cpp:121
void swapChildren(size_t i, size_t j)
Swap children, do not use unless you know what you are doing.
Definition: ExprNode.h:126
const Expression * expr() const
Access expression.
Definition: ExprNode.h:89
int numChildren() const
Number of children.
Definition: ExprNode.h:108
void removeLastChild()
Remove last child and delete the entry.
Definition: ExprNode.h:133
const ExprType & type() const
The type of the node.
Definition: ExprNode.h:150
void addError(const ErrorCode error, const std::vector< std::string > &ids={}) const
Register error. This will allow users and sophisticated editors to highlight where in code problem wa...
Definition: ExprNode.h:182
const ExprNode * child(size_t i) const
Get 0 indexed child.
Definition: ExprNode.h:114
void addChild(ExprNode *child)
Add a child to the child list (for parser use only)
Definition: ExprNode.cpp:106
Node that stores a numeric constant.
Definition: ExprNode.h:610
Node that stores a string.
Definition: ExprNode.h:632
ExprType & String()
Mutate this into a string type.
Definition: ExprType.h:104
bool isValid() const
Definition: ExprType.h:202
ExprType & Constant()
Mutate this into a constant lifetime.
Definition: ExprType.h:122
int dim() const
Definition: ExprType.h:180
ExprType & Varying()
Mutate this into a varying lifetime.
Definition: ExprType.h:134
ExprType & FP(int d)
Mutate this into a floating point type of dimension d.
Definition: ExprType.h:97
bool isFP() const
Direct is predicate checks.
Definition: ExprType.h:190
ExprType & Error()
Mutate this into an error type.
Definition: ExprType.h:111
Variable scope builder is used by the type checking and code gen to track visiblity of variables and ...
Definition: ExprEnv.h:181
Node that references a variable.
Definition: ExprNode.h:572
ExprFuncNode::Data * evalConstant(const ExprFuncNode *node, ArgHandle) const override
ExprType prep(ExprFuncNode *node, bool wantScalar, ExprVarEnvBuilder &envBuilder) const override
void eval(ArgHandle args) override
void eval(ArgHandle args) override
ExprType prep(ExprFuncNode *node, bool, ExprVarEnvBuilder &envBuilder) const override
ExprFuncNode::Data * evalConstant(const ExprFuncNode *, ArgHandle args) const override
void eval(ArgHandle args) override
ExprFuncNode::Data * evalConstant(const ExprFuncNode *, ArgHandle args) const override
ExprType prep(ExprFuncNode *node, bool, ExprVarEnvBuilder &envBuilder) const override
ExprFuncNode::Data * evalConstant(const ExprFuncNode *, ArgHandle) const override
void eval(ArgHandle args) override
ExprType prep(ExprFuncNode *node, bool, ExprVarEnvBuilder &envBuilder) const override
T dot(const Vec< T, d, refother > &o) const
Definition: Vec.h:292
T_VEC_VALUE rotateBy(const Vec< T, 3, refother > &axis, T angle) const
Definition: Vec.h:330
T length() const
Euclidean (2) norm.
Definition: Vec.h:153
KSeExpr_DEFAULT double_t floor(double_t val)
Definition: Utils.cpp:168
double gamma(double x, double g)
Vec3d cvoronoiFn(VoronoiPointData &data, int n, const Vec3d *args)
static const char * pnoise_docstring
static const char * invert_docstring
static const char * atand_docstring
static const char * vfbm4_docstring
Vec3d pvoronoiFn(VoronoiPointData &data, int n, const Vec3d *args)
double max(double x, double y)
Definition: ExprBuiltins.h:74
static const char * trunc_docstring
static const char * ceil_docstring
static const char * remap_docstring
static const char * vnoise_docstring
double deg(double angle)
Definition: ExprBuiltins.h:28
double atan2d(double y, double x)
Definition: ExprBuiltins.h:60
double gaussstep(double x, double a, double b)
double fit(double x, double a1, double b1, double a2, double b2)
double mix(double x, double y, double alpha)
double asind(double x)
Definition: ExprBuiltins.h:52
static const char * voronoi_docstring
static const char * mix_docstring
static const char * fmod_docstring
static const char * cos_docstring
static const char * cross_docstring
double dist(const Vec3d &a, const Vec3d &b)
static const char * pick_docstring
KSeExpr::SPrintFuncX sprintf
static const char * smoothstep_docstring
Vec3d vturbulence(int n, const Vec3d *args)
Vec3d vnoise4(int, const Vec3d *args)
static const char * hypot_docstring
static void voronoi_f1f2_3d(VoronoiPointData &data, const Vec3d &p, double jitter, double &f1, Vec3d &pos1, double &f2, Vec3d &pos2)
static const char * hsi_docstring
static const char * expand_docstring
static const char * noise_docstring
static const char * atan2d_docstring
Vec3d rgbtohsl(const Vec3d &rgb)
double dot(const Vec3d &a, const Vec3d &b)
double fbm4(int n, const Vec3d *args)
static const char * acos_docstring
static const char * hash_docstring
static const char * cycle_docstring
static const char * cfbm4_docstring
Vec3d cfbm(int n, const Vec3d *args)
double bias(double x, double b)
static const char * cellnoise_docstring
KSeExpr::PrintFuncX printf
double pnoise(const Vec3d &p, const Vec3d &period)
static const char * vfbm_docstring
static const char * rad_docstring
Vec3d vfbm(int n, const Vec3d *args)
static const char * asind_docstring
Vec3d cnoise4(int n, const Vec3d *args)
static const char * turbulence_docstring
static const char * compress_docstring
double contrast(double x, double c)
static const char * fit_docstring
double hypot(double x, double y)
static double hslvalue(double x, double y, double H)
double snoise4(int, const Vec3d *args)
double noise(int n, const Vec3d *args)
static const char * acosh_docstring
static const char * rotate_docstring
static const char * pvoronoi_docstring
static const char * atanh_docstring
Vec3d cturbulence(int n, const Vec3d *args)
static const char * cturbulence_docstring
Vec3d norm(const Vec3d &a)
double tand(double x)
Definition: ExprBuiltins.h:44
static const char * dist_docstring
static void voronoi_f1_3d(VoronoiPointData &data, const Vec3d &p, double jitter, double &f1, Vec3d &pos1)
static const char * max_docstring
KSeExpr::CurveData voronoi
static const char * vturbulence_docstring
KSeExpr::GetVar getVar
double length(const Vec3d &v)
double fbm(int n, const Vec3d *args)
static const char * printf_docstring
Vec3d hsiAdjust(const Vec3d &rgb, double h, double s, double i)
static const char * min_docstring
static const char * atan2_docstring
static const char * gamma_docstring
double invert(double x)
Definition: ExprBuiltins.h:84
double angle(const Vec3d &a, const Vec3d &b)
static const char * midhsi_docstring
static Vec3d * voronoi_points(VoronoiPointData &data, const Vec3d &cell, double jitter)
Vec3d up(const Vec3d &P, const Vec3d &upvec)
static const char * wchoose_docstring
double linearstep(double x, double a, double b)
double round(double x)
Definition: ExprBuiltins.h:70
static const char * log10_docstring
static const char * floor_docstring
static const char * boxstep_docstring
static const char * cvoronoi_docstring
Vec3d voronoiFn(VoronoiPointData &data, int n, const Vec3d *args)
static const char * cbrt_docstring
static const char * choose_docstring
double cycle(double index, double loRange, double hiRange)
static const char * cosd_docstring
double boxstep(double x, double a)
static const char * spline_docstring
static const char * hsltorgb_docstring
double expand(double x, double lo, double hi)
static const char * ccellnoise_docstring
static const char * acosd_docstring
double smoothstep(double x, double a, double b)
static const char * dot_docstring
Vec3d cross(const Vec3d &a, const Vec3d &b)
static const char * curve_docstring
static const char * sin_docstring
static const char * ortho_docstring
double remap(double x, double source, double range, double falloff, double interp)
static const char * sqrt_docstring
static const char * sprintf_docstring
static const char * fbm4_docstring
double atand(double x)
Definition: ExprBuiltins.h:56
static const char * log_docstring
double hash(int n, double *args)
double spline(int n, double *params)
static const char * tan_docstring
static const char * angle_docstring
static const char * atan_docstring
static const char * saturate_docstring
double turbulence(int n, const Vec3d *args)
double min(double x, double y)
Definition: ExprBuiltins.h:78
static const char * snoise4_docstring
static const char * pow_docstring
double snoise(const Vec3d &p)
static const char * clamp_docstring
static const char * cfbm_docstring
static const char * swatch_docstring
static const char * norm_docstring
KSeExpr::CCurveFuncX ccurve
@ InvalidFormatString
Invalid format string, only v or f is allowed.
Definition: ErrorCode.h:59
@ WrongNumberOfArgumentsMultiple3Plus1
"Wrong number of arguments, should be multiple of 3 plus 1"
Definition: ErrorCode.h:26
@ FirstArgumentNotString
"First argument must be a string."
Definition: ErrorCode.h:30
@ WrongNumberOfArguments
"Wrong number of arguments, should be 1 to 7"
Definition: ErrorCode.h:24
@ ExpectedFloatOrFloat3
"Expected float or FP[3]"
Definition: ErrorCode.h:20
@ Unknown
Unknown error (message = %1)
Definition: ErrorCode.h:64
@ WrongNumberOfArguments1Plus
"Wrong number of arguments, should be >= 1"
Definition: ErrorCode.h:28
@ UnexpectedEndOfFormatString
Unexpected end of format string.
Definition: ErrorCode.h:57
@ IncompleteFormatSpecifier
"incomplete format specifier"
Definition: ErrorCode.h:32
@ WrongNumberOfArgumentsForFormatString
Wrong number of arguments for format string.
Definition: ErrorCode.h:61
static const char * fabs_docstring
Vec3d vfbm4(int n, const Vec3d *args)
Vec3d hsltorgb(const Vec3d &hsl)
static const char * contrast_docstring
static const char * ccurve_docstring
static const char * tand_docstring
static const char * linearstep_docstring
static const char * cosh_docstring
static const char * length_docstring
Vec3d rotate(int n, const Vec3d *args)
KSeExpr::CachedVoronoiFunc ExprFuncSimple pvoronoi(pvoronoiFn)
Vec3d cfbm4(int n, const Vec3d *args)
static const char * asinh_docstring
KSeExpr::RandFuncX rand
double clamp(double x, double lo, double hi)
Definition: ExprBuiltins.h:66
static Vec3d saturate(const Vec3d &Cin, double amt)
Vec3d vnoise(const Vec3d &p)
static const char * fbm_docstring
static const char * rand_docstring
Vec3d hsi(int n, const Vec3d *args)
static const char * sinh_docstring
double cosd(double x)
Definition: ExprBuiltins.h:36
static const char * vnoise4_docstring
KSeExpr::CachedVoronoiFunc ExprFuncSimple cvoronoi(cvoronoiFn)
void defineBuiltins(ExprFunc::Define, ExprFunc::Define3 define3)
double choose(int n, double *params)
double pick(int n, double *params)
static const char * rgbtohsl_docstring
double rad(double angle)
Definition: ExprBuiltins.h:32
static const char * snoise_docstring
static const char * cnoise_docstring
double swatch(int n, double *params)
static const char * sind_docstring
Vec< double, 3, false > Vec3d
Definition: Vec.h:352
double acosd(double x)
Definition: ExprBuiltins.h:48
static const char * gaussstep_docstring
double compress(double x, double lo, double hi)
Vec3d ortho(const Vec3d &a, const Vec3d &b)
static const char * deg_docstring
static const char * tanh_docstring
static const char * up_docstring
Vec3d midhsi(int n, const Vec3d *args)
double sind(double x)
Definition: ExprBuiltins.h:40
double wchoose(int n, double *params)
double cellnoise(const Vec3d &p)
static const char * exp_docstring
Vec3d ccellnoise(const Vec3d &p)
static const char * getVar_docstring
Vec3d cnoise(const Vec3d &p)
static const char * asin_docstring
static const char * cnoise4_docstring
static const char * bias_docstring
static const char * round_docstring
CurveData(CurveData &&) noexcept=default
~CurveData() override=default
CurveData(const CurveData &)=default
CurveData & operator=(const CurveData &)=default
base class for custom instance data
Definition: ExprNode.h:723
Data(bool cleanup=false)
Definition: ExprNode.h:724
static void f(double *out, double *in)
void(*)(double *, double *) func
Data(func fIn, int dim)
std::vector< std::pair< int, int > > ranges
std::uniform_real_distribution dis
std::array< Vec3d, 27 > points