Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "warp.h"
Toshihiro Shimizu 890ddd
#include "toonz/tdistort.h"
Shinya Kitaoka 120a6e
#include "timage_io.h"  //For debug use only
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Local inlines
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename t=""></typename>
Toshihiro Shimizu 890ddd
inline double convert(const T &pixel);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <>
Shinya Kitaoka 120a6e
inline double convert<tpixel32>(const TPixel32 &pixel) {</tpixel32>
Shinya Kitaoka 120a6e
  return TPixelGR8::from(pixel).value;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <>
Shinya Kitaoka 120a6e
inline double convert<tpixel64>(const TPixel64 &pixel) {</tpixel64>
Shinya Kitaoka 120a6e
  return TPixelGR16::from(pixel).value;
Toshihiro Shimizu 890ddd
}
shun-iwasawa 481b59
shun-iwasawa 481b59
template <>
shun-iwasawa 481b59
inline double convert<tpixelf>(const TPixelF &pixel) {</tpixelf>
shun-iwasawa 481b59
  // clamp between 0 and 1
shun-iwasawa 481b59
  return std::min(1.f, std::max(0.f, TPixelGRF::from(pixel).value));
Toshihiro Shimizu 890ddd
}
shun-iwasawa 481b59
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*-----------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename t=""></typename>
Shinya Kitaoka d1f6c4
class Warper final : public TDistorter {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TRasterPT<t> m_rin;</t>
Shinya Kitaoka 120a6e
  TRasterPT<t> m_warper;</t>
Shinya Kitaoka 120a6e
  TRasterPT<t> m_rout;</t>
Shinya Kitaoka 120a6e
  TPointD m_rinPos;
Shinya Kitaoka 120a6e
  TPointD m_warperPos;
Shinya Kitaoka 120a6e
  TDimension m_oriDim;
Shinya Kitaoka 120a6e
  int m_shrink;
Shinya Kitaoka 120a6e
  double m_warperScale;
Shinya Kitaoka 120a6e
  double m_intensity;
Shinya Kitaoka 120a6e
  bool m_sharpen;
Shinya Kitaoka 120a6e
  Lattice m_lattice;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Warper(TPointD rinPos, TPointD warperPos, const TRasterPT<t> &rin,</t>
Shinya Kitaoka 120a6e
         const TRasterPT<t> &warper, TRasterPT<t> &rout,</t></t>
Shinya Kitaoka 120a6e
         const WarpParams ¶ms)
Shinya Kitaoka 120a6e
      : m_rinPos(rinPos)
Shinya Kitaoka 120a6e
      , m_warperPos(warperPos)
Shinya Kitaoka 120a6e
      , m_rin(rin)
Shinya Kitaoka 120a6e
      , m_warper(warper)
Shinya Kitaoka 120a6e
      , m_rout(rout)
Shinya Kitaoka 120a6e
      , m_intensity(1.5 * 1.5 * params.m_intensity / 100)
Shinya Kitaoka 120a6e
      , m_shrink(params.m_shrink)
Shinya Kitaoka 120a6e
      , m_warperScale(params.m_warperScale)
Shinya Kitaoka 120a6e
      , m_oriDim(rin->getSize())
Shinya Kitaoka 120a6e
      , m_sharpen(params.m_sharpen) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~Warper() {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void createLattice();
Shinya Kitaoka 120a6e
  void shepardWarp();
Shinya Kitaoka 473e70
  TPointD map(const TPointD &p) const override;
Shinya Kitaoka 473e70
  int invMap(const TPointD &p, TPointD *invs) const override;
Shinya Kitaoka 473e70
  int maxInvCount() const override { return 1; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---------------------------------------------------------------------------*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename t=""></typename>
Shinya Kitaoka 120a6e
void Warper<t>::createLattice() {</t>
Shinya Kitaoka 120a6e
  int ori_lx, ori_ly, i, j, lx, ly, incr;
Shinya Kitaoka 120a6e
  double fac;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ori_lx = m_shrink * (m_warper->getLx() - 1) + 1;
Shinya Kitaoka 120a6e
  ori_ly = m_shrink * (m_warper->getLy() - 1) + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  lx = m_lattice.m_width = ori_lx;
Shinya Kitaoka 120a6e
  ly = m_lattice.m_height = ori_ly;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterPT<t> aux = m_warper;</t>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_sharpen) TRop::blur(aux, aux, 6.0, 0, 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_lattice.coords = new LPoint[lx * ly];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  LPoint *coord = m_lattice.coords;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (j = 0; j < ly; ++j) {
Shinya Kitaoka 120a6e
    if (j >= ly - 1) j = ori_ly - 1;
Shinya Kitaoka 120a6e
    coord->s.y = (coord + lx - 1)->s.y = 0;
Shinya Kitaoka 120a6e
    coord->d.y = (coord + lx - 1)->d.y = j;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    (coord + lx - 1)->s.x = 0;
Shinya Kitaoka 120a6e
    (coord + lx - 1)->d.x = ori_lx - 1;
Shinya Kitaoka 120a6e
    coord += lx;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  coord = m_lattice.coords;
Shinya Kitaoka 120a6e
  incr  = (ly - 1) * lx;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < lx; ++i) {
Shinya Kitaoka 120a6e
    if (i >= (lx - 1)) i = ori_lx - 1;
Shinya Kitaoka 120a6e
    coord->s.x = (coord + incr)->s.x = 0;
Shinya Kitaoka 120a6e
    coord->d.x = (coord + incr)->d.x = i;
Shinya Kitaoka 120a6e
    (coord + incr)->s.y              = 0;
Shinya Kitaoka 120a6e
    (coord + incr)->d.y              = ori_ly - 1;
Shinya Kitaoka 120a6e
    coord++;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  fac = m_intensity * (TPixel32::maxChannelValue / (double)T::maxChannelValue);
Shinya Kitaoka 120a6e
  aux->lock();
Shinya Kitaoka 120a6e
  T *buffer = (T *)aux->getRawData();
Shinya Kitaoka 120a6e
  T *pixIn;
Shinya Kitaoka 120a6e
  int auxWrap = aux->getWrap();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (j = 1; j < ly - 1; j++) {
Shinya Kitaoka 120a6e
    pixIn = buffer + j * auxWrap;
Shinya Kitaoka 120a6e
    coord = &(m_lattice.coords[j * lx]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = 1; i < lx - 1; i++) {
Shinya Kitaoka 120a6e
      ++pixIn;
Shinya Kitaoka 120a6e
      ++coord;
Shinya Kitaoka 120a6e
      coord->d.x = i;
Shinya Kitaoka 120a6e
      coord->d.y = j;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // FOR A FUTURE RELEASE: We should not make the diffs below between +1 and
Shinya Kitaoka 120a6e
      // -1, BUT 0 and -1!!
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      coord->s.x = fac * (convert(*(pixIn + 1)) - convert(*(pixIn - 1)));
Shinya Kitaoka 120a6e
      coord->s.y =
Shinya Kitaoka 120a6e
          fac * (convert(*(pixIn + auxWrap)) - convert(*(pixIn - auxWrap)));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  aux->unlock();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Finally, we scale the lattice according to the m_scale parameter.
Shinya Kitaoka 120a6e
  coord  = m_lattice.coords;
Shinya Kitaoka 120a6e
  int wh = m_lattice.m_width * m_lattice.m_height;
Shinya Kitaoka 120a6e
  for (i = 0; i < wh; ++i, ++coord) {
Shinya Kitaoka 120a6e
    coord->d = m_warperPos + m_warperScale * coord->d;
Shinya Kitaoka 120a6e
    coord->s = m_warperScale * coord->s;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename t=""></typename>
Shinya Kitaoka 120a6e
void Warper<t>::shepardWarp() {</t>
Shinya Kitaoka 120a6e
  assert(m_rin.getPointer() != m_rout.getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_rin->lock();
Shinya Kitaoka 120a6e
  m_rout->lock();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRasterP rasIn(m_rin);
Shinya Kitaoka 120a6e
  TRasterP rasOut(m_rout);
Shinya Kitaoka 120a6e
  distort(rasOut, rasIn, *this, -convert(m_rinPos), TRop::Bilinear);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_rout->unlock();
Shinya Kitaoka 120a6e
  m_rin->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename t=""></typename>
Shinya Kitaoka 120a6e
TPointD Warper<t>::map(const TPointD &p) const {</t>
Shinya Kitaoka 120a6e
  return TPointD();  // Not truly necessary
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename t=""></typename>
Shinya Kitaoka 120a6e
int Warper<t>::invMap(const TPointD &p, TPointD *invs) const {</t>
Shinya Kitaoka 120a6e
  // Make a Shepard interpolant of grid points
Shinya Kitaoka 120a6e
  const double maxDist = 2 * m_warperScale;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPointD pos(p + m_rinPos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // First, bisect for the interesting maxDist-from-p region
Shinya Kitaoka 120a6e
  int i, j;
Shinya Kitaoka 120a6e
  double xStart = pos.x - maxDist;
Shinya Kitaoka 120a6e
  double yStart = pos.y - maxDist;
Shinya Kitaoka 120a6e
  double xEnd   = pos.x + maxDist;
Shinya Kitaoka 120a6e
  double yEnd   = pos.y + maxDist;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int a = 0, b = m_lattice.m_width;
Shinya Kitaoka 120a6e
  while (a + 1 < b) {
Shinya Kitaoka 120a6e
    i = (a + b) / 2;
Shinya Kitaoka 120a6e
    if (m_lattice.coords[i].d.x < xStart)
Shinya Kitaoka 120a6e
      a = i;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      b = i;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  i = a;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  a = 0, b = m_lattice.m_height;
Shinya Kitaoka 120a6e
  while (a + 1 < b) {
Shinya Kitaoka 120a6e
    j = (a + b) / 2;
Shinya Kitaoka 120a6e
    if (m_lattice.coords[j * m_lattice.m_width].d.y < yStart)
Shinya Kitaoka 120a6e
      a = j;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      b = j;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  j = a;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Then, build the interpolation
Shinya Kitaoka 120a6e
  int u, v;
Shinya Kitaoka 120a6e
  double w, wsum = 0;
Shinya Kitaoka 120a6e
  double xDistSq, yDistSq;
Shinya Kitaoka 120a6e
  double distSq, maxDistSq = sq(maxDist);
Shinya Kitaoka 120a6e
  TPointD result;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (v = j; v < m_lattice.m_height; ++v) {
Shinya Kitaoka 120a6e
    int vidx = v * m_lattice.m_width;
Shinya Kitaoka 120a6e
    if (m_lattice.coords[vidx].d.y > yEnd) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    yDistSq = sq(pos.y - m_lattice.coords[vidx].d.y);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    LPoint *coord = &m_lattice.coords[vidx + i];
Shinya Kitaoka 120a6e
    for (u = i; u < m_lattice.m_width; ++u, ++coord) {
Shinya Kitaoka 120a6e
      xDistSq = sq(pos.x - m_lattice.coords[u].d.x);
Shinya Kitaoka 120a6e
      if (m_lattice.coords[u].d.x > xEnd) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      distSq = xDistSq + yDistSq;
Shinya Kitaoka 120a6e
      if (distSq > maxDistSq) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      w = maxDist - sqrt(distSq);
Shinya Kitaoka 120a6e
      wsum += w;
Shinya Kitaoka 120a6e
      result += w * coord->s;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (wsum)
Shinya Kitaoka 120a6e
    invs[0] = p + TPointD(result.x / wsum, result.y / wsum);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    invs[0] = p;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return 1;
Toshihiro Shimizu 890ddd
}
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 warped bbox, the requested rect, and the warp params.
Shinya Kitaoka 120a6e
void getWarpComputeRects(TRectD &outputComputeRect, TRectD &warpedComputeRect,
Shinya Kitaoka 120a6e
                         const TRectD &warpedBox, const TRectD &requestedRect,
Shinya Kitaoka 120a6e
                         const WarpParams ¶ms) {
Shinya Kitaoka 120a6e
  if (requestedRect.isEmpty() || warpedBox.isEmpty()) {
Shinya Kitaoka 120a6e
    warpedComputeRect.empty();
Shinya Kitaoka 120a6e
    outputComputeRect.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
  //  0) At this stage, we are definitely not aware of what lies in the warper
Shinya Kitaoka 120a6e
  //     image. Therefore, we must assume the maximum warp factor allowed by the
Shinya Kitaoka 120a6e
  //     warp params for each of its points - see getWarpRadius().
Shinya Kitaoka 120a6e
  //  2) Pixels contributing to any output are necessarily part of warpedBox -
Shinya Kitaoka 120a6e
  //  and only
Shinya Kitaoka 120a6e
  //     those which are warpable into the requestedRect are useful to us
Shinya Kitaoka 120a6e
  //     (i.e. pixels contained in its enlargement by the warp radius).
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double warpRadius = getWarpRadius(params) * params.m_warperScale;
Shinya Kitaoka 120a6e
  TRectD enlargedOut(requestedRect.enlarge(warpRadius));
Shinya Kitaoka 120a6e
  TRectD enlargedBox(warpedBox.enlarge(warpRadius));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  warpedComputeRect = enlargedOut * warpedBox;
Shinya Kitaoka 120a6e
  outputComputeRect = enlargedBox * requestedRect;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Finally, make sure that the result is coherent with the requestedRect's P00
Shinya Kitaoka 120a6e
  warpedComputeRect -= requestedRect.getP00();
Shinya Kitaoka 120a6e
  warpedComputeRect.x0 = tfloor(warpedComputeRect.x0);
Shinya Kitaoka 120a6e
  warpedComputeRect.y0 = tfloor(warpedComputeRect.y0);
Shinya Kitaoka 120a6e
  warpedComputeRect.x1 = tceil(warpedComputeRect.x1);
Shinya Kitaoka 120a6e
  warpedComputeRect.y1 = tceil(warpedComputeRect.y1);
Shinya Kitaoka 120a6e
  warpedComputeRect += requestedRect.getP00();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  outputComputeRect -= requestedRect.getP00();
Shinya Kitaoka 120a6e
  outputComputeRect.x0 = tfloor(outputComputeRect.x0);
Shinya Kitaoka 120a6e
  outputComputeRect.y0 = tfloor(outputComputeRect.y0);
Shinya Kitaoka 120a6e
  outputComputeRect.x1 = tceil(outputComputeRect.x1);
Shinya Kitaoka 120a6e
  outputComputeRect.y1 = tceil(outputComputeRect.y1);
Shinya Kitaoka 120a6e
  outputComputeRect += requestedRect.getP00();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Deals with raster tiles and invokes warper functions.
Shinya Kitaoka 120a6e
//!\b NOTE: \b tileRas's size should be \b warper's one multiplied by
Shinya Kitaoka 38fd86
//! params.m_scale.
Toshihiro Shimizu 890ddd
void warp(TRasterP &tileRas, const TRasterP &rasIn, TRasterP &warper,
Shinya Kitaoka 120a6e
          TPointD rasInPos, TPointD warperPos, const WarpParams ¶ms) {
Shinya Kitaoka 120a6e
  TRaster32P rasIn32   = rasIn;
Shinya Kitaoka 120a6e
  TRaster32P tileRas32 = tileRas;
Shinya Kitaoka 120a6e
  TRaster32P warper32  = warper;
Shinya Kitaoka 120a6e
  TRaster64P rasIn64   = rasIn;
Shinya Kitaoka 120a6e
  TRaster64P tileRas64 = tileRas;
Shinya Kitaoka 120a6e
  TRaster64P warper64  = warper;
shun-iwasawa 481b59
  TRasterFP rasInF     = rasIn;
shun-iwasawa 481b59
  TRasterFP tileRasF   = tileRas;
shun-iwasawa 481b59
  TRasterFP warperF    = warper;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (rasIn32 && tileRas32 && warper32) {
Shinya Kitaoka 120a6e
    Warper<tpixel32> warper(rasInPos, warperPos, rasIn32, warper32, tileRas32,</tpixel32>
Shinya Kitaoka 120a6e
                            params);
Shinya Kitaoka 120a6e
    warper.createLattice();
Shinya Kitaoka 120a6e
    warper.shepardWarp();
Shinya Kitaoka 120a6e
  } else if (rasIn64 && tileRas64 && warper64) {
Shinya Kitaoka 120a6e
    Warper<tpixel64> warper(rasInPos, warperPos, rasIn64, warper64, tileRas64,</tpixel64>
Shinya Kitaoka 120a6e
                            params);
Shinya Kitaoka 120a6e
    warper.createLattice();
Shinya Kitaoka 120a6e
    warper.shepardWarp();
shun-iwasawa 481b59
  } else if (rasInF && tileRasF && warperF) {
shun-iwasawa 481b59
    Warper<tpixelf> warper(rasInPos, warperPos, rasInF, warperF, tileRasF,</tpixelf>
shun-iwasawa 481b59
                           params);
shun-iwasawa 481b59
    warper.createLattice();
shun-iwasawa 481b59
    warper.shepardWarp();
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    throw TRopException("warp: unsupported raster types");
Toshihiro Shimizu 890ddd
}