shun-iwasawa 13c4cf
#include "iwa_motionflowfx.h"
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
#include "tfxattributes.h"
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
#include "toonz/tstageobject.h"
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
#include "trop.h"
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
namespace {
shun-iwasawa 13c4cf
double getSizePixelAmount(const double val, const TAffine affine) {
shun-iwasawa 13c4cf
  /*--- Convert to vector --- */
shun-iwasawa 13c4cf
  TPointD vect;
shun-iwasawa 13c4cf
  vect.x = val;
shun-iwasawa 13c4cf
  vect.y = 0.0;
shun-iwasawa 13c4cf
  /*--- Apply geometrical transformation ---*/
shun-iwasawa 13c4cf
  // For the following lines I referred to lines 586-592 of
shun-iwasawa 13c4cf
  // sources/stdfx/motionblurfx.cpp
shun-iwasawa 13c4cf
  TAffine aff(affine);
shun-iwasawa 13c4cf
  aff.a13 = aff.a23 = 0; /* ignore translation */
shun-iwasawa 13c4cf
  vect              = aff * vect;
shun-iwasawa 13c4cf
  /*--- return the length of the vector ---*/
shun-iwasawa 13c4cf
  return std::sqrt(vect.x * vect.x + vect.y * vect.y);
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
}  // namespace
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
Iwa_MotionFlowFx::Iwa_MotionFlowFx()
shun-iwasawa 13c4cf
    : m_normalizeType(new TIntEnumParam(NORMALIZE_AUTO, "Auto"))
shun-iwasawa 13c4cf
    , m_normalizeRange(1.0) {
shun-iwasawa 13c4cf
  bindParam(this, "shutterLength", m_shutterLength);
shun-iwasawa 13c4cf
  bindParam(this, "motionObjectType", m_motionObjectType);
shun-iwasawa 13c4cf
  bindParam(this, "motionObjectIndex", m_motionObjectIndex);
shun-iwasawa 13c4cf
  bindParam(this, "normalizeType", m_normalizeType);
shun-iwasawa 13c4cf
  bindParam(this, "normalizeRange", m_normalizeRange);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  m_normalizeType->addItem(NORMALIZE_MANUAL, "Manual");
shun-iwasawa 13c4cf
  m_normalizeRange->setMeasureName("fxLength");
shun-iwasawa 13c4cf
  m_normalizeRange->setValueRange(0.01, 1000.0);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  getAttributes()->setIsSpeedAware(true);
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
void Iwa_MotionFlowFx::doCompute(TTile& tile, double frame,
shun-iwasawa 13c4cf
                                 const TRenderSettings& settings) {
shun-iwasawa 13c4cf
  /* Get parameters */
shun-iwasawa 13c4cf
  TAffine aff_Before, aff_After;
shun-iwasawa 13c4cf
  getAttributes()->getMotionAffines(aff_Before, aff_After);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  TDimensionI dimOut(tile.getRaster()->getLx(), tile.getRaster()->getLy());
shun-iwasawa 13c4cf
  /* output */
shun-iwasawa 13c4cf
  TRasterGR8P out_ras(sizeof(double3) * dimOut.lx * dimOut.ly, 1);
shun-iwasawa 13c4cf
  out_ras->lock();
shun-iwasawa 13c4cf
  double3* out_ras_p = (double3*)out_ras->getRawData();
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  double3* out_p = out_ras_p;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  double norm_range = 0.0;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  for (int y = 0; y < dimOut.ly; y++) {
shun-iwasawa 13c4cf
    for (int x = 0; x < dimOut.lx; x++, out_p++) {
shun-iwasawa 13c4cf
      TPointD pos = TPointD((double)x, (double)y) + tile.m_pos;
shun-iwasawa 13c4cf
      TPointD vec = pos - (aff_Before * aff_After.inv() * pos);
shun-iwasawa 13c4cf
      out_p->z    = std::sqrt(vec.x * vec.x + vec.y * vec.y);
shun-iwasawa 13c4cf
      if (out_p->z > 0.0) {
shun-iwasawa 13c4cf
        out_p->x   = vec.x / out_p->z;
shun-iwasawa 13c4cf
        out_p->y   = vec.y / out_p->z;
shun-iwasawa 13c4cf
        norm_range = std::max(norm_range, out_p->z);
shun-iwasawa 13c4cf
      } else {
shun-iwasawa 13c4cf
        out_p->x = 0.0;
shun-iwasawa 13c4cf
        out_p->y = 0.0;
shun-iwasawa 13c4cf
      }
shun-iwasawa 13c4cf
    }
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  if (m_normalizeType->getValue() == NORMALIZE_MANUAL)
shun-iwasawa 13c4cf
    norm_range = getSizePixelAmount(m_normalizeRange->getValue(frame),
shun-iwasawa 13c4cf
                                    settings.m_affine);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  tile.getRaster()->clear();
shun-iwasawa 13c4cf
  TRaster32P outRas32 = (TRaster32P)tile.getRaster();
shun-iwasawa 13c4cf
  TRaster64P outRas64 = (TRaster64P)tile.getRaster();
shun-iwasawa 13c4cf
  if (outRas32)
shun-iwasawa 13c4cf
    setOutRas<traster32p, tpixel32="">(outRas32, out_ras_p, norm_range);</traster32p,>
shun-iwasawa 13c4cf
  else if (outRas64)
shun-iwasawa 13c4cf
    setOutRas<traster64p, tpixel64="">(outRas64, out_ras_p, norm_range);</traster64p,>
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  out_ras->unlock();
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
template <typename pixel="" raster,="" typename=""></typename>
shun-iwasawa 13c4cf
void Iwa_MotionFlowFx::setOutRas(RASTER ras, double3* outBuf,
shun-iwasawa 13c4cf
                                 double norm_range) {
shun-iwasawa 13c4cf
  double3* buf_p = outBuf;
shun-iwasawa 13c4cf
  for (int j = 0; j < ras->getLy(); j++) {
shun-iwasawa 13c4cf
    PIXEL* pix = ras->pixels(j);
shun-iwasawa 13c4cf
    for (int i = 0; i < ras->getLx(); i++, pix++, buf_p++) {
shun-iwasawa 13c4cf
      double val = 0.5 + buf_p->x * 0.5;
shun-iwasawa 13c4cf
      pix->r = (typename PIXEL::Channel)(val * double(PIXEL::maxChannelValue));
shun-iwasawa 13c4cf
      val    = 0.5 + buf_p->y * 0.5;
shun-iwasawa 13c4cf
      pix->g = (typename PIXEL::Channel)(val * double(PIXEL::maxChannelValue));
shun-iwasawa 13c4cf
      val    = std::min(1.0, buf_p->z / norm_range);
shun-iwasawa 13c4cf
      pix->b = (typename PIXEL::Channel)(val * double(PIXEL::maxChannelValue));
shun-iwasawa 13c4cf
      pix->m = PIXEL::maxChannelValue;
shun-iwasawa 13c4cf
    }
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
bool Iwa_MotionFlowFx::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
//------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
bool Iwa_MotionFlowFx::canHandle(const TRenderSettings& info, double frame) {
shun-iwasawa 13c4cf
  return true;
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
/*------------------------------------------------------------
shun-iwasawa 13c4cf
 Since there is a possibility that the reference object is moving,
shun-iwasawa 13c4cf
 Change the alias every frame
shun-iwasawa 13c4cf
------------------------------------------------------------*/
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
std::string Iwa_MotionFlowFx::getAlias(double frame,
shun-iwasawa 13c4cf
                                       const TRenderSettings& info) const {
shun-iwasawa 13c4cf
  std::string alias = getFxType();
shun-iwasawa 13c4cf
  alias += "[";
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // alias of the effects related to the input ports separated by commas
shun-iwasawa 13c4cf
  // a port that is not connected to an alias blank (empty string)
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  std::string paramalias("");
shun-iwasawa 13c4cf
  for (int i = 0; i < getParams()->getParamCount(); i++) {
shun-iwasawa 13c4cf
    TParam* param = getParams()->getParam(i);
shun-iwasawa 13c4cf
    paramalias += param->getName() + "=" + param->getValueAlias(frame, 3);
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
  unsigned long id = getIdentifier();
shun-iwasawa 13c4cf
  return alias + std::to_string(frame) + "," + std::to_string(id) + paramalias +
shun-iwasawa 13c4cf
         "]";
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
FX_PLUGIN_IDENTIFIER(Iwa_MotionFlowFx, "iwa_MotionFlowFx")