shun-iwasawa a23340
#include "iwa_fractalnoisefx.h"
shun-iwasawa a23340
#include "iwa_noise1234.h"
shun-iwasawa a23340
#include "tparamuiconcept.h"
shun-iwasawa a23340
shun-iwasawa a23340
namespace {
shun-iwasawa a23340
// convert sRGB color space to power space
shun-iwasawa a23340
template <typename t="double"></typename>
shun-iwasawa a23340
inline T to_linear_color_space(T nonlinear_color, T exposure, T gamma) {
shun-iwasawa a23340
  // return -std::log(T(1) - std::pow(nonlinear_color, gamma)) / exposure;
shun-iwasawa a23340
  return std::pow(nonlinear_color, gamma) / exposure;
shun-iwasawa a23340
}
shun-iwasawa a23340
// convert power space to sRGB color space
shun-iwasawa a23340
template <typename t="double"></typename>
shun-iwasawa a23340
inline T to_nonlinear_color_space(T linear_color, T exposure, T gamma) {
shun-iwasawa a23340
  // return std::pow(T(1) - std::exp(-exposure * linear_color), T(1) / gamma);
shun-iwasawa a23340
  return std::pow(exposure * linear_color, T(1) / gamma);
shun-iwasawa a23340
}
shun-iwasawa a23340
shun-iwasawa a23340
inline double hardlight(const double *dn, const double *up) {
shun-iwasawa a23340
  if ((*up) < 0.5)
shun-iwasawa a23340
    return (*up) * (*dn) * 2.0;
shun-iwasawa a23340
  else
shun-iwasawa a23340
    return 1.0 - 2.0 * (1.0 - (*up)) * (1.0 - (*dn));
shun-iwasawa a23340
}
shun-iwasawa a23340
shun-iwasawa a23340
template <class t="double"></class>
shun-iwasawa a23340
inline const T &clamp(const T &v, const T &lo, const T &hi) {
shun-iwasawa a23340
  assert(!(hi < lo));
shun-iwasawa a23340
  return (v < lo) ? lo : (hi < v) ? hi : v;
shun-iwasawa a23340
}
shun-iwasawa a23340
shun-iwasawa a23340
const double turbulentGamma = 2.2;
shun-iwasawa a23340
// magic number to offset evolution between generations
shun-iwasawa a23340
const double evolutionOffsetStep = 19.82;
shun-iwasawa a23340
}  // namespace
shun-iwasawa a23340
//------------------------------------------------------------------
shun-iwasawa a23340
shun-iwasawa a23340
Iwa_FractalNoiseFx::Iwa_FractalNoiseFx()
shun-iwasawa a23340
    : m_fractalType(new TIntEnumParam(Basic, "Basic"))
shun-iwasawa a23340
    , m_noiseType(new TIntEnumParam(Block, "Block"))
shun-iwasawa a23340
    , m_invert(false)
shun-iwasawa a23340
    , m_rotation(0.0)
shun-iwasawa a23340
    , m_uniformScaling(true)
shun-iwasawa a23340
    , m_scale(100.0)
shun-iwasawa a23340
    , m_scaleW(100.0)
shun-iwasawa a23340
    , m_scaleH(100.0)
shun-iwasawa a23340
    , m_offsetTurbulence(TPointD(0.0, 0.0))
shun-iwasawa a23340
    , m_perspectiveOffset(false)
shun-iwasawa a23340
    , m_complexity(6.0)
shun-iwasawa a23340
    , m_subInfluence(70.0)
shun-iwasawa a23340
    , m_subScaling(56.0)
shun-iwasawa a23340
    , m_subRotation(0.0)
shun-iwasawa a23340
    , m_subOffset(TPointD(0.0, 0.0))
shun-iwasawa a23340
    ///, m_centerSubscale(false)
shun-iwasawa a23340
    , m_evolution(0.0)
shun-iwasawa a23340
    , m_cycleEvolution(false)
shun-iwasawa a23340
    , m_cycleEvolutionRange(1.0)
shun-iwasawa a23340
    ///, m_randomSeed(0)
shun-iwasawa a23340
    , m_dynamicIntensity(1.0)
