Toshihiro Shimizu 890ddd
#include "texception.h"
Toshihiro Shimizu 890ddd
#include "tfxparam.h"
Toshihiro Shimizu 890ddd
#include "trop.h"
Toshihiro Shimizu 890ddd
#include "stdfx.h"
Toshihiro Shimizu 890ddd
#include "trasterfx.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class BlurFx final : public TStandardRasterFx {
Shinya Kitaoka 120a6e
  FX_PLUGIN_DECLARATION(BlurFx)
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRasterFxPort m_input;
Shinya Kitaoka 120a6e
  TDoubleParamP m_value;
Shinya Kitaoka 120a6e
  TBoolParamP m_useSSE;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  BlurFx() : m_value(20), m_useSSE(true) {
Shinya Kitaoka 120a6e
    m_value->setMeasureName("fxLength");
Shinya Kitaoka 120a6e
    bindParam(this, "value", m_value);
Shinya Kitaoka 120a6e
    bindParam(this, "useSSE", m_useSSE, true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    addInputPort("Source", m_input);
Shinya Kitaoka 120a6e
    m_value->setValueRange(0, std::numeric_limits<double>::max());</double>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~BlurFx(){};
Shinya Kitaoka 120a6e
Shinya Kitaoka 38fd86
  bool doGetBBox(double frame, TRectD &bBox,
Shinya Kitaoka 38fd86
                 const TRenderSettings &info) override {
Shinya Kitaoka 120a6e
    if (m_input.isConnected()) {
Shinya Kitaoka 120a6e
      bool ret = m_input->doGetBBox(frame, bBox, info);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      double blur = fabs(m_value->getValue(frame));
Shinya Kitaoka 120a6e
      int brad    = tceil(blur);
Shinya Kitaoka 120a6e
      bBox        = bBox.enlarge(brad);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      return ret;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      bBox = TRectD();
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void enlarge(const TRectD &bbox, TRectD &requestedRect, int blur);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void transform(double frame, int port, const TRectD &rectOnOutput,
Shinya Kitaoka 120a6e
                 const TRenderSettings &infoOnOutput, TRectD &rectOnInput,
Shinya Kitaoka 473e70
                 TRenderSettings &infoOnInput) override;
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void doCompute(TTile &tile, double frame, const TRenderSettings &) override;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int getMemoryRequirement(const TRectD &rect, double frame,
Shinya Kitaoka 473e70
                           const TRenderSettings &info) override;
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  bool canHandle(const TRenderSettings &info, double frame) override {
Shinya Kitaoka 120a6e
    if (m_value->getValue(frame) == 0) return true;
Shinya Kitaoka 120a6e
    return (isAlmostIsotropic(info.m_affine));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
FX_PLUGIN_IDENTIFIER(BlurFx, "blurFx")
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Calculates the geometry we need for this node computation, given
Shinya Kitaoka 120a6e
//! the known input data (bbox), the requested output (requestedRect) and the
Shinya Kitaoka 120a6e
//! blur factor.
Shinya Kitaoka 120a6e
void BlurFx::enlarge(const TRectD &bbox, TRectD &requestedRect, int blur) {
Shinya Kitaoka 120a6e
  if (bbox.isEmpty() || requestedRect.isEmpty()) {
Shinya Kitaoka 120a6e
    requestedRect.empty();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // We are to find out the geometry that is useful for the fx computation.
Shinya Kitaoka 120a6e
  // There are some rules to follow:
Shinya Kitaoka 120a6e
  //  a) First, the interesting output we can generate is bounded by both
Shinya Kitaoka 120a6e
  //     the requestedRect and the blurred bbox (i.e. enlarged by the blur
Shinya Kitaoka 120a6e
  //     radius).
Shinya Kitaoka 120a6e
  //  b) Pixels contributing to any output are necessarily part of bbox - and
Shinya Kitaoka 120a6e
  //  only
Shinya Kitaoka 120a6e
  //     those which are blurrable into the requestedRect are useful to us
Shinya Kitaoka 120a6e
  //     (i.e. pixels contained in its enlargement by the blur radius).
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRectD enlargedBBox(bbox.enlarge(blur));
Shinya Kitaoka 120a6e
  TRectD enlargedOut(requestedRect.enlarge(blur));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPointD originalP00(requestedRect.getP00());
Shinya Kitaoka 120a6e
  requestedRect = (enlargedOut * bbox) + (enlargedBBox * requestedRect);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Finally, make sure that the result is coherent with the original P00
Shinya Kitaoka 120a6e
  requestedRect -= originalP00;
Shinya Kitaoka 120a6e
  requestedRect.x0 = tfloor(requestedRect.x0);
Shinya Kitaoka 120a6e
  requestedRect.y0 = tfloor(requestedRect.y0);
Shinya Kitaoka 120a6e
  requestedRect.x1 = tceil(requestedRect.x1);
Shinya Kitaoka 120a6e
  requestedRect.y1 = tceil(requestedRect.y1);
Shinya Kitaoka 120a6e
  requestedRect += originalP00;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void BlurFx::transform(double frame, int port, const TRectD &rectOnOutput,
Shinya Kitaoka 120a6e
                       const TRenderSettings &infoOnOutput, TRectD &rectOnInput,
Shinya Kitaoka 120a6e
                       TRenderSettings &infoOnInput) {
Shinya Kitaoka 120a6e
  infoOnInput = infoOnOutput;
Shinya Kitaoka 120a6e
  rectOnInput = rectOnOutput;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double blur =
Shinya Kitaoka 120a6e
      fabs(m_value->getValue(frame) * sqrt(fabs(infoOnOutput.m_affine.det())));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (blur == 0) {
Shinya Kitaoka 120a6e
    rectOnInput = rectOnOutput;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int brad = tceil(blur);
Shinya Kitaoka 120a6e
  TRectD bbox;
Shinya Kitaoka 120a6e
  m_input->getBBox(frame, bbox, infoOnInput);
Shinya Kitaoka 120a6e
  enlarge(bbox, rectOnInput, brad);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int BlurFx::getMemoryRequirement(const TRectD &rect, double frame,
Shinya Kitaoka 120a6e
                                 const TRenderSettings &info) {
Shinya Kitaoka 120a6e
  double blurValue =
Shinya Kitaoka 120a6e
      fabs(m_value->getValue(frame) * sqrt(fabs(info.m_affine.det())));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (blurValue == 0.0) return 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int brad = tceil(blurValue);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Trop::blur is quite inefficient at the moment - it has to allocate a whole
Shinya Kitaoka 120a6e
  // raster of the same size of the input/output made of FLOAT QUADRUPLES...!
Shinya Kitaoka 120a6e
  return TRasterFx::memorySize(rect.enlarge(brad), sizeof(float) << 5);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void BlurFx::doCompute(TTile &tile, double frame,
Shinya Kitaoka 120a6e
                       const TRenderSettings &renderSettings) {
Shinya Kitaoka 120a6e
  if (!m_input.isConnected()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double shrink = 0.5 * (renderSettings.m_shrinkX + renderSettings.m_shrinkY);
Shinya Kitaoka 120a6e
  // Note: shrink is obsolete. It should be always = 1
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double blurValue = fabs(m_value->getValue(frame) *
Shinya Kitaoka 120a6e
                          sqrt(fabs(renderSettings.m_affine.det())) / shrink);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (blurValue == 0) {
Shinya Kitaoka 120a6e
    // No blur will be done. The underlying fx may pass by.
Shinya Kitaoka 120a6e
    m_input->compute(tile, frame, renderSettings);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int brad = tceil(blurValue);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Get the requested tile's geometry
Shinya Kitaoka 120a6e
  TRectD rectIn, rectOut;
Shinya Kitaoka 120a6e
  rectOut = TRectD(tile.m_pos, TDimensionD(tile.getRaster()->getLx(),
Shinya Kitaoka 120a6e
                                           tile.getRaster()->getLy()));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Retrieve the input interesting geometry - and ensure that something
Shinya Kitaoka 120a6e
  // actually has
Shinya Kitaoka 120a6e
  // to be computed
Shinya Kitaoka 120a6e
  if (!m_input->getBBox(frame, rectIn, renderSettings) || rectOut.isEmpty())
Shinya Kitaoka 120a6e
    return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  enlarge(rectIn, rectOut, brad);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (rectOut.isEmpty()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Finally, allocate and compute the blur argument
Shinya Kitaoka 120a6e
  TTile tileIn;
Shinya Kitaoka 120a6e
  m_input->allocateAndCompute(tileIn, rectOut.getP00(),
Shinya Kitaoka 120a6e
                              TDimension(rectOut.getLx(), rectOut.getLy()),
Shinya Kitaoka 120a6e
                              tile.getRaster(), frame, renderSettings);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD displacement(rectOut.getP00() - tile.m_pos);
Shinya Kitaoka 120a6e
  TRop::blur(tile.getRaster(), tileIn.getRaster(), blurValue, displacement.x,
Shinya Kitaoka 120a6e
             displacement.y, false);
Toshihiro Shimizu 890ddd
}