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