Logo ROOT   6.08/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 /*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  fMarker.DrawStar(n, xy);
696  break;
697  case kCircle:
698  case kOpenCircle:
699  fMarker.DrawCircle(n, xy);
700  break;
701  case kMultiply:
702  fMarker.DrawX(n, xy);
703  break;
704  case kFullDotSmall://"Full dot small"
705  fMarker.DrawFullDotSmall(n, xy);
706  break;
707  case kFullDotMedium:
708  fMarker.DrawFullDotMedium(n, xy);
709  break;
710  case kFullDotLarge:
711  case kFullCircle:
712  fMarker.DrawFullDotLarge(n, xy);
713  break;
714  case kFullSquare:
715  fMarker.DrawFullSquare(n, xy);
716  break;
717  case kFullTriangleUp:
719  break;
720  case kFullTriangleDown:
722  break;
723  case kOpenSquare:
724  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
725  fMarker.DrawFullSquare(n, xy);
726  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
727  break;
728  case kOpenTriangleUp:
729  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
731  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
732  break;
733  case kOpenDiamond:
734  fMarker.DrawDiamond(n, xy);
735  break;
736  case kOpenCross:
737  fMarker.DrawCross(n, xy);
738  break;
739  case kFullStar:
740  fMarker.DrawFullStar(n, xy);
741  break;
742  case kOpenStar:
743  fMarker.DrawOpenStar(n, xy);
744  }
745 
747  glMatrixMode(GL_MODELVIEW);
748 }
749 
750 ////////////////////////////////////////////////////////////////////////////////
751 
752 template<class Char>
754 {
756 
757  glLoadIdentity();
758  //
759  glOrtho(0, gPad->GetAbsWNDC() * gPad->GetWw(), 0, gPad->GetAbsHNDC() * gPad->GetWh(), -10., 10.);
760  //
761  glMatrixMode(GL_MODELVIEW);
762 
763  Float_t rgba[4] = {};
764  Rgl::Pad::ExtractRGBA(gVirtualX->GetTextColor(), rgba);
765  glColor4fv(rgba);
766 
767  //10 is the first valid font index.
768  //20 is FreeSerifBold, as in TTF.cxx and in TGLFontManager.cxx.
769  //shift - is the shift to access "extended" fonts.
771 
772  Int_t fontIndex = TMath::Max(Short_t(10), gVirtualX->GetTextFont());
773  if (fontIndex / 10 + shift > TGLFontManager::GetFontFileArray()->GetEntries())
774  fontIndex = 20 + shift * 10;
775  else
776  fontIndex += shift * 10;
777 
778  fFM.RegisterFont(TMath::Max(Int_t(gVirtualX->GetTextSize()) - 1, 10),//kTexture does not work if size < 10.
781  fF.PreRender();
782 
783  const UInt_t padH = UInt_t(gPad->GetAbsHNDC() * gPad->GetWh());
784  fF.Render(text, gPad->XtoPixel(x), padH - gPad->YtoPixel(y), GetTextAngle(), GetTextMagnitude());
785 
786  fF.PostRender();
788 
789  glMatrixMode(GL_MODELVIEW);
790 }
791 
792 ////////////////////////////////////////////////////////////////////////////////
793 ///Draw text. This operation is especially
794 ///dangerous if in locked state -
795 ///ftgl will assert on zero texture size
796 ///(which is result of bad GL context).
797 
799 {
800  if (fLocked) return;
801 
802  if (!gVirtualX->GetTextSize())
803  return;
804 
805  DrawTextHelper(x, y, text, mode);
806 }
807 
808 ////////////////////////////////////////////////////////////////////////////////
809 ///Draw text. This operation is especially
810 ///dangerous if in locked state -
811 ///ftgl will assert on zero texture size
812 ///(which is result of bad GL context).
813 
815 {
816  if (fLocked) return;
817 
818  if (!gVirtualX->GetTextSize())
819  return;
820 
821  DrawTextHelper(x, y, text, mode);
822 }
823 
824 ////////////////////////////////////////////////////////////////////////////////
825 ///Draw text in NDC. This operation is especially
826 ///dangerous if in locked state -
827 ///ftgl will assert on zero texture size
828 ///(which is result of bad GL context).
829 
831 {
832  if (fLocked) return;
833 
834  const Double_t xRange = gPad->GetX2() - gPad->GetX1();
835  const Double_t yRange = gPad->GetY2() - gPad->GetY1();
836  DrawText(gPad->GetX1() + u * xRange, gPad->GetY1() + v * yRange, text, mode);
837 }
838 
839 ////////////////////////////////////////////////////////////////////////////////
840 ///Draw text in NDC. This operation is especially
841 ///dangerous if in locked state -
842 ///ftgl will assert on zero texture size
843 ///(which is result of bad GL context).
844 
846 {
847  if (fLocked) return;
848 
849  const Double_t xRange = gPad->GetX2() - gPad->GetX1();
850  const Double_t yRange = gPad->GetY2() - gPad->GetY1();
851  DrawText(gPad->GetX1() + u * xRange, gPad->GetY1() + v * yRange, text, mode);
852 }
853 
854 ////////////////////////////////////////////////////////////////////////////////
855 ///Save the projection matrix.
856 ///Attention! GL_PROJECTION will become the current matrix
857 ///after this call!
858 
860 {
861  glMatrixMode(GL_PROJECTION);
862  glPushMatrix();
863 }
864 
865 ////////////////////////////////////////////////////////////////////////////////
866 ///Restore the projection matrix.
867 ///Attention! GL_PROJECTION will become the current matrix
868 ///after this call!
869 
871 {
872  glMatrixMode(GL_PROJECTION);
873  glPopMatrix();
874 }
875 
876 ////////////////////////////////////////////////////////////////////////////////
877 ///Save the modelview matrix.
878 ///Attention! GL_MODELVIEW will become the current matrix
879 ///after this call!
880 
882 {
883  glMatrixMode(GL_MODELVIEW);
884  glPushMatrix();
885 }
886 
887 ////////////////////////////////////////////////////////////////////////////////
888 ///Restore the modelview matrix.
889 ///Attention! GL_MODELVIEW will become the current matrix
890 ///after this call!
891 
893 {
894  glMatrixMode(GL_MODELVIEW);
895  glPopMatrix();
896 }
897 
898 ////////////////////////////////////////////////////////////////////////////////
899 ///Extract and save the current viewport.
900 
902 {
903  glGetIntegerv(GL_VIEWPORT, fVp);
904 }
905 
906 ////////////////////////////////////////////////////////////////////////////////
907 ///Restore the saved viewport.
908 
910 {
911  glViewport(fVp[0], fVp[1], fVp[2], fVp[3]);
912 }
913 
914 ////////////////////////////////////////////////////////////////////////////////
915 /// Using TImage save frame-buffer contents as a picture.
916 
917 void TGLPadPainter::SaveImage(TVirtualPad *pad, const char *fileName, Int_t type) const
918 {
919  TVirtualPad *canvas = (TVirtualPad *)pad->GetCanvas();
920  if (!canvas)
921  return;
922 
923  gROOT->ProcessLine(Form("((TCanvas *)0x%lx)->Flush();", (ULong_t)canvas));
924 
925  std::vector<unsigned> buff(canvas->GetWw() * canvas->GetWh());
926  glPixelStorei(GL_PACK_ALIGNMENT, 1);
927  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
928  //In case GL_BGRA is not in gl.h (old windows' gl) - comment/uncomment lines.
929  //glReadPixels(0, 0, canvas->GetWw(), canvas->GetWh(), GL_BGRA, GL_UNSIGNED_BYTE, (char *)&buff[0]);
930  glReadPixels(0, 0, canvas->GetWw(), canvas->GetWh(), GL_RGBA, GL_UNSIGNED_BYTE, (char *)&buff[0]);
931 
932  std::unique_ptr<TImage> image(TImage::Create());
933  if (!image.get()) {
934  ::Error("TGLPadPainter::SaveImage", "TImage creation failed");
935  return;
936  }
937 
938  image->DrawRectangle(0, 0, canvas->GetWw(), canvas->GetWh());
939  UInt_t *argb = image->GetArgbArray();
940 
941  if (!argb) {
942  ::Error("TGLPadPainter::SaveImage", "null argb array in TImage object");
943  return;
944  }
945 
946  const Int_t nLines = canvas->GetWh();
947  const Int_t nPixels = canvas->GetWw();
948 
949  for (Int_t i = 0; i < nLines; ++i) {
950  Int_t base = (nLines - 1 - i) * nPixels;
951  for (Int_t j = 0; j < nPixels; ++j, ++base) {
952  //Uncomment/comment if you don't have GL_BGRA.
953 
954  const UInt_t pix = buff[base];
955  const UInt_t bgra = ((pix & 0xff) << 16) | (pix & 0xff00) |
956  ((pix & 0xff0000) >> 16) | (pix & 0xff000000);
957 
958  //argb[i * nPixels + j] = buff[base];
959  argb[i * nPixels + j] = bgra;
960  }
961  }
962 
963  image->WriteImage(fileName, (TImage::EImageFileTypes)type);
964 }
965 
966 ////////////////////////////////////////////////////////////////////////////////
967 
968 void TGLPadPainter::DrawPixels(const unsigned char *pixelData, UInt_t width, UInt_t height,
969  Int_t dstX, Int_t dstY, Bool_t enableBlending)
970 {
971  if (fLocked)
972  return;
973 
974  if (!pixelData) {
975  //I'd prefer an assert.
976  ::Error("TGLPadPainter::DrawPixels", "pixel data is null");
977  return;
978  }
979 
980  if (std::numeric_limits<UInt_t>::digits >= 32) {
981  //TASImage uses bit 31 as ...
982  //alpha channel flag! FUUUUUUUUUUUUU ..... !!!
983  CLRBIT(width, 31);
984  CLRBIT(height, 31);
985  }
986 
987  if (!width) {
988  //Assert is better.
989  ::Error("TGLPadPainter::DrawPixels", "invalid width");
990  return;
991  }
992 
993  if (!height) {
994  //Assert is better.
995  ::Error("TGLPadPainter::DrawPixels", "invalid height");
996  return;
997  }
998 
999  if (TPad *pad = dynamic_cast<TPad *>(gPad)) {
1000  //TASImage passes pixel coordinates in pad's pixmap coordinate space.
1001  //While glRasterPosX said to work with 'window' coordinates,
1002  //that's a lie :) it does not :)
1003 
1004  const Double_t rasterX = Double_t(dstX) / (pad->GetAbsWNDC() * pad->GetWw()) *
1005  (pad->GetX2() - pad->GetX1()) + pad->GetX1();
1006 
1007  const Double_t yRange = pad->GetY2() - pad->GetY1();
1008  const Double_t rasterY = yRange - Double_t(dstY + height) / (pad->GetAbsHNDC() * pad->GetWh()) * yRange +
1009  pad->GetY1();
1010 
1011  GLdouble oldPos[4] = {};
1012  //Save the previous raster pos.
1013  glGetDoublev(GL_CURRENT_RASTER_POSITION, oldPos);
1014 
1015  glRasterPos2d(rasterX, rasterY);
1016  //Stupid asimage provides us upside-down image.
1017  std::vector<unsigned char> upsideDownImage(4 * width * height);
1018  const unsigned char *srcLine = pixelData + 4 * width * (height - 1);
1019  unsigned char *dstLine = &upsideDownImage[0];
1020  for (UInt_t i = 0; i < height; ++i, srcLine -= 4 * width, dstLine += 4 * width)
1021  std::copy(srcLine, srcLine + 4 * width, dstLine);
1022 
1023  if (enableBlending) {
1024  glEnable(GL_BLEND);
1025  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1026  }
1027 
1028  glDrawPixels(width, height, GL_BGRA, GL_UNSIGNED_BYTE, &upsideDownImage[0]);
1029 
1030  if (enableBlending)
1031  glDisable(GL_BLEND);
1032 
1033  //Restore raster pos.
1034  glRasterPos2d(oldPos[0], oldPos[1]);
1035  } else
1036  ::Error("TGLPadPainter::DrawPixels", "no pad found to draw");
1037 }
1038 
1039 //Aux. functions - gradient and solid fill of arbitrary area.
1040 
1041 ////////////////////////////////////////////////////////////////////////////////
1042 ///At the moment I assume both linear and radial gradients will work the same way -
1043 ///using a stencil buffer and some big rectangle(s) to fill with a gradient.
1044 ///Thus I have a 'common' part - the part responsible for a stencil test.
1045 
1047 {
1048  assert(n > 2 && "DrawPolygonWithGradient, invalid number of points");
1049  assert(x != 0 && "DrawPolygonWithGradient, parameter 'x' is null");
1050  assert(y != 0 && "DrawPolygonWithGradient, parameter 'y' is null");
1051 
1052  assert(dynamic_cast<TColorGradient *>(gROOT->GetColor(gVirtualX->GetFillColor())) != 0 &&
1053  "DrawPolygonWithGradient, the current fill color is not a gradient fill");
1054  const TColorGradient * const grad =
1055  dynamic_cast<TColorGradient *>(gROOT->GetColor(gVirtualX->GetFillColor()));
1056 
1057  if (fLocked)
1058  return;
1059 
1060  //Now, some magic!
1061  const TGLEnableGuard stencilGuard(GL_STENCIL_TEST);
1062 
1063  //TODO: check that the state is restored back correctly after
1064  // we done with a gradient.
1065  //TODO: make sure that we have glDepthMask set to false in general!
1066  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1067 
1068  glStencilFunc(GL_NEVER, 1, 0xFF);
1069  glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);// draw 1s on test fail (always)
1070  //Draw stencil pattern
1071  glStencilMask(0xFF);
1072  glClear(GL_STENCIL_BUFFER_BIT);
1073 
1074  //Draw our polygon into the stencil buffer:
1075  DrawTesselation(n, x, y);
1076 
1077  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1078  glStencilMask(0x00);
1079  //Draw where stencil's value is 0
1080  glStencilFunc(GL_EQUAL, 0, 0xFF);
1081  //Draw only where stencil's value is 1
1082  glStencilFunc(GL_EQUAL, 1, 0xFF);
1083 
1084  //At the moment radial gradient is derived from linear - it was convenient
1085  //at some point, but in fact it was a bad idea. And now I have to
1086  //first check radial gradient.
1087  //TODO: TRadialGradient must inherit TColorGradient directly.
1088  const TRadialGradient * const rGrad = dynamic_cast<const TRadialGradient *>(grad);
1089  if (rGrad)
1090  DrawGradient(rGrad, n, x, y);
1091  else {
1092  const TLinearGradient * const lGrad = dynamic_cast<const TLinearGradient *>(grad);
1093  assert(lGrad != 0 && "DrawPolygonWithGradient, unknown gradient type");
1094  DrawGradient(lGrad, n, x, y);
1095  }
1096 }
1097 
1098 ////////////////////////////////////////////////////////////////////////////////
1099 
1101  const Double_t *xs, const Double_t *ys)
1102 {
1103  assert(grad != 0 && "DrawGradient, parameter 'grad' is null");
1104  assert(nPoints > 2 && "DrawGradient, invalid number of points");
1105  assert(xs != 0 && "DrawGradient, parameter 'xs' is null");
1106  assert(ys != 0 && "DrawGradient, parameter 'ys' is null");
1107 
1108  if (grad->GetGradientType() != TRadialGradient::kSimple) {
1109  ::Warning("TGLPadPainter::DrawGradient",
1110  "extended radial gradient is not supported");//yet?
1111  return;
1112  }
1113 
1114  //TODO: check the polygon's bbox!
1115  const auto &bbox = Rgl::Pad::FindBoundingRect(nPoints, xs, ys);
1116  //
1117  auto center = grad->GetCenter();
1118  auto radius = grad->GetRadius();
1119  //Adjust the center and radius depending on coordinate mode.
1121  radius *= TMath::Max(bbox.fWidth, bbox.fHeight);
1122  center.fX = bbox.fWidth * center.fX + bbox.fXMin;
1123  center.fY = bbox.fHeight * center.fY + bbox.fYMin;
1124  } else {
1125  const auto w = gPad->GetX2() - gPad->GetX1();
1126  const auto h = gPad->GetY2() - gPad->GetY1();
1127 
1128  radius *= TMath::Max(w, h);
1129  center.fX *= w;
1130  center.fY *= h;
1131  }
1132  //Now for the gradient fill we switch into pixel coordinates:
1133  const auto pixelW = gPad->GetAbsWNDC() * gPad->GetWw();
1134  const auto pixelH = gPad->GetAbsHNDC() * gPad->GetWh();
1135  //
1138  //A new ortho projection:
1139  glMatrixMode(GL_PROJECTION);
1140  glLoadIdentity();
1141  //
1142  glOrtho(0., pixelW, 0., pixelH, -10., 10.);
1143  //
1144  radius *= TMath::Max(pixelH, pixelW);
1145  center.fX = gPad->XtoPixel(center.fX);
1146  center.fY = pixelH - gPad->YtoPixel(center.fY);
1147 
1148  Double_t maxR = 0.;
1149  {
1150  const Double_t xMin = gPad->XtoPixel(bbox.fXMin);
1151  const Double_t xMax = gPad->XtoPixel(bbox.fXMax);
1152  const Double_t yMin = pixelH - gPad->YtoPixel(bbox.fYMin);
1153  const Double_t yMax = pixelH - gPad->YtoPixel(bbox.fYMax);
1154  //Get the longest distance from the center to the bounding box vertices
1155  //(this will be the maximum possible radius):
1156  const Double_t maxDistX = TMath::Max(TMath::Abs(center.fX - xMin),
1157  TMath::Abs(center.fX - xMax));
1158  const Double_t maxDistY = TMath::Max(TMath::Abs(center.fY - yMin),
1159  TMath::Abs(center.fY - yMax));
1160  maxR = TMath::Sqrt(maxDistX * maxDistX + maxDistY * maxDistY);
1161  }
1162 
1163  //If gradient 'stops inside the polygon', we use
1164  //the solid fill for the area outside of radial gradient:
1165  const Bool_t solidFillAfter = maxR > radius;
1166  //We emulate a radial gradient using triangles and linear gradient:
1167  //TODO: Can be something smarter? (btw even 100 seems to be enough)
1168  const UInt_t nSlices = 500;
1169 
1170  const auto nColors = grad->GetNumberOfSteps();
1171  //+1 - the strip from the last color's position to radius,
1172  //and (probably) + 1 for solidFillAfter.
1173  const auto nCircles = nColors + 1 + solidFillAfter;
1174 
1175  //TODO: can locations be outside of [0., 1.] ???
1176  //at the moment I assume the answer is NO, NEVER.
1177  const auto locations = grad->GetColorPositions();
1178  // * 2 below == x,y
1179  std::vector<Double_t> circles(nSlices * nCircles * 2);
1180  const Double_t angle = TMath::TwoPi() / nSlices;
1181 
1182  //"Main" circles (for colors at locations[i]).
1183  for (UInt_t i = 0; i < nColors; ++i) {
1184  const auto circle = &circles[i * nSlices * 2];
1185  //TODO: either check locations here or somewhere else.
1186  const auto r = radius * locations[i];
1187  for (UInt_t j = 0, e = nSlices * 2 - 2; j < e; j += 2) {
1188  circle[j] = center.fX + r * TMath::Cos(angle * j);
1189  circle[j + 1] = center.fY + r * TMath::Sin(angle * j);
1190  }
1191  //The "closing" vertices:
1192  circle[(nSlices - 1) * 2] = circle[0];
1193  circle[(nSlices - 1) * 2 + 1] = circle[1];
1194  }
1195 
1196  {
1197  //The strip between lastPos and radius:
1198  const auto circle = &circles[nColors * nSlices * 2];
1199  for (UInt_t j = 0, e = nSlices * 2 - 2; j < e; j += 2) {
1200  circle[j] = center.fX + radius * TMath::Cos(angle * j);
1201  circle[j + 1] = center.fY + radius * TMath::Sin(angle * j);
1202  }
1203 
1204  circle[(nSlices - 1) * 2] = circle[0];
1205  circle[(nSlices - 1) * 2 + 1] = circle[1];
1206  }
1207 
1208  if (solidFillAfter) {
1209  //The strip after the radius:
1210  const auto circle = &circles[(nCircles - 1) * nSlices * 2];
1211  for (UInt_t j = 0, e = nSlices * 2 - 2; j < e; j += 2) {
1212  circle[j] = center.fX + maxR * TMath::Cos(angle * j);
1213  circle[j + 1] = center.fY + maxR * TMath::Sin(angle * j);
1214  }
1215 
1216  circle[(nSlices - 1) * 2] = circle[0];
1217  circle[(nSlices - 1) * 2 + 1] = circle[1];
1218  }
1219 
1220  //Now we draw:
1221  //1) triangle fan in the center (from center to the locations[1],
1222  // with a solid fill).
1223  //2) quad strips for colors.
1224  //3) additional quad strip from the lastLocation to the radius
1225  //4) additional quad strip (if any) from the radius to maxR.
1226 
1227  //RGBA values:
1228  const auto rgba = grad->GetColors();
1229 
1230  const TGLEnableGuard alphaGuard(GL_BLEND);
1231  //TODO?
1232  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1233 
1234  //Probably a degenerated case. Maybe not.
1235  glBegin(GL_TRIANGLE_FAN);
1236  glColor4dv(rgba);
1237  glVertex2d(center.fX, center.fY);
1238 
1239  for (UInt_t i = 0, e = nSlices * 2; i < e; i += 2)
1240  glVertex2dv(&circles[i]);
1241 
1242  glEnd();
1243 
1244  //No auto for circles, explicit types to have const Double_t * const, not Duble_t * const.
1245  for (UInt_t i = 0; i < nColors - 1; ++i) {
1246  const Double_t * const inner = &circles[i * nSlices * 2];
1247  const auto innerRGBA = rgba + i * 4;
1248  const auto outerRGBA = rgba + (i + 1) * 4;
1249  const Double_t * const outer = &circles[(i + 1) * nSlices * 2];
1250 
1251  Rgl::DrawQuadStripWithRadialGradientFill(nSlices, inner, innerRGBA, outer, outerRGBA);
1252  }
1253 
1254  //Probably degenerated strip.
1255  {
1256  glBegin(GL_QUAD_STRIP);
1257  const Double_t * const inner = &circles[nSlices * (nColors - 1) * 2];
1258  const auto solidRGBA = rgba + (nColors - 1) * 4;
1259  const Double_t * const outer = &circles[nSlices * nColors * 2];
1260 
1261  Rgl::DrawQuadStripWithRadialGradientFill(nSlices, inner, solidRGBA, outer, solidRGBA);
1262  }
1263 
1264  if (solidFillAfter) {
1265  glBegin(GL_QUAD_STRIP);
1266  const Double_t * const inner = &circles[nSlices * nColors * 2];
1267  const auto solidRGBA = rgba + (nColors - 1) * 4;
1268  const Double_t * const outer = &circles[nSlices * (nColors + 1) * 2];
1269 
1270  Rgl::DrawQuadStripWithRadialGradientFill(nSlices, inner, solidRGBA, outer, solidRGBA);
1271  }
1272 
1275 }
1276 
1277 ////////////////////////////////////////////////////////////////////////////////
1278 
1280  const Double_t *x, const Double_t *y)
1281 {
1282  assert(grad != 0 && "DrawGradient, parameter 'grad' is null");
1283  assert(n > 2 && "DrawGradient, invalid number of points");
1284  assert(x != 0 && "DrawGradient, parameter 'x' is null");
1285  assert(y != 0 && "DrawGradient, parameter 'y' is null");
1286 
1287  //Now we fill the whole scene with one big rectangle
1288  //(group of rectangles) with a gradient fill using
1289  //stencil test.
1290 
1291  //Find a bounding rect.
1292  const auto &bbox = Rgl::Pad::FindBoundingRect(n, x, y);
1293  //TODO: check the bbox??
1294 
1295  //For the gradient fill we switch into the
1296  //pixel coordinates.
1299 
1300  //A new ortho projection:
1301  glMatrixMode(GL_PROJECTION);
1302  glLoadIdentity();
1303 
1304  const Double_t pixelW = gPad->GetAbsWNDC() * gPad->GetWw();
1305  const Double_t pixelH = gPad->GetAbsHNDC() * gPad->GetWh();
1306  glOrtho(0., pixelW, 0., pixelH, -10., 10.);
1307 
1308  //A new modelview:
1309  glMatrixMode(GL_MODELVIEW);
1310  glLoadIdentity();
1311  //
1312  TColorGradient::Point start = grad->GetStart();
1313  TColorGradient::Point end = grad->GetEnd();
1314 
1315  //Change gradient coordinates from 'NDC' to pad coords:
1317  {
1318  const Double_t w = gPad->GetX2() - gPad->GetX1();
1319  const Double_t h = gPad->GetY2() - gPad->GetY1();
1320 
1321  start.fX = start.fX * w;
1322  start.fY = start.fY * h;
1323  end.fX = end.fX * w;
1324  end.fY = end.fY * h;
1325  } else {
1326  start.fX = start.fX * bbox.fWidth + bbox.fXMin;
1327  start.fY = start.fY * bbox.fHeight + bbox.fYMin;
1328  end.fX = end.fX * bbox.fWidth + bbox.fXMin;
1329  end.fY = end.fY * bbox.fHeight + bbox.fYMin;
1330  }
1331 
1332  //TODO: with a radial fill we'll have to extract the code
1333  // below into the separate function/and have additional function
1334  // for a radial gradient.
1335  //Now from pad to pixels:
1336  start.fX = gPad->XtoPixel(start.fX);
1337  start.fY = pixelH - gPad->YtoPixel(start.fY);
1338  end.fX = gPad->XtoPixel(end.fX);
1339  end.fY = pixelH - gPad->YtoPixel(end.fY);
1340  const Double_t xMin = gPad->XtoPixel(bbox.fXMin);
1341  const Double_t xMax = gPad->XtoPixel(bbox.fXMax);
1342  const Double_t yMin = pixelH - gPad->YtoPixel(bbox.fYMin);
1343  const Double_t yMax = pixelH - gPad->YtoPixel(bbox.fYMax);
1344  //
1345 
1346  //TODO: check all calculations!
1347 
1348  //Get the longest distance from the start point to the bounding box vertices:
1349  const Double_t maxDistX = TMath::Max(TMath::Abs(start.fX - xMin), TMath::Abs(start.fX - xMax));
1350  const Double_t maxDistY = TMath::Max(TMath::Abs(start.fY - yMin), TMath::Abs(start.fY - yMax));
1351 
1352  const Double_t startEndLength = TMath::Sqrt((end.fX - start.fX) * (end.fX - start.fX) +
1353  (end.fY - start.fY) * (end.fY - start.fY));
1354  const Double_t h = TMath::Max(TMath::Sqrt(maxDistX * maxDistX + maxDistY * maxDistY),
1355  startEndLength);
1356 
1357  //Boxes with a gradients to emulate gradient fill with many colors:
1358  const Double_t * const colorPositions = grad->GetColorPositions();
1359  std::vector<Double_t> gradBoxes(grad->GetNumberOfSteps() + 2);
1360  gradBoxes[0] = start.fY - h;
1361  for (unsigned i = 1; i <= grad->GetNumberOfSteps(); ++i)
1362  gradBoxes[i] = startEndLength * colorPositions[i - 1] + start.fY;
1363 
1364  gradBoxes[grad->GetNumberOfSteps() + 1] = start.fY + h;
1365 
1366  //Rotation angle - gradient's axis:
1367  Double_t angle = TMath::ACos((startEndLength * (end.fY - start.fY)) /
1368  (startEndLength * startEndLength)) * TMath::RadToDeg();
1369  if (end.fX > start.fX)
1370  angle *= -1;
1371 
1372  glTranslated(start.fX, start.fY, 0.);
1373  glRotated(angle, 0., 0., 1.);
1374  glTranslated(-start.fX, -start.fY, 0.);
1375  //
1376  const Double_t * const rgba = grad->GetColors();
1377 
1378  const unsigned nEdges = gradBoxes.size();
1379  const unsigned nColors = grad->GetNumberOfSteps();
1380  const Double_t xLeft = start.fX - h, xRight = start.fX + h;
1381 
1382  const TGLEnableGuard alphaGuard(GL_BLEND);
1383  //TODO?
1384  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1385 
1386  Rgl::DrawBoxWithGradientFill(gradBoxes[0], gradBoxes[1], xLeft, xRight, rgba, rgba);
1387  Rgl::DrawBoxWithGradientFill(gradBoxes[nEdges - 2], gradBoxes[nEdges - 1], xLeft, xRight,
1388  rgba + (nColors - 1) * 4, rgba + (nColors - 1) * 4);
1389 
1390  for (unsigned i = 1; i < nEdges - 2; ++i)
1391  Rgl::DrawBoxWithGradientFill(gradBoxes[i], gradBoxes[i + 1], xLeft,
1392  xRight, rgba + (i - 1) * 4, rgba + i * 4);
1393 
1396 }
1397 
1398 ////////////////////////////////////////////////////////////////////////////////
1399 
1401 {
1402  assert(n > 2 && "DrawTesselation, invalid number of points");
1403  assert(x != 0 && "DrawTesselation, parameter 'x' is null");
1404  assert(y != 0 && "DrawTesselation, parameter 'y' is null");
1405 
1406  //Data for a tesselator:
1407  fVs.resize(n * 3);
1408 
1409  for (Int_t i = 0; i < n; ++i) {
1410  fVs[i * 3] = x[i];
1411  fVs[i * 3 + 1] = y[i];
1412  fVs[i * 3 + 2] = 0.;
1413  }
1414 
1415  //TODO: A very primitive way to tesselate - check what
1416  //kind of polygons we can really have from TPad/TCanvas.
1417  GLUtesselator *t = (GLUtesselator *)fTess.GetTess();
1418  gluBeginPolygon(t);
1419  gluNextContour(t, (GLenum)GLU_UNKNOWN);
1420 
1421  for (Int_t i = 0; i < n; ++i)
1422  gluTessVertex(t, &fVs[i * 3], &fVs[i * 3]);
1423 
1424  gluEndPolygon(t);
1425 }
1426 
1427 
1428 //Aux. functions.
1429 namespace {
1430 
1431 template<class ValueType>
1432 void ConvertMarkerPoints(Int_t n, const ValueType *x, const ValueType *y, std::vector<TPoint> & dst)
1433 {
1434  const UInt_t padH = UInt_t(gPad->GetAbsHNDC() * gPad->GetWh());
1435 
1436  dst.resize(n);
1437  for (Int_t i = 0; i < n; ++i) {
1438  dst[i].fX = gPad->XtoPixel(x[i]);
1439  dst[i].fY = padH - gPad->YtoPixel(y[i]);
1440  }
1441 }
1442 
1443 }
1444 
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:44
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
short Style_t
Definition: RtypesCore.h:76
void SetTextColor(Color_t tcolor)
Delegate to gVirtualX.
Rgl::Pad::PolygonStippleSet fSSet
Definition: TGLPadPainter.h:38
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.
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:123
TH1 * h
Definition: legend2.C:5
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:39
virtual UInt_t * GetArgbArray()
Definition: TImage.h:245
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:364
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.
Double_t RadToDeg()
Definition: TMath.h:49
#define CLRBIT(n, i)
Definition: Rtypes.h:122
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
const char * Char
Float_t GetTextAngle() const
Delegate to gVirtualX.
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:169
Short_t Abs(Short_t d)
Definition: TMathBase.h:110
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 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:40
virtual void DrawRectangle(UInt_t, UInt_t, UInt_t, UInt_t, const char *="#000000", UInt_t=1)
Definition: TImage.h:198
std::vector< TPoint > fPoly
Definition: TGLPadPainter.h:50
void RestoreViewport()
Restore the saved viewport.
void SaveProjectionMatrix() const
Save the projection matrix.
Short_t GetTextAlign() const
Delegate to gVirtualX.
Double_t TwoPi()
Definition: TMath.h:45
TVirtualPad is an abstract base class for the Pad and Canvas classes.
Definition: TVirtualPad.h:59
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:48
Font_t GetTextFont() const
Delegate to gVirtualX.
Definition: TPoint.h:33
void DrawOpenStar(UInt_t n, const TPoint *xy) const
HIGZ full star pentagone.
void CopyDrawable(Int_t id, Int_t px, Int_t py)
Not required at the moment.
void DrawPixels(const unsigned char *pixelData, UInt_t width, UInt_t height, Int_t dstX, Int_t dstY, Bool_t enableBlending)
void DrawDot(UInt_t n, const TPoint *xy) const
Simple 1-pixel dots.
Bool_t fIsHollowArea
Definition: TGLPadPainter.h:51
const Double_t lineWidthTS
TRandom2 r(17)
static void InitializeIfNeeded()
Initialize globals that require other libraries to be initialized.
Definition: TGLUtil.cxx:1543
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:36
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
void DrawCross(UInt_t n, const TPoint *xy) const
Color_t GetTextColor() const
Delegate to gVirtualX.
void DrawFullStar(UInt_t n, const TPoint *xy) const
HIGZ full star pentagone.
unsigned int UInt_t
Definition: RtypesCore.h:42
The most important graphics class in the ROOT system.
Definition: TPad.h:37
char * Form(const char *fmt,...)
void SaveViewport()
Extract and save the current viewport.
short Short_t
Definition: RtypesCore.h:35
Rgl::Pad::GLLimits fLimits
Definition: TGLPadPainter.h:41
void DrawFullDotSmall(UInt_t n, const TPoint *xy) const
Double_t ACos(Double_t)
Definition: TMath.h:445
void SetFillStyle(Style_t fstyle)
Delegate to gVirtualX.
void Warning(const char *location, const char *msgfmt,...)
void DrawFullTrianlgeDown(UInt_t n, const TPoint *xy) const
void SetTextAlign(Short_t align)
Delegate to gVirtualX.
#define gVirtualX
Definition: TVirtualX.h:362
Double_t Cos(Double_t)
Definition: TMath.h:424
short Width_t
Definition: RtypesCore.h:78
std::vector< Double_t > fVs
Definition: TGLPadPainter.h:43
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.
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:279
double f(double x)
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)
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:45
EGradientType GetGradientType() const
Get gradient type.
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:202
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:421
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:494
#define gPad
Definition: TVirtualPad.h:289
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()
Float_t GetTextSize() const
Delegate to gVirtualX.
Double_t Sqrt(Double_t x)
Definition: TMath.h:464
static TImage * Create()
Create an image.
Definition: TImage.cxx:36
const Bool_t kTRUE
Definition: Rtypes.h:91
void DestroyDrawable()
Not required at the moment.
TColorGradient extends basic TColor.
void SetOpacity(Int_t percent)
Delegate to gVirtualX.
Float_t GetTextMagnitude() const
Delegate to gVirtualX.
Width_t GetLineWidth() const
Delegate to gVirtualX.
const Int_t n
Definition: legend1.C:16
void DrawTesselation(Int_t n, const Double_t *x, const Double_t *y)
virtual TCanvas * GetCanvas() const =0