Esempio n. 1
0
void RenderTask::onFrameFailed(TException &e) {
  // TRasterP evenRas(m_evenTile.getRaster());

  TRenderPort::RenderData rd(m_frames, m_info, m_tileA.getRaster(),
                             m_tileB.getRaster(), m_renderId, m_taskId);
  m_rendererImp->notifyRasterFailure(rd, e);
}
Esempio n. 2
0
void RenderTask::releaseTiles() {
  m_rendererImp->m_rasterPool.releaseRaster(m_tileA.getRaster());
  m_tileA.setRaster(TRasterP());
  if (m_fieldRender || m_stereoscopic) {
    m_rendererImp->m_rasterPool.releaseRaster(m_tileB.getRaster());
    m_tileB.setRaster(TRasterP());
  }
}
Esempio n. 3
0
	void doCompute(TTile &tile, double frame, const TRenderSettings &ri)
	{
		if (!m_input.isConnected())
			return;

		m_input->compute(tile, frame, ri);

		double v = 1 - m_value->getValue(frame) / 100;
		TRop::rgbmScale(tile.getRaster(), tile.getRaster(), 1, 1, 1, v);
	}
Esempio n. 4
0
void ColumnColorFilterFx::doCompute(TTile &tile, double frame,
                                    const TRenderSettings &ri) {
  if (!m_port.isConnected()) return;

  if (!TRaster32P(tile.getRaster()) && !TRaster64P(tile.getRaster()))
    throw TException("AffineFx unsupported pixel type");

  TRasterFxP src = m_port.getFx();
  src->compute(tile, frame, ri);

  TRop::applyColorScale(tile.getRaster(), m_colorFilter);
}
Esempio n. 5
0
/*------------------------------------------------------------
 背景があり、前景が動かない場合、単純にOverする
------------------------------------------------------------*/
void Iwa_MotionBlurCompFx::composeWithNoMotion(
    TTile &tile, double frame, const TRenderSettings &settings) {
  assert(m_background.isConnected());

  m_background->compute(tile, frame, settings);

  TTile fore_tile;
  m_input->allocateAndCompute(fore_tile, tile.m_pos,
                              tile.getRaster()->getSize(), tile.getRaster(),
                              frame, settings);

  TRasterP up(fore_tile.getRaster()), down(tile.getRaster());
  TRop::over(down, up);
}
Esempio n. 6
0
bool TCacheResource::downloadAll(TTile &tile)
{
	if (!checkTile(tile))
		return false;

	return downloadAll(TPoint(tile.m_pos.x, tile.m_pos.y), tile.getRaster());
}
Esempio n. 7
0
bool TCacheResource::upload(const TTile &tile)
{
	if (!checkTile(tile))
		return false;

	return upload(TPoint(tile.m_pos.x, tile.m_pos.y), tile.getRaster());
}
Esempio n. 8
0
QRegion TCacheResource::download(TTile &tile)
{
	if (!checkTile(tile))
		return QRegion();

	return download(TPoint(tile.m_pos.x, tile.m_pos.y), tile.getRaster());
}
void SwatchViewer::ContentRender::run()
{
	if (suspendedRendering)
		return;

	unsigned long renderId = TRenderer::buildRenderId();

	TPassiveCacheManager::instance()->setContextName(renderId, "S");

	m_viewer->m_renderer.install(renderId);
	m_viewer->m_renderer.declareRenderStart(renderId);
	m_viewer->m_renderer.declareFrameStart(m_frame);

	TRenderSettings info;
	info.m_isSwatch = true;
	info.m_affine = m_aff;

	TTile tile;
	m_fx->allocateAndCompute(tile, -0.5 * TPointD(m_size.lx, m_size.ly), m_size, 0, (double)m_frame, info);
	m_raster = tile.getRaster();

	m_viewer->m_renderer.declareFrameEnd(m_frame);
	m_viewer->m_renderer.declareRenderEnd(renderId);
	m_viewer->m_renderer.uninstall();
}
Esempio n. 10
0
  void doCompute(TTile &tile, double frame, const TRenderSettings &ri) {
    if (!m_port.isConnected()) {
      tile.getRaster()->clear();
      return;
    }

    // Exchange frame with the stored one
    TRasterFxP(m_port.getFx())->compute(tile, m_frame, ri);
  }
Esempio n. 11
0
void RenderTask::onFrameCompleted() {
  TRasterP rasA(m_tileA.getRaster());
  TRasterP rasB(m_tileB.getRaster());

  if (m_fieldRender) {
    assert(rasB);

    double t = m_frames[0];

    int f = (m_info.m_fieldPrevalence == TRenderSettings::EvenField) ? 0 : 1;
    interlace(rasA, rasB, f);
    rasB = TRasterP();
  }

  TRenderPort::RenderData rd(m_frames, m_info, rasA, rasB, m_renderId,
                             m_taskId);
  m_rendererImp->notifyRasterCompleted(rd);
}
Esempio n. 12
0
  void doCompute(TTile &tile, double frame,
                 const TRenderSettings &ri) override {
    if (!m_input.isConnected()) return;

    m_input->compute(tile, frame, ri);

    TRop::invert(tile.getRaster(), m_redChan->getValue(),
                 m_greenChan->getValue(), m_blueChan->getValue(),
                 m_alphaChan->getValue());
  }
Esempio n. 13
0
void TGeometryFx::doCompute(TTile &tile, double frame,
                            const TRenderSettings &ri) {
  TRasterFxPort *input = dynamic_cast<TRasterFxPort *>(getInputPort(0));
  assert(input);

  if (!input->isConnected()) return;

  if (!getActiveTimeRegion().contains(frame)) {
    TRasterFxP(input->getFx())->compute(tile, frame, ri);
    return;
  }

  if (!TRaster32P(tile.getRaster()) && !TRaster64P(tile.getRaster()))
    throw TException("AffineFx unsupported pixel type");

  TAffine aff1 = getPlacement(frame);
  TRenderSettings ri2(ri);
  ri2.m_affine = ri2.m_affine * aff1;

  TRasterFxP src = getInputPort("source")->getFx();
  src->compute(tile, frame, ri2);
  return;
}
Esempio n. 14
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);
  }
