Пример #1
0
  @Override
  public void transform(
      FlameTransformationContext pContext,
      XForm pXForm,
      XYZPoint pAffineTP,
      XYZPoint pVarTP,
      double pAmount) {
    double wedgeJulia_cf = 1.0 - angle * count * M_1_PI * 0.5;
    double wedgeJulia_rN = fabs(power);
    double wedgeJulia_cn = dist / power / 2.0;
    /* wedge_julia from apo plugin pack */

    double r = pAmount * pow(pAffineTP.getPrecalcSumsq(), wedgeJulia_cn);
    int t_rnd = (int) ((wedgeJulia_rN) * pContext.random());
    double a = (pAffineTP.getPrecalcAtanYX() + 2.0 * M_PI * t_rnd) / power;
    double c = floor((count * a + M_PI) * M_1_PI * 0.5);

    a = a * wedgeJulia_cf + c * angle;
    double sa = sin(a);
    double ca = cos(sa);

    pVarTP.x += r * ca;
    pVarTP.y += r * sa;
    if (pContext.isPreserveZCoordinate()) {
      pVarTP.z += pAmount * pAffineTP.z;
    }
  }
Пример #2
0
 @Override
 public void transform(
     FlameTransformationContext pContext,
     XForm pXForm,
     XYZPoint pAffineTP,
     XYZPoint pVarTP,
     double pAmount) {
   double x = (this._isodd != 0) ? pAffineTP.x : this._vvar * atan2(pAffineTP.x, pAffineTP.y);
   double y =
       (this._isodd != 0)
           ? pAffineTP.y
           : this._vvar_2 * log(pAffineTP.x * pAffineTP.x + pAffineTP.y * pAffineTP.y);
   double angle =
       (atan2(y, x) + M_2PI * (pContext.random(Integer.MAX_VALUE) % (int) this._absn)) / this._nnz;
   double r = pAmount * pow(sqr(x) + sqr(y), this._cn) * ((this._isodd == 0) ? 1.0 : this.parity);
   double sina = sin(angle);
   double cosa = cos(angle);
   cosa *= r;
   sina *= r;
   x = (this._isodd != 0) ? cosa : (this._vvar_2 * log(cosa * cosa + sina * sina));
   y = (this._isodd != 0) ? sina : (this._vvar * atan2(cosa, sina));
   pVarTP.x += x;
   pVarTP.y += y;
   if (pContext.isPreserveZCoordinate()) {
     pVarTP.z += pAmount * pAffineTP.z;
   }
 }
Пример #3
0
 public void transformPower1(
     FlameTransformationContext pContext,
     XForm pXForm,
     XYZPoint pAffineTP,
     XYZPoint pVarTP,
     double pAmount) {
   pVarTP.x = pVarTP.x + pAmount * pAffineTP.x;
   pVarTP.y = pVarTP.y + pAmount * pAffineTP.y;
   if (pContext.isPreserveZCoordinate()) {
     pVarTP.z += pAmount * pAffineTP.z;
   }
 }
Пример #4
0
 @Override
 public void transform(
     FlameTransformationContext pContext,
     XForm pXForm,
     XYZPoint pAffineTP,
     XYZPoint pVarTP,
     double pAmount) {
   double sina = sin(pAmount * M_PI * 0.5);
   double cosa = cos(pAmount * M_PI * 0.5);
   double z = cosa * pVarTP.z - sina * pVarTP.y;
   pVarTP.y = sina * pVarTP.z + cosa * pVarTP.y;
   pVarTP.z = z;
 }
 @Override
 public void transform(
     FlameTransformationContext pContext,
     XForm pXForm,
     XYZPoint pAffineTP,
     XYZPoint pVarTP,
     double pAmount) {
   // sinusoidal3d by gossamer_light
   pVarTP.x += pAmount * sin(pAffineTP.x);
   pVarTP.y += pAmount * sin(pAffineTP.y);
   pVarTP.z +=
       pAmount * (atan2(pAffineTP.x * pAffineTP.x, pAffineTP.y * pAffineTP.y) * cos(pAffineTP.z));
 }
