Ejemplo n.º 1
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);
}
Ejemplo n.º 2
0
TRectD SandorFxRenderData::getBBoxEnlargement(const TRectD &bbox)
{
	switch (m_type) {
	case BlendTz: {
		//Nothing happen, unless we have color 0 among the blended ones. In such case,
		//we have to enlarge the bbox proportionally to the amount param.
		std::vector<std::string> items;
		std::string indexes = std::string(m_argv[0]);
		parseIndexes(indexes, items);
		PaletteFilterFxRenderData paletteFilterData;
		insertIndexes(items, &paletteFilterData);

		if (paletteFilterData.m_colors.size() > 0 && *paletteFilterData.m_colors.begin() == 0)
			return bbox.enlarge(m_blendParams.m_amount);

		return bbox;
	}

	case Calligraphic:
	case OutBorder:
		return bbox.enlarge(m_callParams.m_thickness);

	case ArtAtContour:
		return bbox.enlarge(
			tmax(tceil(m_controllerBBox.getLx()), tceil(m_controllerBBox.getLy())) * m_contourParams.m_maxSize);

	default:
		assert(false);
		return bbox;
	}
}
Ejemplo n.º 3
0
void CameraTestTool::drawCleanupCamera(double pixelSize) {
  CleanupParameters *cp =
      CleanupSettingsModel::instance()->getCurrentParameters();

  TRectD rect = cp->m_camera.getStageRect();

  glColor3d(1.0, 0.0, 0.0);
  glLineStipple(1, 0xFFFF);
  glEnable(GL_LINE_STIPPLE);

  // box
  glBegin(GL_LINE_STRIP);
  glVertex2d(rect.x0, rect.y0);
  glVertex2d(rect.x0, rect.y1 - pixelSize);
  glVertex2d(rect.x1 - pixelSize, rect.y1 - pixelSize);
  glVertex2d(rect.x1 - pixelSize, rect.y0);
  glVertex2d(rect.x0, rect.y0);
  glEnd();

  // central cross
  double dx = 0.05 * rect.getP00().x;
  double dy = 0.05 * rect.getP00().y;
  tglDrawSegment(TPointD(-dx, -dy), TPointD(dx, dy));
  tglDrawSegment(TPointD(-dx, dy), TPointD(dx, -dy));

  glDisable(GL_LINE_STIPPLE);

  // camera name
  TPointD pos = rect.getP01() + TPointD(0, 4);
  glPushMatrix();
  glTranslated(pos.x, pos.y, 0);
  glScaled(2, 2, 2);
  tglDrawText(TPointD(), "Cleanup Camera");
  glPopMatrix();
}
Ejemplo n.º 4
0
void RGBPickerTool::pickRect() {
  TImageP image = TImageP(getImage(false));

  TTool::Application *app = TTool::getApplication();
  TPaletteHandle *ph      = app->getPaletteController()->getCurrentPalette();
  int styleId             = ph->getStyleIndex();
  TPalette *palette       = ph->getPalette();
  TRectD area             = m_selectingRect;
  if (!palette) return;
  if (m_selectingRect.x0 > m_selectingRect.x1) {
    area.x1 = m_selectingRect.x0;
    area.x0 = m_selectingRect.x1;
  }
  if (m_selectingRect.y0 > m_selectingRect.y1) {
    area.y1 = m_selectingRect.y0;
    area.y0 = m_selectingRect.y1;
  }
  m_selectingRect.empty();
  if (area.getLx() <= 1 || area.getLy() <= 1) return;
  StylePicker picker(image, palette);

  // iwsw commented out temporarily
  // if (m_viewer->get3DLutUtil() &&
  // Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled())
  //	m_viewer->get3DLutUtil()->bindFBO();

  m_currentValue = picker.pickColor(area);

  // iwsw commented out temporarily
  // if (m_viewer->get3DLutUtil() &&
  // Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled())
  //	m_viewer->get3DLutUtil()->releaseFBO();
}
Ejemplo n.º 5
0
void tglFillRect(const TRectD &rect)
{
	glBegin(GL_POLYGON);
	tglVertex(rect.getP00());
	tglVertex(rect.getP10());
	tglVertex(rect.getP11());
	tglVertex(rect.getP01());
	glEnd();
}
Ejemplo n.º 6
0
void tglDrawRect(const TRectD &rect)
{
	glBegin(GL_LINE_LOOP);
	tglVertex(rect.getP00());
	tglVertex(rect.getP10());
	tglVertex(rect.getP11());
	tglVertex(rect.getP01());
	glEnd();
}
void FullColorBrushTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e)
{
	m_brushPos = m_mousePos = pos;

	TRasterImageP ri = (TRasterImageP)getImage(true);
	if (!ri)
		return;

	double maxThickness = m_thickness.getValue().second;
	double thickness = m_pressure.getValue() ? computeThickness(e.m_pressure, m_thickness) : maxThickness;
	double opacity = (m_pressure.getValue() ? computeThickness(e.m_pressure, m_opacity) : m_opacity.getValue().second) * 0.01;
	TDimension size = m_workRaster->getSize();
	TPointD rasCenter = TPointD(size.lx * 0.5, size.ly * 0.5);
	TThickPoint point(pos + rasCenter, thickness);

	TThickPoint old = m_points.back();
	if (norm2(point - old) < 4)
		return;

	TThickPoint mid((old + point) * 0.5, (point.thick + old.thick) * 0.5);
	m_points.push_back(mid);
	m_points.push_back(point);

	TRect bbox;
	int m = m_points.size();
	TRectD invalidateRect;
	if (m == 3) {
		// ho appena cominciato. devo disegnare un segmento
		TThickPoint pa = m_points.front();
		vector<TThickPoint> points;
		points.push_back(pa);
		points.push_back(mid);
		invalidateRect = ToolUtils::getBounds(points, maxThickness);
		bbox = m_brush->getBoundFromPoints(points);
		updateWorkAndBackupRasters(bbox + m_lastRect);
		m_tileSaver->save(bbox);
		m_brush->addArc(pa, (pa + mid) * 0.5, mid, m_oldOpacity, opacity);
		m_lastRect += bbox;
	} else {
		// caso generale: disegno un arco
		vector<TThickPoint> points;
		points.push_back(m_points[m - 4]);
		points.push_back(old);
		points.push_back(mid);
		invalidateRect = ToolUtils::getBounds(points, maxThickness);
		bbox = m_brush->getBoundFromPoints(points);
		updateWorkAndBackupRasters(bbox + m_lastRect);
		m_tileSaver->save(bbox);
		m_brush->addArc(m_points[m - 4], old, mid, m_oldOpacity, opacity);
		m_lastRect += bbox;
	}
	m_oldOpacity = opacity;
	m_brush->updateDrawing(ri->getRaster(), m_backUpRas, m_currentColor, bbox, m_opacity.getValue().second * 0.01);
	invalidate(invalidateRect.enlarge(2) - rasCenter);
	m_strokeRect += bbox;
}
Ejemplo n.º 8
0
TRectD TAffine::operator*(const TRectD &rect) const
{
	if (rect != TConsts::infiniteRectD) {
		TPointD p1 = *this * rect.getP00(),
				p2 = *this * rect.getP01(),
				p3 = *this * rect.getP10(),
				p4 = *this * rect.getP11();
		return TRectD(tmin(p1.x, p2.x, p3.x, p4.x), tmin(p1.y, p2.y, p3.y, p4.y),
					  tmax(p1.x, p2.x, p3.x, p4.x), tmax(p1.y, p2.y, p3.y, p4.y));
	} else
		return TConsts::infiniteRectD;
}
Ejemplo n.º 9
0
 void get_render_enlarge(const double frame, const TAffine affine,
                         TRectD &bBox) {
   TPointD center(this->get_render_center(frame, bBox.getP00(), affine));
   int margin = this->get_render_int_margin(frame, bBox, affine, center);
   if (0 < margin) {
     /* 拡大のしすぎを防ぐテキトーな制限 */
     if (4096 < margin) {
       margin = 4096;
     }
     bBox = bBox.enlarge(margin);
   }
 }