Esempio n. 15
0
void Iwa_MotionBlurCompFx::doCompute_CPU(
    TTile &tile, double frame, const TRenderSettings &settings,
    float4 *pointsTable, int pointAmount, double hardness, double shutterStart,
    double shutterEnd, int traceResolution, float startValue, float startCurve,
    float endValue, float endCurve, int marginLeft, int marginRight,
    int marginTop, int marginBottom, TDimensionI &enlargedDimIn,
    TTile &enlarge_tile, TDimensionI &dimOut, TDimensionI &filterDim,
    TTile &back_tile) {
  /*- 処理を行うメモリ -*/
  float4 *in_tile_p;  /*- マージンあり -*/
  float4 *out_tile_p; /*- マージンあり -*/
  /*- フィルタ -*/
  float *filter_p;

  /*- メモリ確保 -*/
  TRasterGR8P in_tile_ras(sizeof(float4) * enlargedDimIn.lx, enlargedDimIn.ly);
  in_tile_ras->lock();
  in_tile_p = (float4 *)in_tile_ras->getRawData();
  TRasterGR8P out_tile_ras(sizeof(float4) * enlargedDimIn.lx, enlargedDimIn.ly);
  out_tile_ras->lock();
  out_tile_p = (float4 *)out_tile_ras->getRawData();
  TRasterGR8P filter_ras(sizeof(float) * filterDim.lx, filterDim.ly);
  filter_ras->lock();
  filter_p = (float *)filter_ras->getRawData();

  bool sourceIsPremultiplied;
  /*- ソース画像を0〜1に正規化してメモリに読み込む -*/
  TRaster32P ras32 = (TRaster32P)enlarge_tile.getRaster();
  TRaster64P ras64 = (TRaster64P)enlarge_tile.getRaster();
  if (ras32)
    sourceIsPremultiplied = setSourceRaster<TRaster32P, TPixel32>(
        ras32, in_tile_p, enlargedDimIn,
        (PremultiTypes)m_premultiType->getValue());
  else if (ras64)
    sourceIsPremultiplied = setSourceRaster<TRaster64P, TPixel64>(
        ras64, in_tile_p, enlargedDimIn,
        (PremultiTypes)m_premultiType->getValue());

  /*- 残像モードがオフのとき -*/
  if (!m_zanzoMode->getValue()) {
    /*- フィルタをつくり、正規化する -*/
    makeMotionBlurFilter_CPU(filter_p, filterDim, marginLeft, marginBottom,
                             pointsTable, pointAmount, startValue, startCurve,
                             endValue, endCurve);
  }
  /*- 残像モードがオンのとき -*/
  else {
    /*- 残像フィルタをつくる/正規化する -*/
    makeZanzoFilter_CPU(filter_p, filterDim, marginLeft, marginBottom,
                        pointsTable, pointAmount, startValue, startCurve,
                        endValue, endCurve);
  }

  delete[] pointsTable;

  /*- RGB値(0〜1)をdepremultiply→露光値に変換→再びpremultiply -*/
  convertRGBtoExposure_CPU(in_tile_p, enlargedDimIn, hardness,
                           sourceIsPremultiplied);

  /*- 露光値をフィルタリングしてぼかす -*/
  applyBlurFilter_CPU(in_tile_p, out_tile_p, enlargedDimIn, filter_p, filterDim,
                      marginLeft, marginBottom, marginRight, marginTop, dimOut);
  /*- メモリ解放 -*/
  in_tile_ras->unlock();
  filter_ras->unlock();

  /*- 背景がある場合、Exposureの乗算を行う -*/
  if (m_background.isConnected()) {
    composeBackgroundExposure_CPU(out_tile_p, enlargedDimIn, marginRight,
                                  marginTop, back_tile, dimOut,
                                  (float)hardness);
  }
  /*- 露光値をdepremultipy→RGB値(0〜1)に戻す→premultiply -*/
  convertExposureToRGB_CPU(out_tile_p, enlargedDimIn, hardness);

  /*- ラスタのクリア -*/
  tile.getRaster()->clear();
  TRaster32P outRas32 = (TRaster32P)tile.getRaster();
  TRaster64P outRas64 = (TRaster64P)tile.getRaster();
  int2 margin         = {marginRight, marginTop};
  if (outRas32)
    setOutputRaster<TRaster32P, TPixel32>(out_tile_p, outRas32, enlargedDimIn,
                                          margin);
  else if (outRas64)
    setOutputRaster<TRaster64P, TPixel64>(out_tile_p, outRas64, enlargedDimIn,
                                          margin);

  /*- メモリ解放 -*/
  out_tile_ras->unlock();
}
Esempio n. 16
0
bool TCacheResource::canUpload(const TTile &tile) const
{
	int tileType;
	return checkTile(tile) && checkRasterType(tile.getRaster(), tileType);
}
/*- render_particles から呼ばれる。粒子の数だけ繰り返し -*/
void Particles_Engine::do_render(
    TFlash *flash, Particle *part, TTile *tile,
    std::vector<TRasterFxPort *> part_ports, std::map<int, TTile *> porttiles,
    const TRenderSettings &ri, TDimension &p_size, TPointD &p_offset,
    int lastframe, std::vector<TLevelP> partLevel,
    struct particles_values &values, double opacity_range, int dist_frame,
    std::map<std::pair<int, int>, double> &partScales) {
  // Retrieve the particle frame - that is, the *column frame* from which we are
  // picking
  // the particle to be rendered.
  int ndx = part->frame % lastframe;

  TRasterP tileRas(tile->getRaster());

  std::string levelid;
  double aim_angle = 0;
  if (values.pathaim_val) {
    double arctan = atan2(part->vy, part->vx);
    aim_angle     = arctan * M_180_PI;
  }

  // Calculate the rotational and scale components we have to apply on the
  // particle
  TRotation rotM(part->angle + aim_angle);
  TScale scaleM(part->scale);
  TAffine M(rotM * scaleM);

  // Particles deal with dpi affines on their own
  TAffine scaleAff(m_parent->handledAffine(ri, m_frame));
  double partScale =
      scaleAff.a11 * partScales[std::pair<int, int>(part->level, ndx)];
  TDimensionD partResolution(0, 0);
  TRenderSettings riNew(ri);

  // Retrieve the bounding box in the standard reference
  TRectD bbox(-5.0, -5.0, 5.0, 5.0), standardRefBBox;
  if (part->level <
          (int)part_ports.size() &&  // Not the default levelless cases
      part_ports[part->level]->isConnected()) {
    TRenderSettings riIdentity(ri);
    riIdentity.m_affine = TAffine();

    (*part_ports[part->level])->getBBox(ndx, bbox, riIdentity);

    // A particle's bbox MUST be finite. Gradients and such which have an
    // infinite bbox
    // are just NOT rendered.

    // NOTE: No fx returns half-planes or similar (ie if any coordinate is
    // either
    // (std::numeric_limits<double>::max)() or its opposite, then the rect IS
    // THE infiniteRectD)
    if (bbox == TConsts::infiniteRectD) return;
  }

  // Now, these are the particle rendering specifications
  bbox            = bbox.enlarge(3);
  standardRefBBox = bbox;
  riNew.m_affine  = TScale(partScale);
  bbox            = riNew.m_affine * bbox;
  /*- 縮小済みのParticleのサイズ -*/
  partResolution = TDimensionD(tceil(bbox.getLx()), tceil(bbox.getLy()));

  if (flash) {
    if (!partLevel[part->level]->frame(ndx)) {
      if (part_ports[0]->isConnected()) {
        TTile auxTile;
        TRaster32P tmp;
        tmp = TRaster32P(p_size);
        (*part_ports[0])
            ->allocateAndCompute(auxTile, p_offset, p_size, tmp, ndx, ri);
        partLevel[part->level]->setFrame(ndx,
                                         TRasterImageP(auxTile.getRaster()));
      }
    }

    flash->pushMatrix();

    const TAffine aff;

    flash->multMatrix(scaleM * aff.place(0, 0, part->x, part->y));

    // if(curr_opacity!=1.0 || part->gencol.fadecol || part->fincol.fadecol ||
    // part->foutcol.fadecol)
    {
      TColorFader cf(TPixel32::Red, .5);
      flash->draw(partLevel[part->level]->frame(ndx), &cf);
    }
    // flash->draw(partLevel->frame(ndx), 0);

    flash->popMatrix();
  } else {
    TRasterP ras;

    std::string alias;
    TRasterImageP rimg;
    if (rimg = partLevel[part->level]->frame(ndx)) {
      ras = rimg->getRaster();
    } else {
      alias = "PART: " + (*part_ports[part->level])->getAlias(ndx, riNew);
      if (rimg = TImageCache::instance()->get(alias, false)) {
        ras = rimg->getRaster();

        // Check that the raster resolution is sufficient for our purposes
        if (ras->getLx() < partResolution.lx ||
            ras->getLy() < partResolution.ly)
          ras = 0;
        else
          partResolution = TDimensionD(ras->getLx(), ras->getLy());
      }
    }

    // We are interested in making the relation between scale and (integer)
    // resolution
    // bijective - since we shall cache by using resolution as a partial
    // identification parameter.
    // Therefore, we find the current bbox Lx and take a unique scale out of it.
    partScale      = partResolution.lx / standardRefBBox.getLx();
    riNew.m_affine = TScale(partScale);
    bbox           = riNew.m_affine * standardRefBBox;

    // If no image was retrieved from the cache (or it was not scaled enough),
    // calculate it
    if (!ras) {
      TTile auxTile;
      (*part_ports[part->level])
          ->allocateAndCompute(auxTile, bbox.getP00(),
                               TDimension(partResolution.lx, partResolution.ly),
                               tile->getRaster(), ndx, riNew);
      ras = auxTile.getRaster();

      // For now, we'll just use 32 bit particles
      TRaster32P rcachepart;
      rcachepart = ras;
      if (!rcachepart) {
        rcachepart = TRaster32P(ras->getSize());
        TRop::convert(rcachepart, ras);
      }
      ras = rcachepart;

      // Finally, cache the particle
      addRenderCache(alias, TRasterImageP(ras));
    }

    if (!ras) return;  // At this point, it should never happen anyway...

    // Deal with particle colors/opacity
    TRaster32P rfinalpart;
    double curr_opacity =
        part->set_Opacity(porttiles, values, opacity_range, dist_frame);
    if (curr_opacity != 1.0 || part->gencol.fadecol || part->fincol.fadecol ||
        part->foutcol.fadecol) {
      /*- 毎フレーム現在位置のピクセル色を参照 -*/
      if (values.pick_color_for_every_frame_val && values.gencol_ctrl_val &&
          (porttiles.find(values.gencol_ctrl_val) != porttiles.end()))
        part->get_image_reference(porttiles[values.gencol_ctrl_val], values,
                                  part->gencol.col);

      rfinalpart = ras->clone();
      part->modify_colors_and_opacity(values, curr_opacity, dist_frame,
                                      rfinalpart);
    } else
      rfinalpart = ras;

    // Now, let's build the particle transform before it is overed on the output
    // tile

    // First, complete the transform by adding the rotational and scale
    // components from
    // Particles parameters
    M = ri.m_affine * M * TScale(1.0 / partScale);

    // Then, retrieve the particle position in current reference.
    TPointD pos(part->x, part->y);
    pos = ri.m_affine * pos;

    // Finally, add the translational component to the particle
    // NOTE: p_offset is added to account for the particle relative position
    // inside its level's bbox
    M = TTranslation(pos - tile->m_pos) * M * TTranslation(bbox.getP00());

    if (TRaster32P myras32 = tile->getRaster())
      TRop::over(tileRas, rfinalpart, M);
    else if (TRaster64P myras64 = tile->getRaster())
      TRop::over(tileRas, rfinalpart, M);
    else
      throw TException("ParticlesFx: unsupported Pixel Type");
  }
}
Esempio n. 18
0
void Iwa_TiledParticlesFx::doCompute(TTile &tile, double frame, const TRenderSettings &ri)
{
	std::vector<int> lastframe;
	std::vector<TLevelP> partLevel;

	TPointD p_offset;
	TDimension p_size(0, 0);

	/*- 参照画像ポートの取得 -*/
	std::vector<TRasterFxPort *> part_ports;   /*- テクスチャ素材画像のポート -*/
	std::map<int, TRasterFxPort *> ctrl_ports; /*- コントロール画像のポート番号/ポート -*/
	int portsCount = this->getInputPortCount();

	for (int i = 0; i < portsCount; ++i) {
		std::string tmpName = this->getInputPortName(i);
		QString portName = QString::fromStdString(tmpName);

		if (portName.startsWith("T")) {
			TRasterFxPort *tmpPart = (TRasterFxPort *)this->getInputPort(tmpName);
			if (tmpPart->isConnected())
				part_ports.push_back((TRasterFxPort *)this->getInputPort(tmpName));
		} else {
			portName.replace(QString("Control"), QString(""));
			TRasterFxPort *tmpCtrl = (TRasterFxPort *)this->getInputPort(tmpName);
			if (tmpCtrl->isConnected())
				ctrl_ports[portName.toInt()] = (TRasterFxPort *)this->getInputPort(tmpName);
		}
	}

	/*- テクスチャ素材のバウンディングボックスを足し合わせる ←この工程、いらないかも?-*/
	if (!part_ports.empty()) {
		TRectD outTileBBox(tile.m_pos, TDimensionD(tile.getRaster()->getLx(), tile.getRaster()->getLy()));
		TRectD bbox;

		for (unsigned int i = 0; i < (int)part_ports.size(); ++i) {
			const TFxTimeRegion &tr = (*part_ports[i])->getTimeRegion();

			lastframe.push_back(tr.getLastFrame() + 1);
			partLevel.push_back(new TLevel());
			partLevel[i]->setName((*part_ports[i])->getAlias(0, ri));

			// The particles offset must be calculated without considering the affine's translational
			// component
			TRenderSettings riZero(ri);
			riZero.m_affine.a13 = riZero.m_affine.a23 = 0;

			// Calculate the bboxes union
			for (int t = 0; t <= tr.getLastFrame(); ++t) {
				TRectD inputBox;
				(*part_ports[i])->getBBox(t, inputBox, riZero);
				bbox += inputBox;
			}
		}

		if (bbox == TConsts::infiniteRectD)
			bbox *= outTileBBox;

		p_size.lx = (int)bbox.getLx() + 1;
		p_size.ly = (int)bbox.getLy() + 1;
		p_offset = TPointD(0.5 * (bbox.x0 + bbox.x1), 0.5 * (bbox.y0 + bbox.y1));
	} else {
		partLevel.push_back(new TLevel());
		partLevel[0]->setName("particles");
		TDimension vecsize(10, 10);
		TOfflineGL *offlineGlContext = new TOfflineGL(vecsize);
		offlineGlContext->clear(TPixel32(0, 0, 0, 0));

		TStroke *stroke;
		stroke = makeEllipticStroke(0.07, TPointD((vecsize.lx - 1) * .5, (vecsize.ly - 1) * .5), 2.0, 2.0);
		TVectorImageP vectmp = new TVectorImage();

		TPalette *plt = new TPalette();
		vectmp->setPalette(plt);
		vectmp->addStroke(stroke);
		TVectorRenderData rd(AffI, TRect(vecsize), plt, 0, true, true);
		offlineGlContext->makeCurrent();
		offlineGlContext->draw(vectmp, rd);

		partLevel[0]->setFrame(0, TRasterImageP(offlineGlContext->getRaster()->clone()));
		p_size.lx = vecsize.lx + 1;
		p_size.ly = vecsize.ly + 1;
		lastframe.push_back(1);

		delete offlineGlContext;
	}

	Iwa_Particles_Engine myEngine(this, frame);

	// Retrieving the dpi multiplier from the accumulated affine (which is isotropic). That is,
	// the affine will be applied *before* this effect - and we'll multiply geometrical parameters
	// by this dpi mult. in order to compensate.
	float dpi = sqrt(fabs(ri.m_affine.det())) * 100;

	TTile tileIn;
	if (TRaster32P raster32 = tile.getRaster()) {
		TFlash *flash = 0;
		myEngine.render_particles(flash, &tile, part_ports, ri, p_size, p_offset, ctrl_ports, partLevel,
								  1, (int)frame, 1, 0, 0, 0, 0, lastframe, getIdentifier());
	} else if (TRaster64P raster64 = tile.getRaster()) {
		TFlash *flash = 0;
		myEngine.render_particles(flash, &tile, part_ports, ri, p_size, p_offset, ctrl_ports, partLevel,
								  1, (int)frame, 1, 0, 0, 0, 0, lastframe, getIdentifier());
	} else
		throw TException("ParticlesFx: unsupported Pixel Type");
}
Esempio n. 19
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);
}
void Particles_Engine::render_particles(
    TFlash *flash, TTile *tile, std::vector<TRasterFxPort *> part_ports,
    const TRenderSettings &ri, TDimension &p_size, TPointD &p_offset,
    std::map<int, TRasterFxPort *> ctrl_ports, std::vector<TLevelP> partLevel,
    float dpi, int curr_frame, int shrink, double startx, double starty,
    double endx, double endy, std::vector<int> last_frame, unsigned long fxId) {
  int frame, startframe, intpart = 0, level_n = 0;
  struct particles_values values;
  double dpicorr = dpi * 0.01, fractpart = 0, dpicorr_shrinked = 0,
         opacity_range = 0;
  bool random_level    = false;
  level_n              = part_ports.size();

  bool isPrecomputingEnabled = false;
  {
    TRenderer renderer(TRenderer::instance());
    isPrecomputingEnabled =
        (renderer && renderer.isPrecomputingEnabled()) ? true : false;
  }

  memset(&values, 0, sizeof(values));
  /*- 現在のフレームでの各種パラメータを得る -*/
  fill_value_struct(values, m_frame);
  /*- 不透明度の範囲(透明〜不透明を 0〜1 に正規化)-*/
  opacity_range = (values.opacity_val.second - values.opacity_val.first) * 0.01;
  /*- 開始フレーム -*/
  startframe = (int)values.startpos_val;
  if (values.unit_val == ParticlesFx::UNIT_SMALL_INCH)
    dpicorr_shrinked = dpicorr / shrink;
  else
    dpicorr_shrinked = dpi / shrink;

  std::map<std::pair<int, int>, double> partScales;
  curr_frame = curr_frame / values.step_val;

  ParticlesManager *pc = ParticlesManager::instance();

  // Retrieve the last rolled frame
  ParticlesManager::FrameData *particlesData = pc->data(fxId);

  std::list<Particle> myParticles;
  TRandom myRandom;
  values.random_val  = &myRandom;
  myRandom           = m_parent->randseed_val->getValue();
  int totalparticles = 0;

  int pcFrame = particlesData->m_frame;
  if (pcFrame > curr_frame) {
    // Clear stored particlesData
    particlesData->clear();
    pcFrame = particlesData->m_frame;
  } else if (pcFrame >= startframe - 1) {
    myParticles    = particlesData->m_particles;
    myRandom       = particlesData->m_random;
    totalparticles = particlesData->m_totalParticles;
  }
  /*- スタートからカレントフレームまでループ -*/
  for (frame = startframe - 1; frame <= curr_frame; ++frame) {
    int dist_frame = curr_frame - frame;
    /*-
     * ループ内の現在のフレームでのパラメータを取得。スタートが負ならフレーム=0のときの値を格納
     * -*/
    fill_value_struct(values, frame < 0 ? 0 : frame * values.step_val);
    /*- パラメータの正規化 -*/
    normalize_values(values, ri);
    /*- maxnum_valは"birth_rate"のパラメータ -*/
    intpart = (int)values.maxnum_val;
    /*-
     * /birth_rateが小数だったとき、各フレームの小数部分を足しこんだ結果の整数部分をintpartに渡す。
     * -*/
    fractpart = fractpart + values.maxnum_val - intpart;
    if ((int)fractpart) {
      values.maxnum_val += (int)fractpart;
      fractpart = fractpart - (int)fractpart;
    }

    std::map<int, TTile *> porttiles;

    // Perform the roll
    /*- RenderSettingsを複製して現在のフレームの計算用にする -*/
    TRenderSettings riAux(ri);
    riAux.m_affine = TAffine();
    riAux.m_bpp    = 32;

    int r_frame;  // Useful in case of negative roll frames
    if (frame < 0)
      r_frame = 0;
    else
      r_frame = frame;
    /*- 出力画像のバウンディングボックス -*/
    TRectD outTileBBox(tile->m_pos, TDimensionD(tile->getRaster()->getLx(),
                                                tile->getRaster()->getLy()));
    /*- Controlに刺さっている各ポートについて -*/
    for (std::map<int, TRasterFxPort *>::iterator it = ctrl_ports.begin();
         it != ctrl_ports.end(); ++it) {
      TTile *tmp;
      /*- ポートが接続されていて、Fx内で実際に使用されていたら -*/
      if ((it->second)->isConnected() && port_is_used(it->first, values)) {
        TRectD bbox;
        (*(it->second))->getBBox(r_frame, bbox, riAux);
        /*- 素材が存在する場合、portTilesにコントロール画像タイルを格納 -*/
        if (!bbox.isEmpty()) {
          if (bbox == TConsts::infiniteRectD)  // There could be an infinite
                                               // bbox - deal with it
            bbox = ri.m_affine.inv() * outTileBBox;

          if (frame <= pcFrame) {
            // This frame will not actually be rolled. However, it was
            // dryComputed - so, declare the same here.
            (*it->second)->dryCompute(bbox, r_frame, riAux);
          } else {
            tmp = new TTile;

            if (isPrecomputingEnabled)
              (*it->second)
                  ->allocateAndCompute(*tmp, bbox.getP00(),
                                       convert(bbox).getSize(), 0, r_frame,
                                       riAux);
            else {
              std::string alias =
                  "CTRL: " + (*(it->second))->getAlias(r_frame, riAux);
              TRasterImageP rimg = TImageCache::instance()->get(alias, false);

              if (rimg) {
                tmp->m_pos = bbox.getP00();
                tmp->setRaster(rimg->getRaster());
              } else {
                (*it->second)
                    ->allocateAndCompute(*tmp, bbox.getP00(),
                                         convert(bbox).getSize(), 0, r_frame,
                                         riAux);

                addRenderCache(alias, TRasterImageP(tmp->getRaster()));
              }
            }

            porttiles[it->first] = tmp;
          }
        }
      }
    }

    if (frame > pcFrame) {
      // Invoke the actual rolling procedure
      roll_particles(tile, porttiles, riAux, myParticles, values, 0, 0, frame,
                     curr_frame, level_n, &random_level, 1, last_frame,
                     totalparticles);

      // Store the rolled data in the particles manager
      if (!particlesData->m_calculated ||
          particlesData->m_frame + particlesData->m_maxTrail < frame) {
        particlesData->m_frame     = frame;
        particlesData->m_particles = myParticles;
        particlesData->m_random    = myRandom;
        particlesData->buildMaxTrail();
        particlesData->m_calculated     = true;
        particlesData->m_totalParticles = totalparticles;
      }
    }

    // Render the particles if the distance from current frame is a trail
    // multiple
    if (frame >= startframe - 1 &&
        !(dist_frame %
          (values.trailstep_val > 1.0 ? (int)values.trailstep_val : 1))) {
      // Store the maximum particle size before the do_render cycle
      std::list<Particle>::iterator pt;
      for (pt = myParticles.begin(); pt != myParticles.end(); ++pt) {
        Particle &part = *pt;
        int ndx        = part.frame % last_frame[part.level];
        std::pair<int, int> ndxPair(part.level, ndx);

        std::map<std::pair<int, int>, double>::iterator it =
            partScales.find(ndxPair);

        if (it != partScales.end())
          it->second = std::max(part.scale, it->second);
        else
          partScales[ndxPair] = part.scale;
      }

      if (values.toplayer_val == ParticlesFx::TOP_SMALLER ||
          values.toplayer_val == ParticlesFx::TOP_BIGGER)
        myParticles.sort(ComparebySize());

      if (values.toplayer_val == ParticlesFx::TOP_SMALLER) {
        std::list<Particle>::iterator pt;
        for (pt = myParticles.begin(); pt != myParticles.end(); ++pt) {
          Particle &part = *pt;
          if (dist_frame <= part.trail && part.scale && part.lifetime > 0 &&
              part.lifetime <=
                  part.genlifetime)  // This last... shouldn't always be?
          {
            do_render(flash, &part, tile, part_ports, porttiles, ri, p_size,
                      p_offset, last_frame[part.level], partLevel, values,
                      opacity_range, dist_frame, partScales);
          }
        }
      } else {
        std::list<Particle>::reverse_iterator pt;
        for (pt = myParticles.rbegin(); pt != myParticles.rend(); ++pt) {
          Particle &part = *pt;
          if (dist_frame <= part.trail && part.scale && part.lifetime > 0 &&
              part.lifetime <= part.genlifetime)  // Same here..?
          {
            do_render(flash, &part, tile, part_ports, porttiles, ri, p_size,
                      p_offset, last_frame[part.level], partLevel, values,
                      opacity_range, dist_frame, partScales);
          }
        }
      }
    }

    std::map<int, TTile *>::iterator it;
    for (it = porttiles.begin(); it != porttiles.end(); ++it) delete it->second;
  }
}
Esempio n. 21
0
void Iwa_MotionBlurCompFx::doCompute(TTile &tile, double frame,
                                     const TRenderSettings &settings) {
  /*- 接続していない場合は処理しない -*/
  if (!m_input.isConnected() && !m_background.isConnected()) {
    tile.getRaster()->clear();
    return;
  }
  /*- BGのみ接続の場合 -*/
  if (!m_input.isConnected()) {
    m_background->compute(tile, frame, settings);
    return;
  }

  /*- 動作パラメータを得る -*/
  QList<TPointD> points = getAttributes()->getMotionPoints();
  double hardness       = m_hardness->getValue(frame);
  double shutterStart   = m_shutterStart->getValue(frame);
  double shutterEnd     = m_shutterEnd->getValue(frame);
  int traceResolution   = m_traceResolution->getValue();
  float startValue      = (float)m_startValue->getValue(frame);
  float startCurve      = (float)m_startCurve->getValue(frame);
  float endValue        = (float)m_endValue->getValue(frame);
  float endCurve        = (float)m_endCurve->getValue(frame);

  /*- 軌跡データが2つ以上無い場合は、処理しない -*/
  if (points.size() < 2) {
    if (!m_background.isConnected()) m_input->compute(tile, frame, settings);
    /*- 背景があり、前景が動かない場合、単純にOverする -*/
    else
      composeWithNoMotion(tile, frame, settings);
    return;
  }
  /*-  表示の範囲を得る -*/
  TRectD bBox =
      TRectD(tile.m_pos /*- Render画像上(Pixel単位)の位置 -*/
             ,
             TDimensionD(/*- Render画像上(Pixel単位)のサイズ -*/
                         tile.getRaster()->getLx(), tile.getRaster()->getLy()));

  /*- 上下左右のマージンを得る -*/
  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));

  /*- 動かない(=フィルタマージンが全て0)場合、入力タイルをそのまま返す -*/
  if (marginLeft == 0 && marginRight == 0 && marginTop == 0 &&
      marginBottom == 0) {
    if (!m_background.isConnected()) m_input->compute(tile, frame, settings);
    /*- 背景があり、前景が動かない場合、単純にOverする -*/
    else
      composeWithNoMotion(tile, frame, settings);
    return;
  }

  /*- マージンは、フィルタの上下左右を反転した寸法になる -*/
  TRectD enlargedBBox(bBox.x0 - (double)marginRight,
                      bBox.y0 - (double)marginTop, bBox.x1 + (double)marginLeft,
                      bBox.y1 + (double)marginBottom);

  // std::cout<<"Margin Left:"<<marginLeft<<" Right:"<<marginRight<<
  //	" Bottom:"<<marginBottom<<" Top:"<<marginTop<<std::endl;

  TDimensionI enlargedDimIn(/*- Pixel単位に四捨五入 -*/
                            (int)(enlargedBBox.getLx() + 0.5),
                            (int)(enlargedBBox.getLy() + 0.5));

  TTile enlarge_tile;
  m_input->allocateAndCompute(enlarge_tile, enlargedBBox.getP00(),
                              enlargedDimIn, tile.getRaster(), frame, settings);

  /*- 背景が必要な場合 -*/
  TTile back_Tile;
  if (m_background.isConnected()) {
    m_background->allocateAndCompute(back_Tile, tile.m_pos,
                                     tile.getRaster()->getSize(),
                                     tile.getRaster(), frame, settings);
  }

  //-------------------------------------------------------
  /*- 計算範囲 -*/
  TDimensionI dimOut(tile.getRaster()->getLx(), tile.getRaster()->getLy());
  TDimensionI filterDim(marginLeft + marginRight + 1,
                        marginTop + marginBottom + 1);

  /*- pointsTableの解放は各doCompute内でやっている -*/
  int pointAmount     = points.size();
  float4 *pointsTable = new float4[pointAmount];
  float dt = (float)(shutterStart + shutterEnd) / (float)traceResolution;
  for (int p = 0; p < pointAmount; p++) {
    pointsTable[p].x = (float)points.at(p).x;
    pointsTable[p].y = (float)points.at(p).y;
    /*- zにはp→p+1のベクトルの距離を格納 -*/
    if (p < pointAmount - 1) {
      float2 vec = {(float)(points.at(p + 1).x - points.at(p).x),
                    (float)(points.at(p + 1).y - points.at(p).y)};
      pointsTable[p].z = sqrtf(vec.x * vec.x + vec.y * vec.y);
    }
    /*- wにはシャッター時間のオフセットを格納 -*/
    pointsTable[p].w = -(float)shutterStart + (float)p * dt;
  }

  doCompute_CPU(tile, frame, settings, pointsTable, pointAmount, hardness,
                shutterStart, shutterEnd, traceResolution, startValue,
                startCurve, endValue, endCurve, marginLeft, marginRight,
                marginTop, marginBottom, enlargedDimIn, enlarge_tile, dimOut,
                filterDim, back_Tile);
}
Esempio n. 22
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);
	}
