Logo ROOT   6.10/09
Reference Guide
TGLVoxelPainter.cxx
Go to the documentation of this file.
1 #include <algorithm>
2 
3 #include "KeySymbols.h"
4 #include "TVirtualX.h"
5 #include "Buttons.h"
6 #include "TString.h"
7 #include "TROOT.h"
8 #include "TClass.h"
9 #include "TColor.h"
10 #include "TStyle.h"
11 #include "TH3.h"
12 #include "TF1.h"
13 
14 #include "TGLVoxelPainter.h"
15 #include "TGLPlotCamera.h"
16 #include "TGLIncludes.h"
17 
18 /** \class TGLVoxelPainter
19 \ingroup opengl
20 Paint TH3 histograms as "voxels" - colored boxes, transparent if transfer function was specified.
21 */
22 
24 
25 ////////////////////////////////////////////////////////////////////////////////
26 /// Constructor.
27 ///This plot always needs a palette.
28 
30  : TGLPlotPainter(hist, cam, coord, kFALSE, kFALSE, kFALSE),
31  fTransferFunc(0)
32 {
33  fDrawPalette = kTRUE;
34 }
35 
36 
37 ////////////////////////////////////////////////////////////////////////////////
38 ///Show box info (i, j, k, binContent).
39 
41 {
42  fPlotInfo = "";
43 
44  if (fSelectedPart) {
46  if (fHist->Class())
47  fPlotInfo += fHist->Class()->GetName();
48  fPlotInfo += "::";
49  fPlotInfo += fHist->GetName();
50  } else if (!fHighColor){
51  const Int_t arr2Dsize = fCoord->GetNYBins() * fCoord->GetNZBins();
52  const Int_t binI = (fSelectedPart - fSelectionBase) / arr2Dsize + fCoord->GetFirstXBin();
53  const Int_t binJ = (fSelectedPart - fSelectionBase) % arr2Dsize / fCoord->GetNZBins() + fCoord->GetFirstYBin();
54  const Int_t binK = (fSelectedPart - fSelectionBase) % arr2Dsize % fCoord->GetNZBins() + fCoord->GetFirstZBin();
55 
56  fPlotInfo.Form("(binx = %d; biny = %d; binz = %d; binc = %f)", binI, binJ, binK,
57  fHist->GetBinContent(binI, binJ, binK));
58  } else
59  fPlotInfo = "Switch to true color mode to get correct info";
60  }
61 
62  return (Char_t *)fPlotInfo.Data();
63 }
64 
65 
66 ////////////////////////////////////////////////////////////////////////////////
67 ///Set ranges, find min and max bin content.
68 
70 {
74 
75  if (!fCoord->SetRanges(fHist, kFALSE, kTRUE))//kFALSE == drawErrors, kTRUE == zAsBins
76  return kFALSE;
77 
80 
82  fMinMaxVal.first = fMinMaxVal.second;
83  //Bad. You can up-date some bin value and get wrong picture.
84  for (Int_t ir = fCoord->GetFirstXBin(); ir <= fCoord->GetLastXBin(); ++ir) {
85  for (Int_t jr = fCoord->GetFirstYBin(); jr <= fCoord->GetLastYBin(); ++jr) {
86  for (Int_t kr = fCoord->GetFirstZBin(); kr <= fCoord->GetLastZBin(); ++kr) {
87  fMinMaxVal.second = TMath::Max(fMinMaxVal.second, fHist->GetBinContent(ir, jr, kr));
88  fMinMaxVal.first = TMath::Min(fMinMaxVal.first, fHist->GetBinContent(ir, jr, kr));
89  }
90  }
91  }
92 
93  if (fCoord->Modified()) {
99  }
100 
101  const TList *funcList = fHist->GetListOfFunctions();
102  fTransferFunc = dynamic_cast<TF1*>(funcList->FindObject("TransferFunction"));
103 
104  return kTRUE;
105 }
106 
107 
108 ////////////////////////////////////////////////////////////////////////////////
109 /// User clicks right mouse button (in a pad).
110 
112 {
113  fMousePosition.fX = px;
115  fCamera->StartPan(px, py);
116  fBoxCut.StartMovement(px, fCamera->GetHeight() - py);
117 }
118 
119 
120 ////////////////////////////////////////////////////////////////////////////////
121 /// User's moving mouse cursor, with middle mouse button pressed (for pad).
122 /// Calculate 3d shift related to 2d mouse movement.
123 
125 {
126  // User's moving mouse cursor, with middle mouse button pressed (for pad).
127  // Calculate 3d shift related to 2d mouse movement.
128  if (fSelectedPart >= fSelectionBase) {//Pan camera.
131 
132  fCamera->SetCamera();
134  fCamera->Pan(px, py);
135 
138  } else if (fSelectedPart > 0) {
139  //Convert py into bottom-top orientation.
140  //Possibly, move box here
141  py = fCamera->GetHeight() - py;
144 
145  fCamera->SetCamera();
147 
148 
149  if (!fHighColor) {
151  fBoxCut.MoveBox(px, py, fSelectedPart);
152  else
153  MoveSection(px, py);
154  } else {
155  MoveSection(px, py);
156  }
157 
160  }
161 
162  fMousePosition.fX = px, fMousePosition.fY = py;
164 }
165 
166 
167 ////////////////////////////////////////////////////////////////////////////////
168 /// "z" draw palette or not.
169 
171 {
172  option.Index("z") == kNPOS ? fDrawPalette = kFALSE : fDrawPalette = kTRUE;
173 
174 }
175 
176 ////////////////////////////////////////////////////////////////////////////////
177 /// Remove sections, switch on/off box cut.
178 
180 {
181  if (event == kButton1Double && fBoxCut.IsActive()) {
182  if (fBoxCut.IsActive())
183  fBoxCut.TurnOnOff();
184  if (!gVirtualX->IsCmdThread())
185  gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", ULong_t(this)));
186  else
187  Paint();
188  } else if (event == kKeyPress && (py == kKey_c || py == kKey_C)) {
189  if (fHighColor)
190  Info("ProcessEvent", "Switch to true color mode to use box cut");
191  else {
192  fBoxCut.TurnOnOff();
194  }
195  }
196 }
197 
198 ////////////////////////////////////////////////////////////////////////////////
199 /// Initialize some gl state variables.
200 
202 {
203  glEnable(GL_DEPTH_TEST);
204  glEnable(GL_LIGHTING);
205  glEnable(GL_LIGHT0);
206 
207  glEnable(GL_CULL_FACE);
208  glCullFace(GL_BACK);
209 
210  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
211 }
212 
213 ////////////////////////////////////////////////////////////////////////////////
214 /// Return back some gl state variables.
215 
217 {
218  glDisable(GL_DEPTH_TEST);
219  glDisable(GL_LIGHTING);
220  glDisable(GL_LIGHT0);
221  glDisable(GL_CULL_FACE);
222  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
223 }
224 
225 ////////////////////////////////////////////////////////////////////////////////
226 /// Draw "voxels".
227 
229 {
230  //Shift plot to point of origin.
231  const Rgl::PlotTranslation trGuard(this);
232 
233  if (!fSelectionPass)
234  PreparePalette();
235 
237 
238  TGLDisableGuard depthTest(GL_DEPTH_TEST);
239 
240  if (!fSelectionPass) {
241  glEnable(GL_BLEND);//[1
242  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
243  }
244 
245  //Using front point, find the correct order to draw boxes from
246  //back to front/from bottom to top (it's important only for semi-transparent boxes).
247  const Int_t frontPoint = fBackBox.GetFrontPoint();
248  Int_t irInit = fCoord->GetFirstXBin(), iInit = 0;
249  const Int_t nX = fCoord->GetNXBins();
250  Int_t jrInit = fCoord->GetFirstYBin(), jInit = 0;
251  const Int_t nY = fCoord->GetNYBins();
252  Int_t krInit = fCoord->GetFirstZBin(), kInit = 0;
253  const Int_t nZ = fCoord->GetNZBins();
254 
255  const Int_t addI = frontPoint == 2 || frontPoint == 1 ? 1 : (iInit = nX - 1, irInit = fCoord->GetLastXBin(), -1);
256  const Int_t addJ = frontPoint == 2 || frontPoint == 3 ? 1 : (jInit = nY - 1, jrInit = fCoord->GetLastYBin(), -1);
257  const Int_t addK = fBackBox.Get2DBox()[frontPoint + 4].Y() > fBackBox.Get2DBox()[frontPoint].Y() ? 1
258  : (kInit = nZ - 1, krInit = fCoord->GetLastZBin(),-1);
259  const Double_t xScale = fCoord->GetXScale();
260  const Double_t yScale = fCoord->GetYScale();
261  const Double_t zScale = fCoord->GetZScale();
262  const TAxis *xA = fXAxis;
263  const TAxis *yA = fYAxis;
264  const TAxis *zA = fZAxis;
265 
266  if (fSelectionPass && fHighColor)
268 
269  Double_t maxContent = TMath::Max(TMath::Abs(fMinMaxVal.first), TMath::Abs(fMinMaxVal.second));
270  if(!maxContent)//bad, find better way to check zero.
271  maxContent = 1.;
272 
273  Float_t rgba[4] = {};
274 
275  for(Int_t ir = irInit, i = iInit; addI > 0 ? i < nX : i >= 0; ir += addI, i += addI) {
276  for(Int_t jr = jrInit, j = jInit; addJ > 0 ? j < nY : j >= 0; jr += addJ, j += addJ) {
277 // for(Int_t kr = krInit, k = kInit; addK > 0 ? k < nZ : k >= 0; kr += addK, k += addK) {
278  for(Int_t kr = krInit, k = kInit; addK > 0 ? k < nZ : k >= 0; kr += addK, k += addK) {
279  const Double_t xMin = xScale * xA->GetBinLowEdge(ir);
280  const Double_t xMax = xScale * xA->GetBinUpEdge(ir);
281  const Double_t yMin = yScale * yA->GetBinLowEdge(jr);
282  const Double_t yMax = yScale * yA->GetBinUpEdge(jr);
283  const Double_t zMin = zScale * zA->GetBinLowEdge(kr);
284  const Double_t zMax = zScale * zA->GetBinUpEdge(kr);
285 
286  if (fBoxCut.IsActive() && fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
287  continue;
288 
289  FindVoxelColor(fHist->GetBinContent(ir, jr, kr), rgba);
290 
291  if (rgba[3] < 0.01f)
292  continue;
293 
294  if (!fSelectionPass)
295  SetVoxelColor(rgba);
296 
297  const Int_t binID = fSelectionBase + i * fCoord->GetNZBins() * fCoord->GetNYBins() + j * fCoord->GetNZBins() + k;
298 
299  if (fSelectionPass && !fHighColor)
301  else if(!fHighColor && fSelectedPart == binID)
302  glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gOrangeEmission);
303 
304  Rgl::DrawBoxFront(xMin, xMax, yMin, yMax, zMin, zMax, frontPoint);
305 
306  if (!fSelectionPass && !fHighColor && fSelectedPart == binID)
307  glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gNullEmission);
308  }
309  }
310  }
311 
312  if (fBoxCut.IsActive())
314 
315  if (!fSelectionPass) {
316  if (fDrawPalette)
317  DrawPalette();
318  glDisable(GL_BLEND);//1]
319  }
320 }
321 
322 ////////////////////////////////////////////////////////////////////////////////
323 /// Noop.
324 
326 {
327 }
328 
329 ////////////////////////////////////////////////////////////////////////////////
330 /// Noop.
331 
333 {
334 }
335 
336 
337 ////////////////////////////////////////////////////////////////////////////////
338 /// Noop.
339 
341 {
342 }
343 
344 ////////////////////////////////////////////////////////////////////////////////
345 ///Draw. Palette.
346 
348 {
349  if (!fPalette.GetPaletteSize() || !fCamera)
350  return;
351 
354  else
356 
357  glFinish();
358 
359  fCamera->SetCamera();
361 }
362 
363 ////////////////////////////////////////////////////////////////////////////////
364 ///Draw. Palette. Axis.
365 
367 {
368  if (fCamera) {
369  gVirtualX->SetDrawMode(TVirtualX::kCopy);//TCanvas by default sets in kInverse
371  }
372 }
373 
374 ////////////////////////////////////////////////////////////////////////////////
375 ///Generate palette.
376 
378 {
379  if(fMinMaxVal.first == fMinMaxVal.second)
380  return;//must be std::abs(fMinMaxVal.second - fMinMaxVal.first) < ...
381 
382  fLevels.clear();
383  UInt_t paletteSize = 0;
384 
386  if (const UInt_t trySize = fHist->GetContour()) {
387  fLevels.reserve(trySize);
388 
389  for (UInt_t i = 0; i < trySize; ++i) {
390  const Double_t level = fHist->GetContourLevel(Int_t(i));
391  if (level <= fMinMaxVal.first || level >= fMinMaxVal.second)
392  continue;
393  fLevels.push_back(level);
394  }
395  //sort levels
396  if (fLevels.size()) {
397  std::sort(fLevels.begin(), fLevels.end());
398  fLevels.push_back(fMinMaxVal.second);
399  fLevels.insert(fLevels.begin(), fMinMaxVal.first);
401  paletteSize = fLevels.size() - 1;
402  }
403  }
404 
405  if (!paletteSize)
407  }
408 
409  if (!paletteSize && !(paletteSize = gStyle->GetNumberContours()))
410  paletteSize = 20;
411 
412  fPalette.GeneratePalette(paletteSize, fMinMaxVal);
413 }
414 
415 ////////////////////////////////////////////////////////////////////////////////
416 /// Find box color.
417 
419 {
420  const UChar_t * tc = fPalette.GetColour(binContent);
421  rgba[3] = 0.06f; //Just a constant transparency.
422 
423 
424  if (fTransferFunc) {
425  rgba[3] = fTransferFunc->Eval(binContent);
426  }
427 
428  rgba[0] = tc[0] / 255.f;
429  rgba[1] = tc[1] / 255.f;
430  rgba[2] = tc[2] / 255.f;
431 }
432 
433 
434 ////////////////////////////////////////////////////////////////////////////////
435 /// Set box color.
436 
437 void TGLVoxelPainter::SetVoxelColor(const Float_t *diffColor)const
438 {
439  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffColor);
440  const Float_t specColor[] = {1.f, 1.f, 1.f, 1.f};
441  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor);
442  glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 70.f);
443 }
void AddOption(const TString &stringOption)
"z" draw palette or not.
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
void DrawBox(Bool_t selectionPass, Int_t selected) const
Draw cut as a semi-transparent box.
Int_t GetFrontPoint() const
The nearest point.
Definition: TGLPlotBox.cxx:294
void StartPan(Int_t px, Int_t py)
User clicks right mouse button (in a pad).
void RestoreModelviewMatrix() const
Camera for TGLPlotPainter and sub-classes.
Definition: TGLPlotCamera.h:21
Int_t GetFirstXBin() const
void SetVoxelColor(const Float_t *rgba) const
Set box color.
Int_t GetNYBins() const
Number of Y bins.
void MoveBox(Int_t px, Int_t py, Int_t axisID)
Move box cut along selected direction.
Int_t GetNumberContours() const
Definition: TStyle.h:225
const Float_t gNullEmission[]
Definition: TGLUtil.cxx:2814
float Float_t
Definition: RtypesCore.h:53
virtual Double_t GetBinLowEdge(Int_t bin) const
Return low edge of bin.
Definition: TAxis.cxx:504
const Ssiz_t kNPOS
Definition: RtypesCore.h:115
R__EXTERN TStyle * gStyle
Definition: TStyle.h:402
Double_t fYOZSectionPos
Bool_t TestBit(UInt_t f) const
Definition: TObject.h:159
void StartPan(Int_t px, Int_t py)
User clicks somewhere (px, py).
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
Definition: TH1.cxx:4639
Int_t GetPaletteSize() const
Get. Palette. Size.
Definition: TGLUtil.cxx:4221
const TGLVertex3 * Get3DBox() const
Get 3D box.
Definition: TGLPlotBox.cxx:303
void DeInitGL() const
Return back some gl state variables.
SCoord_t fX
Definition: TPoint.h:35
#define gROOT
Definition: TROOT.h:375
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:587
Paint TH3 histograms as "voxels" - colored boxes, transparent if transfer function was specified...
SCoord_t fY
Definition: TPoint.h:36
Basic string class.
Definition: TString.h:129
Int_t GetNXBins() const
Number of X bins.
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:168
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
void TurnOnOff()
Turn the box cut on/off.
void DrawPalette() const
Draw. Palette.
const UChar_t * GetColour(Double_t z) const
Get color.
Definition: TGLUtil.cxx:4258
void DrawPalette(const TGLPlotCamera *camera, const TGLLevelPalette &palette)
Draw. Palette.
void DrawSectionXOZ() const
Noop.
void DrawPaletteAxis(const TGLPlotCamera *camera, const Range_t &minMax, Bool_t logZ)
Rgl::Range_t fMinMaxVal
virtual Double_t GetContourLevel(Int_t level) const
Return value of contour number level.
Definition: TH1.cxx:7554
Short_t Abs(Short_t d)
Definition: TMathBase.h:108
void Pan(Int_t px, Int_t py)
User&#39;s moving mouse cursor, with middle mouse button pressed (for pad).
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:501
virtual Double_t GetBinUpEdge(Int_t bin) const
Return up edge of bin.
Definition: TAxis.cxx:514
Int_t GetNZBins() const
Number of Z bins.
virtual Int_t GetContour(Double_t *levels=0)
Return contour values into array levels if pointer levels is non zero.
Definition: TH1.cxx:7535
void Apply(Double_t phi, Double_t theta) const
Applies rotations and translations before drawing.
std::vector< Double_t > fLevels
Double_t fXOZSectionPos
Bool_t IsActive() const
void Info(const char *location, const char *msgfmt,...)
void SetCamera() const
Viewport and projection.
Int_t GetFirstYBin() const
void SetYLog(Bool_t yLog)
If log changed, sections must be reset, set fModified.
TGLPlotBox fBackBox
char * GetPlotInfo(Int_t px, Int_t py)
Show box info (i, j, k, binContent).
user specified contour levels
Definition: TH1.h:149
void SetViewVolume(const TGLVertex3 *box)
&#39;box&#39; is the TGLPlotPainter&#39;s back box&#39;s coordinates.
A doubly linked list.
Definition: TList.h:43
void SetContours(const std::vector< Double_t > *contours)
Clear :)
Definition: TGLUtil.cxx:4185
void PreparePalette() const
Generate palette.
Double_t fPadTheta
void ObjectIDToColor(Int_t objectID, Bool_t highColor)
Object id encoded as rgb triplet.
Definition: TGLUtil.cxx:2858
void DrawSectionXOY() const
Noop.
const Rgl::Range_t & GetZRangeScaled() const
Scaled range.
TGLPlotCamera * fCamera
void RestoreProjectionMatrix() const
void DrawBoxFront(Double_t xMin, Double_t xMax, Double_t yMin, Double_t yMax, Double_t zMin, Double_t zMax, Int_t fp)
Draws lego&#39;s bar as a 3d box.
Definition: TGLUtil.cxx:2974
Int_t GetLastYBin() const
void ProcessEvent(Int_t event, Int_t px, Int_t py)
Remove sections, switch on/off box cut.
Class to manage histogram axis.
Definition: TAxis.h:30
void DrawSectionYOZ() const
Noop.
void DrawPlot() const
Draw "voxels".
Helper class for plot-painters holding information about axis ranges, numbers of bins and flags if ce...
void ResetModified()
Reset modified.
void Pan(Int_t px, Int_t py)
Pan camera.
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2332
unsigned int UInt_t
Definition: RtypesCore.h:42
char * Form(const char *fmt,...)
void SetXLog(Bool_t xLog)
If log changed, sections must be reset, set fModified.
Base class for plot-painters that provide GL rendering of various 2D and 3D histograms, functions and parametric surfaces.
std::vector< Double_t > fZLevels
#define gVirtualX
Definition: TVirtualX.h:350
const Bool_t kFALSE
Definition: RtypesCore.h:92
void DrawBox(Int_t selectedPart, Bool_t selectionPass, const std::vector< Double_t > &zLevels, Bool_t highColor) const
Draw back box for a plot.
Definition: TGLPlotBox.cxx:184
Double_t Z() const
Definition: TGLUtil.h:122
Double_t GetYScale() const
virtual Double_t Eval(Double_t x, Double_t y=0, Double_t z=0, Double_t t=0) const
Evaluate this function.
Definition: TF1.cxx:1197
#define ClassImp(name)
Definition: Rtypes.h:336
double f(double x)
double Double_t
Definition: RtypesCore.h:55
void InitGL() const
Initialize some gl state variables.
Bool_t Modified() const
Modified.
unsigned long ULong_t
Definition: RtypesCore.h:51
void SaveProjectionMatrix() const
The TH1 histogram class.
Definition: TH1.h:56
Int_t GetFirstZBin() const
Bool_t SetRanges(const TH1 *hist, Bool_t errors=kFALSE, Bool_t zBins=kFALSE)
Set bin ranges, ranges.
const Rgl::Range_t & GetYRangeScaled() const
Scaled range.
Int_t GetLastXBin() const
char Char_t
Definition: RtypesCore.h:29
Double_t fXOYSectionPos
void DrawPaletteAxis() const
Draw. Palette. Axis.
void SetZLog(Bool_t zLog)
If log changed, sections must be reset, set fModified.
void StartMovement(Int_t px, Int_t py)
Start cut&#39;s movement.
void MoveSection(Int_t px, Int_t py)
Create dynamic profile using selected plane.
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:200
1-Dim function class
Definition: TF1.h:150
void SetPlotBox(const Rgl::Range_t &xRange, const Rgl::Range_t &yRange, const Rgl::Range_t &zRange)
Set up a frame box.
Definition: TGLPlotBox.cxx:198
Bool_t InitGeometry()
Set ranges, find min and max bin content.
const Rgl::Range_t & GetXRangeScaled() const
Scaled range.
void ResetBit(UInt_t f)
Definition: TObject.h:158
unsigned char UChar_t
Definition: RtypesCore.h:34
void FindVoxelColor(Double_t binContent, Float_t *rgba) const
Find box color.
Bool_t fUpdateSelection
Int_t GetLastZBin() const
Int_t GetHeight() const
viewport[3]
void SaveModelviewMatrix() const
TList * GetListOfFunctions() const
Definition: TH1.h:224
Bool_t GeneratePalette(UInt_t paletteSize, const Rgl::Range_t &zRange, Bool_t checkSize=kTRUE)
Try to find colors for palette.
Definition: TGLUtil.cxx:4128
TGLPlotCoordinates * fCoord
TGLLevelPalette fPalette
Double_t Y() const
Definition: TGLUtil.h:120
virtual void Paint()
Draw lego/surf/whatever you can.
const Bool_t kTRUE
Definition: RtypesCore.h:91
const Float_t gOrangeEmission[]
Definition: TGLUtil.cxx:2811
TGLBoxCut fBoxCut
Double_t GetZScale() const
Double_t GetXScale() const
const char * Data() const
Definition: TString.h:347
const TGLVertex3 * Get2DBox() const
Get 2D box.
Definition: TGLPlotBox.cxx:312
Bool_t IsInCut(Double_t xMin, Double_t xMax, Double_t yMin, Double_t yMax, Double_t zMin, Double_t zMax) const
Check, if box defined by xmin/xmax etc. is in cut.
Double_t X() const
Definition: TGLUtil.h:118