Ejemplo n.º 10
0
void ShiftTraceTool::drawControlRect() {
  if (m_ghostIndex < 0 || m_ghostIndex > 1) return;
  int row = m_row[m_ghostIndex];
  if (row < 0) return;
  int col       = TApp::instance()->getCurrentColumn()->getColumnIndex();
  TXsheet *xsh  = TApp::instance()->getCurrentXsheet()->getXsheet();
  TXshCell cell = xsh->getCell(row, col);
  if (cell.isEmpty()) return;
  TImageP img = cell.getImage(false);
  if (!img) return;
  TRectD box;
  if (TRasterImageP ri = img) {
    TRasterP ras = ri->getRaster();
    box =
        (convert(ras->getBounds()) - ras->getCenterD()) * ri->getSubsampling();
  } else if (TToonzImageP ti = img) {
    TRasterP ras = ti->getRaster();
    box =
        (convert(ras->getBounds()) - ras->getCenterD()) * ti->getSubsampling();
  } else if (TVectorImageP vi = img) {
    box = vi->getBBox();
  } else {
    return;
  }
  glPushMatrix();
  tglMultMatrix(getGhostAff());
  TPixel32 color;
  color = m_highlightedGadget == TranslateGadget ? TPixel32(200, 100, 100)
                                                 : TPixel32(120, 120, 120);
  tglColor(color);
  glBegin(GL_LINE_STRIP);
  glVertex2d(box.x0, box.y0);
  glVertex2d(box.x1, box.y0);
  glVertex2d(box.x1, box.y1);
  glVertex2d(box.x0, box.y1);
  glVertex2d(box.x0, box.y0);
  glEnd();
  color =
      m_highlightedGadget == 2000 ? TPixel32(200, 100, 100) : TPixel32::White;
  double r = 4 * sqrt(tglGetPixelSize2());
  drawDot(box.getP00(), r, color);
  drawDot(box.getP01(), r, color);
  drawDot(box.getP10(), r, color);
  drawDot(box.getP11(), r, color);
  if (m_curveStatus == NoCurve) {
    color =
        m_highlightedGadget == 2001 ? TPixel32(200, 100, 100) : TPixel32::White;
    TPointD c = m_center[m_ghostIndex];
    drawDot(c, r, color);
  }
  glPopMatrix();
}
void FullColorBrushTool::leftButtonUp(const TPointD &pos, const TMouseEvent &e)
{
	m_brushPos = m_mousePos = pos;

	TRasterImageP ri = (TRasterImageP)getImage(true);
	if (!ri)
		return;

	if (m_points.size() != 1) {
		double maxThickness = m_thickness.getValue().second;
		double thickness = m_pressure.getValue() ? computeThickness(e.m_pressure, m_thickness) : maxThickness;
		double opacity = (m_pressure.getValue() ? computeThickness(e.m_pressure, m_opacity) : m_opacity.getValue().second) * 0.01;
		TPointD rasCenter = ri->getRaster()->getCenterD();
		TThickPoint point(pos + rasCenter, thickness);
		m_points.push_back(point);
		int m = m_points.size();
		vector<TThickPoint> points;
		points.push_back(m_points[m - 3]);
		points.push_back(m_points[m - 2]);
		points.push_back(m_points[m - 1]);
		TRect bbox = m_brush->getBoundFromPoints(points);
		updateWorkAndBackupRasters(bbox);
		m_tileSaver->save(bbox);
		m_brush->addArc(points[0], points[1], points[2], m_oldOpacity, opacity);
		m_brush->updateDrawing(ri->getRaster(), m_backUpRas, m_currentColor, bbox, m_opacity.getValue().second * 0.01);
		TRectD invalidateRect = ToolUtils::getBounds(points, maxThickness);
		invalidate(invalidateRect.enlarge(2) - rasCenter);
		m_strokeRect += bbox;
		m_lastRect.empty();
	}

	if (m_brush) {
		delete m_brush;
		m_brush = 0;
	}

	m_workRaster->unlock();

	if (m_tileSet->getTileCount() > 0) {
		delete m_tileSaver;
		TTool::Application *app = TTool::getApplication();
		TXshLevel *level = app->getCurrentLevel()->getLevel();
		TXshSimpleLevelP simLevel = level->getSimpleLevel();
		TFrameId frameId = getCurrentFid();
		TRasterP ras = ri->getRaster()->extract(m_strokeRect)->clone();
		TUndoManager::manager()->add(new FullColorBrushUndo(m_tileSet, simLevel.getPointer(), frameId,
															m_isFrameCreated, ras, m_strokeRect.getP00()));
	}

	notifyImageChanged();
	m_strokeRect.empty();
}
Ejemplo n.º 12
0
  int getMemoryRequirement(const TRectD &rect, double frame,
                           const TRenderSettings &info) override {
    double scale = sqrt(fabs(info.m_affine.det()));
    double blur  = m_value->getValue(frame) * scale;

    return TRasterFx::memorySize(rect.enlarge(blur), info.m_bpp);
  }