shun-iwasawa a23340
    , m_alphaRendering(false) {
shun-iwasawa a23340
  m_fractalType->addItem(TurbulentSmooth, "Turbulent Smooth");
shun-iwasawa a23340
  m_fractalType->addItem(TurbulentBasic, "Turbulent Basic");
shun-iwasawa a23340
  m_fractalType->addItem(TurbulentSharp, "Turbulent Sharp");
shun-iwasawa a23340
  m_fractalType->addItem(Dynamic, "Dynamic");
shun-iwasawa a23340
  m_fractalType->addItem(DynamicTwist, "Dynamic Twist");
shun-iwasawa a23340
  m_fractalType->addItem(Max, "Max");
shun-iwasawa a23340
  m_fractalType->addItem(Rocky, "Rocky");
shun-iwasawa a23340
shun-iwasawa a23340
  m_noiseType->addItem(Smooth, "Smooth");
shun-iwasawa a23340
  m_noiseType->setValue(Smooth);
shun-iwasawa a23340
shun-iwasawa a23340
  m_rotation->setMeasureName("angle");
shun-iwasawa a23340
  m_rotation->setValueRange(-360.0, 360.0);
shun-iwasawa a23340
  m_scale->setMeasureName("fxLength");
shun-iwasawa a23340
  m_scale->setValueRange(20.0, 600.0);
shun-iwasawa a23340
  m_scaleW->setMeasureName("fxLength");
shun-iwasawa a23340
  m_scaleW->setValueRange(20.0, 600.0);
shun-iwasawa a23340
  m_scaleH->setMeasureName("fxLength");
shun-iwasawa a23340
  m_scaleH->setValueRange(20.0, 600.0);
shun-iwasawa a23340
  m_offsetTurbulence->getX()->setMeasureName("fxLength");
shun-iwasawa a23340
  m_offsetTurbulence->getY()->setMeasureName("fxLength");
shun-iwasawa a23340
shun-iwasawa a23340
  m_complexity->setValueRange(1.0, 10.0);
shun-iwasawa a23340
  m_subInfluence->setValueRange(25.0, 100.0);
shun-iwasawa a23340
  m_subScaling->setValueRange(25.0, 100.0);
shun-iwasawa a23340
  m_subRotation->setMeasureName("angle");
shun-iwasawa a23340
  m_subRotation->setValueRange(-360.0, 360.0);
shun-iwasawa a23340
  m_subOffset->getX()->setMeasureName("fxLength");
shun-iwasawa a23340
  m_subOffset->getY()->setMeasureName("fxLength");
shun-iwasawa a23340
shun-iwasawa a23340
  m_evolution->setValueRange(-100.0, 100.0);
shun-iwasawa a23340
  m_cycleEvolutionRange->setValueRange(0.1, 30.0);
shun-iwasawa a23340
  m_dynamicIntensity->setValueRange(-10.0, 10.0);
shun-iwasawa a23340
shun-iwasawa a23340
  bindParam(this, "fractalType", m_fractalType);
shun-iwasawa a23340
  bindParam(this, "noiseType", m_noiseType);
shun-iwasawa a23340
  bindParam(this, "invert", m_invert);
shun-iwasawa a23340
  bindParam(this, "rotation", m_rotation);
shun-iwasawa a23340
  bindParam(this, "uniformScaling", m_uniformScaling);
shun-iwasawa a23340
  bindParam(this, "scale", m_scale);
shun-iwasawa a23340
  bindParam(this, "scaleW", m_scaleW);
shun-iwasawa a23340
  bindParam(this, "scaleH", m_scaleH);
shun-iwasawa a23340
  bindParam(this, "offsetTurbulence", m_offsetTurbulence);
shun-iwasawa a23340
  bindParam(this, "perspectiveOffset", m_perspectiveOffset);
shun-iwasawa a23340
  bindParam(this, "complexity", m_complexity);
shun-iwasawa a23340
  bindParam(this, "subInfluence", m_subInfluence);
shun-iwasawa a23340
  bindParam(this, "subScaling", m_subScaling);
shun-iwasawa a23340
  bindParam(this, "subRotation", m_subRotation);
shun-iwasawa a23340
  bindParam(this, "subOffset", m_subOffset);
shun-iwasawa a23340
  /// bindParam(this, "centerSubscale", m_centerSubscale);
shun-iwasawa a23340
  bindParam(this, "evolution", m_evolution);
shun-iwasawa a23340
  bindParam(this, "cycleEvolution", m_cycleEvolution);
shun-iwasawa a23340
  bindParam(this, "cycleEvolutionRange", m_cycleEvolutionRange);
shun-iwasawa a23340
  /// bindParam(this, "randomSeed", m_randomSeed);
shun-iwasawa a23340
  bindParam(this, "dynamicIntensity", m_dynamicIntensity);
shun-iwasawa a23340
shun-iwasawa a23340
  bindParam(this, "alphaRendering", m_alphaRendering);
shun-iwasawa a23340
}
shun-iwasawa a23340
shun-iwasawa a23340
//------------------------------------------------------------------
shun-iwasawa a23340
shun-iwasawa a23340
bool Iwa_FractalNoiseFx::doGetBBox(double frame, TRectD &bBox,
shun-iwasawa a23340
                                   const TRenderSettings &ri) {
shun-iwasawa a23340
  bBox = TConsts::infiniteRectD;
shun-iwasawa a23340
  return true;
shun-iwasawa a23340
}
shun-iwasawa a23340
shun-iwasawa a23340
//------------------------------------------------------------------
shun-iwasawa a23340
shun-iwasawa a23340
void Iwa_FractalNoiseFx::doCompute(TTile &tile, double frame,
shun-iwasawa a23340
                                   const TRenderSettings &ri) {
shun-iwasawa a23340
  // obtain current parameters
shun-iwasawa a23340
  FNParam param;
shun-iwasawa a23340
  obtainParams(param, frame, ri.m_affine);
shun-iwasawa a23340
shun-iwasawa a23340
  Noise1234 pn;
shun-iwasawa a23340
shun-iwasawa a23340
  TDimension outDim = tile.getRaster()->getSize();
shun-iwasawa a23340
  // allocate buffer for accumulating the noise patterns
shun-iwasawa a23340
  TRasterGR8P out_buf_ras = TRasterGR8P(outDim.lx * sizeof(double), outDim.ly);
shun-iwasawa a23340
  out_buf_ras->clear();
shun-iwasawa a23340
  out_buf_ras->lock();
shun-iwasawa a23340
  double *out_buf = (double *)out_buf_ras->getRawData();
shun-iwasawa a23340
shun-iwasawa a23340
  // allocate buffer for storing the noise pattern of each generation
shun-iwasawa a23340
  TRasterGR8P work_buf_ras = TRasterGR8P(outDim.lx * sizeof(double), outDim.ly);
shun-iwasawa a23340
  work_buf_ras->lock();
shun-iwasawa a23340
  double *work_buf = (double *)work_buf_ras->getRawData();
shun-iwasawa a23340
shun-iwasawa a23340
  // affine transformations
shun-iwasawa a23340
  TAffine globalAff       = TTranslation(-tile.m_pos) * ri.m_affine;
shun-iwasawa a23340
  TAffine parentOffsetAff = TTranslation(param.offsetTurbulence);
shun-iwasawa a23340
  TAffine parentAff =
shun-iwasawa a23340
      TScale(param.scale.lx, param.scale.ly) * TRotation(-param.rotation);
shun-iwasawa a23340
  TAffine subAff = TTranslation(param.subOffset) * TScale(param.subScaling) *
shun-iwasawa a23340
                   TRotation(-param.subRotation);
shun-iwasawa a23340
shun-iwasawa a23340
  TAffine genAff;
shun-iwasawa a23340
shun-iwasawa a23340
  // for cyclic evolution, rotate the sample position in ZW space instead of
shun-iwasawa a23340
  // using the periodic noise in Z space so that it can cycle in arbitral
shun-iwasawa a23340
  // period.
shun-iwasawa a23340
  double evolution_z = param.evolution;
shun-iwasawa a23340
  TPointD evolution_zw;
shun-iwasawa a23340
  if (param.cycleEvolution) {
shun-iwasawa a23340
    double theta   = 2.0 * M_PI * param.evolution / param.cycleEvolutionRange;
shun-iwasawa a23340
    double d       = param.cycleEvolutionRange / (2.0 * M_PI);
shun-iwasawa a23340
    evolution_zw.x = d * cos(theta);
shun-iwasawa a23340
    evolution_zw.y = d * sin(theta);
shun-iwasawa a23340
  }
shun-iwasawa a23340
shun-iwasawa a23340
  int genCount = (int)std::ceil(param.complexity);
shun-iwasawa a23340
shun-iwasawa a23340
  // accumulate base noise pattern for each generation
shun-iwasawa a23340
  for (int gen = 0; gen < genCount; gen++) {
shun-iwasawa a23340
    // affine transformation for the current generation
shun-iwasawa a23340
    TAffine currentAff =
shun-iwasawa 93d258
        (globalAff * parentOffsetAff * parentAff * genAff).inv();
shun-iwasawa a23340
    // scale of the current pattern ( used for the Dynamic / Dynamic Twist
shun-iwasawa a23340
    // offset )
shun-iwasawa a23340
    double scale = sqrt(std::abs(currentAff.det()));
shun-iwasawa a23340
shun-iwasawa a23340
    // for each pixel
shun-iwasawa a23340
    double *buf_p = work_buf;
shun-iwasawa a23340
    for (int y = 0; y < outDim.ly; y++) {
shun-iwasawa a23340
      for (int x = 0; x < outDim.lx; x++, buf_p++) {
shun-iwasawa a23340
        // obtain sampling position
shun-iwasawa a23340
        // For Dynamic and Dynamic Twist patterns, the position offsets using
shun-iwasawa a23340
        // gradient / rotation of the parent pattern
shun-iwasawa a23340
        TPointD samplePos =
shun-iwasawa a23340
            getSamplePos(x, y, outDim, out_buf, gen, scale, param);
shun-iwasawa a23340
        // multiply affine transformation
shun-iwasawa a23340
        samplePos = currentAff * samplePos;
shun-iwasawa a23340
        // adjust postion for the block pattern
shun-iwasawa a23340
        if (param.noiseType == Block)
shun-iwasawa a23340
          samplePos = TPointD(std::floor(samplePos.x) + 0.5,
shun-iwasawa a23340
                              std::floor(samplePos.y) + 0.5);
shun-iwasawa a23340
        // calculate the base noise
shun-iwasawa a23340
        if (param.cycleEvolution)
shun-iwasawa a23340
          *buf_p = (pn.noise(samplePos.x, samplePos.y, evolution_zw.x,
shun-iwasawa a23340
                             evolution_zw.y) +
shun-iwasawa a23340
                    1.0) *
shun-iwasawa a23340
                   0.5;
shun-iwasawa a23340
        else
shun-iwasawa a23340
          *buf_p =
shun-iwasawa a23340
              (pn.noise(samplePos.x, samplePos.y, evolution_z) + 1.0) * 0.5;
shun-iwasawa a23340
shun-iwasawa a23340
        // convert the noise
shun-iwasawa a23340
        convert(buf_p, param);
shun-iwasawa a23340
      }
shun-iwasawa a23340
    }
shun-iwasawa a23340
shun-iwasawa a23340
    // just copy the values for the first generation
shun-iwasawa a23340
    if (gen == 0) {
shun-iwasawa a23340
      memcpy(out_buf, work_buf, outDim.lx * outDim.ly * sizeof(double));
shun-iwasawa a23340
    } else {
shun-iwasawa a23340
      // intensity of the last generation will take the fraction part of
shun-iwasawa a23340
      // complexity
shun-iwasawa a23340
      double genIntensity = std::min(1.0, param.complexity - (double)gen);
shun-iwasawa a23340
      // influence of the current generation
shun-iwasawa a23340
      double influence =
shun-iwasawa a23340
          genIntensity * std::pow(param.subInfluence, (double)gen);
shun-iwasawa a23340
      // composite the base noise pattern
shun-iwasawa a23340
      buf_p         = work_buf;
shun-iwasawa a23340
      double *out_p = out_buf;
shun-iwasawa a23340
      for (int i = 0; i < outDim.lx * outDim.ly; i++, buf_p++, out_p++)
shun-iwasawa a23340
        composite(out_p, buf_p, influence, param);
shun-iwasawa a23340
    }
shun-iwasawa a23340
shun-iwasawa a23340
    // update affine transformations (for the next generation loop)
shun-iwasawa a23340
    genAff *= subAff;
shun-iwasawa a23340
    // When the "Perspective Offset" option is ON, reduce the offset amount
shun-iwasawa a23340
    // according to the sub scale
shun-iwasawa a23340
    if (param.perspectiveOffset)
shun-iwasawa a23340
      parentOffsetAff = TScale(param.subScaling) *
shun-iwasawa a23340
                        TRotation(-param.subRotation) * parentOffsetAff *
shun-iwasawa a23340
                        TRotation(param.subRotation) *
shun-iwasawa a23340
                        TScale(1 / param.subScaling);
shun-iwasawa a23340
shun-iwasawa a23340
    if (param.cycleEvolution)
shun-iwasawa a23340
      evolution_zw.x += evolutionOffsetStep;
shun-iwasawa a23340
    else
shun-iwasawa a23340
      evolution_z += evolutionOffsetStep;
shun-iwasawa a23340
  }
shun-iwasawa a23340
shun-iwasawa a23340
  work_buf_ras->unlock();
shun-iwasawa a23340
shun-iwasawa a23340
  // finalize pattern (coverting the color space)
shun-iwasawa a23340
  if (param.fractalType == TurbulentSmooth ||
shun-iwasawa a23340
      param.fractalType == TurbulentBasic ||
shun-iwasawa a23340
      param.fractalType == TurbulentSharp) {
shun-iwasawa a23340
    double *out_p = out_buf;
shun-iwasawa a23340
    for (int i = 0; i < outDim.lx * outDim.ly; i++, out_p++)
shun-iwasawa a23340
      finalize(out_p, param);
shun-iwasawa a23340
  }
shun-iwasawa a23340
shun-iwasawa a23340
  tile.getRaster()->clear();
shun-iwasawa a23340
shun-iwasawa a23340
  // convert to RGB channel values
shun-iwasawa a23340
  TRaster32P ras32 = (TRaster32P)tile.getRaster();
shun-iwasawa a23340
  TRaster64P ras64 = (TRaster64P)tile.getRaster();
shun-iwasawa a23340
  if (ras32)
shun-iwasawa a23340
    outputRaster<traster32p, tpixel32="">(ras32, out_buf, param);</traster32p,>
shun-iwasawa a23340
  else if (ras64)
shun-iwasawa a23340
    outputRaster<traster64p, tpixel64="">(ras64, out_buf, param);</traster64p,>
shun-iwasawa a23340
shun-iwasawa a23340
  out_buf_ras->unlock();
shun-iwasawa a23340
}
shun-iwasawa a23340
shun-iwasawa a23340
//------------------------------------------------------------------
shun-iwasawa a23340
// obtain current parameters
shun-iwasawa a23340
void Iwa_FractalNoiseFx::obtainParams(FNParam ¶m, const double frame,
shun-iwasawa a23340
                                      const TAffine &aff) {
shun-iwasawa a23340
  param.fractalType = (FractalType)m_fractalType->getValue();
shun-iwasawa a23340
  param.noiseType   = (NoiseType)m_noiseType->getValue();
shun-iwasawa a23340
  param.invert      = m_invert->getValue();
shun-iwasawa a23340
  param.rotation    = m_rotation->getValue(frame);  // in degree, not radian
shun-iwasawa a23340
  if (m_uniformScaling->getValue()) {               // uniform case
shun-iwasawa a23340
    double s    = m_scale->getValue(frame);
shun-iwasawa a23340
    param.scale = TDimensionD(s, s);
shun-iwasawa a23340
  } else {  // non-uniform case
shun-iwasawa a23340
    param.scale.lx = m_scaleW->getValue(frame);
shun-iwasawa a23340
    param.scale.ly = m_scaleH->getValue(frame);
shun-iwasawa a23340
  }
shun-iwasawa a23340
  assert(param.scale.lx != 0.0 && param.scale.ly != 0.0);
shun-iwasawa a23340
  if (param.scale.lx == 0.0) param.scale.lx = 1e-8;
shun-iwasawa a23340
  if (param.scale.ly == 0.0) param.scale.ly = 1e-8;
shun-iwasawa a23340
shun-iwasawa a23340
  param.offsetTurbulence  = m_offsetTurbulence->getValue(frame);
shun-iwasawa a23340
  param.perspectiveOffset = m_perspectiveOffset->getValue();
shun-iwasawa a23340
  param.complexity        = m_complexity->getValue(frame);
shun-iwasawa a23340
  if (param.complexity < 1.0)
shun-iwasawa a23340
    param.complexity =
shun-iwasawa a23340
        1.0;  // at least the first generation is rendered in full opacity
shun-iwasawa a23340
  param.subInfluence =
shun-iwasawa a23340
      m_subInfluence->getValue(frame) / 100.0;  // normalize to 0 - 1
shun-iwasawa a23340
  param.subScaling =
shun-iwasawa a23340
      m_subScaling->getValue(frame) / 100.0;           // normalize to 0 - 1
shun-iwasawa a23340
  param.subRotation = m_subRotation->getValue(frame);  // in degree, not radian
shun-iwasawa a23340
  param.subOffset   = m_subOffset->getValue(frame);
shun-iwasawa a23340
  param.evolution   = m_evolution->getValue(frame);
shun-iwasawa a23340
  param.cycleEvolution      = m_cycleEvolution->getValue();
shun-iwasawa a23340
  param.cycleEvolutionRange = m_cycleEvolutionRange->getValue(frame);
shun-iwasawa a23340
  param.dynamicIntensity    = m_dynamicIntensity->getValue(frame) * 10.0;
shun-iwasawa a23340
  param.alphaRendering      = m_alphaRendering->getValue();
shun-iwasawa a23340
}
shun-iwasawa a23340
shun-iwasawa a23340
//------------------------------------------------------------------
shun-iwasawa a23340
template <typename pixel="" raster,="" typename=""></typename>
shun-iwasawa a23340
void Iwa_FractalNoiseFx::outputRaster(const RASTER outRas, double *out_buf,
shun-iwasawa a23340
                                      const FNParam ¶m) {
shun-iwasawa a23340
  TDimension dim = outRas->getSize();
shun-iwasawa a23340
  double *buf_p  = out_buf;
shun-iwasawa a23340
  for (int j = 0; j < dim.ly; j++) {
shun-iwasawa a23340
    PIXEL *pix = outRas->pixels(j);
shun-iwasawa a23340
    for (int i = 0; i < dim.lx; i++, pix++, buf_p++) {
shun-iwasawa a23340
      double val                   = (param.invert) ? 1.0 - (*buf_p) : (*buf_p);
shun-iwasawa a23340
      val                          = clamp(val, 0.0, 1.0);
shun-iwasawa a23340
      typename PIXEL::Channel chan = static_cast<typename pixel::channel="">(</typename>
shun-iwasawa a23340
          val * (double)PIXEL::maxChannelValue);
shun-iwasawa a23340
      pix->r = chan;
shun-iwasawa a23340
      pix->g = chan;
shun-iwasawa a23340
      pix->b = chan;
shun-iwasawa a23340
      pix->m = (param.alphaRendering) ? chan : PIXEL::maxChannelValue;
shun-iwasawa a23340
    }
shun-iwasawa a23340
  }
shun-iwasawa a23340
}
shun-iwasawa a23340
shun-iwasawa a23340
//------------------------------------------------------------------
shun-iwasawa a23340
shun-iwasawa a23340
void Iwa_FractalNoiseFx::getParamUIs(TParamUIConcept *&concepts, int &length) {
shun-iwasawa a23340
  concepts = new TParamUIConcept[length = 2];
shun-iwasawa a23340
shun-iwasawa a23340
  concepts[0].m_type  = TParamUIConcept::POINT;
shun-iwasawa a23340
  concepts[0].m_label = "Offset Turbulence";
shun-iwasawa a23340
  concepts[0].m_params.push_back(m_offsetTurbulence);
shun-iwasawa a23340
shun-iwasawa a23340
  concepts[1].m_type  = TParamUIConcept::POINT;
shun-iwasawa a23340
  concepts[1].m_label = "Sub Offset";
shun-iwasawa a23340
  concepts[1].m_params.push_back(m_subOffset);
shun-iwasawa a23340
}
shun-iwasawa a23340
//------------------------------------------------------------------
shun-iwasawa a23340
// For Dynamic and Dynamic Twist patterns, the position offsets using gradient /
shun-iwasawa a23340
// rotation of the parent pattern
shun-iwasawa a23340
TPointD Iwa_FractalNoiseFx::getSamplePos(int x, int y, const TDimension outDim,
shun-iwasawa a23340
                                         const double *out_buf, const int gen,
shun-iwasawa a23340
                                         const double scale,
shun-iwasawa a23340
                                         const FNParam ¶m) {
shun-iwasawa a23340
  // the position does not offset in the first generation
shun-iwasawa a23340
  if (gen == 0 || param.dynamicIntensity == 0.0 ||
shun-iwasawa a23340
      (param.fractalType != Dynamic && param.fractalType != DynamicTwist))
shun-iwasawa a23340
    return TPointD((double)x, (double)y);
shun-iwasawa a23340
shun-iwasawa a23340
  auto clampPos = [&](int x, int y) {
shun-iwasawa a23340
    if (x < 0)
shun-iwasawa a23340
      x = 0;
shun-iwasawa a23340
    else if (x >= outDim.lx)
shun-iwasawa a23340
      x = outDim.lx - 1;
shun-iwasawa a23340
    if (y < 0)
shun-iwasawa a23340
      y = 0;
shun-iwasawa a23340
    else if (y >= outDim.ly)
shun-iwasawa a23340
      y = outDim.ly - 1;
shun-iwasawa a23340
    return TPoint(x, y);
shun-iwasawa a23340
  };
shun-iwasawa a23340
shun-iwasawa a23340
  auto val    = [&](const TPoint &p) { return out_buf[p.y * outDim.lx + p.x]; };
shun-iwasawa a23340
  int range   = std::max(2, (int)(0.1 / scale));
shun-iwasawa a23340
  TPoint left = clampPos(x - range, y);
shun-iwasawa a23340
  TPoint right = clampPos(x + range, y);
shun-iwasawa a23340
  TPoint down  = clampPos(x, y - range);
shun-iwasawa a23340
  TPoint up    = clampPos(x, y + range);
shun-iwasawa a23340
shun-iwasawa a23340
  double dif_x = param.dynamicIntensity * (1 / scale) *
shun-iwasawa a23340
                 (val(left) - val(right)) / (left.x - right.x);
shun-iwasawa a23340
  double dif_y = param.dynamicIntensity * (1 / scale) * (val(up) - val(down)) /
shun-iwasawa a23340
                 (up.y - down.y);
shun-iwasawa a23340
shun-iwasawa a23340
  if (param.fractalType == Dynamic)
shun-iwasawa a23340
    return TPointD((double)x + dif_x, (double)y + dif_y);  // gradient
shun-iwasawa a23340
  else                                                     // Dynamic_twist
shun-iwasawa a23340
    return TPointD((double)x + dif_y, (double)y - dif_x);  // rotation
shun-iwasawa a23340
}
shun-iwasawa a23340
shun-iwasawa a23340
//------------------------------------------------------------------
shun-iwasawa a23340
// convert the noise
shun-iwasawa a23340
void Iwa_FractalNoiseFx::convert(double *buf, const FNParam ¶m) {
shun-iwasawa a23340
  if (param.fractalType == Basic || param.fractalType == Dynamic ||
shun-iwasawa a23340
      param.fractalType == DynamicTwist)
shun-iwasawa a23340
    return;
shun-iwasawa a23340
shun-iwasawa a23340
  switch (param.fractalType) {
shun-iwasawa a23340
  case TurbulentSmooth:
shun-iwasawa a23340
    *buf = std::pow(std::abs(*buf - 0.5), 2.0) * 3.75;
shun-iwasawa a23340
    *buf = to_linear_color_space(*buf, 1.0, turbulentGamma);
shun-iwasawa a23340
    break;
shun-iwasawa a23340
  case TurbulentBasic:
shun-iwasawa a23340
    *buf = std::pow(std::abs(*buf - 0.5), 1.62) * 4.454;
shun-iwasawa a23340
    *buf = to_linear_color_space(*buf, 1.0, turbulentGamma);
shun-iwasawa a23340
    break;
shun-iwasawa a23340
  case TurbulentSharp:
shun-iwasawa a23340
    *buf = std::pow(std::abs(*buf - 0.5), 0.725) * 1.77;
shun-iwasawa a23340
    *buf = to_linear_color_space(*buf, 1.0, turbulentGamma);
shun-iwasawa a23340
    break;
shun-iwasawa a23340
  case Max:
shun-iwasawa a23340
    *buf = std::abs(*buf - 0.5) * 1.96;
shun-iwasawa a23340
    break;
shun-iwasawa a23340
  case Rocky:
shun-iwasawa a23340
    // convertion LUT for the range from 0.43 to 0.57, every 0.01
shun-iwasawa a23340
    static double table[15] = {
shun-iwasawa a23340
        0.25,        0.256658635, 0.275550218, 0.30569519,  0.345275591,
shun-iwasawa a23340
        0.392513494, 0.440512,    0.5,         0.555085147, 0.607486506,
shun-iwasawa a23340
        0.654724409, 0.69430481,  0.724449782, 0.743341365, 0.75};
shun-iwasawa a23340
    if (*buf <= 0.43)
shun-iwasawa a23340
      *buf = 0.25;
shun-iwasawa a23340
    else if (*buf >= 0.57)
shun-iwasawa a23340
      *buf = 0.75;
shun-iwasawa a23340
    else {
shun-iwasawa a23340
      int id   = (int)std::floor(*buf * 100.0) - 43;
shun-iwasawa a23340
      double t = *buf * 100.0 - (double)(id + 43);
shun-iwasawa a23340
      // linear interpolation the LUT values
shun-iwasawa a23340
      *buf = (1 - t) * table[id] + t * table[id + 1];
shun-iwasawa a23340
    }
shun-iwasawa a23340
    break;
shun-iwasawa a23340
  }
shun-iwasawa a23340
}
shun-iwasawa a23340
shun-iwasawa a23340
//------------------------------------------------------------------
shun-iwasawa a23340
// composite the base noise pattern
shun-iwasawa a23340
void Iwa_FractalNoiseFx::composite(double *out, double *buf,
shun-iwasawa a23340
                                   const double influence,
shun-iwasawa a23340
                                   const FNParam ¶m) {
shun-iwasawa a23340
  switch (param.fractalType) {
shun-iwasawa a23340
  case Basic:
shun-iwasawa a23340
  case Dynamic:
shun-iwasawa a23340
  case DynamicTwist:
shun-iwasawa a23340
  case Rocky: {
shun-iwasawa a23340
    // hard light composition
shun-iwasawa a23340
    double val = hardlight(out, buf);
shun-iwasawa a23340
    *out       = (1.0 - influence) * (*out) + influence * val;
shun-iwasawa a23340
    break;
shun-iwasawa a23340
  }
shun-iwasawa a23340
  case TurbulentSmooth:
shun-iwasawa a23340
  case TurbulentBasic:
shun-iwasawa a23340
  case TurbulentSharp:
shun-iwasawa a23340
    // add composition in the linear color space
shun-iwasawa a23340
    *out += (*buf) * influence;
shun-iwasawa a23340
    break;
shun-iwasawa a23340
  case Max:
shun-iwasawa a23340
    // max composition
shun-iwasawa a23340
    *out = std::max(*out, influence * (*buf));
shun-iwasawa a23340
    break;
shun-iwasawa a23340
  default: {
shun-iwasawa a23340
    double val = hardlight(out, buf);
shun-iwasawa a23340
    *out       = (1.0 - influence) * (*out) + influence * val;
shun-iwasawa a23340
    break;
shun-iwasawa a23340
  }
shun-iwasawa a23340
  }
shun-iwasawa a23340
}
shun-iwasawa a23340
shun-iwasawa a23340
//------------------------------------------------------------------
shun-iwasawa a23340
// finalize pattern (coverting the color space)
shun-iwasawa a23340
void Iwa_FractalNoiseFx::finalize(double *out, const FNParam ¶m) {
shun-iwasawa a23340
  assert(param.fractalType == TurbulentSmooth ||
shun-iwasawa a23340
         param.fractalType == TurbulentBasic ||
shun-iwasawa a23340
         param.fractalType == TurbulentSharp);
shun-iwasawa a23340
shun-iwasawa a23340
  // TurbulentSmooth / TurbulentBasic / TurbulentSharp
shun-iwasawa a23340
  *out = to_nonlinear_color_space(*out, 1.0, turbulentGamma);
shun-iwasawa a23340
}
shun-iwasawa a23340
shun-iwasawa a23340
FX_PLUGIN_IDENTIFIER(Iwa_FractalNoiseFx, "iwa_FractalNoiseFx");