Toshihiro Shimizu 890ddd
#include "tenv.h"
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "ino_common.h"
shun-iwasawa e00258
#include "tfxparam.h"
shun-iwasawa e00258
shun-iwasawa e00258
#include <sstream> /* std::ostringstream */</sstream>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/* copy and paste from
Toshihiro Shimizu 890ddd
 igs_ifx_common.h */
Shinya Kitaoka 120a6e
namespace igs {
Shinya Kitaoka 120a6e
namespace image {
Shinya Kitaoka 120a6e
namespace rgba {
Shinya Kitaoka 120a6e
enum num { blu = 0, gre, red, alp, siz };
Toshihiro Shimizu 890ddd
}
shun-iwasawa e00258
}  // namespace image
shun-iwasawa e00258
}  // namespace igs
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
// T is TPixel32 or TPixel64
Toshihiro Shimizu 890ddd
// U is unsigned char or unsigned short
Toshihiro Shimizu 890ddd
template <class class="" t,="" u=""></class>
shun-iwasawa e00258
void ras_to_arr_(const TRasterPT<t> ras, U* arr, const int channels) {</t>
Shinya Kitaoka 120a6e
  using namespace igs::image::rgba;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int yy = 0; yy < ras->getLy(); ++yy) {
shun-iwasawa e00258
    const T* ras_sl = ras->pixels(yy);
Shinya Kitaoka 120a6e
    for (int xx = 0; xx < ras->getLx(); ++xx, arr += channels) {
Shinya Kitaoka 120a6e
      if (red < channels) {
Shinya Kitaoka 120a6e
        arr[red] = ras_sl[xx].r;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (gre < channels) {
Shinya Kitaoka 120a6e
        arr[gre] = ras_sl[xx].g;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (blu < channels) {
Shinya Kitaoka 120a6e
        arr[blu] = ras_sl[xx].b;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (alp < channels) {
Shinya Kitaoka 120a6e
        arr[alp] = ras_sl[xx].m;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
template <class class="" t="" u,=""></class>
shun-iwasawa e00258
void arr_to_ras_(const U* arr, const int channels, TRasterPT<t> ras,</t>
Shinya Kitaoka 120a6e
                 const int margin  // default is 0
shun-iwasawa e00258
) {
Shinya Kitaoka 120a6e
  arr +=
Shinya Kitaoka 120a6e
      (ras->getLx() + margin + margin) * margin * channels + margin * channels;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  using namespace igs::image::rgba;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int yy = 0; yy < ras->getLy();
Shinya Kitaoka 120a6e
       ++yy, arr += (ras->getLx() + margin + margin) * channels) {
shun-iwasawa e00258
    const U* arrx = arr;
shun-iwasawa e00258
    T* ras_sl     = ras->pixels(yy);
Shinya Kitaoka 120a6e
    for (int xx = 0; xx < ras->getLx(); ++xx, arrx += channels) {
Shinya Kitaoka 120a6e
      if (red < channels) {
Shinya Kitaoka 120a6e
        ras_sl[xx].r = arrx[red];
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (gre < channels) {
Shinya Kitaoka 120a6e
        ras_sl[xx].g = arrx[gre];
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (blu < channels) {
Shinya Kitaoka 120a6e
        ras_sl[xx].b = arrx[blu];
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (alp < channels) {
Shinya Kitaoka 120a6e
        ras_sl[xx].m = arrx[alp];
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
shun-iwasawa e00258
}  // namespace
Toshihiro Shimizu 890ddd
//--------------------
Shinya Kitaoka 120a6e
void ino::ras_to_arr(const TRasterP in_ras, const int channels,
shun-iwasawa e00258
                     unsigned char* out_arr) {
Shinya Kitaoka 120a6e
  if ((TRaster32P)in_ras) {
Shinya Kitaoka 120a6e
    ras_to_arr_<tpixel32, char="" unsigned="">(in_ras, out_arr, channels);</tpixel32,>
Shinya Kitaoka 120a6e
  } else if ((TRaster64P)in_ras) {
Shinya Kitaoka 120a6e
    ras_to_arr_<tpixel64, short="" unsigned="">(</tpixel64,>
shun-iwasawa e00258
        in_ras, reinterpret_cast<unsigned short*="">(out_arr), channels);</unsigned>
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
shun-iwasawa e00258
void ino::arr_to_ras(const unsigned char* in_arr, const int channels,
Shinya Kitaoka 120a6e
                     TRasterP out_ras, const int margin) {
Shinya Kitaoka 120a6e
  if ((TRaster32P)out_ras) {
Shinya Kitaoka 120a6e
    arr_to_ras_<unsigned char,="" tpixel32="">(in_arr, channels, out_ras, margin);</unsigned>
Shinya Kitaoka 120a6e
  } else if ((TRaster64P)out_ras) {
Shinya Kitaoka 120a6e
    arr_to_ras_<unsigned short,="" tpixel64="">(</unsigned>
shun-iwasawa e00258
        reinterpret_cast<const short*="" unsigned="">(in_arr), channels, out_ras,</const>
Shinya Kitaoka 120a6e
        margin);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//--------------------
Shinya Kitaoka 120a6e
void ino::ras_to_vec(const TRasterP in_ras, const int channels,
shun-iwasawa e00258
                     std::vector<unsigned char="">& out_vec) {</unsigned>
Shinya Kitaoka 120a6e
  out_vec.resize(
Shinya Kitaoka 120a6e
      in_ras->getLy() * in_ras->getLx() * channels *
Shinya Kitaoka 120a6e
      (((TRaster64P)in_ras) ? sizeof(unsigned short) : sizeof(unsigned char)));
Shinya Kitaoka 120a6e
  ino::ras_to_arr(in_ras, channels, &out_vec.at(0));
Toshihiro Shimizu 890ddd
}
shun-iwasawa e00258
void ino::vec_to_ras(std::vector<unsigned char="">& in_vec, const int channels,</unsigned>
Shinya Kitaoka 120a6e
                     TRasterP out_ras, const int margin  // default is 0
shun-iwasawa e00258
) {
Shinya Kitaoka 120a6e
  ino::arr_to_ras(&in_vec.at(0), channels, out_ras, margin);
Shinya Kitaoka 120a6e
  in_vec.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//--------------------
Shinya Kitaoka 120a6e
#if 0   //---
Toshihiro Shimizu 890ddd
void ino::Lx_to_wrap( TRasterP ras ) {
Toshihiro Shimizu 890ddd
	/*
Toshihiro Shimizu 890ddd
	ras->getLx()   : 描画の幅
Toshihiro Shimizu 890ddd
	ras->getWrap() : データの存在幅
Toshihiro Shimizu 890ddd
	描画幅よりデータの存在幅の方が大きい場合、
Toshihiro Shimizu 890ddd
	存在幅位置に置き直し、残りをゼロクリア
Toshihiro Shimizu 890ddd
	*/
Toshihiro Shimizu 890ddd
	if ( ras->getWrap() <= ras->getLx() ) { return; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const int rowSize  = ras->getLx()   * ras->getPixelSize();
Toshihiro Shimizu 890ddd
	const int wrapSize = ras->getWrap() * ras->getPixelSize();
Toshihiro Shimizu 890ddd
	const int restSize = wrapSize - rowSize;
Toshihiro Shimizu 890ddd
	const UCHAR *rowImg  = ras->getRawData()+rowSize *(ras->getLy()-1);
Toshihiro Shimizu 890ddd
	      UCHAR *wrapImg = ras->getRawData()+wrapSize*(ras->getLy()-1);
Toshihiro Shimizu 890ddd
	for (int yy = 0; yy < ras->getLy(); ++yy) {
Toshihiro Shimizu 890ddd
		::memcpy(wrapImg, rowImg, rowSize);
Toshihiro Shimizu 890ddd
		::memset(wrapImg+rowSize, 0, restSize); /* 上下にはみ出すとここで落ちる */
Toshihiro Shimizu 890ddd
		rowImg  -= rowSize;
Toshihiro Shimizu 890ddd
		wrapImg -= wrapSize;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Shinya Kitaoka 120a6e
#endif  //---
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
bool enable_sw_ = true;
Shinya Kitaoka 120a6e
bool check_sw_  = true;
shun-iwasawa e00258
}  // namespace
Shinya Kitaoka 120a6e
bool ino::log_enable_sw(void) {
Shinya Kitaoka 120a6e
  if (check_sw_) {
Shinya Kitaoka 120a6e
    TFileStatus file(
Shinya Kitaoka 120a6e
        // ToonzFolder::getProfileFolder()
Shinya Kitaoka 120a6e
        TEnv::getConfigDir() + "fx_ino_no_log.setup");
Shinya Kitaoka 120a6e
    if (file.doesExist()) {
Shinya Kitaoka 120a6e
      enable_sw_ = false;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    check_sw_ = false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return enable_sw_;
Toshihiro Shimizu 890ddd
}
shun-iwasawa e00258
shun-iwasawa e00258
//------------------------------------------------------------
shun-iwasawa e00258
namespace {
shun-iwasawa e00258
/* より大きな四角エリアにPixel整数値で密着する */
shun-iwasawa e00258
void makeRectCoherent(TRectD& rect, const TPointD& pos) {
shun-iwasawa e00258
  rect -= pos;
shun-iwasawa e00258
  rect.x0 = tfloor(rect.x0); /* ((x)<(int)(x)? (int)(x)-1: (int)(x))*/
shun-iwasawa e00258
  rect.y0 = tfloor(rect.y0);
shun-iwasawa e00258
  rect.x1 = tceil(rect.x1); /* ((int)(x)<(x)? (int)(x)+1: (int)(x))*/
shun-iwasawa e00258
  rect.y1 = tceil(rect.y1);
shun-iwasawa e00258
  rect += pos;
shun-iwasawa e00258
}
shun-iwasawa e00258
shun-iwasawa e00258
inline void to_xyz(double* xyz, double const* bgr) {
shun-iwasawa e00258
  xyz[0] = 0.6069 * bgr[2] + 0.1735 * bgr[1] + 0.2003 * bgr[0];  // X
shun-iwasawa e00258
  xyz[1] = 0.2989 * bgr[2] + 0.5866 * bgr[1] + 0.1145 * bgr[0];  // Y
shun-iwasawa e00258
  xyz[2] = 0.0000 * bgr[2] + 0.0661 * bgr[1] + 1.1162 * bgr[0];  // Z
shun-iwasawa e00258
}
shun-iwasawa e00258
shun-iwasawa e00258
inline void to_bgr(double* bgr, double const* xyz) {
shun-iwasawa e00258
  bgr[0] = +0.0585 * xyz[0] - 0.1187 * xyz[1] + 0.9017 * xyz[2];  // blue
shun-iwasawa e00258
  bgr[1] = -0.9844 * xyz[0] + 1.9985 * xyz[1] - 0.0279 * xyz[2];  // green
shun-iwasawa e00258
  bgr[2] = +1.9104 * xyz[0] - 0.5338 * xyz[1] - 0.2891 * xyz[2];  // red
shun-iwasawa e00258
}
shun-iwasawa e00258
shun-iwasawa e00258
// convert sRGB color space to power space
shun-iwasawa e00258
template <typename t="double"></typename>
shun-iwasawa e00258
inline T to_linear_color_space(T nonlinear_color, T exposure, T gamma) {
shun-iwasawa e00258
  // return -std::log(T(1) - std::pow(nonlinear_color, gamma)) / exposure;
shun-iwasawa e00258
  return std::pow(nonlinear_color, gamma) / exposure;
shun-iwasawa e00258
}
shun-iwasawa e00258
// convert power space to sRGB color space
shun-iwasawa e00258
template <typename t="double"></typename>
shun-iwasawa e00258
inline T to_nonlinear_color_space(T linear_color, T exposure, T gamma) {
shun-iwasawa e00258
  // return std::pow(T(1) - std::exp(-exposure * linear_color), T(1) / gamma);
shun-iwasawa e00258
  return std::pow(linear_color * exposure, T(1) / gamma);
shun-iwasawa e00258
}
shun-iwasawa e00258
shun-iwasawa e00258
template <class t="double"></class>
shun-iwasawa e00258
const T& clamp(const T& v, const T& lo, const T& hi) {
shun-iwasawa e00258
  assert(!(hi < lo));
shun-iwasawa e00258
  return (v < lo) ? lo : (hi < v) ? hi : v;
shun-iwasawa e00258
}
shun-iwasawa e00258
}  // namespace
shun-iwasawa e00258
//------------------------------------------------------------
shun-iwasawa e00258
shun-iwasawa e00258
TBlendForeBackRasterFx::TBlendForeBackRasterFx(bool clipping_mask,
shun-iwasawa e00258
                                               bool has_alpha_option)
shun-iwasawa e00258
    : m_opacity(1.0 * ino::param_range())
shun-iwasawa e00258
    , m_clipping_mask(clipping_mask)
shun-iwasawa e00258
    , m_linear(false)
shun-iwasawa e00258
    , m_gamma(2.2)
shun-iwasawa e00258
    , m_premultiplied(true) {
shun-iwasawa e00258
  addInputPort("Fore", this->m_up);
shun-iwasawa e00258
  addInputPort("Back", this->m_down);
shun-iwasawa e00258
  bindParam(this, "opacity", this->m_opacity);
shun-iwasawa e00258
  bindParam(this, "clipping_mask", this->m_clipping_mask);
shun-iwasawa e00258
  bindParam(this, "linear", this->m_linear);
shun-iwasawa e00258
  bindParam(this, "gamma", this->m_gamma);
shun-iwasawa e00258
  bindParam(this, "premultiplied", this->m_premultiplied);
shun-iwasawa e00258
  this->m_opacity->setValueRange(0, 1.0 * ino::param_range());
shun-iwasawa e00258
  this->m_gamma->setValueRange(0.2, 5.0);
shun-iwasawa e00258
shun-iwasawa e00258
  if (has_alpha_option) {
shun-iwasawa e00258
    m_alpha_rendering = TBoolParamP(true);
shun-iwasawa e00258
    bindParam(this, "alpha_rendering", this->m_alpha_rendering);
shun-iwasawa e00258
  }
shun-iwasawa e00258
}
shun-iwasawa e00258
//------------------------------------------------------------
shun-iwasawa e00258
shun-iwasawa e00258
bool TBlendForeBackRasterFx::doGetBBox(double frame, TRectD& bBox,
shun-iwasawa e00258
                                       const TRenderSettings& rs) {
shun-iwasawa e00258
  TRectD up_bx;
shun-iwasawa e00258
  const bool up_sw =
shun-iwasawa e00258
      (m_up.isConnected() ? m_up->doGetBBox(frame, up_bx, rs) : false);
shun-iwasawa e00258
  TRectD dn_bx;
shun-iwasawa e00258
  const bool dn_sw =
shun-iwasawa e00258
      (m_down.isConnected() ? m_down->doGetBBox(frame, dn_bx, rs) : false);
shun-iwasawa e00258
  if (up_sw && dn_sw) {
shun-iwasawa e00258
    bBox = up_bx + dn_bx;
shun-iwasawa e00258
    return !bBox.isEmpty();
shun-iwasawa e00258
  } else if (up_sw) {
shun-iwasawa e00258
    bBox = up_bx;
shun-iwasawa e00258
    return true;
shun-iwasawa e00258
  } else if (dn_sw) {
shun-iwasawa e00258
    bBox = dn_bx;
shun-iwasawa e00258
    return true;
shun-iwasawa e00258
  } else {
shun-iwasawa e00258
    bBox = TRectD();
shun-iwasawa e00258
    return false;
shun-iwasawa e00258
  }
shun-iwasawa e00258
}
shun-iwasawa e00258
//------------------------------------------------------------
shun-iwasawa e00258
shun-iwasawa e00258
void TBlendForeBackRasterFx::dryComputeUpAndDown(TRectD& rect, double frame,
shun-iwasawa e00258
                                                 const TRenderSettings& rs,
shun-iwasawa e00258
                                                 bool upComputesWholeTile) {
shun-iwasawa e00258
  const bool up_is   = (this->m_up.isConnected() &&
shun-iwasawa e00258
                      this->m_up.getFx()->getTimeRegion().contains(frame));
shun-iwasawa e00258
  const bool down_is = (this->m_down.isConnected() &&
shun-iwasawa e00258
                        this->m_down.getFx()->getTimeRegion().contains(frame));
shun-iwasawa e00258
  /* ------ 両方とも切断の時処理しない ---------------------- */
shun-iwasawa e00258
  if (!up_is && !down_is) {
shun-iwasawa e00258
    return;
shun-iwasawa e00258
  }
shun-iwasawa e00258
  /* ------ up接続かつdown切断の時 -------------------------- */
shun-iwasawa e00258
  if (up_is && !down_is) {
shun-iwasawa e00258
    this->m_up->dryCompute(rect, frame, rs);
shun-iwasawa e00258
    return;
shun-iwasawa e00258
  }
shun-iwasawa e00258
  /* ------ down接続時 -------------------------------------- */
shun-iwasawa e00258
  if (down_is) {
shun-iwasawa e00258
    this->m_down->dryCompute(rect, frame, rs);
shun-iwasawa e00258
  }
shun-iwasawa e00258
  /* ------ up切断時 ---------------------------------------- */
shun-iwasawa e00258
  if (!up_is) {
shun-iwasawa e00258
    return;
shun-iwasawa e00258
  }
shun-iwasawa e00258
shun-iwasawa e00258
  /* ------ tileのgeometryを計算する ------------------------ */
shun-iwasawa e00258
  TRectD upBBox;
shun-iwasawa e00258
shun-iwasawa e00258
  if (upComputesWholeTile) {
shun-iwasawa e00258
    upBBox = rect;
shun-iwasawa e00258
  } else {
shun-iwasawa e00258
    this->m_up->getBBox(frame, upBBox, rs);
shun-iwasawa e00258
    upBBox *= rect;
shun-iwasawa e00258
    makeRectCoherent(upBBox, rect.getP00());
shun-iwasawa e00258
  }
shun-iwasawa e00258
  if ((upBBox.getLx() > 0.5) && (upBBox.getLy() > 0.5)) {
shun-iwasawa e00258
    this->m_up->dryCompute(upBBox, frame, rs);
shun-iwasawa e00258
  }
shun-iwasawa e00258
}
shun-iwasawa e00258
shun-iwasawa e00258
//------------------------------------------------------------
shun-iwasawa e00258
void TBlendForeBackRasterFx::doCompute(TTile& tile, double frame,
shun-iwasawa e00258
                                       const TRenderSettings& rs) {
shun-iwasawa e00258
  /* ------ 画像生成 ---------------------------------------- */
shun-iwasawa e00258
  TRasterP dn_ras, up_ras;
shun-iwasawa e00258
  this->computeUpAndDown(tile, frame, rs, dn_ras, up_ras);
shun-iwasawa a834fd
  if (!up_ras) {
shun-iwasawa e00258
    return;
shun-iwasawa e00258
  }
shun-iwasawa a834fd
  // blend on the empty raster if the back port is not active
shun-iwasawa a834fd
  if (!dn_ras) {
shun-iwasawa a834fd
    dn_ras = tile.getRaster();
shun-iwasawa a834fd
  }
shun-iwasawa e00258
  /* ------ 動作パラメータを得る ---------------------------- */
shun-iwasawa e00258
  const double up_opacity =
shun-iwasawa e00258
      this->m_opacity->getValue(frame) / ino::param_range();
shun-iwasawa e00258
  const double gamma = this->m_gamma->getValue(frame);
shun-iwasawa e00258
  /* ------ (app_begin)log記憶 ------------------------------ */
shun-iwasawa e00258
  const bool log_sw = ino::log_enable_sw();
shun-iwasawa e00258
shun-iwasawa e00258
  if (log_sw) {
shun-iwasawa e00258
    std::ostringstream os;
shun-iwasawa e00258
    os << "params"
shun-iwasawa e00258
       << "  up_opacity " << up_opacity << "   dn_tile w " << dn_ras->getLx()
shun-iwasawa e00258
       << "  wrap " << dn_ras->getWrap() << "  h " << dn_ras->getLy()
shun-iwasawa e00258
       << "  pixbits " << ino::pixel_bits(dn_ras) << "   up_tile w "
shun-iwasawa e00258
       << up_ras->getLx() << "  wrap " << up_ras->getWrap() << "  h "
shun-iwasawa e00258
       << up_ras->getLy() << "  pixbits " << ino::pixel_bits(up_ras)
shun-iwasawa e00258
       << "   frame " << frame;
shun-iwasawa e00258
  }
shun-iwasawa e00258
  /* ------ fx処理 ------------------------------------------ */
shun-iwasawa e00258
  try {
shun-iwasawa e00258
    if (dn_ras) {
shun-iwasawa e00258
      dn_ras->lock();
shun-iwasawa e00258
    }
shun-iwasawa e00258
    if (up_ras) {
shun-iwasawa e00258
      up_ras->lock();
shun-iwasawa e00258
    }
shun-iwasawa e00258
    doComputeFx(dn_ras, up_ras, TPoint(), up_opacity, gamma);
shun-iwasawa e00258
    // fx_(dn_ras, up_ras, TPoint(), up_opacity,
shun-iwasawa e00258
    // this->m_clipping_mask->getValue(),
shun-iwasawa e00258
    //  this->m_linear->getValue(), gamma, this->m_premultiplied->getValue());
shun-iwasawa e00258
    if (up_ras) {
shun-iwasawa e00258
      up_ras->unlock();
shun-iwasawa e00258
    }
shun-iwasawa e00258
    if (dn_ras) {
shun-iwasawa e00258
      dn_ras->unlock();
shun-iwasawa e00258
    }
shun-iwasawa e00258
  }
shun-iwasawa e00258
  /* ------ error処理 --------------------------------------- */
shun-iwasawa e00258
  catch (std::exception& e) {
shun-iwasawa e00258
    if (up_ras) {
shun-iwasawa e00258
      up_ras->unlock();
shun-iwasawa e00258
    }
shun-iwasawa e00258
    if (dn_ras) {
shun-iwasawa e00258
      dn_ras->unlock();
shun-iwasawa e00258
    }
shun-iwasawa e00258
    if (log_sw) {
shun-iwasawa e00258
      std::string str("exception <");
shun-iwasawa e00258
      str += e.what();
shun-iwasawa e00258
      str += '>';
shun-iwasawa e00258
    }
shun-iwasawa e00258
    throw;
shun-iwasawa e00258
  } catch (...) {
shun-iwasawa e00258
    if (up_ras) {
shun-iwasawa e00258
      up_ras->unlock();
shun-iwasawa e00258
    }
shun-iwasawa e00258
    if (dn_ras) {
shun-iwasawa e00258
      dn_ras->unlock();
shun-iwasawa e00258
    }
shun-iwasawa e00258
    if (log_sw) {
shun-iwasawa e00258
      std::string str("other exception");
shun-iwasawa e00258
    }
shun-iwasawa e00258
    throw;
shun-iwasawa e00258
  }
shun-iwasawa e00258
}
shun-iwasawa e00258
shun-iwasawa e00258
//------------------------------------------------------------
shun-iwasawa e00258
void TBlendForeBackRasterFx::doComputeFx(TRasterP& dn_ras_out,
shun-iwasawa e00258
                                         const TRasterP& up_ras,
shun-iwasawa e00258
                                         const TPoint& pos,
shun-iwasawa e00258
                                         const double up_opacity,
shun-iwasawa e00258
                                         const double gamma) {
shun-iwasawa e00258
  /* 交差したエリアを処理するようにする、いるのか??? */
shun-iwasawa e00258
  TRect outRect(dn_ras_out->getBounds());
shun-iwasawa e00258
  TRect upRect(up_ras->getBounds() + pos);
shun-iwasawa e00258
  TRect intersection = outRect * upRect;
shun-iwasawa e00258
  if (intersection.isEmpty()) return;
shun-iwasawa e00258
shun-iwasawa e00258
  TRasterP cRout = dn_ras_out->extract(intersection);
shun-iwasawa e00258
  TRect rr       = intersection - pos;
shun-iwasawa e00258
  TRasterP cRup  = up_ras->extract(rr);
shun-iwasawa e00258
shun-iwasawa e00258
  TRaster32P rout32 = cRout, rup32 = cRup;
shun-iwasawa e00258
  TRaster64P rout64 = cRout, rup64 = cRup;
shun-iwasawa e00258
shun-iwasawa e00258
  bool linear_sw = this->m_linear->getValue();
shun-iwasawa e00258
shun-iwasawa e00258
  if (rout32 && rup32) {
shun-iwasawa e00258
    if (linear_sw)
shun-iwasawa e00258
      linearTmpl<tpixel32, uchar="">(rout32, rup32, up_opacity, gamma);</tpixel32,>
shun-iwasawa e00258
    // linearAdd<tpixel32, uchar="">(rout32, rup32, up_opacity, clipping_mask_sw,</tpixel32,>
shun-iwasawa e00258
    //  gamma, premultiplied_sw);
shun-iwasawa e00258
    else
shun-iwasawa e00258
      nonlinearTmpl<tpixel32, uchar="">(rout32, rup32, up_opacity);</tpixel32,>
shun-iwasawa e00258
    // tmpl_<tpixel32, uchar="">(rout32, rup32, up_opacity, clipping_mask_sw);</tpixel32,>
shun-iwasawa e00258
  } else if (rout64 && rup64) {
shun-iwasawa e00258
    if (linear_sw)
shun-iwasawa e00258
      linearTmpl<tpixel64, ushort="">(rout64, rup64, up_opacity, gamma);</tpixel64,>
shun-iwasawa e00258
    else
shun-iwasawa e00258
      nonlinearTmpl<tpixel64, ushort="">(rout64, rup64, up_opacity);</tpixel64,>
shun-iwasawa e00258
  } else {
shun-iwasawa e00258
    throw TRopException("unsupported pixel type");
shun-iwasawa e00258
  }
shun-iwasawa e00258
}
shun-iwasawa e00258
shun-iwasawa e00258
//------------------------------------------------------------
shun-iwasawa e00258
template <class class="" q="" t,=""></class>
shun-iwasawa e00258
void TBlendForeBackRasterFx::nonlinearTmpl(TRasterPT<t> dn_ras_out,</t>
shun-iwasawa e00258
                                           const TRasterPT<t>& up_ras,</t>
shun-iwasawa e00258
                                           const double up_opacity) {
shun-iwasawa e00258
  bool clipping_mask_sw   = this->m_clipping_mask->getValue();
shun-iwasawa e00258
  bool alpha_rendering_sw = (m_alpha_rendering.getPointer())
shun-iwasawa e00258
                                ? this->m_alpha_rendering->getValue()
shun-iwasawa e00258
                                : true;
shun-iwasawa e00258
shun-iwasawa e00258
  double maxi = static_cast<double>(T::maxChannelValue);  // 255or65535</double>
shun-iwasawa e00258
shun-iwasawa e00258
  assert(dn_ras_out->getSize() == up_ras->getSize());
shun-iwasawa e00258
shun-iwasawa e00258
  for (int yy = 0; yy < dn_ras_out->getLy(); ++yy) {
shun-iwasawa e00258
    T* out_pix             = dn_ras_out->pixels(yy);
shun-iwasawa e00258
    const T* const out_end = out_pix + dn_ras_out->getLx();
shun-iwasawa e00258
    const T* up_pix        = up_ras->pixels(yy);
shun-iwasawa e00258
    for (; out_pix < out_end; ++out_pix, ++up_pix) {
shun-iwasawa e00258
      double upr = static_cast<double>(up_pix->r) / maxi;</double>
shun-iwasawa e00258
      double upg = static_cast<double>(up_pix->g) / maxi;</double>
shun-iwasawa e00258
      double upb = static_cast<double>(up_pix->b) / maxi;</double>
shun-iwasawa e00258
      double upa = static_cast<double>(up_pix->m) / maxi;</double>
shun-iwasawa e00258
      double dnr = static_cast<double>(out_pix->r) / maxi;</double>
shun-iwasawa e00258
      double dng = static_cast<double>(out_pix->g) / maxi;</double>
shun-iwasawa e00258
      double dnb = static_cast<double>(out_pix->b) / maxi;</double>
shun-iwasawa e00258
      double dna = static_cast<double>(out_pix->m) / maxi;</double>
shun-iwasawa e00258
      brendKernel(dnr, dng, dnb, dna, upr, upg, upb, upa,
shun-iwasawa e00258
                  clipping_mask_sw ? up_opacity * dna : up_opacity,
shun-iwasawa e00258
                  alpha_rendering_sw);
shun-iwasawa e00258
      out_pix->r = static_cast<q>(dnr * (maxi + 0.999999));</q>
shun-iwasawa e00258
      out_pix->g = static_cast<q>(dng * (maxi + 0.999999));</q>
shun-iwasawa e00258
      out_pix->b = static_cast<q>(dnb * (maxi + 0.999999));</q>
shun-iwasawa e00258
      out_pix->m = static_cast<q>(dna * (maxi + 0.999999));</q>
shun-iwasawa e00258
    }
shun-iwasawa e00258
  }
shun-iwasawa e00258
}
shun-iwasawa e00258
shun-iwasawa e00258
//------------------------------------------------------------
shun-iwasawa e00258
template <class class="" q="" t,=""></class>
shun-iwasawa e00258
void TBlendForeBackRasterFx::linearTmpl(TRasterPT<t> dn_ras_out,</t>
shun-iwasawa e00258
                                        const TRasterPT<t>& up_ras,</t>
shun-iwasawa e00258
                                        const double up_opacity,
shun-iwasawa e00258
                                        const double gamma) {
shun-iwasawa e00258
  bool clipping_mask_sw   = this->m_clipping_mask->getValue();
shun-iwasawa e00258
  bool alpha_rendering_sw = (m_alpha_rendering.getPointer())
shun-iwasawa e00258
                                ? this->m_alpha_rendering->getValue()
shun-iwasawa e00258
                                : true;
shun-iwasawa e00258
  bool premultiplied_sw = this->m_premultiplied->getValue();
shun-iwasawa e00258
  double maxi  = static_cast<double>(T::maxChannelValue);  // 255or65535</double>
shun-iwasawa e00258
  double limit = (maxi + 0.5) / (maxi + 1.0);
shun-iwasawa e00258
shun-iwasawa e00258
  assert(dn_ras_out->getSize() == up_ras->getSize());
shun-iwasawa e00258
shun-iwasawa e00258
  for (int yy = 0; yy < dn_ras_out->getLy(); ++yy) {
shun-iwasawa e00258
    T* out_pix             = dn_ras_out->pixels(yy);
shun-iwasawa e00258
    const T* const out_end = out_pix + dn_ras_out->getLx();
shun-iwasawa e00258
    const T* up_pix        = up_ras->pixels(yy);
shun-iwasawa e00258
    for (; out_pix < out_end; ++out_pix, ++up_pix) {
shun-iwasawa e00258
      if (up_pix->m <= 0 || up_opacity <= 0) {
shun-iwasawa e00258
        continue;
shun-iwasawa e00258
      }
shun-iwasawa e00258
shun-iwasawa e00258
      double dna         = static_cast<double>(out_pix->m) / maxi;</double>
shun-iwasawa e00258
      double tmp_opacity = clipping_mask_sw ? up_opacity * dna : up_opacity;
shun-iwasawa e00258
      if (tmp_opacity <= 0) continue;
shun-iwasawa e00258
shun-iwasawa e00258
      double dnBGR[3];
shun-iwasawa e00258
      dnBGR[0]        = static_cast<double>(out_pix->b) / maxi;</double>
shun-iwasawa e00258
      dnBGR[1]        = static_cast<double>(out_pix->g) / maxi;</double>
shun-iwasawa e00258
      dnBGR[2]        = static_cast<double>(out_pix->r) / maxi;</double>
shun-iwasawa e00258
      double dnXYZ[3] = {0.0, 0.0, 0.0};
shun-iwasawa e00258
      if (dna > 0.0) {
shun-iwasawa e00258
        for (int c = 0; c < 3; c++) {
shun-iwasawa e00258
          if (premultiplied_sw)
shun-iwasawa e00258
            dnBGR[c] = to_linear_color_space(dnBGR[c] / dna, 1.0, gamma) * dna;
shun-iwasawa e00258
          else
shun-iwasawa e00258
            dnBGR[c] = to_linear_color_space(dnBGR[c], 1.0, gamma);
shun-iwasawa e00258
        }
shun-iwasawa e00258
        to_xyz(dnXYZ, dnBGR);
shun-iwasawa e00258
      }
shun-iwasawa e00258
shun-iwasawa e00258
      double upBGR[3];
shun-iwasawa e00258
      upBGR[0]   = static_cast<double>(up_pix->b) / maxi;</double>
shun-iwasawa e00258
      upBGR[1]   = static_cast<double>(up_pix->g) / maxi;</double>
shun-iwasawa e00258
      upBGR[2]   = static_cast<double>(up_pix->r) / maxi;</double>
shun-iwasawa e00258
      double upa = static_cast<double>(up_pix->m) / maxi;</double>
shun-iwasawa e00258
      for (int c = 0; c < 3; c++) {
shun-iwasawa e00258
        if (premultiplied_sw)
shun-iwasawa e00258
          upBGR[c] = to_linear_color_space(upBGR[c] / upa, 1.0, gamma) * upa;
shun-iwasawa e00258
        else
shun-iwasawa e00258
          upBGR[c] = to_linear_color_space(upBGR[c], 1.0, gamma);
shun-iwasawa e00258
      }
shun-iwasawa e00258
shun-iwasawa e00258
      double upXYZ[3];
shun-iwasawa e00258
      to_xyz(upXYZ, upBGR);
shun-iwasawa e00258
shun-iwasawa e00258
      brendKernel(dnXYZ[0], dnXYZ[1], dnXYZ[2], dna, upXYZ[0], upXYZ[1],
shun-iwasawa 26a3ce
                  upXYZ[2], upa, tmp_opacity, alpha_rendering_sw, true);
shun-iwasawa e00258
shun-iwasawa e00258
      to_bgr(dnBGR, dnXYZ);
shun-iwasawa e00258
shun-iwasawa e00258
      // premultiply the result
shun-iwasawa e00258
      double nonlinear_b =
shun-iwasawa e00258
          to_nonlinear_color_space(dnBGR[0] / dna, 1.0, gamma) * dna;
shun-iwasawa e00258
      double nonlinear_g =
shun-iwasawa e00258
          to_nonlinear_color_space(dnBGR[1] / dna, 1.0, gamma) * dna;
shun-iwasawa e00258
      double nonlinear_r =
shun-iwasawa e00258
          to_nonlinear_color_space(dnBGR[2] / dna, 1.0, gamma) * dna;
shun-iwasawa e00258
shun-iwasawa e00258
      out_pix->r =
shun-iwasawa e00258
          static_cast<q>(clamp(nonlinear_r, 0.0, 1.0) * (maxi + 0.999999));</q>
shun-iwasawa e00258
      out_pix->g =
shun-iwasawa e00258
          static_cast<q>(clamp(nonlinear_g, 0.0, 1.0) * (maxi + 0.999999));</q>
shun-iwasawa e00258
      out_pix->b =
shun-iwasawa e00258
          static_cast<q>(clamp(nonlinear_b, 0.0, 1.0) * (maxi + 0.999999));</q>
shun-iwasawa e00258
      out_pix->m = static_cast<q>(dna * (maxi + 0.999999));</q>
shun-iwasawa e00258
    }
shun-iwasawa e00258
  }
shun-iwasawa e00258
}
shun-iwasawa e00258
shun-iwasawa e00258
//------------------------------------------------------------
shun-iwasawa e00258
shun-iwasawa e00258
void TBlendForeBackRasterFx::computeUpAndDown(TTile& tile, double frame,
shun-iwasawa e00258
                                              const TRenderSettings& rs,
shun-iwasawa e00258
                                              TRasterP& dn_ras,
shun-iwasawa e00258
                                              TRasterP& up_ras,
shun-iwasawa e00258
                                              bool upComputesWholeTile) {
shun-iwasawa e00258
  /* ------ サポートしていないPixelタイプはエラーを投げる --- */
shun-iwasawa e00258
  if (!((TRaster32P)tile.getRaster()) && !((TRaster64P)tile.getRaster())) {
shun-iwasawa e00258
    throw TRopException("unsupported input pixel type");
shun-iwasawa e00258
  }
shun-iwasawa e00258
  /*
shun-iwasawa e00258
m_down,m_upは繋がっている方があればそれを表示する
shun-iwasawa e00258
両方とも接続していれば合成処理する
shun-iwasawa e00258
表示スイッチを切ってあるならm_upを表示する
shun-iwasawa e00258
fxをreplaceすると、
shun-iwasawa e00258
  m_source   --> m_up  (=port0)
luz paz 86a900
  m_reference --> m_down(=port1)
shun-iwasawa e00258
となる
shun-iwasawa e00258
*/
shun-iwasawa e00258
  const bool up_is   = (this->m_up.isConnected() &&
shun-iwasawa e00258
                      this->m_up.getFx()->getTimeRegion().contains(frame));
shun-iwasawa e00258
  const bool down_is = (this->m_down.isConnected() &&
shun-iwasawa e00258
                        this->m_down.getFx()->getTimeRegion().contains(frame));
shun-iwasawa e00258
  /* ------ 両方とも切断の時処理しない ---------------------- */
shun-iwasawa e00258
  if (!up_is && !down_is) {
shun-iwasawa e00258
    tile.getRaster()->clear();
shun-iwasawa e00258
    return;
shun-iwasawa e00258
  }
shun-iwasawa e00258
  /* ------ up接続かつdown切断の時 -------------------------- */
shun-iwasawa e00258
  if (up_is && !down_is) {
shun-iwasawa a834fd
    TTile upTile;
shun-iwasawa a834fd
    this->m_up->allocateAndCompute(upTile, tile.m_pos,
shun-iwasawa a834fd
                                   tile.getRaster()->getSize(),
shun-iwasawa a834fd
                                   tile.getRaster(), frame, rs);
shun-iwasawa a834fd
    up_ras = upTile.getRaster();
shun-iwasawa e00258
    return;
shun-iwasawa e00258
  }
shun-iwasawa e00258
  /* ------ down接続時 downのみ描画して... ------------------ */
shun-iwasawa e00258
  if (down_is) {
shun-iwasawa e00258
    this->m_down->compute(tile, frame, rs);
shun-iwasawa e00258
  }
shun-iwasawa e00258
  /* ------ up切断時 ---------------------------------------- */
shun-iwasawa e00258
  if (!up_is) {
shun-iwasawa e00258
    return;
shun-iwasawa e00258
  }
shun-iwasawa e00258
shun-iwasawa e00258
  /* upと重なる部分を描画する */
shun-iwasawa e00258
shun-iwasawa e00258
  /* ------ tileの範囲 -------------------------------------- */
shun-iwasawa e00258
  const TDimension tsz(tile.getRaster()->getSize()); /* 整数 */
shun-iwasawa e00258
  const TRectD tileRect(tile.m_pos, TDimensionD(tsz.lx, tsz.ly));
shun-iwasawa e00258
  TRectD upBBox;
shun-iwasawa e00258
  if (upComputesWholeTile) {
shun-iwasawa e00258
    upBBox = tileRect;
shun-iwasawa e00258
  }      /* tile全体を得る */
shun-iwasawa e00258
  else { /* 厳密なエリア... */
shun-iwasawa e00258
    this->m_up->getBBox(frame, upBBox, rs);
shun-iwasawa e00258
    upBBox *= tileRect; /* upとtileの交差エリア */
shun-iwasawa e00258
shun-iwasawa e00258
    /* より大きな四角エリアにPixel整数値で密着する */
shun-iwasawa e00258
    makeRectCoherent(upBBox, tile.m_pos);  // double-->int grid
shun-iwasawa e00258
  }
shun-iwasawa e00258
shun-iwasawa e00258
  TDimensionI upSize(                        /* TRectDをTDimensionIに変換 */
shun-iwasawa e00258
                     tround(upBBox.getLx())  // getLx() = "x1>=x0?x1-x0:0"
shun-iwasawa e00258
                     ,
shun-iwasawa e00258
                     tround(upBBox.getLy())  // getLy() = "y1>=y0?y1-y0:0"
shun-iwasawa e00258
  );
shun-iwasawa e00258
  if ((upSize.lx <= 0) || (upSize.ly <= 0)) {
shun-iwasawa e00258
    return;
shun-iwasawa e00258
  }
shun-iwasawa e00258
shun-iwasawa e00258
  /* ------ upのメモリ確保と描画 ---------------------------- */
shun-iwasawa e00258
  TTile upTile;
shun-iwasawa e00258
  this->m_up->allocateAndCompute(upTile, upBBox.getP00(), upSize,
shun-iwasawa e00258
                                 tile.getRaster() /* 32/64bitsの判定に使う */
shun-iwasawa e00258
                                 ,
shun-iwasawa e00258
                                 frame, rs);
shun-iwasawa e00258
  /* ------ upとdownのTRasterを得る ------------------------- */
shun-iwasawa e00258
  TRectI dnRect(upTile.getRaster()->getSize());  // TDimensionI(-)
shun-iwasawa e00258
shun-iwasawa e00258
  dnRect += convert(upTile.m_pos - tile.m_pos); /* uptile->tile原点 */
shun-iwasawa e00258
  /*
shun-iwasawa e00258
  ここで問題はdoubleの位置を、四捨五入して整数値にしていること
shun-iwasawa e00258
  移動してから四捨五入ではないの???
shun-iwasawa e00258
  dnRectの元位置が整数位置なので、問題ないか...
shun-iwasawa e00258
  */
shun-iwasawa e00258
shun-iwasawa e00258
  dn_ras = upComputesWholeTile ? tile.getRaster()
shun-iwasawa e00258
                               : tile.getRaster()->extract(dnRect);
shun-iwasawa e00258
  up_ras = upTile.getRaster();
shun-iwasawa e00258
  assert(dn_ras->getSize() == up_ras->getSize());
shun-iwasawa e00258
}