Ejemplo n.º 13
0
	void get_render_enlarge(
		const double frame, const TAffine affine, TRectD &bBox)
	{
		const int margin = this->get_render_margin(frame, affine);
		if (0 < margin) {
			bBox = bBox.enlarge(static_cast<double>(margin));
		}
	}
Ejemplo n.º 14
0
 void get_render_enlarge(const double frame, const TAffine affine,
                         TRectD &bBox) {
   const int margin = igs::gaussian_blur_hv::int_radius(
       this->get_render_real_radius(frame, affine));
   if (0 < margin) {
     bBox = bBox.enlarge(static_cast<double>(margin));
   }
 }
Ejemplo n.º 15
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;
  }
Ejemplo n.º 16
0
TRect TRasterImageUtils::convertWorldToRaster(const TRectD &area, const TRasterImageP ri)
{
	if (area.isEmpty())
		return TRect();
	if (!ri || !ri->getRaster())
		return TRect(tfloor(area.x0), tfloor(area.y0), tfloor(area.x1) - 1, tfloor(area.y1) - 1);
	TRasterP ras = ri->getRaster();
	TRectD rect(area + ras->getCenterD());
	return TRect(tfloor(rect.x0), tfloor(rect.y0), tceil(rect.x1) - 1, tceil(rect.y1) - 1);
}
Ejemplo n.º 17
0
/*-- Paste後のフローティング状態の画像の描画 --*/
void RasterSelectionTool::drawFloatingSelection()
{
	double pixelSize = TTool::getApplication()->getCurrentTool()->getTool()->getPixelSize();

	TAffine aff = m_rasterSelection.getTransformation();
	glPushMatrix();
	tglMultMatrix(aff);

	//draw m_floatingSelection
	if (isFloating()) {
		TRasterP floatingSelection = m_rasterSelection.getFloatingSelection();
		TImageP app;
		if (TRasterCM32P toonzRas = (TRasterCM32P)(floatingSelection))
			app = TToonzImageP(toonzRas, toonzRas->getBounds());
		if (TRaster32P fullColorRas = (TRaster32P)(floatingSelection))
			app = TRasterImageP(fullColorRas);
		if (TRasterGR8P grRas = (TRasterGR8P)(floatingSelection))
			app = TRasterImageP(grRas);
		app->setPalette(m_rasterSelection.getCurrentImage()->getPalette());
		FourPoints points = getBBox() * aff.inv();
		TRectD bbox = points.getBox();
		TPointD center((bbox.getP00() + bbox.getP11()) * 0.5);
		if (TToonzImageP ti = (TToonzImageP)app)
			GLRasterPainter::drawRaster(TTranslation(center), ti, false);
		if (TRasterImageP ri = (TRasterImageP)app)
			GLRasterPainter::drawRaster(TTranslation(center), ri, true);
	}

	std::vector<TStroke> strokes = m_rasterSelection.getStrokes();
	int i;
	for (i = 0; i < (int)strokes.size(); i++) {
		TStroke stroke = strokes[i];
		glEnable(GL_LINE_STIPPLE);
		glLineStipple(1, 0xF0F0);
		tglColor(TPixel32::Black);
		drawStrokeCenterline(stroke, pixelSize);
		glDisable(GL_LINE_STIPPLE);
	}

	glPopMatrix();
}
Ejemplo n.º 18
0
  int get_render_int_margin(const double frame, const TRectD &bBox,
                            const TAffine affine, TPointD center) {
    /*--- 単位変換(mm-->render用pixel)と長さ(scale)変換 ---*/
    const double scale = ino::pixel_per_mm() * sqrt(fabs(affine.det()));
    /*--- margin計算...Twist時正確でない ---*/
    return igs::radial_blur::reference_margin(
        static_cast<int>(ceil(bBox.getLy())),
        static_cast<int>(ceil(bBox.getLx())), center.x, center.y,
        this->m_twist->getValue(frame) * 3.14159265358979 / 180.0,
        0.0  // this->m_twist_radius->getValue(frame) * scale
        ,
        this->m_blur->getValue(frame) / ino_param_range

        //,this->m_radius->getValue(frame) * scale
        ,
        0 /* debug:2012-02-01:ゼロ以上だとmarginが小さすぎになり画像が切れてしまう
             */

        ,
        (this->m_anti_alias->getValue() ? 4 : 1));
  }