Пример #6
0
 @Override
 public void transform(
     FlameTransformationContext pContext,
     XForm pXForm,
     XYZPoint pAffineTP,
     XYZPoint pVarTP,
     double pAmount) {
   pVarTP.x += pAmount * sin(pAffineTP.x);
   pVarTP.y += pAmount * pAffineTP.y;
   if (pContext.isPreserveZCoordinate()) {
     pVarTP.z += pAmount * pAffineTP.z;
   }
 }
Пример #7
0
 @Override
 public void transform(
     FlameTransformationContext pContext,
     XForm pXForm,
     XYZPoint pAffineTP,
     XYZPoint pVarTP,
     double pAmount) {
   double a = pAffineTP.getPrecalcAtan() * 0.5 + M_PI * (int) (2.0 * pContext.random());
   double sina = sin(a);
   double cosa = cos(a);
   double r = pAmount * sqrt(sqrt(pAffineTP.x * pAffineTP.x + pAffineTP.y * pAffineTP.y));
   pVarTP.x += r * cosa;
   pVarTP.y += r * sina;
   if (pContext.isPreserveZCoordinate()) {
     pVarTP.z += pAmount * pAffineTP.z;
   }
 }
Пример #8
0
  @Override
  public void transform(
      FlameTransformationContext pContext,
      XForm pXForm,
      XYZPoint pAffineTP,
      XYZPoint pVarTP,
      double pAmount) {
    // nBlur by FractalDesire, http://fractaldesire.deviantart.com/art/nBlur-plugin-190401515
    // *********Adjustment of width of shape*********
    if (this.adjustToLinear == TRUE) {
      if ((this.numEdges) % 4 == 0) {
        pAmount /=
            sqrt(2.0 - 2.0 * cos(this._midAngle * ((double) this.numEdges / 2.0 - 1.0))) / 2.0;
      } else {
        pAmount /=
            sqrt(2.0 - 2.0 * cos(this._midAngle * floor(((double) this.numEdges / 2.0)))) / 2.0;
      }
    }
    //
    randXY(pContext, _randXYData);

    // ********Exact calculation slower - interpolated calculation faster********
    if ((this.exactCalc == TRUE) && (this.circumCircle == FALSE)) {
      while ((_randXYData.lenXY < _randXYData.lenInnerEdges)
          || (_randXYData.lenXY > _randXYData.lenOuterEdges)) randXY(pContext, _randXYData);
    }
    if ((this.exactCalc == TRUE) && (this.circumCircle == TRUE)) {
      while (_randXYData.lenXY < _randXYData.lenInnerEdges) randXY(pContext, _randXYData);
    }
    double xTmp = _randXYData.x;
    double yTmp = _randXYData.y;

    // **************************************************************************

    // ********Begin of horizontal adjustment (rotation)********
    double x = this._cosa * xTmp - this._sina * yTmp;
    double y = this._sina * xTmp + this._cosa * yTmp;
    // *********End of horizontal adjustment (rotation)*********

    pVarTP.x += pAmount * x;
    pVarTP.y += pAmount * y;

    if (pContext.isPreserveZCoordinate()) {
      pVarTP.z += pAmount * pAffineTP.z;
    }
  }
Пример #9
0
 @Override
 public void transform(
     FlameTransformationContext pContext,
     XForm pXForm,
     XYZPoint pAffineTP,
     XYZPoint pVarTP,
     double pAmount) {
   /* Bent2 in the Apophysis Plugin Pack */
   double nx = pAffineTP.x;
   double ny = pAffineTP.y;
   if (nx < 0.0) nx = nx * x;
   if (ny < 0.0) ny = ny * y;
   pVarTP.x += pAmount * nx;
   pVarTP.y += pAmount * ny;
   if (pContext.isPreserveZCoordinate()) {
     pVarTP.z += pAmount * pAffineTP.z;
   }
 }
Пример #10
0
 @Override
 public void transform(
     FlameTransformationContext pContext,
     XForm pXForm,
     XYZPoint pAffineTP,
     XYZPoint pVarTP,
     double pAmount) {
   pVarTP.z = pAmount * pVarTP.z + ztranslate;
 }
