ROOT  6.06/09
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 
402 const Double_t lineWidthTS = 3.;
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 
814 void TGLPadPainter::DrawText(Double_t x, Double_t y, const wchar_t *text, ETextMode mode)
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::auto_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 
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:169
EImageFileTypes
Definition: TImage.h:52
void DrawFullDotLarge(UInt_t n, const TPoint *xy) const
const Double_t * v1
Definition: TArcBall.cxx:33
short Style_t
Definition: RtypesCore.h:76
void SetTextColor(Color_t tcolor)
Delegate to gVirtualX.
Rgl::Pad::PolygonStippleSet fSSet
Definition: TGLPadPainter.h:38
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...
Double_t GetMaxLineWidth() const
#define assert(cond)
Definition: unittest.h:542
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:131
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:39
virtual UInt_t * GetArgbArray()
Definition: TImage.h:253
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:340
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
Width_t GetLineWidth() const
Delegate to gVirtualX.
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
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:110
void SetTextSizePixels(Int_t npixels)
Delegate to gVirtualX.
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 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]
void Render(const char *txt, Double_t x, Double_t y, Double_t angle, Double_t mgn) 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:40
virtual void DrawRectangle(UInt_t, UInt_t, UInt_t, UInt_t, const char *="#000000", UInt_t=1)
Definition: TImage.h:206
std::vector< TPoint > fPoly
Definition: TGLPadPainter.h:50
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
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 DrawFullStar(UInt_t n, const TPoint *xy) const
HIGZ 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:48
void DrawPlus(UInt_t n, const TPoint *xy) const
Definition: TPoint.h:33
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)
Bool_t fIsHollowArea
Definition: TGLPadPainter.h:51
const Double_t lineWidthTS
void RestoreProjectionMatrix() const
Restore the projection matrix.
ROOT::R::TRInterface & r
Definition: Object.C:4
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
"Delegating" part of TGLPadPainter.
Definition: TGLPadPainter.h:36
void DrawCross(UInt_t n, const TPoint *xy) const
ClassImp(TGLPadPainter) TGLPadPainter
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:46
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:41
Double_t ACos(Double_t)
Definition: TMath.h:445
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:362
static TImage * Create()
Double_t Cos(Double_t)
Definition: TMath.h:424
short Width_t
Definition: RtypesCore.h:78
Double_t GetMaxPointSize() const
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.
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.
static const double x1[5]
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
void InitPainter()
Init gl-pad painter:
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:493
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 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.
TGLFontManager fFM
Definition: TGLPadPainter.h:45
const Double_t * GetColorPositions() const
Get color positions.
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:202
void DrawTextHelper(Double_t x, Double_t y, const Char_t *text, ETextMode mode)
Double_t Sin(Double_t)
Definition: TMath.h:421
Float_t GetTextAngle() const
Delegate to gVirtualX.
#define gPad
Definition: TVirtualPad.h:288
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:464
const Bool_t kTRUE
Definition: Rtypes.h:91
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.
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
HIGZ full star pentagone.
void DrawTesselation(Int_t n, const Double_t *x, const Double_t *y)
const char Int_t const char * image
Definition: TXSlave.cxx:46
virtual TCanvas * GetCanvas() const =0