void Iwa_GradientWarpFx::get_render_enlarge(const double frame,
											const TAffine affine,
											TRectD &bBox)
{
	double h_maxlen = 0.0;
	double v_maxlen = 0.0;
	this->get_render_real_hv(frame, affine, h_maxlen, v_maxlen);
	const int margin = static_cast<int>(ceil(
		(h_maxlen < v_maxlen) ? v_maxlen : h_maxlen));
	if (0 < margin) {
		bBox = bBox.enlarge(static_cast<double>(margin));
	}
}
Ejemplo n.º 20
0
void rect_autofill_learn(const TVectorImageP &imgToLearn, const TRectD &rect)

{
  if (rect.getLx() * rect.getLy() < MIN_SIZE) return;

  double pbx, pby;
  double totalArea = 0;
  pbx = pby = 0;

  if (!regionsReference.isEmpty()) regionsReference.clear();

  int i, index = 0, regionCount = imgToLearn->getRegionCount();
  for (i = 0; i < regionCount; i++) {
    TRegion *region = imgToLearn->getRegion(i);
    if (rect.contains(region->getBBox())) {
      scanRegion(region, index, regionsReference, rect);
      index++;
    }
    int j, subRegionCount = region->getSubregionCount();
    for (j = 0; j < subRegionCount; j++) {
      TRegion *subRegion = region->getSubregion(j);
      if (rect.contains(subRegion->getBBox()))
        scanSubRegion(subRegion, index, regionsReference, rect);
    }
  }

  QMap<int, Region>::Iterator it;
  for (it = regionsReference.begin(); it != regionsReference.end(); it++) {
    pbx += it.value().m_barycentre.x;
    pby += it.value().m_barycentre.y;
    totalArea += it.value().m_area;
  }

  if (totalArea > 0)
    referenceB = TPointD(pbx / totalArea, pby / totalArea);
  else
    referenceB = TPointD(0.0, 0.0);
}
Ejemplo n.º 21
0
void TTool::invalidate(const TRectD &rect) {
  if (m_viewer) {
    if (rect.isEmpty())
      m_viewer->GLInvalidateAll();
    else {
      TPointD dpiScale(1, 1);
      TXshSimpleLevel *sl =
          getApplication()->getCurrentLevel()->getSimpleLevel();
      if (sl) dpiScale = getCurrentDpiScale(sl, getCurrentFid());
      m_viewer->GLInvalidateRect(getCurrentColumnMatrix() *
                                 TScale(dpiScale.x, dpiScale.y) * rect);
    }
  }
}
Ejemplo n.º 22
0
bool TRegion::selectFill(const TRectD &selArea, int styleId)
{
	bool hitSomeRegions = false;

	if (selArea.contains(getBBox())) {
		hitSomeRegions = true;
		setStyle(styleId);
	}

	int regNum = m_imp->m_includedRegionArray.size();

	for (int i = 0; i < regNum; i++)
		hitSomeRegions |= m_imp->m_includedRegionArray[i]->selectFill(selArea, styleId);

	return hitSomeRegions;
}
Ejemplo n.º 23
0
  inline void buildLightRects(const TRectD &tileRect, TRectD &inRect,
                              TRectD &outRect, double blur) {
    if (inRect !=
        TConsts::infiniteRectD)  // Could be, if the input light is a zerary Fx
      makeRectCoherent(inRect, tileRect.getP00());

    int blurI = tceil(blur);

    // It seems that the TRop::blur does wrong with these (cuts at the borders).
    // I don't know why - they would be best...
    // TRectD blurOutRect((lightRect).enlarge(blurI) * tileRect);
    // lightRect = ((tileRect).enlarge(blurI) * lightRect);

    // So we revert to the sum of the two
    outRect = inRect = ((tileRect).enlarge(blurI) * inRect) +
                       ((inRect).enlarge(blurI) * tileRect);
  }