Пример #11
0
 public void transformPowerMinus2(
     FlameTransformationContext pContext,
     XForm pXForm,
     XYZPoint pAffineTP,
     XYZPoint pVarTP,
     double pAmount) {
   double a;
   if (pContext.random(2) == 0) a = atan2(pAffineTP.y, pAffineTP.x) / 2.0;
   else a = M_PI - atan2(pAffineTP.y, pAffineTP.x) / 2.0;
   double sina = sin(a);
   double cosa = cos(a);
   double r = pAmount / sqrt(sqrt(sqr(pAffineTP.x) + sqr(pAffineTP.y)));
   pVarTP.x = pVarTP.x + r * cosa;
   pVarTP.y = pVarTP.y - r * sina;
   if (pContext.isPreserveZCoordinate()) {
     pVarTP.z += pAmount * pAffineTP.z;
   }
 }
Пример #12
0
  public void transformFunction(
      FlameTransformationContext pContext,
      XForm pXForm,
      XYZPoint pAffineTP,
      XYZPoint pVarTP,
      double pAmount) {
    int rnd = pContext.random(absPower);
    double a;
    if ((rnd & 1) == 0) a = (2 * M_PI * rnd + atan2(pAffineTP.y, pAffineTP.x)) / power;
    else a = (2 * M_PI * rnd - atan2(pAffineTP.y, pAffineTP.x)) / power;
    double sina = sin(a);
    double cosa = cos(a);

    double r = pAmount * pow(sqr(pAffineTP.x) + sqr(pAffineTP.y), cPower);
    pVarTP.x = pVarTP.x + r * cosa;
    pVarTP.y = pVarTP.y + r * sina;
    if (pContext.isPreserveZCoordinate()) {
      pVarTP.z += pAmount * pAffineTP.z;
    }
  }
Пример #13
0
 @Override
 public void transform(
     FlameTransformationContext pContext,
     XForm pXForm,
     XYZPoint pAffineTP,
     XYZPoint pVarTP,
     double pAmount) {
   /* inflateZ_3 by Larry Berlin, http://aporev.deviantart.com/art/New-3D-Plugins-136484533?q=gallery%3Aaporev%2F8229210&qo=22 */
   double ang = atan2(pAffineTP.y, pAffineTP.x);
   double val1 = 0.2 * (M_PI - ang) * cos(3.0 * ang + (pAffineTP.y - pAffineTP.x));
   pVarTP.z += pAmount * val1;
 }
Пример #14
0
 @Override
 public void transform(
     FlameTransformationContext pContext,
     XForm pXForm,
     XYZPoint pAffineTP,
     XYZPoint pVarTP,
     double pAmount) {
   double sumsq = pAffineTP.getPrecalcSumsq();
   // Prevent divide by zero error
   if (sumsq == 0) {
     pVarTP.doHide = true;
   } else {
     double xfactor = xscale * pAffineTP.x + xshift;
     double yfactor = yscale * pAffineTP.y + yshift;
     pVarTP.x = (pAmount / sumsq) * sin(xfactor) * (cosh(yfactor) + ushift) * sqr(sin(xfactor));
     pVarTP.y += (pAmount / sumsq) * cos(xfactor) * (cosh(yfactor) + ushift) * sqr(sin(xfactor));
   }
   if (pContext.isPreserveZCoordinate()) {
     pVarTP.z += pAmount * pAffineTP.z;
   }
 }
Пример #15
0
  @Override
  public void transform(
      FlameTransformationContext pContext,
      XForm pXForm,
      XYZPoint pAffineTP,
      XYZPoint pVarTP,
      double pAmount) {
    // fibonacci2 by Larry Berlin, http://aporev.deviantart.com/gallery/#/d2blmhg
    //  p^z - (-p)^(-z)
    // z' = -----------------
    //      sqrt(5)
    //
    // Where p is the Golden Ratio.
    // This function generates the fibonacci sequence
    // for real integer values.
    // 1 2 3 4 5 6  7  8  9 10 11  12  13  14  15 < Real Value
    // 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 < Fib Value
    //
    // Negative real integers produce the negative fibonacci sequence,
    // which is the same as the normal one, except every
    // other number is negative.
    // 1 0 -1 -2 -3 -4 -5 -6 -7  -8 < Real Value
    // 1 0  1 -1  3 -3  5 -8 13 -21 < Fib Value

    double a = pAffineTP.y * fnatlog;
    double snum1 = sin(a);
    double cnum1 = cos(a);
    double b = (pAffineTP.x * M_PI + pAffineTP.y * fnatlog) * -1.0;
    double snum2 = sin(b);
    double cnum2 = cos(b);

    double eradius1 = sc * exp(sc2 * (pAffineTP.x * fnatlog));
    double eradius2 = sc * exp(sc2 * ((pAffineTP.x * fnatlog - pAffineTP.y * M_PI) * -1));

    pVarTP.x += pAmount * (eradius1 * cnum1 - eradius2 * cnum2) * ffive;
    pVarTP.y += pAmount * (eradius1 * snum1 - eradius2 * snum2) * ffive;
    if (pContext.isPreserveZCoordinate()) {
      pVarTP.z += pAmount * pAffineTP.z;
    }
  }
