38 bool IsGradientFill(Color_t fillColorIndex)
40 return dynamic_cast<TColorGradient *
>(gROOT->GetColor(fillColorIndex));
56 ClassImp(TGLPadPainter);
60 TGLPadPainter::TGLPadPainter()
61 : fIsHollowArea(kFALSE),
64 fVp[0] = fVp[1] = fVp[2] = fVp[3] = 0;
71 Color_t TGLPadPainter::GetLineColor()
const
73 return gVirtualX->GetLineColor();
79 Style_t TGLPadPainter::GetLineStyle()
const
81 return gVirtualX->GetLineStyle();
87 Width_t TGLPadPainter::GetLineWidth()
const
89 return gVirtualX->GetLineWidth();
95 void TGLPadPainter::SetLineColor(Color_t lcolor)
97 gVirtualX->SetLineColor(lcolor);
103 void TGLPadPainter::SetLineStyle(Style_t lstyle)
105 gVirtualX->SetLineStyle(lstyle);
111 void TGLPadPainter::SetLineWidth(Width_t lwidth)
113 gVirtualX->SetLineWidth(lwidth);
119 Color_t TGLPadPainter::GetFillColor()
const
121 return gVirtualX->GetFillColor();
127 Style_t TGLPadPainter::GetFillStyle()
const
129 return gVirtualX->GetFillStyle();
136 Bool_t TGLPadPainter::IsTransparent()
const
138 return gVirtualX->IsTransparent();
144 void TGLPadPainter::SetFillColor(Color_t fcolor)
146 gVirtualX->SetFillColor(fcolor);
152 void TGLPadPainter::SetFillStyle(Style_t fstyle)
154 gVirtualX->SetFillStyle(fstyle);
160 void TGLPadPainter::SetOpacity(Int_t percent)
162 gVirtualX->SetOpacity(percent);
168 Short_t TGLPadPainter::GetTextAlign()
const
170 return gVirtualX->GetTextAlign();
176 Float_t TGLPadPainter::GetTextAngle()
const
178 return gVirtualX->GetTextAngle();
184 Color_t TGLPadPainter::GetTextColor()
const
186 return gVirtualX->GetTextColor();
192 Font_t TGLPadPainter::GetTextFont()
const
194 return gVirtualX->GetTextFont();
200 Float_t TGLPadPainter::GetTextSize()
const
202 return gVirtualX->GetTextSize();
208 Float_t TGLPadPainter::GetTextMagnitude()
const
210 return gVirtualX->GetTextMagnitude();
216 void TGLPadPainter::SetTextAlign(Short_t align)
218 gVirtualX->SetTextAlign(align);
224 void TGLPadPainter::SetTextAngle(Float_t tangle)
226 gVirtualX->SetTextAngle(tangle);
232 void TGLPadPainter::SetTextColor(Color_t tcolor)
234 gVirtualX->SetTextColor(tcolor);
240 void TGLPadPainter::SetTextFont(Font_t tfont)
242 gVirtualX->SetTextFont(tfont);
248 void TGLPadPainter::SetTextSize(Float_t tsize)
250 gVirtualX->SetTextSize(tsize);
256 void TGLPadPainter::SetTextSizePixels(Int_t npixels)
258 gVirtualX->SetTextSizePixels(npixels);
268 Int_t TGLPadPainter::CreateDrawable(UInt_t, UInt_t)
276 void TGLPadPainter::ClearDrawable()
283 void TGLPadPainter::CopyDrawable(Int_t , Int_t , Int_t )
290 void TGLPadPainter::DestroyDrawable(Int_t )
300 void TGLPadPainter::SelectDrawable(Int_t )
305 if (TPad *pad = dynamic_cast<TPad *>(gPad)) {
306 Int_t px = 0, py = 0;
308 pad->XYtoAbsPixel(pad->GetX1(), pad->GetY1(), px, py);
310 py = gPad->GetWh() - py;
312 TGLUtil::InitializeIfNeeded();
313 const Float_t scale = TGLUtil::GetScreenScalingFactor();
315 glViewport(GLint(px * scale), GLint(py * scale),
316 GLsizei(gPad->GetWw() * pad->GetAbsWNDC() * scale),
317 GLsizei(gPad->GetWh() * pad->GetAbsHNDC() * scale));
319 glMatrixMode(GL_PROJECTION);
321 glOrtho(pad->GetX1(), pad->GetX2(), pad->GetY1(), pad->GetY2(), -10., 10.);
323 glMatrixMode(GL_MODELVIEW);
325 glTranslated(0., 0., -1.);
327 ::Error(
"TGLPadPainter::SelectDrawable",
328 "function was called not from TPad or TCanvas code\n");
329 throw std::runtime_error(
"");
343 void TGLPadPainter::InitPainter()
345 glDisable(GL_DEPTH_TEST);
346 glDisable(GL_CULL_FACE);
347 glDisable(GL_LIGHTING);
350 glViewport(0, 0, GLsizei(gPad->GetWw()), GLsizei(gPad->GetWh()));
352 glDepthMask(GL_TRUE);
353 glClearColor(1.,1.,1.,1.);
354 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
355 glDepthMask(GL_FALSE);
357 glMatrixMode(GL_PROJECTION);
360 glOrtho(gPad->GetX1(), gPad->GetX2(), gPad->GetY1(), gPad->GetY2(), -10., 10.);
362 glMatrixMode(GL_MODELVIEW);
364 glTranslated(0., 0., -1.);
373 void TGLPadPainter::InvalidateCS()
377 glMatrixMode(GL_PROJECTION);
380 glOrtho(gPad->GetX1(), gPad->GetX2(), gPad->GetY1(), gPad->GetY2(), -10., 10.);
382 glMatrixMode(GL_MODELVIEW);
390 void TGLPadPainter::LockPainter()
402 const Double_t lineWidthTS = 3.;
407 void TGLPadPainter::DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2)
415 if (gVirtualX->GetDrawMode() == TVirtualX::kInvert) {
416 gVirtualX->DrawLine(gPad->XtoAbsPixel(x1), gPad->YtoAbsPixel(y1),
417 gPad->XtoAbsPixel(x2), gPad->YtoAbsPixel(y2));
423 const Rgl::Pad::LineAttribSet lineAttribs(kTRUE, gVirtualX->GetLineStyle(), fLimits.GetMaxLineWidth(), kTRUE);
430 if (gVirtualX->GetLineWidth() > lineWidthTS) {
431 Double_t pointSize = gVirtualX->GetLineWidth();
432 if (pointSize > fLimits.GetMaxPointSize())
433 pointSize = fLimits.GetMaxPointSize();
434 glPointSize((GLfloat)pointSize);
435 const TGLEnableGuard pointSmooth(GL_POINT_SMOOTH);
436 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
451 void TGLPadPainter::DrawLineNDC(Double_t u1, Double_t v1, Double_t u2, Double_t v2)
455 const Rgl::Pad::LineAttribSet lineAttribs(kTRUE, gVirtualX->GetLineStyle(), fLimits.GetMaxLineWidth(), kTRUE);
456 const Double_t xRange = gPad->GetX2() - gPad->GetX1();
457 const Double_t yRange = gPad->GetY2() - gPad->GetY1();
460 glVertex2d(gPad->GetX1() + u1 * xRange, gPad->GetY1() + v1 * yRange);
461 glVertex2d(gPad->GetX1() + u2 * xRange, gPad->GetY1() + v2 * yRange);
468 void TGLPadPainter::DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, EBoxMode mode)
472 if (IsGradientFill(gVirtualX->GetFillColor())) {
473 Double_t xs[] = {x1, x2, x2, x1};
474 Double_t ys[] = {y1, y1, y2, y2};
475 DrawPolygonWithGradient(4, xs, ys);
479 if (mode == kHollow) {
480 const Rgl::Pad::LineAttribSet lineAttribs(kTRUE, 0, fLimits.GetMaxLineWidth(), kTRUE);
482 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
483 glRectd(x1, y1, x2, y2);
484 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
487 const Rgl::Pad::FillAttribSet fillAttribs(fSSet, kFALSE);
488 glRectd(x1, y1, x2, y2);
495 void TGLPadPainter::DrawFillArea(Int_t n,
const Double_t *x,
const Double_t *y)
497 assert(x != 0 &&
"DrawFillArea, parameter 'x' is null");
498 assert(y != 0 &&
"DrawFillArea, parameter 'y' is null");
504 ::Error(
"TGLPadPainter::DrawFillArea",
505 "invalid number of points in a polygon");
509 if (IsGradientFill(gVirtualX->GetFillColor()))
510 return DrawPolygonWithGradient(n, x, y);
512 if (!gVirtualX->GetFillStyle()) {
513 fIsHollowArea = kTRUE;
514 return DrawPolyLine(n, x, y);
517 const Rgl::Pad::FillAttribSet fillAttribs(fSSet, kFALSE);
518 DrawTesselation(n, x, y);
525 void TGLPadPainter::DrawFillArea(Int_t n,
const Float_t *x,
const Float_t *y)
529 if (!gVirtualX->GetFillStyle()) {
530 fIsHollowArea = kTRUE;
531 return DrawPolyLine(n, x, y);
536 for (Int_t i = 0; i < n; ++i) {
538 fVs[i * 3 + 1] = y[i];
541 const Rgl::Pad::FillAttribSet fillAttribs(fSSet, kFALSE);
543 GLUtesselator *t = (GLUtesselator *)fTess.GetTess();
545 gluNextContour(t, (GLenum)GLU_UNKNOWN);
547 for (Int_t i = 0; i < n; ++i)
548 gluTessVertex(t, &fVs[i * 3], &fVs[i * 3]);
557 void TGLPadPainter::DrawPolyLine(Int_t n,
const Double_t *x,
const Double_t *y)
561 const Rgl::Pad::LineAttribSet lineAttribs(kTRUE, gVirtualX->GetLineStyle(), fLimits.GetMaxLineWidth(), kTRUE);
563 glBegin(GL_LINE_STRIP);
565 for (Int_t i = 0; i < n; ++i)
566 glVertex2d(x[i], y[i]);
569 glVertex2d(x[0], y[0]);
570 fIsHollowArea = kFALSE;
574 if (gVirtualX->GetLineWidth() > lineWidthTS) {
575 Double_t pointSize = gVirtualX->GetLineWidth();
576 if (pointSize > fLimits.GetMaxPointSize())
577 pointSize = fLimits.GetMaxPointSize();
578 glPointSize((GLfloat)pointSize);
579 const TGLEnableGuard pointSmooth(GL_POINT_SMOOTH);
580 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
583 for (Int_t i = 0; i < n; ++i)
584 glVertex2d(x[i], y[i]);
594 void TGLPadPainter::DrawPolyLine(Int_t n,
const Float_t *x,
const Float_t *y)
598 const Rgl::Pad::LineAttribSet lineAttribs(kTRUE, gVirtualX->GetLineStyle(), fLimits.GetMaxLineWidth(), kTRUE);
600 glBegin(GL_LINE_STRIP);
602 for (Int_t i = 0; i < n; ++i)
603 glVertex2f(x[i], y[i]);
606 glVertex2f(x[0], y[0]);
607 fIsHollowArea = kFALSE;
616 void TGLPadPainter::DrawPolyLineNDC(Int_t n,
const Double_t *u,
const Double_t *v)
620 const Rgl::Pad::LineAttribSet lineAttribs(kTRUE, gVirtualX->GetLineStyle(), fLimits.GetMaxLineWidth(), kTRUE);
621 const Double_t xRange = gPad->GetX2() - gPad->GetX1();
622 const Double_t yRange = gPad->GetY2() - gPad->GetY1();
623 const Double_t x1 = gPad->GetX1(), y1 = gPad->GetY1();
625 glBegin(GL_LINE_STRIP);
627 for (Int_t i = 0; i < n; ++i)
628 glVertex2d(x1 + u[i] * xRange, y1 + v[i] * yRange);
636 template<
class ValueType>
637 void ConvertMarkerPoints(Int_t n,
const ValueType *x,
const ValueType *y, std::vector<TPoint> & dst);
644 void TGLPadPainter::DrawPolyMarker(Int_t n,
const Double_t *x,
const Double_t *y)
648 ConvertMarkerPoints(n, x, y, fPoly);
655 void TGLPadPainter::DrawPolyMarker(Int_t n,
const Float_t *x,
const Float_t *y)
659 ConvertMarkerPoints(n, x, y, fPoly);
666 void TGLPadPainter::DrawPolyMarker()
670 SaveProjectionMatrix();
673 glOrtho(0, gPad->GetAbsWNDC() * gPad->GetWw(), 0, gPad->GetAbsHNDC() * gPad->GetWh(), -10., 10.);
675 glMatrixMode(GL_MODELVIEW);
677 const TGLEnableGuard blendGuard(GL_BLEND);
679 Float_t rgba[4] = {};
680 Rgl::Pad::ExtractRGBA(gVirtualX->GetMarkerColor(), rgba);
681 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
684 const TPoint *xy = &fPoly[0];
685 const Style_t markerStyle = gVirtualX->GetMarkerStyle();
686 const UInt_t n = UInt_t(fPoly.size());
687 switch (markerStyle) {
689 fMarker.DrawDot(n, xy);
692 fMarker.DrawPlus(n, xy);
696 fMarker.DrawStar(n, xy);
700 fMarker.DrawCircle(n, xy);
703 fMarker.DrawX(n, xy);
706 fMarker.DrawFullDotSmall(n, xy);
709 fMarker.DrawFullDotMedium(n, xy);
713 fMarker.DrawFullDotLarge(n, xy);
716 fMarker.DrawFullSquare(n, xy);
718 case kFullTriangleUp:
719 fMarker.DrawFullTrianlgeUp(n, xy);
721 case kFullTriangleDown:
722 fMarker.DrawFullTrianlgeDown(n, xy);
725 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
726 fMarker.DrawFullSquare(n, xy);
727 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
729 case kOpenTriangleUp:
730 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
731 fMarker.DrawFullTrianlgeUp(n, xy);
732 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
735 fMarker.DrawDiamond(n, xy);
738 fMarker.DrawOpenCross(n, xy);
741 fMarker.DrawFullStar(n, xy);
744 fMarker.DrawOpenStar(n, xy);
746 case kOpenTriangleDown:
747 fMarker.DrawOpenTrianlgeDown(n, xy);
750 fMarker.DrawFullDiamond(n, xy);
753 fMarker.DrawFullCross(n, xy);
755 case kOpenDiamondCross:
756 fMarker.DrawOpenDiamondCross(n, xy);
758 case kOpenSquareDiagonal:
759 fMarker.DrawOpenSquareDiagonal(n, xy);
761 case kOpenThreeTriangles:
762 fMarker.DrawOpenThreeTriangles(n, xy);
765 fMarker.DrawOctagonCross(n, xy);
767 case kFullThreeTriangles:
768 fMarker.DrawFullThreeTriangles(n, xy);
770 case kOpenFourTrianglesX:
771 fMarker.DrawOpenFourTrianglesX(n, xy);
773 case kFullFourTrianglesX:
774 fMarker.DrawFullFourTrianglesX(n, xy);
776 case kOpenDoubleDiamond:
777 fMarker.DrawOpenDoubleDiamond(n, xy);
779 case kFullDoubleDiamond:
780 fMarker.DrawFullDoubleDiamond(n, xy);
782 case kOpenFourTrianglesPlus:
783 fMarker.DrawOpenFourTrianglesPlus(n, xy);
785 case kFullFourTrianglesPlus:
786 fMarker.DrawFullFourTrianglesPlus(n, xy);
789 fMarker.DrawOpenCrossX(n, xy);
792 fMarker.DrawFullCrossX(n, xy);
795 fMarker.DrawFourSquaresX(n, xy);
797 case kFourSquaresPlus:
798 fMarker.DrawFourSquaresPlus(n, xy);
802 RestoreProjectionMatrix();
803 glMatrixMode(GL_MODELVIEW);
809 void TGLPadPainter::DrawTextHelper(Double_t x, Double_t y,
const Char *text, ETextMode )
811 SaveProjectionMatrix();
815 glOrtho(0, gPad->GetAbsWNDC() * gPad->GetWw(), 0, gPad->GetAbsHNDC() * gPad->GetWh(), -10., 10.);
817 glMatrixMode(GL_MODELVIEW);
819 Float_t rgba[4] = {};
820 Rgl::Pad::ExtractRGBA(gVirtualX->GetTextColor(), rgba);
826 const Int_t shift = TGLFontManager::GetExtendedFontStartIndex();
828 Int_t fontIndex = TMath::Max(Short_t(10), gVirtualX->GetTextFont());
829 if (fontIndex / 10 + shift > TGLFontManager::GetFontFileArray()->GetEntries())
830 fontIndex = 20 + shift * 10;
832 fontIndex += shift * 10;
834 fFM.RegisterFont(TMath::Max(Int_t(gVirtualX->GetTextSize()) - 1, 10),
835 TGLFontManager::GetFontNameFromId(fontIndex),
836 TGLFont::kTexture, fF);
839 const UInt_t padH = UInt_t(gPad->GetAbsHNDC() * gPad->GetWh());
840 fF.Render(text, gPad->XtoPixel(x), padH - gPad->YtoPixel(y), GetTextAngle(), GetTextMagnitude());
843 RestoreProjectionMatrix();
845 glMatrixMode(GL_MODELVIEW);
854 void TGLPadPainter::DrawText(Double_t x, Double_t y,
const char *text, ETextMode mode)
858 if (!gVirtualX->GetTextSize())
861 DrawTextHelper(x, y, text, mode);
870 void TGLPadPainter::DrawText(Double_t x, Double_t y,
const wchar_t *text, ETextMode mode)
874 if (!gVirtualX->GetTextSize())
877 DrawTextHelper(x, y, text, mode);
886 void TGLPadPainter::DrawTextNDC(Double_t u, Double_t v,
const char *text, ETextMode mode)
890 const Double_t xRange = gPad->GetX2() - gPad->GetX1();
891 const Double_t yRange = gPad->GetY2() - gPad->GetY1();
892 DrawText(gPad->GetX1() + u * xRange, gPad->GetY1() + v * yRange, text, mode);
901 void TGLPadPainter::DrawTextNDC(Double_t u, Double_t v,
const wchar_t *text, ETextMode mode)
905 const Double_t xRange = gPad->GetX2() - gPad->GetX1();
906 const Double_t yRange = gPad->GetY2() - gPad->GetY1();
907 DrawText(gPad->GetX1() + u * xRange, gPad->GetY1() + v * yRange, text, mode);
915 void TGLPadPainter::SaveProjectionMatrix()
const
917 glMatrixMode(GL_PROJECTION);
926 void TGLPadPainter::RestoreProjectionMatrix()
const
928 glMatrixMode(GL_PROJECTION);
937 void TGLPadPainter::SaveModelviewMatrix()
const
939 glMatrixMode(GL_MODELVIEW);
948 void TGLPadPainter::RestoreModelviewMatrix()
const
950 glMatrixMode(GL_MODELVIEW);
957 void TGLPadPainter::SaveViewport()
959 glGetIntegerv(GL_VIEWPORT, fVp);
965 void TGLPadPainter::RestoreViewport()
967 glViewport(fVp[0], fVp[1], fVp[2], fVp[3]);
973 void TGLPadPainter::SaveImage(TVirtualPad *pad,
const char *fileName, Int_t type)
const
975 TVirtualPad *canvas = (TVirtualPad *)pad->GetCanvas();
979 gROOT->ProcessLine(Form(
"((TCanvas *)0x%lx)->Flush();", (ULong_t)canvas));
981 std::vector<unsigned> buff(canvas->GetWw() * canvas->GetWh());
982 glPixelStorei(GL_PACK_ALIGNMENT, 1);
983 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
986 glReadPixels(0, 0, canvas->GetWw(), canvas->GetWh(), GL_RGBA, GL_UNSIGNED_BYTE, (
char *)&buff[0]);
988 std::unique_ptr<TImage> image(TImage::Create());
990 ::Error(
"TGLPadPainter::SaveImage",
"TImage creation failed");
994 image->DrawRectangle(0, 0, canvas->GetWw(), canvas->GetWh());
995 UInt_t *argb = image->GetArgbArray();
998 ::Error(
"TGLPadPainter::SaveImage",
"null argb array in TImage object");
1002 const Int_t nLines = canvas->GetWh();
1003 const Int_t nPixels = canvas->GetWw();
1005 for (Int_t i = 0; i < nLines; ++i) {
1006 Int_t base = (nLines - 1 - i) * nPixels;
1007 for (Int_t j = 0; j < nPixels; ++j, ++base) {
1010 const UInt_t pix = buff[base];
1011 const UInt_t bgra = ((pix & 0xff) << 16) | (pix & 0xff00) |
1012 ((pix & 0xff0000) >> 16) | (pix & 0xff000000);
1015 argb[i * nPixels + j] = bgra;
1019 image->WriteImage(fileName, (TImage::EImageFileTypes)type);
1024 void TGLPadPainter::DrawPixels(
const unsigned char *pixelData, UInt_t width, UInt_t height,
1025 Int_t dstX, Int_t dstY, Bool_t enableBlending)
1032 ::Error(
"TGLPadPainter::DrawPixels",
"pixel data is null");
1036 if (std::numeric_limits<UInt_t>::digits >= 32) {
1045 ::Error(
"TGLPadPainter::DrawPixels",
"invalid width");
1051 ::Error(
"TGLPadPainter::DrawPixels",
"invalid height");
1055 if (TPad *pad = dynamic_cast<TPad *>(gPad)) {
1060 const Double_t rasterX = Double_t(dstX) / (pad->GetAbsWNDC() * pad->GetWw()) *
1061 (pad->GetX2() - pad->GetX1()) + pad->GetX1();
1063 const Double_t yRange = pad->GetY2() - pad->GetY1();
1064 const Double_t rasterY = yRange - Double_t(dstY + height) / (pad->GetAbsHNDC() * pad->GetWh()) * yRange +
1067 GLdouble oldPos[4] = {};
1069 glGetDoublev(GL_CURRENT_RASTER_POSITION, oldPos);
1071 glRasterPos2d(rasterX, rasterY);
1073 std::vector<unsigned char> upsideDownImage(4 * width * height);
1074 const unsigned char *srcLine = pixelData + 4 * width * (height - 1);
1075 unsigned char *dstLine = &upsideDownImage[0];
1076 for (UInt_t i = 0; i < height; ++i, srcLine -= 4 * width, dstLine += 4 * width)
1077 std::copy(srcLine, srcLine + 4 * width, dstLine);
1079 if (enableBlending) {
1081 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1084 glDrawPixels(width, height, GL_BGRA, GL_UNSIGNED_BYTE, &upsideDownImage[0]);
1087 glDisable(GL_BLEND);
1090 glRasterPos2d(oldPos[0], oldPos[1]);
1092 ::Error(
"TGLPadPainter::DrawPixels",
"no pad found to draw");
1102 void TGLPadPainter::DrawPolygonWithGradient(Int_t n,
const Double_t *x,
const Double_t *y)
1104 assert(n > 2 &&
"DrawPolygonWithGradient, invalid number of points");
1105 assert(x != 0 &&
"DrawPolygonWithGradient, parameter 'x' is null");
1106 assert(y != 0 &&
"DrawPolygonWithGradient, parameter 'y' is null");
1108 assert(dynamic_cast<TColorGradient *>(gROOT->GetColor(gVirtualX->GetFillColor())) != 0 &&
1109 "DrawPolygonWithGradient, the current fill color is not a gradient fill");
1110 const TColorGradient *
const grad =
1111 dynamic_cast<TColorGradient *
>(gROOT->GetColor(gVirtualX->GetFillColor()));
1117 const TGLEnableGuard stencilGuard(GL_STENCIL_TEST);
1122 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1124 glStencilFunc(GL_NEVER, 1, 0xFF);
1125 glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
1127 glStencilMask(0xFF);
1128 glClear(GL_STENCIL_BUFFER_BIT);
1131 DrawTesselation(n, x, y);
1133 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1134 glStencilMask(0x00);
1136 glStencilFunc(GL_EQUAL, 0, 0xFF);
1138 glStencilFunc(GL_EQUAL, 1, 0xFF);
1144 const TRadialGradient *
const rGrad =
dynamic_cast<const TRadialGradient *
>(grad);
1146 DrawGradient(rGrad, n, x, y);
1148 const TLinearGradient *
const lGrad =
dynamic_cast<const TLinearGradient *
>(grad);
1149 assert(lGrad != 0 &&
"DrawPolygonWithGradient, unknown gradient type");
1150 DrawGradient(lGrad, n, x, y);
1156 void TGLPadPainter::DrawGradient(
const TRadialGradient *grad, Int_t nPoints,
1157 const Double_t *xs,
const Double_t *ys)
1159 assert(grad != 0 &&
"DrawGradient, parameter 'grad' is null");
1160 assert(nPoints > 2 &&
"DrawGradient, invalid number of points");
1161 assert(xs != 0 &&
"DrawGradient, parameter 'xs' is null");
1162 assert(ys != 0 &&
"DrawGradient, parameter 'ys' is null");
1164 if (grad->GetGradientType() != TRadialGradient::kSimple) {
1165 ::Warning(
"TGLPadPainter::DrawGradient",
1166 "extended radial gradient is not supported");
1171 const auto &bbox = Rgl::Pad::FindBoundingRect(nPoints, xs, ys);
1173 auto center = grad->GetCenter();
1174 auto radius = grad->GetRadius();
1176 if (grad->GetCoordinateMode() == TColorGradient::kObjectBoundingMode) {
1177 radius *= TMath::Max(bbox.fWidth, bbox.fHeight);
1178 center.fX = bbox.fWidth * center.fX + bbox.fXMin;
1179 center.fY = bbox.fHeight * center.fY + bbox.fYMin;
1181 const auto w = gPad->GetX2() - gPad->GetX1();
1182 const auto h = gPad->GetY2() - gPad->GetY1();
1184 radius *= TMath::Max(w, h);
1189 const auto pixelW = gPad->GetAbsWNDC() * gPad->GetWw();
1190 const auto pixelH = gPad->GetAbsHNDC() * gPad->GetWh();
1192 SaveProjectionMatrix();
1193 SaveModelviewMatrix();
1195 glMatrixMode(GL_PROJECTION);
1198 glOrtho(0., pixelW, 0., pixelH, -10., 10.);
1200 radius *= TMath::Max(pixelH, pixelW);
1201 center.fX = gPad->XtoPixel(center.fX);
1202 center.fY = pixelH - gPad->YtoPixel(center.fY);
1206 const Double_t xMin = gPad->XtoPixel(bbox.fXMin);
1207 const Double_t xMax = gPad->XtoPixel(bbox.fXMax);
1208 const Double_t yMin = pixelH - gPad->YtoPixel(bbox.fYMin);
1209 const Double_t yMax = pixelH - gPad->YtoPixel(bbox.fYMax);
1212 const Double_t maxDistX = TMath::Max(TMath::Abs(center.fX - xMin),
1213 TMath::Abs(center.fX - xMax));
1214 const Double_t maxDistY = TMath::Max(TMath::Abs(center.fY - yMin),
1215 TMath::Abs(center.fY - yMax));
1216 maxR = TMath::Sqrt(maxDistX * maxDistX + maxDistY * maxDistY);
1221 const Bool_t solidFillAfter = maxR > radius;
1224 const UInt_t nSlices = 500;
1226 const auto nColors = grad->GetNumberOfSteps();
1229 const auto nCircles = nColors + 1 + solidFillAfter;
1233 const auto locations = grad->GetColorPositions();
1235 std::vector<Double_t> circles(nSlices * nCircles * 2);
1236 const Double_t angle = TMath::TwoPi() / nSlices;
1239 for (UInt_t i = 0; i < nColors; ++i) {
1240 const auto circle = &circles[i * nSlices * 2];
1242 const auto r = radius * locations[i];
1243 for (UInt_t j = 0, e = nSlices * 2 - 2; j < e; j += 2) {
1244 circle[j] = center.fX + r * TMath::Cos(angle * j);
1245 circle[j + 1] = center.fY + r * TMath::Sin(angle * j);
1248 circle[(nSlices - 1) * 2] = circle[0];
1249 circle[(nSlices - 1) * 2 + 1] = circle[1];
1254 const auto circle = &circles[nColors * nSlices * 2];
1255 for (UInt_t j = 0, e = nSlices * 2 - 2; j < e; j += 2) {
1256 circle[j] = center.fX + radius * TMath::Cos(angle * j);
1257 circle[j + 1] = center.fY + radius * TMath::Sin(angle * j);
1260 circle[(nSlices - 1) * 2] = circle[0];
1261 circle[(nSlices - 1) * 2 + 1] = circle[1];
1264 if (solidFillAfter) {
1266 const auto circle = &circles[(nCircles - 1) * nSlices * 2];
1267 for (UInt_t j = 0, e = nSlices * 2 - 2; j < e; j += 2) {
1268 circle[j] = center.fX + maxR * TMath::Cos(angle * j);
1269 circle[j + 1] = center.fY + maxR * TMath::Sin(angle * j);
1272 circle[(nSlices - 1) * 2] = circle[0];
1273 circle[(nSlices - 1) * 2 + 1] = circle[1];
1284 const auto rgba = grad->GetColors();
1286 const TGLEnableGuard alphaGuard(GL_BLEND);
1288 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1291 glBegin(GL_TRIANGLE_FAN);
1293 glVertex2d(center.fX, center.fY);
1295 for (UInt_t i = 0, e = nSlices * 2; i < e; i += 2)
1296 glVertex2dv(&circles[i]);
1301 for (UInt_t i = 0; i < nColors - 1; ++i) {
1302 const Double_t *
const inner = &circles[i * nSlices * 2];
1303 const auto innerRGBA = rgba + i * 4;
1304 const auto outerRGBA = rgba + (i + 1) * 4;
1305 const Double_t *
const outer = &circles[(i + 1) * nSlices * 2];
1307 Rgl::DrawQuadStripWithRadialGradientFill(nSlices, inner, innerRGBA, outer, outerRGBA);
1312 glBegin(GL_QUAD_STRIP);
1313 const Double_t *
const inner = &circles[nSlices * (nColors - 1) * 2];
1314 const auto solidRGBA = rgba + (nColors - 1) * 4;
1315 const Double_t *
const outer = &circles[nSlices * nColors * 2];
1317 Rgl::DrawQuadStripWithRadialGradientFill(nSlices, inner, solidRGBA, outer, solidRGBA);
1320 if (solidFillAfter) {
1321 glBegin(GL_QUAD_STRIP);
1322 const Double_t *
const inner = &circles[nSlices * nColors * 2];
1323 const auto solidRGBA = rgba + (nColors - 1) * 4;
1324 const Double_t *
const outer = &circles[nSlices * (nColors + 1) * 2];
1326 Rgl::DrawQuadStripWithRadialGradientFill(nSlices, inner, solidRGBA, outer, solidRGBA);
1329 RestoreProjectionMatrix();
1330 RestoreModelviewMatrix();
1335 void TGLPadPainter::DrawGradient(
const TLinearGradient *grad, Int_t n,
1336 const Double_t *x,
const Double_t *y)
1338 assert(grad != 0 &&
"DrawGradient, parameter 'grad' is null");
1339 assert(n > 2 &&
"DrawGradient, invalid number of points");
1340 assert(x != 0 &&
"DrawGradient, parameter 'x' is null");
1341 assert(y != 0 &&
"DrawGradient, parameter 'y' is null");
1348 const auto &bbox = Rgl::Pad::FindBoundingRect(n, x, y);
1353 SaveProjectionMatrix();
1354 SaveModelviewMatrix();
1357 glMatrixMode(GL_PROJECTION);
1360 const Double_t pixelW = gPad->GetAbsWNDC() * gPad->GetWw();
1361 const Double_t pixelH = gPad->GetAbsHNDC() * gPad->GetWh();
1362 glOrtho(0., pixelW, 0., pixelH, -10., 10.);
1365 glMatrixMode(GL_MODELVIEW);
1368 TColorGradient::Point start = grad->GetStart();
1369 TColorGradient::Point end = grad->GetEnd();
1372 if (grad->GetCoordinateMode() == TColorGradient::kPadMode)
1374 const Double_t w = gPad->GetX2() - gPad->GetX1();
1375 const Double_t h = gPad->GetY2() - gPad->GetY1();
1377 start.fX = start.fX * w;
1378 start.fY = start.fY * h;
1379 end.fX = end.fX * w;
1380 end.fY = end.fY * h;
1382 start.fX = start.fX * bbox.fWidth + bbox.fXMin;
1383 start.fY = start.fY * bbox.fHeight + bbox.fYMin;
1384 end.fX = end.fX * bbox.fWidth + bbox.fXMin;
1385 end.fY = end.fY * bbox.fHeight + bbox.fYMin;
1392 start.fX = gPad->XtoPixel(start.fX);
1393 start.fY = pixelH - gPad->YtoPixel(start.fY);
1394 end.fX = gPad->XtoPixel(end.fX);
1395 end.fY = pixelH - gPad->YtoPixel(end.fY);
1396 const Double_t xMin = gPad->XtoPixel(bbox.fXMin);
1397 const Double_t xMax = gPad->XtoPixel(bbox.fXMax);
1398 const Double_t yMin = pixelH - gPad->YtoPixel(bbox.fYMin);
1399 const Double_t yMax = pixelH - gPad->YtoPixel(bbox.fYMax);
1405 const Double_t maxDistX = TMath::Max(TMath::Abs(start.fX - xMin), TMath::Abs(start.fX - xMax));
1406 const Double_t maxDistY = TMath::Max(TMath::Abs(start.fY - yMin), TMath::Abs(start.fY - yMax));
1408 const Double_t startEndLength = TMath::Sqrt((end.fX - start.fX) * (end.fX - start.fX) +
1409 (end.fY - start.fY) * (end.fY - start.fY));
1410 const Double_t h = TMath::Max(TMath::Sqrt(maxDistX * maxDistX + maxDistY * maxDistY),
1414 const Double_t *
const colorPositions = grad->GetColorPositions();
1415 std::vector<Double_t> gradBoxes(grad->GetNumberOfSteps() + 2);
1416 gradBoxes[0] = start.fY - h;
1417 for (
unsigned i = 1; i <= grad->GetNumberOfSteps(); ++i)
1418 gradBoxes[i] = startEndLength * colorPositions[i - 1] + start.fY;
1420 gradBoxes[grad->GetNumberOfSteps() + 1] = start.fY + h;
1423 Double_t angle = TMath::ACos((startEndLength * (end.fY - start.fY)) /
1424 (startEndLength * startEndLength)) * TMath::RadToDeg();
1425 if (end.fX > start.fX)
1428 glTranslated(start.fX, start.fY, 0.);
1429 glRotated(angle, 0., 0., 1.);
1430 glTranslated(-start.fX, -start.fY, 0.);
1432 const Double_t *
const rgba = grad->GetColors();
1434 const unsigned nEdges = gradBoxes.size();
1435 const unsigned nColors = grad->GetNumberOfSteps();
1436 const Double_t xLeft = start.fX - h, xRight = start.fX + h;
1438 const TGLEnableGuard alphaGuard(GL_BLEND);
1440 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1442 Rgl::DrawBoxWithGradientFill(gradBoxes[0], gradBoxes[1], xLeft, xRight, rgba, rgba);
1443 Rgl::DrawBoxWithGradientFill(gradBoxes[nEdges - 2], gradBoxes[nEdges - 1], xLeft, xRight,
1444 rgba + (nColors - 1) * 4, rgba + (nColors - 1) * 4);
1446 for (
unsigned i = 1; i < nEdges - 2; ++i)
1447 Rgl::DrawBoxWithGradientFill(gradBoxes[i], gradBoxes[i + 1], xLeft,
1448 xRight, rgba + (i - 1) * 4, rgba + i * 4);
1450 RestoreProjectionMatrix();
1451 RestoreModelviewMatrix();
1456 void TGLPadPainter::DrawTesselation(Int_t n,
const Double_t *x,
const Double_t *y)
1458 assert(n > 2 &&
"DrawTesselation, invalid number of points");
1459 assert(x != 0 &&
"DrawTesselation, parameter 'x' is null");
1460 assert(y != 0 &&
"DrawTesselation, parameter 'y' is null");
1465 for (Int_t i = 0; i < n; ++i) {
1467 fVs[i * 3 + 1] = y[i];
1468 fVs[i * 3 + 2] = 0.;
1473 GLUtesselator *t = (GLUtesselator *)fTess.GetTess();
1475 gluNextContour(t, (GLenum)GLU_UNKNOWN);
1477 for (Int_t i = 0; i < n; ++i)
1478 gluTessVertex(t, &fVs[i * 3], &fVs[i * 3]);
1487 template<
class ValueType>
1488 void ConvertMarkerPoints(Int_t n,
const ValueType *x,
const ValueType *y, std::vector<TPoint> & dst)
1490 const UInt_t padH = UInt_t(gPad->GetAbsHNDC() * gPad->GetWh());
1493 for (Int_t i = 0; i < n; ++i) {
1494 dst[i].fX = gPad->XtoPixel(x[i]);
1495 dst[i].fY = padH - gPad->YtoPixel(y[i]);