Ejemplo n.º 24
0
 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;
   }
 }
Ejemplo n.º 25
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;
}
*/
}
Ejemplo n.º 26
0
  /*--  AutoCloseが実行されたらtrue,実行されなければfalseを返す --*/
  bool applyAutoclose(const TToonzImageP &ti, const TRectD &selRect = TRectD(),
                      TStroke *stroke = 0) {
    if (!ti) return false;
    // inizializzo gli AutocloseParameters
    AutocloseParameters params;
    params.m_closingDistance = (int)(m_distance.getValue());
    params.m_spotAngle       = (int)(m_angle.getValue());
    params.m_opacity         = m_opacity.getValue();
    std::string inkString    = ::to_string(m_inkIndex.getValue());
    int inkIndex =
        TTool::getApplication()
            ->getCurrentLevelStyleIndex();  // TApp::instance()->getCurrentPalette()->getStyleIndex();
    if (isInt(inkString)) inkIndex = std::stoi(inkString);
    params.m_inkIndex              = inkIndex;

    TPoint delta;
    TRasterCM32P ras, raux = ti->getRaster();
    if (m_closeType.getValue() == RECT_CLOSE && raux && !selRect.isEmpty()) {
      TRectD selArea = selRect;
      if (selRect.x0 > selRect.x1) {
        selArea.x1 = selRect.x0;
        selArea.x0 = selRect.x1;
      }
      if (selRect.y0 > selRect.y1) {
        selArea.y1 = selRect.y0;
        selArea.y0 = selRect.y1;
      }
      TRect myRect(ToonzImageUtils::convertWorldToRaster(selArea, ti));
      ras   = raux->extract(myRect);
      delta = myRect.getP00();
    } else if ((m_closeType.getValue() == FREEHAND_CLOSE ||
                m_closeType.getValue() == POLYLINE_CLOSE) &&
               stroke) {
      TRectD selArea = stroke->getBBox();
      TRect myRect(ToonzImageUtils::convertWorldToRaster(selArea, ti));
      ras   = raux->extract(myRect);
      delta = myRect.getP00();
    } else
      ras = raux;
    if (!ras) return false;

    TAutocloser ac(ras, params.m_closingDistance, params.m_spotAngle,
                   params.m_inkIndex, params.m_opacity);

    std::vector<TAutocloser::Segment> segments;
    ac.compute(segments);

    if ((m_closeType.getValue() == FREEHAND_CLOSE ||
         m_closeType.getValue() == POLYLINE_CLOSE) &&
        stroke)
      checkSegments(segments, stroke, raux, delta);

    std::vector<TAutocloser::Segment> segments2(segments);

    /*-- segmentが取得できなければfalseを返す --*/
    if (segments2.empty()) return false;

    int i;
    if (delta != TPoint(0, 0))
      for (i = 0; i < (int)segments2.size(); i++) {
        segments2[i].first += delta;
        segments2[i].second += delta;
      }

    TTileSetCM32 *tileSet = new TTileSetCM32(raux->getSize());
    for (i = 0; i < (int)segments2.size(); i++) {
      TRect bbox(segments2[i].first, segments2[i].second);
      bbox = bbox.enlarge(2);
      tileSet->add(raux, bbox);
    }

    TXshSimpleLevel *sl =
        TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
    TFrameId id = getCurrentFid();
    TUndoManager::manager()->add(
        new RasterAutocloseUndo(tileSet, params, segments2, sl, id));
    ac.draw(segments);
    ToolUtils::updateSaveBox();
    return true;
  }