Пример #16
0
  @Override
  public void transform(
      FlameTransformationContext pContext,
      XForm pXForm,
      XYZPoint pAffineTP,
      XYZPoint pVarTP,
      double pAmount) {
    /* hexnix3D by Larry Berlin, http://aporev.deviantart.com/art/3D-Plugins-Collection-One-138514007?q=gallery%3Aaporev%2F8229210&qo=15 */
    if (_fcycle > 5) { // Resets the cyclic counting
      _fcycle = 0;
      _rswtch = (int) trunc(pContext.random() * 3.0); //  Chooses new 6 or 3 nodes
    }
    if (_bcycle > 2) {
      _bcycle = 0;
      _rswtch = (int) trunc(pContext.random() * 3.0); //  Chooses new 6 or 3 nodes
    }

    double lrmaj = pAmount; // Sets hexagon length radius - major plane
    double smooth = 1.0;
    double smRotxTP = 0.0;
    double smRotyTP = 0.0;
    double smRotxFT = 0.0;
    double smRotyFT = 0.0;
    double gentleZ = 0.0;

    if (fabs(pAmount) <= 0.5) {
      smooth = pAmount * 2.0;
    } else {
      smooth = 1.0;
    }
    double boost = 0.0; //  Boost is the separation distance between the two planes
    int posNeg = 1;
    int loc60;
    int loc120;
    double scale = this.scale;
    double scale3 = this._3side;

    if (pContext.random() < 0.5) {
      posNeg = -1;
    }

    // Determine whether one or two major planes
    int majplane = 0;
    double abmajp = fabs(this.majp);
    if (abmajp <= 1.0) {
      majplane = 0; // 0= 1 plate active  1= transition to two plates active  2= defines two plates
      boost = 0.0;
    } else if (abmajp > 1.0 && abmajp < 2.0) {
      majplane = 1;
      boost = 0.0;
    } else {
      majplane = 2;
      boost = (abmajp - 2.0) * 0.5; // distance above and below XY plane
    }

    //      Creating Z factors relative to the planes
    if (majplane == 0) {
      pVarTP.z += smooth * pAffineTP.z * scale * this.zlift; // single plate instructions
    } else if (majplane == 1
        && this.majp < 0.0) { // Transition for reversing plates  because  majp is negative value
      if (this.majp < -1.0 && this.majp >= -2.0) {
        gentleZ = (abmajp - 1.0); //  Set transition smoothing values  0.00001 to 1.0
      } else {
        gentleZ = 1.0; // full effect explicit default value
      }
      // Begin reverse transition - starts with pVarTP.z==pVarTP.z proceeds by gradual negative
      if (posNeg < 0) {
        pVarTP.z +=
            -2.0 * (pVarTP.z * gentleZ); // gradually grows negative plate, in place, no boost,
      }
    }
    if (majplane == 2
        && this.majp < 0.0) { // Begin the splitting operation, animation transition is done
      if (posNeg > 0) { //  The splitting operation positive side
        pVarTP.z += (smooth * (pAffineTP.z * scale * this.zlift + boost));
      } else { //  The splitting operation negative side
        pVarTP.z =
            (pVarTP.z - (2.0 * smooth * pVarTP.z))
                + (smooth * posNeg * (pAffineTP.z * scale * this.zlift + boost));
      }
    } else { //  majp > 0.0       The splitting operation
      pVarTP.z += smooth * (pAffineTP.z * scale * this.zlift + (posNeg * boost));
    }

    if (this._rswtch <= 1) { //  Occasion to build using 60 degree segments
      loc60 = (int) trunc(pContext.random() * 6.0); // random nodes selection
      // loc60 = this.fcycle;   // sequential nodes selection - seems to create artifacts that are
      // progressively displaced
      smRotxTP =
          (smooth * scale * pVarTP.x * _seg60x[loc60])
              - (smooth * scale * pVarTP.y * _seg60y[loc60]);
      smRotyTP =
          (smooth * scale * pVarTP.y * _seg60x[loc60])
              + (smooth * scale * pVarTP.x * _seg60y[loc60]);
      smRotxFT =
          (pAffineTP.x * smooth * scale * _seg60x[loc60])
              - (pAffineTP.y * smooth * scale * _seg60y[loc60]);
      smRotyFT =
          (pAffineTP.y * smooth * scale * _seg60x[loc60])
              + (pAffineTP.x * smooth * scale * _seg60y[loc60]);

      pVarTP.x = pVarTP.x * (1.0 - smooth) + smRotxTP + smRotxFT + smooth * lrmaj * _seg60x[loc60];
      pVarTP.y = pVarTP.y * (1.0 - smooth) + smRotyTP + smRotyFT + smooth * lrmaj * _seg60y[loc60];

      this._fcycle += 1;
    } else { // Occasion to build on 120 degree segments
      loc120 = (int) trunc(pContext.random() * 3.0); // random nodes selection
      // loc120 = this.bcycle;  // sequential nodes selection - seems to create artifacts that are
      // progressively displaced
      smRotxTP =
          (smooth * scale * pVarTP.x * _seg120x[loc120])
              - (smooth * scale * pVarTP.y * _seg120y[loc120]);
      smRotyTP =
          (smooth * scale * pVarTP.y * _seg120x[loc120])
              + (smooth * scale * pVarTP.x * _seg120y[loc120]);
      smRotxFT =
          (pAffineTP.x * smooth * scale * _seg120x[loc120])
              - (pAffineTP.y * smooth * scale * _seg120y[loc120]);
      smRotyFT =
          (pAffineTP.y * smooth * scale * _seg120x[loc120])
              + (pAffineTP.x * smooth * scale * _seg120y[loc120]);

      pVarTP.x =
          pVarTP.x * (1.0 - smooth)
              + smRotxTP
              + smRotxFT
              + smooth * lrmaj * scale3 * _seg120x[loc120];
      pVarTP.y =
          pVarTP.y * (1.0 - smooth)
              + smRotyTP
              + smRotyFT
              + smooth * lrmaj * scale3 * _seg120y[loc120];

      this._bcycle += 1;
    }
    /*
    Rotations need to interchange smoothly between x and y values (pseudo code)
    new x = in_x*cos(r) - in_y*sin(r) + movedLoci_x;
    new y = in_y*cos(r) + in_x*sin(r) + movedLoci_y;
    */
  }
  public void transform(
      FlameTransformationContext pContext,
      XForm pXForm,
      XYZPoint pAffineTP,
      XYZPoint pVarTP,
      double pAmount,
      double pInputX,
      double pInputY) {
    double x = (pInputX - (offsetX + 0.5) + 1.0) / scaleX * (double) (imgWidth - 1);
    double y = (pInputY - (offsetY + 0.5) + 1.0) / scaleY * (double) (imgHeight - 1);
    int ix = Tools.FTOI(x);
    int iy = Tools.FTOI(y);
    if (this.tileX == 1) {
      if (ix < 0) {
        int nx = ix / imgWidth - 1;
        ix -= nx * imgWidth;
      } else if (ix >= imgWidth) {
        int nx = ix / imgWidth;
        ix -= nx * imgWidth;
      }
    }
    if (this.tileY == 1) {
      if (iy < 0) {
        int ny = iy / imgHeight - 1;
        iy -= ny * imgHeight;
      } else if (iy >= imgHeight) {
        int ny = iy / imgHeight;
        iy -= ny * imgHeight;
      }
    }

    double r, g, b;
    if (ix >= 0 && ix < imgWidth && iy >= 0 && iy < imgHeight) {
      if (colorMap instanceof SimpleImage) {
        toolPixel.setARGBValue(((SimpleImage) colorMap).getARGBValue(ix, iy));
        r = (double) toolPixel.r / 255.0;
        g = (double) toolPixel.g / 255.0;
        b = (double) toolPixel.b / 255.0;
      } else {
        ((SimpleHDRImage) colorMap).getRGBValues(rgbArray, ix, iy);
        r = rgbArray[0];
        g = rgbArray[0];
        b = rgbArray[0];
      }
    } else {
      return;
    }

    switch (mode) {
      case MODE_TRANSLATE:
        {
          double amountX = (r - 0.5) * pAmount;
          double amountY = (g - 0.5) * pAmount;
          pVarTP.x += amountX;
          pVarTP.y += amountY;
        }
        break;
      case MODE_SCALE:
        {
          double intensity = calcIntensity(r, g, b) - bias;
          if (intensity > 0.0) {
            double scl = 1.0 + (intensity - 0.5) * pAmount;
            pVarTP.x *= scl;
            pVarTP.y *= scl;
          }
        }
        break;
      case MODE_SCISSOR:
        {
          double amountX = (r - 0.5) * pAmount;
          double amountY = (g - 0.5) * pAmount;
          double newx = pVarTP.x * amountX * amountY + pVarTP.y * amountY;
          double newy = pVarTP.x * amountY - pVarTP.y * amountX * amountY;
          pVarTP.x = newx;
          pVarTP.y = newy;
        }
        break;
      case MODE_ROTATE:
      default:
        {
          double intensity = calcIntensity(r, g, b) - bias;
          if (intensity > 0.0) {
            double angle = intensity * M_2PI * pAmount;
            double sina = sin(angle);
            double cosa = cos(angle);
            double xnew = pVarTP.x * cosa - pVarTP.y * sina;
            double ynew = pVarTP.x * sina + pVarTP.y * cosa;
            pVarTP.x = xnew;
            pVarTP.y = ynew;
          }
        }
    }

    switch (colorMode) {
      case COLOR_MODE_INHERIT:
        {
          pVarTP.rgbColor = true;
          pVarTP.redColor = r;
          pVarTP.greenColor = g;
          pVarTP.blueColor = b;
          pVarTP.color = getColorIdx(r, g, b);
        }
        break;
    }
  }
