Logo ROOT   6.12/07
Reference Guide
TGLPadPainter.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Timur Pocheptsov 06/05/2009
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2009, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include <stdexcept>
13 #include <cassert>
14 #include <limits>
15 #include <memory>
16 #include <vector>
17 
18 #include "TAttMarker.h"
19 #include "TObjArray.h"
20 #include "TVirtualX.h"
21 #include "TError.h"
22 #include "TImage.h"
23 #include "TROOT.h"
24 #include "TPad.h"
25 
26 #include "TColorGradient.h"
27 #include "TGLPadPainter.h"
28 #include "TGLIncludes.h"
29 #include "TGLUtil.h"
30 #include "TError.h"
31 #include "TMath.h"
32 
33 namespace {
34 
35 ////////////////////////////////////////////////////////////////////////////////
36 ///Not a bad idea to assert on gVirtualX != nullptr
37 
38 bool IsGradientFill(Color_t fillColorIndex)
39 {
40  return dynamic_cast<TColorGradient *>(gROOT->GetColor(fillColorIndex));
41 }
42 
43 }
44 
45 /** \class TGLPadPainter
46 \ingroup opengl
47 "Delegating" part of TGLPadPainter. Line/fill/etc. attributes can be
48 set inside TPad, but not only there:
49 many of them are set by base sub-objects of 2d primitives
50 (2d primitives usually inherit TAttLine or TAttFill etc.). And these sub-objects
51 call gVirtualX->SetLineWidth ... etc. So, if I save some attributes in my painter,
52 it will be mess - at any moment I do not know, where to take line attribute - from
53 gVirtualX or from my own member. So! All attributed, _ALL_ go to/from gVirtualX.
54 */
55 
57 
58 ////////////////////////////////////////////////////////////////////////////////
59 
61  : fIsHollowArea(kFALSE),
62  fLocked(kTRUE)
63 {
64  fVp[0] = fVp[1] = fVp[2] = fVp[3] = 0;
65 }
66 
67 
68 ////////////////////////////////////////////////////////////////////////////////
69 ///Delegate to gVirtualX.
70 
72 {
73  return gVirtualX->GetLineColor();
74 }
75 
76 ////////////////////////////////////////////////////////////////////////////////
77 ///Delegate to gVirtualX.
78 
80 {
81  return gVirtualX->GetLineStyle();
82 }
83 
84 ////////////////////////////////////////////////////////////////////////////////
85 ///Delegate to gVirtualX.
86 
88 {
89  return gVirtualX->GetLineWidth();
90 }
91 
92 ////////////////////////////////////////////////////////////////////////////////
93 ///Delegate to gVirtualX.
94 
96 {
97  gVirtualX->SetLineColor(lcolor);
98 }
99 
100 ////////////////////////////////////////////////////////////////////////////////
101 ///Delegate to gVirtualX.
102 
104 {
105  gVirtualX->SetLineStyle(lstyle);
106 }
107 
108 ////////////////////////////////////////////////////////////////////////////////
109 ///Delegate to gVirtualX.
110 
112 {
113  gVirtualX->SetLineWidth(lwidth);
114 }
115 
116 ////////////////////////////////////////////////////////////////////////////////
117 ///Delegate to gVirtualX.
118 
120 {
121  return gVirtualX->GetFillColor();
122 }
123 
124 ////////////////////////////////////////////////////////////////////////////////
125 ///Delegate to gVirtualX.
126 
128 {
129  return gVirtualX->GetFillStyle();
130 }
131 
132 ////////////////////////////////////////////////////////////////////////////////
133 ///Delegate to gVirtualX.
134 ///IsTransparent is implemented as inline function in TAttFill.
135 
137 {
138  return gVirtualX->IsTransparent();
139 }
140 
141 ////////////////////////////////////////////////////////////////////////////////
142 ///Delegate to gVirtualX.
143 
145 {
146  gVirtualX->SetFillColor(fcolor);
147 }
148 
149 ////////////////////////////////////////////////////////////////////////////////
150 ///Delegate to gVirtualX.
151 
153 {
154  gVirtualX->SetFillStyle(fstyle);
155 }
156 
157 ////////////////////////////////////////////////////////////////////////////////
158 ///Delegate to gVirtualX.
159 
161 {
162  gVirtualX->SetOpacity(percent);
163 }
164 
165 ////////////////////////////////////////////////////////////////////////////////
166 ///Delegate to gVirtualX.
167 
169 {
170  return gVirtualX->GetTextAlign();
171 }
172 
173 ////////////////////////////////////////////////////////////////////////////////
174 ///Delegate to gVirtualX.
175 
177 {
178  return gVirtualX->GetTextAngle();
179 }
180 
181 ////////////////////////////////////////////////////////////////////////////////
182 ///Delegate to gVirtualX.
183 
185 {
186  return gVirtualX->GetTextColor();
187 }
188 
189 ////////////////////////////////////////////////////////////////////////////////
190 ///Delegate to gVirtualX.
191 
193 {
194  return gVirtualX->GetTextFont();
195 }
196 
197 ////////////////////////////////////////////////////////////////////////////////
198 ///Delegate to gVirtualX.
199 
201 {
202  return gVirtualX->GetTextSize();
203 }
204 
205 ////////////////////////////////////////////////////////////////////////////////
206 ///Delegate to gVirtualX.
207 
209 {
210  return gVirtualX->GetTextMagnitude();
211 }
212 
213 ////////////////////////////////////////////////////////////////////////////////
214 ///Delegate to gVirtualX.
215 
217 {
218  gVirtualX->SetTextAlign(align);
219 }
220 
221 ////////////////////////////////////////////////////////////////////////////////
222 ///Delegate to gVirtualX.
223 
225 {
226  gVirtualX->SetTextAngle(tangle);
227 }
228 
229 ////////////////////////////////////////////////////////////////////////////////
230 ///Delegate to gVirtualX.
231 
233 {
234  gVirtualX->SetTextColor(tcolor);
235 }
236 
237 ////////////////////////////////////////////////////////////////////////////////
238 ///Delegate to gVirtualX.
239 
241 {
242  gVirtualX->SetTextFont(tfont);
243 }
244 
245 ////////////////////////////////////////////////////////////////////////////////
246 ///Delegate to gVirtualX.
247 
249 {
250  gVirtualX->SetTextSize(tsize);
251 }
252 
253 ////////////////////////////////////////////////////////////////////////////////
254 ///Delegate to gVirtualX.
255 
257 {
258  gVirtualX->SetTextSizePixels(npixels);
259 }
260 
261 /*
262 "Pixmap" part of TGLPadPainter.
263 */
264 
265 ////////////////////////////////////////////////////////////////////////////////
266 ///Not required at the moment.
267 
269 {
270  return 0;
271 }
272 
273 ////////////////////////////////////////////////////////////////////////////////
274 ///Not required at the moment.
275 
277 {
278 }
279 
280 ////////////////////////////////////////////////////////////////////////////////
281 ///Not required at the moment.
282 
283 void TGLPadPainter::CopyDrawable(Int_t /*device*/, Int_t /*px*/, Int_t /*py*/)
284 {
285 }
286 
287 ////////////////////////////////////////////////////////////////////////////////
288 ///Not required at the moment.
289 
291 {
292 }
293 
294 ////////////////////////////////////////////////////////////////////////////////
295 ///For gVirtualX this means select pixmap (or window)
296 ///and all subsequent drawings will go into
297 ///this pixmap. For OpenGL this means the change of
298 ///coordinate system and viewport.
299 
301 {
302  if (fLocked)
303  return;
304 
305  if (TPad *pad = dynamic_cast<TPad *>(gPad)) {
306  Int_t px = 0, py = 0;
307 
308  pad->XYtoAbsPixel(pad->GetX1(), pad->GetY1(), px, py);
309 
310  py = gPad->GetWh() - py;
311  //
314 
315  glViewport(GLint(px * scale), GLint(py * scale),
316  GLsizei(gPad->GetWw() * pad->GetAbsWNDC() * scale),
317  GLsizei(gPad->GetWh() * pad->GetAbsHNDC() * scale));
318 
319  glMatrixMode(GL_PROJECTION);
320  glLoadIdentity();
321  glOrtho(pad->GetX1(), pad->GetX2(), pad->GetY1(), pad->GetY2(), -10., 10.);
322 
323  glMatrixMode(GL_MODELVIEW);
324  glLoadIdentity();
325  glTranslated(0., 0., -1.);
326  } else {
327  ::Error("TGLPadPainter::SelectDrawable",
328  "function was called not from TPad or TCanvas code\n");
329  throw std::runtime_error("");
330  }
331 }
332 
333 ////////////////////////////////////////////////////////////////////////////////
334 ///Init gl-pad painter:
335 ///1. 2D painter does not use depth test, should not modify
336 /// depth-buffer content (except initial cleanup).
337 ///2. Disable cull face.
338 ///3. Disable lighting.
339 ///4. Set viewport (to the whole canvas area).
340 ///5. Set camera.
341 ///6. Unlock painter.
342 
344 {
345  glDisable(GL_DEPTH_TEST);
346  glDisable(GL_CULL_FACE);
347  glDisable(GL_LIGHTING);
348 
349  //Clear the buffer
350  glViewport(0, 0, GLsizei(gPad->GetWw()), GLsizei(gPad->GetWh()));
351 
352  glDepthMask(GL_TRUE);
353  glClearColor(1.,1.,1.,1.);
354  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
355  glDepthMask(GL_FALSE);
356 
357  glMatrixMode(GL_PROJECTION);
358  glLoadIdentity();
359 
360  glOrtho(gPad->GetX1(), gPad->GetX2(), gPad->GetY1(), gPad->GetY2(), -10., 10.);
361 
362  glMatrixMode(GL_MODELVIEW);
363  glLoadIdentity();
364  glTranslated(0., 0., -1.);
365 
366  fLocked = kFALSE;
367 }
368 
369 ////////////////////////////////////////////////////////////////////////////////
370 ///When TPad::Range for gPad is called, projection
371 ///must be changed in OpenGL.
372 
374 {
375  if (fLocked) return;
376 
377  glMatrixMode(GL_PROJECTION);
378  glLoadIdentity();
379 
380  glOrtho(gPad->GetX1(), gPad->GetX2(), gPad->GetY1(), gPad->GetY2(), -10., 10.);
381 
382  glMatrixMode(GL_MODELVIEW);
383 }
384 
385 ////////////////////////////////////////////////////////////////////////////////
386 ///Locked state of painter means, that
387 ///GL context can be invalid, so no GL calls
388 ///can be executed.
389 
391 {
392  if (fLocked) return;
393 
394  glFinish();
395  fLocked = kTRUE;
396 }
397 
398 /*
399 2D primitives.
400 */
401 
403 
404 ////////////////////////////////////////////////////////////////////////////////
405 ///Draw line segment.
406 
408 {
409  if (fLocked) {
410  //GL pad painter can be called in non-standard situation:
411  //not from TPad::Paint, but
412  //from TView3D::ExecuteRotateView. This means in fact,
413  //that TView3D wants to draw itself in a XOR mode, via
414  //gVirtualX.
415  if (gVirtualX->GetDrawMode() == TVirtualX::kInvert) {
416  gVirtualX->DrawLine(gPad->XtoAbsPixel(x1), gPad->YtoAbsPixel(y1),
417  gPad->XtoAbsPixel(x2), gPad->YtoAbsPixel(y2));
418  }
419 
420  return;
421  }
422 
423  const Rgl::Pad::LineAttribSet lineAttribs(kTRUE, gVirtualX->GetLineStyle(), fLimits.GetMaxLineWidth(), kTRUE);
424 
425  glBegin(GL_LINES);
426  glVertex2d(x1, y1);
427  glVertex2d(x2, y2);
428  glEnd();
429 
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);
437  glBegin(GL_POINTS);
438 
439  glVertex2d(x1, y1);
440  glVertex2d(x2, y2);
441 
442  glEnd();
443  glPointSize(1.f);
444  }
445 
446 }
447 
448 ////////////////////////////////////////////////////////////////////////////////
449 ///Draw line segment in NDC coordinates.
450 
452 {
453  if (fLocked) return;
454 
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();
458 
459  glBegin(GL_LINES);
460  glVertex2d(gPad->GetX1() + u1 * xRange, gPad->GetY1() + v1 * yRange);
461  glVertex2d(gPad->GetX1() + u2 * xRange, gPad->GetY1() + v2 * yRange);
462  glEnd();
463 }
464 
465 ////////////////////////////////////////////////////////////////////////////////
466 ///Draw filled or hollow box.
467 
469 {
470  if (fLocked) return;
471 
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);
476  return;
477  }
478 
479  if (mode == kHollow) {
480  const Rgl::Pad::LineAttribSet lineAttribs(kTRUE, 0, fLimits.GetMaxLineWidth(), kTRUE);
481  //
482  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
483  glRectd(x1, y1, x2, y2);
484  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
485  glLineWidth(1.f);
486  } else {
487  const Rgl::Pad::FillAttribSet fillAttribs(fSSet, kFALSE);//Set filling parameters.
488  glRectd(x1, y1, x2, y2);
489  }
490 }
491 
492 ////////////////////////////////////////////////////////////////////////////////
493 ///Draw tesselated polygon (probably, outline only).
494 
496 {
497  assert(x != 0 && "DrawFillArea, parameter 'x' is null");
498  assert(y != 0 && "DrawFillArea, parameter 'y' is null");
499 
500  if (fLocked)
501  return;
502 
503  if (n < 3) {
504  ::Error("TGLPadPainter::DrawFillArea",
505  "invalid number of points in a polygon");
506  return;
507  }
508 
509  if (IsGradientFill(gVirtualX->GetFillColor()))
510  return DrawPolygonWithGradient(n, x, y);
511 
512  if (!gVirtualX->GetFillStyle()) {
514  return DrawPolyLine(n, x, y);
515  }
516 
517  const Rgl::Pad::FillAttribSet fillAttribs(fSSet, kFALSE);
518  DrawTesselation(n, x, y);
519 }
520 
521 ////////////////////////////////////////////////////////////////////////////////
522 ///Draw tesselated polygon (never called, probably, since TPad::PaintFillArea for floats
523 ///is deprecated).
524 
526 {
527  if (fLocked) return;
528 
529  if (!gVirtualX->GetFillStyle()) {
531  return DrawPolyLine(n, x, y);
532  }
533 
534  fVs.resize(n * 3);
535 
536  for (Int_t i = 0; i < n; ++i) {
537  fVs[i * 3] = x[i];
538  fVs[i * 3 + 1] = y[i];
539  }
540 
541  const Rgl::Pad::FillAttribSet fillAttribs(fSSet, kFALSE);
542 
543  GLUtesselator *t = (GLUtesselator *)fTess.GetTess();
544  gluBeginPolygon(t);
545  gluNextContour(t, (GLenum)GLU_UNKNOWN);
546 
547  for (Int_t i = 0; i < n; ++i)
548  gluTessVertex(t, &fVs[i * 3], &fVs[i * 3]);
549 
550 
551  gluEndPolygon(t);
552 }
553 
554 ////////////////////////////////////////////////////////////////////////////////
555 ///Draw poly-line in user coordinates.
556 
558 {
559  if (fLocked) return;
560 
561  const Rgl::Pad::LineAttribSet lineAttribs(kTRUE, gVirtualX->GetLineStyle(), fLimits.GetMaxLineWidth(), kTRUE);
562 
563  glBegin(GL_LINE_STRIP);
564 
565  for (Int_t i = 0; i < n; ++i)
566  glVertex2d(x[i], y[i]);
567 
568  if (fIsHollowArea) {
569  glVertex2d(x[0], y[0]);
571  }
572  glEnd();
573 
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);
581  glBegin(GL_POINTS);
582 
583  for (Int_t i = 0; i < n; ++i)
584  glVertex2d(x[i], y[i]);
585 
586  glEnd();
587  glPointSize(1.f);
588  }
589 }
590 
591 ////////////////////////////////////////////////////////////////////////////////
592 ///Never called?
593 
595 {
596  if (fLocked) return;
597 
598  const Rgl::Pad::LineAttribSet lineAttribs(kTRUE, gVirtualX->GetLineStyle(), fLimits.GetMaxLineWidth(), kTRUE);
599 
600  glBegin(GL_LINE_STRIP);
601 
602  for (Int_t i = 0; i < n; ++i)
603  glVertex2f(x[i], y[i]);
604 
605  if (fIsHollowArea) {
606  glVertex2f(x[0], y[0]);
608  }
609 
610  glEnd();
611 }
612 
613 ////////////////////////////////////////////////////////////////////////////////
614 ///Poly line in NDC.
615 
617 {
618  if (fLocked) return;
619 
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();
624 
625  glBegin(GL_LINE_STRIP);
626 
627  for (Int_t i = 0; i < n; ++i)
628  glVertex2d(x1 + u[i] * xRange, y1 + v[i] * yRange);
629 
630  glEnd();
631 }
632 
633 namespace {
634 
635 //Aux. function.
636 template<class ValueType>
637 void ConvertMarkerPoints(Int_t n, const ValueType *x, const ValueType *y, std::vector<TPoint> & dst);
638 
639 }
640 
641 ////////////////////////////////////////////////////////////////////////////////
642 ///Poly-marker.
643 
645 {
646  if (fLocked) return;
647 
648  ConvertMarkerPoints(n, x, y, fPoly);
649  DrawPolyMarker();
650 }
651 
652 ////////////////////////////////////////////////////////////////////////////////
653 ///Poly-marker.
654 
656 {
657  if (fLocked) return;
658 
659  ConvertMarkerPoints(n, x, y, fPoly);
660  DrawPolyMarker();
661 }
662 
663 ////////////////////////////////////////////////////////////////////////////////
664 ///Poly-marker.
665 
667 {
668  if (fLocked) return;
669 
671  glLoadIdentity();
672  //
673  glOrtho(0, gPad->GetAbsWNDC() * gPad->GetWw(), 0, gPad->GetAbsHNDC() * gPad->GetWh(), -10., 10.);
674  //
675  glMatrixMode(GL_MODELVIEW);
676  //
677  const TGLEnableGuard blendGuard(GL_BLEND);
678 
679  Float_t rgba[4] = {};
680  Rgl::Pad::ExtractRGBA(gVirtualX->GetMarkerColor(), rgba);
681  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
682  glColor4fv(rgba);
683 
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) {
688  case kDot:
689  fMarker.DrawDot(n, xy);
690  break;
691  case kPlus:
692  fMarker.DrawPlus(n, xy);
693  break;
694  case kStar:
695  case 31:
696  fMarker.DrawStar(n, xy);
697  break;
698  case kCircle:
699  case kOpenCircle:
700  fMarker.DrawCircle(n, xy);
701  break;
702  case kMultiply:
703  fMarker.DrawX(n, xy);
704  break;
705  case kFullDotSmall://"Full dot small"
706  fMarker.DrawFullDotSmall(n, xy);
707  break;
708  case kFullDotMedium:
709  fMarker.DrawFullDotMedium(n, xy);
710  break;
711  case kFullDotLarge:
712  case kFullCircle:
713  fMarker.DrawFullDotLarge(n, xy);
714  break;
715  case kFullSquare:
716  fMarker.DrawFullSquare(n, xy);
717  break;
718  case kFullTriangleUp:
720  break;
721  case kFullTriangleDown:
723  break;
724  case kOpenSquare:
725  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
726  fMarker.DrawFullSquare(n, xy);
727  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
728  break;
729  case kOpenTriangleUp:
730  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
732  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
733  break;
734  case kOpenDiamond:
735  fMarker.DrawDiamond(n, xy);
736  break;
737  case kOpenCross:
738  fMarker.DrawOpenCross(n, xy);
739  break;
740  case kFullStar:
741  fMarker.DrawFullStar(n, xy);
742  break;
743  case kOpenStar:
744  fMarker.DrawOpenStar(n, xy);
745  break;
746  case kOpenTriangleDown:
748  break;
749  case kFullDiamond:
750  fMarker.DrawFullDiamond(n, xy);
751  break;
752  case kFullCross:
753  fMarker.DrawFullCross(n, xy);
754  break;
755  case kOpenDiamondCross:
757  break;
758  case kOpenSquareDiagonal:
760  break;
761  case kOpenThreeTriangles:
763  break;
764  case kOctagonCross:
765  fMarker.DrawOctagonCross(n, xy);
766  break;
767  case kFullThreeTriangles:
769  break;
770  case kOpenFourTrianglesX:
772  break;
773  case kFullFourTrianglesX:
775  break;
776  case kOpenDoubleDiamond:
778  break;
779  case kFullDoubleDiamond:
781  break;
784  break;
787  break;
788  case kOpenCrossX:
789  fMarker.DrawOpenCrossX(n, xy);
790  break;
791  case kFullCrossX:
792  fMarker.DrawFullCrossX(n, xy);
793  break;
794  case kFourSquaresX:
795  fMarker.DrawFourSquaresX(n, xy);
796  break;
797  case kFourSquaresPlus:
799  break;
800  }
801 
803  glMatrixMode(GL_MODELVIEW);
804 }
805 
806 ////////////////////////////////////////////////////////////////////////////////
807 
808 template<class Char>
810 {
812 
813  glLoadIdentity();
814  //
815  glOrtho(0, gPad->GetAbsWNDC() * gPad->GetWw(), 0, gPad->GetAbsHNDC() * gPad->GetWh(), -10., 10.);
816  //
817  glMatrixMode(GL_MODELVIEW);
818 
819  Float_t rgba[4] = {};
820  Rgl::Pad::ExtractRGBA(gVirtualX->GetTextColor(), rgba);
821  glColor4fv(rgba);
822 
823  //10 is the first valid font index.
824  //20 is FreeSerifBold, as in TTF.cxx and in TGLFontManager.cxx.
825  //shift - is the shift to access "extended" fonts.
827 
828  Int_t fontIndex = TMath::Max(Short_t(10), gVirtualX->GetTextFont());
829  if (fontIndex / 10 + shift > TGLFontManager::GetFontFileArray()->GetEntries())
830  fontIndex = 20 + shift * 10;
831  else
832  fontIndex += shift * 10;
833 
834  fFM.RegisterFont(TMath::Max(Int_t(gVirtualX->GetTextSize()) - 1, 10),//kTexture does not work if size < 10.
837  fF.PreRender();
838 
839  const UInt_t padH = UInt_t(gPad->GetAbsHNDC() * gPad->GetWh());
840  fF.Render(text, gPad->XtoPixel(x), padH - gPad->YtoPixel(y), GetTextAngle(), GetTextMagnitude());
841 
842  fF.PostRender();
844 
845  glMatrixMode(GL_MODELVIEW);
846 }
847 
848 ////////////////////////////////////////////////////////////////////////////////
849 ///Draw text. This operation is especially
850 ///dangerous if in locked state -
851 ///ftgl will assert on zero texture size
852 ///(which is result of bad GL context).
853 
855 {
856  if (fLocked) return;
857 
858  if (!gVirtualX->GetTextSize())
859  return;
860 
861  DrawTextHelper(x, y, text, mode);
862 }
863 
864 ////////////////////////////////////////////////////////////////////////////////
865 ///Draw text. This operation is especially
866 ///dangerous if in locked state -
867 ///ftgl will assert on zero texture size
868 ///(which is result of bad GL context).
869 
871 {
872  if (fLocked) return;
873 
874  if (!gVirtualX->GetTextSize())
875  return;
876 
877  DrawTextHelper(x, y, text, mode);
878 }
879 
880 ////////////////////////////////////////////////////////////////////////////////
881 ///Draw text in NDC. This operation is especially
882 ///dangerous if in locked state -
883 ///ftgl will assert on zero texture size
884 ///(which is result of bad GL context).
885 
887 {
888  if (fLocked) return;
889 
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);
893 }
894 
895 ////////////////////////////////////////////////////////////////////////////////
896 ///Draw text in NDC. This operation is especially
897 ///dangerous if in locked state -
898 ///ftgl will assert on zero texture size
899 ///(which is result of bad GL context).
900 
902 {
903  if (fLocked) return;
904 
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);
908 }
909 
910 ////////////////////////////////////////////////////////////////////////////////
911 ///Save the projection matrix.
912 ///Attention! GL_PROJECTION will become the current matrix
913 ///after this call!
914 
916 {
917  glMatrixMode(GL_PROJECTION);
918  glPushMatrix();
919 }
920 
921 ////////////////////////////////////////////////////////////////////////////////
922 ///Restore the projection matrix.
923 ///Attention! GL_PROJECTION will become the current matrix
924 ///after this call!
925 
927 {
928  glMatrixMode(GL_PROJECTION);
929  glPopMatrix();
930 }
931 
932 ////////////////////////////////////////////////////////////////////////////////
933 ///Save the modelview matrix.
934 ///Attention! GL_MODELVIEW will become the current matrix
935 ///after this call!
936 
938 {
939  glMatrixMode(GL_MODELVIEW);
940  glPushMatrix();
941 }
942 
943 ////////////////////////////////////////////////////////////////////////////////
944 ///Restore the modelview matrix.
945 ///Attention! GL_MODELVIEW will become the current matrix
946 ///after this call!
947 
949 {
950  glMatrixMode(GL_MODELVIEW);
951  glPopMatrix();
952 }
953 
954 ////////////////////////////////////////////////////////////////////////////////
955 ///Extract and save the current viewport.
956 
958 {
959  glGetIntegerv(GL_VIEWPORT, fVp);
960 }
961 
962 ////////////////////////////////////////////////////////////////////////////////
963 ///Restore the saved viewport.
964 
966 {
967  glViewport(fVp[0], fVp[1], fVp[2], fVp[3]);
968 }
969 
970 ////////////////////////////////////////////////////////////////////////////////
971 /// Using TImage save frame-buffer contents as a picture.
972 
973 void TGLPadPainter::SaveImage(TVirtualPad *pad, const char *fileName, Int_t type) const
974 {
975  TVirtualPad *canvas = (TVirtualPad *)pad->GetCanvas();
976  if (!canvas)
977  return;
978 
979  gROOT->ProcessLine(Form("((TCanvas *)0x%lx)->Flush();", (ULong_t)canvas));
980 
981  std::vector<unsigned> buff(canvas->GetWw() * canvas->GetWh());
982  glPixelStorei(GL_PACK_ALIGNMENT, 1);
983  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
984  //In case GL_BGRA is not in gl.h (old windows' gl) - comment/uncomment lines.
985  //glReadPixels(0, 0, canvas->GetWw(), canvas->GetWh(), GL_BGRA, GL_UNSIGNED_BYTE, (char *)&buff[0]);
986  glReadPixels(0, 0, canvas->GetWw(), canvas->GetWh(), GL_RGBA, GL_UNSIGNED_BYTE, (char *)&buff[0]);
987 
988  std::unique_ptr<TImage> image(TImage::Create());
989  if (!image.get()) {
990  ::Error("TGLPadPainter::SaveImage", "TImage creation failed");
991  return;
992  }
993 
994  image->DrawRectangle(0, 0, canvas->GetWw(), canvas->GetWh());
995  UInt_t *argb = image->GetArgbArray();
996 
997  if (!argb) {
998  ::Error("TGLPadPainter::SaveImage", "null argb array in TImage object");
999  return;
1000  }
1001 
1002  const Int_t nLines = canvas->GetWh();
1003  const Int_t nPixels = canvas->GetWw();
1004 
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) {
1008  //Uncomment/comment if you don't have GL_BGRA.
1009 
1010  const UInt_t pix = buff[base];
1011  const UInt_t bgra = ((pix & 0xff) << 16) | (pix & 0xff00) |
1012  ((pix & 0xff0000) >> 16) | (pix & 0xff000000);
1013 
1014  //argb[i * nPixels + j] = buff[base];
1015  argb[i * nPixels + j] = bgra;
1016  }
1017  }
1018 
1019  image->WriteImage(fileName, (TImage::EImageFileTypes)type);
1020 }
1021 
1022 ////////////////////////////////////////////////////////////////////////////////
1023 
1024 void TGLPadPainter::DrawPixels(const unsigned char *pixelData, UInt_t width, UInt_t height,
1025  Int_t dstX, Int_t dstY, Bool_t enableBlending)
1026 {
1027  if (fLocked)
1028  return;
1029 
1030  if (!pixelData) {
1031  //I'd prefer an assert.
1032  ::Error("TGLPadPainter::DrawPixels", "pixel data is null");
1033  return;
1034  }
1035 
1036  if (std::numeric_limits<UInt_t>::digits >= 32) {
1037  //TASImage uses bit 31 as ...
1038  //alpha channel flag! FUUUUUUUUUUUUU ..... !!!
1039  CLRBIT(width, 31);
1040  CLRBIT(height, 31);
1041  }
1042 
1043  if (!width) {
1044  //Assert is better.
1045  ::Error("TGLPadPainter::DrawPixels", "invalid width");
1046  return;
1047  }
1048 
1049  if (!height) {
1050  //Assert is better.
1051  ::Error("TGLPadPainter::DrawPixels", "invalid height");
1052  return;
1053  }
1054 
1055  if (TPad *pad = dynamic_cast<TPad *>(gPad)) {
1056  //TASImage passes pixel coordinates in pad's pixmap coordinate space.
1057  //While glRasterPosX said to work with 'window' coordinates,
1058  //that's a lie :) it does not :)
1059 
1060  const Double_t rasterX = Double_t(dstX) / (pad->GetAbsWNDC() * pad->GetWw()) *
1061  (pad->GetX2() - pad->GetX1()) + pad->GetX1();
1062 
1063  const Double_t yRange = pad->GetY2() - pad->GetY1();
1064  const Double_t rasterY = yRange - Double_t(dstY + height) / (pad->GetAbsHNDC() * pad->GetWh()) * yRange +
1065  pad->GetY1();
1066 
1067  GLdouble oldPos[4] = {};
1068  //Save the previous raster pos.
1069  glGetDoublev(GL_CURRENT_RASTER_POSITION, oldPos);
1070 
1071  glRasterPos2d(rasterX, rasterY);
1072  //Stupid asimage provides us upside-down image.
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);
1078 
1079  if (enableBlending) {
1080  glEnable(GL_BLEND);
1081  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1082  }
1083 
1084  glDrawPixels(width, height, GL_BGRA, GL_UNSIGNED_BYTE, &upsideDownImage[0]);
1085 
1086  if (enableBlending)
1087  glDisable(GL_BLEND);
1088 
1089  //Restore raster pos.
1090  glRasterPos2d(oldPos[0], oldPos[1]);
1091  } else
1092  ::Error("TGLPadPainter::DrawPixels", "no pad found to draw");
1093 }
1094 
1095 //Aux. functions - gradient and solid fill of arbitrary area.
1096 
1097 ////////////////////////////////////////////////////////////////////////////////
1098 ///At the moment I assume both linear and radial gradients will work the same way -
1099 ///using a stencil buffer and some big rectangle(s) to fill with a gradient.
1100 ///Thus I have a 'common' part - the part responsible for a stencil test.
1101 
1103 {
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");
1107 
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()));
1112 
1113  if (fLocked)
1114  return;
1115 
1116  //Now, some magic!
1117  const TGLEnableGuard stencilGuard(GL_STENCIL_TEST);
1118 
1119  //TODO: check that the state is restored back correctly after
1120  // we done with a gradient.
1121  //TODO: make sure that we have glDepthMask set to false in general!
1122  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1123 
1124  glStencilFunc(GL_NEVER, 1, 0xFF);
1125  glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);// draw 1s on test fail (always)
1126  //Draw stencil pattern
1127  glStencilMask(0xFF);
1128  glClear(GL_STENCIL_BUFFER_BIT);
1129 
1130  //Draw our polygon into the stencil buffer:
1131  DrawTesselation(n, x, y);
1132 
1133  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1134  glStencilMask(0x00);
1135  //Draw where stencil's value is 0
1136  glStencilFunc(GL_EQUAL, 0, 0xFF);
1137  //Draw only where stencil's value is 1
1138  glStencilFunc(GL_EQUAL, 1, 0xFF);
1139 
1140  //At the moment radial gradient is derived from linear - it was convenient
1141  //at some point, but in fact it was a bad idea. And now I have to
1142  //first check radial gradient.
1143  //TODO: TRadialGradient must inherit TColorGradient directly.
1144  const TRadialGradient * const rGrad = dynamic_cast<const TRadialGradient *>(grad);
1145  if (rGrad)
1146  DrawGradient(rGrad, n, x, y);
1147  else {
1148  const TLinearGradient * const lGrad = dynamic_cast<const TLinearGradient *>(grad);
1149  assert(lGrad != 0 && "DrawPolygonWithGradient, unknown gradient type");
1150  DrawGradient(lGrad, n, x, y);
1151  }
1152 }
1153 
1154 ////////////////////////////////////////////////////////////////////////////////
1155 
1157  const Double_t *xs, const Double_t *ys)
1158 {
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");
1163 
1164  if (grad->GetGradientType() != TRadialGradient::kSimple) {
1165  ::Warning("TGLPadPainter::DrawGradient",
1166  "extended radial gradient is not supported");//yet?
1167  return;
1168  }
1169 
1170  //TODO: check the polygon's bbox!
1171  const auto &bbox = Rgl::Pad::FindBoundingRect(nPoints, xs, ys);
1172  //
1173  auto center = grad->GetCenter();
1174  auto radius = grad->GetRadius();
1175  //Adjust the center and radius depending on coordinate mode.
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;
1180  } else {
1181  const auto w = gPad->GetX2() - gPad->GetX1();
1182  const auto h = gPad->GetY2() - gPad->GetY1();
1183 
1184  radius *= TMath::Max(w, h);
1185  center.fX *= w;
1186  center.fY *= h;
1187  }
1188  //Now for the gradient fill we switch into pixel coordinates:
1189  const auto pixelW = gPad->GetAbsWNDC() * gPad->GetWw();
1190  const auto pixelH = gPad->GetAbsHNDC() * gPad->GetWh();
1191  //
1194  //A new ortho projection:
1195  glMatrixMode(GL_PROJECTION);
1196  glLoadIdentity();
1197  //
1198  glOrtho(0., pixelW, 0., pixelH, -10., 10.);
1199  //
1200  radius *= TMath::Max(pixelH, pixelW);
1201  center.fX = gPad->XtoPixel(center.fX);
1202  center.fY = pixelH - gPad->YtoPixel(center.fY);
1203 
1204  Double_t maxR = 0.;
1205  {
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);
1210  //Get the longest distance from the center to the bounding box vertices
1211  //(this will be the maximum possible radius):
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);
1217  }
1218 
1219  //If gradient 'stops inside the polygon', we use
1220  //the solid fill for the area outside of radial gradient:
1221  const Bool_t solidFillAfter = maxR > radius;
1222  //We emulate a radial gradient using triangles and linear gradient:
1223  //TODO: Can be something smarter? (btw even 100 seems to be enough)
1224  const UInt_t nSlices = 500;
1225 
1226  const auto nColors = grad->GetNumberOfSteps();
1227  //+1 - the strip from the last color's position to radius,
1228  //and (probably) + 1 for solidFillAfter.
1229  const auto nCircles = nColors + 1 + solidFillAfter;
1230 
1231  //TODO: can locations be outside of [0., 1.] ???
1232  //at the moment I assume the answer is NO, NEVER.
1233  const auto locations = grad->GetColorPositions();
1234  // * 2 below == x,y
1235  std::vector<Double_t> circles(nSlices * nCircles * 2);
1236  const Double_t angle = TMath::TwoPi() / nSlices;
1237 
1238  //"Main" circles (for colors at locations[i]).
1239  for (UInt_t i = 0; i < nColors; ++i) {
1240  const auto circle = &circles[i * nSlices * 2];
1241  //TODO: either check locations here or somewhere else.
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);
1246  }
1247  //The "closing" vertices:
1248  circle[(nSlices - 1) * 2] = circle[0];
1249  circle[(nSlices - 1) * 2 + 1] = circle[1];
1250  }
1251 
1252  {
1253  //The strip between lastPos and radius:
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);
1258  }
1259 
1260  circle[(nSlices - 1) * 2] = circle[0];
1261  circle[(nSlices - 1) * 2 + 1] = circle[1];
1262  }
1263 
1264  if (solidFillAfter) {
1265  //The strip after the radius:
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);
1270  }
1271 
1272  circle[(nSlices - 1) * 2] = circle[0];
1273  circle[(nSlices - 1) * 2 + 1] = circle[1];
1274  }
1275 
1276  //Now we draw:
1277  //1) triangle fan in the center (from center to the locations[1],
1278  // with a solid fill).
1279  //2) quad strips for colors.
1280  //3) additional quad strip from the lastLocation to the radius
1281  //4) additional quad strip (if any) from the radius to maxR.
1282 
1283  //RGBA values:
1284  const auto rgba = grad->GetColors();
1285 
1286  const TGLEnableGuard alphaGuard(GL_BLEND);
1287  //TODO?
1288  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1289 
1290  //Probably a degenerated case. Maybe not.
1291  glBegin(GL_TRIANGLE_FAN);
1292  glColor4dv(rgba);
1293  glVertex2d(center.fX, center.fY);
1294 
1295  for (UInt_t i = 0, e = nSlices * 2; i < e; i += 2)
1296  glVertex2dv(&circles[i]);
1297 
1298  glEnd();
1299 
1300  //No auto for circles, explicit types to have const Double_t * const, not Duble_t * const.
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];
1306 
1307  Rgl::DrawQuadStripWithRadialGradientFill(nSlices, inner, innerRGBA, outer, outerRGBA);
1308  }
1309 
1310  //Probably degenerated strip.
1311  {
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];
1316 
1317  Rgl::DrawQuadStripWithRadialGradientFill(nSlices, inner, solidRGBA, outer, solidRGBA);
1318  }
1319 
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];
1325 
1326  Rgl::DrawQuadStripWithRadialGradientFill(nSlices, inner, solidRGBA, outer, solidRGBA);
1327  }
1328 
1331 }
1332 
1333 ////////////////////////////////////////////////////////////////////////////////
1334 
1336  const Double_t *x, const Double_t *y)
1337 {
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");
1342 
1343  //Now we fill the whole scene with one big rectangle
1344  //(group of rectangles) with a gradient fill using
1345  //stencil test.
1346 
1347  //Find a bounding rect.
1348  const auto &bbox = Rgl::Pad::FindBoundingRect(n, x, y);
1349  //TODO: check the bbox??
1350 
1351  //For the gradient fill we switch into the
1352  //pixel coordinates.
1355 
1356  //A new ortho projection:
1357  glMatrixMode(GL_PROJECTION);
1358  glLoadIdentity();
1359 
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.);
1363 
1364  //A new modelview:
1365  glMatrixMode(GL_MODELVIEW);
1366  glLoadIdentity();
1367  //
1368  TColorGradient::Point start = grad->GetStart();
1369  TColorGradient::Point end = grad->GetEnd();
1370 
1371  //Change gradient coordinates from 'NDC' to pad coords:
1373  {
1374  const Double_t w = gPad->GetX2() - gPad->GetX1();
1375  const Double_t h = gPad->GetY2() - gPad->GetY1();
1376 
1377  start.fX = start.fX * w;
1378  start.fY = start.fY * h;
1379  end.fX = end.fX * w;
1380  end.fY = end.fY * h;
1381  } else {
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;
1386  }
1387 
1388  //TODO: with a radial fill we'll have to extract the code
1389  // below into the separate function/and have additional function
1390  // for a radial gradient.
1391  //Now from pad to pixels:
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);
1400  //
1401 
1402  //TODO: check all calculations!
1403 
1404  //Get the longest distance from the start point to the bounding box vertices:
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));
1407 
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),
1411  startEndLength);
1412 
1413  //Boxes with a gradients to emulate gradient fill with many colors:
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;
1419 
1420  gradBoxes[grad->GetNumberOfSteps() + 1] = start.fY + h;
1421 
1422  //Rotation angle - gradient's axis:
1423  Double_t angle = TMath::ACos((startEndLength * (end.fY - start.fY)) /
1424  (startEndLength * startEndLength)) * TMath::RadToDeg();
1425  if (end.fX > start.fX)
1426  angle *= -1;
1427 
1428  glTranslated(start.fX, start.fY, 0.);
1429  glRotated(angle, 0., 0., 1.);
1430  glTranslated(-start.fX, -start.fY, 0.);
1431  //
1432  const Double_t * const rgba = grad->GetColors();
1433 
1434  const unsigned nEdges = gradBoxes.size();
1435  const unsigned nColors = grad->GetNumberOfSteps();
1436  const Double_t xLeft = start.fX - h, xRight = start.fX + h;
1437 
1438  const TGLEnableGuard alphaGuard(GL_BLEND);
1439  //TODO?
1440  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1441 
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);
1445 
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);
1449 
1452 }
1453 
1454 ////////////////////////////////////////////////////////////////////////////////
1455 
1457 {
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");
1461 
1462  //Data for a tesselator:
1463  fVs.resize(n * 3);
1464 
1465  for (Int_t i = 0; i < n; ++i) {
1466  fVs[i * 3] = x[i];
1467  fVs[i * 3 + 1] = y[i];
1468  fVs[i * 3 + 2] = 0.;
1469  }
1470 
1471  //TODO: A very primitive way to tesselate - check what
1472  //kind of polygons we can really have from TPad/TCanvas.
1473  GLUtesselator *t = (GLUtesselator *)fTess.GetTess();
1474  gluBeginPolygon(t);
1475  gluNextContour(t, (GLenum)GLU_UNKNOWN);
1476 
1477  for (Int_t i = 0; i < n; ++i)
1478  gluTessVertex(t, &fVs[i * 3], &fVs[i * 3]);
1479 
1480  gluEndPolygon(t);
1481 }
1482 
1483 
1484 //Aux. functions.
1485 namespace {
1486 
1487 template<class ValueType>
1488 void ConvertMarkerPoints(Int_t n, const ValueType *x, const ValueType *y, std::vector<TPoint> & dst)
1489 {
1490  const UInt_t padH = UInt_t(gPad->GetAbsHNDC() * gPad->GetWh());
1491 
1492  dst.resize(n);
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]);
1496  }
1497 }
1498 
1499 }
1500 
void DrawOpenTrianlgeDown(UInt_t n, const TPoint *xy) const
Double_t GetRadius() const
Get radius.
void SelectDrawable(Int_t device)
For gVirtualX this means select pixmap (or window) and all subsequent drawings will go into this pixm...
void DrawCircle(UInt_t n, const TPoint *xy) const
Color_t GetLineColor() const
Delegate to gVirtualX.
EImageFileTypes
Definition: TImage.h:36
virtual void PreRender(Bool_t autoLight=kTRUE, Bool_t lightOn=kFALSE) const
Set-up GL state before FTFont rendering.
void Render(const char *txt, Double_t x, Double_t y, Double_t angle, Double_t mgn) const
void DrawOpenFourTrianglesX(UInt_t n, const TPoint *xy) const
short Style_t
Definition: RtypesCore.h:76
void SetTextColor(Color_t tcolor)
Delegate to gVirtualX.
Rgl::Pad::PolygonStippleSet fSSet
Definition: TGLPadPainter.h:30
const Point & GetCenter() const
Get center.
static const char * GetFontNameFromId(Int_t)
Get font name from TAttAxis font id.
void LockPainter()
Locked state of painter means, that GL context can be invalid, so no GL calls can be executed...
float Float_t
Definition: RtypesCore.h:53
const Double_t * GetColorPositions() const
Get color positions.
void DrawPolygonWithGradient(Int_t n, const Double_t *x, const Double_t *y)
At the moment I assume both linear and radial gradients will work the same way - using a stencil buff...
ECoordinateMode GetCoordinateMode() const
Get coordinate mode.
constexpr Double_t TwoPi()
Definition: TMath.h:44
void DrawX(UInt_t n, const TPoint *xy) const
void DrawQuadStripWithRadialGradientFill(unsigned nPoints, const Double_t *inner, const Double_t *innerRGBA, const Double_t *outer, const Double_t *outerRGBA)
TODO: is it possible to use GLdouble to avoid problems with Double_t/GLdouble if they are not the sam...
Definition: TGLUtil.cxx:3184
Int_t CreateDrawable(UInt_t w, UInt_t h)
Not required at the moment.
virtual void WriteImage(const char *, EImageFileTypes=TImage::kUnknown)
Definition: TImage.h:115
TH1 * h
Definition: legend2.C:5
void DrawFullFourTrianglesPlus(UInt_t n, const TPoint *xy) const
void DrawPolyLine(Int_t n, const Double_t *x, const Double_t *y)
Draw poly-line in user coordinates.
void SetTextSize(Float_t tsize)
Delegate to gVirtualX.
SizeType_t GetNumberOfSteps() const
Get number of steps.
void ClearDrawable()
Not required at the moment.
Rgl::Pad::Tesselator fTess
Definition: TGLPadPainter.h:31
virtual UInt_t * GetArgbArray()
Definition: TImage.h:237
static Float_t GetScreenScalingFactor()
Returns scaling factor between screen points and GL viewport pixels.
Definition: TGLUtil.cxx:1813
void SetLineColor(Color_t lcolor)
Delegate to gVirtualX.
#define gROOT
Definition: TROOT.h:402
const Point & GetEnd() const
Get end.
void DrawLineNDC(Double_t u1, Double_t v1, Double_t u2, Double_t v2)
Draw line segment in NDC coordinates.
void DrawText(Double_t x, Double_t y, const char *text, ETextMode mode)
Draw text.
#define CLRBIT(n, i)
Definition: Rtypes.h:80
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
const char * Char
Float_t GetTextAngle() const
Delegate to gVirtualX.
void DrawFourSquaresPlus(UInt_t n, const TPoint *xy) const
void SaveModelviewMatrix() const
Save the modelview matrix.
void DrawBoxWithGradientFill(Double_t y1, Double_t y2, Double_t x1, Double_t x2, const Double_t *rgba1, const Double_t *rgba2)
Definition: TGLUtil.cxx:3164
Define a radial color gradient.
void DrawPolyLineNDC(Int_t n, const Double_t *u, const Double_t *v)
Poly line in NDC.
void DrawGradient(const TLinearGradient *gradient, Int_t n, const Double_t *x, const Double_t *y)
short Font_t
Definition: RtypesCore.h:75
void * GetTess() const
Definition: TGLPadUtils.h:180
Short_t Abs(Short_t d)
Definition: TMathBase.h:108
void SaveImage(TVirtualPad *pad, const char *fileName, Int_t type) const
Using TImage save frame-buffer contents as a picture.
void SetTextSizePixels(Int_t npixels)
Delegate to gVirtualX.
void InvalidateCS()
When TPad::Range for gPad is called, projection must be changed in OpenGL.
void RegisterFont(Int_t size, Int_t file, TGLFont::EMode mode, TGLFont &out)
Provide font with given size, file and FTGL class.
static const double x2[5]
Double_t x[n]
Definition: legend1.C:17
void RestoreModelviewMatrix() const
Restore the modelview matrix.
void DrawFullCrossX(UInt_t n, const TPoint *xy) const
void DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, EBoxMode mode)
Draw filled or hollow box.
void ExtractRGBA(Color_t colorIndex, Float_t *rgba)
Rgl::Pad::MarkerPainter fMarker
Definition: TGLPadPainter.h:32
virtual void DrawRectangle(UInt_t, UInt_t, UInt_t, UInt_t, const char *="#000000", UInt_t=1)
Definition: TImage.h:190
std::vector< TPoint > fPoly
Definition: TGLPadPainter.h:42
void RestoreViewport()
Restore the saved viewport.
void SaveProjectionMatrix() const
Save the projection matrix.
void DrawOpenCrossX(UInt_t n, const TPoint *xy) const
void DrawOctagonCross(UInt_t n, const TPoint *xy) const
Short_t GetTextAlign() const
Delegate to gVirtualX.
TVirtualPad is an abstract base class for the Pad and Canvas classes.
Definition: TVirtualPad.h:49
void DrawPolyMarker()
Poly-marker.
void Error(const char *location, const char *msgfmt,...)
short Color_t
Definition: RtypesCore.h:79
Int_t fVp[4]
Definition: TGLPadPainter.h:40
Font_t GetTextFont() const
Delegate to gVirtualX.
Definition: TPoint.h:31
void DrawOpenStar(UInt_t n, const TPoint *xy) const
Full star pentagone.
void DrawPixels(const unsigned char *pixelData, UInt_t width, UInt_t height, Int_t dstX, Int_t dstY, Bool_t enableBlending)
void DrawOpenFourTrianglesPlus(UInt_t n, const TPoint *xy) const
void DrawDot(UInt_t n, const TPoint *xy) const
Simple 1-pixel dots.
void DrawFullThreeTriangles(UInt_t n, const TPoint *xy) const
Bool_t fIsHollowArea
Definition: TGLPadPainter.h:43
const Double_t lineWidthTS
void DrawOpenThreeTriangles(UInt_t n, const TPoint *xy) const
ROOT::R::TRInterface & r
Definition: Object.C:4
static void InitializeIfNeeded()
Initialize globals that require other libraries to be initialized.
Definition: TGLUtil.cxx:1543
void DrawFullFourTrianglesX(UInt_t n, const TPoint *xy) const
void DrawFullDotMedium(UInt_t n, const TPoint *xy) const
SVector< double, 2 > v
Definition: Dict.h:5
XPoint xy[kMAXMK]
Definition: TGX11.cxx:122
"Delegating" part of TGLPadPainter.
Definition: TGLPadPainter.h:28
void DrawFillArea(Int_t n, const Double_t *x, const Double_t *y)
Draw tesselated polygon (probably, outline only).
void DrawPlus(UInt_t n, const TPoint *xy) const
Color_t GetTextColor() const
Delegate to gVirtualX.
void DrawFullStar(UInt_t n, const TPoint *xy) const
Full star pentagone.
unsigned int UInt_t
Definition: RtypesCore.h:42
The most important graphics class in the ROOT system.
Definition: TPad.h:29
char * Form(const char *fmt,...)
void CopyDrawable(Int_t device, Int_t px, Int_t py)
Not required at the moment.
void SaveViewport()
Extract and save the current viewport.
short Short_t
Definition: RtypesCore.h:35
Rgl::Pad::GLLimits fLimits
Definition: TGLPadPainter.h:33
void DrawFullDotSmall(UInt_t n, const TPoint *xy) const
Double_t ACos(Double_t)
Definition: TMath.h:571
void SetFillStyle(Style_t fstyle)
Delegate to gVirtualX.
void Warning(const char *location, const char *msgfmt,...)
void DrawOpenDiamondCross(UInt_t n, const TPoint *xy) const
void DrawFullTrianlgeDown(UInt_t n, const TPoint *xy) const
void SetTextAlign(Short_t align)
Delegate to gVirtualX.
#define gVirtualX
Definition: TVirtualX.h:350
Double_t Cos(Double_t)
Definition: TMath.h:550
short Width_t
Definition: RtypesCore.h:78
std::vector< Double_t > fVs
Definition: TGLPadPainter.h:35
const Bool_t kFALSE
Definition: RtypesCore.h:88
void DrawTextNDC(Double_t x, Double_t y, const char *text, ETextMode mode)
Draw text in NDC.
Color_t GetFillColor() const
Delegate to gVirtualX.
Define a linear color gradient.
void SetFillColor(Color_t fcolor)
Delegate to gVirtualX.
void DrawFourSquaresX(UInt_t n, const TPoint *xy) const
Double_t GetMaxLineWidth() const
Double_t GetMaxPointSize() const
Style_t GetLineStyle() const
Delegate to gVirtualX.
const Point & GetStart() const
Get start.
void SetTextAngle(Float_t tangle)
Delegate to gVirtualX.
static const double x1[5]
void RestoreProjectionMatrix() const
Restore the projection matrix.
#define ClassImp(name)
Definition: Rtypes.h:359
double Double_t
Definition: RtypesCore.h:55
TText * text
void DrawDiamond(UInt_t n, const TPoint *xy) const
void DrawStar(UInt_t n, const TPoint *xy) const
int type
Definition: TGX11.cxx:120
unsigned long ULong_t
Definition: RtypesCore.h:51
Double_t y[n]
Definition: legend1.C:17
void DrawFullDotLarge(UInt_t n, const TPoint *xy) const
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
void InitPainter()
Init gl-pad painter:
void DrawFullSquare(UInt_t n, const TPoint *xy) const
BoundingRect< ValueType > FindBoundingRect(Int_t nPoints, const ValueType *xs, const ValueType *ys)
constexpr Double_t RadToDeg()
Definition: TMath.h:60
void DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Draw line segment.
Style_t GetFillStyle() const
Delegate to gVirtualX.
virtual void PostRender() const
Reset GL state after FTFont rendering.
TGLFontManager fFM
Definition: TGLPadPainter.h:37
void DrawOpenDoubleDiamond(UInt_t n, const TPoint *xy) const
EGradientType GetGradientType() const
Get gradient type.
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:200
Bool_t IsTransparent() const
Delegate to gVirtualX.
void DrawTextHelper(Double_t x, Double_t y, const Char_t *text, ETextMode mode)
Double_t Sin(Double_t)
Definition: TMath.h:547
void DrawOpenCross(UInt_t n, const TPoint *xy) const
void DrawFullTrianlgeUp(UInt_t n, const TPoint *xy) const
const Double_t * GetColors() const
Get colors.
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:522
#define gPad
Definition: TVirtualPad.h:285
void SetTextFont(Font_t tfont)
Delegate to gVirtualX.
void SetLineStyle(Style_t lstyle)
Delegate to gVirtualX.
void SetLineWidth(Width_t lwidth)
Delegate to gVirtualX.
#define GL_BGRA
Definition: TGLViewer.cxx:64
static TObjArray * GetFontFileArray()
Get id to file name map.
static Int_t GetExtendedFontStartIndex()
void DestroyDrawable(Int_t device)
Not required at the moment.
Float_t GetTextSize() const
Delegate to gVirtualX.
Double_t Sqrt(Double_t x)
Definition: TMath.h:590
static TImage * Create()
Create an image.
Definition: TImage.cxx:36
TColorGradient extends basic TColor.
void DrawFullCross(UInt_t n, const TPoint *xy) const
void SetOpacity(Int_t percent)
Delegate to gVirtualX.
Float_t GetTextMagnitude() const
Delegate to gVirtualX.
const Bool_t kTRUE
Definition: RtypesCore.h:87
Width_t GetLineWidth() const
Delegate to gVirtualX.
const Int_t n
Definition: legend1.C:16
void DrawFullDiamond(UInt_t n, const TPoint *xy) const
void DrawFullDoubleDiamond(UInt_t n, const TPoint *xy) const
void DrawTesselation(Int_t n, const Double_t *x, const Double_t *y)
void DrawOpenSquareDiagonal(UInt_t n, const TPoint *xy) const
virtual TCanvas * GetCanvas() const =0