Beispiel #1
0
TScannerParameters::TScannerParameters()
    : m_bw(false)
    , m_gray(false)
    , m_rgb(false)
    , m_scanType(None)
    , m_scanArea(TRectD())
    , m_cropBox(TRectD())
    , m_isPreview(false)
    , m_maxPaperSize(TDimensionD(0, 0))
    , m_paperOverflow(false)
    , m_brightness()
    , m_contrast()
    , m_threshold()
    , m_dpi()
    , m_paperFeeder()
    , m_twainVersion()
    , m_manufacturer()
    , m_prodFamily()
    , m_productName()
    , m_version()
    , m_reverseOrder(false)
    , m_validatedByCurrentScanner(false) {
  m_threshold.m_value  = 127;
  m_brightness.m_value = 127;
}
Beispiel #2
0
void TScannerParameters::setPaperFormat(std::string paperFormat) {
  TPaperFormatManager *formatManager = TPaperFormatManager::instance();
  assert(formatManager->isValidFormat(paperFormat));
  if (!formatManager->isValidFormat(paperFormat))
    paperFormat = formatManager->getDefaultFormat();
  m_paperFormat = paperFormat;
  TDimensionD d = TPaperFormatManager::instance()->getSize(paperFormat);
  m_scanArea    = TRectD(TPointD(0, 0), d);
  cropScanArea();
  if (m_cropBox == TRectD()) m_cropBox = m_scanArea;
}
Beispiel #3
0
/*! rectangular rgb picking. The picked color will be an average of pixels in
 * specified rectangle
*/
void ImageViewer::rectPickColor(bool putValueToStyleEditor) {
  if (!m_isHistogramEnable) return;
  if (!m_histogramPopup->isVisible()) return;

  StylePicker picker(m_image);

  TPoint startPos =
      TPoint(m_pressedMousePos.x, height() - 1 - m_pressedMousePos.y);
  TPoint endPos = TPoint(m_pos.x(), height() - 1 - m_pos.y());
  TRectD area   = TRectD(convert(startPos), convert(endPos));
  area          = area.enlarge(-1, -1);
  if (area.getLx() < 2 || area.getLy() < 2) {
    m_histogramPopup->updateAverageColor(TPixel32::Transparent);
    return;
  }

  if (m_lutCalibrator && m_lutCalibrator->isValid() && m_fbo) m_fbo->bind();

  const TPixel32 pix = picker.pickColor(area.enlarge(-1, -1));

  if (m_lutCalibrator && m_lutCalibrator->isValid() && m_fbo) m_fbo->release();

  // throw the picked color to the histogram
  m_histogramPopup->updateAverageColor(pix);
  // throw it to the style editor as well
  if (putValueToStyleEditor) setPickedColorToStyleEditor(pix);
}
void MeshTexturizer::Imp::allocateTextures(int groupIdx, const TRaster32P &ras, const TRaster32P &aux,
										   int x, int y, int textureLx, int textureLy,
										   bool premultiplied)
{
	TextureData *data = m_textureDatas[groupIdx].get();

	// Test the specified texture allocation
	if (testTextureAlloc(textureLx, textureLy)) {
		TPointD scale(data->m_geom.getLx() / (double)ras->getLx(),
					  data->m_geom.getLy() / (double)ras->getLy());
		TRectD tileGeom(
			TRectD(
				scale.x * (x - TOTAL_BORDER), scale.y * (y - TOTAL_BORDER),
				scale.x * (x + textureLx + TOTAL_BORDER), scale.y * (y + textureLy + TOTAL_BORDER)) +
			data->m_geom.getP00());

		GLuint texId = textureAlloc(ras, aux, x, y, textureLx, textureLy, premultiplied);

		TextureData::TileData td = {texId, tileGeom};
		data->m_tileDatas.push_back(td);

		return;
	}

	if (textureLx <= 1 && textureLy <= 1)
		return; // No texture can be allocated

	// The texture could not be allocated. Then, bisecate and branch.
	if (textureLx > textureLy) {
		int textureLx_2 = textureLx >> 1;
		allocateTextures(groupIdx, ras, aux, x, y, textureLx_2, textureLy, premultiplied);
		allocateTextures(groupIdx, ras, aux, x + textureLx_2, y, textureLx_2, textureLy, premultiplied);
	} else {
Beispiel #5
0
DrawableTextureDataP texture_utils::getTextureData(
	const TXshSimpleLevel *sl, const TFrameId &fid, int subsampling)
{
	const std::string &texId = sl->getImageId(fid);

	// Now, we must associate a texture
	DrawableTextureDataP data(TTexturesStorage::instance()->getTextureData(texId));
	if (data)
		return data;

	// There was no associated texture. We must bind the texture and repeat

	// First, retrieve the image to be used as texture
	TRasterImageP ri(::getTexture(sl, fid, subsampling));
	if (!ri)
		return DrawableTextureDataP();

	TRaster32P ras(ri->getRaster());
	assert(ras);

	TRectD const geom
		= TScale(ri->getSubsampling())
		* TTranslation(convert(ri->getOffset()) - ras->getCenterD())
		* TRectD(0, 0, ras->getLx(), ras->getLy());

	return TTexturesStorage::instance()->loadTexture(texId, ras, geom);
}
  bool doGetBBox(double frame, TRectD &bBox,
                 const TRenderSettings &ri) override {
    if (m_input.isConnected() && m_controller.isConnected()) {
      TRectD controlBox, inputBox;

      TRenderSettings ri2(ri);
      ri2.m_affine = TAffine();

      m_controller->getBBox(frame, controlBox, ri2);

      TRenderSettings ri3(ri);

      int shrink = tround((ri.m_shrinkX + ri.m_shrinkY) / 2.0);
      // Should be there no need for the alias...
      SandorFxRenderData *artContourData =
          buildRenderData(frame, shrink, controlBox, "");
      ri3.m_data.push_back(artContourData);

      return m_input->doGetBBox(frame, bBox, ri3);
    } else if (m_input.isConnected()) {
      m_input->doGetBBox(frame, bBox, ri);
      return false;
    }
    bBox = TRectD();
    return false;
  }
Beispiel #7
0
 bool doGetBBox(double frame, TRectD &bBox, const TRenderSettings &info) {
   if (this->m_input.isConnected()) {
     return this->m_input->doGetBBox(frame, bBox, info);
   } else {
     bBox = TRectD();
     return false;
   }
 }
Beispiel #8
0
 //------------------------------------------------------------
 bool doGetBBox(double frame, TRectD &bBox, const TRenderSettings &info) {
   if (false == this->m_input.isConnected()) {
     bBox = TRectD();
     return false;
   }
   const bool ret = this->m_input->doGetBBox(frame, bBox, info);
   this->get_render_enlarge(frame, info.m_affine, bBox);
   return ret;
 }
TRectD TRasterImageUtils::convertRasterToWorld(const TRect &area, const TRasterImageP ri)
{
	if (area.isEmpty())
		return TRectD();

	TRectD rect(area.x0, area.y0, area.x1 + 1, area.y1 + 1);
	if (ri && ri->getRaster())
		rect = rect - ri->getRaster()->getCenterD();
	return rect;
}
 bool doGetBBox(double frame, TRectD &bBox,
                const TRenderSettings &info) override {
   if (m_input.isConnected()) {
     bool ret = m_input->doGetBBox(frame, bBox, info);
     return ret;
   } else {
     bBox = TRectD();
     return false;
   }
 }
Beispiel #11
0
	bool doGetBBox(double frame, TRectD &bBox, const TRenderSettings &info)
	{
		if (m_input.isConnected()) {
			bool ret = m_input->doGetBBox(frame, bBox, info);
			// devo scurire bgColor
			return ret;
		} else {
			bBox = TRectD();
			return false;
		}
	};
 bool doGetBBox(double frame, TRectD &bBox,
                const TRenderSettings &info) override {
   for (int ii = 0; ii < this->getInputPortCount(); ++ii) {
     std::string nm          = this->getInputPortName(ii);
     TRasterFxPort *tmp_port = (TRasterFxPort *)this->getInputPort(nm);
     if (tmp_port->isConnected()) {
       return (*tmp_port)->doGetBBox(frame, bBox, info);
     }
   }
   bBox = TRectD();
   return false;
 }
void ShiftTraceTool::clearData() {
  m_ghostIndex        = 0;
  m_curveStatus       = NoCurve;
  m_gadget            = NoGadget;
  m_highlightedGadget = NoGadget;

  m_box = TRectD();
  for (int i = 0; i < 2; i++) {
    m_row[i]    = -1;
    m_aff[i]    = TAffine();
    m_center[i] = TPointD();
  }
}
Beispiel #14
0
	TRectD getBBox() const
	{
		if (!m_isValidBBox) {
			m_bBox = TRectD();

			for (UINT i = 0; i < m_edge.size(); i++)
				m_bBox += m_edge[i]->m_s->getBBox(tmin(m_edge[i]->m_w0, m_edge[i]->m_w1),
												  tmax(m_edge[i]->m_w0, m_edge[i]->m_w1));

			m_isValidBBox = true;
		}
		return m_bBox;
	}
bool Iwa_GradientWarpFx::doGetBBox(double frame,
								   TRectD &bBox,
								   const TRenderSettings &info)
{
	if (!m_source.isConnected()) {
		bBox = TRectD();
		return false;
	}

	const bool ret = m_source->doGetBBox(frame, bBox, info);
	get_render_enlarge(frame, info.m_affine, bBox);
	return ret;
}
Beispiel #16
0
	bool doGetBBox(double frame, TRectD &bBox, const TRenderSettings &info)
	{
		if (m_input.isConnected()) {
			//Build the render data
			TRenderSettings info2(info);
			buildBlendData(info2, frame);

			return m_input->doGetBBox(frame, bBox, info2);
		} else {
			bBox = TRectD();
			return false;
		}
	}
Beispiel #17
0
void CameraTestTool::mouseMove(const TPointD &p, const TMouseEvent &e) {
  if (m_lastPos.x != -1)  // left mouse button is clicked
  {
    m_scaling = eNoScale;
    return;
  }

  CleanupParameters *cp =
      CleanupSettingsModel::instance()->getCurrentParameters();
  double pixelSize = getPixelSize();

  TPointD size(10 * pixelSize, 10 * pixelSize);
  TRectD r(cp->m_camera.getStageRect());
  TPointD aux(Stage::inch * TPointD(0.5 * cp->m_offx, 0.5 * cp->m_offy));
  r -= aux;
  double maxDist = 5 * pixelSize;

  if (TRectD(r.getP00() - size, r.getP00() + size).contains(p))
    m_scaling = e00;
  else if (TRectD(r.getP01() - size, r.getP01() + size).contains(p))
    m_scaling = e01;
  else if (TRectD(r.getP11() - size, r.getP11() + size).contains(p))
    m_scaling = e11;
  else if (TRectD(r.getP10() - size, r.getP10() + size).contains(p))
    m_scaling = e10;
  else if (isCloseToSegment(p, TSegment(r.getP00(), r.getP10()), maxDist))
    m_scaling = eM0;
  else if (isCloseToSegment(p, TSegment(r.getP10(), r.getP11()), maxDist))
    m_scaling = e1M;
  else if (isCloseToSegment(p, TSegment(r.getP11(), r.getP01()), maxDist))
    m_scaling = eM1;
  else if (isCloseToSegment(p, TSegment(r.getP01(), r.getP00()), maxDist))
    m_scaling = e0M;
  else
    m_scaling = eNoScale;
}
void ShiftTraceTool::updateData()
{
	TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
	int row = TApp::instance()->getCurrentFrame()->getFrame();
	int col = TApp::instance()->getCurrentColumn()->getColumnIndex();
	TXshCell cell = xsh->getCell(row, col);
	m_box = TRectD();
	for (int i = 0; i < 2; i++)
		m_row[i] = -1;
	m_dpiAff = TAffine();

	// we must find the prev (m_row[0]) and next (m_row[1]) reference images
	// (either might not exist)
	// see also stage.cpp, StageBuilder::addCellWithOnionSkin

	if (cell.isEmpty()) {
		// current cell is empty. search for the prev ref img
		int r = row - 1;
		while (r >= 0 && xsh->getCell(r, col).getSimpleLevel() == 0)
			r--;
		if (r >= 0)
			m_row[0] = r;
		// else prev drawing doesn't exist : nothing to do
	} else {
		// current cell is not empty
		// search for prev ref img
		TXshSimpleLevel *sl = cell.getSimpleLevel();
		int r = row - 1;
		if (r >= 0) {
			TXshCell otherCell = xsh->getCell(r, col);
			if (otherCell.getSimpleLevel() == sl) {
				// find the span start
				while (r - 1 >= 0 && xsh->getCell(r - 1, col) == otherCell)
					r--;
				m_row[0] = r;
			}
		}

		// search for next ref img
		r = row + 1;
		while (xsh->getCell(r, col) == cell)
			r++;
		// first cell after the current span has the same level
		if (xsh->getCell(r, col).getSimpleLevel() == sl)
			m_row[1] = r;
	}
	updateBox();
}
Beispiel #19
0
bool Iwa_MotionBlurCompFx::doGetBBox(double frame, TRectD &bBox,
                                     const TRenderSettings &info) {
  if (!m_input.isConnected() && !m_background.isConnected()) {
    bBox = TRectD();
    return false;
  }

  /*- 取り急ぎ、背景が繋がっていたら無限サイズにする -*/
  if (m_background.isConnected()) {
    bool _ret = m_background->doGetBBox(frame, bBox, info);
    bBox      = TConsts::infiniteRectD;
    return _ret;
  }

  bool ret = m_input->doGetBBox(frame, bBox, info);

  if (bBox == TConsts::infiniteRectD) return true;

  QList<TPointD> points = getAttributes()->getMotionPoints();
  /*- 移動した軌跡のバウンディングボックスからマージンを求める -*/
  /*- 各軌跡点の座標の絶対値の最大値を得る -*/
  /*- 上下左右のマージンを得る -*/
  double minX = 0.0;
  double maxX = 0.0;
  double minY = 0.0;
  double maxY = 0.0;
  for (int p = 0; p < points.size(); p++) {
    if (points.at(p).x > maxX) maxX = points.at(p).x;
    if (points.at(p).x < minX) minX = points.at(p).x;
    if (points.at(p).y > maxY) maxY = points.at(p).y;
    if (points.at(p).y < minY) minY = points.at(p).y;
  }
  int marginLeft   = (int)ceil(abs(minX));
  int marginRight  = (int)ceil(abs(maxX));
  int marginTop    = (int)ceil(abs(maxY));
  int marginBottom = (int)ceil(abs(minY));

  TRectD enlargedBBox(
      bBox.x0 - (double)marginLeft, bBox.y0 - (double)marginBottom,
      bBox.x1 + (double)marginRight, bBox.y1 + (double)marginTop);

  bBox = enlargedBBox;

  return ret;
}
Beispiel #20
0
bool TGeometryFx::doGetBBox(double frame, TRectD &bBox,
                            const TRenderSettings &info) {
  TRasterFxPort *input = dynamic_cast<TRasterFxPort *>(getInputPort(0));
  assert(input);

  if (input->isConnected()) {
    TRasterFxP fx = input->getFx();
    assert(fx);
    bool ret = fx->doGetBBox(frame, bBox, info);
    if (getActiveTimeRegion().contains(frame))
      bBox = getPlacement(frame) * bBox;
    return ret;
  } else {
    bBox = TRectD();
    return false;
  }
  return true;
};
Beispiel #21
0
  bool doGetBBox(double frame, TRectD &bBox, const TRenderSettings &info) {
    if (m_warped.isConnected()) {
      int ret = m_warped->doGetBBox(frame, bBox, info);

      if (ret && !bBox.isEmpty()) {
        if (bBox != TConsts::infiniteRectD) {
          WarpParams params;
          params.m_intensity = m_intensity->getValue(frame);

          bBox = bBox.enlarge(getWarpRadius(params));
        }
        return true;
      }
    }

    bBox = TRectD();
    return false;
  }
 bool doGetBBox(double frame, TRectD &bBox, const TRenderSettings &rs) {
   TRectD up_bx;
   const bool up_sw =
       (m_up.isConnected() ? m_up->doGetBBox(frame, up_bx, rs) : false);
   TRectD dn_bx;
   const bool dn_sw =
       (m_down.isConnected() ? m_down->doGetBBox(frame, dn_bx, rs) : false);
   if (up_sw && dn_sw) {
     bBox = up_bx + dn_bx;
     return !bBox.isEmpty();
   } else if (up_sw) {
     bBox = up_bx;
     return true;
   } else if (dn_sw) {
     bBox = dn_bx;
     return true;
   } else {
     bBox = TRectD();
     return false;
   }
 }
Beispiel #23
0
/*! rgb picking
*/
void ImageViewer::pickColor(QMouseEvent *event, bool putValueToStyleEditor) {
  if (!m_isHistogramEnable) return;
  if (!m_histogramPopup->isVisible()) return;

  QPoint curPos = event->pos() * getDevPixRatio();

  // avoid to pick outside of the flip
  if ((!m_image) || !rect().contains(curPos)) {
    // throw transparent color
    m_histogramPopup->updateInfo(TPixel32::Transparent, TPointD(-1, -1));
    return;
  }

  StylePicker picker(m_image);

  TPoint mousePos = TPoint(curPos.x(), height() - 1 - curPos.y());
  TRectD area     = TRectD(mousePos.x, mousePos.y, mousePos.x, mousePos.y);

  if (m_lutCalibrator && m_lutCalibrator->isValid()) m_fbo->bind();

  const TPixel32 pix = picker.pickColor(area);

  if (m_lutCalibrator && m_lutCalibrator->isValid()) m_fbo->release();

  QPoint viewP = mapFrom(this, curPos);
  TPointD pos  = getViewAff().inv() *
                TPointD(viewP.x() - width() / 2, -viewP.y() + height() / 2);
  TPointD imagePos = TPointD(0.5 * m_image->getBBox().getLx() + pos.x,
                             0.5 * m_image->getBBox().getLy() + pos.y);
  if (m_image->getBBox().contains(imagePos)) {
    // throw the picked color to the histogram
    m_histogramPopup->updateInfo(pix, imagePos);
    // throw it to the style editor as well
    if (putValueToStyleEditor) setPickedColorToStyleEditor(pix);
  } else {
    // throw transparent color if picking outside of the image
    m_histogramPopup->updateInfo(TPixel32::Transparent, TPointD(-1, -1));
  }
}
Beispiel #24
0
bool TExternalProgramFx::doGetBBox(double frame, TRectD &bBox,
                                   const TRenderSettings &info) {
  // bBox = TRectD(-30,-30,30,30);
  //  return true;

  std::map<std::string, Port>::const_iterator portIt;
  for (portIt = m_ports.begin(); portIt != m_ports.end(); ++portIt) {
    if (portIt->second.m_port != 0) {
      TRasterFxPort *tmp;
      tmp = portIt->second.m_port;
      if (tmp->isConnected()) {
        TRectD tmpbBox;
        (*tmp)->doGetBBox(frame, tmpbBox, info);
        bBox += tmpbBox;
      }
    }
  }

  if (bBox.isEmpty()) {
    bBox = TRectD();
    return false;
  } else
    return true;
  /*
if(m_input1.isConnected() || m_input2.isConnected())
{
bool ret = m_input1->doGetBBox(frame, bBox) || m_input1->doGetBBox(frame, bBox);
return ret;
}
else
{
bBox = TRectD();
return false;
}
*/
}
Beispiel #25
0
//!Converts a TVectorImage into a TRasterImage. The input vector image
//!is transformed through the passed affine \b aff, and put into a
//!TRasterImage strictly covering the bounding box of the transformed
//!vector image. The output image has its lower-left position in the
//!world reference specified by the \b pos parameter, which is granted to
//!be an integer displacement of the passed value. Additional parameters
//!include an integer \b enlarge by which the output image is enlarged with
//!respect to the transformed image's bbox, and the bool \b transformThickness
//!to specify whether the transformation should involve strokes' thickensses
//!or not.
TRasterImageP TRasterImageUtils::vectorToFullColorImage(
	const TVectorImageP &vimage, const TAffine &aff, TPalette *palette,
	const TPointD &outputPos, const TDimension &outputSize,
	const std::vector<TRasterFxRenderDataP> *fxs, bool transformThickness)
{
	if (!vimage || !palette)
		return 0;

	//Transform the vector image through aff
	TVectorImageP vi = vimage->clone();
	vi->transform(aff, transformThickness);

	//Allocate the output ToonzImage
	TRaster32P raster(outputSize.lx, outputSize.ly);
	raster->clear();
	TRasterImageP ri(raster);
	ri->setPalette(palette->clone());

	//Shift outputPos to the origin
	vi->transform(TTranslation(-outputPos));

	int strokeCount = vi->getStrokeCount();
	std::vector<int> strokeIndex(strokeCount);
	std::vector<TStroke *> strokes(strokeCount);
	int i;
	for (i = 0; i < strokeCount; ++i) {
		strokeIndex[i] = i;
		strokes[i] = vi->getStroke(i);
	}
	vi->notifyChangedStrokes(strokeIndex, strokes);

	int maxStyleId = palette->getStyleCount() - 1;
	for (i = 0; i < (int)vi->getRegionCount(); ++i) {
		TRegion *region = vi->getRegion(i);
		fastAddPaintRegion(ri, region, tmin(maxStyleId, region->getStyle()), maxStyleId);
	}

	set<int> colors;
	if (fxs) {
		for (i = 0; i < (int)fxs->size(); i++) {
			SandorFxRenderData *sandorData = dynamic_cast<SandorFxRenderData *>((*fxs)[i].getPointer());
			if (sandorData && sandorData->m_type == BlendTz) {
				std::string indexes = toString(sandorData->m_blendParams.m_colorIndex);
				std::vector<std::string> items;
				parseIndexes(indexes, items);
				PaletteFilterFxRenderData paletteFilterData;
				insertIndexes(items, &paletteFilterData);
				colors = paletteFilterData.m_colors;
				break;
			}
		}
	}

	for (i = 0; i < strokeCount; ++i) {
		TStroke *stroke = vi->getStroke(i);

		bool visible = false;
		int styleId = stroke->getStyle();
		TColorStyleP style = palette->getStyle(styleId);
		assert(style);
		int colorCount = style->getColorParamCount();
		if (colorCount == 0)
			visible = true;
		else {
			visible = false;
			for (int j = 0; j < style->getColorParamCount() && !visible; j++) {
				TPixel32 color = style->getColorParamValue(j);
				if (color.m != 0)
					visible = true;
			}
		}
		if (visible)
			fastAddInkStroke(ri, stroke, TRectD(), 1, true);
	}
	return ri;
}
Beispiel #26
0
	void doCompute(TTile &tile, double frame, const TRenderSettings &info)
	{
		bool isWarped = m_warped.isConnected();

		if (!isWarped)
			return;

		if (fabs(m_intensity->getValue(frame)) < 0.01) {
			m_warped->compute(tile, frame, info);
			return;
		}

		int shrink = (info.m_shrinkX + info.m_shrinkY) / 2;
		double scale = sqrt(fabs(info.m_affine.det()));
		double gridStep = 1.5 * m_gridStep->getValue(frame);

		WarpParams params;
		params.m_intensity = m_intensity->getValue(frame) / gridStep;
		params.m_warperScale = scale * gridStep;
		params.m_sharpen = m_sharpen->getValue();
		params.m_shrink = shrink;
		double evolution = m_evol->getValue(frame);
		double size = 100.0 / info.m_shrinkX;
		TPointD pos(m_posx->getValue(frame), m_posy->getValue(frame));

		//The warper is calculated on a standard reference, with fixed dpi. This makes sure
		//that the lattice created for the warp does not depend on camera transforms and resolution.
		TRenderSettings warperInfo(info);
		double warperScaleFactor = 1.0 / params.m_warperScale;
		warperInfo.m_affine = TScale(warperScaleFactor) * info.m_affine;

		//Retrieve tile's geometry
		TRectD tileRect;
		{
			TRasterP tileRas = tile.getRaster();
			tileRect = TRectD(tile.m_pos, TDimensionD(tileRas->getLx(), tileRas->getLy()));
		}

		//Build the compute rect
		TRectD warpedBox, warpedComputeRect, tileComputeRect;
		m_warped->getBBox(frame, warpedBox, info);

		getWarpComputeRects(tileComputeRect, warpedComputeRect, warpedBox, tileRect, params);

		if (tileComputeRect.getLx() <= 0 || tileComputeRect.getLy() <= 0)
			return;
		if (warpedComputeRect.getLx() <= 0 || warpedComputeRect.getLy() <= 0)
			return;

		TRectD warperComputeRect(TScale(warperScaleFactor) * tileComputeRect);
		double warperEnlargement = getWarperEnlargement(params);
		warperComputeRect = warperComputeRect.enlarge(warperEnlargement);
		warperComputeRect.x0 = tfloor(warperComputeRect.x0);
		warperComputeRect.y0 = tfloor(warperComputeRect.y0);
		warperComputeRect.x1 = tceil(warperComputeRect.x1);
		warperComputeRect.y1 = tceil(warperComputeRect.y1);

		//Compute the warped tile
		TTile tileIn;
		m_warped->allocateAndCompute(tileIn, warpedComputeRect.getP00(),
									 TDimension(warpedComputeRect.getLx(), warpedComputeRect.getLy()),
									 tile.getRaster(), frame, info);
		TRasterP rasIn = tileIn.getRaster();

		//Compute the warper tile
		TSpectrum::ColorKey colors[] = {
			TSpectrum::ColorKey(0, TPixel32::White),
			TSpectrum::ColorKey(1, TPixel32::Black)};

		TSpectrumParamP cloudscolors = TSpectrumParamP(tArrayCount(colors), colors);

		//Build the warper
		warperInfo.m_affine = warperInfo.m_affine;
		TAffine aff = warperInfo.m_affine.inv();

		TTile warperTile;
		TRasterP rasWarper = rasIn->create(warperComputeRect.getLx(), warperComputeRect.getLy());
		warperTile.m_pos = warperComputeRect.getP00();
		warperTile.setRaster(rasWarper);

		{
			TRenderSettings info2(warperInfo);

			//Now, separate the part of the affine the Fx can handle from the rest.
			TAffine fxHandledAffine = handledAffine(warperInfo, frame);
			info2.m_affine = fxHandledAffine;

			TAffine aff = warperInfo.m_affine * fxHandledAffine.inv();
			aff.a13 /= warperInfo.m_shrinkX;
			aff.a23 /= warperInfo.m_shrinkY;

			TRectD rectIn = aff.inv() * warperComputeRect;

			//rectIn = rectIn.enlarge(getResampleFilterRadius(info));  //Needed to counter the resample filter

			TRect rectInI(tfloor(rectIn.x0), tfloor(rectIn.y0), tceil(rectIn.x1) - 1, tceil(rectIn.y1) - 1);

			// rasIn e' un raster dello stesso tipo di tile.getRaster()

			TTile auxtile(warperTile.getRaster()->create(rectInI.getLx(), rectInI.getLy()), convert(rectInI.getP00()));

			TPointD mypos(auxtile.m_pos - pos);

			double scale2 = sqrt(fabs(info2.m_affine.det()));
			doClouds(auxtile.getRaster(), cloudscolors, mypos, evolution, size, 0.0, 1.0, PNOISE_CLOUDS, scale2, frame);

			info2.m_affine = aff;
			TRasterFx::applyAffine(warperTile, auxtile, info2);
		}

		//Warp
		TPointD db;
		TRect rasComputeRectI(convert(tileComputeRect - tileRect.getP00(), db));
		TRasterP tileRas = tile.getRaster()->extract(rasComputeRectI);

		TPointD rasInPos(warpedComputeRect.getP00() - tileComputeRect.getP00());
		TPointD warperPos((TScale(params.m_warperScale) * warperComputeRect.getP00()) - tileComputeRect.getP00());
		warp(tileRas, rasIn, rasWarper, rasInPos, warperPos, params);
	}
Beispiel #27
0
void ImageViewer::paintGL() {
  if (m_lutCalibrator && m_lutCalibrator->isValid()) m_fbo->bind();

  TDimension viewerSize(width(), height());
  TAffine aff = m_viewAff;

  // if (!m_visualSettings.m_defineLoadbox && m_flipbook &&
  // m_flipbook->getLoadbox()!=TRect())
  //  offs =
  //  convert(m_flipbook->getLoadbox().getP00())-TPointD(m_flipbook->getImageSize().lx/2.0,
  //  m_flipbook->getImageSize().ly/2.0);

  TDimension imageSize;
  TRect loadbox;

  if (m_flipbook) {
    QString title =
        (!m_image)
            ? m_flipbook->getTitle() + tr("  ::  Zoom : ") +
                  QString::number(tround(sqrt(m_viewAff.det()) * 100)) + " %"
            : m_flipbook->getLevelZoomTitle() + tr("  ::  Zoom : ") +
                  QString::number(tround(sqrt(m_viewAff.det()) * 100)) + " %";
    m_flipbook->parentWidget()->setWindowTitle(title);
    imageSize = m_flipbook->getImageSize();
    if (m_visualSettings.m_useLoadbox && m_flipbook->getLoadbox() != TRect())
      loadbox = m_flipbook->getLoadbox();
  }
  m_visualSettings.m_sceneProperties =
      TApp::instance()->getCurrentScene()->getScene()->getProperties();
  // enable checks only in the color model
  m_visualSettings.m_useChecks = m_isColorModel;
  ImagePainter::paintImage(m_image, imageSize, viewerSize, aff,
                           m_visualSettings, m_compareSettings, loadbox);

  // when fx parameter is modified with showing the fx preview,
  // a flipbook shows a red border line before the rendered result is shown.
  if (m_isRemakingPreviewFx) {
    glPushMatrix();
    glLoadIdentity();
    glColor3d(1.0, 0.0, 0.0);

    glBegin(GL_LINE_LOOP);
    glVertex2d(5, 5);
    glVertex2d(5, height() - 5);
    glVertex2d(width() - 5, height() - 5);
    glVertex2d(width() - 5, 5);
    glEnd();

    glBegin(GL_LINE_LOOP);
    glVertex2d(10, 10);
    glVertex2d(10, height() - 10);
    glVertex2d(width() - 10, height() - 10);
    glVertex2d(width() - 10, 10);
    glEnd();
    glPopMatrix();
  }

  if (!m_image) {
    if (m_lutCalibrator && m_lutCalibrator->isValid())
      m_lutCalibrator->onEndDraw(m_fbo);
    return;
  }

  if (safeAreaToggle.getStatus() && !m_isColorModel) {
    TRasterImageP rimg = (TRasterImageP)m_image;
    TVectorImageP vimg = (TVectorImageP)m_image;
    TToonzImageP timg  = (TToonzImageP)m_image;
    TRect bbox;

    TPointD centerD;
    TRect bounds;
    if (rimg) {
      centerD = rimg->getRaster()->getCenterD();
      bounds  = rimg->getRaster()->getBounds();
    } else if (timg) {
      centerD = timg->getRaster()->getCenterD();
      bounds  = timg->getRaster()->getBounds();
    }

    if (!vimg) {
      TAffine aff = TTranslation(viewerSize.lx * 0.5, viewerSize.ly * 0.5) *
                    m_viewAff * TTranslation(-centerD);
      TRectD bbox = aff * TRectD(0, 0, bounds.getLx() - 1, bounds.getLy() - 1);
      drawSafeArea(bbox);
    }
  }
  TPoint fromPos, toPos;

  if (m_visualSettings.m_defineLoadbox && m_flipbook) {
    TRect loadbox =
        convert(getImgToWidgetAffine() * convert(m_flipbook->getLoadbox()));
    if (loadbox != TRect()) {
      TPoint p00 = loadbox.getP00();
      TPoint p11 = loadbox.getP11();
      fromPos =
          TPoint(p00.x - width() * 0.5,
                 height() * 0.5 - p00.y);  // m_flipbook->getLoadbox().getP00();
      toPos =
          TPoint(p11.x - width() * 0.5,
                 height() * 0.5 - p11.y);  // m_flipbook->getLoadbox().getP11();
    }
  } else if (m_draggingZoomSelection || m_rectRGBPick) {
    fromPos = TPoint(m_pressedMousePos.x - width() * 0.5,
                     height() * 0.5 - m_pressedMousePos.y);
    toPos = TPoint(m_pos.x() - width() * 0.5, height() * 0.5 - m_pos.y());
  }
  if (fromPos != TPoint() || toPos != TPoint()) {
    if (m_rectRGBPick) {
      tglColor(TPixel32::Red);
      // TODO: glLineStipple is deprecated in the latest OpenGL. Need to be
      // replaced. (shun_iwasawa 2015/12/25)
      glLineStipple(1, 0x3F33);
      glEnable(GL_LINE_STIPPLE);

      glBegin(GL_LINE_STRIP);
      // do not draw the rect around the mouse cursor
      int margin = (fromPos.y < toPos.y) ? -3 : 3;
      glVertex2i(toPos.x, toPos.y + margin);
      glVertex2i(toPos.x, fromPos.y);
      glVertex2i(fromPos.x, fromPos.y);
      glVertex2i(fromPos.x, toPos.y);
      margin = (fromPos.x < toPos.x) ? -3 : 3;
      glVertex2i(toPos.x + margin, toPos.y);
      glEnd();
      glDisable(GL_LINE_STIPPLE);
    } else {
      tglColor(m_draggingZoomSelection ? TPixel32::Red : TPixel32::Blue);
      glBegin(GL_LINE_STRIP);
      glVertex2i(fromPos.x, fromPos.y);
      glVertex2i(fromPos.x, toPos.y);
      glVertex2i(toPos.x, toPos.y);
      glVertex2i(toPos.x, fromPos.y);
      glVertex2i(fromPos.x, fromPos.y);
      glEnd();
    }
  }

  if (m_lutCalibrator && m_lutCalibrator->isValid())
    m_lutCalibrator->onEndDraw(m_fbo);
}
Beispiel #28
0
void subCompute(TRasterFxPort &m_input, TTile &tile, double frame,
                const TRenderSettings &ri, TPointD p00, TPointD p01,
                TPointD p11, TPointD p10, int details, bool wireframe,
                TDimension m_offScreenSize, bool isCast) {
  TPixel32 bgColor;
  TRectD outBBox, inBBox;
  outBBox = inBBox = TRectD(tile.m_pos, TDimensionD(tile.getRaster()->getLx(),
                                                    tile.getRaster()->getLy()));
  m_input->getBBox(frame, inBBox, ri);
  if (inBBox == TConsts::infiniteRectD)  // e' uno zerario
    inBBox = outBBox;

  int inBBoxLx = (int)inBBox.getLx() / ri.m_shrinkX;
  int inBBoxLy = (int)inBBox.getLy() / ri.m_shrinkY;

  if (inBBox.isEmpty()) return;

  if (p00 == p01 && p00 == p10 && p00 == p11 &&
      !isCast)  // significa che non c'e' deformazione
  {
    m_input->compute(tile, frame, ri);
    return;
  }

  TRaster32P rasIn;
  TPointD rasInPos;

  if (!wireframe) {
    if (ri.m_bpp == 64 || ri.m_bpp == 48) {
      TRaster64P aux = TRaster64P(inBBoxLx, inBBoxLy);
      rasInPos = TPointD(inBBox.x0 / ri.m_shrinkX, inBBox.y0 / ri.m_shrinkY);
      TTile tmp(aux, rasInPos);
      m_input->compute(tmp, frame, ri);
      rasIn = TRaster32P(inBBoxLx, inBBoxLy);
      TRop::convert(rasIn, aux);
    } else {
      rasInPos = TPointD(inBBox.x0 / ri.m_shrinkX, inBBox.y0 / ri.m_shrinkY);
      TTile tmp(TRaster32P(inBBoxLx, inBBoxLy), rasInPos);
      m_input->allocateAndCompute(tmp, rasInPos, TDimension(inBBoxLx, inBBoxLy),
                                  TRaster32P(), frame, ri);
      rasIn = tmp.getRaster();
    }
  }

  unsigned int texWidth  = 2;
  unsigned int texHeight = 2;

  while (texWidth < (unsigned int)inBBoxLx) texWidth = texWidth << 1;

  while (texHeight < (unsigned int)inBBoxLy) texHeight = texHeight << 1;

  while (texWidth > 1024 || texHeight > 1024)  // avevo usato la costante
                                               // GL_MAX_TEXTURE_SIZE invece di
                                               // 1024, ma non funzionava!
  {
    inBBoxLx  = inBBoxLx >> 1;
    inBBoxLy  = inBBoxLy >> 1;
    texWidth  = texWidth >> 1;
    texHeight = texHeight >> 1;
  }

  if (rasIn->getLx() != inBBoxLx || rasIn->getLy() != inBBoxLy) {
    TRaster32P rasOut = TRaster32P(inBBoxLx, inBBoxLy);
    TRop::resample(rasOut, rasIn,
                   TScale((double)rasOut->getLx() / rasIn->getLx(),
                          (double)rasOut->getLy() / rasIn->getLy()));
    rasIn = rasOut;
  }

  int rasterWidth  = tile.getRaster()->getLx() + 2;
  int rasterHeight = tile.getRaster()->getLy() + 2;
  assert(rasterWidth > 0);
  assert(rasterHeight > 0);

  TRectD clippingRect =
      TRectD(tile.m_pos,
             TDimensionD(tile.getRaster()->getLx(), tile.getRaster()->getLy()));
#if CREATE_GL_CONTEXT_ONE_TIME
  int ret = wglMakeCurrent(m_offScreenGL.m_offDC, m_offScreenGL.m_hglRC);
  assert(ret == TRUE);
#else
  TOfflineGL offScreenRendering(TDimension(rasterWidth, rasterHeight));
  //#ifdef _WIN32
  offScreenRendering.makeCurrent();
//#else
//#if defined(LINUX) || defined(MACOSX)
// offScreenRendering.m_offlineGL->makeCurrent();
//#endif
#endif

  checkErrorsByGL
      // disabilito quello che non mi serve per le texture
      glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
  glDisable(GL_DITHER);
  glDisable(GL_DEPTH_TEST);
  glCullFace(GL_FRONT);
  glDisable(GL_STENCIL_TEST);
  glDisable(GL_LOGIC_OP);

  // creo la texture in base all'immagine originale
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

  checkErrorsByGL
#if !CREATE_GL_CONTEXT_ONE_TIME
      TRaster32P rasaux;
  if (!wireframe) {
    TRaster32P texture(texWidth, texHeight);
    texture->clear();
    rasaux = texture;
    rasaux->lock();
    texture->copy(rasIn);

    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    glTexImage2D(GL_TEXTURE_2D, 0, 4, texWidth, texHeight, 0, GL_RGBA,
                 GL_UNSIGNED_BYTE, texture->getRawData());
  }
#else

      unsigned int texWidth = 1024;
  unsigned int texHeight    = 1024;
  rasaux                    = rasIn;
  rasaux->lock();

  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rasIn->getLx(), rasIn->getLy(),
                  GL_RGBA, GL_UNSIGNED_BYTE, rasIn->getRawData());

#endif
  checkErrorsByGL

      glEnable(GL_TEXTURE_2D);

  // cfr. help: OpenGL/Programming tip/OpenGL Correctness Tips
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-rasterWidth * 0.5, rasterWidth * 0.5, -rasterHeight * 0.5,
          rasterHeight * 0.5, -1, 1);
  glViewport(0, 0, rasterWidth, rasterHeight);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  glClear(GL_COLOR_BUFFER_BIT);

  // do OpenGL draw

  double lwTex = (double)(inBBoxLx - 1) / (double)(texWidth - 1);
  double lhTex = (double)(inBBoxLy - 1) / (double)(texHeight - 1);

  TPointD tex00 = TPointD(0.0, 0.0);
  TPointD tex10 = TPointD(lwTex, 0.0);
  TPointD tex11 = TPointD(lwTex, lhTex);
  TPointD tex01 = TPointD(0.0, lhTex);

  GLenum polygonStyle;
  if (wireframe) {
    polygonStyle = GL_LINE;
    glDisable(GL_TEXTURE_2D);
  } else
    polygonStyle = GL_FILL;
  checkErrorsByGL p00.x /= ri.m_shrinkX;
  p00.y /= ri.m_shrinkY;

  p10.x /= ri.m_shrinkX;
  p10.y /= ri.m_shrinkY;

  p11.x /= ri.m_shrinkX;
  p11.y /= ri.m_shrinkY;

  p01.x /= ri.m_shrinkX;
  p01.y /= ri.m_shrinkY;

  TPointD translate = TPointD(tile.m_pos.x + tile.getRaster()->getLx() * 0.5,
                              tile.m_pos.y + tile.getRaster()->getLy() * 0.5);
  glTranslated(-translate.x, -translate.y, 0.0);

  // disegno il poligono
  double dist_p00_p01                 = tdistance2(p00, p01);
  double dist_p10_p11                 = tdistance2(p10, p11);
  double dist_p01_p11                 = tdistance2(p01, p11);
  double dist_p00_p10                 = tdistance2(p00, p10);
  bool vertical                       = (dist_p00_p01 == dist_p10_p11);
  bool horizontal                     = (dist_p00_p10 == dist_p01_p11);
  if (vertical && horizontal) details = 1;
  glPolygonMode(GL_FRONT_AND_BACK, polygonStyle);
  subdivision(p00, p10, p11, p01, tex00, tex10, tex11, tex01, clippingRect,
              details);

  if (!wireframe) {
    // abilito l'antialiasing delle linee
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);

    // disegno il bordo del poligono
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glBegin(GL_QUADS);
    glTexCoord2d(tex00.x, tex00.y);
    tglVertex(p00);
    glTexCoord2d(tex10.x, tex10.y);
    tglVertex(p10);
    glTexCoord2d(tex11.x, tex11.y);
    tglVertex(p11);
    glTexCoord2d(tex01.x, tex01.y);
    tglVertex(p01);
    glEnd();

    // disabilito l'antialiasing per le linee
    glDisable(GL_LINE_SMOOTH);
    glDisable(GL_BLEND);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisable(GL_TEXTURE_2D);
  }

  // force to finish
  glFlush();

  // rimetto il disegno dei poligoni a GL_FILL
  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

  // metto il frame buffer nel raster del tile
  glPixelStorei(GL_UNPACK_ROW_LENGTH, rasterWidth);
  glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

  TRaster32P newRas(tile.getRaster()->getLx(), tile.getRaster()->getLy());
  newRas->lock();
  glReadPixels(1, 1, newRas->getLx(), newRas->getLy(), GL_RGBA,
               GL_UNSIGNED_BYTE, (void *)newRas->getRawData());
  newRas->unlock();
  checkErrorsByGL

      rasaux->unlock();

  tile.getRaster()->copy(newRas);
}
Beispiel #29
0
void subdivision(const TPointD &p00, const TPointD &p10, const TPointD &p11,
                 const TPointD &p01, const TPointD &tex00, const TPointD &tex10,
                 const TPointD &tex11, const TPointD &tex01,
                 const TRectD &clippingRect, int details) {
  if (details == 1) {
    glBegin(GL_QUADS);

    glTexCoord2d(tex00.x, tex00.y);
    tglVertex(p00);

    glTexCoord2d(tex10.x, tex10.y);
    tglVertex(p10);

    glTexCoord2d(tex11.x, tex11.y);
    tglVertex(p11);

    glTexCoord2d(tex01.x, tex01.y);
    tglVertex(p01);

    glEnd();
  } else {
    TPointD A = p00;
    TPointD B = p10;
    TPointD C = p11;
    TPointD D = p01;

    /*
*     D                L2               C
*     +----------------+----------------+
*     |                |                |
*     |                |                |
*     |                |                |
*     |                |                |
*     |                |                |
*  H1 +----------------+----------------+ H2
*     |                | M              |
*     |                |                |
*     |                |                |
*     |                |                |
*     |                |                |
*     +----------------+----------------+
*     A                L1               B
*
*/

    TPointD M, L1, L2, H1, H2, P1, P2;
    bool intersection;

    // M
    intersection = lineIntersection(A, C, B, D, M);
    assert(intersection);

    // P1 (punto di fuga)
    intersection = lineIntersection(D, C, A, B, P1);
    if (!intersection) {
      P1.x = 0.5 * (A.x + D.x);
      P1.y = 0.5 * (A.y + D.y);
    }
    // H1
    intersection = lineIntersection(A, D, P1, M, H1);
    assert(intersection);

    // H2
    intersection = lineIntersection(B, C, P1, M, H2);
    assert(intersection);

    // P2 (punto di fuga)
    intersection = lineIntersection(A, D, B, C, P2);
    if (!intersection) {
      P2.x = 0.5 * (A.x + B.x);
      P2.y = 0.5 * (A.y + B.y);
    }
    // L1
    intersection = lineIntersection(A, B, P2, M, L1);
    assert(intersection);

    // L2
    intersection = lineIntersection(D, C, P2, M, L2);
    assert(intersection);

    TPointD texA = (tex00 + tex10) * 0.5;
    TPointD texB = (tex10 + tex11) * 0.5;
    TPointD texC = (tex11 + tex01) * 0.5;
    TPointD texD = (tex01 + tex00) * 0.5;
    TPointD texM = (texA + texC) * 0.5;

    details--;

    TRectD r1 = TRectD(
        std::min({A.x, L1.x, M.x, H1.x}), std::min({A.y, L1.y, M.y, H1.y}),
        std::max({A.x, L1.x, M.x, H1.x}), std::max({A.y, L1.y, M.y, H1.y}));

    TRectD r2 = TRectD(
        std::min({L1.x, B.x, H2.x, M.x}), std::min({L1.y, B.y, H2.y, M.y}),
        std::max({L1.x, B.x, H2.x, M.x}), std::max({L1.y, B.y, H2.y, M.y}));

    TRectD r3 = TRectD(
        std::min({M.x, H2.x, C.x, L2.x}), std::min({M.y, H2.y, C.y, L2.y}),
        std::max({M.x, H2.x, C.x, L2.x}), std::max({M.y, H2.y, C.y, L2.y}));

    TRectD r4 = TRectD(
        std::min({H1.x, M.x, L2.x, D.x}), std::min({H1.y, M.y, L2.y, D.y}),
        std::max({H1.x, M.x, L2.x, D.x}), std::max({H1.y, M.y, L2.y, D.y}));

    if (r1.overlaps(clippingRect))
      subdivision(A, L1, M, H1, tex00, texA, texM, texD, clippingRect, details);

    if (r2.overlaps(clippingRect))
      subdivision(L1, B, H2, M, texA, tex10, texB, texM, clippingRect, details);

    if (r3.overlaps(clippingRect))
      subdivision(M, H2, C, L2, texM, texB, tex11, texC, clippingRect, details);

    if (r4.overlaps(clippingRect))
      subdivision(H1, M, L2, D, texD, texM, texC, tex01, clippingRect, details);
  }
}
Beispiel #30
0
  void doCompute(TTile &tile, double frame,
                 const TRenderSettings &info) override {
    bool isWarped = m_warped.isConnected();

    if (!isWarped) return;

    if (fabs(m_intensity->getValue(frame)) < 0.01) {
      m_warped->compute(tile, frame, info);
      return;
    }

    int shrink      = (info.m_shrinkX + info.m_shrinkY) / 2;
    double scale    = sqrt(fabs(info.m_affine.det()));
    double gridStep = 1.5 * m_gridStep->getValue(frame);

    WarpParams params;
    params.m_intensity   = m_intensity->getValue(frame) / gridStep;
    params.m_warperScale = scale * gridStep;
    params.m_sharpen     = m_sharpen->getValue();
    params.m_shrink      = shrink;
    double period        = m_period->getValue(frame) / info.m_shrinkX;
    double count         = m_count->getValue(frame);
    double cycle         = m_cycle->getValue(frame) / info.m_shrinkX;
    double scaleX        = m_scaleX->getValue(frame) / 100.0;
    double scaleY        = m_scaleY->getValue(frame) / 100.0;
    double angle         = -m_angle->getValue(frame);
    TPointD center       = m_center->getValue(frame) * (1.0 / info.m_shrinkX);

    // The warper is calculated on a standard reference, with fixed dpi. This
    // makes sure
    // that the lattice created for the warp does not depend on camera
    // transforms and resolution.
    TRenderSettings warperInfo(info);
    double warperScaleFactor = 1.0 / params.m_warperScale;
    warperInfo.m_affine      = TScale(warperScaleFactor) * info.m_affine;

    // Retrieve tile's geometry
    TRectD tileRect;
    {
      TRasterP tileRas = tile.getRaster();
      tileRect =
          TRectD(tile.m_pos, TDimensionD(tileRas->getLx(), tileRas->getLy()));
    }

    // Build the compute rect
    TRectD warpedBox, warpedComputeRect, tileComputeRect;
    m_warped->getBBox(frame, warpedBox, info);

    getWarpComputeRects(tileComputeRect, warpedComputeRect, warpedBox, tileRect,
                        params);

    if (tileComputeRect.getLx() <= 0 || tileComputeRect.getLy() <= 0) return;
    if (warpedComputeRect.getLx() <= 0 || warpedComputeRect.getLy() <= 0)
      return;

    TRectD warperComputeRect(TScale(warperScaleFactor) * tileComputeRect);
    double warperEnlargement = getWarperEnlargement(params);
    warperComputeRect        = warperComputeRect.enlarge(warperEnlargement);
    warperComputeRect.x0     = tfloor(warperComputeRect.x0);
    warperComputeRect.y0     = tfloor(warperComputeRect.y0);
    warperComputeRect.x1     = tceil(warperComputeRect.x1);
    warperComputeRect.y1     = tceil(warperComputeRect.y1);

    // Compute the warped tile
    TTile tileIn;
    m_warped->allocateAndCompute(
        tileIn, warpedComputeRect.getP00(),
        TDimension(warpedComputeRect.getLx(), warpedComputeRect.getLy()),
        tile.getRaster(), frame, info);
    TRasterP rasIn = tileIn.getRaster();

    // Compute the warper tile
    TSpectrum::ColorKey colors[] = {TSpectrum::ColorKey(0, TPixel32::White),
                                    TSpectrum::ColorKey(0.5, TPixel32::Black),
                                    TSpectrum::ColorKey(1, TPixel32::White)};

    TSpectrumParamP ripplecolors = TSpectrumParamP(tArrayCount(colors), colors);

    // Build the multiradial
    warperInfo.m_affine = warperInfo.m_affine * TTranslation(center) *
                          TRotation(angle) * TScale(scaleX, scaleY);
    TAffine aff      = warperInfo.m_affine.inv();
    TPointD posTrasf = aff * (warperComputeRect.getP00());
    TRasterP rasWarper =
        rasIn->create(warperComputeRect.getLx(), warperComputeRect.getLy());
    multiRadial(rasWarper, posTrasf, ripplecolors, period, count, cycle, aff,
                frame);
    // TImageWriter::save(TFilePath("C:\\ripple.tif"), rasWarper);

    // Warp
    TPointD db;
    TRect rasComputeRectI(convert(tileComputeRect - tileRect.getP00(), db));
    TRasterP tileRas = tile.getRaster()->extract(rasComputeRectI);

    TPointD rasInPos(warpedComputeRect.getP00() - tileComputeRect.getP00());
    TPointD warperPos(
        (TScale(params.m_warperScale) * warperComputeRect.getP00()) -
        tileComputeRect.getP00());
    warp(tileRas, rasIn, rasWarper, rasInPos, warperPos, params);
  }