Пример #18
0
  @Override
  public void transform(
      FlameTransformationContext pContext,
      XForm pXForm,
      XYZPoint pAffineTP,
      XYZPoint pVarTP,
      double pAmount) {
    // bwrands, by dark-beam
    double Vx, Vy; // V is "global" vector,
    double Cx, Cy; // C is "cell centre" vector
    double Lx, Ly; // L is "local" bubble vector
    double r, theta, s, c;
    double Vv2, flwr;

    Vx = pAffineTP.x;
    Vy = pAffineTP.y;

    if (fabs(cellsize) < SMALL_EPSILON) {
      // Linear if cells are too small
      pVarTP.x += pAmount * Vx;
      pVarTP.y += pAmount * Vy;
      if (pContext.isPreserveZCoordinate()) {
        pVarTP.z += pAmount * pAffineTP.z;
      }
      return;
    }

    int Ix = (int) floor(Vx / cellsize);
    int Iy = (int) floor(Vy / cellsize);

    Cx = (Ix + 0.5) * cellsize;
    Cy = (Iy + 0.5) * cellsize;

    // mess with Ix & Iy to get random
    int xx = Ix ^ 0xB641;
    int yy = Iy ^ 0x9D81;
    int xy = xx * yy + seed;
    xx &= 0xFFFF;
    yy &= 0xFFFF;
    xy &= 0xFFFF;
    // no less than 3 remixes are needed to get good randomness
    // use always identical mixes or you lose some data (you don't want this!)
    int tt = bytemix(xx, yy);
    yy = bytemix(yy, xx);
    xx = tt;
    tt = byteshf(xx, xy);
    yy = byteshf(xy, yy);
    xx = tt;
    tt = bytexim(xx, yy);
    yy = bytexim(yy, xx);
    xx = tt;
    double Ssz = ((double) xx) / 65535.0; // to get a range not 0-1 for circles size edit here
    Ssz = rmin + Ssz * (1.0 - rmin);
    double Aan =
        rrot
            * M_2PI
            * ((double) yy)
            / 65535.0; // to get a range not 0-2pi for rotations size edit here
    tt = byteprimes(xx, yy);
    yy = byteprimes(yy, xx);
    xx = tt;
    double LoonieChance = -((double) xx) / 65535.0 + loonie_chance; // 0.5 for a chance 50% !
    double PetalsChance = 0.0;
    if (LoonieChance < 0) PetalsChance = LoonieChance + petals_chance;
    // user choice but don't upset modulus...
    double NPetals;
    if (_pety == 0) NPetals = (double) _petx; // ... when min = max
    else
      NPetals =
          (double)
              (_petx
                  + (yy >> 3)
                      % (1 + _pety)); // yy last byte is not enough random. But yy >> 3 is good

    if (LoonieChance <= PetalsChance) LoonieChance = -1.0; // the bigger probability must win.

    // if more random values are needed remix again :D

    Lx = Vx - Cx;
    Ly = Vy - Cy;

    Vv2 = Ssz * _r2;

    if ((Lx * Lx + Ly * Ly) > Vv2) {
      // Linear if outside the bubble
      pVarTP.x += pAmount * Vx;
      pVarTP.y += pAmount * Vy;
      if (pContext.isPreserveZCoordinate()) {
        pVarTP.z += pAmount * pAffineTP.z;
      }
      return;
    }

    if (LoonieChance > 0.0) {
      // We're in the loonie!
      // r = Vv2 / (Lx * Lx + Ly * Ly) - MAX(MIN(VAR(bwrands_gain),1.0),0.0); LOOKING BAD!!!
      r = Vv2 / (Lx * Lx + Ly * Ly) - 1.0;
      r = sqrt(r);
      Lx *= r;
      Ly *= r;
      Vv2 = 1.0; // recycled var
    } else if (PetalsChance > 0.0) {
      // We're in the petals!
      flwr = NPetals / M_2PI * (M_PI + atan2(Ly, Lx));
      flwr = flwr - (int) (flwr);
      flwr = fabs(flwr - 0.5) * 2.0;
      r = sqrt(Lx * Lx + Ly * Ly);

      // We need a little chaos game to fill the empty space outside the flower.
      PetalsChance = pContext.random();

      if (PetalsChance < .5 * (flwr + .5)) {
        // petals
        Lx *= (1.0 - r) * (flwr * 1.1); // 1.1 remove the ugly border
        Ly *= (1.0 - r) * (flwr * 1.1); // 1.1 remove the ugly border
      } else {
        Vv2 = sqrt(Vv2); // dist to circle border
        // filling the rest of the circle
        Lx *= (Vv2 - r * (1.0 - flwr)) / (r + SMALL_EPSILON);
        Ly *= (Vv2 - r * (1.0 - flwr)) / (r + SMALL_EPSILON);
      }

      Vv2 = 1.0; // recycled var
    } else {
      // We're in the bubble!
      // Bubble distortion on local co-ordinates:
      Lx *= _g2;
      Ly *= _g2;
      r = _rfactor / ((Lx * Lx + Ly * Ly) / (4.0 * Ssz) + 1.0);
      Lx *= r;
      Ly *= r;
      Vv2 = sqrt(Ssz); // recycled var
    }
    // Spin around the centre:
    r = Vv2 * (Lx * Lx + Ly * Ly) / _r2; // r should be 0.0 - 1.0
    theta = inner_twist * (1.0 - r) + outer_twist * r;
    s = sin(theta + Aan);
    c = cos(theta + Aan);

    // Add rotated local vectors direct to centre (avoids use of temp storage)
    Vx = Cx + c * Lx + s * Ly;
    Vy = Cy - s * Lx + c * Ly;

    // Finally add values in
    pVarTP.x += pAmount * Vx;
    pVarTP.y += pAmount * Vy;
    if (pContext.isPreserveZCoordinate()) {
      pVarTP.z += pAmount * pAffineTP.z;
    }
  }