Esempio n. 23
0
  void doCompute(TTile &tile, double frame,
                 const TRenderSettings &ri) override {
    Status status = getFxStatus(m_light, m_lighted);

    if (status & NoPortsConnected)
      // If no port, just do nothing :)
      return;

    // Calculate source
    if (status & Port1Connected) m_lighted->compute(tile, frame, ri);

    // Calculate light
    if (status & Port0Connected) {
      // Init light infos
      TDimension tileSize(tile.getRaster()->getSize());
      TRectD tileRect(tile.m_pos, TDimensionD(tileSize.lx, tileSize.ly));

      double scale = sqrt(fabs(ri.m_affine.det()));
      double blur  = m_value->getValue(frame) * scale;

      // Build the light interesting rect
      TRectD lightRect, blurOutRect;
      m_light->getBBox(frame, lightRect, ri);

      buildLightRects(tileRect, lightRect, blurOutRect, blur);

      if ((lightRect.getLx() <= 0) || (lightRect.getLy() <= 0)) return;
      if ((blurOutRect.getLx() <= 0) || (blurOutRect.getLy() <= 0)) return;

      // Calculate the light tile
      TTile lightTile;
      TDimension lightSize(tround(lightRect.getLx()),
                           tround(lightRect.getLy()));
      m_light->allocateAndCompute(lightTile, lightRect.getP00(), lightSize,
                                  tile.getRaster(), frame, ri);

      // Init glow parameters
      TPixel32 color    = m_color->getValue(frame);
      double brightness = m_brightness->getValue(frame) / 100.0;
      double fade       = m_fade->getValue(frame) / 100.0;

      // Now, apply the glow

      // First, deal with the fade
      {
        TRasterP light     = lightTile.getRaster();
        TRaster32P light32 = light;
        TRaster64P light64 = light;
        if (light32)
          ::fade(light32, fade, color);
        else if (light64)
          ::fade(light64, fade, toPixel64(color));
        else
          assert(false);
      }

      // Then, build the blur
      TRasterP blurOut;
      if (blur > 0) {
        // Build a temporary output to the blur
        {
          TRasterP light(lightTile.getRaster());

          blurOut = light->create(tround(blurOutRect.getLx()),
                                  tround(blurOutRect.getLy()));

          // Apply the blur. Please note that SSE2 should not be used for now -
          // I've seen it
          // doing strange things to the blur...
          TPointD displacement(lightRect.getP00() - blurOutRect.getP00());
          TRop::blur(blurOut, light, blur, tround(displacement.x),
                     tround(displacement.y), false);
        }
      } else
        blurOut = lightTile.getRaster();

      // Apply the rgbm scale
      TRop::rgbmScale(blurOut, blurOut, 1, 1, 1, brightness);

      // Apply the add
      {
        TRectD interestingRect(tileRect * blurOutRect);

        TRect interestingTileRect(tround(interestingRect.x0 - tileRect.x0),
                                  tround(interestingRect.y0 - tileRect.y0),
                                  tround(interestingRect.x1 - tileRect.x0) - 1,
                                  tround(interestingRect.y1 - tileRect.y0) - 1);
        TRect interestingBlurRect(
            tround(interestingRect.x0 - blurOutRect.x0),
            tround(interestingRect.y0 - blurOutRect.y0),
            tround(interestingRect.x1 - blurOutRect.x0) - 1,
            tround(interestingRect.y1 - blurOutRect.y0) - 1);

        if ((interestingTileRect.getLx() <= 0) ||
            (interestingTileRect.getLy() <= 0))
          return;
        if ((interestingBlurRect.getLx() <= 0) ||
            (interestingBlurRect.getLy() <= 0))
          return;

        TRasterP tileInterestRas(
            tile.getRaster()->extract(interestingTileRect));
        TRasterP blurInterestRas(blurOut->extract(interestingBlurRect));
        TRop::add(blurInterestRas, tileInterestRas, tileInterestRas);
      }
    }
  }
