Logo ROOT   6.10/00
Reference Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 /*id*/, 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 
Color_t GetFillColor() const
Delegate to gVirtualX.
void DrawDot(UInt_t n, const TPoint *xy) const
Simple 1-pixel dots.
void SelectDrawable(Int_t device)
For gVirtualX this means select pixmap (or window) and all subsequent drawings will go into this pixm...
void * GetTess() const
Definition: TGLPadUtils.h:180
void DrawOpenSquareDiagonal(UInt_t n, const TPoint *xy) const
EImageFileTypes
Definition: TImage.h:36
void DrawFullDotLarge(UInt_t n, const TPoint *xy) const
void DrawOpenFourTrianglesPlus(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
void DrawOctagonCross(UInt_t n, const TPoint *xy) const
static const char * GetFontNameFromId(Int_t)
Get font name from TAttAxis font id.
ECoordinateMode GetCoordinateMode() const
Get coordinate mode.
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
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...
constexpr Double_t TwoPi()
Definition: TMath.h:44
Double_t GetMaxLineWidth() 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.
void DrawFourSquaresX(UInt_t n, const TPoint *xy) const
virtual void WriteImage(const char *, EImageFileTypes=TImage::kUnknown)
Definition: TImage.h:115
TH1 * h
Definition: legend2.C:5
void DrawCircle(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.
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:375
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:77
void DrawFullDoubleDiamond(UInt_t n, const TPoint *xy) const
Width_t GetLineWidth() const
Delegate to gVirtualX.
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
Bool_t IsTransparent() const
Delegate to gVirtualX.
void DrawFullTrianlgeDown(UInt_t n, const TPoint *xy) const
const char * Char
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
const Point & GetCenter() const
Get center.
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
Short_t Abs(Short_t d)
Definition: TMathBase.h:108
void SetTextSizePixels(Int_t npixels)
Delegate to gVirtualX.
void DrawFullFourTrianglesPlus(UInt_t n, const TPoint *xy) const
void DrawDiamond(UInt_t n, const TPoint *xy) const
void InvalidateCS()
When TPad::Range for gPad is called, projection must be changed in OpenGL.
void DrawFullDotMedium(UInt_t n, const TPoint *xy) const
void DrawFullThreeTriangles(UInt_t n, const TPoint *xy) const
void RegisterFont(Int_t size, Int_t file, TGLFont::EMode mode, TGLFont &out)
Provide font with given size, file and FTGL class.
void DrawFullFourTrianglesX(UInt_t n, const TPoint *xy) const
static const double x2[5]
Double_t x[n]
Definition: legend1.C:17
void Render(const char *txt, Double_t x, Double_t y, Double_t angle, Double_t mgn) const
void DrawOpenThreeTriangles(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
Short_t GetTextAlign() const
Delegate to gVirtualX.
void RestoreViewport()
Restore the saved viewport.
void DrawFullSquare(UInt_t n, const TPoint *xy) const
void DrawFullDotSmall(UInt_t n, const TPoint *xy) const
void DrawOpenDiamondCross(UInt_t n, const TPoint *xy) const
void DrawOpenTrianlgeDown(UInt_t n, const TPoint *xy) const
void DrawFullDiamond(UInt_t n, const TPoint *xy) const
TVirtualPad is an abstract base class for the Pad and Canvas classes.
Definition: TVirtualPad.h:49
void DrawPolyMarker()
Poly-marker.
void DrawFullStar(UInt_t n, const TPoint *xy) const
Full star pentagone.
void Error(const char *location, const char *msgfmt,...)
short Color_t
Definition: RtypesCore.h:79
Int_t fVp[4]
Definition: TGLPadPainter.h:40
void DrawPlus(UInt_t n, const TPoint *xy) const
Definition: TPoint.h:31
void CopyDrawable(Int_t id, Int_t px, Int_t py)
Not required at the moment.
void DrawFullCross(UInt_t n, const TPoint *xy) const
void DrawPixels(const unsigned char *pixelData, UInt_t width, UInt_t height, Int_t dstX, Int_t dstY, Bool_t enableBlending)
Bool_t fIsHollowArea
Definition: TGLPadPainter.h:43
const Double_t lineWidthTS
void RestoreProjectionMatrix() const
Restore the projection matrix.
TRandom2 r(17)
Double_t GetRadius() const
Get radius.
static void InitializeIfNeeded()
Initialize globals that require other libraries to be initialized.
Definition: TGLUtil.cxx:1543
SVector< double, 2 > v
Definition: Dict.h:5
XPoint xy[kMAXMK]
Definition: TGX11.cxx:122
Float_t GetTextSize() const
Delegate to gVirtualX.
SizeType_t GetNumberOfSteps() const
Get number of steps.
void DrawFullTrianlgeUp(UInt_t n, const TPoint *xy) const
&quot;Delegating&quot; 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).
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,...)
const Point & GetEnd() const
Get end.
void DrawStar(UInt_t n, const TPoint *xy) const
void SaveViewport()
Extract and save the current viewport.
Color_t GetTextColor() const
Delegate to gVirtualX.
virtual void PostRender() const
Reset GL state after FTFont rendering.
short Short_t
Definition: RtypesCore.h:35
Rgl::Pad::GLLimits fLimits
Definition: TGLPadPainter.h:33
Double_t ACos(Double_t)
Definition: TMath.h:572
void SetFillStyle(Style_t fstyle)
Delegate to gVirtualX.
void SaveModelviewMatrix() const
Save the modelview matrix.
void Warning(const char *location, const char *msgfmt,...)
void RestoreModelviewMatrix() const
Restore the modelview matrix.
void SetTextAlign(Short_t align)
Delegate to gVirtualX.
#define gVirtualX
Definition: TVirtualX.h:350
Double_t Cos(Double_t)
Definition: TMath.h:551
short Width_t
Definition: RtypesCore.h:78
Double_t GetMaxPointSize() const
std::vector< Double_t > fVs
Definition: TGLPadPainter.h:35
const Bool_t kFALSE
Definition: RtypesCore.h:92
void DrawTextNDC(Double_t x, Double_t y, const char *text, ETextMode mode)
Draw text in NDC.
Define a linear color gradient.
void SetFillColor(Color_t fcolor)
Delegate to gVirtualX.
EGradientType GetGradientType() const
Get gradient type.
const Double_t * GetColors() const
Get colors.
void SetTextAngle(Float_t tangle)
Delegate to gVirtualX.
void DrawOpenCross(UInt_t n, const TPoint *xy) const
void DrawOpenDoubleDiamond(UInt_t n, const TPoint *xy) const
static const double x1[5]
#define ClassImp(name)
Definition: Rtypes.h:336
double f(double x)
double Double_t
Definition: RtypesCore.h:55
void SaveProjectionMatrix() const
Save the projection matrix.
TText * text
int type
Definition: TGX11.cxx:120
unsigned long ULong_t
Definition: RtypesCore.h:51
Double_t y[n]
Definition: legend1.C:17
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:
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:494
const Point & GetStart() const
Get start.
BoundingRect< ValueType > FindBoundingRect(Int_t nPoints, const ValueType *xs, const ValueType *ys)
void SaveImage(TVirtualPad *pad, const char *fileName, Int_t type) const
Using TImage save frame-buffer contents as a picture.
void DrawOpenFourTrianglesX(UInt_t n, const TPoint *xy) const
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 GetLineStyle() const
Delegate to gVirtualX.
Font_t GetTextFont() const
Delegate to gVirtualX.
void DrawOpenCrossX(UInt_t n, const TPoint *xy) const
TGLFontManager fFM
Definition: TGLPadPainter.h:37
const Double_t * GetColorPositions() const
Get color positions.
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:200
void DrawTextHelper(Double_t x, Double_t y, const Char_t *text, ETextMode mode)
Double_t Sin(Double_t)
Definition: TMath.h:548
Float_t GetTextAngle() const
Delegate to gVirtualX.
#define gPad
Definition: TVirtualPad.h:284
virtual void PreRender(Bool_t autoLight=kTRUE, Bool_t lightOn=kFALSE) const
Set-up GL state before FTFont rendering.
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.
Style_t GetFillStyle() const
Delegate to gVirtualX.
static Int_t GetExtendedFontStartIndex()
Double_t Sqrt(Double_t x)
Definition: TMath.h:591
static TImage * Create()
Create an image.
Definition: TImage.cxx:36
void DestroyDrawable()
Not required at the moment.
Color_t GetLineColor() const
Delegate to gVirtualX.
TColorGradient extends basic TColor.
void SetOpacity(Int_t percent)
Delegate to gVirtualX.
const Bool_t kTRUE
Definition: RtypesCore.h:91
Float_t GetTextMagnitude() const
Delegate to gVirtualX.
void DrawX(UInt_t n, const TPoint *xy) const
const Int_t n
Definition: legend1.C:16
void DrawOpenStar(UInt_t n, const TPoint *xy) const
Full star pentagone.
void DrawFourSquaresPlus(UInt_t n, const TPoint *xy) const
void DrawFullCrossX(UInt_t n, const TPoint *xy) const
void DrawTesselation(Int_t n, const Double_t *x, const Double_t *y)
virtual TCanvas * GetCanvas() const =0