shun-iwasawa 13c4cf
//--------------------------------------------------------------
shun-iwasawa 13c4cf
// This Fx is based on & modified from the source code by Zhanping Liu, licensed
shun-iwasawa 13c4cf
// with the terms as follows:
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//----------------[Start of the License Notice]-----------------
shun-iwasawa 13c4cf
////////////////////////////////////////////////////////////////////////////
shun-iwasawa 13c4cf
///          Line Integral Convolution for Flow Visualization            ///
shun-iwasawa 13c4cf
///                           Initial  Version                           ///
shun-iwasawa 13c4cf
///                             May 15, 1999                             ///
shun-iwasawa 13c4cf
///                           by  Zhanping Liu                           ///
shun-iwasawa 13c4cf
///                      (zhanping@erc.msstate.edu)                      ///
shun-iwasawa 13c4cf
///                    while with  Graphics  Laboratory,                 ///
shun-iwasawa 13c4cf
///                    Peking  University, P. R. China                   ///
shun-iwasawa 13c4cf
///----------------------------------------------------------------------///
shun-iwasawa 13c4cf
///                           Later  Condensed                           ///
shun-iwasawa 13c4cf
///                             May 4,  2002                             ///
shun-iwasawa 13c4cf
///                                                                      ///
shun-iwasawa 13c4cf
///          VAIL (Visualization Analysis & Imaging Laboratory)          ///
shun-iwasawa 13c4cf
///                  ERC  (Engineering Research Center)                  ///
shun-iwasawa 13c4cf
///                     Mississippi State University                     ///
shun-iwasawa 13c4cf
////////////////////////////////////////////////////////////////////////////
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
////////////////////////////////////////////////////////////////////////////
shun-iwasawa 13c4cf
/// This code was developed  based on  the original algorithm  proposed by///
shun-iwasawa 13c4cf
/// Brian Cabral  and  Leith (Casey) Leedom  in the paper  "Imaging Vector///
shun-iwasawa 13c4cf
/// Fields Using Line Integral Convolution", published  in  Proceedings of///
shun-iwasawa 13c4cf
/// ACM  SigGraph 93,  Aug 2-6,  Anaheim,  California,  pp. 263-270, 1993.///
shun-iwasawa 13c4cf
/// Permission to use, copy, modify, distribute and sell this code for any///
shun-iwasawa 13c4cf
/// purpose is hereby granted without fee,  provided that the above notice///
shun-iwasawa 13c4cf
/// appears in all copies  and  that both that notice and  this permission///
shun-iwasawa 13c4cf
/// appear in supporting documentation. The  developer  of this code makes///
shun-iwasawa 13c4cf
/// no  representations  about  the  suitability  of  this  code  for  any///
shun-iwasawa 13c4cf
/// purpose.  It is provided "as is"  without express or implied warranty.///
shun-iwasawa 13c4cf
////////////////////////////////////////////////////////////////////////////
shun-iwasawa 13c4cf
//-----------------[End of the License Notice]------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//--------------------------------------------------------------
shun-iwasawa 13c4cf
#include "iwa_flowblurfx.h"
shun-iwasawa 13c4cf
#include <QThreadPool>
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
namespace {
shun-iwasawa 13c4cf
const double LINE_SQUARE_CLIP_MAX = 100000.0;
shun-iwasawa 13c4cf
const double VECTOR_COMPONENT_MIN = 0.05;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
inline double clamp01(double val) {
shun-iwasawa 13c4cf
  return (val > 1.0) ? 1.0 : (val < 0.0) ? 0.0 : val;
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
// convert sRGB color space to power space
shun-iwasawa 13c4cf
template <typename T = double>
shun-iwasawa 13c4cf
inline T to_linear_color_space(T nonlinear_color, T exposure, T gamma) {
shun-iwasawa 481b59
  if (nonlinear_color <= T(0)) return T(0);
shun-iwasawa 13c4cf
  return std::pow(nonlinear_color, gamma) / exposure;
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
// convert power space to sRGB color space
shun-iwasawa 13c4cf
template <typename T = double>
shun-iwasawa 13c4cf
inline T to_nonlinear_color_space(T linear_color, T exposure, T gamma) {
shun-iwasawa 481b59
  if (linear_color <= T(0)) return T(0);
shun-iwasawa 13c4cf
  return std::pow(linear_color * exposure, T(1) / gamma);
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
}  // namespace
shun-iwasawa 13c4cf
//------------------------------------------------------------
shun-iwasawa 13c4cf
template <typename RASTER, typename PIXEL>
shun-iwasawa 13c4cf
void Iwa_FlowBlurFx::setSourceTileToBuffer(const RASTER srcRas, double4 *buf,
shun-iwasawa 13c4cf
                                           bool isLinear, double gamma) {
shun-iwasawa 13c4cf
  double4 *buf_p = buf;
shun-iwasawa 13c4cf
  for (int j = 0; j < srcRas->getLy(); j++) {
shun-iwasawa 13c4cf
    PIXEL *pix = srcRas->pixels(j);
shun-iwasawa 13c4cf
    for (int i = 0; i < srcRas->getLx(); i++, pix++, buf_p++) {
shun-iwasawa 13c4cf
      (*buf_p).x = double(pix->r) / double(PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
      (*buf_p).y = double(pix->g) / double(PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
      (*buf_p).z = double(pix->b) / double(PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
      (*buf_p).w = double(pix->m) / double(PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
      if (isLinear && (*buf_p).w > 0.0) {
shun-iwasawa 13c4cf
        (*buf_p).x =
shun-iwasawa 13c4cf
            to_linear_color_space((*buf_p).x / (*buf_p).w, 1.0, gamma) *
shun-iwasawa 13c4cf
            (*buf_p).w;
shun-iwasawa 13c4cf
        (*buf_p).y =
shun-iwasawa 13c4cf
            to_linear_color_space((*buf_p).y / (*buf_p).w, 1.0, gamma) *
shun-iwasawa 13c4cf
            (*buf_p).w;
shun-iwasawa 13c4cf
        (*buf_p).z =
shun-iwasawa 13c4cf
            to_linear_color_space((*buf_p).z / (*buf_p).w, 1.0, gamma) *
shun-iwasawa 13c4cf
            (*buf_p).w;
shun-iwasawa 13c4cf
      }
shun-iwasawa 13c4cf
    }
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
//------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
template <typename RASTER, typename PIXEL>
shun-iwasawa 13c4cf
void Iwa_FlowBlurFx::setFlowTileToBuffer(const RASTER flowRas, double2 *buf,
shun-iwasawa 13c4cf
                                         double *refBuf) {
shun-iwasawa 13c4cf
  double2 *buf_p   = buf;
shun-iwasawa 13c4cf
  double *refBuf_p = refBuf;
shun-iwasawa 13c4cf
  for (int j = 0; j < flowRas->getLy(); j++) {
shun-iwasawa 13c4cf
    PIXEL *pix = flowRas->pixels(j);
shun-iwasawa 13c4cf
    for (int i = 0; i < flowRas->getLx(); i++, pix++, buf_p++) {
shun-iwasawa 13c4cf
      double val = double(pix->r) / double(PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
      (*buf_p).x = val * 2.0 - 1.0;
shun-iwasawa 13c4cf
      val        = double(pix->g) / double(PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
      (*buf_p).y = val * 2.0 - 1.0;
shun-iwasawa 13c4cf
      if (refBuf != nullptr) {
shun-iwasawa 13c4cf
        *refBuf_p = double(pix->b) / double(PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
        refBuf_p++;
shun-iwasawa 13c4cf
      }
shun-iwasawa 13c4cf
    }
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
template <typename RASTER, typename PIXEL>
shun-iwasawa 13c4cf
void Iwa_FlowBlurFx::setReferenceTileToBuffer(const RASTER refRas,
shun-iwasawa 13c4cf
                                              double *buf) {
shun-iwasawa 13c4cf
  double *buf_p = buf;
shun-iwasawa 13c4cf
  for (int j = 0; j < refRas->getLy(); j++) {
shun-iwasawa 13c4cf
    PIXEL *pix = refRas->pixels(j);
shun-iwasawa 13c4cf
    for (int i = 0; i < refRas->getLx(); i++, pix++, buf_p++) {
shun-iwasawa 13c4cf
      // Value = 0.3R 0.59G 0.11B
shun-iwasawa 13c4cf
      (*buf_p) = (double(pix->r) * 0.3 + double(pix->g) * 0.59 +
shun-iwasawa 13c4cf
                  double(pix->b) * 0.11) /
shun-iwasawa 13c4cf
                 double(PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
    }
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
template <typename RASTER, typename PIXEL>
shun-iwasawa 13c4cf
void Iwa_FlowBlurFx::setOutputRaster(double4 *out_buf, const RASTER dstRas,
shun-iwasawa 13c4cf
                                     bool isLinear, double gamma) {
shun-iwasawa 13c4cf
  double4 *buf_p = out_buf;
shun-iwasawa 13c4cf
  for (int j = 0; j < dstRas->getLy(); j++) {
shun-iwasawa 13c4cf
    PIXEL *pix = dstRas->pixels(j);
shun-iwasawa 13c4cf
    for (int i = 0; i < dstRas->getLx(); i++, pix++, buf_p++) {
shun-iwasawa 13c4cf
      if (!isLinear || (*buf_p).w == 0.0) {
shun-iwasawa 13c4cf
        pix->r = (typename PIXEL::Channel)(clamp01((*buf_p).x) *
shun-iwasawa 13c4cf
                                           (double)PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
        pix->g = (typename PIXEL::Channel)(clamp01((*buf_p).y) *
shun-iwasawa 13c4cf
                                           (double)PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
        pix->b = (typename PIXEL::Channel)(clamp01((*buf_p).z) *
shun-iwasawa 13c4cf
                                           (double)PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
      } else {
shun-iwasawa 13c4cf
        double val;
shun-iwasawa 13c4cf
        val = to_nonlinear_color_space((*buf_p).x / (*buf_p).w, 1.0, gamma) *
shun-iwasawa 13c4cf
              (*buf_p).w;
shun-iwasawa 13c4cf
        pix->r = (typename PIXEL::Channel)(clamp01(val) *
shun-iwasawa 13c4cf
                                           (double)PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
        val    = to_nonlinear_color_space((*buf_p).y / (*buf_p).w, 1.0, gamma) *
shun-iwasawa 13c4cf
              (*buf_p).w;
shun-iwasawa 13c4cf
        pix->g = (typename PIXEL::Channel)(clamp01(val) *
shun-iwasawa 13c4cf
                                           (double)PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
        val    = to_nonlinear_color_space((*buf_p).z / (*buf_p).w, 1.0, gamma) *
shun-iwasawa 13c4cf
              (*buf_p).w;
shun-iwasawa 13c4cf
        pix->b = (typename PIXEL::Channel)(clamp01(val) *
shun-iwasawa 13c4cf
                                           (double)PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
      }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
      pix->m = (typename PIXEL::Channel)(clamp01((*buf_p).w) *
shun-iwasawa 13c4cf
                                         (double)PIXEL::maxChannelValue);
shun-iwasawa 13c4cf
    }
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
//------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
void FlowBlurWorker::run() {
shun-iwasawa 13c4cf
  auto sourceAt = [&](int x, int y) {
shun-iwasawa 13c4cf
    if (x < 0 || x >= m_dim.lx || y < 0 || y >= m_dim.ly) return double4();
shun-iwasawa 13c4cf
    return m_source_buf[y * m_dim.lx + x];
shun-iwasawa 13c4cf
  };
shun-iwasawa 13c4cf
  auto flowAt = [&](int x, int y) {
shun-iwasawa 13c4cf
    if (x < 0 || x >= m_dim.lx || y < 0 || y >= m_dim.ly) return double2();
shun-iwasawa 13c4cf
    return m_flow_buf[y * m_dim.lx + x];
shun-iwasawa 13c4cf
  };
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // ロジスティック分布の確率密度関数を格納する(s = 1/3、0-1の範囲で100分割)
shun-iwasawa 13c4cf
  double logDist[101];
shun-iwasawa 13c4cf
  if (m_filterType == Gaussian) {
shun-iwasawa 13c4cf
    double scale = 1.0 / 3.0;
shun-iwasawa 13c4cf
    for (int i = 0; i <= 101; i++) {
shun-iwasawa 13c4cf
      double x   = (double)i / 100.0;
shun-iwasawa 13c4cf
      logDist[i] = std::tanh(x / (2.0 * scale));
shun-iwasawa 13c4cf
    }
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
  // 0-1に正規化した変数の累積値を返す
shun-iwasawa 13c4cf
  auto getCumulative = [&](double pos) {
shun-iwasawa 13c4cf
    if (pos > 1.0) return 1.0;
shun-iwasawa 13c4cf
    if (m_filterType == Linear)
shun-iwasawa 13c4cf
      return 2.0 * pos - pos * pos;
shun-iwasawa 13c4cf
    else if (m_filterType == Gaussian)
shun-iwasawa 13c4cf
      return logDist[(int)(std::ceil(pos * 100.0))];
shun-iwasawa 13c4cf
    else  // Flat
shun-iwasawa 13c4cf
      return pos;
shun-iwasawa 13c4cf
  };
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  int max_ADVCTS = int(m_krnlen * 3);  // MAXIMUM number of advection steps per
shun-iwasawa 13c4cf
                                       // direction to break dead loops
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  double4 *out_p = &m_out_buf[m_yFrom * m_dim.lx];
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  double *ref_p =
shun-iwasawa 13c4cf
      (m_reference_buf) ? &m_reference_buf[m_yFrom * m_dim.lx] : nullptr;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // for each pixel in the 2D output LIC image
shun-iwasawa 13c4cf
  for (int j = m_yFrom; j < m_yTo; j++) {
shun-iwasawa 13c4cf
    for (int i = 0; i < m_dim.lx; i++, out_p++) {
shun-iwasawa 13c4cf
      double4 t_acum[2];            // texture accumulators zero-initialized
shun-iwasawa 13c4cf
      double w_acum[2] = {0., 0.};  // weight accumulators zero-initialized
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
      double blurLength = (ref_p) ? (*ref_p) * m_krnlen : m_krnlen;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
      if (blurLength == 0.0) {
shun-iwasawa 13c4cf
        (*out_p) = sourceAt(i, j);
shun-iwasawa 13c4cf
        if (ref_p) ref_p++;
shun-iwasawa 13c4cf
        continue;
shun-iwasawa 13c4cf
      }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
      // for either advection direction
shun-iwasawa 13c4cf
      for (int advDir = 0; advDir < 2; advDir++) {
shun-iwasawa 13c4cf
        // init the step counter, curve-length measurer, and streamline seed///
shun-iwasawa 13c4cf
        int advcts =
shun-iwasawa 13c4cf
            0;  // number of ADVeCTion stepS per direction (a step counter)
shun-iwasawa 13c4cf
        double curLen = 0.0;  // CURrent   LENgth of the streamline
shun-iwasawa 13c4cf
        double clp0_x =
shun-iwasawa 13c4cf
            (double)i + 0.5;  // x-coordinate of CLiP point 0 (current)
shun-iwasawa 13c4cf
        double clp0_y =
shun-iwasawa 13c4cf
            (double)j + 0.5;  // y-coordinate of CLiP point 0	(current)
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
        // until the streamline is advected long enough or a tightly  spiralling
shun-iwasawa 13c4cf
        // center / focus is encountered///
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
        double2 pre_vctr = flowAt(int(clp0_x), int(clp0_y));
shun-iwasawa 13c4cf
        if (advDir == 1) {
shun-iwasawa 13c4cf
          pre_vctr.x = -pre_vctr.x;
shun-iwasawa 13c4cf
          pre_vctr.y = -pre_vctr.y;
shun-iwasawa 13c4cf
        }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
        while (curLen < blurLength && advcts < max_ADVCTS) {
shun-iwasawa 13c4cf
          // access the vector at the sample
shun-iwasawa 13c4cf
          double2 vctr = flowAt(int(clp0_x), int(clp0_y));
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
          // in case of a critical point
shun-iwasawa 13c4cf
          if (vctr.x == 0.0 && vctr.y == 0.0) {
shun-iwasawa 13c4cf
            w_acum[advDir] = (advcts == 0) ? 1.0 : w_acum[advDir];
shun-iwasawa 13c4cf
            break;
shun-iwasawa 13c4cf
          }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
          // negate the vector for the backward-advection case
shun-iwasawa 13c4cf
          if (advDir == 1) {
shun-iwasawa 13c4cf
            vctr.x = -vctr.x;
shun-iwasawa 13c4cf
            vctr.y = -vctr.y;
shun-iwasawa 13c4cf
          }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
          // assuming that the flow field vector is bi-directional
shun-iwasawa 13c4cf
          // if the vector is at an acute angle to the previous vector, negate
shun-iwasawa 13c4cf
          // it.
shun-iwasawa 13c4cf
          if (vctr.x * pre_vctr.x + vctr.y * pre_vctr.y < 0) {
shun-iwasawa 13c4cf
            vctr.x = -vctr.x;
shun-iwasawa 13c4cf
            vctr.y = -vctr.y;
shun-iwasawa 13c4cf
          }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
          // clip the segment against the pixel boundaries --- find the shorter
shun-iwasawa 13c4cf
          // from the two clipped segments replace  all  if-statements  whenever
shun-iwasawa 13c4cf
          // possible  as  they  might  affect the computational speed
shun-iwasawa 13c4cf
          double tmpLen;
shun-iwasawa 13c4cf
          double segLen = LINE_SQUARE_CLIP_MAX;  // SEGment   LENgth
shun-iwasawa 13c4cf
          segLen        = (vctr.x < -VECTOR_COMPONENT_MIN)
shun-iwasawa 13c4cf
                              ? (std::floor(clp0_x) - clp0_x) / vctr.x
shun-iwasawa 13c4cf
                              : segLen;
shun-iwasawa 13c4cf
          segLen =
shun-iwasawa 13c4cf
              (vctr.x > VECTOR_COMPONENT_MIN)
shun-iwasawa 13c4cf
                  ? (std::floor(std::floor(clp0_x) + 1.5) - clp0_x) / vctr.x
shun-iwasawa 13c4cf
                  : segLen;
shun-iwasawa 13c4cf
          segLen = (vctr.y < -VECTOR_COMPONENT_MIN)
shun-iwasawa 13c4cf
                       ? (((tmpLen = (std::floor(clp0_y) - clp0_y) / vctr.y) <
shun-iwasawa 13c4cf
                           segLen)
shun-iwasawa 13c4cf
                              ? tmpLen
shun-iwasawa 13c4cf
                              : segLen)
shun-iwasawa 13c4cf
                       : segLen;
shun-iwasawa 13c4cf
          segLen = (vctr.y > VECTOR_COMPONENT_MIN)
shun-iwasawa 13c4cf
                       ? (((tmpLen = (std::floor(std::floor(clp0_y) + 1.5) -
shun-iwasawa 13c4cf
                                      clp0_y) /
shun-iwasawa 13c4cf
                                     vctr.y) < segLen)
shun-iwasawa 13c4cf
                              ? tmpLen
shun-iwasawa 13c4cf
                              : segLen)
shun-iwasawa 13c4cf
                       : segLen;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
          // update the curve-length measurers
shun-iwasawa 13c4cf
          double prvLen = curLen;
shun-iwasawa 13c4cf
          curLen += segLen;
shun-iwasawa 13c4cf
          segLen += 0.0004;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
          // check if the filter has reached either end
shun-iwasawa 13c4cf
          segLen =
shun-iwasawa 13c4cf
              (curLen > m_krnlen) ? ((curLen = m_krnlen) - prvLen) : segLen;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
          // obtain the next clip point
shun-iwasawa 13c4cf
          double clp1_x = clp0_x + vctr.x * segLen;
shun-iwasawa 13c4cf
          double clp1_y = clp0_y + vctr.y * segLen;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
          // obtain the middle point of the segment as the texture-contributing
shun-iwasawa 13c4cf
          // sample
shun-iwasawa 13c4cf
          double2 samp;
shun-iwasawa 13c4cf
          samp.x = (clp0_x + clp1_x) * 0.5;
shun-iwasawa 13c4cf
          samp.y = (clp0_y + clp1_y) * 0.5;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
          // obtain the texture value of the sample
shun-iwasawa 13c4cf
          double4 texVal = sourceAt(int(samp.x), int(samp.y));
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
          // update the accumulated weight and the accumulated composite texture
shun-iwasawa 13c4cf
          // (texture x weight)
shun-iwasawa 13c4cf
          double W_ACUM = getCumulative(curLen / blurLength);
shun-iwasawa 13c4cf
          // double W_ACUM = curLen;
shun-iwasawa 13c4cf
          // W_ACUM = wgtLUT[int(curLen * len2ID)];
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
          double smpWgt  = W_ACUM - w_acum[advDir];
shun-iwasawa 13c4cf
          w_acum[advDir] = W_ACUM;
shun-iwasawa 13c4cf
          t_acum[advDir].x += texVal.x * smpWgt;
shun-iwasawa 13c4cf
          t_acum[advDir].y += texVal.y * smpWgt;
shun-iwasawa 13c4cf
          t_acum[advDir].z += texVal.z * smpWgt;
shun-iwasawa 13c4cf
          t_acum[advDir].w += texVal.w * smpWgt;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
          // update the step counter and the "current" clip point
shun-iwasawa 13c4cf
          advcts++;
shun-iwasawa 13c4cf
          clp0_x = clp1_x;
shun-iwasawa 13c4cf
          clp0_y = clp1_y;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
          pre_vctr = vctr;
shun-iwasawa 13c4cf
          // check if the streamline has gone beyond the flow field///
shun-iwasawa 13c4cf
          if (clp0_x < 0.0 || clp0_x >= double(m_dim.lx) || clp0_y < 0.0 ||
shun-iwasawa 13c4cf
              clp0_y >= double(m_dim.ly))
shun-iwasawa 13c4cf
            break;
shun-iwasawa 13c4cf
        }
shun-iwasawa 13c4cf
      }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
      // normalize the accumulated composite texture
shun-iwasawa 13c4cf
      (*out_p).x = (t_acum[0].x + t_acum[1].x) / (w_acum[0] + w_acum[1]);
shun-iwasawa 13c4cf
      (*out_p).y = (t_acum[0].y + t_acum[1].y) / (w_acum[0] + w_acum[1]);
shun-iwasawa 13c4cf
      (*out_p).z = (t_acum[0].z + t_acum[1].z) / (w_acum[0] + w_acum[1]);
shun-iwasawa 13c4cf
      (*out_p).w = (t_acum[0].w + t_acum[1].w) / (w_acum[0] + w_acum[1]);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
      if (ref_p) ref_p++;
shun-iwasawa 13c4cf
    }
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
Iwa_FlowBlurFx::Iwa_FlowBlurFx()
shun-iwasawa 13c4cf
    : m_length(5.0)
shun-iwasawa 13c4cf
    , m_linear(false)
shun-iwasawa 13c4cf
    , m_gamma(2.2)
shun-iwasawa 13c4cf
    , m_filterType(new TIntEnumParam(Linear, "Linear"))
shun-iwasawa 13c4cf
    , m_referenceMode(new TIntEnumParam(REFERENCE, "Reference Image")) {
shun-iwasawa 13c4cf
  addInputPort("Source", m_source);
shun-iwasawa 13c4cf
  addInputPort("Flow", m_flow);
shun-iwasawa 13c4cf
  addInputPort("Reference", m_reference);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  bindParam(this, "length", m_length);
shun-iwasawa 13c4cf
  bindParam(this, "linear", m_linear);
shun-iwasawa 13c4cf
  bindParam(this, "gamma", m_gamma);
shun-iwasawa 13c4cf
  bindParam(this, "filterType", m_filterType);
shun-iwasawa 13c4cf
  bindParam(this, "referenceMode", m_referenceMode);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  m_length->setMeasureName("fxLength");
shun-iwasawa 13c4cf
  m_length->setValueRange(0., 100.0);
shun-iwasawa 13c4cf
  m_gamma->setValueRange(0.2, 5.0);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  m_filterType->addItem(Gaussian, "Gaussian");
shun-iwasawa 13c4cf
  m_filterType->addItem(Flat, "Flat");
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  m_referenceMode->addItem(FLOW_BLUE_CHANNEL, "Blue Channel of Flow Image");
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
void Iwa_FlowBlurFx::doCompute(TTile &tile, double frame,
shun-iwasawa 13c4cf
                               const TRenderSettings &settings) {
shun-iwasawa 13c4cf
  // do nothing if Source or Flow port is not connected
shun-iwasawa 13c4cf
  if (!m_source.isConnected() || !m_flow.isConnected()) {
shun-iwasawa 13c4cf
    tile.getRaster()->clear();
shun-iwasawa 13c4cf
    return;
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // output size
shun-iwasawa 13c4cf
  TDimension dim = tile.getRaster()->getSize();
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  double fac     = sqrt(fabs(settings.m_affine.det()));
shun-iwasawa 13c4cf
  double krnlen  = fac * m_length->getValue(frame);
shun-iwasawa 13c4cf
  int max_ADVCTS = int(krnlen * 3);  // MAXIMUM number of advection steps per
shun-iwasawa 13c4cf
                                     // direction to break dead loops
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  if (max_ADVCTS == 0) {
shun-iwasawa 13c4cf
    // No blur will be done. The underlying fx may pass by.
shun-iwasawa 13c4cf
    m_source->compute(tile, frame, settings);
shun-iwasawa 13c4cf
    return;
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  bool isLinear = m_linear->getValue();
shun-iwasawa 13c4cf
  double gamma  = m_gamma->getValue(frame);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // obtain Source memory buffer (RGBA)
shun-iwasawa 13c4cf
  TTile sourceTile;
shun-iwasawa 13c4cf
  m_source->allocateAndCompute(sourceTile, tile.m_pos, dim, tile.getRaster(),
shun-iwasawa 13c4cf
                               frame, settings);
shun-iwasawa 13c4cf
  // allocate buffer
shun-iwasawa 13c4cf
  double4 *source_buf;
shun-iwasawa 13c4cf
  TRasterGR8P source_buf_ras(dim.lx * dim.ly * sizeof(double4), 1);
shun-iwasawa 13c4cf
  source_buf_ras->lock();
shun-iwasawa 13c4cf
  source_buf       = (double4 *)source_buf_ras->getRawData();
shun-iwasawa 13c4cf
  TRaster32P ras32 = tile.getRaster();
shun-iwasawa 13c4cf
  TRaster64P ras64 = tile.getRaster();
shun-iwasawa 13c4cf
  if (ras32)
shun-iwasawa 13c4cf
    setSourceTileToBuffer<TRaster32P, TPixel32>(sourceTile.getRaster(),
shun-iwasawa 13c4cf
                                                source_buf, isLinear, gamma);
shun-iwasawa 13c4cf
  else if (ras64)
shun-iwasawa 13c4cf
    setSourceTileToBuffer<TRaster64P, TPixel64>(sourceTile.getRaster(),
shun-iwasawa 13c4cf
                                                source_buf, isLinear, gamma);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // obtain Flow memory buffer (XY)
shun-iwasawa 13c4cf
  TTile flowTile;
shun-iwasawa 13c4cf
  m_flow->allocateAndCompute(flowTile, tile.m_pos, dim, tile.getRaster(), frame,
shun-iwasawa 13c4cf
                             settings);
shun-iwasawa 13c4cf
  // allocate buffer
shun-iwasawa 13c4cf
  double2 *flow_buf;
shun-iwasawa 13c4cf
  TRasterGR8P flow_buf_ras(dim.lx * dim.ly * sizeof(double2), 1);
shun-iwasawa 13c4cf
  flow_buf_ras->lock();
shun-iwasawa 13c4cf
  flow_buf = (double2 *)flow_buf_ras->getRawData();
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  double *reference_buf = nullptr;
shun-iwasawa 13c4cf
  TRasterGR8P reference_buf_ras;
shun-iwasawa 13c4cf
  if (m_referenceMode->getValue() == FLOW_BLUE_CHANNEL ||
shun-iwasawa 13c4cf
      m_reference.isConnected()) {
shun-iwasawa 13c4cf
    reference_buf_ras = TRasterGR8P(dim.lx * dim.ly * sizeof(double), 1);
shun-iwasawa 13c4cf
    reference_buf_ras->lock();
shun-iwasawa 13c4cf
    reference_buf = (double *)reference_buf_ras->getRawData();
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  if (ras32)
shun-iwasawa 13c4cf
    setFlowTileToBuffer<TRaster32P, TPixel32>(flowTile.getRaster(), flow_buf,
shun-iwasawa 13c4cf
                                              reference_buf);
shun-iwasawa 13c4cf
  else if (ras64)
shun-iwasawa 13c4cf
    setFlowTileToBuffer<TRaster64P, TPixel64>(flowTile.getRaster(), flow_buf,
shun-iwasawa 13c4cf
                                              reference_buf);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  if (m_referenceMode->getValue() == REFERENCE && m_reference.isConnected()) {
shun-iwasawa 13c4cf
    TTile referenceTile;
shun-iwasawa 13c4cf
    m_reference->allocateAndCompute(referenceTile, tile.m_pos, dim,
shun-iwasawa 13c4cf
                                    tile.getRaster(), frame, settings);
shun-iwasawa 13c4cf
    if (ras32)
shun-iwasawa 13c4cf
      setReferenceTileToBuffer<TRaster32P, TPixel32>(referenceTile.getRaster(),
shun-iwasawa 13c4cf
                                                     reference_buf);
shun-iwasawa 13c4cf
    else if (ras64)
shun-iwasawa 13c4cf
      setReferenceTileToBuffer<TRaster64P, TPixel64>(referenceTile.getRaster(),
shun-iwasawa 13c4cf
                                                     reference_buf);
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // buffer for output raster
shun-iwasawa 13c4cf
  double4 *out_buf;
shun-iwasawa 13c4cf
  TRasterGR8P out_buf_ras(dim.lx * dim.ly * sizeof(double4), 1);
shun-iwasawa 13c4cf
  out_buf_ras->lock();
shun-iwasawa 13c4cf
  out_buf = (double4 *)out_buf_ras->getRawData();
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  int activeThreadCount = QThreadPool::globalInstance()->activeThreadCount();
shun-iwasawa 13c4cf
  // use half of the available threads
shun-iwasawa 13c4cf
  int threadAmount       = std::max(1, activeThreadCount / 2);
shun-iwasawa 13c4cf
  FILTER_TYPE filterType = (FILTER_TYPE)m_filterType->getValue();
shun-iwasawa 13c4cf
  QList<QThread *> threadList;
shun-iwasawa 13c4cf
  int tmpStart = 0;
shun-iwasawa 13c4cf
  for (int t = 0; t < threadAmount; t++) {
shun-iwasawa 13c4cf
    int tmpEnd =
shun-iwasawa 13c4cf
        (int)std::round((float)(dim.ly * (t + 1)) / (float)threadAmount);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
    FlowBlurWorker *worker =
shun-iwasawa 13c4cf
        new FlowBlurWorker(source_buf, flow_buf, out_buf, reference_buf, dim,
shun-iwasawa 13c4cf
                           krnlen, tmpStart, tmpEnd, filterType);
shun-iwasawa 13c4cf
    worker->start();
shun-iwasawa 13c4cf
    threadList.append(worker);
shun-iwasawa 13c4cf
    tmpStart = tmpEnd;
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  for (auto worker : threadList) {
shun-iwasawa 13c4cf
    worker->wait();
shun-iwasawa 13c4cf
    delete worker;
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  source_buf_ras->unlock();
shun-iwasawa 13c4cf
  flow_buf_ras->unlock();
shun-iwasawa 13c4cf
  if (reference_buf) reference_buf_ras->unlock();
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // render vector field with red & green channels
shun-iwasawa 13c4cf
  if (ras32)
shun-iwasawa 13c4cf
    setOutputRaster<TRaster32P, TPixel32>(out_buf, ras32, isLinear, gamma);
shun-iwasawa 13c4cf
  else if (ras64)
shun-iwasawa 13c4cf
    setOutputRaster<TRaster64P, TPixel64>(out_buf, ras64, isLinear, gamma);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  out_buf_ras->unlock();
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
bool Iwa_FlowBlurFx::doGetBBox(double frame, TRectD &bBox,
shun-iwasawa 13c4cf
                               const TRenderSettings &info) {
shun-iwasawa 13c4cf
  bBox = TConsts::infiniteRectD;
shun-iwasawa 13c4cf
  return true;
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
bool Iwa_FlowBlurFx::canHandle(const TRenderSettings &info, double frame) {
shun-iwasawa 13c4cf
  return true;
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
FX_PLUGIN_IDENTIFIER(Iwa_FlowBlurFx, "iwa_FlowBlurFx")