Esempio n. 24
0
void TExternalProgramFx::doCompute(TTile &tile, double frame,
                                   const TRenderSettings &ri) {
  TRaster32P ras = tile.getRaster();
  if (!ras) return;
  std::string args           = m_args;
  std::string executablePath = ::to_string(m_executablePath);
  std::map<std::string, TFilePath> tmpFiles;  // portname --> file
  TFilePath outputTmpFile;

  std::map<std::string, Port>::const_iterator portIt;
  for (portIt = m_ports.begin(); portIt != m_ports.end(); ++portIt) {
    TFilePath fp            = TSystem::getUniqueFile("externfx");
    fp                      = fp.withType(portIt->second.m_ext);
    tmpFiles[portIt->first] = fp;
    if (portIt->second.m_port == 0)  // solo una porta e' di output
      outputTmpFile = fp;
    else {
      TRasterFxPort *tmp;
      tmp = portIt->second.m_port;
      if (tmp->isConnected()) {
        (*tmp)->compute(tile, frame, ri);
        TImageWriter::save(fp, ras);
      }
    }
  }

  // args e' della forma "$src $ctrl -o $out -v $value"
  // sostituisco le variabili
  int i = 0;
  for (;;) {
    i = args.find('$', i);
    if (i == (int)std::string::npos) break;
    int j   = i + 1;
    int len = args.length();
    while (j < len && isalnum(args[j])) j++;
    // un '$' non seguito da caratteri alfanumerici va ignorato
    if (j == i + 1) {
      // la sequenza '$$' diventa '$'
      if (j < len && args[j] == '$') args.replace(i, 2, "$");
      i++;
      continue;
    }
    // ho trovato una variabile
    int m            = j - i - 1;
    std::string name = args.substr(i + 1, m);
    // calcolo il valore.
    std::string value;

    std::map<std::string, TFilePath>::const_iterator it;
    it = tmpFiles.find(name);
    if (it != tmpFiles.end()) {
      // e' una porta. il valore e' il nome del
      // file temporaneo
      value = "\"" + ::to_string(it->second.getWideString()) + "\"";
    } else {
      // e' un parametro
      // se il nome non viene riconosciuto sostituisco la stringa nulla
      TDoubleParamP param = TParamP(getParams()->getParam(name));
      if (param) value    = std::to_string(param->getValue(frame));
    }

    args.replace(i, m + 1, value);
  }
  args = " " + args;  // aggiungo uno spazio per sicurezza
  // ofstream os("C:\\temp\\butta.txt");
  // os << args << endl;

  // bisognerebbe calcolare le immagini dalla/e porta/e di input
  // scrivere il/i valore/i nei files temporanei/o
  // chiamare "m_executablePath args"
  // e leggere l'immagine scritta in outputTmpFile
  // poi cancellare tutto
  std::string expandedargs;
  char buffer[1024];
#ifdef _WIN32
  ExpandEnvironmentStrings(args.c_str(), buffer, 1024);

  STARTUPINFO si;
  PROCESS_INFORMATION pinfo;

  GetStartupInfo(&si);

  BOOL ret = CreateProcess(
      (char *)executablePath.c_str(),           // name of executable module
      buffer,                                   // command line string
      NULL,                                     // SD
      NULL,                                     // SD
      TRUE,                                     // handle inheritance option
      CREATE_NO_WINDOW, /*CREATE_NEW_CONSOLE*/  // creation flags
      NULL,                                     // new environment block
      NULL,                                     // current directory name
      &si,                                      // startup information
      &pinfo                                    // process information
      );

  if (!ret) DWORD err = GetLastError();

  // aspetta che il processo termini
  WaitForSingleObject(pinfo.hProcess, INFINITE);

  DWORD exitCode;
  ret = GetExitCodeProcess(pinfo.hProcess,  // handle to the process
                           &exitCode);      // termination status

#else
  std::string cmdline = executablePath + buffer;
  //    int exitCode =
  system(cmdline.c_str());
#endif
  /*
string name = m_executablePath.getName();
TPixel32 color;
if(name == "saturate") color = TPixel32::Magenta;
else if(name == "over") color = TPixel32::Green;
else color = TPixel32::Red;
for(int iy=0;iy<ras->getLy();iy++)
{
TPixel32 *pix = ras->pixels(iy);
TPixel32 *endPix = pix + ras->getLx();
double x = tile.m_pos.x;
double y = tile.m_pos.y + iy;
while(pix<endPix)
 {
  if(x*x+y*y<900) *pix = color;
  else *pix = TPixel32(0,0,0,0);
  ++pix;
  x+=1.0;
 }
}
*/

  try {
    TRasterP ras = tile.getRaster();
    TImageReader::load(outputTmpFile, ras);
  } catch (...) {
  }

  // butto i file temporanei creati
  std::map<std::string, TFilePath>::const_iterator fileIt;
  for (fileIt = tmpFiles.begin(); fileIt != tmpFiles.end(); ++fileIt) {
    if (TFileStatus(fileIt->second).doesExist() == true) try {
        TSystem::deleteFile(fileIt->second);
      } catch (...) {
      }
  }
  if (TFileStatus(outputTmpFile).doesExist() == true) try {
      TSystem::deleteFile(outputTmpFile);
    } catch (...) {
    }
}
void Iwa_GradientWarpFx::doCompute(TTile &tile,
								   double frame,
								   const TRenderSettings &settings)
{
	/*- ソース画像が刺さっていなければreturn -*/
	if (!m_source.isConnected()) {
		tile.getRaster()->clear();
		return;
	}
	/*- 参照画像が刺さっていなければ、ソース画像をそのまま返す -*/
	if (!m_warper.isConnected()) {
		m_source->compute(tile, frame, settings);
		return;
	}

	/*-  計算パラメータを得る -*/
	/*- 移動距離のピクセルサイズ -*/
	/*--- 拡大縮小(移動回転しないで)のGeometryを反映させる ---*/
	double k = sqrt(fabs(settings.m_affine.det()));
	double hLength = m_h_maxlen->getValue(frame) * k;
	double vLength = m_v_maxlen->getValue(frame) * k;

	double scale = m_scale->getValue(frame);

	/*- ワープ距離が0なら、ソース画像をそのまま返す -*/
	if (hLength == 0.0 && vLength == 0.0) {
		m_source->compute(tile, frame, settings);
		return;
	}

	int margin = static_cast<int>(ceil((abs(hLength) < abs(vLength)) ? abs(vLength) : abs(hLength)));

	/*- 素材計算範囲を計算 -*/
	/*- 出力範囲 -*/
	TRectD rectOut(tile.m_pos, TDimensionD(
								   tile.getRaster()->getLx(), tile.getRaster()->getLy()));
	TRectD enlargedRect = rectOut.enlarge((double)margin);
	TDimensionI enlargedDim((int)enlargedRect.getLx(), (int)enlargedRect.getLy());

	/*- ソース画像を正規化して格納 -*/
	float4 *source_host;
	TRasterGR8P source_host_ras(enlargedDim.lx * sizeof(float4), enlargedDim.ly);
	source_host_ras->lock();
	source_host = (float4 *)source_host_ras->getRawData();
	{
		/*- タイルはこのフォーカス内だけ使用。正規化してsource_hostに取り込んだらもう使わない。 -*/
		TTile sourceTile;
		m_source->allocateAndCompute(
			sourceTile, enlargedRect.getP00(),
			enlargedDim,
			tile.getRaster(), frame, settings);
		/*- タイルの画像を0〜1に正規化してホストメモリに読み込む -*/
		TRaster32P ras32 = (TRaster32P)sourceTile.getRaster();
		TRaster64P ras64 = (TRaster64P)sourceTile.getRaster();
		if (ras32)
			setSourceRaster<TRaster32P, TPixel32>(ras32, source_host, enlargedDim);
		else if (ras64)
			setSourceRaster<TRaster64P, TPixel64>(ras64, source_host, enlargedDim);
	}

	/*- 参照画像を正規化して格納 -*/
	float *warper_host;
	TRasterGR8P warper_host_ras(enlargedDim.lx * sizeof(float), enlargedDim.ly);
	warper_host_ras->lock();
	warper_host = (float *)warper_host_ras->getRawData();
	{
		/*- タイルはこのフォーカス内だけ使用。正規化してwarper_hostに取り込んだらもう使わない -*/
		TTile warperTile;
		m_warper->allocateAndCompute(
			warperTile, enlargedRect.getP00(),
			enlargedDim,
			tile.getRaster(), frame, settings);
		/*- タイルの画像の輝度値を0〜1に正規化してホストメモリに読み込む -*/
		TRaster32P ras32 = (TRaster32P)warperTile.getRaster();
		TRaster64P ras64 = (TRaster64P)warperTile.getRaster();
		if (ras32)
			setWarperRaster<TRaster32P, TPixel32>(ras32, warper_host, enlargedDim);
		else if (ras64)
			setWarperRaster<TRaster64P, TPixel64>(ras64, warper_host, enlargedDim);
	}

	/*- 変位値をScale倍して増やす -*/
	hLength *= scale;
	vLength *= scale;

	TRasterGR8P result_host_ras;

	result_host_ras = TRasterGR8P(enlargedDim.lx * sizeof(float4), enlargedDim.ly);
	/*- 結果を収めるメモリ -*/
	float4 *result_host;
	result_host_ras->lock();
	result_host = (float4 *)result_host_ras->getRawData();
	doCompute_CPU(tile, frame, settings,
				  hLength, vLength,
				  margin,
				  enlargedDim,
				  source_host,
				  warper_host,
				  result_host);
	/*- ポインタ入れ替え -*/
	source_host = result_host;

	int2 yohaku = {(enlargedDim.lx - tile.getRaster()->getSize().lx) / 2,
				   (enlargedDim.ly - tile.getRaster()->getSize().ly) / 2};
	/*- ラスタのクリア -*/
	tile.getRaster()->clear();
	TRaster32P outRas32 = (TRaster32P)tile.getRaster();
	TRaster64P outRas64 = (TRaster64P)tile.getRaster();
	if (outRas32)
		setOutputRaster<TRaster32P, TPixel32>(source_host, outRas32, enlargedDim, yohaku);
	else if (outRas64)
		setOutputRaster<TRaster64P, TPixel64>(source_host, outRas64, enlargedDim, yohaku);

	/*- ソース画像のメモリ解放 -*/
	source_host_ras->unlock();
	/*- 参照画像のメモリ解放 -*/
	warper_host_ras->unlock();
	result_host_ras->unlock();
}
Esempio n. 26
0
/*------------------------------------------------------------
 背景を露光値にして通常合成
------------------------------------------------------------*/
void Iwa_MotionBlurCompFx::composeBackgroundExposure_CPU(
    float4 *out_tile_p, TDimensionI &enlargedDimIn, int marginRight,
    int marginTop, TTile &back_tile, TDimensionI &dimOut, float hardness) {
  /*- ホストのメモリ確保 -*/
  TRasterGR8P background_host_ras(sizeof(float4) * dimOut.lx, dimOut.ly);
  background_host_ras->lock();
  float4 *background_host = (float4 *)background_host_ras->getRawData();

  bool bgIsPremultiplied;

  /*- 背景画像を0〜1に正規化してホストメモリに読み込む -*/
  TRaster32P backRas32 = (TRaster32P)back_tile.getRaster();
  TRaster64P backRas64 = (TRaster64P)back_tile.getRaster();
  if (backRas32)
    bgIsPremultiplied = setSourceRaster<TRaster32P, TPixel32>(
        backRas32, background_host, dimOut);
  else if (backRas64)
    bgIsPremultiplied = setSourceRaster<TRaster64P, TPixel64>(
        backRas64, background_host, dimOut);

  float4 *bg_p = background_host;
  float4 *out_p;

  for (int j = 0; j < dimOut.ly; j++) {
    out_p = out_tile_p + ((marginTop + j) * enlargedDimIn.lx + marginRight);
    for (int i = 0; i < dimOut.lx; i++, bg_p++, out_p++) {
      /*- 上レイヤが完全に不透明ならcontinue -*/
      if ((*out_p).w >= 1.0f) continue;

      /*- 下レイヤが完全に透明でもcontinue -*/
      if ((*bg_p).w < 0.0001f) continue;

      float3 bgExposure = {(*bg_p).x, (*bg_p).y, (*bg_p).z};

      /*- 通常のLevelなど、Premultiplyされている素材に対し、depremultiplyを行う
              DigiBookなどには行わない -*/
      if (bgIsPremultiplied) {
        // demultiply
        bgExposure.x /= (*bg_p).w;
        bgExposure.y /= (*bg_p).w;
        bgExposure.z /= (*bg_p).w;
      }

      /*- ExposureをRGB値にする -*/
      bgExposure.x = powf(10, (bgExposure.x - 0.5f) * hardness);
      bgExposure.y = powf(10, (bgExposure.y - 0.5f) * hardness);
      bgExposure.z = powf(10, (bgExposure.z - 0.5f) * hardness);

      // multiply
      bgExposure.x *= (*bg_p).w;
      bgExposure.y *= (*bg_p).w;
      bgExposure.z *= (*bg_p).w;

      /*- 手前とOver合成 -*/
      (*out_p).x = (*out_p).x + bgExposure.x * (1.0f - (*out_p).w);
      (*out_p).y = (*out_p).y + bgExposure.y * (1.0f - (*out_p).w);
      (*out_p).z = (*out_p).z + bgExposure.z * (1.0f - (*out_p).w);
      /*- アルファ値もOver合成 -*/
      (*out_p).w = (*out_p).w + (*bg_p).w * (1.0f - (*out_p).w);
    }
  }
  background_host_ras->unlock();
}
Esempio n. 27
0
void FreeDistortBaseFx::doCompute(TTile &tile, double frame, const TRenderSettings &ri)
{
	if (!m_input.isConnected())
		return;

	//Upon deactivation, this fx does nothing.
	if (m_deactivate->getValue()) {
		m_input->compute(tile, frame, ri);
		return;
	}

	//Get the source quad
	TPointD p00_b = m_p00_b->getValue(frame);
	TPointD p10_b = m_p10_b->getValue(frame);
	TPointD p01_b = m_p01_b->getValue(frame);
	TPointD p11_b = m_p11_b->getValue(frame);

	//Get destination quad
	TPointD p00_a = m_p00_a->getValue(frame);
	TPointD p10_a = m_p10_a->getValue(frame);
	TPointD p01_a = m_p01_a->getValue(frame);
	TPointD p11_a = m_p11_a->getValue(frame);

	if (m_isCastShadow) {
		//Shadows are mirrored
		tswap(p00_a, p01_a);
		tswap(p10_a, p11_a);
	}

	//Get requested tile's geometry
	TRasterP tileRas(tile.getRaster());
	TRectD tileRect(convert(tileRas->getBounds()) + tile.m_pos);

	//Call transform to get the minimal rectOnInput
	TRectD inRect;
	TRenderSettings riNew;
	TRectD inBBox;

	safeTransform(frame, 0, tileRect, ri, inRect, riNew, inBBox);

	//Intersect with the bbox
	inRect *= inBBox;

	if (myIsEmpty(inRect))
		return;

	double scale = ri.m_affine.a11;

	double downBlur = m_downBlur->getValue(frame) * scale;
	double upBlur = m_upBlur->getValue(frame) * scale;
	int brad = tceil(tmax(downBlur, upBlur));

	inRect = inRect.enlarge(brad);

	TDimension inRectSize(tceil(inRect.getLx()), tceil(inRect.getLy()));

	TTile inTile;
	m_input->allocateAndCompute(inTile, inRect.getP00(), inRectSize, tileRas, frame, riNew);

	TPointD inTilePosRi = inTile.m_pos;

	//Update quads by the scale factors
	p00_b = riNew.m_affine * p00_b;
	p10_b = riNew.m_affine * p10_b;
	p01_b = riNew.m_affine * p01_b;
	p11_b = riNew.m_affine * p11_b;

	p00_a = ri.m_affine * p00_a;
	p10_a = ri.m_affine * p10_a;
	p01_a = ri.m_affine * p01_a;
	p11_a = ri.m_affine * p11_a;

	PerspectiveDistorter perpDistorter(
		p00_b - inTile.m_pos, p10_b - inTile.m_pos, p01_b - inTile.m_pos, p11_b - inTile.m_pos,
		p00_a, p10_a, p01_a, p11_a);

	BilinearDistorter bilDistorter(
		p00_b - inTile.m_pos, p10_b - inTile.m_pos, p01_b - inTile.m_pos, p11_b - inTile.m_pos,
		p00_a, p10_a, p01_a, p11_a);

	TQuadDistorter *distorter;
	if (m_distortType->getValue() == PERSPECTIVE)
		distorter = &perpDistorter;
	else if (m_distortType->getValue() == BILINEAR)
		distorter = &bilDistorter;
	else
		assert(0);

	if (m_isCastShadow) {
		TRaster32P ras32 = inTile.getRaster();
		TRaster64P ras64 = inTile.getRaster();

		if (ras32) {
			if (m_fade->getValue(frame) > 0)
				doFade(ras32, m_color->getValue(frame), m_fade->getValue(frame) / 100.0);
			if (brad > 0)
				doBlur(ras32, upBlur, downBlur,
					   m_upTransp->getValue(frame) / 100.0, m_downTransp->getValue(frame) / 100.0,
					   inBBox.y0 - inTile.m_pos.y, inBBox.y1 - inTile.m_pos.y);
			else if (m_upTransp->getValue(frame) > 0 || m_downTransp->getValue(frame) > 0)
				doTransparency(ras32, m_upTransp->getValue(frame) / 100.0, m_downTransp->getValue(frame) / 100.0,
							   inBBox.y0 - inTile.m_pos.y, inBBox.y1 - inTile.m_pos.y);
		} else if (ras64) {
			if (m_fade->getValue(frame) > 0)
				doFade(ras64, toPixel64(m_color->getValue(frame)), m_fade->getValue(frame) / 100.0);
			if (brad > 0)
				doBlur(ras64, upBlur, downBlur,
					   m_upTransp->getValue(frame) / 100.0, m_downTransp->getValue(frame) / 100.0,
					   inBBox.y0 - inTile.m_pos.y, inBBox.y1 - inTile.m_pos.y);
			else if (m_upTransp->getValue(frame) > 0 || m_downTransp->getValue(frame) > 0)
				doTransparency(ras64, m_upTransp->getValue(frame) / 100.0, m_downTransp->getValue(frame) / 100.0,
							   inBBox.y0 - inTile.m_pos.y, inBBox.y1 - inTile.m_pos.y);
		} else
			assert(false);
	}

	distort(tileRas, inTile.getRaster(), *distorter, convert(tile.m_pos), TRop::Bilinear);
}