Ejemplo n.º 27
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");
}
Ejemplo n.º 28
0
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;
  }
}
Ejemplo n.º 29
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);
  }
Ejemplo n.º 30
0
void TColorStyle::makeIcon(const TDimension &d) {
  checkErrorsByGL;
  TColorStyle *style = this->clone();
  checkErrorsByGL;

  TPaletteP tmpPalette = new TPalette();
  checkErrorsByGL;
  int id = tmpPalette->addStyle(style);
  checkErrorsByGL;

  int contextLx = pow(2.0, tceil(log((double)d.lx) / log(2.0)));
  int contextLy = pow(2.0, tceil(log((double)d.ly) / log(2.0)));
  TDimension dim(contextLx, contextLy);

  TOfflineGL *glContext = TOfflineGL::getStock(dim);

  checkErrorsByGL;
  glContext->clear(TPixel32::White);
  checkErrorsByGL;

  TVectorImageP img = new TVectorImage;
  checkErrorsByGL;
  img->setPalette(tmpPalette.getPointer());
  checkErrorsByGL;

  std::vector<TThickPoint> points(3);

  if (isRegionStyle() && !isStrokeStyle()) {
    points[0]        = TThickPoint(-55, -50, 1);
    points[1]        = TThickPoint(0, -60, 1);
    points[2]        = TThickPoint(55, -50, 1);
    TStroke *stroke1 = new TStroke(points);

    img->addStroke(stroke1);

    points[0]        = TThickPoint(50, -55, 1);
    points[1]        = TThickPoint(60, 0, 1);
    points[2]        = TThickPoint(50, 55, 1);
    TStroke *stroke2 = new TStroke(points);
    img->addStroke(stroke2);

    points[0]        = TThickPoint(55, 50, 1);
    points[1]        = TThickPoint(0, 60, 1);
    points[2]        = TThickPoint(-55, 50, 1);
    TStroke *stroke3 = new TStroke(points);
    img->addStroke(stroke3);

    points[0]        = TThickPoint(-50, 55, 1);
    points[1]        = TThickPoint(-60, 0, 1);
    points[2]        = TThickPoint(-50, -55, 1);
    TStroke *stroke4 = new TStroke(points);
    img->addStroke(stroke4);

    img->fill(TPointD(0, 0), id);
  } else if (isStrokeStyle() && !isRegionStyle()) {
    double rasX05 = d.lx * 0.5;
    double rasY05 = d.ly * 0.5;

    points[0]        = TThickPoint(-rasX05, -rasY05, 7);
    points[1]        = TThickPoint(0, -rasY05, 9);
    points[2]        = TThickPoint(rasX05, rasY05, 12);
    TStroke *stroke1 = new TStroke(points);

    stroke1->setStyle(id);

    img->addStroke(stroke1);
    points.clear();
  } else if (!isRasterStyle()) {
    assert(isStrokeStyle() && isRegionStyle());

    points[0]        = TThickPoint(-60, -30, 0.5);
    points[1]        = TThickPoint(0, -30, 0.5);
    points[2]        = TThickPoint(60, -30, 0.5);
    TStroke *stroke1 = new TStroke(points);
    stroke1->setStyle(id);
    img->addStroke(stroke1);

    points[0]        = TThickPoint(60, -30, 0.5);
    points[1]        = TThickPoint(60, 0, 0.5);
    points[2]        = TThickPoint(60, 30, 0.5);
    TStroke *stroke2 = new TStroke(points);
    stroke2->setStyle(id);
    img->addStroke(stroke2);

    points[0]        = TThickPoint(60, 30, 0.5);
    points[1]        = TThickPoint(0, 30, 0.5);
    points[2]        = TThickPoint(-60, 30, 0.5);
    TStroke *stroke3 = new TStroke(points);
    stroke3->setStyle(id);
    img->addStroke(stroke3);

    points[0]        = TThickPoint(-60, 30, 0.5);
    points[1]        = TThickPoint(-60, 0, 0.5);
    points[2]        = TThickPoint(-60, -30, 0.5);
    TStroke *stroke4 = new TStroke(points);
    stroke4->setStyle(id);
    img->addStroke(stroke4);

    img->fill(TPointD(0, 0), id);
  }

  TRectD bbox = img->getBBox();
  checkErrorsByGL;

  bbox = bbox.enlarge(TDimensionD(-10, -10));
  checkErrorsByGL;

  double scx = 0.9 * d.lx / bbox.getLx();
  double scy = 0.9 * d.ly / bbox.getLy();
  double sc  = std::min(scx, scy);
  double dx  = (d.lx - bbox.getLx() * sc) * 0.5;
  double dy  = (d.ly - bbox.getLy() * sc) * 0.5;
  TAffine aff =
      TScale(scx, scy) * TTranslation(-bbox.getP00() + TPointD(dx, dy));

  checkErrorsByGL;
  if (isRegionStyle() && !isStrokeStyle()) aff = aff * TTranslation(-10, -10);

  checkErrorsByGL;
  const TVectorRenderData rd(aff, TRect(), tmpPalette.getPointer(), 0, true);
  checkErrorsByGL;
  glContext->draw(img, rd);
  checkErrorsByGL;

  TRect rect(d);
  if (!m_icon || m_icon->getSize() != d) {
    checkErrorsByGL;
    m_icon = glContext->getRaster()->extract(rect)->clone();
  } else {
    checkErrorsByGL;
    m_icon->copy(glContext->getRaster()->extract(rect));
  }
}