diff --git a/Source/Ember/Ember.cpp b/Source/Ember/Ember.cpp index 6fb85f6..a902efc 100644 --- a/Source/Ember/Ember.cpp +++ b/Source/Ember/Ember.cpp @@ -18,7 +18,11 @@ template EMBER_API class QTIsaac; #include "Point.h" #include "VarFuncs.h" #include "Variation.h" -#include "Variations01.h" +#ifdef FLAM3_COMPAT + #include "Variations01_flam3_compat.h"//Do this instead if you want full compatibility with flam3. +#else + #include "Variations01.h" +#endif #include "Variations02.h" #include "Variations03.h" #include "Variations04.h" diff --git a/Source/Ember/EmberDefines.h b/Source/Ember/EmberDefines.h index 92d2532..cebebc5 100644 --- a/Source/Ember/EmberDefines.h +++ b/Source/Ember/EmberDefines.h @@ -38,6 +38,7 @@ static void sincos(float x, float* s, float* c) namespace EmberNs { #define EMBER_VERSION "1.0.0.17" +//#define FLAM3_COMPAT 1//Uncomment this if you want full compatibility with flam3 regarding some of the trig-based variations in Variations01.h #define EPS6 T(1e-6) #define EPS std::numeric_limits::epsilon()//Apoplugin.h uses -20, but it's more mathematically correct to do it this way. #define ISAAC_SIZE 4 diff --git a/Source/Ember/VariationList.cpp b/Source/Ember/VariationList.cpp index 37c9835..18dfd34 100644 --- a/Source/Ember/VariationList.cpp +++ b/Source/Ember/VariationList.cpp @@ -1,6 +1,10 @@ #include "EmberPch.h" #include "VariationList.h" -#include "Variations01.h" +#ifdef FLAM3_COMPAT + #include "Variations01_flam3_compat.h"//Do this instead if you want full compatibility with flam3. +#else + #include "Variations01.h" +#endif #include "Variations02.h" #include "Variations03.h" #include "Variations04.h" diff --git a/Source/Ember/Variations01_flam3_compat.h b/Source/Ember/Variations01_flam3_compat.h new file mode 100644 index 0000000..de83ada --- /dev/null +++ b/Source/Ember/Variations01_flam3_compat.h @@ -0,0 +1,7094 @@ +#pragma once + +#include "Variation.h" +#include "Xform.h" + +namespace EmberNs +{ +//template class Xform; + +/// +/// Linear: +/// nx = tx; +/// ny = ty; +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class LinearVariation : public Variation +{ +public: + LinearVariation(T weight = 1.0) : Variation("linear", eVariationId::VAR_LINEAR, weight) { } + + VARCOPY(LinearVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * helper.In.x; + helper.Out.y = m_Weight * helper.In.y; + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * vIn.x;\n" + << "\t\tvOut.y = " << weight << " * vIn.y;\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Sinusoidal: +/// nx = sin(tx); +/// ny = sin(ty); +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class SinusoidalVariation : public Variation +{ +public: + SinusoidalVariation(T weight = 1.0) : Variation("sinusoidal", eVariationId::VAR_SINUSOIDAL, weight) { } + + VARCOPY(SinusoidalVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * std::sin(helper.In.x); + helper.Out.y = m_Weight * std::sin(helper.In.y); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * sin(vIn.x);\n" + << "\t\tvOut.y = " << weight << " * sin(vIn.y);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Spherical: +/// T r2 = tx * tx + ty * ty + 1e-6; +/// nx = tx / r2; +/// ny = ty / r2; +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class SphericalVariation : public Variation +{ +public: + SphericalVariation(T weight = 1.0) : Variation("spherical", eVariationId::VAR_SPHERICAL, weight, true) { } + + VARCOPY(SphericalVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r2 = m_Weight / Zeps(helper.m_PrecalcSumSquares); + helper.Out.x = r2 * helper.In.x; + helper.Out.y = r2 * helper.In.y; + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t r2 = " << weight << " / Zeps(precalcSumSquares);\n" + << "\n" + << "\t\tvOut.x = r2 * vIn.x;\n" + << "\t\tvOut.y = r2 * vIn.y;\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Swirl: +/// double r2 = tx * tx + ty * ty; +/// double c1 = sin(r2); +/// double c2 = cos(r2); +/// nx = c1 * tx - c2 * ty; +/// ny = c2 * tx + c1 * ty; +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class SwirlVariation : public Variation +{ +public: + SwirlVariation(T weight = 1.0) : Variation("swirl", eVariationId::VAR_SWIRL, weight, true) { } + + VARCOPY(SwirlVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T c1, c2; + sincos(helper.m_PrecalcSumSquares, &c1, &c2); + helper.Out.x = m_Weight * (c1 * helper.In.x - c2 * helper.In.y); + helper.Out.y = m_Weight * (c2 * helper.In.x + c1 * helper.In.y); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t c1 = sin(precalcSumSquares);\n" + << "\t\treal_t c2 = cos(precalcSumSquares);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * fma(c1, vIn.x, -(c2 * vIn.y));\n" + << "\t\tvOut.y = " << weight << " * fma(c2, vIn.x, c1 * vIn.y);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// swirl3. +/// By Zy0rg. +/// +template +class Swirl3Variation : public ParametricVariation +{ +public: + Swirl3Variation(T weight = 1.0) : ParametricVariation("swirl3", eVariationId::VAR_SWIRL3, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(Swirl3Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T rad = helper.m_PrecalcSqrtSumSquares; + T ang = helper.m_PrecalcAtanyx + std::log(rad) * m_Shift; + helper.Out.x = m_Weight * rad * std::cos(ang); + helper.Out.y = m_Weight * rad * std::sin(ang); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string shift = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t rad = precalcSqrtSumSquares;\n" + << "\t\treal_t ang = fma(log(rad), " << shift << ", precalcAtanyx);\n" + << "\t\tvOut.x = " << weight << " * rad * cos(ang);\n" + << "\t\tvOut.y = " << weight << " * rad * sin(ang);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Shift, prefix + "swirl3_shift", T(0.5))); + } + +private: + T m_Shift; +}; + +/// +/// swirl3r. +/// By Zy0rg. +/// +template +class Swirl3rVariation : public ParametricVariation +{ +public: + Swirl3rVariation(T weight = 1.0) : ParametricVariation("swirl3r", eVariationId::VAR_SWIRL3R, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(Swirl3rVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T rad = helper.m_PrecalcSqrtSumSquares; + T ang = helper.m_PrecalcAtanyx; + T ang2; + + if (rad < m_Minr) + ang2 = ang + m_Mina; + else if (rad > m_Maxr) + ang2 = ang + m_Maxa; + else + ang2 = ang + std::log(rad) * m_Shift; + + helper.Out.x = m_Weight * rad * std::cos(ang2); + helper.Out.y = m_Weight * rad * std::sin(ang2); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string shift = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string mmin = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string mmax = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string minr = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string maxr = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string mina = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string maxa = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t rad = precalcSqrtSumSquares;\n" + << "\t\treal_t ang2, ang = precalcAtanyx;\n" + << "\n" + << "\t\tif (rad < " << minr << ")\n" + << "\t\t ang2 = ang + " << mina << ";\n" + << "\t\telse if (rad > " << maxr << ")\n" + << "\t\t ang2 = ang + " << maxa << ";\n" + << "\t\telse\n" + << "\t\t ang2 = ang + log(rad) * " << shift << ";\n" + << "\n" + << "\t\tvOut.x = " << weight << " * rad * cos(ang);\n" + << "\t\tvOut.y = " << weight << " * rad * sin(ang);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Minr = std::min(m_Min, m_Max); + m_Maxr = std::max(m_Min, m_Max); + m_Mina = m_Minr > 0 ? std::log(m_Minr) * m_Shift : 0; + m_Maxa = m_Maxr > 0 ? std::log(m_Maxr) * m_Shift : 0; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Shift, prefix + "swirl3r_shift", T(0.5))); + m_Params.push_back(ParamWithName(&m_Min, prefix + "swirl3r_min", T(0.5), eParamType::REAL, 0)); + m_Params.push_back(ParamWithName(&m_Max, prefix + "swirl3r_max", 1, eParamType::REAL, 0)); + m_Params.push_back(ParamWithName(true, &m_Minr, prefix + "swirl3r_minr"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Maxr, prefix + "swirl3r_maxr")); + m_Params.push_back(ParamWithName(true, &m_Mina, prefix + "swirl3r_mina")); + m_Params.push_back(ParamWithName(true, &m_Maxa, prefix + "swirl3r_maxa")); + } + +private: + T m_Shift; + T m_Min; + T m_Max; + T m_Minr;//Precalc. + T m_Maxr; + T m_Mina; + T m_Maxa; +}; + +/// +/// Horseshoe: +/// a = atan2(tx, ty); +/// c1 = sin(a); +/// c2 = cos(a); +/// nx = c1 * tx - c2 * ty; +/// ny = c2 * tx + c1 * ty; +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class HorseshoeVariation : public Variation +{ +public: + HorseshoeVariation(T weight = 1.0) : Variation("horseshoe", eVariationId::VAR_HORSESHOE, weight, true, true) { } + + VARCOPY(HorseshoeVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = m_Weight / Zeps(helper.m_PrecalcSqrtSumSquares); + helper.Out.x = (helper.In.x - helper.In.y) * (helper.In.x + helper.In.y) * r; + helper.Out.y = 2 * helper.In.x * helper.In.y * r; + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t r = " << weight << " / Zeps(precalcSqrtSumSquares);\n" + << "\n" + << "\t\tvOut.x = (vIn.x - vIn.y) * (vIn.x + vIn.y) * r;\n" + << "\t\tvOut.y = (real_t)(2.0) * vIn.x * vIn.y * r;\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Polar: +/// nx = atan2(tx, ty) / M_PI; +/// ny = std::sqrt(tx * tx + ty * ty) - 1.0; +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class PolarVariation : public Variation +{ +public: + PolarVariation(T weight = 1.0) : Variation("polar", eVariationId::VAR_POLAR, weight, true, true, false, true, false) { } + + VARCOPY(PolarVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * (helper.m_PrecalcAtanxy * T(M_1_PI)); + helper.Out.y = m_Weight * (helper.m_PrecalcSqrtSumSquares - 1); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * (precalcAtanxy * M1PI);\n" + << "\t\tvOut.y = " << weight << " * (precalcSqrtSumSquares - (real_t)(1.0));\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Handkerchief: +/// a = atan2(tx, ty); +/// r = std::sqrt(tx * tx + ty * ty); +/// p[0] += weight * sin(a + r) * r; +/// p[1] += weight * cos(a - r) * r; +/// +template +class HandkerchiefVariation : public Variation +{ +public: + HandkerchiefVariation(T weight = 1.0) : Variation("handkerchief", eVariationId::VAR_HANDKERCHIEF, weight, true, true, false, true) { } + + VARCOPY(HandkerchiefVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * helper.m_PrecalcSqrtSumSquares * std::sin(helper.m_PrecalcAtanxy + helper.m_PrecalcSqrtSumSquares); + helper.Out.y = m_Weight * helper.m_PrecalcSqrtSumSquares * std::cos(helper.m_PrecalcAtanxy - helper.m_PrecalcSqrtSumSquares); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * precalcSqrtSumSquares * sin(precalcAtanxy + precalcSqrtSumSquares);\n" + << "\t\tvOut.y = " << weight << " * precalcSqrtSumSquares * cos(precalcAtanxy - precalcSqrtSumSquares);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Heart: +/// a = atan2(tx, ty); +/// r = std::sqrt(tx * tx + ty * ty); +/// a *= r; +/// p[0] += weight * sin(a) * r; +/// p[1] += weight * cos(a) * -r; +/// +template +class HeartVariation : public Variation +{ +public: + HeartVariation(T weight = 1.0) : Variation("heart", eVariationId::VAR_HEART, weight, true, true, false, true) { } + + VARCOPY(HeartVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T a = helper.m_PrecalcSqrtSumSquares * helper.m_PrecalcAtanxy; + T r = m_Weight * helper.m_PrecalcSqrtSumSquares; + helper.Out.x = r * std::sin(a); + helper.Out.y = (-r) * std::cos(a); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t a = precalcSqrtSumSquares * precalcAtanxy;\n" + << "\t\treal_t r = " << weight << " * precalcSqrtSumSquares;\n" + << "\n" + << "\t\tvOut.x = r * sin(a);\n" + << "\t\tvOut.y = (-r) * cos(a);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Disc: +/// nx = tx * M_PI; +/// ny = ty * M_PI; +/// a = atan2(nx, ny); +/// r = std::sqrt(nx * nx + ny * ny); +/// p[0] += weight * sin(r) * a / M_PI; +/// p[1] += weight * cos(r) * a / M_PI; +/// +template +class DiscVariation : public ParametricVariation +{ +public: + DiscVariation(T weight = 1.0) : ParametricVariation("disc", eVariationId::VAR_DISC, weight, true, true, false, true) + { + Init(); + } + + PARVARCOPY(DiscVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T val = T(M_PI) * helper.m_PrecalcSqrtSumSquares; + T r = m_WeightByPI * helper.m_PrecalcAtanxy; + helper.Out.x = std::sin(val) * r; + helper.Out.y = std::cos(val) * r; + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string weightByPI = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Precalcs only, no params. + ss << "\t{\n" + << "\t\treal_t val = MPI * precalcSqrtSumSquares;\n" + << "\t\treal_t r = " << weightByPI << " * precalcAtanxy;\n" + << "\n" + << "\t\tvOut.x = sin(val) * r;\n" + << "\t\tvOut.y = cos(val) * r;\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_WeightByPI = m_Weight * T(M_1_PI); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(true, &m_WeightByPI, prefix + "disc_weight_by_pi"));//Precalcs only, no params. + } + +private: + T m_WeightByPI;//Precalcs only, no params. +}; + +/// +/// Spiral: +/// a = atan2(tx, ty); +/// r = std::sqrt(tx * tx + ty * ty) + 1e-6; +/// p[0] += weight * (cos(a) + sin(r)) / r; +/// p[1] += weight * (sin(a) - cos(r)) / r; +/// +template +class SpiralVariation : public Variation +{ +public: + SpiralVariation(T weight = 1.0) : Variation("spiral", eVariationId::VAR_SPIRAL, weight, true, true, true) { } + + VARCOPY(SpiralVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = Zeps(helper.m_PrecalcSqrtSumSquares); + T r1 = m_Weight / r; + helper.Out.x = r1 * (helper.m_PrecalcCosa + std::sin(r)); + helper.Out.y = r1 * (helper.m_PrecalcSina - std::cos(r)); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t r = Zeps(precalcSqrtSumSquares);\n" + << "\t\treal_t r1 = " << weight << " / r;\n" + << "\n" + << "\t\tvOut.x = r1 * (precalcCosa + sin(r));\n" + << "\t\tvOut.y = r1 * (precalcSina - cos(r));\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Hyperbolic: +/// a = atan2(tx, ty); +/// r = std::sqrt(tx * tx + ty * ty) + 1e-6; +/// p[0] += weight * sin(a) / r; +/// p[1] += weight * cos(a) * r; +/// +template +class HyperbolicVariation : public Variation +{ +public: + HyperbolicVariation(T weight = 1.0) : Variation("hyperbolic", eVariationId::VAR_HYPERBOLIC, weight, true, true, true) { } + + VARCOPY(HyperbolicVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = Zeps(helper.m_PrecalcSqrtSumSquares); + helper.Out.x = m_Weight * helper.m_PrecalcSina / r; + helper.Out.y = m_Weight * helper.m_PrecalcCosa * r; + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t r = Zeps(precalcSqrtSumSquares);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * precalcSina / r;\n" + << "\t\tvOut.y = " << weight << " * precalcCosa * r;\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Diamond: +/// a = atan2(tx, ty); +/// r = std::sqrt(tx * tx + ty * ty); +/// p[0] += weight * sin(a) * cos(r); +/// p[1] += weight * cos(a) * sin(r); +/// +template +class DiamondVariation : public Variation +{ +public: + DiamondVariation(T weight = 1.0) : Variation("diamond", eVariationId::VAR_DIAMOND, weight, true, true, true) { } + + VARCOPY(DiamondVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * helper.m_PrecalcSina * std::cos(helper.m_PrecalcSqrtSumSquares); + helper.Out.y = m_Weight * helper.m_PrecalcCosa * std::sin(helper.m_PrecalcSqrtSumSquares); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * precalcSina * cos(precalcSqrtSumSquares);\n" + << "\t\tvOut.y = " << weight << " * precalcCosa * sin(precalcSqrtSumSquares);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Ex: +/// a = atan2(tx, ty); +/// r = std::sqrt(tx * tx + ty * ty); +/// n0 = sin(a + r); +/// n1 = cos(a - r); +/// m0 = n0 * n0 * n0 * r; +/// m1 = n1 * n1 * n1 * r; +/// p[0] += weight * (m0 + m1); +/// p[1] += weight * (m0 - m1); +/// +template +class ExVariation : public Variation +{ +public: + ExVariation(T weight = 1.0) : Variation("ex", eVariationId::VAR_EX, weight, true, true, false, true) { } + + VARCOPY(ExVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T a = helper.m_PrecalcAtanxy; + T r = helper.m_PrecalcSqrtSumSquares; + T n0 = std::sin(a + r); + T n1 = std::cos(a - r); + T m0 = n0 * n0 * n0 * r; + T m1 = n1 * n1 * n1 * r; + helper.Out.x = m_Weight * (m0 + m1); + helper.Out.y = m_Weight * (m0 - m1); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t a = precalcAtanxy;\n" + << "\t\treal_t r = precalcSqrtSumSquares;\n" + << "\t\treal_t n0 = sin(a + r);\n" + << "\t\treal_t n1 = cos(a - r);\n" + << "\t\treal_t m0 = n0 * n0 * n0 * r;\n" + << "\t\treal_t m1 = n1 * n1 * n1 * r;\n" + << "\n" + << "\t\tvOut.x = " << weight << " * (m0 + m1);\n" + << "\t\tvOut.y = " << weight << " * (m0 - m1);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Julia: +/// a = atan2(tx, ty)/2.0; +/// if (random bit()) a += M_PI; +/// r = pow(tx*tx + ty*ty, 0.25); +/// nx = r * cos(a); +/// ny = r * sin(a); +/// p[0] += v * nx; +/// p[1] += v * ny; +/// +template +class JuliaVariation : public Variation +{ +public: + JuliaVariation(T weight = 1.0) : Variation("julia", eVariationId::VAR_JULIA, weight, true, true, false, true) { } + + VARCOPY(JuliaVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = m_Weight * std::sqrt(helper.m_PrecalcSqrtSumSquares); + T a = T(0.5) * helper.m_PrecalcAtanxy; + + if (rand.RandBit()) + a += T(M_PI); + + helper.Out.x = r * std::cos(a); + helper.Out.y = r * std::sin(a); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t r = " << weight << " * sqrt(precalcSqrtSumSquares);\n" + << "\t\treal_t a = (real_t)(0.5) * precalcAtanxy;\n" + << "\n" + << "\t\tif (MwcNext(mwc) & 1)\n" + << "\t\t a += MPI;\n" + << "\n" + << "\t\tvOut.x = r * cos(a);\n" + << "\t\tvOut.y = r * sin(a);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Bent: +/// nx = tx; +/// ny = ty; +/// if (nx < 0.0) nx = nx * 2.0; +/// if (ny < 0.0) ny = ny / 2.0; +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class BentVariation : public Variation +{ +public: + BentVariation(T weight = 1.0) : Variation("bent", eVariationId::VAR_BENT, weight) { } + + VARCOPY(BentVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T nx = helper.In.x < T(0.0) ? helper.In.x * 2 : helper.In.x; + T ny = helper.In.y < T(0.0) ? helper.In.y / 2 : helper.In.y; + helper.Out.x = m_Weight * nx; + helper.Out.y = m_Weight * ny; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t nx = vIn.x < (real_t)(0.0) ? (vIn.x * (real_t)(2.0)) : vIn.x;\n" + << "\t\treal_t ny = vIn.y < (real_t)(0.0) ? (vIn.y / (real_t)(2.0)) : vIn.y;\n" + << "\n" + << "\t\tvOut.x = " << weight << " * nx;\n" + << "\t\tvOut.y = " << weight << " * ny;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Waves: +/// dx = coef[2][0]; +/// dy = coef[2][1]; +/// nx = tx + coef[1][0] * sin(ty / ((dx * dx) + EPS)); +/// ny = ty + coef[1][1] * sin(tx / ((dy * dy) + EPS)); +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// Special case here, use parametric for precalcs, but no regular params. +/// +template +class WavesVariation : public ParametricVariation +{ +public: + WavesVariation(T weight = 1.0) : ParametricVariation("waves", eVariationId::VAR_WAVES, weight) + { + Init(); + } + + PARVARCOPY(WavesVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T c10 = m_Xform->m_Affine.B(); + T c11 = m_Xform->m_Affine.E(); + T nx = helper.In.x + c10 * std::sin(helper.In.y * m_Dx2); + T ny = helper.In.y + c11 * std::sin(helper.In.x * m_Dy2); + helper.Out.x = m_Weight * nx; + helper.Out.y = m_Weight * ny; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string dx2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Precalcs only, no params. + string dy2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t c10 = xform->m_B;\n" + << "\t\treal_t c11 = xform->m_E;\n" + << "\t\treal_t nx = fma(c10, sin(vIn.y * " << dx2 << "), vIn.x);\n" + << "\t\treal_t ny = fma(c11, sin(vIn.x * " << dy2 << "), vIn.y);\n" + << "\n" + << "\t\tvOut.x = (" << weight << " * nx);\n" + << "\t\tvOut.y = (" << weight << " * ny);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + if (m_Xform)//If this variation exists by itself and hasn't been added to an xform yet, m_Xform will be nullptr. + { + T dx = m_Xform->m_Affine.C(); + T dy = m_Xform->m_Affine.F(); + m_Dx2 = 1 / Zeps(dx * dx); + m_Dy2 = 1 / Zeps(dy * dy); + } + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(true, &m_Dx2, prefix + "waves_dx2"));//Precalcs only, no params. + m_Params.push_back(ParamWithName(true, &m_Dy2, prefix + "waves_dy2")); + } + +private: + T m_Dx2;//Precalcs only, no params. + T m_Dy2; +}; + +/// +/// Fisheye: +/// a = atan2(tx, ty); +/// r = std::sqrt(tx * tx + ty * ty); +/// r = 2 * r / (r + 1); +/// nx = r * cos(a); +/// ny = r * sin(a); +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class FisheyeVariation : public Variation +{ +public: + FisheyeVariation(T weight = 1.0) : Variation("fisheye", eVariationId::VAR_FISHEYE, weight, true, true) { } + + VARCOPY(FisheyeVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = 2 * m_Weight / (helper.m_PrecalcSqrtSumSquares + 1); + helper.Out.x = r * helper.In.y; + helper.Out.y = r * helper.In.x; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t r = 2 * " << weight << " / (precalcSqrtSumSquares + 1);\n" + << "\n" + << "\t\tvOut.x = r * vIn.y;\n" + << "\t\tvOut.y = r * vIn.x;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Popcorn: +/// dx = tan(3 * ty); +/// dy = tan(3 * tx); +/// nx = tx + coef[2][0] * sin(dx); +/// ny = ty + coef[2][1] * sin(dy); +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class PopcornVariation : public Variation +{ +public: + PopcornVariation(T weight = 1.0) : Variation("popcorn", eVariationId::VAR_POPCORN, weight) { } + + VARCOPY(PopcornVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T dx = SafeTan(3 * helper.In.y); + T dy = SafeTan(3 * helper.In.x); + T nx = helper.In.x + m_Xform->m_Affine.C() * std::sin(dx); + T ny = helper.In.y + m_Xform->m_Affine.F() * std::sin(dy); + helper.Out.x = m_Weight * nx; + helper.Out.y = m_Weight * ny; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t dx = tan(3 * vIn.y);\n" + << "\t\treal_t dy = tan(3 * vIn.x);\n" + << "\t\treal_t nx = fma(xform->m_C, sin(dx), vIn.x);\n" + << "\t\treal_t ny = fma(xform->m_F, sin(dy), vIn.y);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * nx;\n" + << "\t\tvOut.y = " << weight << " * ny;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Exponential: +/// dx = exp(tx - 1.0); +/// dy = M_PI * ty; +/// nx = cos(dy) * dx; +/// ny = sin(dy) * dx; +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class ExponentialVariation : public Variation +{ +public: + ExponentialVariation(T weight = 1.0) : Variation("exponential", eVariationId::VAR_EXPONENTIAL, weight) { } + + VARCOPY(ExponentialVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T dx = m_Weight * std::exp(helper.In.x - 1); + T dy = T(M_PI) * helper.In.y; + helper.Out.x = dx * std::cos(dy); + helper.Out.y = dx * std::sin(dy); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t dx = " << weight << " * exp(vIn.x - (real_t)(1.0));\n" + << "\t\treal_t dy = MPI * vIn.y;\n" + << "\n" + << "\t\tvOut.x = dx * cos(dy);\n" + << "\t\tvOut.y = dx * sin(dy);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Power: +/// a = atan2(tx, ty); +/// sa = sin(a); +/// r = std::sqrt(tx * tx + ty * ty); +/// r = pow(r, sa); +/// nx = r * precalc_cosa; +/// ny = r * sa; +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class PowerVariation : public Variation +{ +public: + PowerVariation(T weight = 1.0) : Variation("power", eVariationId::VAR_POWER, weight, true, true, true) { } + + VARCOPY(PowerVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = m_Weight * std::pow(helper.m_PrecalcSqrtSumSquares, helper.m_PrecalcSina); + helper.Out.x = r * helper.m_PrecalcCosa; + helper.Out.y = r * helper.m_PrecalcSina; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t r = " << weight << " * pow(precalcSqrtSumSquares, precalcSina);\n" + << "\n" + << "\t\tvOut.x = r * precalcCosa;\n" + << "\t\tvOut.y = r * precalcSina;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Cosine: +/// nx = cos(tx * M_PI) * cosh(ty); +/// ny = -sin(tx * M_PI) * sinh(ty); +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class CosineVariation : public Variation +{ +public: + CosineVariation(T weight = 1.0) : Variation("cosine", eVariationId::VAR_COSINE, weight) { } + + VARCOPY(CosineVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T a = helper.In.x * T(M_PI); + T nx = std::cos(a) * std::cosh(helper.In.y); + T ny = -std::sin(a) * std::sinh(helper.In.y); + helper.Out.x = m_Weight * nx; + helper.Out.y = m_Weight * ny; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t a = vIn.x * MPI;\n" + << "\t\treal_t nx = cos(a) * cosh(vIn.y);\n" + << "\t\treal_t ny = -sin(a) * sinh(vIn.y);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * nx;\n" + << "\t\tvOut.y = " << weight << " * ny;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Rings: +/// dx = coef[2][0]; +/// dx = dx * dx + EPS; +/// r = std::sqrt(tx * tx + ty * ty); +/// r = fmod(r + dx, 2 * dx) - dx + r * (1 - dx); +/// a = atan2(tx, ty); +/// nx = cos(a) * r; +/// ny = sin(a) * r; +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class RingsVariation : public Variation +{ +public: + RingsVariation(T weight = 1.0) : Variation("rings", eVariationId::VAR_RINGS, weight, true, true, true) { } + + VARCOPY(RingsVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T dx = Zeps(m_Xform->m_Affine.C() * m_Xform->m_Affine.C()); + T r = helper.m_PrecalcSqrtSumSquares; + r = m_Weight * (fmod(r + dx, 2 * dx) - dx + r * (1 - dx)); + helper.Out.x = r * helper.m_PrecalcCosa; + helper.Out.y = r * helper.m_PrecalcSina; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t dx = Zeps(xform->m_C * xform->m_C);\n" + << "\t\treal_t r = precalcSqrtSumSquares;\n" + << "\n" + << "\t\tr = " << weight << " * (fmod(r + dx, 2 * dx) + fma(r, ((real_t)(1.0) - dx), -dx));\n" + << "\t\tvOut.x = r * precalcCosa;\n" + << "\t\tvOut.y = r * precalcSina;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Fan: +/// dx = coef[2][0]; +/// dy = coef[2][1]; +/// dx = M_PI * (dx * dx + EPS); +/// dx2 = dx / 2; +/// a = atan(tx, ty); +/// r = std::sqrt(tx * tx + ty * ty); +/// a += (fmod(a + dy, dx) > dx2) ? -dx2 : dx2; +/// nx = cos(a) * r; +/// ny = sin(a) * r; +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class FanVariation : public Variation +{ +public: + FanVariation(T weight = 1.0) : Variation("fan", eVariationId::VAR_FAN, weight, true, true, false, true) { } + + VARCOPY(FanVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T dx = T(M_PI) * Zeps(m_Xform->m_Affine.C() * m_Xform->m_Affine.C()); + T dy = m_Xform->m_Affine.F(); + T dx2 = T(0.5) * dx; + T a = helper.m_PrecalcAtanxy; + T r = m_Weight * helper.m_PrecalcSqrtSumSquares; + a += (fmod(a + dy, dx) > dx2) ? -dx2 : dx2; + helper.Out.x = r * std::cos(a); + helper.Out.y = r * std::sin(a); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t dx = MPI * Zeps(xform->m_C * xform->m_C);\n" + << "\t\treal_t dy = xform->m_F;\n" + << "\t\treal_t dx2 = (real_t)(0.5) * dx;\n" + << "\t\treal_t a = precalcAtanxy + ((fmod(precalcAtanxy + dy, dx) > dx2) ? -dx2 : dx2);\n" + << "\t\treal_t r = " << weight << " * precalcSqrtSumSquares;\n" + << "\n" + << "\t\tvOut.x = r * cos(a);\n" + << "\t\tvOut.y = r * sin(a);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Blob: +/// a = atan2(tx, ty); +/// r = std::sqrt(tx * tx + ty * ty); +/// r = r * (bloblow + (blobhigh - bloblow) * (0.5 + 0.5 * sin(blobwaves * a))); +/// nx = sin(a) * r; +/// ny = cos(a) * r; +/// +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class BlobVariation : public ParametricVariation +{ +public: + BlobVariation(T weight = 1.0) : ParametricVariation("blob", eVariationId::VAR_BLOB, weight, true, true, true, true) + { + Init(); + } + + PARVARCOPY(BlobVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = helper.m_PrecalcSqrtSumSquares * (m_BlobLow + m_BlobDiff * (T(0.5) + T(0.5) * std::sin(m_BlobWaves * helper.m_PrecalcAtanxy))); + helper.Out.x = m_Weight * helper.m_PrecalcSina * r; + helper.Out.y = m_Weight * helper.m_PrecalcCosa * r; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string blobLow = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blobHigh = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blobWaves = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blobDiff = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t r = precalcSqrtSumSquares * fma(" << blobDiff << ", fma((real_t)(0.5), sin(" << blobWaves << " * precalcAtanxy), (real_t)(0.5)), " << blobLow << ");\n" + << "\n" + << "\t\tvOut.x = " << weight << " * precalcSina * r;\n" + << "\t\tvOut.y = " << weight << " * precalcCosa * r;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_BlobDiff = m_BlobHigh - m_BlobLow; + } + + virtual void Random(QTIsaac& rand) override + { + m_BlobLow = T(0.2) + T(0.5) * rand.Frand01(); + m_BlobHigh = T(0.8) + T(0.4) * rand.Frand01(); + m_BlobWaves = T(int(2 + 5 * rand.Frand01())); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_BlobLow, prefix + "blob_low")); + m_Params.push_back(ParamWithName(&m_BlobHigh, prefix + "blob_high", 1)); + m_Params.push_back(ParamWithName(&m_BlobWaves, prefix + "blob_waves", 1)); + m_Params.push_back(ParamWithName(true, &m_BlobDiff, prefix + "blob_diff"));//Precalc. + } + +private: + T m_BlobLow; + T m_BlobHigh; + T m_BlobWaves; + T m_BlobDiff;//Precalc. +}; + +/// +/// Pdj: +/// nx1 = cos(pdjb * tx); +/// nx2 = sin(pdjc * tx); +/// ny1 = sin(pdja * ty); +/// ny2 = cos(pdjd * ty); +/// +/// p[0] += weight * (ny1 - nx1); +/// p[1] += weight * (nx2 - ny2); +/// +template +class PdjVariation : public ParametricVariation +{ +public: + PdjVariation(T weight = 1.0) : ParametricVariation("pdj", eVariationId::VAR_PDJ, weight) + { + Init(); + } + + PARVARCOPY(PdjVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T nx1 = std::cos(m_PdjB * helper.In.x); + T nx2 = std::sin(m_PdjC * helper.In.x); + T ny1 = std::sin(m_PdjA * helper.In.y); + T ny2 = std::cos(m_PdjD * helper.In.y); + helper.Out.x = m_Weight * (ny1 - nx1); + helper.Out.y = m_Weight * (nx2 - ny2); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string pdjA = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string pdjB = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string pdjC = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string pdjD = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t nx1 = cos(" << pdjB << " * vIn.x)" << ";\n" + << "\t\treal_t nx2 = sin(" << pdjC << " * vIn.x)" << ";\n" + << "\t\treal_t ny1 = sin(" << pdjA << " * vIn.y)" << ";\n" + << "\t\treal_t ny2 = cos(" << pdjD << " * vIn.y)" << ";\n" + << "\n" + << "\t\tvOut.x = (" << weight << " * (ny1 - nx1));\n" + << "\t\tvOut.y = (" << weight << " * (nx2 - ny2));\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Random(QTIsaac& rand) override + { + m_PdjA = 3 * rand.Frand11(); + m_PdjB = 3 * rand.Frand11(); + m_PdjC = 3 * rand.Frand11(); + m_PdjD = 3 * rand.Frand11(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_PdjA, prefix + "pdj_a")); + m_Params.push_back(ParamWithName(&m_PdjB, prefix + "pdj_b")); + m_Params.push_back(ParamWithName(&m_PdjC, prefix + "pdj_c")); + m_Params.push_back(ParamWithName(&m_PdjD, prefix + "pdj_d")); + } + +private: + T m_PdjA; + T m_PdjB; + T m_PdjC; + T m_PdjD; +}; + +/// +/// Fan2: +/// a = precalc_atan; +/// r = precalc_sqrt; +/// +/// dy = fan2y; +/// dx = M_PI * (fan2x * fan2x + EPS); +/// dx2 = dx / 2.0; +/// +/// t = a + dy - dx * (int)((a + dy) / dx); +/// +/// if (t > dx2) +/// a = a - dx2; +/// else +/// a = a + dx2; +/// +/// nx = sin(a) * r; +/// ny = cos(a) * r; +/// +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class Fan2Variation : public ParametricVariation +{ +public: + Fan2Variation(T weight = 1.0) : ParametricVariation("fan2", eVariationId::VAR_FAN2, weight, true, true, false, true) + { + Init(); + } + + PARVARCOPY(Fan2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T a = helper.m_PrecalcAtanxy; + T r = m_Weight * helper.m_PrecalcSqrtSumSquares; + T t = a + m_Fan2Y - m_Fan2Dx * int((a + m_Fan2Y) / m_Fan2Dx); + + if (t > m_Fan2Dx2) + a = a - m_Fan2Dx2; + else + a = a + m_Fan2Dx2; + + helper.Out.x = r * std::sin(a); + helper.Out.y = r * std::cos(a); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string fan2X = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string fan2Y = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string dx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string dx2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t a = precalcAtanxy;\n" + << "\t\treal_t r = " << weight << " * precalcSqrtSumSquares;\n" + << "\t\treal_t t = a + " << fan2Y << " - " << dx << " * (int)((a + " << fan2Y << ") / " << dx << ");\n" + << "\n" + << "\t\tif (t > " << dx2 << ")\n" + << "\t\t a = a - " << dx2 << ";\n" + << "\t\telse\n" + << "\t\t a = a + " << dx2 << ";\n" + << "\n" + << "\t\tvOut.x = r * sin(a);\n" + << "\t\tvOut.y = r * cos(a);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Fan2Dx = T(M_PI) * Zeps(SQR(m_Fan2X)); + m_Fan2Dx2 = T(0.5) * m_Fan2Dx; + } + + virtual void Random(QTIsaac& rand) override + { + m_Fan2X = rand.Frand11(); + m_Fan2Y = rand.Frand11(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Fan2X, prefix + "fan2_x")); + m_Params.push_back(ParamWithName(&m_Fan2Y, prefix + "fan2_y")); + m_Params.push_back(ParamWithName(true, &m_Fan2Dx, prefix + "fan2_dx"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Fan2Dx2, prefix + "fan2_dx2")); + } + +private: + T m_Fan2X; + T m_Fan2Y; + T m_Fan2Dx;//Precalc. + T m_Fan2Dx2; +}; + +/// +/// Rings2: +/// r = precalc_sqrt; +/// dx = rings2val * rings2val + EPS; +/// r += dx - 2.0 * dx * (int)((r + dx)/(2.0 * dx)) - dx + r * (1.0 - dx); +/// nx = precalc_sina * r; +/// ny = precalc_cosa * r; +/// p[0] += weight * nx; +/// p[1] += weight * ny; +/// +template +class Rings2Variation : public ParametricVariation +{ +public: + Rings2Variation(T weight = 1.0) : ParametricVariation("rings2", eVariationId::VAR_RINGS2, weight, true, true, true) + { + Init(); + } + + PARVARCOPY(Rings2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = helper.m_PrecalcSqrtSumSquares; + r += -2 * m_Rings2Val2 * int((r + m_Rings2Val2) / (2 * m_Rings2Val2)) + r * (1 - m_Rings2Val2); + helper.Out.x = m_Weight * helper.m_PrecalcSina * r; + helper.Out.y = m_Weight * helper.m_PrecalcCosa * r; + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string rings2Val = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string rings2Val2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t r = precalcSqrtSumSquares;\n" + << "\n" + << "\t\tr += fma((real_t)(-2.0) * " << rings2Val2 << ", (real_t)(int)((r + " << rings2Val2 << ") / ((real_t)(2.0) * " << rings2Val2 << ")), r * ((real_t)(1.0) - " << rings2Val2 << "));\n" + //<< "\t\tr += -(real_t)(2.0) * " << rings2Val2 << " * (int)((r + " << rings2Val2 << ") / ((real_t)(2.0) * " << rings2Val2 << ")) + r * ((real_t)(1.0) - " << rings2Val2 << ");\n" + << "\t\tvOut.x = (" << weight << " * precalcSina * r);\n" + << "\t\tvOut.y = (" << weight << " * precalcCosa * r);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Rings2Val2 = Zeps(SQR(m_Rings2Val)); + } + + virtual void Random(QTIsaac& rand) override + { + m_Rings2Val = 2 * rand.Frand01(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Rings2Val, prefix + "rings2_val", 1));//This differs from the original which used zero. Use 1 instead to avoid getting too close to dividing by zero. + m_Params.push_back(ParamWithName(true, &m_Rings2Val2, prefix + "rings2_val2"));//Precalc. + } + +private: + T m_Rings2Val; + T m_Rings2Val2;//Precalc. +}; + +/// +/// Eyefish: +/// r = 2.0 * weight / (precalc_sqrt + 1.0); +/// p[0] += r * tx; +/// p[1] += r * ty; +/// +template +class EyefishVariation : public Variation +{ +public: + EyefishVariation(T weight = 1.0) : Variation("eyefish", eVariationId::VAR_EYEFISH, weight, true, true) { } + + VARCOPY(EyefishVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = 2 * m_Weight / (helper.m_PrecalcSqrtSumSquares + 1); + helper.Out.x = r * helper.In.x; + helper.Out.y = r * helper.In.y; + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t r = (" << weight << " * (real_t)(2.0)) / (precalcSqrtSumSquares + (real_t)(1.0));\n" + << "\n" + << "\t\tvOut.x = r * vIn.x;\n" + << "\t\tvOut.y = r * vIn.y;\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Bubble. +/// +template +class BubbleVariation : public Variation +{ +public: + BubbleVariation(T weight = 1.0) : Variation("bubble", eVariationId::VAR_BUBBLE, weight, true) { } + + VARCOPY(BubbleVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T denom = T(0.25) * helper.m_PrecalcSumSquares + 1; + T r = m_Weight / denom; + helper.Out.x = r * helper.In.x; + helper.Out.y = r * helper.In.y; + helper.Out.z = m_Weight * (2 / Zeps(denom - 1)); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t denom = fma((real_t)(0.25), precalcSumSquares, (real_t)(1.0));\n" + << "\t\treal_t r = " << weight << " / denom;\n" + << "\n" + << "\t\tvOut.x = r * vIn.x;\n" + << "\t\tvOut.y = r * vIn.y;\n" + << "\t\tvOut.z = " << weight << " * (2 / Zeps(denom - 1));\n" + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Cylinder. +/// +template +class CylinderVariation : public Variation +{ +public: + CylinderVariation(T weight = 1.0) : Variation("cylinder", eVariationId::VAR_CYLINDER, weight) { } + + VARCOPY(CylinderVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * std::sin(helper.In.x); + helper.Out.y = m_Weight * helper.In.y; + helper.Out.z = m_Weight * std::cos(helper.In.x); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * sin(vIn.x);\n" + << "\t\tvOut.y = " << weight << " * vIn.y;\n" + << "\t\tvOut.z = " << weight << " * cos(vIn.x);\n" + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Perspective. +/// +template +class PerspectiveVariation : public ParametricVariation +{ +public: + PerspectiveVariation(T weight = 1.0) : ParametricVariation("perspective", eVariationId::VAR_PERSPECTIVE, weight) + { + Init(); + } + + PARVARCOPY(PerspectiveVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T d = Zeps(m_Dist - helper.In.y * m_Vsin); + T t = 1 / d; + helper.Out.x = m_Weight * m_Dist * helper.In.x * t; + helper.Out.y = m_Weight * m_VfCos * helper.In.y * t; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string angle = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Params. + string dist = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string vSin = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Precalc. + string vfCos = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t d = Zeps(" << dist << " - vIn.y * " << vSin << ");\n" + << "\t\treal_t t = (real_t)(1.0) / d;\n" + << "\n" + << "\t\tvOut.x = (" << weight << " * " << dist << " * vIn.x * t);\n" + << "\t\tvOut.y = (" << weight << " * " << vfCos << " * vIn.y * t);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + + virtual void Precalc() override + { + T angle = m_Angle * T(M_PI) / 2; + m_Vsin = std::sin(angle); + m_VfCos = m_Dist * std::cos(angle); + } + + virtual void Random(QTIsaac& rand) override + { + m_Angle = rand.Frand01(); + m_Dist = 2 * rand.Frand01() + 1; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Angle, prefix + "perspective_angle"));//Params. + m_Params.push_back(ParamWithName(&m_Dist, prefix + "perspective_dist")); + m_Params.push_back(ParamWithName(true, &m_Vsin, prefix + "perspective_vsin"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_VfCos, prefix + "perspective_vfcos")); + } + +private: + T m_Angle;//Params. + T m_Dist; + T m_Vsin;//Precalc. + T m_VfCos; +}; + +/// +/// Noise. +/// +template +class NoiseVariation : public Variation +{ +public: + NoiseVariation(T weight = 1.0) : Variation("noise", eVariationId::VAR_NOISE, weight) { } + + VARCOPY(NoiseVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T tempr = rand.Frand01() * M_2PI; + T r = m_Weight * rand.Frand01(); + helper.Out.x = helper.In.x * r * std::cos(tempr); + helper.Out.y = helper.In.y * r * std::sin(tempr); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t tempr = MwcNext01(mwc) * M_2PI;\n" + << "\t\treal_t r = " << weight << " * MwcNext01(mwc);\n" + << "\n" + << "\t\tvOut.x = vIn.x * r * cos(tempr);\n" + << "\t\tvOut.y = vIn.y * r * sin(tempr);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// JuliaN. +/// +template +class JuliaNGenericVariation : public ParametricVariation +{ +public: + JuliaNGenericVariation(T weight = 1.0) : ParametricVariation("julian", eVariationId::VAR_JULIAN, weight, true, false, false, false, true) + { + Init(); + } + + PARVARCOPY(JuliaNGenericVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T tempr = (helper.m_PrecalcAtanyx + M_2PI * rand.Rand(ISAAC_INT(m_Rn))) / m_Power; + T r = m_Weight * std::pow(helper.m_PrecalcSumSquares, m_Cn); + helper.Out.x = r * std::cos(tempr); + helper.Out.y = r * std::sin(tempr); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string dist = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Params. + string power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string rn = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Precalc. + string cn = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tint tRnd = (int)(" << rn << " * MwcNext01(mwc));\n" + << "\t\treal_t tempr = fma(M_2PI, (real_t)tRnd, precalcAtanyx) / " << power << ";\n" + << "\t\treal_t r = " << weight << " * pow(precalcSumSquares, " << cn << ");\n" + << "\n" + << "\t\tvOut.x = r * cos(tempr);\n" + << "\t\tvOut.y = r * sin(tempr);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Power = Zeps(m_Power); + m_Rn = std::abs(m_Power); + m_Cn = m_Dist / m_Power / 2; + } + + virtual void Random(QTIsaac& rand) override + { + m_Dist = 1; + m_Power = T(int(5 * rand.Frand01() + 2)); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Dist, prefix + "julian_dist", 1));//Params. + m_Params.push_back(ParamWithName(&m_Power, prefix + "julian_power", 1, eParamType::INTEGER_NONZERO)); + m_Params.push_back(ParamWithName(true, &m_Rn, prefix + "julian_rn"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Cn, prefix + "julian_cn")); + } + +private: + T m_Dist;//Params. + T m_Power; + T m_Rn;//Precalc. + T m_Cn; +}; + +/// +/// JuliaScope. +/// +template +class JuliaScopeVariation : public ParametricVariation +{ +public: + JuliaScopeVariation(T weight = 1.0) : ParametricVariation("juliascope", eVariationId::VAR_JULIASCOPE, weight, true, false, false, false, true) + { + Init(); + } + + PARVARCOPY(JuliaScopeVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + int rnd = int(m_Rn * rand.Frand01()); + T tempr, r = m_Weight * std::pow(helper.m_PrecalcSumSquares, m_Cn); + + if ((rnd & 1) == 0) + tempr = (M_2PI * rnd + helper.m_PrecalcAtanyx) / m_Power; + else + tempr = (M_2PI * rnd - helper.m_PrecalcAtanyx) / m_Power; + + helper.Out.x = r * std::cos(tempr); + helper.Out.y = r * std::sin(tempr); + helper.Out.z = m_Weight * helper.In.z; + //int rnd = (int)(m_Rn * rand.Frand01()); + //T tempr, r; + //if ((rnd & 1) == 0) + // tempr = (2 * T(M_PI) * (int)(m_Rn * rand.Frand01()) + helper.m_PrecalcAtanyx) / m_Power;//Fixed to get new random rather than use rnd from above.//SMOULDER + //else + // tempr = (2 * T(M_PI) * (int)(m_Rn * rand.Frand01()) - helper.m_PrecalcAtanyx) / m_Power; + //r = m_Weight * pow(helper.m_PrecalcSumSquares, m_Cn); + //helper.Out.x = r * cos(tempr); + //helper.Out.y = r * sin(tempr); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string dist = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Params. + string power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string rn = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Precalc. + string cn = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tint rnd = (int)(" << rn << " * MwcNext01(mwc));\n" + << "\t\treal_t tempr, r;\n" + << "\n" + << "\t\tif ((rnd & 1) == 0)\n" + << "\t\t tempr = fma(M_2PI, (real_t)rnd, precalcAtanyx) / " << power << ";\n" + << "\t\telse\n" + << "\t\t tempr = fma(M_2PI, (real_t)rnd, -precalcAtanyx) / " << power << ";\n" + << "\n" + << "\t\tr = " << weight << " * pow(precalcSumSquares, " << cn << ");\n" + << "\n" + << "\t\tvOut.x = r * cos(tempr);\n" + << "\t\tvOut.y = r * sin(tempr);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + //ss << "\t{\n" + // << "\t\tint rnd = (int)(" << rn << " * MwcNext01(mwc));\n" + // << "\t\treal_t tempr, r;\n" + // << "\n" + // << "\t\tif ((rnd & 1) == 0)\n" + // << "\t\t tempr = (2 * M_PI * (int)(" << rn << " * MwcNext01(mwc)) + precalcAtanyx) / " << power << ";\n"//Fixed to get new random rather than use rnd from above.//SMOULDER + // << "\t\telse\n" + // << "\t\t tempr = (2 * M_PI * (int)(" << rn << " * MwcNext01(mwc)) - precalcAtanyx) / " << power << ";\n" + // << "\n" + // << "\t\tr = " << weight << " * pow(precalcSumSquares, " << cn << ");\n" + // << "\n" + // << "\t\tvOut.x = r * cos(tempr);\n" + // << "\t\tvOut.y = r * sin(tempr);\n" + // << "\t\tvOut.z = " << weight << " * vIn.z;\n" + // << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Rn = std::abs(m_Power); + m_Cn = m_Dist / m_Power / 2; + } + + virtual void Random(QTIsaac& rand) override + { + m_Dist = 1; + m_Power = T(int(5 * rand.Frand01() + 2)); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Dist, prefix + "juliascope_dist", 1));//Params. + m_Params.push_back(ParamWithName(&m_Power, prefix + "juliascope_power", 1, eParamType::REAL_NONZERO)); + m_Params.push_back(ParamWithName(true, &m_Rn, prefix + "juliascope_rn"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Cn, prefix + "juliascope_cn")); + } + +private: + T m_Dist;//Params. + T m_Power; + T m_Rn;//Precalc. + T m_Cn; +}; + +/// +/// Blur. +/// This is somewhat different than the original functionality in that blur used +/// the code below, but pre_blur used gaussian_blur. +/// If the original pre_blur functionality is needed, use pre_gaussian_blur. +/// +template +class BlurVariation : public Variation +{ +public: + BlurVariation(T weight = 1.0) : Variation("blur", eVariationId::VAR_BLUR, weight) { } + + VARCOPY(BlurVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T tempr = rand.Frand01() * M_2PI; + T r = m_Weight * rand.Frand01(); + helper.Out.x = r * std::cos(tempr); + helper.Out.y = r * std::sin(tempr); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t tmpr = MwcNext01(mwc) * M_2PI;\n" + << "\t\treal_t r = " << weight << " * MwcNext01(mwc);\n" + << "\n" + << "\t\tvOut.x = r * cos(tmpr);\n" + << "\t\tvOut.y = r * sin(tmpr);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Gaussian blur. +/// +template +class GaussianBlurVariation : public Variation +{ +public: + GaussianBlurVariation(T weight = 1.0) : Variation("gaussian_blur", eVariationId::VAR_GAUSSIAN_BLUR, weight) { } + + VARCOPY(GaussianBlurVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T angle = rand.Frand01() * M_2PI; + T r = m_Weight * (rand.Frand01() + rand.Frand01() + rand.Frand01() + rand.Frand01() - 2); + helper.Out.x = r * std::cos(angle); + helper.Out.y = r * std::sin(angle); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t angle = MwcNext01(mwc) * M_2PI;\n" + << "\t\treal_t r = " << weight << " * (MwcNext01(mwc) + MwcNext01(mwc) + MwcNext01(mwc) + MwcNext01(mwc) - (real_t)(2.0));\n" + << "\n" + << "\t\tvOut.x = r * cos(angle);\n" + << "\t\tvOut.y = r * sin(angle);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Gaussian. +/// +template +class GaussianVariation : public Variation +{ +public: + GaussianVariation(T weight = 1.0) : Variation("gaussian", eVariationId::VAR_GAUSSIAN, weight) { } + + VARCOPY(GaussianVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T angle = rand.Frand01() * M_2PI; + T r = m_Weight * (rand.Frand01() + rand.Frand01() + rand.Frand01() + rand.Frand01() - 2); + helper.Out.x = r * std::cos(angle) + helper.In.x; + helper.Out.y = r * std::sin(angle) + helper.In.y; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t angle = MwcNext01(mwc) * M_2PI;\n" + << "\t\treal_t r = " << weight << " * (MwcNext01(mwc) + MwcNext01(mwc) + MwcNext01(mwc) + MwcNext01(mwc) - (real_t)(2.0));\n" + << "\n" + << "\t\tvOut.x = fma(r, cos(angle), vIn.x);\n" + << "\t\tvOut.y = fma(r, sin(angle), vIn.y);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Radial blur. +/// +template +class RadialBlurVariation : public ParametricVariation +{ +public: + RadialBlurVariation(T weight = 1.0) : ParametricVariation("radial_blur", eVariationId::VAR_RADIAL_BLUR, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(RadialBlurVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + //Get pseudo-gaussian. + T rndG = m_Weight * (rand.Frand01() + rand.Frand01() + + rand.Frand01() + rand.Frand01() - 2); + //Calculate angle & zoom. + T ra = helper.m_PrecalcSqrtSumSquares; + T tempa = helper.m_PrecalcAtanyx + m_Spin * rndG; + T rz = m_Zoom * rndG - 1; + helper.Out.x = ra * std::cos(tempa) + rz * helper.In.x; + helper.Out.y = ra * std::sin(tempa) + rz * helper.In.y; + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string angle = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Params. + string spin = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Precalc. + string zoom = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t rndG = " << weight << " * (MwcNext01(mwc) + MwcNext01(mwc) + MwcNext01(mwc) + MwcNext01(mwc) - (real_t)(2.0));\n" + << "\t\treal_t ra = precalcSqrtSumSquares;\n" + << "\t\treal_t tempa = fma(" << spin << ", rndG, precalcAtanyx);\n" + << "\t\treal_t rz = fma(" << zoom << ", rndG, (real_t)(-1.0));\n" + << "\n" + << "\t\tvOut.x = fma(ra, cos(tempa), rz * vIn.x);\n" + << "\t\tvOut.y = fma(ra, sin(tempa), rz * vIn.y);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + sincos(m_Angle * T(M_PI) / 2, &m_Spin, &m_Zoom); + } + + virtual void Random(QTIsaac& rand) override + { + m_Angle = (2 * rand.Frand01() - 1); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Angle, prefix + "radial_blur_angle"));//Params. + m_Params.push_back(ParamWithName(true, &m_Spin, prefix + "radial_blur_spin"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Zoom, prefix + "radial_blur_zoom")); + } + +private: + T m_Angle;//Params. + T m_Spin;//Precalc. + T m_Zoom; +}; + +/// +/// Pie. +/// +template +class PieVariation : public ParametricVariation +{ +public: + PieVariation(T weight = 1.0) : ParametricVariation("pie", eVariationId::VAR_PIE, weight) + { + Init(); + } + + PARVARCOPY(PieVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + int sl = int(rand.Frand01() * m_Slices + T(0.5)); + T a = m_Rotation + m_Pi2Slices * (sl + m_Thickness * rand.Frand01()); + T r = m_Weight * rand.Frand01(); + helper.Out.x = r * std::cos(a); + helper.Out.y = r * std::sin(a); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string slices = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string rotation = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string thickness = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string pi2Slices = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tint sl = (int)(fma(MwcNext01(mwc), " << slices << ", (real_t)(0.5)));\n" + << "\t\treal_t a = fma(" << pi2Slices << ", fma(" << thickness << ", MwcNext01(mwc), sl), " << rotation << ");\n" + << "\t\treal_t r = " << weight << " * MwcNext01(mwc);\n" + << "\n" + << "\t\tvOut.x = r * cos(a);\n" + << "\t\tvOut.y = r * sin(a);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Pi2Slices = M_2PI / m_Slices; + } + + virtual void Random(QTIsaac& rand) override + { + m_Params[0].Set(10 * rand.Frand01());//Slices. + m_Params[1].Set(M_2PI * rand.Frand11());//Rotation. + m_Thickness = rand.Frand01(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Slices, prefix + "pie_slices", 6, eParamType::INTEGER_NONZERO, 1)); + m_Params.push_back(ParamWithName(&m_Rotation, prefix + "pie_rotation", T(0.5), eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Thickness, prefix + "pie_thickness", T(0.5), eParamType::REAL, 0, 1)); + m_Params.push_back(ParamWithName(true, &m_Pi2Slices, prefix + "pie_pi2_slices")); + } + +private: + T m_Slices; + T m_Rotation; + T m_Thickness; + T m_Pi2Slices;//Precalc +}; + +/// +/// Ngon. +/// +template +class NgonVariation : public ParametricVariation +{ +public: + NgonVariation(T weight = 1.0) : ParametricVariation("ngon", eVariationId::VAR_NGON, weight, true, false, false, false, true) + { + Init(); + } + + PARVARCOPY(NgonVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T rFactor; + + if ((helper.In.x == 0) && (helper.In.y == 0)) + rFactor = 0; + else + rFactor = std::pow(helper.m_PrecalcSumSquares, m_CPower); + + T phi = helper.m_PrecalcAtanyx - m_CSides * Floor(helper.m_PrecalcAtanyx * m_CSidesInv); + + if (phi > T(0.5) * m_CSides) + phi -= m_CSides; + + T amp = (m_Corners * (1 / std::cos(phi) - 1) + m_Circle) * m_Weight * rFactor; + helper.Out.x = amp * helper.In.x; + helper.Out.y = amp * helper.In.y; + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string sides = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string circle = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string corners = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string csides = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string csidesinv = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string cpower = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t rFactor;\n" + << "\n" + << "\t\tif ((vIn.x == (real_t)(0.0)) && (vIn.y == (real_t)(0.0)))\n" + << "\t\t rFactor = (real_t)(0.0);\n" + << "\t\telse\n" + << "\t\t rFactor = pow(precalcSumSquares, " << cpower << ");\n" + << "\n" + << "\t\treal_t phi = precalcAtanyx - " << csides << " * floor(precalcAtanyx * " << csidesinv << ");\n" + << "\n" + << "\t\tif (phi > (real_t)(0.5) * " << csides << ")\n" + << "\t\t phi -= " << csides << ";\n" + << "\n" + << "\t\treal_t amp = fma(" << corners << ", (1 / cos(phi) - 1), " << circle << ") * " << weight << " * rFactor;\n" + << "\n" + << "\t\tvOut.x = amp * vIn.x;\n" + << "\t\tvOut.y = amp * vIn.y;\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_CPower = -T(0.5) * m_Power; + m_CSides = 2 * T(M_PI) / m_Sides; + m_CSidesInv = 1 / m_CSides; + } + + virtual void Random(QTIsaac& rand) override + { + m_Sides = T(int(rand.Frand01() * 10 + 3)); + m_Power = 3 * rand.Frand01() + 1; + m_Circle = 3 * rand.Frand01(); + m_Corners = 2 * rand.Frand01() * m_Circle; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Sides, prefix + "ngon_sides", 5, eParamType::INTEGER_NONZERO)); + m_Params.push_back(ParamWithName(&m_Power, prefix + "ngon_power", 3)); + m_Params.push_back(ParamWithName(&m_Circle, prefix + "ngon_circle", 1)); + m_Params.push_back(ParamWithName(&m_Corners, prefix + "ngon_corners", 2)); + m_Params.push_back(ParamWithName(true, &m_CSides, prefix + "ngon_csides")); + m_Params.push_back(ParamWithName(true, &m_CSidesInv, prefix + "ngon_csides_inv")); + m_Params.push_back(ParamWithName(true, &m_CPower, prefix + "ngon_cpower")); + } + +private: + T m_Sides; + T m_Power; + T m_Circle; + T m_Corners; + T m_CSides; + T m_CSidesInv; + T m_CPower; +}; + +/// +/// Curl. +/// Note that in Apophysis, curl and post_curl differed slightly. +/// Using what post_curl did here gave bad results, so sticking with the original +/// curl code. +/// +template +class CurlVariation : public ParametricVariation +{ +public: + CurlVariation(T weight = 1.0) : ParametricVariation("curl", eVariationId::VAR_CURL, weight) + { + Init(); + } + + PARVARCOPY(CurlVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T re = 1 + m_C1 * helper.In.x + m_C2 * (SQR(helper.In.x) - SQR(helper.In.y)); + T im = m_C1 * helper.In.y + m_C22 * helper.In.x * helper.In.y; + T r = m_Weight / Zeps(SQR(re) + SQR(im)); + helper.Out.x = (helper.In.x * re + helper.In.y * im) * r; + helper.Out.y = (helper.In.y * re - helper.In.x * im) * r; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string c1 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string c2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string c22 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t re = (real_t)(1.0) + " << c1 << " * vIn.x + " << c2 << " * fma(vIn.x, vIn.x, -SQR(vIn.y));\n" + << "\t\treal_t im = fma(" << c1 << ", vIn.y, " << c22 << " * vIn.x * vIn.y);\n" + << "\t\treal_t r = " << weight << " / Zeps(fma(re, re, SQR(im)));\n" + << "\n" + << "\t\tvOut.x = fma(vIn.x, re, vIn.y * im) * r;\n" + << "\t\tvOut.y = fma(vIn.y, re, -(vIn.x * im)) * r;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + + virtual void Precalc() override + { + m_C22 = 2 * m_C2; + } + + virtual void Random(QTIsaac& rand) override + { + m_C1 = rand.Frand01(); + m_C2 = rand.Frand01(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_C1, prefix + "curl_c1", 1)); + m_Params.push_back(ParamWithName(&m_C2, prefix + "curl_c2")); + m_Params.push_back(ParamWithName(true, &m_C22, prefix + "curl_c22"));//Precalc. + } + +private: + T m_C1; + T m_C2; + T m_C22;//Precalc. +}; + +/// +/// Rectangles. +/// +template +class RectanglesVariation : public ParametricVariation +{ +public: + RectanglesVariation(T weight = 1.0) : ParametricVariation("rectangles", eVariationId::VAR_RECTANGLES, weight) + { + Init(); + } + + PARVARCOPY(RectanglesVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + if (m_X == 0) + helper.Out.x = m_Weight * helper.In.x; + else + helper.Out.x = m_Weight * ((2 * Floor(helper.In.x / m_X) + 1) * m_X - helper.In.x); + + if (m_Y == 0) + helper.Out.y = m_Weight * helper.In.y; + else + helper.Out.y = m_Weight * ((2 * Floor(helper.In.y / m_Y) + 1) * m_Y - helper.In.y); + + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string x = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tif (" << x << " == 0)\n" + << "\t\t vOut.x = " << weight << " * vIn.x;\n" + << "\t\telse\n" + << "\t\t vOut.x = " << weight << " * fma(fma((real_t)(2.0), floor(vIn.x / " << x << "), 1), " << x << ", -vIn.x);\n" + << "\n" + << "\t\tif (" << y << " == 0)\n" + << "\t\t vOut.y = " << weight << " * vIn.y;\n" + << "\t\telse\n" + << "\t\t vOut.y = " << weight << " * fma(fma((real_t)(2.0), floor(vIn.y / " << y << "), 1), " << y << ", -vIn.y);\n" + << "\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Random(QTIsaac& rand) override + { + m_X = rand.Frand01(); + m_Y = rand.Frand01(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_X, prefix + "rectangles_x", 1)); + m_Params.push_back(ParamWithName(&m_Y, prefix + "rectangles_y", 1)); + } + +private: + T m_X; + T m_Y; +}; + +/// +/// Arch. +/// +template +class ArchVariation : public Variation +{ +public: + ArchVariation(T weight = 1.0) : Variation("arch", eVariationId::VAR_ARCH, weight) { } + + VARCOPY(ArchVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T angle = rand.Frand01() * m_Weight * T(M_PI); + T sinr, cosr; + sincos(angle, &sinr, &cosr); + helper.Out.x = m_Weight * sinr; + helper.Out.y = m_Weight * (sinr * sinr) / cosr; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t angle = MwcNext01(mwc) * " << weight << " * MPI;\n" + << "\t\treal_t sinr = sin(angle);\n" + << "\t\treal_t cosr = cos(angle);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * sinr;\n" + << "\t\tvOut.y = " << weight << " * (sinr * sinr) / cosr;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Tangent. +/// +template +class TangentVariation : public Variation +{ +public: + TangentVariation(T weight = 1.0) : Variation("tangent", eVariationId::VAR_TANGENT, weight) { } + + VARCOPY(TangentVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * std::sin(helper.In.x) / std::cos(helper.In.y); + helper.Out.y = m_Weight * SafeTan(helper.In.y); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * sin(vIn.x) / cos(vIn.y);\n" + << "\t\tvOut.y = " << weight << " * tan(vIn.y);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Square. +/// +template +class SquareVariation : public Variation +{ +public: + SquareVariation(T weight = 1.0) : Variation("square", eVariationId::VAR_SQUARE, weight) { } + + VARCOPY(SquareVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * (rand.Frand01() - T(0.5)); + helper.Out.y = m_Weight * (rand.Frand01() - T(0.5)); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * (MwcNext01(mwc) - (real_t)(0.5));\n" + << "\t\tvOut.y = " << weight << " * (MwcNext01(mwc) - (real_t)(0.5));\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Rays. +/// +template +class RaysVariation : public Variation +{ +public: + RaysVariation(T weight = 1.0) : Variation("rays", eVariationId::VAR_RAYS, weight, true) { } + + VARCOPY(RaysVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T ang = m_Weight * rand.Frand01() * T(M_PI); + T r = m_Weight / Zeps(helper.m_PrecalcSumSquares); + T tanr = m_Weight * SafeTan(ang) * r; + helper.Out.x = tanr * std::cos(helper.In.x); + helper.Out.y = tanr * std::sin(helper.In.y); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t ang = " << weight << " * MwcNext01(mwc) * MPI;\n" + << "\t\treal_t r = " << weight << " / Zeps(precalcSumSquares);\n" + << "\t\treal_t tanr = " << weight << " * tan(ang) * r;\n" + << "\n" + << "\t\tvOut.x = tanr * cos(vIn.x);\n" + << "\t\tvOut.y = tanr * sin(vIn.y);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Rays1 from JWildfire by Raykoid666. +/// +template +class Rays1Variation : public Variation +{ +public: + Rays1Variation(T weight = 1.0) : Variation("rays1", eVariationId::VAR_RAYS1, weight, true, true) { } + + VARCOPY(Rays1Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T u = 1 / Zeps(SafeTan(helper.m_PrecalcSqrtSumSquares)) + (m_Weight * T(SQR(M_2_PI))); + + if (m_VarType == eVariationType::VARTYPE_REG) + outPoint.m_X = outPoint.m_Y = 0;//This variation assigns, instead of summing, so order will matter. + + helper.Out.x = m_Weight * u * helper.m_PrecalcSumSquares / Zeps(helper.In.x); + helper.Out.y = m_Weight * u * helper.m_PrecalcSumSquares / Zeps(helper.In.y); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t u = fma(" << weight << ", SQR(M2PI), 1 / Zeps(tan(precalcSqrtSumSquares)));\n"; + + if (m_VarType == eVariationType::VARTYPE_REG) + ss << "\t\toutPoint->m_X = outPoint->m_Y = 0;\n"; + + ss + << "\t\tvOut.x = " << weight << " * u * precalcSumSquares / Zeps(vIn.x);\n" + << "\t\tvOut.y = " << weight << " * u * precalcSumSquares / Zeps(vIn.y);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Rays2 from JWildfire by Raykoid666. +/// +template +class Rays2Variation : public Variation +{ +public: + Rays2Variation(T weight = 1.0) : Variation("rays2", eVariationId::VAR_RAYS2, weight, true) { } + + VARCOPY(Rays2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T u = 1 / std::cos(helper.m_PrecalcSumSquares * std::tan(1 / Zeps(helper.m_PrecalcSumSquares))); + + if (m_VarType == eVariationType::VARTYPE_REG) + outPoint.m_X = outPoint.m_Y = 0;//This variation assigns, instead of summing, so order will matter. + + helper.Out.x = (m_Weight / 10) * u * helper.m_PrecalcSumSquares / Zeps(helper.In.x); + helper.Out.y = (m_Weight / 10) * u * helper.m_PrecalcSumSquares / Zeps(helper.In.y); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t u = 1 / cos(precalcSumSquares * tan(1 / Zeps(precalcSumSquares)));\n"; + + if (m_VarType == eVariationType::VARTYPE_REG) + ss << "\t\toutPoint->m_X = outPoint->m_Y = 0;\n"; + + ss + << "\t\tvOut.x = (" << weight << " / 10) * u * precalcSumSquares / Zeps(vIn.x);\n" + << "\t\tvOut.y = (" << weight << " / 10) * u * precalcSumSquares / Zeps(vIn.y);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Rays3 from JWildfire by Raykoid666. +/// +template +class Rays3Variation : public Variation +{ +public: + Rays3Variation(T weight = 1.0) : Variation("rays3", eVariationId::VAR_RAYS3, weight, true) { } + + VARCOPY(Rays3Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T sq = SQR(helper.m_PrecalcSumSquares); + T u = 1 / std::sqrt(std::cos(std::sin(sq) * std::sin(1 / Zeps(sq)))); + + if (m_VarType == eVariationType::VARTYPE_REG) + outPoint.m_X = outPoint.m_Y = 0;//This variation assigns, instead of summing, so order will matter. + + helper.Out.x = (m_Weight / 10) * u * std::cos(helper.m_PrecalcSumSquares) * helper.m_PrecalcSumSquares / Zeps(helper.In.x); + helper.Out.y = (m_Weight / 10) * u * std::tan(helper.m_PrecalcSumSquares) * helper.m_PrecalcSumSquares / Zeps(helper.In.y); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t sq = SQR(precalcSumSquares);\n" + << "\t\treal_t u = 1 / sqrt(cos(sin(sq) * sin(1 / Zeps(sq))));\n"; + + if (m_VarType == eVariationType::VARTYPE_REG) + ss << "\t\toutPoint->m_X = outPoint->m_Y = 0;\n"; + + ss + << "\t\tvOut.x = (" << weight << " / 10) * u * cos(precalcSumSquares) * precalcSumSquares / Zeps(vIn.x);\n" + << "\t\tvOut.y = (" << weight << " / 10) * u * tan(precalcSumSquares) * precalcSumSquares / Zeps(vIn.y);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Blade. +/// +template +class BladeVariation : public Variation +{ +public: + BladeVariation(T weight = 1.0) : Variation("blade", eVariationId::VAR_BLADE, weight, true, true) { } + + VARCOPY(BladeVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = rand.Frand01() * m_Weight * helper.m_PrecalcSqrtSumSquares; + T sinr, cosr; + sincos(r, &sinr, &cosr); + helper.Out.x = m_Weight * helper.In.x * (cosr + sinr); + helper.Out.y = m_Weight * helper.In.x * (cosr - sinr); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t r = MwcNext01(mwc) * " << weight << " * precalcSqrtSumSquares;\n" + << "\t\treal_t sinr = sin(r);\n" + << "\t\treal_t cosr = cos(r);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * vIn.x * (cosr + sinr);\n" + << "\t\tvOut.y = " << weight << " * vIn.x * (cosr - sinr);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Secant2. +/// +template +class Secant2Variation : public Variation +{ +public: + Secant2Variation(T weight = 1.0) : Variation("secant2", eVariationId::VAR_SECANT2, weight, true, true) { } + + VARCOPY(Secant2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = m_Weight * helper.m_PrecalcSqrtSumSquares; + T cr = std::cos(r); + T icr = 1 / cr; + helper.Out.x = m_Weight * helper.In.x; + + if (cr < 0) + helper.Out.y = m_Weight * (icr + 1); + else + helper.Out.y = m_Weight * (icr - 1); + + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t r = " << weight << " * precalcSqrtSumSquares;\n" + << "\t\treal_t cr = cos(r);\n" + << "\t\treal_t icr = (real_t)(1.0) / cr;\n" + << "\n" + << "\t\tvOut.x = " << weight << " * vIn.x;\n" + << "\n" + << "\t\tif (cr < (real_t)(0.0))\n" + << "\t\t vOut.y = " << weight << " * (icr + (real_t)(1.0));\n" + << "\t\telse\n" + << "\t\t vOut.y = " << weight << " * (icr - (real_t)(1.0));\n" + << "\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// TwinTrian. +/// +template +class TwinTrianVariation : public Variation +{ +public: + TwinTrianVariation(T weight = 1.0) : Variation("TwinTrian", eVariationId::VAR_TWINTRIAN, weight, true, true) { } + + VARCOPY(TwinTrianVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = rand.Frand01() * m_Weight * helper.m_PrecalcSqrtSumSquares; + T sinr, cosr, diff; + sincos(r, &sinr, &cosr); + diff = std::log10(SQR(sinr)) + cosr; + + if (BadVal(diff)) + diff = -30.0; + + helper.Out.x = m_Weight * helper.In.x * diff; + helper.Out.y = m_Weight * helper.In.x * (diff - sinr * T(M_PI)); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t r = MwcNext01(mwc) * " << weight << " * precalcSqrtSumSquares;\n" + << "\t\treal_t sinr = sin(r);\n" + << "\t\treal_t cosr = cos(r);\n" + << "\t\treal_t diff = log10(SQR(sinr)) + cosr;\n" + << "\n" + << "\t\tif (BadVal(diff))\n" + << "\t\t diff = -(real_t)(30.0);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * vIn.x * diff;\n" + << "\t\tvOut.y = " << weight << " * vIn.x * (diff - sinr * MPI);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Cross. +/// +template +class CrossVariation : public Variation +{ +public: + CrossVariation(T weight = 1.0) : Variation("cross", eVariationId::VAR_CROSS, weight) { } + + VARCOPY(CrossVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = m_Weight / Zeps(std::abs((helper.In.x - helper.In.y) * (helper.In.x + helper.In.y))); + helper.Out.x = helper.In.x * r; + helper.Out.y = helper.In.y * r; + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t r = " << weight << " /Zeps(fabs((vIn.x - vIn.y) * (vIn.x + vIn.y)));\n" + << "\n" + << "\t\tvOut.x = vIn.x * r;\n" + << "\t\tvOut.y = vIn.y * r;\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Disc2. +/// +template +class Disc2Variation : public ParametricVariation +{ +public: + Disc2Variation(T weight = 1.0) : ParametricVariation("disc2", eVariationId::VAR_DISC2, weight, false, false, false, true) + { + Init(); + } + + PARVARCOPY(Disc2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r, t, sinr, cosr; + t = m_RotTimesPi * (helper.In.x + helper.In.y); + sincos(t, &sinr, &cosr); + r = m_Weight * helper.m_PrecalcAtanxy / T(M_PI); + helper.Out.x = (sinr + m_CosAdd) * r; + helper.Out.y = (cosr + m_SinAdd) * r; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string rot = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Params. + string twist = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sinAdd = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Precalc. + string cosAdd = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string rotTimesPi = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t t = " << rotTimesPi << " * (vIn.x + vIn.y);\n" + << "\t\treal_t sinr = sin(t);\n" + << "\t\treal_t cosr = cos(t);\n" + << "\t\treal_t r = " << weight << " * precalcAtanxy / MPI;\n" + << "\n" + << "\t\tvOut.x = (sinr + " << cosAdd << ") * r;\n" + << "\t\tvOut.y = (cosr + " << sinAdd << ") * r;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + T k, add = m_Twist; + m_RotTimesPi = m_Rot * T(M_PI); + sincos(add, &m_SinAdd, &m_CosAdd); + m_CosAdd -= 1; + + if (add > 2 * M_PI) + { + k = (1 + add - 2 * T(M_PI)); + m_CosAdd *= k; + m_SinAdd *= k; + } + + if (add < -2 * M_PI) + { + k = (1 + add + 2 * T(M_PI)); + m_CosAdd *= k; + m_SinAdd *= k; + } + } + + virtual void Random(QTIsaac& rand) override + { + m_Rot = T(0.5) * rand.Frand01(); + m_Twist = T(0.5) * rand.Frand01(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Rot, prefix + "disc2_rot"));//Params. + m_Params.push_back(ParamWithName(&m_Twist, prefix + "disc2_twist")); + m_Params.push_back(ParamWithName(true, &m_SinAdd, prefix + "disc2_sin_add"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_CosAdd, prefix + "disc2_cos_add")); + m_Params.push_back(ParamWithName(true, &m_RotTimesPi, prefix + "disc2_rot_times_pi")); + } + +private: + T m_Rot;//Params. + T m_Twist; + T m_SinAdd;//Precalc. + T m_CosAdd; + T m_RotTimesPi; +}; + +/// +/// SuperShape. +/// +template +class SuperShapeVariation : public ParametricVariation +{ +public: + SuperShapeVariation(T weight = 1.0) : ParametricVariation("super_shape", eVariationId::VAR_SUPER_SHAPE, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(SuperShapeVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T theta = m_Pm4 * helper.m_PrecalcAtanyx + T(M_PI_4); + T t1 = std::abs(std::cos(theta)); + t1 = std::pow(t1, m_N2); + T t2 = std::abs(std::sin(theta)); + t2 = std::pow(t2, m_N3); + T r = m_Weight * ((m_Rnd * rand.Frand01() + (1 - m_Rnd) * helper.m_PrecalcSqrtSumSquares) - m_Holes) + * std::pow(t1 + t2, m_PNeg1N1) / helper.m_PrecalcSqrtSumSquares; + helper.Out.x = r * helper.In.x; + helper.Out.y = r * helper.In.y; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string m = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Params. + string n1 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string n2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string n3 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string rnd = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string holes = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string pm4 = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Precalc. + string pNeg1N1 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t theta = " << pm4 << " * precalcAtanyx + MPI4;\n" + << "\t\treal_t t1 = fabs(cos(theta));\n" + << "\t\tt1 = pow(t1, " << n2 << ");\n" + << "\t\treal_t t2 = fabs(sin(theta));\n" + << "\t\tt2 = pow(t2, " << n3 << ");\n" + << "\t\treal_t r = " << weight << " * (fma(" << rnd << ", MwcNext01(mwc), ((real_t)(1.0) - " << rnd << ") * precalcSqrtSumSquares) - " << holes << ") * pow(t1 + t2, " << pNeg1N1 << ") / precalcSqrtSumSquares;\n" + << "\n" + << "\t\tvOut.x = r * vIn.x;\n" + << "\t\tvOut.y = r * vIn.y;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Pm4 = m_M / T(4.0); + m_PNeg1N1 = T(-1.0) / m_N1; + } + + virtual void Random(QTIsaac& rand) override + { + m_Rnd = rand.Frand01(); + m_M = T(int(rand.Frand01() * 6)); + m_N1 = rand.Frand01() * 40; + m_N2 = rand.Frand01() * 20; + m_N3 = m_N2; + m_Holes = 0.0; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_M, prefix + "super_shape_m"));//Params. + m_Params.push_back(ParamWithName(&m_N1, prefix + "super_shape_n1", 1)); + m_Params.push_back(ParamWithName(&m_N2, prefix + "super_shape_n2", 1)); + m_Params.push_back(ParamWithName(&m_N3, prefix + "super_shape_n3", 1)); + m_Params.push_back(ParamWithName(&m_Rnd, prefix + "super_shape_rnd")); + m_Params.push_back(ParamWithName(&m_Holes, prefix + "super_shape_holes")); + m_Params.push_back(ParamWithName(true, &m_Pm4, prefix + "super_shape_pm4"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_PNeg1N1, prefix + "super_shape_pneg1n1")); + } + +private: + T m_M;//Params. + T m_N1; + T m_N2; + T m_N3; + T m_Rnd; + T m_Holes; + T m_Pm4;//Precalc. + T m_PNeg1N1; +}; + +/// +/// Flower. +/// +template +class FlowerVariation : public ParametricVariation +{ +public: + FlowerVariation(T weight = 1.0) : ParametricVariation("flower", eVariationId::VAR_FLOWER, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(FlowerVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T theta = helper.m_PrecalcAtanyx; + T r = m_Weight * (rand.Frand01() - m_Holes) * std::cos(m_Petals * theta) / helper.m_PrecalcSqrtSumSquares; + helper.Out.x = r * helper.In.x; + helper.Out.y = r * helper.In.y; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string petals = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string holes = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t theta = precalcAtanyx;\n" + << "\t\treal_t r = " << weight << " * (MwcNext01(mwc) - " << holes << ") * cos(" << petals << " * theta) / precalcSqrtSumSquares;\n" + << "\n" + << "\t\tvOut.x = r * vIn.x;\n" + << "\t\tvOut.y = r * vIn.y;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Random(QTIsaac& rand) override + { + m_Petals = 4 * rand.Frand01(); + m_Holes = rand.Frand01(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Petals, prefix + "flower_petals")); + m_Params.push_back(ParamWithName(&m_Holes, prefix + "flower_holes")); + } + +private: + T m_Petals; + T m_Holes; +}; + +/// +/// flowerdb. +/// By dark-beam. +/// +template +class FlowerDbVariation : public ParametricVariation +{ +public: + FlowerDbVariation(T weight = 1.0) : ParametricVariation("flowerdb", eVariationId::VAR_FLOWER_DB, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(FlowerDbVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = m_Weight * helper.m_PrecalcSqrtSumSquares; + T t = helper.m_PrecalcAtanyx; + T r2 = r * (std::abs((m_Spread + std::sin(m_Petals * t)) * cos(m_PetalsSplit * t))); + helper.Out.x = r2 * std::cos(t); + helper.Out.y = r2 * std::sin(t); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string petals = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string split = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string spread = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string petalssplit = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t r = " << weight << " * precalcSqrtSumSquares;\n" + << "\t\treal_t t = precalcAtanyx;\n" + << "\t\treal_t r2 = r * (fabs((" << spread << " + sin(" << petals << " * t)) * cos(" << petalssplit << " * t)));\n" + << "\n" + << "\t\tvOut.x = r * cos(t);\n" + << "\t\tvOut.y = r * sin(t);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_PetalsSplit = m_Petals * m_Split; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Petals, prefix + "flowerdb_petals", 6)); + m_Params.push_back(ParamWithName(&m_Split, prefix + "flowerdb_petal_split")); + m_Params.push_back(ParamWithName(&m_Spread, prefix + "flowerdb_petal_spread", 1)); + m_Params.push_back(ParamWithName(true, &m_PetalsSplit, prefix + "flowerdb_petal_split_petals"));//Precalc. + } + +private: + T m_Petals; + T m_Split; + T m_Spread; + T m_PetalsSplit;//Precalc. +}; + +/// +/// Conic. +/// +template +class ConicVariation : public ParametricVariation +{ +public: + ConicVariation(T weight = 1.0) : ParametricVariation("conic", eVariationId::VAR_CONIC, weight, true, true) + { + Init(); + } + + PARVARCOPY(ConicVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T z = Zeps(helper.m_PrecalcSqrtSumSquares); + T ct = helper.In.x / z; + T r = m_Weight * (rand.Frand01() - m_Holes) * + m_Eccentricity / (1 + m_Eccentricity * ct) / z; + helper.Out.x = r * helper.In.x; + helper.Out.y = r * helper.In.y; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string eccentricity = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string holes = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t z = Zeps(precalcSqrtSumSquares);\n" + << "\t\treal_t ct = vIn.x / precalcSqrtSumSquares;\n" + << "\t\treal_t r = " << weight << " * (MwcNext01(mwc) - " << holes << ") * " << eccentricity << " / fma(" << eccentricity << ", ct, 1) / z;\n" + << "\n" + << "\t\tvOut.x = r * vIn.x;\n" + << "\t\tvOut.y = r * vIn.y;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + + virtual void Random(QTIsaac& rand) override + { + m_Eccentricity = rand.Frand01(); + m_Holes = rand.Frand01(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Eccentricity, prefix + "conic_eccentricity", 1)); + m_Params.push_back(ParamWithName(&m_Holes, prefix + "conic_holes")); + } + +private: + T m_Eccentricity; + T m_Holes; +}; + +/// +/// Parabola. +/// +template +class ParabolaVariation : public ParametricVariation +{ +public: + ParabolaVariation(T weight = 1.0) : ParametricVariation("parabola", eVariationId::VAR_PARABOLA, weight, true, true) + { + Init(); + } + + PARVARCOPY(ParabolaVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T sr, cr; + sincos(helper.m_PrecalcSqrtSumSquares, &sr, &cr); + helper.Out.x = m_Height * m_Weight * sr * sr * rand.Frand01(); + helper.Out.y = m_Width * m_Weight * cr * rand.Frand01(); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string height = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string width = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t sr = sin(precalcSqrtSumSquares);\n" + << "\t\treal_t cr = cos(precalcSqrtSumSquares);\n" + << "\n" + << "\t\tvOut.x = " << height << " * (" << weight << " * sr * sr * MwcNext01(mwc));\n" + << "\t\tvOut.y = " << width << " * (" << weight << " * cr * MwcNext01(mwc));\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Random(QTIsaac& rand) override + { + m_Height = T(0.5) * rand.Frand01(); + m_Width = T(0.5) * rand.Frand01(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Height, prefix + "parabola_height")); + m_Params.push_back(ParamWithName(&m_Width, prefix + "parabola_width")); + } + +private: + T m_Height; + T m_Width; +}; + +/// +/// Bent2. +/// +template +class Bent2Variation : public ParametricVariation +{ +public: + Bent2Variation(T weight = 1.0) : ParametricVariation("bent2", eVariationId::VAR_BENT2, weight) + { + Init(); + } + + PARVARCOPY(Bent2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + if (helper.In.x >= 0) + helper.Out.x = m_Weight * helper.In.x; + else + helper.Out.x = m_Vx * helper.In.x; + + if (helper.In.y >= 0) + helper.Out.y = m_Weight * helper.In.y; + else + helper.Out.y = m_Vy * helper.In.y; + + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string x = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string vx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string vy = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tif (vIn.x >= 0)\n" + << "\t\t vOut.x = " << weight << " * vIn.x;\n" + << "\t\telse\n" + << "\t\t vOut.x = " << vx << " * vIn.x;\n" + << "\n" + << "\t\tif (vIn.y >= 0)\n" + << "\t\t vOut.y = " << weight << " * vIn.y;\n" + << "\t\telse\n" + << "\t\tvOut.y = " << vy << " * vIn.y;\n" + << "\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Vx = m_X * m_Weight; + m_Vy = m_Y * m_Weight; + } + + virtual void Random(QTIsaac& rand) override + { + m_X = 3 * (T(-0.5) + rand.Frand01()); + m_Y = 3 * (T(-0.5) + rand.Frand01()); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_X, prefix + "bent2_x", 1));//Params. + m_Params.push_back(ParamWithName(&m_Y, prefix + "bent2_y", 1)); + m_Params.push_back(ParamWithName(true, &m_Vx, prefix + "bent2_vx"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Vy, prefix + "bent2_vy")); + } + +private: + T m_X;//Params. + T m_Y; + T m_Vx;//Precalc. + T m_Vy; +}; + +/// +/// Bipolar. +/// +template +class BipolarVariation : public ParametricVariation +{ +public: + BipolarVariation(T weight = 1.0) : ParametricVariation("bipolar", eVariationId::VAR_BIPOLAR, weight, true) + { + Init(); + } + + PARVARCOPY(BipolarVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + const T x2y2 = helper.m_PrecalcSumSquares; + const T t = x2y2 + 1; + const T x2 = 2 * helper.In.x; + T y = T(0.5) * std::atan2(2 * helper.In.y, x2y2 - 1) + m_S; + + if (y > T(M_PI_2)) + y = -T(M_PI_2) + fmod(y + T(M_PI_2), T(M_PI)); + else if (y < -T(M_PI_2)) + y = T(M_PI_2) - fmod(T(M_PI_2) - y, T(M_PI)); + + const T f = t + x2; + const T g = t - x2; + + if ((g == 0) || (f / g <= 0)) + { + if (m_VarType == eVariationType::VARTYPE_REG) + { + helper.Out.x = 0; + helper.Out.y = 0; + helper.Out.z = 0; + } + else + { + helper.Out.x = helper.In.x; + helper.Out.y = helper.In.y; + helper.Out.z = helper.In.z; + } + } + else + { + helper.Out.x = m_V4 * std::log((t + x2) / Zeps(t - x2)); + helper.Out.y = m_V * y; + helper.Out.z = m_Weight * helper.In.z; + } + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string shift = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string s = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string v = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string v4 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t x2y2 = precalcSumSquares;\n" + << "\t\treal_t t = x2y2 + 1;\n" + << "\t\treal_t x2 = 2 * vIn.x;\n" + << "\t\treal_t ps = " << s << ";\n" + << "\t\treal_t y = (real_t)(0.5) * atan2((real_t)(2.0) * vIn.y, x2y2 - (real_t)(1.0)) + ps;\n" + << "\n" + << "\t\tif (y > MPI2)\n" + << "\t\t y = -MPI2 + fmod(y + MPI2, MPI);\n" + << "\t\telse if (y < -MPI2)\n" + << "\t\t y = MPI2 - fmod(MPI2 - y, MPI);\n" + << "\n" + << "\t\treal_t f = t + x2;\n" + << "\t\treal_t g = t - x2;\n" + << "\n"; + + if (m_VarType == eVariationType::VARTYPE_REG) + { + ss << "\t\tif ((g == 0) || (f / g <= 0))\n" + << "\t\t{\n" + << "\t\t vOut.x = 0;\n" + << "\t\t vOut.y = 0;\n" + << "\t\t vOut.z = 0;\n" + << "\t\t}\n"; + } + else + { + ss << "\t\tif ((g == 0) || (f / g <= 0))\n" + << "\t\t{\n" + << "\t\t vOut.x = vIn.x;\n" + << "\t\t vOut.y = vIn.y;\n" + << "\t\t vOut.z = vIn.z;\n" + << "\t\t}\n"; + } + + ss << "\t\telse\n" + << "\t\t{\n" + << "\t\t vOut.x = (" << v4 << " * log((t + x2) / Zeps(t - x2)));\n" + << "\t\t vOut.y = (" << v << " * y);\n" + << "\t\t vOut.z = " << weight << " * vIn.z;\n" + << "\t\t}\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_S = -T(M_PI_2) * m_Shift;; + m_V = m_Weight * T(M_2_PI); + m_V4 = m_Weight * T(0.25) * T(M_2_PI); + } + + virtual void Random(QTIsaac& rand) override + { + m_Shift = 2 * rand.Frand01() - 1; + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + + virtual bool SetParamVal(const char* name, T val) override + { + if (!_stricmp(name, "bipolar_shift")) + { + T temp = VarFuncs::Fabsmod(T(0.5) * (val + 1)); + m_Shift = 2 * temp - 1; + Precalc(); + return true; + } + + return ParametricVariation::SetParamVal(name, val); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Shift, prefix + "bipolar_shift"));//Params. + m_Params.push_back(ParamWithName(true, &m_S, prefix + "bipolar_s"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_V, prefix + "bipolar_v")); + m_Params.push_back(ParamWithName(true, &m_V4, prefix + "bipolar_v4")); + } + +private: + T m_Shift;//Params. + T m_S;//Precalc. + T m_V; + T m_V4; +}; + +/// +/// Boarders. +/// +template +class BoardersVariation : public Variation +{ +public: + BoardersVariation(T weight = 1.0) : Variation("boarders", eVariationId::VAR_BOARDERS, weight) { } + + VARCOPY(BoardersVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T roundX = std::rint(helper.In.x); + T roundY = std::rint(helper.In.y); + T offsetX = helper.In.x - roundX; + T offsetY = helper.In.y - roundY; + + if (rand.Frand01() >= T(0.75)) + { + helper.Out.x = m_Weight * (offsetX * T(0.5) + roundX); + helper.Out.y = m_Weight * (offsetY * T(0.5) + roundY); + } + else + { + if (std::abs(offsetX) >= std::abs(offsetY)) + { + if (offsetX >= 0) + { + helper.Out.x = m_Weight * (offsetX * T(0.5) + roundX + T(0.25)); + helper.Out.y = m_Weight * (offsetY * T(0.5) + roundY + T(0.25) * offsetY / offsetX); + } + else + { + helper.Out.x = m_Weight * (offsetX * T(0.5) + roundX - T(0.25)); + helper.Out.y = m_Weight * (offsetY * T(0.5) + roundY - T(0.25) * offsetY / offsetX); + } + } + else + { + if (offsetY >= 0) + { + helper.Out.y = m_Weight * (offsetY * T(0.5) + roundY + T(0.25)); + helper.Out.x = m_Weight * (offsetX * T(0.5) + roundX + offsetX / offsetY * T(0.25)); + } + else + { + helper.Out.y = m_Weight * (offsetY * T(0.5) + roundY - T(0.25)); + helper.Out.x = m_Weight * (offsetX * T(0.5) + roundX - offsetX / offsetY * T(0.25)); + } + } + } + + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t roundX = rint(vIn.x);\n" + << "\t\treal_t roundY = rint(vIn.y);\n" + << "\t\treal_t offsetX = vIn.x - roundX;\n" + << "\t\treal_t offsetY = vIn.y - roundY;\n" + << "\n" + << "\t\tif (MwcNext01(mwc) >= (real_t)(0.75))\n" + << "\t\t{\n" + << "\t\t vOut.x = " << weight << " * fma(offsetX, (real_t)(0.5), roundX);\n" + << "\t\t vOut.y = " << weight << " * fma(offsetY, (real_t)(0.5), roundY);\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t if (fabs(offsetX) >= fabs(offsetY))\n" + << "\t\t {\n" + << "\t\t if (offsetX >= (real_t)(0.0))\n" + << "\t\t {\n" + << "\t\t vOut.x = " << weight << " * fma(offsetX, (real_t)(0.5), roundX + (real_t)(0.25));\n" + << "\t\t vOut.y = " << weight << " * (fma(offsetY, (real_t)(0.5), roundY) + (real_t)(0.25) * offsetY / offsetX);\n" + << "\t\t }\n" + << "\t\t else\n" + << "\t\t {\n" + << "\t\t vOut.x = " << weight << " * fma(offsetX, (real_t)(0.5), roundX - (real_t)(0.25));\n" + << "\t\t vOut.y = " << weight << " * (fma(offsetY, (real_t)(0.5), roundY) - (real_t)(0.25) * offsetY / offsetX);\n" + << "\t\t }\n" + << "\t\t }\n" + << "\t\t else\n" + << "\t\t {\n" + << "\t\t if (offsetY >= (real_t)(0.0))\n" + << "\t\t {\n" + << "\t\t vOut.y = " << weight << " * fma(offsetY, (real_t)(0.5), roundY + (real_t)(0.25));\n" + << "\t\t vOut.x = " << weight << " * (fma(offsetX, (real_t)(0.5), roundX) + offsetX / offsetY * (real_t)(0.25));\n" + << "\t\t }\n" + << "\t\t else\n" + << "\t\t {\n" + << "\t\t vOut.y = " << weight << " * fma(offsetY, (real_t)(0.5), roundY - (real_t)(0.25));\n" + << "\t\t vOut.x = " << weight << " * (fma(offsetX, (real_t)(0.5), roundX) - offsetX / offsetY * (real_t)(0.25));\n" + << "\t\t }\n" + << "\t\t }\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Butterfly. +/// +template +class ButterflyVariation : public Variation +{ +public: + ButterflyVariation(T weight = 1.0) : Variation("butterfly", eVariationId::VAR_BUTTERFLY, weight) { } + + VARCOPY(ButterflyVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T wx = m_Weight * T(1.3029400317411197908970256609023);//This precision came from the original. + T y2 = helper.In.y * 2; + T r = wx * std::sqrt(std::abs(helper.In.y * helper.In.x) / Zeps(SQR(helper.In.x) + SQR(y2))); + helper.Out.x = r * helper.In.x; + helper.Out.y = r * y2; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t wx = " << weight << " * (real_t)(1.3029400317411197908970256609023);\n" + << "\t\treal_t y2 = vIn.y * (real_t)(2.0);\n" + << "\t\treal_t r = wx * sqrt(fabs(vIn.y * vIn.x) / Zeps(fma(vIn.x, vIn.x, SQR(y2))));\n" + << "\n" + << "\t\tvOut.x = r * vIn.x;\n" + << "\t\tvOut.y = r * y2;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Cell. +/// +template +class CellVariation : public ParametricVariation +{ +public: + CellVariation(T weight = 1.0) : ParametricVariation("cell", eVariationId::VAR_CELL, weight) + { + Init(); + } + + PARVARCOPY(CellVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T invCellSize = 1 / m_Size; + T x = std::floor(helper.In.x * invCellSize);//Calculate input cell. Note that int cast is omitted here. See below. + T y = std::floor(helper.In.y * invCellSize); + T dx = helper.In.x - x * m_Size;//Offset from cell origin. + T dy = helper.In.y - y * m_Size; + + //Interleave cells. + if (y >= 0) + { + if (x >= 0) + { + y *= 2; + x *= 2; + } + else + { + y *= 2; + x = -(2 * x + 1); + } + } + else + { + if (x >= 0) + { + y = -(2 * y + 1); + x *= 2; + } + else + { + y = -(2 * y + 1); + x = -(2 * x + 1); + } + } + + helper.Out.x = m_Weight * (dx + x * m_Size); + helper.Out.y = -(m_Weight * (dy + y * m_Size)); + helper.Out.z = DefaultZ(helper); + } + + /// + /// Cell is very strange and will not run using integers. + /// When using floats, it at least gives some output, however + /// that output is slightly different than the CPU. But not by enough + /// to change the shape of the final image. + /// + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string size = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t invCellSize = (real_t)(1.0) / " << size << ";\n" + //Float to int, orig. + //<< "\t\tint x = (int)floor(vIn.x * invCellSize);\n" + //<< "\t\tint y = (int)floor(vIn.y * invCellSize);\n" + //For some reason, OpenCL renders nothing if these are ints, so use floats. + //Note that Cuburn also omits the usage of ints. + << "\t\treal_t x = floor(vIn.x * invCellSize);\n" + << "\t\treal_t y = floor(vIn.y * invCellSize);\n" + << "\t\treal_t dx = vIn.x - x * " << size << ";\n" + << "\t\treal_t dy = vIn.y - y * " << size << ";\n" + << "\n" + << "\t\tif (y >= 0)\n" + << "\t\t{\n" + << "\t\t if (x >= 0)\n" + << "\t\t {\n" + << "\t\t y *= 2;\n" + << "\t\t x *= 2;\n" + << "\t\t }\n" + << "\t\t else\n" + << "\t\t {\n" + << "\t\t y *= 2;\n" + << "\t\t x = -fma((real_t)(2.0), x, (real_t)(1.0));\n" + << "\t\t }\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t if (x >= 0)\n" + << "\t\t {\n" + << "\t\t y = -fma((real_t)(2.0), y, (real_t)(1.0));\n" + << "\t\t x *= 2;\n" + << "\t\t }\n" + << "\t\t else\n" + << "\t\t {\n" + << "\t\t y = -fma((real_t)(2.0), y, (real_t)(1.0));\n" + << "\t\t x = -fma((real_t)(2.0), x, (real_t)(1.0));\n" + << "\t\t }\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.x = " << weight << " * fma(x, " << size << ", dx);\n" + << "\t\tvOut.y = -(" << weight << " * fma(y, " << size << ", dy));\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Random(QTIsaac& rand) override + { + m_Size = 2 * rand.Frand01() + T(0.5); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Size, prefix + "cell_size", 1)); + } + +private: + T m_Size; +}; + +/// +/// Cpow. +/// +template +class CpowVariation : public ParametricVariation +{ +public: + CpowVariation(T weight = 1.0) : ParametricVariation("cpow", eVariationId::VAR_CPOW, weight, true, false, false, false, true) + { + Init(); + } + + PARVARCOPY(CpowVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T a = helper.m_PrecalcAtanyx; + T lnr = T(0.5) * std::log(helper.m_PrecalcSumSquares); + T angle = m_C * a + m_D * lnr + m_Ang * Floor(m_Power * rand.Frand01()); + T m = m_Weight * std::exp(m_C * lnr - m_D * a); + helper.Out.x = m * std::cos(angle); + helper.Out.y = m * std::sin(angle); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string powerR = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string powerI = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string c = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string d = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string ang = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t a = precalcAtanyx;\n" + << "\t\treal_t lnr = (real_t)(0.5) * log(precalcSumSquares);\n" + << "\t\treal_t angle = fma(" << c << ", a, fma(" << d << ", lnr, " << ang << " * floor(" << power << " * MwcNext01(mwc))));\n" + << "\t\treal_t m = " << weight << " * exp(fma(" << c << ", lnr, -(" << d << " * a)));\n" + << "\n" + << "\t\tvOut.x = m * cos(angle);\n" + << "\t\tvOut.y = m * sin(angle);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_C = m_PowerR / m_Power; + m_D = m_PowerI / m_Power; + m_Ang = 2 * T(M_PI) / m_Power; + } + + virtual void Random(QTIsaac& rand) override + { + m_PowerR = 3 * rand.Frand01(); + m_PowerI = rand.Frand01() - T(0.5); + m_Params[2].Set(5 * rand.Frand01());//Power. + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_PowerR, prefix + "cpow_r", 1));//Params. + m_Params.push_back(ParamWithName(&m_PowerI, prefix + "cpow_i")); + m_Params.push_back(ParamWithName(&m_Power, prefix + "cpow_power", 1, eParamType::INTEGER_NONZERO)); + m_Params.push_back(ParamWithName(true, &m_C, prefix + "cpow_c"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_D, prefix + "cpow_d")); + m_Params.push_back(ParamWithName(true, &m_Ang, prefix + "cpow_ang")); + } + +private: + T m_PowerR;//Params. + T m_PowerI; + T m_Power; + T m_C;//Precalc. + T m_D; + T m_Ang; +}; + +/// +/// Curve. +/// +template +class CurveVariation : public ParametricVariation +{ +public: + CurveVariation(T weight = 1.0) : ParametricVariation("curve", eVariationId::VAR_CURVE, weight) + { + Init(); + } + + PARVARCOPY(CurveVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * helper.In.x + m_XAmpV * std::exp(-helper.In.y * helper.In.y * m_XLengthV); + helper.Out.y = m_Weight * helper.In.y + m_YAmpV * std::exp(-helper.In.x * helper.In.x * m_YLengthV); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string xAmp = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string yAmp = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string xLength = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string yLength = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string xAmpV = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string yAmpV = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string xLengthV = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string yLengthV = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tvOut.x = fma(" << weight << ", vIn.x, " << xAmpV << " * exp(-vIn.y * vIn.y * " << xLengthV << "));\n" + << "\t\tvOut.y = fma(" << weight << ", vIn.y, " << yAmpV << " * exp(-vIn.x * vIn.x * " << yLengthV << "));\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_XAmpV = m_Weight * m_XAmp; + m_YAmpV = m_Weight * m_YAmp; + m_XLengthV = 1 / std::max(SQR(m_XLength), T(1e-20)); + m_YLengthV = 1 / std::max(SQR(m_YLength), T(1e-20)); + } + + virtual void Random(QTIsaac& rand) override + { + m_XAmp = 5 * (rand.Frand01() - T(0.5)); + m_YAmp = 4 * (rand.Frand01() - T(0.5)); + m_XLength = 2 * (rand.Frand01() + T(0.5)); + m_YLength = 2 * (rand.Frand01() + T(0.5)); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_XAmp, prefix + "curve_xamp"));//Params. + m_Params.push_back(ParamWithName(&m_YAmp, prefix + "curve_yamp")); + m_Params.push_back(ParamWithName(&m_XLength, prefix + "curve_xlength", 1)); + m_Params.push_back(ParamWithName(&m_YLength, prefix + "curve_ylength", 1)); + m_Params.push_back(ParamWithName(true, &m_XAmpV, prefix + "curve_xampv"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_YAmpV, prefix + "curve_yampv")); + m_Params.push_back(ParamWithName(true, &m_XLengthV, prefix + "curve_xlenv")); + m_Params.push_back(ParamWithName(true, &m_YLengthV, prefix + "curve_ylenv")); + } + +private: + T m_XAmp;//Params. + T m_YAmp; + T m_XLength; + T m_YLength; + T m_XAmpV;//Precalc. + T m_YAmpV; + T m_XLengthV; + T m_YLengthV; +}; + +/// +/// Edisc. +/// +template +class EdiscVariation : public Variation +{ +public: + EdiscVariation(T weight = 1.0) : Variation("edisc", eVariationId::VAR_EDISC, weight, true) { } + + VARCOPY(EdiscVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T tmp = helper.m_PrecalcSumSquares + 1; + T tmp2 = 2 * helper.In.x; + T r1 = std::sqrt(tmp + tmp2); + T r2 = std::sqrt(tmp - tmp2); + T xmax = Zeps((r1 + r2) * T(0.5)); + T a1 = std::log(xmax + std::sqrt(xmax - 1)); + T a2 = -std::acos(Clamp(helper.In.x / xmax, -1, 1)); + T w = m_Weight / T(11.57034632);//This is an interesting magic number. + T snv, csv, snhu, cshu; + sincos(a1, &snv, &csv); + snhu = std::sinh(a2); + cshu = std::cosh(a2); + + if (helper.In.y > 0.0) + snv = -snv; + + helper.Out.x = w * cshu * csv; + helper.Out.y = w * snhu * snv; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t tmp = precalcSumSquares + (real_t)(1.0);\n" + << "\t\treal_t tmp2 = (real_t)(2.0) * vIn.x;\n" + << "\t\treal_t r1 = sqrt(tmp + tmp2);\n" + << "\t\treal_t r2 = sqrt(tmp - tmp2);\n" + << "\t\treal_t xmax = Zeps((r1 + r2) * (real_t)(0.5));\n" + << "\t\treal_t a1 = log(xmax + sqrt(xmax - (real_t)(1.0)));\n" + << "\t\treal_t a2 = -acos(clamp(vIn.x / xmax, -(real_t)(1.0), (real_t)(1.0)));\n" + << "\t\treal_t w = " << weight << " / (real_t)(11.57034632);\n" + << "\t\treal_t snv = sin(a1);\n" + << "\t\treal_t csv = cos(a1);\n" + << "\t\treal_t snhu = sinh(a2);\n" + << "\t\treal_t cshu = cosh(a2);\n" + << "\t\tif (vIn.y > 0)\n" + << "\t\t snv = -snv;\n" + << "\t\tvOut.x = w * cshu * csv;\n" + << "\t\tvOut.y = w * snhu * snv;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Elliptic. +/// +template +class EllipticVariation : public ParametricVariation +{ +public: + EllipticVariation(T weight = 1.0) : ParametricVariation("elliptic", eVariationId::VAR_ELLIPTIC, weight, true) + { + Init(); + } + + PARVARCOPY(EllipticVariation) + + //An improved version which was posted in the Discord chat by user Claude which was helps with rounding errors. + //Note that for this to work, a "bad value" had to be changed from 1e10 and -1e10 to 1e50 and -1e50. + //For this to be correct, it must always use double. So there is no point in switching precisions when using this variation. + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + if (typeid(T) == typeid(float)) + { + T tmp = helper.m_PrecalcSumSquares + 1; + T x2 = 2 * helper.In.x; + T xmax = T(0.5) * (std::sqrt(tmp + x2) + std::sqrt(tmp - x2)); + T a = helper.In.x / xmax; + T b = 1 - a * a; + T ssx = xmax - 1; + const T w = m_WeightDivPiDiv2; + + if (b < 0) + b = 0; + else + b = std::sqrt(b); + + if (ssx < 0) + ssx = 0; + else + ssx = std::sqrt(ssx); + + helper.Out.x = w * std::atan2(a, b); + + if (helper.In.y > 0) + helper.Out.y = w * std::log(xmax + ssx); + else + helper.Out.y = -(w * std::log(xmax + ssx)); + + helper.Out.z = DefaultZ(helper); + } + else + { + double x2 = 2 * helper.In.x; + double u = helper.m_PrecalcSumSquares + x2; + double v = helper.m_PrecalcSumSquares - x2; + double xmaxm1 = 0.5 * (Sqrt1pm1(u) + Sqrt1pm1(v)); + double a = helper.In.x / (1 + xmaxm1); + double ssx = xmaxm1 < 0 ? 0 : std::sqrt(xmaxm1); + helper.Out.x = T(m_WeightDivPiDiv2 * std::asin(Clamp(a, -1.0, 1.0))); + + if (helper.In.y > 0) + helper.Out.y = T(m_WeightDivPiDiv2 * std::log1p(xmaxm1 + ssx)); + else + helper.Out.y = T(-(m_WeightDivPiDiv2 * std::log1p(xmaxm1 + ssx))); + + helper.Out.z = DefaultZ(helper); + } + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0; + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string weightDivPiDiv2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + + if (typeid(T) == typeid(float)) + { + ss << "\t{\n" + << "\t\treal_t tmp = precalcSumSquares + (real_t)(1.0);\n" + << "\t\treal_t x2 = (real_t)(2.0) * vIn.x;\n" + << "\t\treal_t xmax = (real_t)(0.5) * (sqrt(tmp + x2) + sqrt(tmp - x2));\n" + << "\t\treal_t a = vIn.x / xmax;\n" + << "\t\treal_t b = (real_t)(1.0) - a * a;\n" + << "\t\treal_t ssx = xmax - (real_t)(1.0);\n" + << "\t\tconst real_t w = " << weightDivPiDiv2 << ";\n" + << "\n" + << "\t\tif (b < 0)\n" + << "\t\t b = 0;\n" + << "\t\telse\n" + << "\t\t b = sqrt(b);\n" + << "\n" + << "\t\tif (ssx < 0)\n" + << "\t\t ssx = 0;\n" + << "\t\telse\n" + << "\t\t ssx = sqrt(ssx);\n" + << "\n" + << "\t\tvOut.x = w * atan2(a, b);\n" + << "\n" + << "\t\tif (vIn.y > 0)\n" + << "\t\t vOut.y = w * log(xmax + ssx);\n" + << "\t\telse\n" + << "\t\t vOut.y = -(w * log(xmax + ssx));\n" + << "\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + } + else + { + ss << "\t{\n" + << "\t\tdouble x2 = 2.0 * vIn.x;\n" + << "\t\tdouble u = precalcSumSquares + x2;\n" + << "\t\tdouble v = precalcSumSquares - x2;\n" + << "\t\tdouble xmaxm1 = 0.5 * (Sqrt1pm1(u) + Sqrt1pm1(v));\n" + << "\t\tdouble a = vIn.x / (1 + xmaxm1);\n" + << "\t\tdouble ssx = xmaxm1 < 0 ? 0.0 : sqrt(xmaxm1);\n" + << "\t\tvOut.x = (" << weightDivPiDiv2 << " * asin(clamp(a, (double)-1.0, (double)1.0)));\n" + << "\n" + << "\t\tif (vIn.y > 0)\n" + << "\t\t\tvOut.y = " << weightDivPiDiv2 << " * log1p(xmaxm1 + ssx);\n" + << "\t\telse\n" + << "\t\t\tvOut.y = -(" << weightDivPiDiv2 << " * log1p(xmaxm1 + ssx));\n" + << "\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + } + + return ss.str(); + } + + virtual string OpenCLFuncsString() const override + { + return + "double Sqrt1pm1(double x)\n" + "{\n" + " if (-0.0625 < x && x < 0.0625)\n" + " {\n" + " double num = 0;\n" + " double den = 0;\n" + " num += 1.0 / 32.0;\n" + " den += 1.0 / 256.0;\n" + " num *= x;\n" + " den *= x;\n" + " num += 5.0 / 16.0;\n" + " den += 5.0 / 32.0;\n" + " num *= x;\n" + " den *= x;\n" + " num += 3.0 / 4.0;\n" + " den += 15.0 / 16.0;\n" + " num *= x;\n" + " den *= x;\n" + " num += 1.0 / 2.0;\n" + " den += 7.0 / 4.0;\n" + " num *= x;\n" + " den *= x;\n" + " den += 1;\n" + " return num / den;\n" + " }\n" + "\n" + " return sqrt(1 + x) - 1;\n" + "}\n\n"; + } + + virtual void Precalc() override + { + m_WeightDivPiDiv2 = m_Weight / T(M_PI_2); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(true, &m_WeightDivPiDiv2, prefix + "elliptic_weight_div_pi_div_2"));//Precalc. + } + +private: + //An improved version which was posted in the Discord chat by user Claude which was helps with rounding errors. + //Note that for this to work, a "bad value" had to be changed from 1e10 and -1e10 to 1e50 and -1e50. + //For this to be correct, it must always use double. So there is no point in switching precisions when using this variation. + double Sqrt1pm1(double x) + { + if (-0.0625 < x && x < 0.0625) + { + double num = 0; + double den = 0; + num += 1.0 / 32; + den += 1.0 / 256; + num *= x; + den *= x; + num += 5.0 / 16; + den += 5.0 / 32; + num *= x; + den *= x; + num += 3.0 / 4; + den += 15.0 / 16; + num *= x; + den *= x; + num += 1.0 / 2; + den += 7.0 / 4; + num *= x; + den *= x; + den += 1; + return num / den; + } + + return std::sqrt(1 + x) - 1; + } + + T m_WeightDivPiDiv2;//Precalc. +}; + +/// +/// Escher. +/// +template +class EscherVariation : public ParametricVariation +{ +public: + EscherVariation(T weight = 1.0) : ParametricVariation("escher", eVariationId::VAR_ESCHER, weight, true, false, false, false, true) + { + Init(); + } + + PARVARCOPY(EscherVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T a = helper.m_PrecalcAtanyx; + T lnr = T(0.5) * std::log(helper.m_PrecalcSumSquares); + T m = m_Weight * std::exp(m_C * lnr - m_D * a); + T n = m_C * a + m_D * lnr; + helper.Out.x = m * std::cos(n); + helper.Out.y = m * std::sin(n); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string beta = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string c = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string d = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t a = precalcAtanyx;\n" + << "\t\treal_t lnr = (real_t)(0.5) * log(precalcSumSquares);\n" + << "\t\treal_t m = " << weight << " * exp(fma(" << c << ", lnr, -(" << d << " * a)));\n" + << "\t\treal_t n = fma(" << c << ", a, " << d << " * lnr);\n" + << "\n" + << "\t\tvOut.x = m * cos(n);\n" + << "\t\tvOut.y = m * sin(n);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + sincos(m_Beta, &m_D, &m_C); + m_C = T(0.5) * (1 + m_C); + m_D = T(0.5) * m_D; + } + + virtual void Random(QTIsaac& rand) override + { + SetParamVal("escher_beta", T(M_PI) * rand.Frand01()); + } + + virtual bool SetParamVal(const char* name, T val) override + { + if (!_stricmp(name, "escher_beta")) + { + m_Beta = VarFuncs::Fabsmod((val + T(M_PI)) / (2 * T(M_PI))) * 2 * T(M_PI) - T(M_PI); + Precalc(); + return true; + } + + return ParametricVariation::SetParamVal(name, val); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Beta, prefix + "escher_beta"));//Params. + m_Params.push_back(ParamWithName(true, &m_C, prefix + "escher_beta_c"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_D, prefix + "escher_beta_d")); + } + +private: + T m_Beta;//Params. + T m_C;//Precalc. + T m_D; +}; + +/// +/// Foci. +/// +template +class FociVariation : public Variation +{ +public: + FociVariation(T weight = 1.0) : Variation("foci", eVariationId::VAR_FOCI, weight) { } + + VARCOPY(FociVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T expx = std::exp(helper.In.x) * T(0.5); + T expnx = T(0.25) / Zeps(expx); + T sn, cn, tmp; + sincos(helper.In.y, &sn, &cn); + tmp = m_Weight / Zeps(expx + expnx - cn); + helper.Out.x = tmp * (expx - expnx); + helper.Out.y = tmp * sn; + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t expx = exp(vIn.x) * (real_t)(0.5);\n" + << "\t\treal_t expnx = (real_t)(0.25) / Zeps(expx);\n" + << "\t\treal_t sn = sin(vIn.y);\n" + << "\t\treal_t cn = cos(vIn.y);\n" + << "\t\treal_t tmp = Zeps(expx + expnx - cn);\n" + << "\n" + << "\t\ttmp = " << weight << " / tmp;\n" + << "\n" + << "\t\tvOut.x = tmp * (expx - expnx);\n" + << "\t\tvOut.y = tmp * sn;\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// LazySusan. +/// +template +class LazySusanVariation : public ParametricVariation +{ +public: + LazySusanVariation(T weight = 1.0) : ParametricVariation("lazysusan", eVariationId::VAR_LAZYSUSAN, weight) + { + Init(); + } + + PARVARCOPY(LazySusanVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T x = helper.In.x - m_X; + T y = helper.In.y + m_Y; + T r = std::sqrt(x * x + y * y); + + if (r < m_Weight) + { + T a = std::atan2(y, x) + m_Spin + m_Twist * (m_Weight - r); + helper.Out.x = m_Weight * (r * std::cos(a) + m_X);//Fix to make it colapse to 0 when weight is 0.//SMOULDER + helper.Out.y = m_Weight * (r * std::sin(a) - m_Y); + } + else + { + r = 1 + m_Space / Zeps(r); + helper.Out.x = m_Weight * (r * x + m_X);//Fix to make it colapse to 0 when weight is 0.//SMOULDER + helper.Out.y = m_Weight * (r * y - m_Y); + } + + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string spin = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string space = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string twist = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string x = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t x = vIn.x - " << x << ";\n" + << "\t\treal_t y = vIn.y + " << y << ";\n" + << "\t\treal_t r = sqrt(fma(x, x, SQR(y)));\n" + << "\n" + << "\t\tif (r < " << weight << ")\n" + << "\t\t{\n" + << "\t\t real_t a = fma(" << twist << ", " << weight << " - r, atan2(y, x) + " << spin << ");\n" + << "\n" + << "\t\t vOut.x = " << weight << " * fma(r, cos(a), " << x << ");\n" + << "\t\t vOut.y = " << weight << " * fma(r, sin(a), -" << y << ");\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t r = (real_t)(1.0) + " << space << " / Zeps(r);\n" + << "\n" + << "\t\t vOut.x = " << weight << " * fma(r, x, " << x << ");\n" + << "\t\t vOut.y = " << weight << " * fma(r, y, -" << y << ");\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + + virtual bool SetParamVal(const char* name, T val) override + { + if (!_stricmp(name, "lazysusan_spin")) + { + m_Spin = VarFuncs::Fabsmod(val / T(M_2PI)) * T(M_2PI); + this->Precalc(); + return true; + } + + return ParametricVariation::SetParamVal(name, val); + } + + virtual void Random(QTIsaac& rand) override + { + m_X = 2 * rand.Frand11(); + m_Y = 2 * rand.Frand11(); + m_Spin = T(M_PI) * rand.Frand11(); + m_Space = 2 * rand.Frand11(); + m_Twist = 2 * rand.Frand11(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Spin, prefix + "lazysusan_spin", T(M_PI))); + m_Params.push_back(ParamWithName(&m_Space, prefix + "lazysusan_space")); + m_Params.push_back(ParamWithName(&m_Twist, prefix + "lazysusan_twist")); + m_Params.push_back(ParamWithName(&m_X, prefix + "lazysusan_x")); + m_Params.push_back(ParamWithName(&m_Y, prefix + "lazysusan_y")); + } + +private: + T m_Spin; + T m_Space; + T m_Twist; + T m_X; + T m_Y; +}; + +/// +/// Loonie. +/// +template +class LoonieVariation : public ParametricVariation +{ +public: + LoonieVariation(T weight = 1.0) : ParametricVariation("loonie", eVariationId::VAR_LOONIE, weight, true) + { + Init(); + } + + PARVARCOPY(LoonieVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + if (helper.m_PrecalcSumSquares < m_W2 && helper.m_PrecalcSumSquares != 0) + { + T r = m_Weight * std::sqrt((m_W2 / helper.m_PrecalcSumSquares) - 1); + helper.Out.x = r * helper.In.x; + helper.Out.y = r * helper.In.y; + } + else + { + helper.Out.x = m_Weight * helper.In.x; + helper.Out.y = m_Weight * helper.In.y; + } + + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string w2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tif (precalcSumSquares < " << w2 << " && precalcSumSquares != 0)\n" + << "\t\t{\n" + << "\t\t real_t r = " << weight << " * sqrt((" << w2 << " / precalcSumSquares) - (real_t)(1.0));\n" + << "\t\t vOut.x = r * vIn.x;\n" + << "\t\t vOut.y = r * vIn.y;\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t vOut.x = " << weight << " * vIn.x;\n" + << "\t\t vOut.y = " << weight << " * vIn.y;\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_W2 = SQR(m_Weight); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(true, &m_W2, prefix + "loonie_w2"));//Precalc. + } + +private: + T m_W2;//Precalc. +}; + +/// +/// Modulus. +/// +template +class ModulusVariation : public ParametricVariation +{ +public: + ModulusVariation(T weight = 1.0) : ParametricVariation("modulus", eVariationId::VAR_MODULUS, weight) + { + Init(); + } + + PARVARCOPY(ModulusVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + if (helper.In.x > m_X) + helper.Out.x = m_Weight * (-m_X + fmod(helper.In.x + m_X, m_XRange)); + else if (helper.In.x < -m_X) + helper.Out.x = m_Weight * (m_X - fmod(m_X - helper.In.x, m_XRange)); + else + helper.Out.x = m_Weight * helper.In.x; + + if (helper.In.y > m_Y) + helper.Out.y = m_Weight * (-m_Y + fmod(helper.In.y + m_Y, m_YRange)); + else if (helper.In.y < -m_Y) + helper.Out.y = m_Weight * (m_Y - fmod(m_Y - helper.In.y, m_YRange)); + else + helper.Out.y = m_Weight * helper.In.y; + + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string x = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string xr = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string yr = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tif (vIn.x > " << x << ")\n" + << "\t\t vOut.x = " << weight << " * (-" << x << " + fmod(vIn.x + " << x << ", " << xr << "));\n" + << "\t\telse if (vIn.x < -" << x << ")\n" + << "\t\t vOut.x = " << weight << " * ( " << x << " - fmod(" << x << " - vIn.x, " << xr << "));\n" + << "\t\telse\n" + << "\t\t vOut.x = " << weight << " * vIn.x;\n" + << "\n" + << "\t\tif (vIn.y > " << y << ")\n" + << "\t\t vOut.y = " << weight << " * (-" << y << " + fmod(vIn.y + " << y << ", " << yr << "));\n" + << "\t\telse if (vIn.y < -" << y << ")\n" + << "\t\t vOut.y = " << weight << " * ( " << y << " - fmod(" << y << " - vIn.y, " << yr << "));\n" + << "\t\telse\n" + << "\t\t vOut.y = " << weight << " * vIn.y;\n" + << "\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_XRange = 2 * m_X; + m_YRange = 2 * m_Y; + } + + virtual void Random(QTIsaac& rand) override + { + m_X = rand.Frand11(); + m_Y = rand.Frand11(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_X, prefix + "modulus_x", 1));//Params. + m_Params.push_back(ParamWithName(&m_Y, prefix + "modulus_y", 1)); + m_Params.push_back(ParamWithName(true, &m_XRange, prefix + "modulus_xrange"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_YRange, prefix + "modulus_yrange")); + } + +private: + T m_X;//Params. + T m_Y; + T m_XRange;//Precalc. + T m_YRange; +}; + +/// +/// Oscilloscope. +/// +template +class OscilloscopeVariation : public ParametricVariation +{ +public: + OscilloscopeVariation(T weight = 1.0) : ParametricVariation("oscilloscope", eVariationId::VAR_OSCILLOSCOPE, weight) + { + Init(); + } + + PARVARCOPY(OscilloscopeVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T t; + + if (m_Damping == 0.0) + t = m_Amplitude * std::cos(m_2PiFreq * helper.In.x) + m_Separation; + else + t = m_Amplitude * std::exp(-std::abs(helper.In.x) * m_Damping) * std::cos(m_2PiFreq * helper.In.x) + m_Separation; + + if (std::abs(helper.In.y) <= t) + { + helper.Out.x = m_Weight * helper.In.x; + helper.Out.y = -(m_Weight * helper.In.y); + } + else + { + helper.Out.x = m_Weight * helper.In.x; + helper.Out.y = m_Weight * helper.In.y; + } + + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string separation = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string frequency = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string amplitude = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string damping = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string tpf = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t t;\n" + << "\n" + << "\t\tif (" << damping << " == (real_t)(0.0))\n" + << "\t\t t = fma(" << amplitude << ", cos(" << tpf << " * vIn.x), " << separation << ");\n" + << "\t\telse\n" + << "\t\t t = fma(" << amplitude << ", exp(-fabs(vIn.x) * " << damping << ") * cos(" << tpf << " * vIn.x), " << separation << ");\n" + << "\n" + << "\t\tif (fabs(vIn.y) <= t)\n" + << "\t\t{\n" + << "\t\t vOut.x = " << weight << " * vIn.x;\n" + << "\t\t vOut.y = -(" << weight << " * vIn.y);\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t vOut.x = " << weight << " * vIn.x;\n" + << "\t\t vOut.y = " << weight << " * vIn.y;\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_2PiFreq = m_Frequency * T(M_2PI); + } + + virtual void Random(QTIsaac& rand) override + { + m_Separation = 1 + rand.Frand11(); + m_Frequency = T(M_PI) * rand.Frand11(); + m_Amplitude = 1 + 2 * rand.Frand01(); + m_Damping = rand.Frand01(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Separation, prefix + "oscilloscope_separation", 1));//Params. + m_Params.push_back(ParamWithName(&m_Frequency, prefix + "oscilloscope_frequency", T(M_PI))); + m_Params.push_back(ParamWithName(&m_Amplitude, prefix + "oscilloscope_amplitude", 1)); + m_Params.push_back(ParamWithName(&m_Damping, prefix + "oscilloscope_damping")); + m_Params.push_back(ParamWithName(true, &m_2PiFreq, prefix + "oscilloscope_2pifreq"));//Precalc. + } + +private: + T m_Separation;//Params. + T m_Frequency; + T m_Amplitude; + T m_Damping; + T m_2PiFreq;//Precalc. +}; + +/// +/// Oscilloscope2. +/// By dark-beam. +/// +template +class Oscilloscope2Variation : public ParametricVariation +{ +public: + Oscilloscope2Variation(T weight = 1.0) : ParametricVariation("oscilloscope2", eVariationId::VAR_OSCILLOSCOPE2, weight) + { + Init(); + } + + PARVARCOPY(Oscilloscope2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T t; + T pt = m_Perturbation * std::sin(m_Tpf2 * helper.In.y); + + if (!m_Damping) + t = m_Amplitude * std::cos(m_Tpf * helper.In.x + pt) + m_Separation; + else + t = m_Amplitude * std::exp(-std::abs(helper.In.x) * m_Damping) * std::cos(m_Tpf * helper.In.x + pt) + m_Separation; + + if (std::abs(helper.In.y) <= t) + { + helper.Out.x = -(m_Weight * helper.In.x); + helper.Out.y = -(m_Weight * helper.In.y); + } + else + { + helper.Out.x = m_Weight * helper.In.x; + helper.Out.y = m_Weight * helper.In.y; + } + + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string separation = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string frequencyx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string frequencyy = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string amplitude = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string perturbation = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string damping = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string tpf = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string tpf2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t t;\n" + << "\t\treal_t pt = " << perturbation << " * sin(" << tpf2 << " * vIn.y);\n" + << "\n" + << "\t\tif (!" << damping << ")\n" + << "\t\t t = fma(" << amplitude << ", cos(fma(" << tpf << ", vIn.x, pt)), " << separation << ");\n" + << "\t\telse\n" + << "\t\t t = fma(" << amplitude << ", exp(-fabs(vIn.x) * " << damping << ") * cos(fma(" << tpf << ", vIn.x, pt)), " << separation << ");\n" + << "\n" + << "\t\tif (fabs(vIn.y) <= t)\n" + << "\t\t{\n" + << "\t\t vOut.x = -(" << weight << " * vIn.x);\n" + << "\t\t vOut.y = -(" << weight << " * vIn.y);\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t vOut.x = " << weight << " * vIn.x;\n" + << "\t\t vOut.y = " << weight << " * vIn.y;\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Tpf = M_2PI * m_FrequencyX; + m_Tpf2 = M_2PI * m_FrequencyY; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Separation, prefix + "oscilloscope2_separation", 1, eParamType::REAL, 0));//Params. + m_Params.push_back(ParamWithName(&m_FrequencyX, prefix + "oscilloscope2_frequencyx", T(M_PI))); + m_Params.push_back(ParamWithName(&m_FrequencyY, prefix + "oscilloscope2_frequencyy", T(M_PI))); + m_Params.push_back(ParamWithName(&m_Amplitude, prefix + "oscilloscope2_amplitude", 1)); + m_Params.push_back(ParamWithName(&m_Perturbation, prefix + "oscilloscope2_perturbation", 1)); + m_Params.push_back(ParamWithName(&m_Damping, prefix + "oscilloscope2_damping", 0, eParamType::INTEGER, 0, 1)); + m_Params.push_back(ParamWithName(true, &m_Tpf, prefix + "oscilloscope2_tpf"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Tpf2, prefix + "oscilloscope2_tpf2")); + } + +private: + T m_Separation;//Params. + T m_FrequencyX; + T m_FrequencyY; + T m_Amplitude; + T m_Perturbation; + T m_Damping; + T m_Tpf;//Precalc. + T m_Tpf2; +}; + +/// +/// Polar2. +/// +template +class Polar2Variation : public ParametricVariation +{ +public: + Polar2Variation(T weight = 1.0) : ParametricVariation("polar2", eVariationId::VAR_POLAR2, weight, true, false, false, true) + { + Init(); + } + + PARVARCOPY(Polar2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Vvar * helper.m_PrecalcAtanxy; + helper.Out.y = m_Vvar2 * std::log(helper.m_PrecalcSumSquares); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string vvar = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string vvar2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tvOut.x = " << vvar << " * precalcAtanxy;\n" + << "\t\tvOut.y = " << vvar2 << " * log(precalcSumSquares);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Vvar = m_Weight / T(M_PI); + m_Vvar2 = m_Vvar * T(0.5); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(true, &m_Vvar, prefix + "polar2_vvar"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Vvar2, prefix + "polar2_vvar2")); + } + +private: + T m_Vvar; + T m_Vvar2; +}; + +/// +/// Popcorn2. +/// +template +class Popcorn2Variation : public ParametricVariation +{ +public: + Popcorn2Variation(T weight = 1.0) : ParametricVariation("popcorn2", eVariationId::VAR_POPCORN2, weight) + { + Init(); + } + + PARVARCOPY(Popcorn2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * (helper.In.x + m_X * std::sin(SafeTan(helper.In.y * m_C))); + helper.Out.y = m_Weight * (helper.In.y + m_Y * std::sin(SafeTan(helper.In.x * m_C))); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string x = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string c = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * fma(" << x << ", sin(tan(vIn.y * " << c << ")), vIn.x);\n" + << "\t\tvOut.y = " << weight << " * fma(" << y << ", sin(tan(vIn.x * " << c << ")), vIn.y);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Random(QTIsaac& rand) override + { + m_X = T(0.2) + rand.Frand01(); + m_Y = T(0.2) * rand.Frand01(); + m_C = 5 * rand.Frand01(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_X, prefix + "popcorn2_x", T(0.1))); + m_Params.push_back(ParamWithName(&m_Y, prefix + "popcorn2_y", T(0.1))); + m_Params.push_back(ParamWithName(&m_C, prefix + "popcorn2_c", 3)); + } + +private: + T m_X; + T m_Y; + T m_C; +}; + +/// +/// Scry. +/// Note that scry does not multiply by weight, but as the +/// values still approach 0 as the weight approaches 0, it +/// should be ok. +/// +template +class ScryVariation : public ParametricVariation +{ +public: + ScryVariation(T weight = 1.0) : ParametricVariation("scry", eVariationId::VAR_SCRY, weight, true, true) + { + Init(); + } + + PARVARCOPY(ScryVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T t = helper.m_PrecalcSumSquares; + T r = 1 / Zeps(helper.m_PrecalcSqrtSumSquares * (t + m_InvWeight)); + helper.Out.x = helper.In.x * r; + helper.Out.y = helper.In.y * r; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + int i = 0; + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string invWeight = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t t = precalcSumSquares;\n" + << "\t\treal_t r = (real_t)(1.0) / Zeps(precalcSqrtSumSquares * (t + " << invWeight << "));\n" + << "\n" + << "\t\tvOut.x = vIn.x * r;\n" + << "\t\tvOut.y = vIn.y * r;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + + virtual void Precalc() override + { + m_InvWeight = 1 / Zeps(m_Weight); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(true, &m_InvWeight, prefix + "scry_inv_weight"));//Precalcs only, no params. + } + +private: + T m_InvWeight;//Precalcs only, no params. +}; + +/// +/// scry2. +/// By dark-beam, modified by tatasz to increase the speed. +/// +template +class Scry2Variation : public ParametricVariation +{ +public: + Scry2Variation(T weight = 1.0) : ParametricVariation("scry2", eVariationId::VAR_SCRY2, weight, true) + { + Init(); + } + + PARVARCOPY(Scry2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r2 = helper.m_PrecalcSumSquares; + T s = 1 / Zeps(std::sqrt(r2) * (r2 + 1)); + T newX = helper.In.x * s; + T newY = helper.In.y * s; + T dang = (std::atan2(newY, newX) + T(M_PI)) / m_2PiOverPower; + T rad = std::sqrt(SQR(newX) + SQR(newY)); + T zang1 = T(Floor(dang)); + T xang1 = dang - zang1; + T xang2 = xang1 > 0.5 ? 1 - xang1 : xang1; + T zang = xang1 > 0.5 ? zang1 + 1 : zang1; + T sign = T(xang1 > 0.5 ? -1 : 1); + T xang = std::atan(xang2 * std::tan(m_2PiOverPower * T(0.5)) * 2) / m_2PiOverPower; + T coeff = 1 / std::cos(xang * m_2PiOverPower); + T ang = (zang + sign * xang) * m_2PiOverPower - T(M_PI); + helper.Out.x = m_Weight * coeff * rad * std::cos(ang); + helper.Out.y = m_Weight * coeff * rad * std::sin(ang); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + int i = 0; + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string twopioverpower = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t r2 = precalcSumSquares;\n" + << "\t\treal_t s = 1 / Zeps(sqrt(r2) * (r2 + 1));\n" + << "\t\treal_t newX = vIn.x * s;\n" + << "\t\treal_t newY = vIn.y * s;\n" + << "\t\treal_t dang = (atan2(newY, newX) + MPI) / " << twopioverpower << ";\n" + << "\t\treal_t rad = sqrt(SQR(newX) + SQR(newY));\n" + << "\t\treal_t zang1 = floor(dang);\n" + << "\t\treal_t xang1 = dang - zang1;\n" + << "\t\treal_t xang2 = xang1 > 0.5 ? 1 - xang1 : xang1;\n" + << "\t\treal_t zang = xang1 > 0.5 ? zang1 + 1 : zang1;\n" + << "\t\treal_t sign = xang1 > 0.5 ? -1.0 : 1.0;\n" + << "\t\treal_t xang = atan(xang2 * tan(" << twopioverpower << " * 0.5) * 2) / " << twopioverpower << ";\n" + << "\t\treal_t coeff = 1 / cos(xang * " << twopioverpower << ");\n" + << "\t\treal_t ang = (zang + sign * xang) * " << twopioverpower << " - MPI;\n" + << "\t\tvOut.x = " << weight << " * coeff * rad * cos(ang);\n" + << "\t\tvOut.y = " << weight << " * coeff * rad * sin(ang);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + + virtual void Precalc() override + { + m_2PiOverPower = M_2PI / Zeps(m_Power); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Power, prefix + "scry2_power", 4)); + m_Params.push_back(ParamWithName(true, &m_2PiOverPower, prefix + "scry2_2pi_over_power"));//Precalc. + } + +private: + T m_Power; + T m_2PiOverPower;//Precalc. +}; + +/// +/// Separation. +/// +template +class SeparationVariation : public ParametricVariation +{ +public: + SeparationVariation(T weight = 1.0) : ParametricVariation("separation", eVariationId::VAR_SEPARATION, weight) + { + Init(); + } + + PARVARCOPY(SeparationVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + if (helper.In.x > 0.0) + helper.Out.x = m_Weight * (std::sqrt(SQR(helper.In.x) + m_XX) - helper.In.x * m_XInside); + else + helper.Out.x = -(m_Weight * (std::sqrt(SQR(helper.In.x) + m_XX) + helper.In.x * m_XInside)); + + if (helper.In.y > 0.0) + helper.Out.y = m_Weight * (std::sqrt(SQR(helper.In.y) + m_YY) - helper.In.y * m_YInside); + else + helper.Out.y = -(m_Weight * (std::sqrt(SQR(helper.In.y) + m_YY) + helper.In.y * m_YInside)); + + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string x = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string xInside = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string yInside = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string xx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string yy = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tif (vIn.x > (real_t)(0.0))\n" + << "\t\t vOut.x = " << weight << " * (sqrt(fma(vIn.x, vIn.x, " << xx << ")) - vIn.x * " << xInside << ");\n" + << "\t\telse\n" + << "\t\t vOut.x = -(" << weight << " * fma(vIn.x, " << xInside << ", sqrt(fma(vIn.x, vIn.x, " << xx << "))));\n" + << "\n" + << "\t\tif (vIn.y > (real_t)(0.0))\n" + << "\t\t vOut.y = " << weight << " * (sqrt(fma(vIn.y, vIn.y, " << yy << ")) - vIn.y * " << yInside << ");\n" + << "\t\telse\n" + << "\t\t vOut.y = -(" << weight << " * fma(vIn.y, " << yInside << ", sqrt(fma(vIn.y, vIn.y, " << yy << "))));\n" + << "\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_XX = SQR(m_X); + m_YY = SQR(m_Y); + } + + virtual void Random(QTIsaac& rand) override + { + m_X = 1 + rand.Frand11(); + m_XInside = 1 + rand.Frand11(); + m_Y = rand.Frand11(); + m_YInside = rand.Frand11(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_X, prefix + "separation_x", 1));//Params. + m_Params.push_back(ParamWithName(&m_XInside, prefix + "separation_xinside")); + m_Params.push_back(ParamWithName(&m_Y, prefix + "separation_y", 1)); + m_Params.push_back(ParamWithName(&m_YInside, prefix + "separation_yinside")); + m_Params.push_back(ParamWithName(true, &m_XX, prefix + "separation_xx"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_YY, prefix + "separation_yy")); + } + +private: + T m_X;//Params. + T m_XInside; + T m_Y; + T m_YInside; + T m_XX;//Precalc. + T m_YY; +}; + +/// +/// Split. +/// +template +class SplitVariation : public ParametricVariation +{ +public: + SplitVariation(T weight = 1.0) : ParametricVariation("split", eVariationId::VAR_SPLIT, weight) + { + Init(); + } + + PARVARCOPY(SplitVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + if (std::cos(helper.In.y * m_YAng) >= 0) + helper.Out.x = m_Weight * helper.In.x; + else + helper.Out.x = -(m_Weight * helper.In.x); + + if (std::cos(helper.In.x * m_XAng) >= 0) + helper.Out.y = m_Weight * helper.In.y; + else + helper.Out.y = -(m_Weight * helper.In.y); + + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string xSize = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string ySize = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string xAng = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string yAng = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tif (cos(vIn.y * " << yAng << ") >= 0)\n" + << "\t\t vOut.x = " << weight << " * vIn.x;\n" + << "\t\telse\n" + << "\t\t vOut.x = -(" << weight << " * vIn.x);\n" + << "\n" + << "\t\tif (cos(vIn.x * " << xAng << ") >= 0)\n" + << "\t\t vOut.y = " << weight << " * vIn.y;\n" + << "\t\telse\n" + << "\t\t vOut.y = -(" << weight << " * vIn.y);\n" + << "\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_XAng = T(M_PI) * m_XSize; + m_YAng = T(M_PI) * m_YSize; + } + + virtual void Random(QTIsaac& rand) override + { + m_XSize = rand.Frand11(); + m_YSize = rand.Frand11(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_XSize, prefix + "split_xsize", T(0.5)));//Params. + m_Params.push_back(ParamWithName(&m_YSize, prefix + "split_ysize", T(0.5))); + m_Params.push_back(ParamWithName(true, &m_XAng, prefix + "split_xang"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_YAng, prefix + "split_yang")); + } + +private: + T m_XSize;//Params. + T m_YSize; + T m_XAng;//Precalc. + T m_YAng; +}; + +/// +/// Splits. +/// +template +class SplitsVariation : public ParametricVariation +{ +public: + SplitsVariation(T weight = 1.0) : ParametricVariation("splits", eVariationId::VAR_SPLITS, weight) + { + Init(); + } + + PARVARCOPY(SplitsVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + if (helper.In.x >= 0) + helper.Out.x = m_Weight * (helper.In.x + m_X); + else + helper.Out.x = m_Weight * (helper.In.x - m_X); + + if (helper.In.y >= 0) + helper.Out.y = m_Weight * (helper.In.y + m_Y); + else + helper.Out.y = m_Weight * (helper.In.y - m_Y); + + helper.Out.z = m_Weight * helper.In.z;//Original from flam3 does not have this, but the apo implementation does, so use Apo since it's more recent. + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string x = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tif (vIn.x >= 0)\n" + << "\t\t vOut.x = " << weight << " * (vIn.x + " << x << ");\n" + << "\t\telse\n" + << "\t\t vOut.x = " << weight << " * (vIn.x - " << x << ");\n" + << "\n" + << "\t\tif (vIn.y >= 0)\n" + << "\t\t vOut.y = " << weight << " * (vIn.y + " << y << ");\n" + << "\t\telse\n" + << "\t\t vOut.y = " << weight << " * (vIn.y - " << y << ");\n" + << "\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Random(QTIsaac& rand) override + { + m_X = rand.Frand11(); + m_Y = rand.Frand11(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_X, prefix + "splits_x")); + m_Params.push_back(ParamWithName(&m_Y, prefix + "splits_y")); + } + +private: + T m_X; + T m_Y; +}; + +/// +/// Stripes. +/// +template +class StripesVariation : public ParametricVariation +{ +public: + StripesVariation(T weight = 1.0) : ParametricVariation("stripes", eVariationId::VAR_STRIPES, weight) + { + Init(); + } + + PARVARCOPY(StripesVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T roundx = T(int(helper.In.x >= 0 ? (helper.In.x + T(0.5)) : (helper.In.x - T(0.5)))); + T offsetx = helper.In.x - roundx; + helper.Out.x = m_Weight * (offsetx * (1 - m_Space) + roundx); + helper.Out.y = m_Weight * (helper.In.y + offsetx * offsetx * m_Warp); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string space = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string warp = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t roundx = (real_t)(int)(vIn.x >= 0 ? (vIn.x + (real_t)(0.5)) : (vIn.x - (real_t)(0.5)));\n" + << "\t\treal_t offsetx = vIn.x - roundx;\n" + << "\n" + << "\t\tvOut.x = " << weight << " * fma(offsetx, (real_t)(1.0) - " << space << ", roundx);\n" + << "\t\tvOut.y = " << weight << " * fma(SQR(offsetx), " << warp << ", vIn.y);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Random(QTIsaac& rand) override + { + m_Params[0].Set(rand.Frand01());//Space. + m_Params[1].Set(5 * rand.Frand01());//Warp. + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Space, prefix + "stripes_space", T(0.5), eParamType::REAL, T(0.5), 5)); + m_Params.push_back(ParamWithName(&m_Warp, prefix + "stripes_warp")); + } + +private: + T m_Space; + T m_Warp; +}; + +/// +/// Wedge. +/// +template +class WedgeVariation : public ParametricVariation +{ +public: + WedgeVariation(T weight = 1.0) : ParametricVariation("wedge", eVariationId::VAR_WEDGE, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(WedgeVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = helper.m_PrecalcSqrtSumSquares; + T a = helper.m_PrecalcAtanyx + m_Swirl * r; + T c = T(Floor((m_Count * a + T(M_PI)) * T(M_1_PI) * T(0.5))); + a = a * m_CompFac + c * m_Angle; + r = m_Weight * (r + m_Hole); + helper.Out.x = r * std::cos(a); + helper.Out.y = r * std::sin(a); + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string angle = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string hole = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string count = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string swirl = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string compFac = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t r = precalcSqrtSumSquares;\n" + << "\t\treal_t a = fma(" << swirl << ", r, precalcAtanyx);\n" + << "\t\treal_t c = floor(fma(" << count << ", a, MPI) * M1PI * (real_t)(0.5));\n" + << "\n" + << "\t\ta = fma(a, " << compFac << ", c * " << angle << ");\n" + << "\t\tr = " << weight << " * (r + " << hole << ");\n" + << "\t\tvOut.x = r * cos(a);\n" + << "\t\tvOut.y = r * sin(a);\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_CompFac = 1 - m_Angle * m_Count * T(M_1_PI) * T(0.5); + } + + virtual void Random(QTIsaac& rand) override + { + m_Angle = T(M_PI) * rand.Frand01(); + m_Hole = T(0.5) * rand.Frand11(); + m_Count = T(Floor(5 * rand.Frand01())) + 1; + m_Swirl = rand.Frand01(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Angle, prefix + "wedge_angle", T(M_PI_2)));//Params. + m_Params.push_back(ParamWithName(&m_Hole, prefix + "wedge_hole")); + m_Params.push_back(ParamWithName(&m_Count, prefix + "wedge_count", 2, eParamType::INTEGER, 1)); + m_Params.push_back(ParamWithName(&m_Swirl, prefix + "wedge_swirl")); + m_Params.push_back(ParamWithName(true, &m_CompFac, prefix + "wedge_compfac"));//Precalc. + } + +private: + T m_Angle;//Params. + T m_Hole; + T m_Count; + T m_Swirl; + T m_CompFac;//Precalc. +}; + +/// +/// Wedge julia. +/// +template +class WedgeJuliaVariation : public ParametricVariation +{ +public: + WedgeJuliaVariation(T weight = 1.0) : ParametricVariation("wedge_julia", eVariationId::VAR_WEDGE_JULIA, weight, true, false, false, false, true) + { + Init(); + } + + PARVARCOPY(WedgeJuliaVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = m_Weight * std::pow(helper.m_PrecalcSumSquares, m_Cn); + int tRand = int(m_Rn * rand.Frand01()); + T a = (helper.m_PrecalcAtanyx + M_2PI * tRand) / m_Power; + T c = T(Floor((m_Count * a + T(M_PI)) * T(M_1_PI) * T(0.5))); + a = a * m_Cf + c * m_Angle; + helper.Out.x = r * std::cos(a); + helper.Out.y = r * std::sin(a); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string angle = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Params. + string count = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string dist = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string rn = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Precalc. + string cn = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string cf = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t r = " << weight << " * pow(precalcSumSquares, " << cn << ");\n" + << "\t\tint tRand = (int)(" << rn << " * MwcNext01(mwc));\n" + << "\t\treal_t a = fma(M_2PI, (real_t)tRand, precalcAtanyx) / " << power << ";\n" + << "\t\treal_t c = floor(fma(" << count << ", a, MPI) * M1PI * (real_t)(0.5));\n" + << "\n" + << "\t\ta = fma(a, " << cf << ", c * " << angle << ");\n" + << "\t\tvOut.x = r * cos(a);\n" + << "\t\tvOut.y = r * sin(a);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Cf = 1 - m_Angle * m_Count * T(M_1_PI) * T(0.5); + m_Rn = std::abs(m_Power); + m_Cn = m_Dist / m_Power / 2; + } + + virtual void Random(QTIsaac& rand) override + { + m_Power = T(int(5 * rand.Frand01() + 2)); + m_Dist = 1; + m_Count = T(int(3 * rand.Frand01() + 1)); + m_Angle = T(M_PI) * rand.Frand01(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Angle, prefix + "wedge_julia_angle"));//Params. + m_Params.push_back(ParamWithName(&m_Count, prefix + "wedge_julia_count", 1)); + m_Params.push_back(ParamWithName(&m_Power, prefix + "wedge_julia_power", 1)); + m_Params.push_back(ParamWithName(&m_Dist, prefix + "wedge_julia_dist")); + m_Params.push_back(ParamWithName(true, &m_Rn, prefix + "wedge_julia_rn"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Cn, prefix + "wedge_julia_cn")); + m_Params.push_back(ParamWithName(true, &m_Cf, prefix + "wedge_julia_cf")); + } + +private: + T m_Angle;//Params. + T m_Count; + T m_Power; + T m_Dist; + T m_Rn;//Precalc. + T m_Cn; + T m_Cf; +}; + +/// +/// Wedge sph. +/// +template +class WedgeSphVariation : public ParametricVariation +{ +public: + WedgeSphVariation(T weight = 1.0) : ParametricVariation("wedge_sph", eVariationId::VAR_WEDGE_SPH, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(WedgeSphVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = 1 / Zeps(helper.m_PrecalcSqrtSumSquares); + T a = helper.m_PrecalcAtanyx + m_Swirl * r; + auto c = Floor((m_Count * a + T(M_PI)) * m_C12Pi); + a = a * m_CompFac + c * m_Angle; + T temp = m_Weight * (r + m_Hole); + helper.Out.x = temp * std::cos(a); + helper.Out.y = temp * std::sin(a); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string angle = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string count = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string hole = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string swirl = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string c12pi = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string compfac = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t r = (real_t)(1.0) / Zeps(precalcSqrtSumSquares);\n" + << "\t\treal_t a = fma(" << swirl << ", r, precalcAtanyx);\n" + << "\t\treal_t c = floor(fma(" << count << ", a, MPI) * " << c12pi << "); \n" + << "\n" + << "\t\ta = fma(a, " << compfac << ", c * " << angle << ");\n" + << "\t\treal_t temp = " << weight << " * (r + " << hole << ");\n" + << "\t\tvOut.x = temp * cos(a);\n" + << "\t\tvOut.y = temp * sin(a);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + + virtual void Random(QTIsaac& rand) override + { + m_Angle = T(M_PI) * rand.Frand01(); + m_Count = T(Floor(5 * rand.Frand01())) + 1; + m_Hole = T(0.5) * rand.Frand11(); + m_Swirl = rand.Frand01(); + } + + virtual void Precalc() override + { + m_C12Pi = T(M_1_PI) / 2; + m_CompFac = 1 - m_Angle * m_Count * m_C12Pi; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Angle, prefix + "wedge_sph_angle", T(M_PI_2))); + m_Params.push_back(ParamWithName(&m_Count, prefix + "wedge_sph_count", 2, eParamType::INTEGER, 1)); + m_Params.push_back(ParamWithName(&m_Hole, prefix + "wedge_sph_hole")); + m_Params.push_back(ParamWithName(&m_Swirl, prefix + "wedge_sph_swirl")); + m_Params.push_back(ParamWithName(true, &m_C12Pi, prefix + "wedge_sph_c1_2pi")); + m_Params.push_back(ParamWithName(true, &m_CompFac, prefix + "wedge_sph_comp_fac")); + } + +private: + T m_Angle; + T m_Count; + T m_Hole; + T m_Swirl; + T m_C12Pi;//Precalc. + T m_CompFac; +}; + +/// +/// Whorl. +/// +template +class WhorlVariation : public ParametricVariation +{ +public: + WhorlVariation(T weight = 1.0) : ParametricVariation("whorl", eVariationId::VAR_WHORL, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(WhorlVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T a, r = helper.m_PrecalcSqrtSumSquares; + + if (r < m_Weight) + a = helper.m_PrecalcAtanyx + m_Inside / (m_Weight - r); + else + a = helper.m_PrecalcAtanyx + m_Outside / Zeps(m_Weight - r); + + helper.Out.x = m_Weight * r * std::cos(a); + helper.Out.y = m_Weight * r * std::sin(a); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string inside = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string outside = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t a;\n" + << "\t\treal_t r = precalcSqrtSumSquares;\n" + << "\n" + << "\t\tif (r < " << weight << ")\n" + << "\t\t a = precalcAtanyx + " << inside << " / (" << weight << " - r);\n" + << "\t\telse\n" + << "\t\t a = precalcAtanyx + " << outside << " / Zeps(" << weight << " - r);\n" + << "\n" + << "\t\tvOut.x = (" << weight << " * r * cos(a));\n" + << "\t\tvOut.y = (" << weight << " * r * sin(a));\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + + virtual void Random(QTIsaac& rand) override + { + m_Inside = rand.Frand01(); + m_Outside = rand.Frand01(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Inside, prefix + "whorl_inside", 1)); + m_Params.push_back(ParamWithName(&m_Outside, prefix + "whorl_outside", 1)); + } + +private: + T m_Inside; + T m_Outside; +}; + +/// +/// Waves. +/// +template +class Waves2Variation : public ParametricVariation +{ +public: + Waves2Variation(T weight = 1.0) : ParametricVariation("waves2", eVariationId::VAR_WAVES2, weight, true, true) + { + Init(); + } + + PARVARCOPY(Waves2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * (helper.In.x + m_ScaleX * std::sin(helper.In.y * m_FreqX)); + helper.Out.y = m_Weight * (helper.In.y + m_ScaleY * std::sin(helper.In.x * m_FreqY)); + helper.Out.z = m_Weight * (helper.In.z + m_ScaleZ * std::sin(helper.m_PrecalcSqrtSumSquares * m_FreqZ)); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string freqX = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string scaleX = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string freqY = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string scaleY = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string freqZ = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string scaleZ = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * fma(" << scaleX << ", sin(vIn.y * " << freqX << "), vIn.x);\n" + << "\t\tvOut.y = " << weight << " * fma(" << scaleY << ", sin(vIn.x * " << freqY << "), vIn.y);\n" + << "\t\tvOut.z = " << weight << " * fma(" << scaleZ << ", sin(precalcSqrtSumSquares * " << freqZ << "), vIn.z);\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Random(QTIsaac& rand) override + { + m_FreqX = 4 * rand.Frand01(); + m_ScaleX = T(0.5) + rand.Frand01(); + m_FreqY = 4 * rand.Frand01(); + m_ScaleY = T(0.5) + rand.Frand01(); + m_FreqZ = 0; + m_ScaleZ = 0; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_FreqX, prefix + "waves2_freqx", 2)); + m_Params.push_back(ParamWithName(&m_ScaleX, prefix + "waves2_scalex")); + m_Params.push_back(ParamWithName(&m_FreqY, prefix + "waves2_freqy", 2)); + m_Params.push_back(ParamWithName(&m_ScaleY, prefix + "waves2_scaley")); + m_Params.push_back(ParamWithName(&m_FreqZ, prefix + "waves2_freqz")); + m_Params.push_back(ParamWithName(&m_ScaleZ, prefix + "waves2_scalez")); + } + +private: + T m_FreqX; + T m_ScaleX; + T m_FreqY; + T m_ScaleY; + T m_FreqZ; + T m_ScaleZ; +}; + +/// +/// Exp. +/// +template +class ExpVariation : public Variation +{ +public: + ExpVariation(T weight = 1.0) : Variation("exp", eVariationId::VAR_EXP, weight) { } + + VARCOPY(ExpVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T expe = m_Weight * std::exp(helper.In.x); + helper.Out.x = expe * std::cos(helper.In.y); + helper.Out.y = expe * std::sin(helper.In.y); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + ss << "\t{\n" + << "\t\treal_t expe = " << weight << " * exp(vIn.x);\n" + << "\n" + << "\t\tvOut.x = expe * cos(vIn.y);\n" + << "\t\tvOut.y = expe * sin(vIn.y);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Exp2. +/// By tatasz. +/// +template +class Exp2Variation : public Variation +{ +public: + Exp2Variation(T weight = 1.0) : Variation("exp2", eVariationId::VAR_EXP2, weight) { } + + VARCOPY(Exp2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T ypi = helper.In.y * T(M_PI); + T expe = m_Weight * std::exp(helper.In.x * T(M_PI)); + helper.Out.x = expe * std::cos(ypi); + helper.Out.y = expe * std::sin(ypi); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + ss << "\t{\n" + << "\t\treal_t ypi = vIn.y * MPI;\n" + << "\t\treal_t expe = " << weight << " * exp(vIn.x * MPI);\n" + << "\n" + << "\t\tvOut.x = expe * cos(ypi);\n" + << "\t\tvOut.y = expe * sin(ypi);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Log. +/// +template +class LogVariation : public ParametricVariation +{ +public: + LogVariation(T weight = 1.0) : ParametricVariation("log", eVariationId::VAR_LOG, weight, true, false, false, false, true) + { + Init(); + } + + PARVARCOPY(LogVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * std::log(helper.m_PrecalcSumSquares) * m_Denom; + helper.Out.y = m_Weight * helper.m_PrecalcAtanyx; + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string base = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string denom = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * log(precalcSumSquares) * " << denom << ";\n" + << "\t\tvOut.y = " << weight << " * precalcAtanyx;\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Denom = T(0.5) / std::log(m_Base); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Base, prefix + "log_base", T(M_E), eParamType::REAL, EPS, TMAX)); + m_Params.push_back(ParamWithName(true, &m_Denom, prefix + "log_denom"));//Precalc. + } + +private: + T m_Base; + T m_Denom;//Precalc. +}; + +/// +/// Sine. +/// +template +class SinVariation : public Variation +{ +public: + SinVariation(T weight = 1.0) : Variation("sin", eVariationId::VAR_SIN, weight) { } + + VARCOPY(SinVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * std::sin(helper.In.x) * std::cosh(helper.In.y); + helper.Out.y = m_Weight * std::cos(helper.In.x) * std::sinh(helper.In.y); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * sin(vIn.x) * cosh(vIn.y);\n" + << "\t\tvOut.y = " << weight << " * cos(vIn.x) * sinh(vIn.y);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Cosine. +/// +template +class CosVariation : public Variation +{ +public: + CosVariation(T weight = 1.0) : Variation("cos", eVariationId::VAR_COS, weight) { } + + VARCOPY(CosVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + //clamp fabs x and y to 7.104760e+002 for cosh, and |x| 7.104760e+002 for sinh + helper.Out.x = m_Weight * std::cos(helper.In.x) * std::cosh(helper.In.y); + helper.Out.y = -(m_Weight * std::sin(helper.In.x) * std::sinh(helper.In.y)); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * cos(vIn.x) * cosh(vIn.y);\n" + << "\t\tvOut.y = -(" << weight << " * sin(vIn.x) * sinh(vIn.y));\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Tangent. +/// +template +class TanVariation : public Variation +{ +public: + TanVariation(T weight = 1.0) : Variation("tan", eVariationId::VAR_TAN, weight) { } + + VARCOPY(TanVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T tansin, tancos, tansinh, tancosh, tanden; + sincos(2 * helper.In.x, &tansin, &tancos); + tansinh = std::sinh(2 * helper.In.y); + tancosh = std::cosh(2 * helper.In.y); + tanden = 1 / Zeps(tancos + tancosh); + helper.Out.x = m_Weight * tanden * tansin; + helper.Out.y = m_Weight * tanden * tansinh; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t tansin = sin((real_t)(2.0) * vIn.x);\n" + << "\t\treal_t tancos = cos((real_t)(2.0) * vIn.x);\n" + << "\t\treal_t tansinh = sinh((real_t)(2.0) * vIn.y);\n" + << "\t\treal_t tancosh = cosh((real_t)(2.0) * vIn.y);\n" + << "\t\treal_t tanden = (real_t)(1.0) / Zeps(tancos + tancosh);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * tanden * tansin;\n" + << "\t\tvOut.y = " << weight << " * tanden * tansinh;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Sec. +/// +template +class SecVariation : public Variation +{ +public: + SecVariation(T weight = 1.0) : Variation("sec", eVariationId::VAR_SEC, weight) { } + + VARCOPY(SecVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T secsin, seccos, secsinh, seccosh, secden; + sincos(helper.In.x, &secsin, &seccos); + secsinh = std::sinh(helper.In.y); + seccosh = std::cosh(helper.In.y); + secden = 2 / Zeps(std::cos(2 * helper.In.x) + std::cosh(2 * helper.In.y)); + helper.Out.x = m_Weight * secden * seccos * seccosh; + helper.Out.y = m_Weight * secden * secsin * secsinh; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t secsin = sin(vIn.x);\n" + << "\t\treal_t seccos = cos(vIn.x);\n" + << "\t\treal_t secsinh = sinh(vIn.y);\n" + << "\t\treal_t seccosh = cosh(vIn.y);\n" + << "\t\treal_t secden = (real_t)(2.0) / Zeps(cos((real_t)(2.0) * vIn.x) + cosh((real_t)(2.0) * vIn.y));\n" + << "\n" + << "\t\tvOut.x = " << weight << " * secden * seccos * seccosh;\n" + << "\t\tvOut.y = " << weight << " * secden * secsin * secsinh;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Cosecant. +/// +template +class CscVariation : public Variation +{ +public: + CscVariation(T weight = 1.0) : Variation("csc", eVariationId::VAR_CSC, weight) { } + + VARCOPY(CscVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T cscsin, csccos, cscsinh, csccosh, cscden; + sincos(helper.In.x, &cscsin, &csccos); + cscsinh = std::sinh(helper.In.y); + csccosh = std::cosh(helper.In.y); + cscden = 2 / Zeps(std::cosh(2 * helper.In.y) - std::cos(2 * helper.In.x)); + helper.Out.x = m_Weight * cscden * cscsin * csccosh; + helper.Out.y = -(m_Weight * cscden * csccos * cscsinh); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t cscsin = sin(vIn.x);\n" + << "\t\treal_t csccos = cos(vIn.x);\n" + << "\t\treal_t cscsinh = sinh(vIn.y);\n" + << "\t\treal_t csccosh = cosh(vIn.y);\n" + << "\t\treal_t cscden = (real_t)(2.0) / Zeps(cosh((real_t)(2.0) * vIn.y) - cos((real_t)(2.0) * vIn.x));\n" + << "\n" + << "\t\tvOut.x = " << weight << " * cscden * cscsin * csccosh;\n" + << "\t\tvOut.y = -(" << weight << " * cscden * csccos * cscsinh);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Cotangent. +/// +template +class CotVariation : public Variation +{ +public: + CotVariation(T weight = 1.0) : Variation("cot", eVariationId::VAR_COT, weight) { } + + VARCOPY(CotVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T cotsin, cotcos, cotsinh, cotcosh, cotden; + sincos(2 * helper.In.x, &cotsin, &cotcos); + cotsinh = std::sinh(2 * helper.In.y); + cotcosh = std::cosh(2 * helper.In.y); + cotden = 1 / Zeps(cotcosh - cotcos); + helper.Out.x = m_Weight * cotden * cotsin; + helper.Out.y = m_Weight * cotden * -1 * cotsinh; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t cotsin = sin((real_t)(2.0) * vIn.x);\n" + << "\t\treal_t cotcos = cos((real_t)(2.0) * vIn.x);\n" + << "\t\treal_t cotsinh = sinh((real_t)(2.0) * vIn.y);\n" + << "\t\treal_t cotcosh = cosh((real_t)(2.0) * vIn.y);\n" + << "\t\treal_t cotden = (real_t)(1.0) / Zeps(cotcosh - cotcos);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * cotden * cotsin;\n" + << "\t\tvOut.y = " << weight << " * cotden * -1 * cotsinh;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Sinh. +/// +template +class SinhVariation : public Variation +{ +public: + SinhVariation(T weight = 1.0) : Variation("sinh", eVariationId::VAR_SINH, weight) { } + + VARCOPY(SinhVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T sinhsin, sinhcos, sinhsinh, sinhcosh; + sincos(helper.In.y, &sinhsin, &sinhcos); + sinhsinh = std::sinh(helper.In.x); + sinhcosh = std::cosh(helper.In.x); + helper.Out.x = m_Weight * sinhsinh * sinhcos; + helper.Out.y = m_Weight * sinhcosh * sinhsin; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t sinhsin = sin(vIn.y);\n" + << "\t\treal_t sinhcos = cos(vIn.y);\n" + << "\t\treal_t sinhsinh = sinh(vIn.x);\n" + << "\t\treal_t sinhcosh = cosh(vIn.x);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * sinhsinh * sinhcos;\n" + << "\t\tvOut.y = " << weight << " * sinhcosh * sinhsin;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Cosh. +/// +template +class CoshVariation : public Variation +{ +public: + CoshVariation(T weight = 1.0) : Variation("cosh", eVariationId::VAR_COSH, weight) { } + + VARCOPY(CoshVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T coshsin, coshcos, coshsinh, coshcosh; + sincos(helper.In.y, &coshsin, &coshcos); + coshsinh = std::sinh(helper.In.x); + coshcosh = std::cosh(helper.In.x); + helper.Out.x = m_Weight * coshcosh * coshcos; + helper.Out.y = m_Weight * coshsinh * coshsin; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t coshsin = sin(vIn.y);\n" + << "\t\treal_t coshcos = cos(vIn.y);\n" + << "\t\treal_t coshsinh = sinh(vIn.x);\n" + << "\t\treal_t coshcosh = cosh(vIn.x);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * coshcosh * coshcos;\n" + << "\t\tvOut.y = " << weight << " * coshsinh * coshsin;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// Tanh. +/// +template +class TanhVariation : public Variation +{ +public: + TanhVariation(T weight = 1.0) : Variation("tanh", eVariationId::VAR_TANH, weight) { } + + VARCOPY(TanhVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T tanhsin, tanhcos, tanhsinh, tanhcosh, tanhden; + sincos(2 * helper.In.y, &tanhsin, &tanhcos); + tanhsinh = std::sinh(2 * helper.In.x); + tanhcosh = std::cosh(2 * helper.In.x); + tanhden = 1 / Zeps(tanhcos + tanhcosh); + helper.Out.x = m_Weight * tanhden * tanhsinh; + helper.Out.y = m_Weight * tanhden * tanhsin; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t tanhsin = sin((real_t)(2.0) * vIn.y);\n" + << "\t\treal_t tanhcos = cos((real_t)(2.0) * vIn.y);\n" + << "\t\treal_t tanhsinh = sinh((real_t)(2.0) * vIn.x);\n" + << "\t\treal_t tanhcosh = cosh((real_t)(2.0) * vIn.x);\n" + << "\t\treal_t tanhden = (real_t)(1.0) / Zeps(tanhcos + tanhcosh);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * tanhden * tanhsinh;\n" + << "\t\tvOut.y = " << weight << " * tanhden * tanhsin;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// tanh_spiral. +/// +template +class TanhSpiralVariation : public ParametricVariation +{ +public: + TanhSpiralVariation(T weight = 1.0) : ParametricVariation("tanh_spiral", eVariationId::VAR_TANH_SPIRAL, weight) + { + Init(); + } + + PARVARCOPY(TanhSpiralVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T t2 = (rand.Frand01() - T(0.5)) * M_2PI; + T aux = Zeps(std::cos(m_A * t2) + std::cosh(t2)); + helper.Out.x = m_Weight * (std::sinh(t2) / aux); + helper.Out.y = m_Weight * (std::sin(m_A * t2) / aux); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string a = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t t2 = (MwcNext01(mwc) - 0.5) * M_2PI;\n" + << "\t\treal_t aux = Zeps(cos(" << a << " * t2) + cosh(t2));\n" + << "\n" + << "\t\tvOut.x = " << weight << " * (sinh(t2) / aux);\n" + << "\t\tvOut.y = " << weight << " * (sin(" << a << " * t2) / aux);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_A, prefix + "tanh_spiral_a", 4)); + } + +private: + T m_A; +}; + +/// +/// Sech +/// +template +class SechVariation : public Variation +{ +public: + SechVariation(T weight = 1.0) : Variation("sech", eVariationId::VAR_SECH, weight) { } + + VARCOPY(SechVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T sechsin, sechcos, sechsinh, sechcosh, sechden; + sincos(helper.In.y, &sechsin, &sechcos); + sechsinh = std::sinh(helper.In.x); + sechcosh = std::cosh(helper.In.x); + sechden = 2 / Zeps(std::cos(2 * helper.In.y) + std::cosh(2 * helper.In.x)); + helper.Out.x = m_Weight * sechden * sechcos * sechcosh; + helper.Out.y = -(m_Weight * sechden * sechsin * sechsinh); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t sechsin = sin(vIn.y);\n" + << "\t\treal_t sechcos = cos(vIn.y);\n" + << "\t\treal_t sechsinh = sinh(vIn.x);\n" + << "\t\treal_t sechcosh = cosh(vIn.x);\n" + << "\t\treal_t sechden = (real_t)(2.0) / Zeps(cos((real_t)(2.0) * vIn.y) + cosh((real_t)(2.0) * vIn.x));\n" + << "\n" + << "\t\tvOut.x = " << weight << " * sechden * sechcos * sechcosh;\n" + << "\t\tvOut.y = -(" << weight << " * sechden * sechsin * sechsinh);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Csch. +/// +template +class CschVariation : public Variation +{ +public: + CschVariation(T weight = 1.0) : Variation("csch", eVariationId::VAR_CSCH, weight) { } + + VARCOPY(CschVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T cschsin, cschcos, cschsinh, cschcosh, cschden; + sincos(helper.In.y, &cschsin, &cschcos); + cschsinh = std::sinh(helper.In.x); + cschcosh = std::cosh(helper.In.x); + cschden = 2 / Zeps(std::cosh(2 * helper.In.x) - std::cos(2 * helper.In.y)); + helper.Out.x = m_Weight * cschden * cschsinh * cschcos; + helper.Out.y = -(m_Weight * cschden * cschcosh * cschsin); + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t cschsin = sin(vIn.y);\n" + << "\t\treal_t cschcos = cos(vIn.y);\n" + << "\t\treal_t cschsinh = sinh(vIn.x);\n" + << "\t\treal_t cschcosh = cosh(vIn.x);\n" + << "\t\treal_t cschden = (real_t)(2.0) / Zeps(cosh((real_t)(2.0) * vIn.x) - cos((real_t)(2.0) * vIn.y));\n" + << "\n" + << "\t\tvOut.x = " << weight << " * cschden * cschsinh * cschcos;\n" + << "\t\tvOut.y = -(" << weight << " * cschden * cschcosh * cschsin);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Coth. +/// +template +class CothVariation : public Variation +{ +public: + CothVariation(T weight = 1.0) : Variation("coth", eVariationId::VAR_COTH, weight) { } + + VARCOPY(CothVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T cothsin, cothcos, cothsinh, cothcosh, cothden; + sincos(2 * helper.In.y, &cothsin, &cothcos); + cothsinh = std::sinh(2 * helper.In.x); + cothcosh = std::cosh(2 * helper.In.x); + cothden = 1 / Zeps(cothcosh - cothcos); + helper.Out.x = m_Weight * cothden * cothsinh; + helper.Out.y = m_Weight * cothden * cothsin; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + intmax_t varIndex = IndexInXform(); + ss << "\t{\n" + << "\t\treal_t cothsin = sin((real_t)(2.0) * vIn.y);\n" + << "\t\treal_t cothcos = cos((real_t)(2.0) * vIn.y);\n" + << "\t\treal_t cothsinh = sinh((real_t)(2.0) * vIn.x);\n" + << "\t\treal_t cothcosh = cosh((real_t)(2.0) * vIn.x);\n" + << "\t\treal_t cothden = (real_t)(1.0) / Zeps(cothcosh - cothcos);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * cothden * cothsinh;\n" + << "\t\tvOut.y = " << weight << " * cothden * cothsin;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + +/// +/// Auger. +/// +template +class AugerVariation : public ParametricVariation +{ +public: + AugerVariation(T weight = 1.0) : ParametricVariation("auger", eVariationId::VAR_AUGER, weight) + { + Init(); + } + + PARVARCOPY(AugerVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T s = std::sin(m_Freq * helper.In.x); + T t = std::sin(m_Freq * helper.In.y); + T dx = helper.In.x + m_AugerWeight * (m_HalfScale * t + std::abs(helper.In.x) * t); + T dy = helper.In.y + m_AugerWeight * (m_HalfScale * s + std::abs(helper.In.y) * s); + helper.Out.x = m_Weight * (helper.In.x + m_Symmetry * (dx - helper.In.x)); + helper.Out.y = m_Weight * dy; + helper.Out.z = m_Weight * helper.In.z; + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string symmetry = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string augerWeight = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string freq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string scale = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string halfscale = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t s = sin(" << freq << " * vIn.x);\n" + << "\t\treal_t t = sin(" << freq << " * vIn.y);\n" + << "\t\treal_t dx = fma(" << augerWeight << ", fma(" << halfscale << ", t, fabs(vIn.x) * t), vIn.x);\n" + << "\t\treal_t dy = fma(" << augerWeight << ", fma(" << halfscale << ", s, fabs(vIn.y) * s), vIn.y);\n" + << "\n" + << "\t\tvOut.x = " << weight << " * fma(" << symmetry << ", (dx - vIn.x), vIn.x);\n" + << "\t\tvOut.y = " << weight << " * dy;\n" + << "\t\tvOut.z = " << weight << " * vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Random(QTIsaac& rand) override + { + m_Symmetry = 0; + m_AugerWeight = T(0.5) + rand.Frand01() / 2; + m_Freq = T(Floor(5 * rand.Frand01())) + 1; + m_Scale = rand.Frand01(); + } + + virtual void Precalc() override + { + m_HalfScale = m_Scale / 2; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Symmetry, prefix + "auger_sym")); + m_Params.push_back(ParamWithName(&m_AugerWeight, prefix + "auger_weight", T(0.5))); + m_Params.push_back(ParamWithName(&m_Freq, prefix + "auger_freq", 5)); + m_Params.push_back(ParamWithName(&m_Scale, prefix + "auger_scale", T(0.1))); + m_Params.push_back(ParamWithName(&m_HalfScale, prefix + "auger_half_scale")); + } + +private: + T m_Symmetry; + T m_AugerWeight; + T m_Freq; + T m_Scale; + T m_HalfScale; +}; + +/// +/// Flux. +/// +template +class FluxVariation : public ParametricVariation +{ +public: + FluxVariation(T weight = 1.0) : ParametricVariation("flux", eVariationId::VAR_FLUX, weight) + { + Init(); + } + + PARVARCOPY(FluxVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T xpw = helper.In.x + m_Weight; + T xmw = helper.In.x - m_Weight; + T yy = SQR(helper.In.y); + T frac = std::sqrt(yy + SQR(xmw)); + + if (frac == 0) + frac = 1; + + T avgr = m_Weight * (m_Spr * std::sqrt(std::sqrt(yy + SQR(xpw)) / frac)); + T avga = (std::atan2(helper.In.y, xmw) - std::atan2(helper.In.y, xpw)) * T(0.5); + helper.Out.x = avgr * std::cos(avga); + helper.Out.y = avgr * std::sin(avga); + helper.Out.z = helper.In.z;//Apo does not use weight, sums only z. Sum here for reg, else assign. + } + + virtual string OpenCLString() const override + { + ostringstream ss, ss2; + intmax_t i = 0, varIndex = IndexInXform(); + ss2 << "_" << XformIndexInEmber() << "]"; + string index = ss2.str(); + string weight = WeightDefineString(); + string spread = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string spr = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t xpw = vIn.x + " << weight << ";\n" + << "\t\treal_t xmw = vIn.x - " << weight << ";\n" + << "\t\treal_t yy = SQR(vIn.y);\n" + << "\t\treal_t frac = sqrt(fma(xmw, xmw, yy));\n" + << "\n" + << "\t\tif (frac == (real_t)(0.0))\n" + << "\t\t frac = (real_t)(1.0);\n" + << "\n" + << "\t\treal_t avgr = " << weight << " * (" << spr << " * sqrt(sqrt(fma(xpw, xpw, yy)) / frac));\n" + << "\t\treal_t avga = (atan2(vIn.y, xmw) - atan2(vIn.y, xpw)) * (real_t)(0.5);\n" + << "\n" + << "\t\tvOut.x = avgr * cos(avga);\n" + << "\t\tvOut.y = avgr * sin(avga);\n" + << "\t\tvOut.z = vIn.z;\n" + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Spr = 2 + m_Spread; + } + + virtual void Random(QTIsaac& rand) override + { + m_Spread = T(0.5) + rand.Frand01() / 2; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Spread, prefix + "flux_spread"));//Params. + m_Params.push_back(ParamWithName(true, &m_Spr, prefix + "flux_spr"));//Precalc. + } + +private: + T m_Spread;//Params. + T m_Spr;//Precalc. +}; + +MAKEPREPOSTVAR(Linear, linear, LINEAR) +MAKEPREPOSTVAR(Sinusoidal, sinusoidal, SINUSOIDAL) +MAKEPREPOSTVAR(Spherical, spherical, SPHERICAL) +MAKEPREPOSTVAR(Swirl, swirl, SWIRL) +MAKEPREPOSTPARVAR(Swirl3, swirl3, SWIRL3) +MAKEPREPOSTPARVAR(Swirl3r, swirl3r, SWIRL3R) +MAKEPREPOSTVAR(Horseshoe, horseshoe, HORSESHOE) +MAKEPREPOSTVAR(Polar, polar, POLAR) +MAKEPREPOSTVAR(Handkerchief, handkerchief, HANDKERCHIEF) +MAKEPREPOSTVAR(Heart, heart, HEART) +MAKEPREPOSTPARVAR(Disc, disc, DISC) +MAKEPREPOSTVAR(Spiral, spiral, SPIRAL) +MAKEPREPOSTVAR(Hyperbolic, hyperbolic, HYPERBOLIC) +MAKEPREPOSTVAR(Diamond, diamond, DIAMOND) +MAKEPREPOSTVAR(Ex, ex, EX) +MAKEPREPOSTVAR(Julia, julia, JULIA) +MAKEPREPOSTVAR(Bent, bent, BENT) +MAKEPREPOSTPARVAR(Waves, waves, WAVES) +MAKEPREPOSTVAR(Fisheye, fisheye, FISHEYE) +MAKEPREPOSTVAR(Popcorn, popcorn, POPCORN) +MAKEPREPOSTVAR(Exponential, exponential, EXPONENTIAL) +MAKEPREPOSTVAR(Power, power, POWER) +MAKEPREPOSTVAR(Cosine, cosine, COSINE) +MAKEPREPOSTVAR(Rings, rings, RINGS) +MAKEPREPOSTVAR(Fan, fan, FAN) +MAKEPREPOSTPARVAR(Blob, blob, BLOB) +MAKEPREPOSTPARVAR(Pdj, pdj, PDJ) +MAKEPREPOSTPARVAR(Fan2, fan2, FAN2) +MAKEPREPOSTPARVAR(Rings2, rings2, RINGS2) +MAKEPREPOSTVAR(Eyefish, eyefish, EYEFISH) +MAKEPREPOSTVAR(Bubble, bubble, BUBBLE) +MAKEPREPOSTVAR(Cylinder, cylinder, CYLINDER) +MAKEPREPOSTPARVAR(Perspective, perspective, PERSPECTIVE) +MAKEPREPOSTVAR(Noise, noise, NOISE) +MAKEPREPOSTPARVAR(JuliaNGeneric, julian, JULIAN) +MAKEPREPOSTPARVAR(JuliaScope, juliascope, JULIASCOPE) +MAKEPREPOSTVARASSIGN(Blur, blur, BLUR, eVariationAssignType::ASSIGNTYPE_SUM) +MAKEPREPOSTVARASSIGN(GaussianBlur, gaussian_blur, GAUSSIAN_BLUR, eVariationAssignType::ASSIGNTYPE_SUM) +MAKEPREPOSTVAR(Gaussian, gaussian, GAUSSIAN) +MAKEPREPOSTPARVAR(RadialBlur, radial_blur, RADIAL_BLUR) +//MAKEPREPOSTPARVAR(RadialGaussian, radial_gaussian, RADIAL_GAUSSIAN) +MAKEPREPOSTPARVARASSIGN(Pie, pie, PIE, eVariationAssignType::ASSIGNTYPE_SUM) +MAKEPREPOSTPARVAR(Ngon, ngon, NGON) +MAKEPREPOSTPARVAR(Curl, curl, CURL) +MAKEPREPOSTPARVAR(Rectangles, rectangles, RECTANGLES) +MAKEPREPOSTVARASSIGN(Arch, arch, ARCH, eVariationAssignType::ASSIGNTYPE_SUM) +MAKEPREPOSTVAR(Tangent, tangent, TANGENT) +MAKEPREPOSTVARASSIGN(Square, square, SQUARE, eVariationAssignType::ASSIGNTYPE_SUM) +MAKEPREPOSTVAR(Rays, rays, RAYS) +MAKEPREPOSTVAR(Rays1, rays1, RAYS1) +MAKEPREPOSTVAR(Rays2, rays2, RAYS2) +MAKEPREPOSTVAR(Rays3, rays3, RAYS3) +MAKEPREPOSTVAR(Blade, blade, BLADE) +MAKEPREPOSTVAR(Secant2, secant2, SECANT2) +MAKEPREPOSTVAR(TwinTrian, TwinTrian, TWINTRIAN) +MAKEPREPOSTVAR(Cross, cross, CROSS) +MAKEPREPOSTPARVAR(Disc2, disc2, DISC2) +MAKEPREPOSTPARVAR(SuperShape, super_shape, SUPER_SHAPE) +MAKEPREPOSTPARVAR(Flower, flower, FLOWER) +MAKEPREPOSTPARVAR(FlowerDb, flowerdb, FLOWER_DB) +MAKEPREPOSTPARVAR(Conic, conic, CONIC) +MAKEPREPOSTPARVAR(Parabola, parabola, PARABOLA) +MAKEPREPOSTPARVAR(Bent2, bent2, BENT2) +MAKEPREPOSTPARVAR(Bipolar, bipolar, BIPOLAR) +MAKEPREPOSTVAR(Boarders, boarders, BOARDERS) +MAKEPREPOSTVAR(Butterfly, butterfly, BUTTERFLY) +MAKEPREPOSTPARVAR(Cell, cell, CELL) +MAKEPREPOSTPARVAR(Cpow, cpow, CPOW) +MAKEPREPOSTPARVAR(Curve, curve, CURVE) +MAKEPREPOSTVAR(Edisc, edisc, EDISC) +MAKEPREPOSTPARVAR(Elliptic, elliptic, ELLIPTIC) +MAKEPREPOSTPARVAR(Escher, escher, ESCHER) +MAKEPREPOSTVAR(Foci, foci, FOCI) +MAKEPREPOSTPARVAR(LazySusan, lazysusan, LAZYSUSAN) +MAKEPREPOSTPARVAR(Loonie, loonie, LOONIE) +MAKEPREPOSTPARVAR(Modulus, modulus, MODULUS) +MAKEPREPOSTPARVAR(Oscilloscope, oscilloscope, OSCILLOSCOPE) +MAKEPREPOSTPARVAR(Oscilloscope2, oscilloscope2, OSCILLOSCOPE2) +MAKEPREPOSTPARVAR(Polar2, polar2, POLAR2) +MAKEPREPOSTPARVAR(Popcorn2, popcorn2, POPCORN2) +MAKEPREPOSTPARVAR(Scry, scry, SCRY) +MAKEPREPOSTPARVAR(Scry2, scry2, SCRY2) +MAKEPREPOSTPARVAR(Separation, separation, SEPARATION) +MAKEPREPOSTPARVAR(Split, split, SPLIT) +MAKEPREPOSTPARVAR(Splits, splits, SPLITS) +MAKEPREPOSTPARVAR(Stripes, stripes, STRIPES) +MAKEPREPOSTPARVAR(Wedge, wedge, WEDGE) +MAKEPREPOSTPARVAR(WedgeJulia, wedge_julia, WEDGE_JULIA) +MAKEPREPOSTPARVAR(WedgeSph, wedge_sph, WEDGE_SPH) +MAKEPREPOSTPARVAR(Whorl, whorl, WHORL) +MAKEPREPOSTPARVAR(Waves2, waves2, WAVES2) +MAKEPREPOSTVAR(Exp, exp, EXP) +MAKEPREPOSTVAR(Exp2, exp2, EXP2) +MAKEPREPOSTPARVAR(Log, log, LOG) +MAKEPREPOSTVAR(Sin, sin, SIN) +MAKEPREPOSTVAR(Cos, cos, COS) +MAKEPREPOSTVAR(Tan, tan, TAN) +MAKEPREPOSTVAR(Sec, sec, SEC) +MAKEPREPOSTVAR(Csc, csc, CSC) +MAKEPREPOSTVAR(Cot, cot, COT) +MAKEPREPOSTVAR(Sinh, sinh, SINH) +MAKEPREPOSTVAR(Cosh, cosh, COSH) +MAKEPREPOSTVAR(Tanh, tanh, TANH) +MAKEPREPOSTPARVAR(TanhSpiral, tanh_spiral, TANH_SPIRAL) +MAKEPREPOSTVAR(Sech, sech, SECH) +MAKEPREPOSTVAR(Csch, csch, CSCH) +MAKEPREPOSTVAR(Coth, coth, COTH) +MAKEPREPOSTPARVAR(Auger, auger, AUGER) +MAKEPREPOSTPARVAR(Flux, flux, FLUX) +}