shun-iwasawa 25dc51
#include "iwa_glarefx.h"
shun-iwasawa 25dc51
shun-iwasawa 25dc51
#include "trop.h"
shun-iwasawa 25dc51
#include "tdoubleparam.h"
shun-iwasawa 25dc51
#include "trasterfx.h"
shun-iwasawa 25dc51
#include "trasterimage.h"
shun-iwasawa 25dc51
shun-iwasawa 25dc51
#include "tparamuiconcept.h"
shun-iwasawa 25dc51
shun-iwasawa 25dc51
#include "kiss_fft.h"
shun-iwasawa 25dc51
#include "iwa_cie_d65.h"
shun-iwasawa 25dc51
#include "iwa_xyz.h"
shun-iwasawa 25dc51
#include "iwa_simplexnoise.h"
shun-iwasawa 25dc51
shun-iwasawa c1adfa
#include <random></random>
shun-iwasawa c1adfa
shun-iwasawa 25dc51
#include <qpair></qpair>
shun-iwasawa 25dc51
#include <qvector></qvector>
shun-iwasawa 25dc51
#include <qreadwritelock></qreadwritelock>
shun-iwasawa 25dc51
#include <qmutexlocker></qmutexlocker>
shun-iwasawa 25dc51
#include <qmap></qmap>
shun-iwasawa c1adfa
#include <qimage></qimage>
shun-iwasawa c1adfa
#include <qpainter></qpainter>
shun-iwasawa 25dc51
shun-iwasawa 25dc51
namespace {
shun-iwasawa 25dc51
// FFT coordinate -> Normal corrdinate
shun-iwasawa 25dc51
inline int getCoord(int i, int j, int lx, int ly) {
shun-iwasawa 25dc51
  int cx = i - lx / 2;
shun-iwasawa 25dc51
  int cy = j - ly / 2;
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  if (cx < 0) cx += lx;
shun-iwasawa 25dc51
  if (cy < 0) cy += ly;
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  return cy * lx + cx;
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
};  // namespace
shun-iwasawa 25dc51
shun-iwasawa 25dc51
//--------------------------------------------
shun-iwasawa 25dc51
// Iwa_GlareFx
shun-iwasawa 25dc51
//--------------------------------------------
shun-iwasawa 25dc51
shun-iwasawa 25dc51
Iwa_GlareFx::Iwa_GlareFx()
shun-iwasawa 25dc51
    : m_renderMode(new TIntEnumParam(RendeMode_FilterPreview, "Filter Preview"))
shun-iwasawa c1adfa
    , m_irisMode(new TIntEnumParam(Iris_InputImage, "Input Image"))
shun-iwasawa c1adfa
    , m_irisScale(0.2)
shun-iwasawa c1adfa
    , m_irisGearEdgeCount(10)
shun-iwasawa c1adfa
    , m_irisRandomSeed(0)
shun-iwasawa c1adfa
    , m_irisSymmetry(1.0)
shun-iwasawa c1adfa
    , m_irisAppearance(new TIntEnumParam())
shun-iwasawa 25dc51
    , m_intensity(0.0)
shun-iwasawa 25dc51
    , m_size(100.0)
shun-iwasawa 25dc51
    , m_rotation(0.0)
shun-iwasawa c1adfa
    , m_aberration(1.0)
shun-iwasawa 25dc51
    , m_noise_factor(0.0)
shun-iwasawa 25dc51
    , m_noise_size(0.5)
shun-iwasawa 25dc51
    , m_noise_octave(new TIntEnumParam(1, "1"))
shun-iwasawa 25dc51
    , m_noise_evolution(0.0)
shun-iwasawa 25dc51
    , m_noise_offset(TPointD(0, 0)) {
shun-iwasawa c1adfa
  // Version 1 : lights had been constantly summed in all wavelength
shun-iwasawa c1adfa
  // Version 2 : intensities are weighted proportional to 1/(rambda^2)
shun-iwasawa c1adfa
  setFxVersion(2);
shun-iwasawa c1adfa
shun-iwasawa 25dc51
  // Bind the common parameters
shun-iwasawa 25dc51
  addInputPort("Source", m_source);
shun-iwasawa 25dc51
  addInputPort("Iris", m_iris);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  bindParam(this, "renderMode", m_renderMode);
shun-iwasawa 25dc51
  m_renderMode->addItem(RendeMode_Render, "Render");
shun-iwasawa c1adfa
  m_renderMode->addItem(RenderMode_Iris, "Iris");
shun-iwasawa c1adfa
shun-iwasawa c1adfa
  bindParam(this, "irisMode", m_irisMode);
shun-iwasawa c1adfa
  m_irisMode->addItem(Iris_Square, "4 Streaks");
shun-iwasawa c1adfa
  m_irisMode->addItem(Iris_Hexagon, "6 Streaks");
shun-iwasawa c1adfa
  m_irisMode->addItem(Iris_Octagon, "8 Streaks");
shun-iwasawa c1adfa
  m_irisMode->addItem(Iris_GearShape, "Multiple Streaks");
shun-iwasawa c1adfa
shun-iwasawa c1adfa
  bindParam(this, "irisScale", m_irisScale);
shun-iwasawa c1adfa
  bindParam(this, "irisGearEdgeCount", m_irisGearEdgeCount);
shun-iwasawa c1adfa
  bindParam(this, "irisRandomSeed", m_irisRandomSeed);
shun-iwasawa c1adfa
  bindParam(this, "irisSymmetry", m_irisSymmetry);
shun-iwasawa c1adfa
  bindParam(this, "irisAppearance", m_irisAppearance);
shun-iwasawa c1adfa
  m_irisAppearance->addItem(Appearance_ThinLine, "Thin Line");
shun-iwasawa c1adfa
  m_irisAppearance->addItem(Appearance_MediumLine, "Medium Line");
shun-iwasawa c1adfa
  m_irisAppearance->addItem(Appearance_ThickLine, "Thick Line");
shun-iwasawa c1adfa
  m_irisAppearance->addItem(Appearance_Fill, "Filled");
shun-iwasawa c1adfa
  m_irisAppearance->setValue(Appearance_MediumLine);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  bindParam(this, "intensity", m_intensity, false);
shun-iwasawa 25dc51
  bindParam(this, "size", m_size, false);
shun-iwasawa 25dc51
  m_size->setMeasureName("fxLength");
shun-iwasawa 25dc51
  bindParam(this, "rotation", m_rotation, false);
shun-iwasawa c1adfa
  bindParam(this, "aberration", m_aberration, false);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  bindParam(this, "noise_factor", m_noise_factor, false);
shun-iwasawa 25dc51
  bindParam(this, "noise_size", m_noise_size, false);
shun-iwasawa 25dc51
  bindParam(this, "noise_octave", m_noise_octave, false);
shun-iwasawa 25dc51
  m_noise_octave->addItem(2, "2");
shun-iwasawa 25dc51
  m_noise_octave->addItem(3, "3");
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  bindParam(this, "noise_evolution", m_noise_evolution, false);
shun-iwasawa 25dc51
  bindParam(this, "noise_offset", m_noise_offset, false);
shun-iwasawa 25dc51
  m_noise_offset->getX()->setMeasureName("fxLength");
shun-iwasawa 25dc51
  m_noise_offset->getY()->setMeasureName("fxLength");
shun-iwasawa 25dc51
shun-iwasawa c1adfa
  m_irisScale->setValueRange(0.1, 0.8);
shun-iwasawa c1adfa
  m_irisGearEdgeCount->setValueRange(3, 50);
shun-iwasawa c1adfa
  m_irisSymmetry->setValueRange(0.1, 1.0);
shun-iwasawa c1adfa
  m_irisRandomSeed->setValueRange(0, (std::numeric_limits<int>::max)());</int>
shun-iwasawa c1adfa
shun-iwasawa 25dc51
  m_intensity->setValueRange(-5.0, 5.0);
shun-iwasawa c1adfa
  m_size->setValueRange(10.0, 1500.0);
shun-iwasawa 25dc51
  m_rotation->setValueRange(-1800, 1800);
shun-iwasawa c1adfa
  m_aberration->setValueRange(-2.0, 2.0);
shun-iwasawa 25dc51
  m_noise_factor->setValueRange(0.0, 1.0);
shun-iwasawa 25dc51
  m_noise_size->setValueRange(0.01, 3.0);
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
//--------------------------------------------------------------
shun-iwasawa 25dc51
double Iwa_GlareFx::getSizePixelAmount(const double val, const TAffine affine) {
shun-iwasawa 25dc51
  /*--- Convert to vector --- */
shun-iwasawa 25dc51
  TPointD vect;
shun-iwasawa 25dc51
  vect.x = val;
shun-iwasawa 25dc51
  vect.y = 0.0;
shun-iwasawa 25dc51
  /*--- Apply geometrical transformation ---*/
shun-iwasawa 25dc51
  // For the following lines I referred to lines 586-592 of
shun-iwasawa 25dc51
  // sources/stdfx/motionblurfx.cpp
shun-iwasawa 25dc51
  TAffine aff(affine);
shun-iwasawa 25dc51
  aff.a13 = aff.a23 = 0; /* ignore translation */
shun-iwasawa 25dc51
  vect              = aff * vect;
shun-iwasawa 25dc51
  /*--- return the length of the vector ---*/
shun-iwasawa 25dc51
  return sqrt(vect.x * vect.x + vect.y * vect.y);
shun-iwasawa 25dc51
}
shun-iwasawa c1adfa
shun-iwasawa c1adfa
//--------------------------------------------------------------
shun-iwasawa c1adfa
shun-iwasawa c1adfa
void Iwa_GlareFx::drawPresetIris(TRaster32P irisRas, double irisSize,
shun-iwasawa c1adfa
                                 const double frame) {
shun-iwasawa c1adfa
  QImage img(irisRas->getLx(), irisRas->getLy(),
shun-iwasawa c1adfa
             QImage::Format_ARGB32_Premultiplied);
shun-iwasawa c1adfa
  img.fill(Qt::black);
shun-iwasawa c1adfa
  QPainter painter(&img);
shun-iwasawa c1adfa
  painter.setRenderHint(QPainter::Antialiasing, true);
shun-iwasawa c1adfa
  painter.translate(
shun-iwasawa c1adfa
      QPointF((float)irisRas->getLx() / 2.0, (float)irisRas->getLy() / 2.0));
shun-iwasawa c1adfa
  painter.scale(irisSize, irisSize);
shun-iwasawa c1adfa
  // shrink a bit
shun-iwasawa c1adfa
  painter.scale(0.9, 0.9);
shun-iwasawa c1adfa
shun-iwasawa c1adfa
  QPen pen(Qt::white);
shun-iwasawa c1adfa
  double lineWidthRatio;
shun-iwasawa c1adfa
  int appearance = m_irisAppearance->getValue();
shun-iwasawa c1adfa
  if (appearance == Appearance_Fill) {
shun-iwasawa c1adfa
    painter.setPen(Qt::NoPen);
shun-iwasawa c1adfa
    painter.setBrush(Qt::white);
shun-iwasawa c1adfa
  } else {
shun-iwasawa c1adfa
    assert(appearance >= 0 && appearance <= 2);
shun-iwasawa c1adfa
    pen.setCapStyle(Qt::RoundCap);
shun-iwasawa c1adfa
    pen.setJoinStyle(Qt::MiterJoin);
shun-iwasawa c1adfa
    double ratio[3] = {0.05, 0.1, 0.2};
shun-iwasawa c1adfa
    lineWidthRatio  = ratio[appearance];
shun-iwasawa c1adfa
    pen.setWidthF(lineWidthRatio);
shun-iwasawa c1adfa
    painter.setPen(pen);
shun-iwasawa c1adfa
    painter.setBrush(Qt::NoBrush);
shun-iwasawa c1adfa
  }
shun-iwasawa c1adfa
shun-iwasawa c1adfa
  double symmetry = m_irisSymmetry->getValue(frame);
shun-iwasawa c1adfa
shun-iwasawa c1adfa
  switch (m_irisMode->getValue()) {
shun-iwasawa c1adfa
  case Iris_Square:
shun-iwasawa c1adfa
    painter.scale(1.0, symmetry);
shun-iwasawa c1adfa
    painter.drawRect(QRectF(-1.0, -1.0, 2.0, 2.0));
shun-iwasawa c1adfa
    break;
shun-iwasawa c1adfa
  case Iris_Hexagon: {
shun-iwasawa c1adfa
    QPointF p(1.0 - 0.5 * symmetry, symmetry * std::sqrt(3) * 0.5);
shun-iwasawa c1adfa
    const QPointF points[6] = {-p, QPointF(-1.0, 0.0), QPointF(-p.x(), p.y()),
shun-iwasawa c1adfa
                               p,  QPointF(1.0, 0.0),  QPointF(p.x(), -p.y())};
shun-iwasawa c1adfa
    if (appearance != Appearance_Fill) {
shun-iwasawa c1adfa
      if (symmetry < 1.0) {
shun-iwasawa c1adfa
        painter.drawPolyline(points, 3);
shun-iwasawa c1adfa
        painter.drawPolyline(&points[3], 3);
shun-iwasawa c1adfa
      }
shun-iwasawa c1adfa
      pen.setWidthF(lineWidthRatio * symmetry);
shun-iwasawa c1adfa
      painter.setPen(pen);
shun-iwasawa c1adfa
    }
shun-iwasawa c1adfa
    painter.drawPolygon(points, 6);
shun-iwasawa c1adfa
    if (appearance != Appearance_Fill && symmetry < 1.0) {
shun-iwasawa c1adfa
      pen.setColor(Qt::black);
shun-iwasawa c1adfa
      painter.setPen(pen);
shun-iwasawa c1adfa
      painter.setBrush(Qt::NoBrush);
shun-iwasawa c1adfa
      painter.drawRect(
shun-iwasawa c1adfa
          QRectF(-1.2, -p.y() - symmetry, 2.4, (p.y() + symmetry) * 2.0));
shun-iwasawa c1adfa
    }
shun-iwasawa c1adfa
  } break;
shun-iwasawa c1adfa
  case Iris_Octagon: {
shun-iwasawa c1adfa
    double u = (2 + std::sqrt(2) * (1 - symmetry)) / (2 * std::sqrt(2) + 2);
shun-iwasawa c1adfa
    double v = (2 + std::sqrt(2) * (1 + symmetry)) / (2 * std::sqrt(2) + 2);
shun-iwasawa c1adfa
    const QPointF points[8] = {QPointF(u, v),  QPointF(v, u),   QPointF(v, -u),
shun-iwasawa c1adfa
                               QPointF(u, -v), QPointF(-u, -v), QPointF(-v, -u),
shun-iwasawa c1adfa
                               QPointF(-v, u), QPointF(-u, v)};
shun-iwasawa c1adfa
    if (appearance != Appearance_Fill) {
shun-iwasawa c1adfa
      if (symmetry < 1.0) {
shun-iwasawa c1adfa
        painter.drawLine(points[0], points[1]);
shun-iwasawa c1adfa
        painter.drawLine(points[2], points[3]);
shun-iwasawa c1adfa
        painter.drawLine(points[4], points[5]);
shun-iwasawa c1adfa
        painter.drawLine(points[6], points[7]);
shun-iwasawa c1adfa
      }
shun-iwasawa c1adfa
      pen.setWidthF(lineWidthRatio * symmetry);
shun-iwasawa c1adfa
      painter.setPen(pen);
shun-iwasawa c1adfa
    }
shun-iwasawa c1adfa
    painter.drawPolygon(points, 8);
shun-iwasawa c1adfa
    if (appearance != Appearance_Fill && symmetry < 1.0) {
shun-iwasawa c1adfa
      pen.setColor(Qt::black);
shun-iwasawa c1adfa
      painter.setPen(pen);
shun-iwasawa c1adfa
      painter.setBrush(Qt::NoBrush);
shun-iwasawa c1adfa
      painter.drawRect(QRectF(-v - symmetry, -v - symmetry,
shun-iwasawa c1adfa
                              (v + symmetry) * 2.0, (v + symmetry) * 2.0));
shun-iwasawa c1adfa
    }
shun-iwasawa c1adfa
  } break;
shun-iwasawa c1adfa
  case Iris_GearShape: {
shun-iwasawa c1adfa
    int edgeCount   = (int)std::round(m_irisGearEdgeCount->getValue(frame));
shun-iwasawa c1adfa
    QPointF* points = new QPointF[edgeCount * 2];
shun-iwasawa c1adfa
    QList<double> thickness;</double>
shun-iwasawa c1adfa
    double angleUnit = M_PI / (double)edgeCount;
shun-iwasawa c1adfa
    std::mt19937_64 mt;
shun-iwasawa c1adfa
    mt.seed(m_irisRandomSeed->getValue());
shun-iwasawa c1adfa
    std::uniform_real_distribution<> random_plusminus1(-1.0, 1.0);
shun-iwasawa c1adfa
    std::uniform_real_distribution<> random_thickness(symmetry * lineWidthRatio,
shun-iwasawa c1adfa
                                                      lineWidthRatio);
shun-iwasawa c1adfa
    for (int e = 0; e < edgeCount; e++) {
shun-iwasawa c1adfa
      double baseAngle = angleUnit * e * 2.0;
shun-iwasawa c1adfa
      double theta =
shun-iwasawa c1adfa
          baseAngle + random_plusminus1(mt) * angleUnit * (1.0 - symmetry);
shun-iwasawa c1adfa
      points[e * 2] = QPointF(std::cos(theta), std::sin(theta));
shun-iwasawa c1adfa
      thickness.append(random_thickness(mt));
shun-iwasawa c1adfa
      baseAngle += angleUnit;
shun-iwasawa c1adfa
      theta = baseAngle + random_plusminus1(mt) * angleUnit * (1.0 - symmetry);
shun-iwasawa c1adfa
      points[e * 2 + 1] = QPointF(0.5 * std::cos(theta), 0.5 * std::sin(theta));
shun-iwasawa c1adfa
      thickness.append(random_thickness(mt));
shun-iwasawa c1adfa
    }
shun-iwasawa c1adfa
shun-iwasawa c1adfa
    if (appearance != Appearance_Fill) {
shun-iwasawa c1adfa
      for (int v = 0; v < edgeCount * 2; v++) {
shun-iwasawa c1adfa
        int next_v = (v == edgeCount * 2 - 1) ? 0 : v + 1;
shun-iwasawa c1adfa
        pen.setWidthF(thickness.at(v));
shun-iwasawa c1adfa
        painter.setPen(pen);
shun-iwasawa c1adfa
        painter.drawLine(points[v], points[next_v]);
shun-iwasawa c1adfa
      }
shun-iwasawa c1adfa
    } else {
shun-iwasawa c1adfa
      painter.drawPolygon(points, edgeCount * 2);
shun-iwasawa c1adfa
    }
shun-iwasawa c1adfa
    delete[] points;
shun-iwasawa c1adfa
  } break;
shun-iwasawa c1adfa
  default:
shun-iwasawa c1adfa
    break;
shun-iwasawa c1adfa
  }
shun-iwasawa c1adfa
shun-iwasawa c1adfa
  for (int j = 0; j < img.height(); j++) {
shun-iwasawa c1adfa
    TPixel32* pix = irisRas->pixels(j);
shun-iwasawa c1adfa
    QRgb* img_p   = (QRgb*)img.scanLine(img.height() - j - 1);
shun-iwasawa c1adfa
    for (int i = 0; i < img.width(); i++, img_p++, pix++) {
shun-iwasawa c1adfa
      pix->r = (unsigned char)(qRed(*img_p));
shun-iwasawa c1adfa
      pix->g = (unsigned char)(qGreen(*img_p));
shun-iwasawa c1adfa
      pix->b = (unsigned char)(qBlue(*img_p));
shun-iwasawa c1adfa
      pix->m = (unsigned char)(qAlpha(*img_p));
shun-iwasawa c1adfa
    }
shun-iwasawa c1adfa
  }
shun-iwasawa c1adfa
}
shun-iwasawa c1adfa
shun-iwasawa 25dc51
//--------------------------------------------------------------
shun-iwasawa 25dc51
shun-iwasawa 25dc51
void Iwa_GlareFx::doCompute(TTile& tile, double frame,
shun-iwasawa 25dc51
                            const TRenderSettings& settings) {
shun-iwasawa c1adfa
  int irisMode = m_irisMode->getValue();
shun-iwasawa 25dc51
  // If the iris is not connected, then do nothing
shun-iwasawa c1adfa
  if (irisMode == Iris_InputImage && !m_iris.isConnected()) {
shun-iwasawa 25dc51
    tile.getRaster()->clear();
shun-iwasawa 25dc51
    return;
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  int renderMode = m_renderMode->getValue();
shun-iwasawa 25dc51
  // If the source is not connected & it is render mode, then do nothing.
shun-iwasawa 25dc51
  if (!m_source.isConnected() && renderMode == RendeMode_Render) {
shun-iwasawa 25dc51
    tile.getRaster()->clear();
shun-iwasawa 25dc51
    return;
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // Get the original size of Iris image
shun-iwasawa 25dc51
  TRectD irisBBox;
shun-iwasawa 25dc51
  TTile irisTile;
shun-iwasawa c1adfa
  TRasterP irisRas;
shun-iwasawa 25dc51
  double size = getSizePixelAmount(m_size->getValue(frame), settings.m_affine);
shun-iwasawa c1adfa
  if (irisMode == Iris_InputImage) {
shun-iwasawa c1adfa
    m_iris->getBBox(frame, irisBBox, settings);
shun-iwasawa c1adfa
    // Compute the iris tile.
shun-iwasawa c1adfa
    m_iris->allocateAndCompute(
shun-iwasawa c1adfa
        irisTile, irisBBox.getP00(),
shun-iwasawa c1adfa
        TDimension(static_cast<int>(irisBBox.getLx() + 0.5),</int>
shun-iwasawa c1adfa
                   static_cast<int>(irisBBox.getLy() + 0.5)),</int>
shun-iwasawa c1adfa
        tile.getRaster(), frame, settings);
shun-iwasawa c1adfa
    irisRas = irisTile.getRaster();
shun-iwasawa c1adfa
  } else {
shun-iwasawa c1adfa
    // obtain iris bbox based on the glare pattern size
shun-iwasawa c1adfa
    double irisSize = size * m_irisScale->getValue(frame);
shun-iwasawa c1adfa
    irisBBox        = TRectD(-irisSize, -irisSize, irisSize, irisSize);
shun-iwasawa c1adfa
    int dimIrisRas  = int(std::ceil(irisSize) * 2.0);
shun-iwasawa c1adfa
    irisRas         = TRaster32P(dimIrisRas, dimIrisRas);
shun-iwasawa c1adfa
    drawPresetIris(irisRas, irisSize, frame);
shun-iwasawa c1adfa
  }
shun-iwasawa c1adfa
shun-iwasawa c1adfa
  if (renderMode == RenderMode_Iris) {
shun-iwasawa c1adfa
    TTranslation aff(
shun-iwasawa c1adfa
        (double)(tile.getRaster()->getLx() - irisRas->getLx()) * 0.5,
shun-iwasawa c1adfa
        (double)(tile.getRaster()->getLy() - irisRas->getLy()) * 0.5);
shun-iwasawa c1adfa
    TRop::quickPut(tile.getRaster(), irisRas, aff);
shun-iwasawa c1adfa
    return;
shun-iwasawa c1adfa
  }
shun-iwasawa c1adfa
shun-iwasawa 25dc51
  int dimIris = int(std::ceil(size) * 2.0);
shun-iwasawa 25dc51
  dimIris     = kiss_fft_next_fast_size(dimIris);
shun-iwasawa 25dc51
  while ((tile.getRaster()->getSize().lx - dimIris) % 2 != 0)
shun-iwasawa 25dc51
    dimIris = kiss_fft_next_fast_size(dimIris + 1);
shun-iwasawa 25dc51
  double irisResizeFactor = double(dimIris) * 0.5 / size;
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  kiss_fft_cpx* kissfft_comp_iris;
shun-iwasawa 25dc51
  // create the iris data for FFT (in the same size as the source tile)
shun-iwasawa 25dc51
  TRasterGR8P kissfft_comp_iris_ras(dimIris * sizeof(kiss_fft_cpx), dimIris);
shun-iwasawa 25dc51
  kissfft_comp_iris_ras->lock();
shun-iwasawa 25dc51
  kissfft_comp_iris = (kiss_fft_cpx*)kissfft_comp_iris_ras->getRawData();
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  {
shun-iwasawa 25dc51
    // Create the Iris image for FFT
shun-iwasawa 25dc51
    kiss_fft_cpx* kissfft_comp_iris_before;
shun-iwasawa 25dc51
    TRasterGR8P kissfft_comp_iris_before_ras(dimIris * sizeof(kiss_fft_cpx),
shun-iwasawa 25dc51
                                             dimIris);
shun-iwasawa 25dc51
    kissfft_comp_iris_before_ras->lock();
shun-iwasawa 25dc51
    kissfft_comp_iris_before =
shun-iwasawa 25dc51
        (kiss_fft_cpx*)kissfft_comp_iris_before_ras->getRawData();
shun-iwasawa c1adfa
shun-iwasawa c1adfa
    convertIris(kissfft_comp_iris_before, dimIris, irisBBox, irisRas);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
    // Create the FFT plan for the iris image.
shun-iwasawa 25dc51
    kiss_fftnd_cfg iris_kissfft_plan;
shun-iwasawa 25dc51
    while (1) {
shun-iwasawa 25dc51
      int dims[2]       = {dimIris, dimIris};
shun-iwasawa 25dc51
      int ndims         = 2;
shun-iwasawa 25dc51
      iris_kissfft_plan = kiss_fftnd_alloc(dims, ndims, false, 0, 0);
shun-iwasawa 25dc51
      if (iris_kissfft_plan != NULL) break;
shun-iwasawa 25dc51
    }
shun-iwasawa 25dc51
    // Do FFT the iris image.
shun-iwasawa 25dc51
    kiss_fftnd(iris_kissfft_plan, kissfft_comp_iris_before, kissfft_comp_iris);
shun-iwasawa 25dc51
    kiss_fft_free(iris_kissfft_plan);
shun-iwasawa 25dc51
    kissfft_comp_iris_before_ras->unlock();
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  double3* glare_pattern;
shun-iwasawa 25dc51
  TRasterGR8P glare_pattern_ras(dimIris * sizeof(double3), dimIris);
shun-iwasawa 25dc51
  glare_pattern = (double3*)glare_pattern_ras->getRawData();
shun-iwasawa 25dc51
  glare_pattern_ras->lock();
shun-iwasawa 25dc51
  // Resize the power spectrum according to each wavelength and combine into the
shun-iwasawa 25dc51
  // glare pattern
shun-iwasawa 25dc51
  double intensity = m_intensity->getValue(frame);
shun-iwasawa 25dc51
  powerSpectrum2GlarePattern(frame, settings.m_affine, kissfft_comp_iris,
shun-iwasawa 25dc51
                             glare_pattern, dimIris, intensity,
shun-iwasawa 25dc51
                             irisResizeFactor);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  kissfft_comp_iris_ras->unlock();
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // clear the raster memory
shun-iwasawa 25dc51
  tile.getRaster()->clear();
shun-iwasawa 25dc51
  TRaster32P ras32 = tile.getRaster();
shun-iwasawa 25dc51
  TRaster64P ras64 = tile.getRaster();
shun-iwasawa 25dc51
  if (ras32)
shun-iwasawa 25dc51
    ras32->fill(TPixel32::Transparent);
shun-iwasawa 25dc51
  else if (ras64)
shun-iwasawa 25dc51
    ras64->fill(TPixel64::Transparent);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // filter preview mode
shun-iwasawa 25dc51
  if (renderMode == RendeMode_FilterPreview) {
shun-iwasawa 25dc51
    int2 margin = {(dimIris - tile.getRaster()->getSize().lx) / 2,
shun-iwasawa 25dc51
                   (dimIris - tile.getRaster()->getSize().ly) / 2};
shun-iwasawa 25dc51
shun-iwasawa 25dc51
    if (ras32)
shun-iwasawa 25dc51
      setFilterPreviewToResult<traster32p, tpixel32="">(ras32, glare_pattern,</traster32p,>
shun-iwasawa 25dc51
                                                     dimIris, margin);
shun-iwasawa 25dc51
    else if (ras64)
shun-iwasawa 25dc51
      setFilterPreviewToResult<traster64p, tpixel64="">(ras64, glare_pattern,</traster64p,>
shun-iwasawa 25dc51
                                                     dimIris, margin);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
    return;
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // render mode
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // Range of computation
shun-iwasawa 25dc51
  TRectD _rectOut(tile.m_pos, TDimensionD(tile.getRaster()->getLx(),
shun-iwasawa 25dc51
                                          tile.getRaster()->getLy()));
shun-iwasawa 25dc51
  _rectOut = _rectOut.enlarge(static_cast<double>(dimIris / 2));</double>
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  TDimensionI dimOut(static_cast<int>(_rectOut.getLx() + 0.5),</int>
shun-iwasawa 25dc51
                     static_cast<int>(_rectOut.getLy() + 0.5));</int>
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // Enlarge the size to the "fast size" for kissfft which has no factors other
shun-iwasawa 25dc51
  // than 2,3, or 5.
shun-iwasawa 25dc51
  if (dimOut.lx < 10000 && dimOut.ly < 10000) {
shun-iwasawa 25dc51
    int new_x = kiss_fft_next_fast_size(dimOut.lx);
shun-iwasawa 25dc51
    int new_y = kiss_fft_next_fast_size(dimOut.ly);
shun-iwasawa 25dc51
    // margin should be integer
shun-iwasawa 25dc51
    while ((new_x - dimOut.lx) % 2 != 0)
shun-iwasawa 25dc51
      new_x = kiss_fft_next_fast_size(new_x + 1);
shun-iwasawa 25dc51
    while ((new_y - dimOut.ly) % 2 != 0)
shun-iwasawa 25dc51
      new_y = kiss_fft_next_fast_size(new_y + 1);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
    _rectOut = _rectOut.enlarge(static_cast<double>(new_x - dimOut.lx) / 2.0,</double>
shun-iwasawa 25dc51
                                static_cast<double>(new_y - dimOut.ly) / 2.0);</double>
shun-iwasawa 25dc51
shun-iwasawa 25dc51
    dimOut.lx = new_x;
shun-iwasawa 25dc51
    dimOut.ly = new_y;
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  kiss_fft_cpx* kissfft_comp_tmp;
shun-iwasawa 25dc51
  kiss_fft_cpx* kissfft_comp_glare;
shun-iwasawa 25dc51
  kiss_fft_cpx* kissfft_comp_source;
shun-iwasawa 25dc51
  TRasterGR8P kissfft_comp_tmp_ras(dimOut.lx * sizeof(kiss_fft_cpx), dimOut.ly);
shun-iwasawa 25dc51
  TRasterGR8P kissfft_comp_glare_ras(dimOut.lx * sizeof(kiss_fft_cpx),
shun-iwasawa 25dc51
                                     dimOut.ly);
shun-iwasawa 25dc51
  TRasterGR8P kissfft_comp_source_ras(dimOut.lx * sizeof(kiss_fft_cpx),
shun-iwasawa 25dc51
                                      dimOut.ly);
shun-iwasawa 25dc51
  kissfft_comp_tmp    = (kiss_fft_cpx*)kissfft_comp_tmp_ras->getRawData();
shun-iwasawa 25dc51
  kissfft_comp_glare  = (kiss_fft_cpx*)kissfft_comp_glare_ras->getRawData();
shun-iwasawa 25dc51
  kissfft_comp_source = (kiss_fft_cpx*)kissfft_comp_source_ras->getRawData();
shun-iwasawa 25dc51
  kissfft_comp_tmp_ras->lock();
shun-iwasawa 25dc51
  kissfft_comp_glare_ras->lock();
shun-iwasawa 25dc51
  kissfft_comp_source_ras->lock();
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  int dims[2]              = {dimOut.ly, dimOut.lx};
shun-iwasawa 25dc51
  int ndims                = 2;
shun-iwasawa 25dc51
  kiss_fftnd_cfg plan_fwd  = kiss_fftnd_alloc(dims, ndims, false, 0, 0);
shun-iwasawa 25dc51
  kiss_fftnd_cfg plan_bkwd = kiss_fftnd_alloc(dims, ndims, true, 0, 0);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // store the source image to tmp
shun-iwasawa 25dc51
  {
shun-iwasawa 25dc51
    // obtain the source tile
shun-iwasawa 25dc51
    TTile sourceTile;
shun-iwasawa 25dc51
    m_source->allocateAndCompute(sourceTile, _rectOut.getP00(), dimOut,
shun-iwasawa 25dc51
                                 tile.getRaster(), frame, settings);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
    if (ras32)
shun-iwasawa 25dc51
      setSourceTileToBuffer<traster32p, tpixel32="">(sourceTile.getRaster(),</traster32p,>
shun-iwasawa 25dc51
                                                  kissfft_comp_tmp);
shun-iwasawa 25dc51
    else if (ras64)
shun-iwasawa 25dc51
      setSourceTileToBuffer<traster64p, tpixel64="">(sourceTile.getRaster(),</traster64p,>
shun-iwasawa 25dc51
                                                  kissfft_comp_tmp);
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
  // FFT the source
shun-iwasawa 25dc51
  kiss_fftnd(plan_fwd, kissfft_comp_tmp, kissfft_comp_source);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // compute for each rgb channels
shun-iwasawa 25dc51
  for (int ch = 0; ch < 3; ch++) {
shun-iwasawa 25dc51
    kissfft_comp_tmp_ras->clear();
shun-iwasawa 25dc51
    // store the glare pattern to tmp
shun-iwasawa 25dc51
    setGlarePatternToBuffer(glare_pattern, kissfft_comp_tmp, ch, dimIris,
shun-iwasawa 25dc51
                            dimOut);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
    // FFT the glare pattern
shun-iwasawa 25dc51
    kiss_fftnd(plan_fwd, kissfft_comp_tmp, kissfft_comp_glare);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
    // multiply the glare and the source
shun-iwasawa 25dc51
    multiplyFilter(kissfft_comp_glare, kissfft_comp_source,
shun-iwasawa 25dc51
                   dimOut.lx * dimOut.ly);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
    // Backward-FFT the glare pattern to tmp
shun-iwasawa 25dc51
    kiss_fftnd(plan_bkwd, kissfft_comp_glare,
shun-iwasawa 25dc51
               kissfft_comp_tmp);  // Backward FFT
shun-iwasawa 25dc51
shun-iwasawa 25dc51
    // convert tmp to channel values, store it into the tile
shun-iwasawa 25dc51
    if (ras32)
shun-iwasawa 25dc51
      setChannelToResult<traster32p, tpixel32="">(ras32, kissfft_comp_tmp, ch,</traster32p,>
shun-iwasawa 25dc51
                                               dimOut);
shun-iwasawa 25dc51
    else if (ras64)
shun-iwasawa 25dc51
      setChannelToResult<traster64p, tpixel64="">(ras64, kissfft_comp_tmp, ch,</traster64p,>
shun-iwasawa 25dc51
                                               dimOut);
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  kiss_fft_free(plan_fwd);
shun-iwasawa 25dc51
  kiss_fft_free(plan_bkwd);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  kissfft_comp_source_ras->unlock();
shun-iwasawa 25dc51
  kissfft_comp_glare_ras->unlock();
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
//------------------------------------------------
shun-iwasawa 25dc51
shun-iwasawa 25dc51
void Iwa_GlareFx::powerSpectrum2GlarePattern(
shun-iwasawa 25dc51
    const double frame, const TAffine affine, kiss_fft_cpx* spectrum,
shun-iwasawa 25dc51
    double3* glare, int dimIris, double intensity, double irisResizeFactor) {
shun-iwasawa 25dc51
  auto lerp = [](double val1, double val2, double ratio) {
shun-iwasawa 25dc51
    return val1 * (1.0 - ratio) + val2 * ratio;
shun-iwasawa 25dc51
  };
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  auto lerpGlarePtn = [&](double i, double j, double* gp) {
shun-iwasawa 25dc51
    int iId[2], jId[2];
shun-iwasawa 25dc51
    double iRatio, jRatio;
shun-iwasawa 25dc51
    iId[0] = int(i);
shun-iwasawa 25dc51
    iId[1] = (iId[0] < dimIris - 1) ? iId[0] + 1 : iId[0];
shun-iwasawa 25dc51
    iRatio = i - double(iId[0]);
shun-iwasawa 25dc51
    jId[0] = int(j);
shun-iwasawa 25dc51
    jId[1] = (jId[0] < dimIris - 1) ? jId[0] + 1 : jId[0];
shun-iwasawa 25dc51
    jRatio = j - double(jId[0]);
shun-iwasawa 25dc51
    if (iRatio == 0.0 && jRatio == 0.0) return gp[jId[0] * dimIris + iId[0]];
shun-iwasawa 25dc51
shun-iwasawa 25dc51
    return lerp(lerp(gp[jId[0] * dimIris + iId[0]],
shun-iwasawa 25dc51
                     gp[jId[0] * dimIris + iId[1]], iRatio),
shun-iwasawa 25dc51
                lerp(gp[jId[1] * dimIris + iId[0]],
shun-iwasawa 25dc51
                     gp[jId[1] * dimIris + iId[1]], iRatio),
shun-iwasawa 25dc51
                jRatio);
shun-iwasawa 25dc51
  };
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  double factor =
shun-iwasawa 25dc51
      (m_renderMode->getValue() == RendeMode_FilterPreview) ? -5 : -11;
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  double* glarePattern_p;
shun-iwasawa 25dc51
  TRasterGR8P glarePattern_ras(dimIris * sizeof(double), dimIris);
shun-iwasawa 25dc51
  glarePattern_p = (double*)glarePattern_ras->getRawData();
shun-iwasawa 25dc51
  glarePattern_ras->lock();
shun-iwasawa 25dc51
  double* g_p = glarePattern_p;
shun-iwasawa 25dc51
  for (int j = 0; j < dimIris; j++) {
shun-iwasawa 25dc51
    for (int i = 0; i < dimIris; i++, g_p++) {
shun-iwasawa 25dc51
      kiss_fft_cpx sp_p = spectrum[getCoord(i, j, dimIris, dimIris)];
shun-iwasawa 25dc51
      (*g_p)            = sqrt(sp_p.r * sp_p.r + sp_p.i * sp_p.i) *
shun-iwasawa 25dc51
               std::exp(intensity + factor);
shun-iwasawa 25dc51
    }
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // distort the pattern with noise here
shun-iwasawa 25dc51
  double noise_factor = m_noise_factor->getValue(frame);
shun-iwasawa 25dc51
  double rotation     = m_rotation->getValue(frame);
shun-iwasawa 25dc51
  if (noise_factor > 0.0 || m_rotation != 0.0) {
shun-iwasawa 25dc51
    distortGlarePattern(frame, affine, glarePattern_p, dimIris);
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  double3* glare_xyz;
shun-iwasawa 25dc51
  TRasterGR8P glare_xyz_ras(dimIris * sizeof(double3), dimIris);
shun-iwasawa 25dc51
  glare_xyz_ras->lock();
shun-iwasawa 25dc51
  glare_xyz = (double3*)glare_xyz_ras->getRawData();
shun-iwasawa 25dc51
  glare_xyz_ras->clear();
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  double irisRadius = double(dimIris / 2);
shun-iwasawa c1adfa
  double aberration = m_aberration->getValue(frame);
shun-iwasawa c1adfa
shun-iwasawa c1adfa
  // old version had summed each wavelength constantly.
shun-iwasawa c1adfa
  // it was not physically-collect but keep it in order to maintain backward
shun-iwasawa c1adfa
  // compatibility.
shun-iwasawa c1adfa
  bool isOldVersion = getFxVersion() < 2;
shun-iwasawa c1adfa
shun-iwasawa 25dc51
  // accumurate xyz values for each optical wavelength
shun-iwasawa 25dc51
  for (int ram = 0; ram < 34; ram++) {
shun-iwasawa 25dc51
    double rambda = 0.38 + 0.01 * (double)ram;
shun-iwasawa c1adfa
    // double scale = 0.55 / rambda;
shun-iwasawa c1adfa
    double scale = std::pow(0.55 / rambda, aberration);
shun-iwasawa c1adfa
    double intensity_scale =
shun-iwasawa c1adfa
        (isOldVersion) ? 1.0 : std::pow(0.55 / rambda, 2.0 * aberration);
shun-iwasawa 25dc51
    scale *= irisResizeFactor;
shun-iwasawa 25dc51
    for (int j = 0; j < dimIris; j++) {
shun-iwasawa 25dc51
      double j_scaled = (double(j) - irisRadius) * scale + irisRadius;
shun-iwasawa 25dc51
      if (j_scaled < 0)
shun-iwasawa 25dc51
        continue;
shun-iwasawa 25dc51
      else if (j_scaled > double(dimIris - 1))
shun-iwasawa 25dc51
        break;
shun-iwasawa 25dc51
shun-iwasawa 25dc51
      double3* g_xyz_p = &glare_xyz[j * dimIris];
shun-iwasawa 25dc51
      for (int i = 0; i < dimIris; i++, g_xyz_p++) {
shun-iwasawa 25dc51
        double i_scaled = (double(i) - irisRadius) * scale + irisRadius;
shun-iwasawa 25dc51
        if (i_scaled < 0)
shun-iwasawa 25dc51
          continue;
shun-iwasawa 25dc51
        else if (i_scaled > double(dimIris - 1))
shun-iwasawa 25dc51
          break;
shun-iwasawa 25dc51
shun-iwasawa c1adfa
        double gl =
shun-iwasawa c1adfa
            lerpGlarePtn(i_scaled, j_scaled, glarePattern_p) * intensity_scale;
shun-iwasawa 25dc51
        g_xyz_p->x += gl * cie_d65[ram] * xyz[ram * 3 + 0];
shun-iwasawa 25dc51
        g_xyz_p->y += gl * cie_d65[ram] * xyz[ram * 3 + 1];
shun-iwasawa 25dc51
        g_xyz_p->z += gl * cie_d65[ram] * xyz[ram * 3 + 2];
shun-iwasawa 25dc51
      }
shun-iwasawa 25dc51
    }
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
  glarePattern_ras->unlock();
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // convert to rgb
shun-iwasawa 25dc51
  double3* g_xyz_p = glare_xyz;
shun-iwasawa 25dc51
  double3* g_out_p = glare;
shun-iwasawa 25dc51
  for (int i = 0; i < dimIris * dimIris; i++, g_xyz_p++, g_out_p++) {
shun-iwasawa 25dc51
    (*g_out_p).x = 3.240479f * (*g_xyz_p).x - 1.537150f * (*g_xyz_p).y -
shun-iwasawa 25dc51
                   0.498535f * (*g_xyz_p).z;
shun-iwasawa 25dc51
    (*g_out_p).y = -0.969256f * (*g_xyz_p).x + 1.875992f * (*g_xyz_p).y +
shun-iwasawa 25dc51
                   0.041556f * (*g_xyz_p).z;
shun-iwasawa 25dc51
    (*g_out_p).z = 0.055648f * (*g_xyz_p).x - 0.204043f * (*g_xyz_p).y +
shun-iwasawa 25dc51
                   1.057311f * (*g_xyz_p).z;
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  glare_xyz_ras->unlock();
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
//------------------------------------------------
shun-iwasawa 25dc51
shun-iwasawa 25dc51
void Iwa_GlareFx::distortGlarePattern(const double frame, const TAffine affine,
shun-iwasawa 25dc51
                                      double* glare, const int dimIris) {
shun-iwasawa 25dc51
  auto lerp = [](double val1, double val2, double ratio) {
shun-iwasawa 25dc51
    return val1 * (1.0 - ratio) + val2 * ratio;
shun-iwasawa 25dc51
  };
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  auto lerpGlarePtn = [&](double i, double j, double* gp) {
shun-iwasawa 25dc51
    int iId[2], jId[2];
shun-iwasawa 25dc51
    double iRatio, jRatio;
shun-iwasawa 25dc51
    iId[0] = int(i);
shun-iwasawa 25dc51
    iId[1] = (iId[0] < dimIris - 1) ? iId[0] + 1 : iId[0];
shun-iwasawa 25dc51
    iRatio = i - double(iId[0]);
shun-iwasawa 25dc51
    jId[0] = int(j);
shun-iwasawa 25dc51
    jId[1] = (jId[0] < dimIris - 1) ? jId[0] + 1 : jId[0];
shun-iwasawa 25dc51
    jRatio = j - double(jId[0]);
shun-iwasawa 25dc51
    if (iRatio == 0.0 && jRatio == 0.0) return gp[jId[0] * dimIris + iId[0]];
shun-iwasawa 25dc51
shun-iwasawa 25dc51
    return lerp(lerp(gp[jId[0] * dimIris + iId[0]],
shun-iwasawa 25dc51
                     gp[jId[0] * dimIris + iId[1]], iRatio),
shun-iwasawa 25dc51
                lerp(gp[jId[1] * dimIris + iId[0]],
shun-iwasawa 25dc51
                     gp[jId[1] * dimIris + iId[1]], iRatio),
shun-iwasawa 25dc51
                jRatio);
shun-iwasawa 25dc51
  };
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  double size         = m_noise_size->getValue(frame);
shun-iwasawa 25dc51
  double evolution    = m_noise_evolution->getValue(frame);
shun-iwasawa 25dc51
  int octave          = m_noise_octave->getValue();
shun-iwasawa 25dc51
  double noiseFactor  = m_noise_factor->getValue(frame);
shun-iwasawa 25dc51
  double offsetFactor = 0.005;
shun-iwasawa 25dc51
  TPointD offset =
shun-iwasawa 25dc51
      TScale(offsetFactor) * affine * m_noise_offset->getValue(frame);
shun-iwasawa 25dc51
  double theta = m_rotation->getValue(frame) * M_PI_180;
shun-iwasawa 25dc51
  double cos_t = std::cos(theta);
shun-iwasawa 25dc51
  double sin_t = std::sin(theta);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  QList<double> noise_intensity;</double>
shun-iwasawa 25dc51
  double intensity_sum = 0.0;
shun-iwasawa 25dc51
  double tmp_intensity = 1.0;
shun-iwasawa 25dc51
  for (int i = 0; i < octave; i++) {
shun-iwasawa 25dc51
    noise_intensity.append(tmp_intensity);
shun-iwasawa 25dc51
    intensity_sum += tmp_intensity;
shun-iwasawa 25dc51
    tmp_intensity *= 0.5;
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
  for (double& n_i : noise_intensity) n_i /= intensity_sum;
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // raster for storing the result
shun-iwasawa 25dc51
  double* distortedPtn_p;
shun-iwasawa 25dc51
  TRasterGR8P distortedPtn_ras(dimIris * sizeof(double), dimIris);
shun-iwasawa 25dc51
  distortedPtn_p = (double*)distortedPtn_ras->getRawData();
shun-iwasawa 25dc51
  distortedPtn_ras->lock();
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  double* dist_p = distortedPtn_p;
shun-iwasawa 25dc51
  for (int j = 0; j < dimIris; j++) {
shun-iwasawa 25dc51
    double v = double(j) - double(dimIris) / 2.0;
shun-iwasawa 25dc51
    for (int i = 0; i < dimIris; i++, dist_p++) {
shun-iwasawa 25dc51
      double u = double(i) - double(dimIris) / 2.0;
shun-iwasawa 25dc51
shun-iwasawa 25dc51
      // obtain the noise coordinate
shun-iwasawa 25dc51
      double2 noiseUV;
shun-iwasawa 25dc51
      double len             = std::sqrt(u * u + v * v) * size;
shun-iwasawa 25dc51
      noiseUV.x              = (len == 0.0) ? 0.0 : u / len;
shun-iwasawa 25dc51
      noiseUV.y              = (len == 0.0) ? 0.0 : v / len;
shun-iwasawa 25dc51
      double currentSize     = 1.0;
shun-iwasawa 25dc51
      double currentEvoScale = 1.0;
shun-iwasawa 25dc51
      double noiseVal        = 0.5;
shun-iwasawa 25dc51
      noiseUV.x += offset.x;
shun-iwasawa 25dc51
      noiseUV.y += offset.y;
shun-iwasawa 25dc51
      for (int oct = 0; oct < octave; oct++) {
shun-iwasawa 25dc51
        double2 currentNoiseUV = {noiseUV.x / currentSize,
shun-iwasawa 25dc51
                                  noiseUV.y / currentSize};
shun-iwasawa 25dc51
        noiseVal += noise_intensity[oct] *
shun-iwasawa 25dc51
                    SimplexNoise::noise(currentNoiseUV.x, currentNoiseUV.y,
shun-iwasawa 25dc51
                                        evolution * currentEvoScale);
shun-iwasawa 25dc51
        currentSize *= 0.5;
shun-iwasawa 25dc51
        currentEvoScale *= 2.0;
shun-iwasawa 25dc51
      }
shun-iwasawa 25dc51
shun-iwasawa 25dc51
      double scale = 1.0 / (1.0 + (noiseVal - 1) * noiseFactor);
shun-iwasawa 25dc51
      double rot_u = u * cos_t - v * sin_t;
shun-iwasawa 25dc51
      double rot_v = u * sin_t + v * cos_t;
shun-iwasawa 25dc51
shun-iwasawa 25dc51
      double distorted_i = rot_u * scale + double(dimIris) / 2.0;
shun-iwasawa 25dc51
      double distorted_j = rot_v * scale + double(dimIris) / 2.0;
shun-iwasawa 25dc51
shun-iwasawa 25dc51
      if (distorted_i < 0.0 || distorted_i >= double(dimIris - 1) ||
shun-iwasawa 25dc51
          distorted_j < 0.0 || distorted_j >= double(dimIris - 1))
shun-iwasawa 25dc51
        (*dist_p) = 0.0;
shun-iwasawa 25dc51
      else
shun-iwasawa 25dc51
        (*dist_p) = lerpGlarePtn(distorted_i, distorted_j, glare);
shun-iwasawa 25dc51
    }
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  dist_p       = distortedPtn_p;
shun-iwasawa 25dc51
  double* gl_p = glare;
shun-iwasawa 25dc51
  for (int i = 0; i < dimIris * dimIris; i++, dist_p++, gl_p++)
shun-iwasawa 25dc51
    (*gl_p) = (*dist_p);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  distortedPtn_ras->unlock();
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
//------------------------------------------------
shun-iwasawa 25dc51
shun-iwasawa 25dc51
template <typename pixel="" raster,="" typename=""></typename>
shun-iwasawa 25dc51
void Iwa_GlareFx::setFilterPreviewToResult(const RASTER ras, double3* glare,
shun-iwasawa 25dc51
                                           int dimIris, int2 margin) {
shun-iwasawa 25dc51
  auto clamp01 = [](double chan) {
shun-iwasawa 25dc51
    if (chan < 0.0) return 0.0;
shun-iwasawa 25dc51
    if (chan > 1.0) return 1.0;
shun-iwasawa 25dc51
    return chan;
shun-iwasawa 25dc51
  };
shun-iwasawa 25dc51
  int j = margin.y;
shun-iwasawa 25dc51
  for (int out_j = 0; out_j < ras->getLy(); j++, out_j++) {
shun-iwasawa 25dc51
    if (j < 0)
shun-iwasawa 25dc51
      continue;
shun-iwasawa 25dc51
    else if (j >= dimIris)
shun-iwasawa 25dc51
      break;
shun-iwasawa 25dc51
    PIXEL* pix = ras->pixels(out_j);
shun-iwasawa 25dc51
    int i      = margin.x;
shun-iwasawa 25dc51
    for (int out_i = 0; out_i < ras->getLx(); i++, out_i++, pix++) {
shun-iwasawa 25dc51
      if (i < 0)
shun-iwasawa 25dc51
        continue;
shun-iwasawa 25dc51
      else if (i >= dimIris)
shun-iwasawa 25dc51
        break;
shun-iwasawa 25dc51
      double3 gl_p = glare[j * dimIris + i];
shun-iwasawa 25dc51
      pix->r       = (typename PIXEL::Channel)(clamp01(gl_p.x) *
shun-iwasawa 25dc51
                                         double(PIXEL::maxChannelValue));
shun-iwasawa 25dc51
      pix->g       = (typename PIXEL::Channel)(clamp01(gl_p.y) *
shun-iwasawa 25dc51
                                         double(PIXEL::maxChannelValue));
shun-iwasawa 25dc51
      pix->b       = (typename PIXEL::Channel)(clamp01(gl_p.z) *
shun-iwasawa 25dc51
                                         double(PIXEL::maxChannelValue));
shun-iwasawa 25dc51
      pix->m       = PIXEL::maxChannelValue;
shun-iwasawa 25dc51
    }
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
//------------------------------------------------
shun-iwasawa 25dc51
shun-iwasawa 25dc51
// put the source tile's brightness to fft buffer
shun-iwasawa 25dc51
template <typename pixel="" raster,="" typename=""></typename>
shun-iwasawa 25dc51
void Iwa_GlareFx::setSourceTileToBuffer(const RASTER ras, kiss_fft_cpx* buf) {
shun-iwasawa 25dc51
  kiss_fft_cpx* buf_p = buf;
shun-iwasawa 25dc51
  for (int j = 0; j < ras->getLy(); j++) {
shun-iwasawa 25dc51
    PIXEL* pix = ras->pixels(j);
shun-iwasawa 25dc51
    for (int i = 0; i < ras->getLx(); i++, pix++, buf_p++) {
shun-iwasawa 25dc51
      // Value = 0.3R 0.59G 0.11B
shun-iwasawa 25dc51
      (*buf_p).r = (double(pix->r) * 0.3 + double(pix->g) * 0.59 +
shun-iwasawa 25dc51
                    double(pix->b) * 0.11) /
shun-iwasawa 25dc51
                   double(PIXEL::maxChannelValue);
shun-iwasawa 25dc51
    }
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
//------------------------------------------------
shun-iwasawa 25dc51
shun-iwasawa 25dc51
void Iwa_GlareFx::setGlarePatternToBuffer(const double3* glare,
shun-iwasawa 25dc51
                                          kiss_fft_cpx* buf, const int channel,
shun-iwasawa 25dc51
                                          const int dimIris,
shun-iwasawa 25dc51
                                          const TDimensionI& dimOut) {
shun-iwasawa 25dc51
  int margin_x = (dimOut.lx - dimIris) / 2;
shun-iwasawa 25dc51
  int margin_y = (dimOut.ly - dimIris) / 2;
shun-iwasawa 25dc51
  for (int j = margin_y; j < margin_y + dimIris; j++) {
shun-iwasawa 25dc51
    const double3* glare_p = &glare[(j - margin_y) * dimIris];
shun-iwasawa 25dc51
    kiss_fft_cpx* buf_p    = &buf[j * dimOut.lx + margin_x];
shun-iwasawa 25dc51
    for (int i = margin_x; i < margin_x + dimIris; i++, buf_p++, glare_p++) {
shun-iwasawa 25dc51
      (*buf_p).r = (channel == 0)
shun-iwasawa 25dc51
                       ? (*glare_p).x
shun-iwasawa 25dc51
                       : (channel == 1) ? (*glare_p).y : (*glare_p).z;
shun-iwasawa 25dc51
    }
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
//------------------------------------------------
shun-iwasawa 25dc51
shun-iwasawa 25dc51
void Iwa_GlareFx::multiplyFilter(kiss_fft_cpx* glare,
shun-iwasawa 25dc51
                                 const kiss_fft_cpx* source, const int count) {
shun-iwasawa 25dc51
  kiss_fft_cpx* g_p       = glare;
shun-iwasawa 25dc51
  const kiss_fft_cpx* s_p = source;
shun-iwasawa 25dc51
  for (int i = 0; i < count; i++, g_p++, s_p++) {
shun-iwasawa 25dc51
    double re = (*g_p).r * (*s_p).r - (*g_p).i * (*s_p).i;
shun-iwasawa 25dc51
    double im = (*g_p).r * (*s_p).i + (*s_p).r * (*g_p).i;
shun-iwasawa 25dc51
    (*g_p).r  = re;
shun-iwasawa 25dc51
    (*g_p).i  = im;
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
//------------------------------------------------
shun-iwasawa 25dc51
template <typename pixel="" raster,="" typename=""></typename>
shun-iwasawa 25dc51
void Iwa_GlareFx::setChannelToResult(const RASTER ras, kiss_fft_cpx* buf,
shun-iwasawa 25dc51
                                     int channel, const TDimensionI& dimOut) {
shun-iwasawa 25dc51
  auto clamp01 = [](double chan) {
shun-iwasawa 25dc51
    if (chan < 0.0) return 0.0;
shun-iwasawa 25dc51
    if (chan > 1.0) return 1.0;
shun-iwasawa 25dc51
    return chan;
shun-iwasawa 25dc51
  };
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  int margin_x = (dimOut.lx - ras->getSize().lx) / 2;
shun-iwasawa 25dc51
  int margin_y = (dimOut.ly - ras->getSize().ly) / 2;
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  for (int j = 0; j < ras->getLy(); j++) {
shun-iwasawa 25dc51
    // kiss_fft_cpx* buf_p = &buf[(j + margin_y)*dimOut.lx + margin_x];
shun-iwasawa 25dc51
    PIXEL* pix = ras->pixels(j);
shun-iwasawa 25dc51
    for (int i = 0; i < ras->getLx(); i++, pix++) {
shun-iwasawa 25dc51
      kiss_fft_cpx fft_val =
shun-iwasawa 25dc51
          buf[getCoord(i + margin_x, j + margin_y, dimOut.lx, dimOut.ly)];
shun-iwasawa 25dc51
      double val = fft_val.r / (dimOut.lx * dimOut.ly);
shun-iwasawa 25dc51
      if (channel == 0)
shun-iwasawa 25dc51
        pix->r = (typename PIXEL::Channel)(clamp01(val) *
shun-iwasawa 25dc51
                                           double(PIXEL::maxChannelValue));
shun-iwasawa 25dc51
      else if (channel == 1)
shun-iwasawa 25dc51
        pix->g = (typename PIXEL::Channel)(clamp01(val) *
shun-iwasawa 25dc51
                                           double(PIXEL::maxChannelValue));
shun-iwasawa 25dc51
      else if (channel == 2) {
shun-iwasawa 25dc51
        pix->b = (typename PIXEL::Channel)(clamp01(val) *
shun-iwasawa 25dc51
                                           double(PIXEL::maxChannelValue));
shun-iwasawa 25dc51
        pix->m = PIXEL::maxChannelValue;
shun-iwasawa 25dc51
      }
shun-iwasawa 25dc51
    }
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
//------------------------------------------------
shun-iwasawa 25dc51
bool Iwa_GlareFx::doGetBBox(double frame, TRectD& bBox,
shun-iwasawa 25dc51
                            const TRenderSettings& info) {
shun-iwasawa 25dc51
  bBox = TConsts::infiniteRectD;
shun-iwasawa 25dc51
  return true;
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
//------------------------------------------------
shun-iwasawa 25dc51
shun-iwasawa 25dc51
bool Iwa_GlareFx::canHandle(const TRenderSettings& info, double frame) {
shun-iwasawa 25dc51
  return false;
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
//------------------------------------------------
shun-iwasawa 25dc51
// Resize / flip the iris image according to the size ratio.
shun-iwasawa 25dc51
// Normalize the brightness of the iris image.
shun-iwasawa 25dc51
// Enlarge the iris to the output size.
shun-iwasawa 25dc51
void Iwa_GlareFx::convertIris(kiss_fft_cpx* kissfft_comp_iris_before,
shun-iwasawa 25dc51
                              const int& dimIris, const TRectD& irisBBox,
shun-iwasawa c1adfa
                              const TRasterP irisRaster) {
shun-iwasawa 25dc51
  // the original size of iris image
shun-iwasawa 25dc51
  double2 irisOrgSize = {irisBBox.getLx(), irisBBox.getLy()};
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // add 1 pixel margins to all sides
shun-iwasawa 25dc51
  int2 filterSize = {(int)std::ceil(irisOrgSize.x) + 2,
shun-iwasawa 25dc51
                     (int)std::ceil(irisOrgSize.y) + 2};
shun-iwasawa 25dc51
  TPointD resizeOffset((double)filterSize.x - irisOrgSize.x,
shun-iwasawa 25dc51
                       (double)filterSize.y - irisOrgSize.y);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // Try to set the center of the iris to the center of the screen
shun-iwasawa 25dc51
  if ((dimIris - filterSize.x) % 2 == 1) filterSize.x++;
shun-iwasawa 25dc51
  if ((dimIris - filterSize.y) % 2 == 1) filterSize.y++;
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  TRaster64P resizedIris(TDimension(filterSize.x, filterSize.y));
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  TAffine aff;
shun-iwasawa 25dc51
  TPointD affOffset(0.5, 0.5);
shun-iwasawa 25dc51
  if (dimIris % 2 == 1) affOffset += TPointD(0.5, 0.5);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  aff = TTranslation(resizedIris->getCenterD() + affOffset);
shun-iwasawa c1adfa
  aff *= TTranslation(-(irisRaster->getCenterD() + affOffset));
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // resample the iris
shun-iwasawa c1adfa
  TRop::resample(resizedIris, irisRaster, aff);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // accumulated value
shun-iwasawa 25dc51
  float irisValAmount = 0.0;
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  int iris_j = 0;
shun-iwasawa 25dc51
  // Initialize
shun-iwasawa 25dc51
  for (int i = 0; i < dimIris * dimIris; i++) {
shun-iwasawa 25dc51
    kissfft_comp_iris_before[i].r = 0.0;
shun-iwasawa 25dc51
    kissfft_comp_iris_before[i].i = 0.0;
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
  for (int j = (dimIris - filterSize.y) / 2; iris_j < filterSize.y;
shun-iwasawa 25dc51
       j++, iris_j++) {
shun-iwasawa 25dc51
    if (j < 0) continue;
shun-iwasawa 25dc51
    if (j >= dimIris) break;
shun-iwasawa 25dc51
    TPixel64* pix = resizedIris->pixels(iris_j);
shun-iwasawa 25dc51
    int iris_i    = 0;
shun-iwasawa 25dc51
    for (int i = (dimIris - filterSize.x) / 2; iris_i < filterSize.x;
shun-iwasawa 25dc51
         i++, iris_i++) {
shun-iwasawa 25dc51
      if (i < 0) continue;
shun-iwasawa 25dc51
      if (i >= dimIris) break;
shun-iwasawa 25dc51
      // Value = 0.3R 0.59G 0.11B
shun-iwasawa 25dc51
      kissfft_comp_iris_before[j * dimIris + i].r =
shun-iwasawa 25dc51
          ((float)pix->r * 0.3f + (float)pix->g * 0.59f +
shun-iwasawa 25dc51
           (float)pix->b * 0.11f) /
shun-iwasawa 25dc51
          (float)USHRT_MAX;
shun-iwasawa 25dc51
      irisValAmount += kissfft_comp_iris_before[j * dimIris + i].r;
shun-iwasawa 25dc51
      pix++;
shun-iwasawa 25dc51
    }
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  // Normalize value
shun-iwasawa 25dc51
  for (int i = 0; i < dimIris * dimIris; i++) {
shun-iwasawa 25dc51
    kissfft_comp_iris_before[i].r /= irisValAmount;
shun-iwasawa 25dc51
  }
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
void Iwa_GlareFx::getParamUIs(TParamUIConcept*& concepts, int& length) {
shun-iwasawa 25dc51
  concepts = new TParamUIConcept[length = 2];
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  concepts[0].m_type  = TParamUIConcept::RADIUS;
shun-iwasawa 25dc51
  concepts[0].m_label = "Size";
shun-iwasawa 25dc51
  concepts[0].m_params.push_back(m_size);
shun-iwasawa 25dc51
shun-iwasawa 25dc51
  concepts[1].m_type  = TParamUIConcept::POINT;
shun-iwasawa 25dc51
  concepts[1].m_label = "Noise Offset";
shun-iwasawa 25dc51
  concepts[1].m_params.push_back(m_noise_offset);
shun-iwasawa 25dc51
}
shun-iwasawa 25dc51
shun-iwasawa 25dc51
FX_PLUGIN_IDENTIFIER(Iwa_GlareFx, "iwa_GlareFx")