Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGLUtil.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Richard Maunder 25/05/2005
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, 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 <algorithm>
13 #include <cassert>
14 #include <string>
15 #include <map>
16 
17 #include "THLimitsFinder.h"
18 #include "TVirtualPad.h"
19 #include "TVirtualX.h"
20 #include "Riostream.h"
21 #include "TStyle.h"
22 #include "TGaxis.h"
23 #include "TColor.h"
24 #include "TError.h"
25 #include "TH1.h"
26 #include "TMath.h"
27 #include "TROOT.h"
28 #include "TClass.h"
29 #include "TEnv.h"
30 
31 #include "TGLBoundingBox.h"
32 #include "TGLCamera.h"
33 #include "TGLPlotPainter.h"
34 #include "TGLIncludes.h"
35 #include "TGLQuadric.h"
36 #include "TGLUtil.h"
37 
38 /** \class TGLVertex3
39 \ingroup opengl
40 3 component (x/y/z) vertex class.
41 
42 This is part of collection of simple utility classes for GL only in
43 TGLUtil.h/cxx. These provide const and non-const accessors Arr() &
44 CArr() to a GL compatible internal field - so can be used directly
45 with OpenGL C API calls - which TVector3 etc cannot (easily).
46 They are not intended to be fully featured just provide minimum required.
47 */
48 
49 ClassImp(TGLVertex3);
50 
51 ////////////////////////////////////////////////////////////////////////////////
52 /// Construct a default (0.0, 0.0, 0.0) vertex
53 
54 TGLVertex3::TGLVertex3()
55 {
56  Fill(0.0);
57 }
58 
59 ////////////////////////////////////////////////////////////////////////////////
60 /// Construct a vertex with components (x,y,z)
61 
62 TGLVertex3::TGLVertex3(Double_t x, Double_t y, Double_t z)
63 {
64  Set(x,y,z);
65 }
66 
67 ////////////////////////////////////////////////////////////////////////////////
68 /// Construct a vertex with components (v[0], v[1], v[2])
69 
70 TGLVertex3::TGLVertex3(Double_t* v)
71 {
72  Set(v[0], v[1], v[2]);
73 }
74 
75 ////////////////////////////////////////////////////////////////////////////////
76 /// Construct a vertex from 'other'
77 
78 TGLVertex3::TGLVertex3(const TGLVertex3 & other)
79 {
80  Set(other);
81 }
82 
83 ////////////////////////////////////////////////////////////////////////////////
84 /// Destroy vertex object
85 
86 TGLVertex3::~TGLVertex3()
87 {
88 }
89 
90 ////////////////////////////////////////////////////////////////////////////////
91 /// Offset a vertex by vector 'shift'
92 
93 void TGLVertex3::Shift(TGLVector3 & shift)
94 {
95  fVals[0] += shift[0];
96  fVals[1] += shift[1];
97  fVals[2] += shift[2];
98 }
99 
100 ////////////////////////////////////////////////////////////////////////////////
101 /// Offset a vertex by components (xDelta, yDelta, zDelta)
102 
103 void TGLVertex3::Shift(Double_t xDelta, Double_t yDelta, Double_t zDelta)
104 {
105  fVals[0] += xDelta;
106  fVals[1] += yDelta;
107  fVals[2] += zDelta;
108 }
109 
110 ////////////////////////////////////////////////////////////////////////////////
111 
112 void TGLVertex3::Minimum(const TGLVertex3 & other)
113 {
114  fVals[0] = TMath::Min(fVals[0], other.fVals[0]);
115  fVals[1] = TMath::Min(fVals[1], other.fVals[1]);
116  fVals[2] = TMath::Min(fVals[2], other.fVals[2]);
117 }
118 
119 ////////////////////////////////////////////////////////////////////////////////
120 
121 void TGLVertex3::Maximum(const TGLVertex3 & other)
122 {
123  fVals[0] = TMath::Max(fVals[0], other.fVals[0]);
124  fVals[1] = TMath::Max(fVals[1], other.fVals[1]);
125  fVals[2] = TMath::Max(fVals[2], other.fVals[2]);
126 }
127 
128 ////////////////////////////////////////////////////////////////////////////////
129 /// Output vertex component values to std::cout
130 
131 void TGLVertex3::Dump() const
132 {
133  std::cout << "(" << fVals[0] << "," << fVals[1] << "," << fVals[2] << ")" << std::endl;
134 }
135 
136 /** \class TGLVector3
137 \ingroup opengl
138 3 component (x/y/z) vector class.
139 
140 This is part of collection of utility classes for GL in TGLUtil.h/cxx
141 These provide const and non-const accessors Arr() / CArr() to a GL
142 compatible internal field - so can be used directly with OpenGL C API
143 calls. They are not intended to be fully featured just provide
144 minimum required.
145 */
146 
147 ClassImp(TGLVector3);
148 
149 ////////////////////////////////////////////////////////////////////////////////
150 /// Construct a vector with components (x,y,z)
151 
152 TGLVector3::TGLVector3(Double_t x, Double_t y, Double_t z) :
153  TGLVertex3(x, y, z)
154 {
155 }
156 
157 ////////////////////////////////////////////////////////////////////////////////
158 /// Construct a vector with components (src[0], src[1], src[2])
159 
160 TGLVector3::TGLVector3(const Double_t *src) :
161  TGLVertex3(src[0], src[1], src[2])
162 {
163 }
164 
165 
166 /** \class TGLLine3
167 \ingroup opengl
168 3D space, fixed length, line class, with direction / length 'vector',
169 passing through point 'vertex'. Just wraps a TGLVector3 / TGLVertex3 pair.
170 */
171 
172 ClassImp(TGLLine3);
173 
174 ////////////////////////////////////////////////////////////////////////////////
175 /// Construct 3D line running from 'start' to 'end'
176 
177 TGLLine3::TGLLine3(const TGLVertex3 & start, const TGLVertex3 & end) :
178  fVertex(start), fVector(end - start)
179 {
180 }
181 
182 ////////////////////////////////////////////////////////////////////////////////
183 /// Construct 3D line running from 'start', magnitude 'vect'
184 
185 TGLLine3::TGLLine3(const TGLVertex3 & start, const TGLVector3 & vect) :
186  fVertex(start), fVector(vect)
187 {
188 }
189 
190 ////////////////////////////////////////////////////////////////////////////////
191 /// Set 3D line running from 'start' to 'end'
192 
193 void TGLLine3::Set(const TGLVertex3 & start, const TGLVertex3 & end)
194 {
195  fVertex = start;
196  fVector = end - start;
197 }
198 
199 ////////////////////////////////////////////////////////////////////////////////
200 /// Set 3D line running from start, magnitude 'vect'
201 
202 void TGLLine3::Set(const TGLVertex3 & start, const TGLVector3 & vect)
203 {
204  fVertex = start;
205  fVector = vect;
206 }
207 
208 ////////////////////////////////////////////////////////////////////////////////
209 /// Draw line in current basic GL color. Assume we are in the correct reference
210 /// frame
211 
212 void TGLLine3::Draw() const
213 {
214  glBegin(GL_LINE_LOOP);
215  glVertex3dv(fVertex.CArr());
216  glVertex3dv(End().CArr());
217  glEnd();
218 }
219 
220 /** \class TGLRect
221 \ingroup opengl
222 Viewport (pixel base) 2D rectangle class.
223 */
224 
225 ClassImp(TGLRect);
226 
227 ////////////////////////////////////////////////////////////////////////////////
228 /// Construct empty rect object, corner (0,0), width/height 0
229 
230 TGLRect::TGLRect() :
231  fX(0), fY(0), fWidth(0), fHeight(0)
232 {
233 }
234 
235 ////////////////////////////////////////////////////////////////////////////////
236 /// Construct rect object, corner (x,y), dimensions 'width', 'height'
237 
238 TGLRect::TGLRect(Int_t x, Int_t y, Int_t width, Int_t height) :
239  fX(x), fY(y), fWidth(width), fHeight(height)
240 {
241 }
242 
243 ////////////////////////////////////////////////////////////////////////////////
244 /// Construct rect object, corner (x,y), dimensions 'width', 'height'
245 
246 TGLRect::TGLRect(Int_t x, Int_t y, UInt_t width, UInt_t height) :
247  fX(x), fY(y), fWidth(width), fHeight(height)
248 {
249 }
250 
251 
252 ////////////////////////////////////////////////////////////////////////////////
253 /// Destroy rect object
254 
255 TGLRect::~TGLRect()
256 {
257 }
258 
259 ////////////////////////////////////////////////////////////////////////////////
260 /// Expand the rect to encompass point (x,y)
261 
262 void TGLRect::Expand(Int_t x, Int_t y)
263 {
264  Int_t delX = x - fX;
265  Int_t delY = y - fY;
266 
267  if (delX > fWidth) {
268  fWidth = delX;
269  }
270  if (delY > fHeight) {
271  fHeight = delY;
272  }
273 
274  if (delX < 0) {
275  fX = x;
276  fWidth += -delX;
277  }
278  if (delY < 0) {
279  fY = y;
280  fHeight += -delY;
281  }
282 }
283 
284 ////////////////////////////////////////////////////////////////////////////////
285 /// Return the diagonal of the rectangle.
286 
287 Int_t TGLRect::Diagonal() const
288 {
289  const Double_t w = static_cast<Double_t>(fWidth);
290  const Double_t h = static_cast<Double_t>(fHeight);
291  return TMath::Nint(TMath::Sqrt(w*w + h*h));
292 }
293 
294 ////////////////////////////////////////////////////////////////////////////////
295 /// Return overlap result (kInside, kOutside, kPartial) of this
296 /// rect with 'other'
297 
298 Rgl::EOverlap TGLRect::Overlap(const TGLRect & other) const
299 {
300  using namespace Rgl;
301 
302  if ((fX <= other.fX) && (fX + fWidth >= other.fX + other.fWidth) &&
303  (fY <= other.fY) && (fY + fHeight >= other.fY + other.fHeight))
304  {
305  return kInside;
306  }
307  else if ((fX >= other.fX + static_cast<Int_t>(other.fWidth)) ||
308  (fX + static_cast<Int_t>(fWidth) <= other.fX) ||
309  (fY >= other.fY + static_cast<Int_t>(other.fHeight)) ||
310  (fY + static_cast<Int_t>(fHeight) <= other.fY))
311  {
312  return kOutside;
313  }
314  else
315  {
316  return kPartial;
317  }
318 }
319 
320 /** \class TGLPlane
321 \ingroup opengl
322 3D plane class - of format Ax + By + Cz + D = 0
323 
324 This is part of collection of simple utility classes for GL only in
325 TGLUtil.h/cxx. These provide const and non-const accessors Arr() &
326 CArr() to a GL compatible internal field - so can be used directly
327 with OpenGL C API calls - which TVector3 etc cannot (easily).
328 They are not intended to be fully featured just provide minimum
329 required.
330 */
331 
332 ClassImp(TGLPlane);
333 
334 ////////////////////////////////////////////////////////////////////////////////
335 /// Construct a default plane of x + y + z = 0
336 
337 TGLPlane::TGLPlane()
338 {
339  Set(1.0, 1.0, 1.0, 0.0);
340 }
341 
342 ////////////////////////////////////////////////////////////////////////////////
343 /// Construct plane from 'other'
344 
345 TGLPlane::TGLPlane(const TGLPlane & other)
346 {
347  Set(other);
348 }
349 
350 ////////////////////////////////////////////////////////////////////////////////
351 /// Construct plane with equation a.x + b.y + c.z + d = 0
352 /// with optional normalisation
353 
354 TGLPlane::TGLPlane(Double_t a, Double_t b, Double_t c, Double_t d)
355 {
356  Set(a, b, c, d);
357 }
358 
359 ////////////////////////////////////////////////////////////////////////////////
360 /// Construct plane with equation eq[0].x + eq[1].y + eq[2].z + eq[3] = 0
361 /// with optional normalisation
362 
363 TGLPlane::TGLPlane(Double_t eq[4])
364 {
365  Set(eq);
366 }
367 
368 ////////////////////////////////////////////////////////////////////////////////
369 /// Construct plane passing through 3 supplied points
370 /// with optional normalisation
371 
372 TGLPlane::TGLPlane(const TGLVertex3 & p1, const TGLVertex3 & p2,
373  const TGLVertex3 & p3)
374 {
375  Set(p1, p2, p3);
376 }
377 
378 ////////////////////////////////////////////////////////////////////////////////
379 /// Construct plane with supplied normal vector, passing through point
380 /// with optional normalisation
381 
382 TGLPlane::TGLPlane(const TGLVector3 & v, const TGLVertex3 & p)
383 {
384  Set(v, p);
385 }
386 
387 ////////////////////////////////////////////////////////////////////////////////
388 /// Assignment operator
389 
390 TGLPlane &TGLPlane::operator=(const TGLPlane &src)
391 {
392  Set(src);
393  return *this;
394 }
395 
396 ////////////////////////////////////////////////////////////////////////////////
397 /// Normalise the plane.
398 
399 void TGLPlane::Normalise()
400 {
401  Double_t mag = sqrt(fVals[0]*fVals[0] + fVals[1]*fVals[1] + fVals[2]*fVals[2]);
402 
403  if (mag == 0.0 ) {
404  Error("TGLPlane::Normalise", "trying to normalise plane with zero magnitude normal");
405  return;
406  }
407  mag = 1.0 / mag;
408  fVals[0] *= mag;
409  fVals[1] *= mag;
410  fVals[2] *= mag;
411  fVals[3] *= mag;
412 }
413 
414 ////////////////////////////////////////////////////////////////////////////////
415 /// Output plane equation to std::out
416 
417 void TGLPlane::Dump() const
418 {
419  std::cout.precision(6);
420  std::cout << "Plane : " << fVals[0] << "x + " << fVals[1] << "y + " << fVals[2] << "z + " << fVals[3] << std::endl;
421 }
422 
423 ////////////////////////////////////////////////////////////////////////////////
424 /// Assign from other.
425 
426 void TGLPlane::Set(const TGLPlane & other)
427 {
428  fVals[0] = other.fVals[0];
429  fVals[1] = other.fVals[1];
430  fVals[2] = other.fVals[2];
431  fVals[3] = other.fVals[3];
432 }
433 
434 ////////////////////////////////////////////////////////////////////////////////
435 /// Set by values.
436 
437 void TGLPlane::Set(Double_t a, Double_t b, Double_t c, Double_t d)
438 {
439  fVals[0] = a;
440  fVals[1] = b;
441  fVals[2] = c;
442  fVals[3] = d;
443  Normalise();
444 }
445 
446 ////////////////////////////////////////////////////////////////////////////////
447 /// Set by array values.
448 
449 void TGLPlane::Set(Double_t eq[4])
450 {
451  fVals[0] = eq[0];
452  fVals[1] = eq[1];
453  fVals[2] = eq[2];
454  fVals[3] = eq[3];
455  Normalise();
456 }
457 
458 ////////////////////////////////////////////////////////////////////////////////
459 /// Set plane from a normal vector and in-plane point pair
460 
461 void TGLPlane::Set(const TGLVector3 & norm, const TGLVertex3 & point)
462 {
463  fVals[0] = norm[0];
464  fVals[1] = norm[1];
465  fVals[2] = norm[2];
466  fVals[3] = -(fVals[0]*point[0] + fVals[1]*point[1] + fVals[2]*point[2]);
467  Normalise();
468 }
469 
470 ////////////////////////////////////////////////////////////////////////////////
471 /// Set plane by three points.
472 
473 void TGLPlane::Set(const TGLVertex3 & p1, const TGLVertex3 & p2, const TGLVertex3 & p3)
474 {
475  TGLVector3 norm = Cross(p2 - p1, p3 - p1);
476  Set(norm, p2);
477 }
478 
479 ////////////////////////////////////////////////////////////////////////////////
480 /// Negate the plane.
481 
482 void TGLPlane::Negate()
483 {
484  fVals[0] = -fVals[0];
485  fVals[1] = -fVals[1];
486  fVals[2] = -fVals[2];
487  fVals[3] = -fVals[3];
488 }
489 
490 ////////////////////////////////////////////////////////////////////////////////
491 /// Distance from plane to vertex.
492 
493 Double_t TGLPlane::DistanceTo(const TGLVertex3 & vertex) const
494 {
495  return (fVals[0]*vertex[0] + fVals[1]*vertex[1] + fVals[2]*vertex[2] + fVals[3]);
496 }
497 
498 ////////////////////////////////////////////////////////////////////////////////
499 /// Return nearest point on plane.
500 
501 TGLVertex3 TGLPlane::NearestOn(const TGLVertex3 & point) const
502 {
503  TGLVector3 o = Norm() * (Dot(Norm(), TGLVector3(point[0], point[1], point[2])) + D() / Dot(Norm(), Norm()));
504  TGLVertex3 v = point - o;
505  return v;
506 }
507 
508 // Some free functions for plane intersections
509 
510 ////////////////////////////////////////////////////////////////////////////////
511 /// Find 3D line interestion of this plane with 'other'. Returns a std::pair
512 ///
513 /// first (Bool_t) second (TGLLine3)
514 /// kTRUE - planes intersect intersection line between planes
515 /// kFALSE - no intersect (parallel) undefined
516 
517 std::pair<Bool_t, TGLLine3> Intersection(const TGLPlane & p1, const TGLPlane & p2)
518 {
519  TGLVector3 lineDir = Cross(p1.Norm(), p2.Norm());
520 
521  if (lineDir.Mag() == 0.0) {
522  return std::make_pair(kFALSE, TGLLine3(TGLVertex3(0.0, 0.0, 0.0),
523  TGLVector3(0.0, 0.0, 0.0)));
524  }
525  TGLVertex3 linePoint = Cross((p1.Norm()*p2.D() - p2.Norm()*p1.D()), lineDir) /
526  Dot(lineDir, lineDir);
527  return std::make_pair(kTRUE, TGLLine3(linePoint, lineDir));
528 }
529 
530 ////////////////////////////////////////////////////////////////////////////////
531 
532 std::pair<Bool_t, TGLVertex3> Intersection(const TGLPlane & p1, const TGLPlane & p2, const TGLPlane & p3)
533 {
534  Double_t denom = Dot(p1.Norm(), Cross(p2.Norm(), p3.Norm()));
535  if (denom == 0.0) {
536  return std::make_pair(kFALSE, TGLVertex3(0.0, 0.0, 0.0));
537  }
538  TGLVector3 vect = ((Cross(p2.Norm(),p3.Norm())* -p1.D()) -
539  (Cross(p3.Norm(),p1.Norm())*p2.D()) -
540  (Cross(p1.Norm(),p2.Norm())*p3.D())) / denom;
541  TGLVertex3 interVert(vect.X(), vect.Y(), vect.Z());
542  return std::make_pair(kTRUE, interVert);
543 }
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 /// Find intersection of 3D space 'line' with this plane. If 'extend' is kTRUE
547 /// then line extents can be extended (infinite length) to find intersection.
548 /// If 'extend' is kFALSE the fixed extents of line is respected.
549 ///
550 /// The return a std::pair
551 ///
552 /// - first (Bool_t) second (TGLVertex3)
553 /// - kTRUE - line/plane intersect intersection vertex on plane
554 /// - kFALSE - no line/plane intersect undefined
555 ///
556 /// If intersection is not found (first == kFALSE) & 'extend' was kTRUE (infinite line)
557 /// this implies line and plane are parallel. If 'extend' was kFALSE, then
558 /// either line parallel or insufficient length.
559 
560 std::pair<Bool_t, TGLVertex3> Intersection(const TGLPlane & plane, const TGLLine3 & line, Bool_t extend)
561 {
562  Double_t denom = -(plane.A()*line.Vector().X() +
563  plane.B()*line.Vector().Y() +
564  plane.C()*line.Vector().Z());
565 
566  if (denom == 0.0) {
567  return std::make_pair(kFALSE, TGLVertex3(0.0, 0.0, 0.0));
568  }
569 
570  Double_t num = plane.A()*line.Start().X() + plane.B()*line.Start().Y() +
571  plane.C()*line.Start().Z() + plane.D();
572  Double_t factor = num/denom;
573 
574  // If not extending (projecting) line is length from start enough to reach plane?
575  if (!extend && (factor < 0.0 || factor > 1.0)) {
576  return std::make_pair(kFALSE, TGLVertex3(0.0, 0.0, 0.0));
577  }
578 
579  TGLVector3 toPlane = line.Vector() * factor;
580  return std::make_pair(kTRUE, line.Start() + toPlane);
581 }
582 
583 /** \class TGLMatrix
584 \ingroup opengl
585 16 component (4x4) transform matrix - column MAJOR as per GL.
586 Provides limited support for adjusting the translation, scale and
587 rotation components.
588 
589 This is part of collection of simple utility classes for GL only in
590 TGLUtil.h/cxx. These provide const and non-const accessors Arr() &
591 CArr() to a GL compatible internal field - so can be used directly
592 with OpenGL C API calls - which TVector3 etc cannot (easily).
593 They are not intended to be fully featured just provide minimum
594 required.
595 */
596 
597 ClassImp(TGLMatrix);
598 
599 ////////////////////////////////////////////////////////////////////////////////
600 /// Construct default identity matrix:
601 ///
602 /// 1 0 0 0
603 /// 0 1 0 0
604 /// 0 0 1 0
605 /// 0 0 0 1
606 
607 TGLMatrix::TGLMatrix()
608 {
609  SetIdentity();
610 }
611 
612 ////////////////////////////////////////////////////////////////////////////////
613 /// Construct matrix with translation components x,y,z:
614 ///
615 /// 1 0 0 x
616 /// 0 1 0 y
617 /// 0 0 1 z
618 /// 0 0 0 1
619 
620 TGLMatrix::TGLMatrix(Double_t x, Double_t y, Double_t z)
621 {
622  SetIdentity();
623  SetTranslation(x, y, z);
624 }
625 
626 ////////////////////////////////////////////////////////////////////////////////
627 /// Construct matrix with translation components x,y,z:
628 ///
629 /// 1 0 0 translation.X()
630 /// 0 1 0 translation.Y()
631 /// 0 0 1 translation.Z()
632 /// 0 0 0 1
633 
634 TGLMatrix::TGLMatrix(const TGLVertex3 & translation)
635 {
636  SetIdentity();
637  SetTranslation(translation);
638 }
639 
640 ////////////////////////////////////////////////////////////////////////////////
641 /// Construct matrix which when applied puts local origin at
642 /// 'origin' and the local Z axis in direction 'z'. Both
643 /// 'origin' and 'zAxisVec' are expressed in the parent frame
644 
645 TGLMatrix::TGLMatrix(const TGLVertex3 & origin, const TGLVector3 & zAxis)
646 {
647  SetIdentity();
648 
649  TGLVector3 zAxisInt(zAxis);
650  zAxisInt.Normalise();
651  TGLVector3 arbAxis;
652 
653  if (TMath::Abs(zAxisInt.X()) <= TMath::Abs(zAxisInt.Y()) && TMath::Abs(zAxisInt.X()) <= TMath::Abs(zAxisInt.Z())) {
654  arbAxis.Set(1.0, 0.0, 0.0);
655  } else if (TMath::Abs(zAxisInt.Y()) <= TMath::Abs(zAxisInt.X()) && TMath::Abs(zAxisInt.Y()) <= TMath::Abs(zAxisInt.Z())) {
656  arbAxis.Set(0.0, 1.0, 0.0);
657  } else {
658  arbAxis.Set(0.0, 0.0, 1.0);
659  }
660 
661  Set(origin, zAxis, Cross(zAxisInt, arbAxis));
662 }
663 
664 ////////////////////////////////////////////////////////////////////////////////
665 /// Construct matrix which when applied puts local origin at
666 /// 'origin' and the local Z axis in direction 'z'. Both
667 /// 'origin' and 'zAxisVec' are expressed in the parent frame
668 
669 TGLMatrix::TGLMatrix(const TGLVertex3 & origin, const TGLVector3 & zAxis, const TGLVector3 & xAxis)
670 {
671  SetIdentity();
672  Set(origin, zAxis, xAxis);
673 }
674 
675 ////////////////////////////////////////////////////////////////////////////////
676 /// Construct matrix using the 16 Double_t 'vals' passed,
677 /// ordering is maintained - i.e. should be column major
678 /// as we are
679 
680 TGLMatrix::TGLMatrix(const Double_t vals[16])
681 {
682  Set(vals);
683 }
684 
685 ////////////////////////////////////////////////////////////////////////////////
686 /// Construct matrix from 'other'
687 
688 TGLMatrix::TGLMatrix(const TGLMatrix & other)
689 {
690  *this = other;
691 }
692 
693 ////////////////////////////////////////////////////////////////////////////////
694 /// Destroy matrix object
695 
696 TGLMatrix::~TGLMatrix()
697 {
698 }
699 
700 ////////////////////////////////////////////////////////////////////////////////
701 /// Multiply with matrix rhs on right.
702 
703 void TGLMatrix::MultRight(const TGLMatrix & rhs)
704 {
705  Double_t B[4];
706  Double_t* C = fVals;
707  for(int r=0; r<4; ++r, ++C)
708  {
709  const Double_t* T = rhs.fVals;
710  for(int c=0; c<4; ++c, T+=4)
711  B[c] = C[0]*T[0] + C[4]*T[1] + C[8]*T[2] + C[12]*T[3];
712  C[0] = B[0]; C[4] = B[1]; C[8] = B[2]; C[12] = B[3];
713  }
714 }
715 
716 ////////////////////////////////////////////////////////////////////////////////
717 /// Multiply with matrix lhs on left.
718 
719 void TGLMatrix::MultLeft (const TGLMatrix & lhs)
720 {
721  Double_t B[4];
722  Double_t* C = fVals;
723  for (int c=0; c<4; ++c, C+=4)
724  {
725  const Double_t* T = lhs.fVals;
726  for(int r=0; r<4; ++r, ++T)
727  B[r] = T[0]*C[0] + T[4]*C[1] + T[8]*C[2] + T[12]*C[3];
728  C[0] = B[0]; C[1] = B[1]; C[2] = B[2]; C[3] = B[3];
729  }
730 }
731 
732 ////////////////////////////////////////////////////////////////////////////////
733 /// Set matrix which when applied puts local origin at
734 /// 'origin' and the local Z axis in direction 'z'. Both
735 /// 'origin' and 'z' are expressed in the parent frame
736 
737 void TGLMatrix::Set(const TGLVertex3 & origin, const TGLVector3 & zAxis, const TGLVector3 & xAxis)
738 {
739  TGLVector3 zAxisInt(zAxis);
740  zAxisInt.Normalise();
741 
742  TGLVector3 xAxisInt(xAxis);
743  xAxisInt.Normalise();
744  TGLVector3 yAxisInt = Cross(zAxisInt, xAxisInt);
745 
746  fVals[0] = xAxisInt.X(); fVals[4] = yAxisInt.X(); fVals[8 ] = zAxisInt.X(); fVals[12] = origin.X();
747  fVals[1] = xAxisInt.Y(); fVals[5] = yAxisInt.Y(); fVals[9 ] = zAxisInt.Y(); fVals[13] = origin.Y();
748  fVals[2] = xAxisInt.Z(); fVals[6] = yAxisInt.Z(); fVals[10] = zAxisInt.Z(); fVals[14] = origin.Z();
749  fVals[3] = 0.0; fVals[7] = 0.0; fVals[11] = 0.0; fVals[15] = 1.0;
750 }
751 
752 ////////////////////////////////////////////////////////////////////////////////
753 /// Set matrix using the 16 Double_t 'vals' passed,
754 /// ordering is maintained - i.e. should be column major.
755 
756 void TGLMatrix::Set(const Double_t vals[16])
757 {
758  for (UInt_t i=0; i < 16; i++) {
759  fVals[i] = vals[i];
760  }
761 }
762 
763 ////////////////////////////////////////////////////////////////////////////////
764 /// Set matrix to identity.
765 
766 void TGLMatrix::SetIdentity()
767 {
768  fVals[0] = 1.0; fVals[4] = 0.0; fVals[8 ] = 0.0; fVals[12] = 0.0;
769  fVals[1] = 0.0; fVals[5] = 1.0; fVals[9 ] = 0.0; fVals[13] = 0.0;
770  fVals[2] = 0.0; fVals[6] = 0.0; fVals[10] = 1.0; fVals[14] = 0.0;
771  fVals[3] = 0.0; fVals[7] = 0.0; fVals[11] = 0.0; fVals[15] = 1.0;
772 }
773 
774 ////////////////////////////////////////////////////////////////////////////////
775 /// Set matrix translation components x,y,z.
776 
777 void TGLMatrix::SetTranslation(Double_t x, Double_t y, Double_t z)
778 {
779  SetTranslation(TGLVertex3(x,y,z));
780 }
781 
782 ////////////////////////////////////////////////////////////////////////////////
783 /// Set matrix translation components x,y,z.
784 
785 void TGLMatrix::SetTranslation(const TGLVertex3 & translation)
786 {
787  fVals[12] = translation[0];
788  fVals[13] = translation[1];
789  fVals[14] = translation[2];
790 }
791 
792 ////////////////////////////////////////////////////////////////////////////////
793 /// Return the translation component of matrix.
794 
795 TGLVector3 TGLMatrix::GetTranslation() const
796 {
797  return TGLVector3(fVals[12], fVals[13], fVals[14]);
798 }
799 
800 ////////////////////////////////////////////////////////////////////////////////
801 /// Shift matrix translation components by 'vect' in parent frame.
802 
803 void TGLMatrix::Translate(const TGLVector3 & vect)
804 {
805  fVals[12] += vect[0];
806  fVals[13] += vect[1];
807  fVals[14] += vect[2];
808 }
809 
810 ////////////////////////////////////////////////////////////////////////////////
811 /// Translate in local frame.
812 /// i1, i2 are axes indices: 1 ~ x, 2 ~ y, 3 ~ z.
813 
814 void TGLMatrix::MoveLF(Int_t ai, Double_t amount)
815 {
816  const Double_t *C = fVals + 4*--ai;
817  fVals[12] += amount*C[0]; fVals[13] += amount*C[1]; fVals[14] += amount*C[2];
818 }
819 
820 ////////////////////////////////////////////////////////////////////////////////
821 /// Translate in local frame along all base vectors simultaneously.
822 
823 void TGLMatrix::Move3LF(Double_t x, Double_t y, Double_t z)
824 {
825  fVals[12] += x*fVals[0] + y*fVals[4] + z*fVals[8];
826  fVals[13] += x*fVals[1] + y*fVals[5] + z*fVals[9];
827  fVals[14] += x*fVals[2] + y*fVals[6] + z*fVals[10];
828 }
829 
830 ////////////////////////////////////////////////////////////////////////////////
831 /// Set matrix axis scales to 'scale'. Note - this really sets
832 /// the overall (total) scaling for each axis - it does NOT
833 /// apply compounded scale on top of existing one
834 
835 void TGLMatrix::Scale(const TGLVector3 & scale)
836 {
837  TGLVector3 currentScale = GetScale();
838 
839  // x
840  if (currentScale[0] != 0.0) {
841  fVals[0] *= scale[0]/currentScale[0];
842  fVals[1] *= scale[0]/currentScale[0];
843  fVals[2] *= scale[0]/currentScale[0];
844  } else {
845  Error("TGLMatrix::Scale()", "zero scale div by zero");
846  }
847  // y
848  if (currentScale[1] != 0.0) {
849  fVals[4] *= scale[1]/currentScale[1];
850  fVals[5] *= scale[1]/currentScale[1];
851  fVals[6] *= scale[1]/currentScale[1];
852  } else {
853  Error("TGLMatrix::Scale()", "zero scale div by zero");
854  }
855  // z
856  if (currentScale[2] != 0.0) {
857  fVals[8] *= scale[2]/currentScale[2];
858  fVals[9] *= scale[2]/currentScale[2];
859  fVals[10] *= scale[2]/currentScale[2];
860  } else {
861  Error("TGLMatrix::Scale()", "zero scale div by zero");
862  }
863 }
864 
865 ////////////////////////////////////////////////////////////////////////////////
866 /// Update matrix so resulting transform has been rotated about 'pivot'
867 /// (in parent frame), round vector 'axis', through 'angle' (radians)
868 /// Equivalent to glRotate function, but with addition of translation
869 /// and compounded on top of existing.
870 
871 void TGLMatrix::Rotate(const TGLVertex3 & pivot, const TGLVector3 & axis, Double_t angle)
872 {
873  TGLVector3 nAxis = axis;
874  nAxis.Normalise();
875  Double_t x = nAxis.X();
876  Double_t y = nAxis.Y();
877  Double_t z = nAxis.Z();
878  Double_t c = TMath::Cos(angle);
879  Double_t s = TMath::Sin(angle);
880 
881  // Calculate local rotation, with pre-translation to local pivot origin
882  TGLMatrix rotMat;
883  rotMat[ 0] = x*x*(1-c) + c; rotMat[ 4] = x*y*(1-c) - z*s; rotMat[ 8] = x*z*(1-c) + y*s; rotMat[12] = pivot[0];
884  rotMat[ 1] = y*x*(1-c) + z*s; rotMat[ 5] = y*y*(1-c) + c; rotMat[ 9] = y*z*(1-c) - x*s; rotMat[13] = pivot[1];
885  rotMat[ 2] = x*z*(1-c) - y*s; rotMat[ 6] = y*z*(1-c) + x*s; rotMat[10] = z*z*(1-c) + c; rotMat[14] = pivot[2];
886  rotMat[ 3] = 0.0; rotMat[ 7] = 0.0; rotMat[11] = 0.0; rotMat[15] = 1.0;
887  TGLMatrix localToWorld(-pivot);
888 
889  // TODO: Ugly - should use quaternions to avoid compound rounding errors and
890  // triple multiplication
891  *this = rotMat * localToWorld * (*this);
892 }
893 
894 ////////////////////////////////////////////////////////////////////////////////
895 /// Rotate in local frame. Does optimised version of MultRight.
896 /// i1, i2 are axes indices: 1 ~ x, 2 ~ y, 3 ~ z.
897 
898 void TGLMatrix::RotateLF(Int_t i1, Int_t i2, Double_t amount)
899 {
900  if(i1 == i2) return;
901  const Double_t cos = TMath::Cos(amount), sin = TMath::Sin(amount);
902  Double_t b1, b2;
903  Double_t* c = fVals;
904  --i1 <<= 2; --i2 <<= 2; // column major
905  for(int r=0; r<4; ++r, ++c) {
906  b1 = cos*c[i1] + sin*c[i2];
907  b2 = cos*c[i2] - sin*c[i1];
908  c[i1] = b1; c[i2] = b2;
909  }
910 }
911 
912 ////////////////////////////////////////////////////////////////////////////////
913 /// Rotate in parent frame. Does optimised version of MultLeft.
914 
915 void TGLMatrix::RotatePF(Int_t i1, Int_t i2, Double_t amount)
916 {
917  if(i1 == i2) return;
918 
919  // Optimized version:
920  const Double_t cos = TMath::Cos(amount), sin = TMath::Sin(amount);
921  Double_t b1, b2;
922  Double_t* C = fVals;
923  --i1; --i2;
924  for(int c=0; c<4; ++c, C+=4) {
925  b1 = cos*C[i1] - sin*C[i2];
926  b2 = cos*C[i2] + sin*C[i1];
927  C[i1] = b1; C[i2] = b2;
928  }
929 }
930 
931 ////////////////////////////////////////////////////////////////////////////////
932 /// Transform passed 'vertex' by this matrix - converts local frame to parent
933 
934 void TGLMatrix::TransformVertex(TGLVertex3 & vertex) const
935 {
936  TGLVertex3 orig = vertex;
937  for (UInt_t i = 0; i < 3; i++) {
938  vertex[i] = orig[0] * fVals[0+i] + orig[1] * fVals[4+i] +
939  orig[2] * fVals[8+i] + fVals[12+i];
940  }
941 }
942 
943 ////////////////////////////////////////////////////////////////////////////////
944 /// Transpose the top left 3x3 matrix component along major diagonal
945 /// Supported as currently incompatibility between TGeo and GL matrix
946 /// layouts for this 3x3 only. To be resolved.
947 
948 void TGLMatrix::Transpose3x3()
949 {
950  // TODO: Move this fix to the TBuffer3D filling side and remove
951  //
952  // 0 4 8 12
953  // 1 5 9 13
954  // 2 6 10 14
955  // 3 7 11 15
956 
957  Double_t temp = fVals[4];
958  fVals[4] = fVals[1];
959  fVals[1] = temp;
960  temp = fVals[8];
961  fVals[8] = fVals[2];
962  fVals[2] = temp;
963  temp = fVals[9];
964  fVals[9] = fVals[6];
965  fVals[6] = temp;
966 }
967 
968 ////////////////////////////////////////////////////////////////////////////////
969 /// Invert the matrix, returns determinant.
970 /// Copied from TMatrixFCramerInv.
971 
972 Double_t TGLMatrix::Invert()
973 {
974  Double_t* M = fVals;
975 
976  const Double_t det2_12_01 = M[1]*M[6] - M[5]*M[2];
977  const Double_t det2_12_02 = M[1]*M[10] - M[9]*M[2];
978  const Double_t det2_12_03 = M[1]*M[14] - M[13]*M[2];
979  const Double_t det2_12_13 = M[5]*M[14] - M[13]*M[6];
980  const Double_t det2_12_23 = M[9]*M[14] - M[13]*M[10];
981  const Double_t det2_12_12 = M[5]*M[10] - M[9]*M[6];
982  const Double_t det2_13_01 = M[1]*M[7] - M[5]*M[3];
983  const Double_t det2_13_02 = M[1]*M[11] - M[9]*M[3];
984  const Double_t det2_13_03 = M[1]*M[15] - M[13]*M[3];
985  const Double_t det2_13_12 = M[5]*M[11] - M[9]*M[7];
986  const Double_t det2_13_13 = M[5]*M[15] - M[13]*M[7];
987  const Double_t det2_13_23 = M[9]*M[15] - M[13]*M[11];
988  const Double_t det2_23_01 = M[2]*M[7] - M[6]*M[3];
989  const Double_t det2_23_02 = M[2]*M[11] - M[10]*M[3];
990  const Double_t det2_23_03 = M[2]*M[15] - M[14]*M[3];
991  const Double_t det2_23_12 = M[6]*M[11] - M[10]*M[7];
992  const Double_t det2_23_13 = M[6]*M[15] - M[14]*M[7];
993  const Double_t det2_23_23 = M[10]*M[15] - M[14]*M[11];
994 
995 
996  const Double_t det3_012_012 = M[0]*det2_12_12 - M[4]*det2_12_02 + M[8]*det2_12_01;
997  const Double_t det3_012_013 = M[0]*det2_12_13 - M[4]*det2_12_03 + M[12]*det2_12_01;
998  const Double_t det3_012_023 = M[0]*det2_12_23 - M[8]*det2_12_03 + M[12]*det2_12_02;
999  const Double_t det3_012_123 = M[4]*det2_12_23 - M[8]*det2_12_13 + M[12]*det2_12_12;
1000  const Double_t det3_013_012 = M[0]*det2_13_12 - M[4]*det2_13_02 + M[8]*det2_13_01;
1001  const Double_t det3_013_013 = M[0]*det2_13_13 - M[4]*det2_13_03 + M[12]*det2_13_01;
1002  const Double_t det3_013_023 = M[0]*det2_13_23 - M[8]*det2_13_03 + M[12]*det2_13_02;
1003  const Double_t det3_013_123 = M[4]*det2_13_23 - M[8]*det2_13_13 + M[12]*det2_13_12;
1004  const Double_t det3_023_012 = M[0]*det2_23_12 - M[4]*det2_23_02 + M[8]*det2_23_01;
1005  const Double_t det3_023_013 = M[0]*det2_23_13 - M[4]*det2_23_03 + M[12]*det2_23_01;
1006  const Double_t det3_023_023 = M[0]*det2_23_23 - M[8]*det2_23_03 + M[12]*det2_23_02;
1007  const Double_t det3_023_123 = M[4]*det2_23_23 - M[8]*det2_23_13 + M[12]*det2_23_12;
1008  const Double_t det3_123_012 = M[1]*det2_23_12 - M[5]*det2_23_02 + M[9]*det2_23_01;
1009  const Double_t det3_123_013 = M[1]*det2_23_13 - M[5]*det2_23_03 + M[13]*det2_23_01;
1010  const Double_t det3_123_023 = M[1]*det2_23_23 - M[9]*det2_23_03 + M[13]*det2_23_02;
1011  const Double_t det3_123_123 = M[5]*det2_23_23 - M[9]*det2_23_13 + M[13]*det2_23_12;
1012 
1013  const Double_t det = M[0]*det3_123_123 - M[4]*det3_123_023 +
1014  M[8]*det3_123_013 - M[12]*det3_123_012;
1015 
1016  if(det == 0) {
1017  Warning("TGLMatrix::Invert", "matrix is singular.");
1018  return 0;
1019  }
1020 
1021  const Double_t oneOverDet = 1.0/det;
1022  const Double_t mn1OverDet = - oneOverDet;
1023 
1024  M[0] = det3_123_123 * oneOverDet;
1025  M[4] = det3_023_123 * mn1OverDet;
1026  M[8] = det3_013_123 * oneOverDet;
1027  M[12] = det3_012_123 * mn1OverDet;
1028 
1029  M[1] = det3_123_023 * mn1OverDet;
1030  M[5] = det3_023_023 * oneOverDet;
1031  M[9] = det3_013_023 * mn1OverDet;
1032  M[13] = det3_012_023 * oneOverDet;
1033 
1034  M[2] = det3_123_013 * oneOverDet;
1035  M[6] = det3_023_013 * mn1OverDet;
1036  M[10] = det3_013_013 * oneOverDet;
1037  M[14] = det3_012_013 * mn1OverDet;
1038 
1039  M[3] = det3_123_012 * mn1OverDet;
1040  M[7] = det3_023_012 * oneOverDet;
1041  M[11] = det3_013_012 * mn1OverDet;
1042  M[15] = det3_012_012 * oneOverDet;
1043 
1044  return det;
1045 }
1046 
1047 ////////////////////////////////////////////////////////////////////////////////
1048 /// Multiply vector.
1049 
1050 TGLVector3 TGLMatrix::Multiply(const TGLVector3& v, Double_t w) const
1051 {
1052  const Double_t* M = fVals;
1053  TGLVector3 r;
1054  r.X() = M[0]*v[0] + M[4]*v[1] + M[8]*v[2] + M[12]*w;
1055  r.Y() = M[1]*v[0] + M[5]*v[1] + M[9]*v[2] + M[13]*w;
1056  r.Z() = M[2]*v[0] + M[6]*v[1] + M[10]*v[2] + M[14]*w;
1057  return r;
1058 }
1059 
1060 ////////////////////////////////////////////////////////////////////////////////
1061 /// Rotate vector. Translation is not applied.
1062 
1063 TGLVector3 TGLMatrix::Rotate(const TGLVector3& v) const
1064 {
1065  const Double_t* M = fVals;
1066  TGLVector3 r;
1067  r.X() = M[0]*v[0] + M[4]*v[1] + M[8]*v[2];
1068  r.Y() = M[1]*v[0] + M[5]*v[1] + M[9]*v[2];
1069  r.Z() = M[2]*v[0] + M[6]*v[1] + M[10]*v[2];
1070  return r;
1071 }
1072 
1073 ////////////////////////////////////////////////////////////////////////////////
1074 /// Multiply vector in-place.
1075 
1076 void TGLMatrix::MultiplyIP(TGLVector3& v, Double_t w) const
1077 {
1078  const Double_t* M = fVals;
1079  Double_t r[3] = { v[0], v[1], v[2] };
1080  v.X() = M[0]*r[0] + M[4]*r[1] + M[8]*r[2] + M[12]*w;
1081  v.Y() = M[1]*r[0] + M[5]*r[1] + M[9]*r[2] + M[13]*w;
1082  v.Z() = M[2]*r[0] + M[6]*r[1] + M[10]*r[2] + M[14]*w;
1083 }
1084 
1085 ////////////////////////////////////////////////////////////////////////////////
1086 /// Rotate vector in-place. Translation is not applied.
1087 
1088 void TGLMatrix::RotateIP(TGLVector3& v) const
1089 {
1090  const Double_t* M = fVals;
1091  Double_t r[3] = { v[0], v[1], v[2] };
1092  v.X() = M[0]*r[0] + M[4]*r[1] + M[8]*r[2];
1093  v.Y() = M[1]*r[0] + M[5]*r[1] + M[9]*r[2];
1094  v.Z() = M[2]*r[0] + M[6]*r[1] + M[10]*r[2];
1095 }
1096 
1097 ////////////////////////////////////////////////////////////////////////////////
1098 /// Get local axis scaling factors
1099 
1100 TGLVector3 TGLMatrix::GetScale() const
1101 {
1102  TGLVector3 x(fVals[0], fVals[1], fVals[2]);
1103  TGLVector3 y(fVals[4], fVals[5], fVals[6]);
1104  TGLVector3 z(fVals[8], fVals[9], fVals[10]);
1105  return TGLVector3(x.Mag(), y.Mag(), z.Mag());
1106 }
1107 
1108 ////////////////////////////////////////////////////////////////////////////////
1109 /// Return true if matrix is to be considered a scaling matrix
1110 /// for rendering.
1111 
1112 Bool_t TGLMatrix::IsScalingForRender() const
1113 {
1114  Double_t ss;
1115  ss = fVals[0]*fVals[0] + fVals[1]*fVals[1] + fVals[2]*fVals[2];
1116  if (ss < 0.8 || ss > 1.2) return kTRUE;
1117  ss = fVals[4]*fVals[4] + fVals[5]*fVals[5] + fVals[6]*fVals[6];
1118  if (ss < 0.8 || ss > 1.2) return kTRUE;
1119  ss = fVals[8]*fVals[8] + fVals[9]*fVals[9] + fVals[10]*fVals[10];
1120  if (ss < 0.8 || ss > 1.2) return kTRUE;
1121  return kFALSE;
1122 }
1123 
1124 ////////////////////////////////////////////////////////////////////////////////
1125 /// Output 16 matrix components to std::cout
1126 ///
1127 /// 0 4 8 12
1128 /// 1 5 9 13
1129 /// 2 6 10 14
1130 /// 3 7 11 15
1131 ///
1132 
1133 void TGLMatrix::Dump() const
1134 {
1135  std::cout.precision(6);
1136  for (Int_t x = 0; x < 4; x++) {
1137  std::cout << "[ ";
1138  for (Int_t y = 0; y < 4; y++) {
1139  std::cout << fVals[y*4 + x] << " ";
1140  }
1141  std::cout << "]" << std::endl;
1142  }
1143 }
1144 
1145 
1146 /** \class TGLColor
1147 \ingroup opengl
1148 Class encapsulating color information in preferred GL format - an
1149 array of four unsigned bytes.
1150 Color index is also cached for easier interfacing with the
1151 traditional ROOT graphics.
1152 */
1153 
1154 ClassImp(TGLColor);
1155 
1156 ////////////////////////////////////////////////////////////////////////////////
1157 /// Default constructor. Color is initialized to black.
1158 
1159 TGLColor::TGLColor()
1160 {
1161  fRGBA[0] = fRGBA[1] = fRGBA[2] = 0;
1162  fRGBA[3] = 255;
1163  fIndex = -1;
1164 }
1165 
1166 ////////////////////////////////////////////////////////////////////////////////
1167 /// Constructor from Int_t values.
1168 
1169 TGLColor::TGLColor(Int_t r, Int_t g, Int_t b, Int_t a)
1170 {
1171  SetColor(r, g, b, a);
1172 }
1173 
1174 ////////////////////////////////////////////////////////////////////////////////
1175 /// Constructor from Float_t values.
1176 
1177 TGLColor::TGLColor(Float_t r, Float_t g, Float_t b, Float_t a)
1178 {
1179  SetColor(r, g, b, a);
1180 }
1181 
1182 ////////////////////////////////////////////////////////////////////////////////
1183 /// Constructor from color-index and transparency.
1184 
1185 TGLColor::TGLColor(Color_t color_index, Char_t transparency)
1186 {
1187  SetColor(color_index, transparency);
1188 }
1189 
1190 ////////////////////////////////////////////////////////////////////////////////
1191 /// copy constructor
1192 
1193 TGLColor::TGLColor(const TGLColor& c)
1194 {
1195  fRGBA[0] = c.fRGBA[0];
1196  fRGBA[1] = c.fRGBA[1];
1197  fRGBA[2] = c.fRGBA[2];
1198  fRGBA[3] = c.fRGBA[3];
1199  fIndex = c.fIndex;
1200 }
1201 
1202 ////////////////////////////////////////////////////////////////////////////////
1203 /// Assignment operator.
1204 
1205 TGLColor& TGLColor::operator=(const TGLColor& c)
1206 {
1207  fRGBA[0] = c.fRGBA[0];
1208  fRGBA[1] = c.fRGBA[1];
1209  fRGBA[2] = c.fRGBA[2];
1210  fRGBA[3] = c.fRGBA[3];
1211  fIndex = c.fIndex;
1212  return *this;
1213 }
1214 
1215 ////////////////////////////////////////////////////////////////////////////////
1216 /// Returns color-index representing the color.
1217 
1218 Color_t TGLColor::GetColorIndex() const
1219 {
1220  if (fIndex == -1)
1221  fIndex = TColor::GetColor(fRGBA[0], fRGBA[1], fRGBA[2]);
1222  return fIndex;
1223 }
1224 
1225 ////////////////////////////////////////////////////////////////////////////////
1226 /// Returns transparency value.
1227 
1228 Char_t TGLColor::GetTransparency() const
1229 {
1230  return TMath::Nint(100.0*(1.0 - fRGBA[3]/255.0));
1231 }
1232 
1233 ////////////////////////////////////////////////////////////////////////////////
1234 /// Set color with Int_t values.
1235 
1236 void TGLColor::SetColor(Int_t r, Int_t g, Int_t b, Int_t a)
1237 {
1238  fRGBA[0] = r;
1239  fRGBA[1] = g;
1240  fRGBA[2] = b;
1241  fRGBA[3] = a;
1242  fIndex = -1;
1243 }
1244 
1245 ////////////////////////////////////////////////////////////////////////////////
1246 /// Set color with Float_t values.
1247 
1248 void TGLColor::SetColor(Float_t r, Float_t g, Float_t b, Float_t a)
1249 {
1250  fRGBA[0] = (UChar_t)(255*r);
1251  fRGBA[1] = (UChar_t)(255*g);
1252  fRGBA[2] = (UChar_t)(255*b);
1253  fRGBA[3] = (UChar_t)(255*a);
1254  fIndex = -1;
1255 }
1256 
1257 ////////////////////////////////////////////////////////////////////////////////
1258 /// Set color by color-index. Alpha is not changed.
1259 /// If color_index is not valid, color is set to magenta.
1260 
1261 void TGLColor::SetColor(Color_t color_index)
1262 {
1263  TColor* c = gROOT->GetColor(color_index);
1264  if (c)
1265  {
1266  fRGBA[0] = (UChar_t)(255*c->GetRed());
1267  fRGBA[1] = (UChar_t)(255*c->GetGreen());
1268  fRGBA[2] = (UChar_t)(255*c->GetBlue());
1269  fIndex = color_index;
1270  }
1271  else
1272  {
1273  // Set to magenta.
1274  fRGBA[0] = 255;
1275  fRGBA[1] = 0;
1276  fRGBA[2] = 255;
1277  fIndex = -1;
1278  }
1279 }
1280 
1281 ////////////////////////////////////////////////////////////////////////////////
1282 /// Set color by color-index and alpha from the transparency.
1283 /// If color_index is not valid, color is set to magenta.
1284 
1285 void TGLColor::SetColor(Color_t color_index, Char_t transparency)
1286 {
1287  UChar_t alpha = (255*(100 - transparency))/100;
1288 
1289  TColor* c = gROOT->GetColor(color_index);
1290  if (c)
1291  {
1292  fRGBA[0] = (UChar_t)(255*c->GetRed());
1293  fRGBA[1] = (UChar_t)(255*c->GetGreen());
1294  fRGBA[2] = (UChar_t)(255*c->GetBlue());
1295  fRGBA[3] = alpha;
1296  fIndex = color_index;
1297  }
1298  else
1299  {
1300  // Set to magenta.
1301  fRGBA[0] = 255;
1302  fRGBA[1] = 0;
1303  fRGBA[2] = 255;
1304  fRGBA[3] = alpha;
1305  fIndex = -1;
1306  return;
1307  }
1308 }
1309 
1310 ////////////////////////////////////////////////////////////////////////////////
1311 /// Set alpha from the transparency.
1312 
1313 void TGLColor::SetTransparency(Char_t transparency)
1314 {
1315  fRGBA[3] = (255*(100 - transparency))/100;
1316 }
1317 
1318 ////////////////////////////////////////////////////////////////////////////////
1319 /// Return string describing the color.
1320 
1321 TString TGLColor::AsString() const
1322 {
1323  return TString::Format("rgba:%02hhx/%02hhx/%02hhx/%02hhx",
1324  fRGBA[0], fRGBA[1], fRGBA[2], fRGBA[3]);
1325 }
1326 
1327 
1328 /** \class TGLColorSet
1329 \ingroup opengl
1330 Class encapsulating a set of colors used throughout standard rendering.
1331 */
1332 
1333 ClassImp(TGLColorSet);
1334 
1335 ////////////////////////////////////////////////////////////////////////////////
1336 /// Constructor. Sets default for dark background.
1337 
1338 TGLColorSet::TGLColorSet()
1339 {
1340  StdDarkBackground();
1341 }
1342 
1343 ////////////////////////////////////////////////////////////////////////////////
1344 /// Copy constructor
1345 
1346 TGLColorSet::TGLColorSet(const TGLColorSet& s)
1347 {
1348  fBackground = s.fBackground;
1349  fForeground = s.fForeground;
1350  fOutline = s.fOutline;
1351  fMarkup = s.fMarkup;
1352  for (Int_t i = 0; i < 5; ++i)
1353  fSelection[i] = s.fSelection[i];
1354 }
1355 
1356 ////////////////////////////////////////////////////////////////////////////////
1357 /// Assignment operator.
1358 
1359 TGLColorSet& TGLColorSet::operator=(const TGLColorSet& s)
1360 {
1361  fBackground = s.fBackground;
1362  fForeground = s.fForeground;
1363  fOutline = s.fOutline;
1364  fMarkup = s.fMarkup;
1365  for (Int_t i = 0; i < 5; ++i)
1366  fSelection[i] = s.fSelection[i];
1367  return *this;
1368 }
1369 
1370 ////////////////////////////////////////////////////////////////////////////////
1371 /// Set defaults for dark (black) background.
1372 
1373 void TGLColorSet::StdDarkBackground()
1374 {
1375  fBackground .SetColor(0, 0, 0);
1376  fForeground .SetColor(255, 255, 255);
1377  fOutline .SetColor(240, 255, 240);
1378  fMarkup .SetColor(200, 200, 200);
1379 
1380  fSelection[0].SetColor( 0, 0, 0);
1381  fSelection[1].SetColor(255, 220, 220);
1382  fSelection[2].SetColor(255, 220, 220);
1383  fSelection[3].SetColor(200, 200, 255);
1384  fSelection[4].SetColor(200, 200, 255);
1385 }
1386 
1387 ////////////////////////////////////////////////////////////////////////////////
1388 /// Set defaults for light (white) background.
1389 
1390 void TGLColorSet::StdLightBackground()
1391 {
1392  fBackground .SetColor(255, 255, 255);
1393  fForeground .SetColor(0, 0, 0);
1394  fOutline .SetColor(0, 0, 0);
1395  fMarkup .SetColor(55, 55, 55);
1396 
1397  fSelection[0].SetColor(0, 0, 0);
1398  fSelection[1].SetColor(200, 100, 100);
1399  fSelection[2].SetColor(200, 100, 100);
1400  fSelection[3].SetColor(100, 100, 200);
1401  fSelection[4].SetColor(100, 100, 200);
1402 }
1403 
1404 
1405 /** \class TGLUtil
1406 \ingroup opengl
1407 Wrapper class for various misc static functions - error checking, draw helpers etc.
1408 */
1409 
1410 ClassImp(TGLUtil);
1411 
1412 UInt_t TGLUtil::fgDefaultDrawQuality = 10;
1413 UInt_t TGLUtil::fgDrawQuality = fgDefaultDrawQuality;
1414 UInt_t TGLUtil::fgColorLockCount = 0;
1415 
1416 Float_t TGLUtil::fgPointSize = 1.0f;
1417 Float_t TGLUtil::fgLineWidth = 1.0f;
1418 Float_t TGLUtil::fgPointSizeScale = 1.0f;
1419 Float_t TGLUtil::fgLineWidthScale = 1.0f;
1420 
1421 Float_t TGLUtil::fgScreenScalingFactor = 1.0f;
1422 Float_t TGLUtil::fgPointLineScalingFactor = 1.0f;
1423 Int_t TGLUtil::fgPickingRadius = 1;
1424 
1425 const UChar_t TGLUtil::fgRed[4] = { 230, 0, 0, 255 };
1426 const UChar_t TGLUtil::fgGreen[4] = { 0, 230, 0, 255 };
1427 const UChar_t TGLUtil::fgBlue[4] = { 0, 0, 230, 255 };
1428 const UChar_t TGLUtil::fgYellow[4] = { 210, 210, 0, 255 };
1429 const UChar_t TGLUtil::fgWhite[4] = { 255, 255, 255, 255 };
1430 const UChar_t TGLUtil::fgGrey[4] = { 128, 128, 128, 100 };
1431 
1432 #ifndef CALLBACK
1433 #define CALLBACK
1434 #endif
1435 
1436 extern "C"
1437 {
1438 #if defined(__APPLE_CC__) && __APPLE_CC__ > 4000 && __APPLE_CC__ < 5450 && !defined(__INTEL_COMPILER)
1439  typedef GLvoid (*tessfuncptr_t)(...);
1440 #elif defined(__linux__) || defined(__FreeBSD__) || defined( __OpenBSD__ ) || defined(__sun) || defined (__CYGWIN__) || defined (__APPLE__)
1441  typedef GLvoid (*tessfuncptr_t)();
1442 #elif defined (WIN32)
1443  typedef GLvoid (CALLBACK *tessfuncptr_t)();
1444 #else
1445  #error "Error - need to define type tessfuncptr_t for this platform/compiler"
1446 #endif
1447 }
1448 
1449 namespace
1450 {
1451 
1452 class TGLTesselatorWrap
1453 {
1454 protected:
1455 
1456 public:
1457  GLUtesselator *fTess;
1458 
1459  TGLTesselatorWrap(tessfuncptr_t vertex_func) : fTess(0)
1460  {
1461  fTess = gluNewTess();
1462  if (!fTess)
1463  throw std::bad_alloc();
1464 
1465 #if defined(__GNUC__) && __GNUC__ >= 8
1466 #pragma GCC diagnostic push
1467 #pragma GCC diagnostic ignored "-Wcast-function-type"
1468 #endif
1469 
1470  gluTessCallback(fTess, (GLenum)GLU_BEGIN, (tessfuncptr_t) glBegin);
1471  gluTessCallback(fTess, (GLenum)GLU_END, (tessfuncptr_t) glEnd);
1472  gluTessCallback(fTess, (GLenum)GLU_VERTEX, vertex_func);
1473 
1474 #if defined(__GNUC__) && __GNUC__ >= 8
1475 #pragma GCC diagnostic pop
1476 #endif
1477 
1478  }
1479 
1480  virtual ~TGLTesselatorWrap()
1481  {
1482  if (fTess)
1483  gluDeleteTess(fTess);
1484  }
1485 };
1486 
1487 }
1488 
1489 ////////////////////////////////////////////////////////////////////////////////
1490 /// Returns a tesselator for direct drawing when using 3-vertices with
1491 /// single precision.
1492 
1493 GLUtesselator* TGLUtil::GetDrawTesselator3fv()
1494 {
1495 
1496 #if defined(__GNUC__) && __GNUC__ >= 8
1497 #pragma GCC diagnostic push
1498 #pragma GCC diagnostic ignored "-Wcast-function-type"
1499 #endif
1500 
1501  static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex3fv);
1502 
1503 #if defined(__GNUC__) && __GNUC__ >= 8
1504 #pragma GCC diagnostic pop
1505 #endif
1506 
1507  return singleton.fTess;
1508 }
1509 
1510 ////////////////////////////////////////////////////////////////////////////////
1511 /// Returns a tesselator for direct drawing when using 4-vertices with
1512 /// single precision.
1513 
1514 GLUtesselator* TGLUtil::GetDrawTesselator4fv()
1515 {
1516 
1517 #if defined(__GNUC__) && __GNUC__ >= 8
1518 #pragma GCC diagnostic push
1519 #pragma GCC diagnostic ignored "-Wcast-function-type"
1520 #endif
1521 
1522  static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex4fv);
1523 
1524 #if defined(__GNUC__) && __GNUC__ >= 8
1525 #pragma GCC diagnostic pop
1526 #endif
1527 
1528  return singleton.fTess;
1529 }
1530 
1531 ////////////////////////////////////////////////////////////////////////////////
1532 /// Returns a tesselator for direct drawing when using 3-vertices with
1533 /// double precision.
1534 
1535 GLUtesselator* TGLUtil::GetDrawTesselator3dv()
1536 {
1537 
1538 #if defined(__GNUC__) && __GNUC__ >= 8
1539 #pragma GCC diagnostic push
1540 #pragma GCC diagnostic ignored "-Wcast-function-type"
1541 #endif
1542 
1543  static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex3dv);
1544 
1545 #if defined(__GNUC__) && __GNUC__ >= 8
1546 #pragma GCC diagnostic pop
1547 #endif
1548 
1549  return singleton.fTess;
1550 }
1551 
1552 ////////////////////////////////////////////////////////////////////////////////
1553 /// Returns a tesselator for direct drawing when using 4-vertices with
1554 /// double precision.
1555 
1556 GLUtesselator* TGLUtil::GetDrawTesselator4dv()
1557 {
1558 
1559 #if defined(__GNUC__) && __GNUC__ >= 8
1560 #pragma GCC diagnostic push
1561 #pragma GCC diagnostic ignored "-Wcast-function-type"
1562 #endif
1563 
1564  static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex4dv);
1565 
1566 #if defined(__GNUC__) && __GNUC__ >= 8
1567 #pragma GCC diagnostic pop
1568 #endif
1569 
1570  return singleton.fTess;
1571 }
1572 
1573 ////////////////////////////////////////////////////////////////////////////////
1574 /// Initialize globals that require other libraries to be initialized.
1575 /// This is called from TGLWidget creation function.
1576 
1577 void TGLUtil::InitializeIfNeeded()
1578 {
1579  static Bool_t init_done = kFALSE;
1580  if (init_done) return;
1581  init_done = kTRUE;
1582 
1583  fgScreenScalingFactor = gVirtualX->GetOpenGLScalingFactor();
1584 
1585  if (strcmp(gEnv->GetValue("OpenGL.PointLineScalingFactor", "native"), "native") == 0)
1586  {
1587  fgPointLineScalingFactor = fgScreenScalingFactor;
1588  }
1589  else
1590  {
1591  fgPointLineScalingFactor = gEnv->GetValue("OpenGL.PointLineScalingFactor", 1.0);
1592  }
1593 
1594  fgPickingRadius = TMath::Nint(gEnv->GetValue("OpenGL.PickingRadius", 3.0) * TMath::Sqrt(fgScreenScalingFactor));
1595 }
1596 
1597 ////////////////////////////////////////////////////////////////////////////////
1598 ///static: get draw quality
1599 
1600 UInt_t TGLUtil::GetDrawQuality()
1601 {
1602  return fgDrawQuality;
1603 }
1604 
1605 ////////////////////////////////////////////////////////////////////////////////
1606 ///static: set draw quality
1607 
1608 void TGLUtil::SetDrawQuality(UInt_t dq)
1609 {
1610  fgDrawQuality = dq;
1611 }
1612 
1613 ////////////////////////////////////////////////////////////////////////////////
1614 ///static: reset draw quality
1615 
1616 void TGLUtil::ResetDrawQuality()
1617 {
1618  fgDrawQuality = fgDefaultDrawQuality;
1619 }
1620 
1621 ////////////////////////////////////////////////////////////////////////////////
1622 ///static: get default draw quality
1623 
1624 UInt_t TGLUtil::GetDefaultDrawQuality()
1625 {
1626  return fgDefaultDrawQuality;
1627 }
1628 
1629 ////////////////////////////////////////////////////////////////////////////////
1630 ///static: set default draw quality
1631 
1632 void TGLUtil::SetDefaultDrawQuality(UInt_t dq)
1633 {
1634  fgDefaultDrawQuality = dq;
1635 }
1636 
1637 ////////////////////////////////////////////////////////////////////////////////
1638 /// Check current GL error state, outputting details via ROOT
1639 /// Error method if one
1640 
1641 Int_t TGLUtil::CheckError(const char * loc)
1642 {
1643  GLenum errCode;
1644  const GLubyte *errString;
1645 
1646  if ((errCode = glGetError()) != GL_NO_ERROR) {
1647  errString = gluErrorString(errCode);
1648  if (loc) {
1649  Error(loc, "GL Error %s", (const char *)errString);
1650  } else {
1651  Error("TGLUtil::CheckError", "GL Error %s", (const char *)errString);
1652  }
1653  }
1654  return errCode;
1655 }
1656 
1657 /******************************************************************************/
1658 // Color wrapping functions
1659 /******************************************************************************/
1660 
1661 ////////////////////////////////////////////////////////////////////////////////
1662 /// Prevent further color changes.
1663 
1664 UInt_t TGLUtil::LockColor()
1665 {
1666  return ++fgColorLockCount;
1667 }
1668 
1669 ////////////////////////////////////////////////////////////////////////////////
1670 /// Allow color changes.
1671 
1672 UInt_t TGLUtil::UnlockColor()
1673 {
1674  if (fgColorLockCount)
1675  --fgColorLockCount;
1676  else
1677  Error("TGLUtil::UnlockColor", "fgColorLockCount already 0.");
1678  return fgColorLockCount;
1679 }
1680 
1681 ////////////////////////////////////////////////////////////////////////////////
1682 /// Returns true if color lock-count is greater than 0.
1683 
1684 Bool_t TGLUtil::IsColorLocked()
1685 {
1686  return fgColorLockCount > 0;
1687 }
1688 
1689 ////////////////////////////////////////////////////////////////////////////////
1690 /// Set color from TGLColor.
1691 
1692 void TGLUtil::Color(const TGLColor& color)
1693 {
1694  if (fgColorLockCount == 0) glColor4ubv(color.CArr());
1695 }
1696 
1697 ////////////////////////////////////////////////////////////////////////////////
1698 /// Set color from TGLColor and alpha value.
1699 
1700 void TGLUtil::ColorAlpha(const TGLColor& color, UChar_t alpha)
1701 {
1702  if (fgColorLockCount == 0)
1703  {
1704  glColor4ub(color.GetRed(), color.GetGreen(), color.GetBlue(), alpha);
1705  }
1706 }
1707 
1708 ////////////////////////////////////////////////////////////////////////////////
1709 /// Set color from TGLColor and alpha value.
1710 
1711 void TGLUtil::ColorAlpha(const TGLColor& color, Float_t alpha)
1712 {
1713  if (fgColorLockCount == 0)
1714  {
1715  glColor4ub(color.GetRed(), color.GetGreen(), color.GetBlue(), (UChar_t)(255*alpha));
1716  }
1717 }
1718 
1719 ////////////////////////////////////////////////////////////////////////////////
1720 /// Set color from color_index and GL-style alpha (default 1).
1721 
1722 void TGLUtil::ColorAlpha(Color_t color_index, Float_t alpha)
1723 {
1724  if (fgColorLockCount == 0) {
1725  if (color_index < 0)
1726  color_index = 1;
1727  TColor* c = gROOT->GetColor(color_index);
1728  if (c)
1729  glColor4f(c->GetRed(), c->GetGreen(), c->GetBlue(), alpha);
1730  }
1731 }
1732 
1733 ////////////////////////////////////////////////////////////////////////////////
1734 /// Set color from color_index and ROOT-style transparency (default 0).
1735 
1736 void TGLUtil::ColorTransparency(Color_t color_index, Char_t transparency)
1737 {
1738  if (fgColorLockCount == 0) {
1739  if (color_index < 0)
1740  color_index = 1;
1741  TColor* c = gROOT->GetColor(color_index);
1742  if (c)
1743  glColor4f(c->GetRed(), c->GetGreen(), c->GetBlue(), 1.0f - 0.01f*transparency);
1744  }
1745 }
1746 
1747 ////////////////////////////////////////////////////////////////////////////////
1748 /// Wrapper for glColor3ub.
1749 
1750 void TGLUtil::Color3ub(UChar_t r, UChar_t g, UChar_t b)
1751 {
1752  if (fgColorLockCount == 0) glColor3ub(r, g, b);
1753 }
1754 
1755 ////////////////////////////////////////////////////////////////////////////////
1756 /// Wrapper for glColor4ub.
1757 
1758 void TGLUtil::Color4ub(UChar_t r, UChar_t g, UChar_t b, UChar_t a)
1759 {
1760  if (fgColorLockCount == 0) glColor4ub(r, g, b, a);
1761 }
1762 
1763 ////////////////////////////////////////////////////////////////////////////////
1764 /// Wrapper for glColor3ubv.
1765 
1766 void TGLUtil::Color3ubv(const UChar_t* rgb)
1767 {
1768  if (fgColorLockCount == 0) glColor3ubv(rgb);
1769 }
1770 
1771 ////////////////////////////////////////////////////////////////////////////////
1772 /// Wrapper for glColor4ubv.
1773 
1774 void TGLUtil::Color4ubv(const UChar_t* rgba)
1775 {
1776  if (fgColorLockCount == 0) glColor4ubv(rgba);
1777 }
1778 
1779 ////////////////////////////////////////////////////////////////////////////////
1780 /// Wrapper for glColor3f.
1781 
1782 void TGLUtil::Color3f(Float_t r, Float_t g, Float_t b)
1783 {
1784  if (fgColorLockCount == 0) glColor3f(r, g, b);
1785 }
1786 
1787 ////////////////////////////////////////////////////////////////////////////////
1788 /// Wrapper for glColor4f.
1789 
1790 void TGLUtil::Color4f(Float_t r, Float_t g, Float_t b, Float_t a)
1791 {
1792  if (fgColorLockCount == 0) glColor4f(r, g, b, a);
1793 }
1794 
1795 ////////////////////////////////////////////////////////////////////////////////
1796 /// Wrapper for glColor3fv.
1797 
1798 void TGLUtil::Color3fv(const Float_t* rgb)
1799 {
1800  if (fgColorLockCount == 0) glColor3fv(rgb);
1801 }
1802 
1803 ////////////////////////////////////////////////////////////////////////////////
1804 /// Wrapper for glColor4fv.
1805 
1806 void TGLUtil::Color4fv(const Float_t* rgba)
1807 {
1808  if (fgColorLockCount == 0) glColor4fv(rgba);
1809 }
1810 
1811 /******************************************************************************/
1812 // Coordinate conversion and extra scaling (needed for osx retina)
1813 /******************************************************************************/
1814 
1815 ////////////////////////////////////////////////////////////////////////////////
1816 /// Convert from point/screen coordinates to GL viewport coordinates.
1817 
1818 void TGLUtil::PointToViewport(Int_t& x, Int_t& y)
1819 {
1820  if (fgScreenScalingFactor != 1.0)
1821  {
1822  x = TMath::Nint(x * fgScreenScalingFactor);
1823  y = TMath::Nint(y * fgScreenScalingFactor);
1824  }
1825 }
1826 
1827 ////////////////////////////////////////////////////////////////////////////////
1828 /// Convert from point/screen coordinates to GL viewport coordinates.
1829 
1830 void TGLUtil::PointToViewport(Int_t& x, Int_t& y, Int_t& w, Int_t& h)
1831 {
1832  if (fgScreenScalingFactor != 1.0)
1833  {
1834  x = TMath::Nint(x * fgScreenScalingFactor);
1835  y = TMath::Nint(y * fgScreenScalingFactor);
1836  w = TMath::Nint(w * fgScreenScalingFactor);
1837  h = TMath::Nint(h * fgScreenScalingFactor);
1838  }
1839 }
1840 
1841 ////////////////////////////////////////////////////////////////////////////////
1842 /// Returns scaling factor between screen points and GL viewport pixels.
1843 /// This is what is returned by gVirtualX->GetOpenGLScalingFactor() but is
1844 /// cached here to avoid a virtual function call as it is used quite often in
1845 /// TGLPhysical shape when drawing the selection highlight.
1846 
1847 Float_t TGLUtil::GetScreenScalingFactor()
1848 {
1849  return fgScreenScalingFactor;
1850 }
1851 
1852 ////////////////////////////////////////////////////////////////////////////////
1853 /// Return extra scaling factor for points and lines.
1854 /// By default this is set to the same value as ScreenScalingFactor to keep
1855 /// the same appearance. To override use rootrc entry, e.g.:
1856 /// OpenGL.PointLineScalingFactor: 1.0
1857 
1858 Float_t TGLUtil::GetPointLineScalingFactor()
1859 {
1860  return fgPointLineScalingFactor;
1861 }
1862 
1863 ////////////////////////////////////////////////////////////////////////////////
1864 /// Returns picking radius.
1865 
1866 Int_t TGLUtil::GetPickingRadius()
1867 {
1868  return fgPickingRadius;
1869 }
1870 
1871 /******************************************************************************/
1872 // Control for scaling of point-size and line-width.
1873 /******************************************************************************/
1874 
1875 ////////////////////////////////////////////////////////////////////////////////
1876 /// Get global point-size scale.
1877 
1878 Float_t TGLUtil::GetPointSizeScale()
1879 {
1880  return fgPointSizeScale;
1881 }
1882 
1883 ////////////////////////////////////////////////////////////////////////////////
1884 /// Set global point-size scale.
1885 
1886 void TGLUtil::SetPointSizeScale(Float_t scale)
1887 {
1888  fgPointSizeScale = scale;
1889 }
1890 
1891 ////////////////////////////////////////////////////////////////////////////////
1892 /// Returns global line-width scale.
1893 
1894 Float_t TGLUtil::GetLineWidthScale()
1895 {
1896  return fgLineWidthScale;
1897 }
1898 
1899 ////////////////////////////////////////////////////////////////////////////////
1900 /// Set global line-width scale.
1901 
1902 void TGLUtil::SetLineWidthScale(Float_t scale)
1903 {
1904  fgLineWidthScale = scale;
1905 }
1906 
1907 ////////////////////////////////////////////////////////////////////////////////
1908 /// Set the point-size, taking the global scaling into account.
1909 /// Wrapper for glPointSize.
1910 
1911 void TGLUtil::PointSize(Float_t point_size)
1912 {
1913  fgPointSize = point_size * fgPointSizeScale * fgPointLineScalingFactor;
1914  glPointSize(fgPointSize);
1915 }
1916 
1917 ////////////////////////////////////////////////////////////////////////////////
1918 /// Set the line-width, taking the global scaling into account.
1919 /// Wrapper for glLineWidth.
1920 
1921 void TGLUtil::LineWidth(Float_t line_width)
1922 {
1923  fgLineWidth = line_width * fgLineWidthScale * fgPointLineScalingFactor;
1924  glLineWidth(fgLineWidth);
1925 }
1926 
1927 ////////////////////////////////////////////////////////////////////////////////
1928 /// Get the point-size, taking the global scaling into account.
1929 
1930 Float_t TGLUtil::PointSize()
1931 {
1932  return fgPointSize;
1933 }
1934 
1935 ////////////////////////////////////////////////////////////////////////////////
1936 /// Get the line-width, taking the global scaling into account.
1937 
1938 Float_t TGLUtil::LineWidth()
1939 {
1940  return fgLineWidth;
1941 }
1942 
1943 /******************************************************************************/
1944 // Rendering of polymarkers and lines from logical-shapes.
1945 /******************************************************************************/
1946 
1947 void TGLUtil::BeginExtendPickRegion(Float_t scale)
1948 {
1949  // Extend pick region for large point-sizes or line-widths.
1950 
1951  glMatrixMode(GL_PROJECTION);
1952  glPushMatrix();
1953  Float_t pm[16];
1954  glGetFloatv(GL_PROJECTION_MATRIX, pm);
1955  for (Int_t i=0; i<=12; i+=4) {
1956  pm[i] *= scale; pm[i+1] *= scale;
1957  }
1958  glLoadMatrixf(pm);
1959  glMatrixMode(GL_MODELVIEW);
1960 }
1961 
1962 void TGLUtil::EndExtendPickRegion()
1963 {
1964  // End extension of the pick region.
1965 
1966  glMatrixMode(GL_PROJECTION);
1967  glPopMatrix();
1968  glMatrixMode(GL_MODELVIEW);
1969 }
1970 
1971 ////////////////////////////////////////////////////////////////////////////////
1972 /// Render polymarkers at points specified by p-array.
1973 /// Supports point and cross-like styles.
1974 
1975 void TGLUtil::RenderPolyMarkers(const TAttMarker& marker, Char_t transp,
1976  Float_t* p, Int_t n,
1977  Int_t pick_radius, Bool_t selection,
1978  Bool_t sec_selection)
1979 {
1980  if (n == 0) return;
1981 
1982  glPushAttrib(GL_ENABLE_BIT | GL_POINT_BIT | GL_LINE_BIT);
1983 
1984  glDisable(GL_LIGHTING);
1985  TGLUtil::ColorTransparency(marker.GetMarkerColor(), transp);
1986 
1987  Int_t s = marker.GetMarkerStyle();
1988  if (s == 2 || s == 3 || s == 5 || s == 28)
1989  RenderCrosses(marker, p, n, sec_selection);
1990  else
1991  RenderPoints(marker, p, n, pick_radius, selection, sec_selection);
1992 
1993  glPopAttrib();
1994 }
1995 
1996 ////////////////////////////////////////////////////////////////////////////////
1997 /// Render polymarkers at points specified by p-array.
1998 /// Supports point and cross-like styles.
1999 /// Color is set externally. Lighting is disabled externally.
2000 
2001 void TGLUtil::RenderPolyMarkers(const TAttMarker &marker, const std::vector<Double_t> &points,
2002  Double_t dX, Double_t dY, Double_t dZ)
2003 {
2004  const Int_t s = marker.GetMarkerStyle();
2005  if (s == 2 || s == 3 || s == 5 || s == 28)
2006  RenderCrosses(marker, points, dX, dY, dZ);
2007  else
2008  RenderPoints(marker, points);
2009 }
2010 
2011 ////////////////////////////////////////////////////////////////////////////////
2012 /// Render markers as circular or square points.
2013 /// Color is never changed.
2014 
2015 void TGLUtil::RenderPoints(const TAttMarker& marker,
2016  Float_t* op, Int_t n,
2017  Int_t pick_radius, Bool_t selection,
2018  Bool_t sec_selection)
2019 {
2020  Int_t style = marker.GetMarkerStyle();
2021  Float_t size = 5*marker.GetMarkerSize();
2022  if (style == 4 || style == 20 || style == 24)
2023  {
2024  glEnable(GL_POINT_SMOOTH);
2025  if (style == 4 || style == 24) {
2026  glEnable(GL_BLEND);
2027  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2028  glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
2029  }
2030  }
2031  else
2032  {
2033  glDisable(GL_POINT_SMOOTH);
2034  if (style == 1) size = 1;
2035  else if (style == 6) size = 2;
2036  else if (style == 7) size = 3;
2037  }
2038  TGLUtil::PointSize(size);
2039 
2040  // During selection extend picking region for large point-sizes.
2041  Bool_t changePM = selection && PointSize() > pick_radius;
2042  if (changePM)
2043  BeginExtendPickRegion((Float_t) pick_radius / PointSize());
2044 
2045  Float_t* p = op;
2046  if (sec_selection)
2047  {
2048  glPushName(0);
2049  for (Int_t i=0; i<n; ++i, p+=3)
2050  {
2051  glLoadName(i);
2052  glBegin(GL_POINTS);
2053  glVertex3fv(p);
2054  glEnd();
2055  }
2056  glPopName();
2057  }
2058  else
2059  {
2060  glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
2061  glVertexPointer(3, GL_FLOAT, 0, p);
2062  glEnableClientState(GL_VERTEX_ARRAY);
2063  { // Circumvent bug in ATI's linux drivers.
2064  Int_t nleft = n;
2065  Int_t ndone = 0;
2066  const Int_t maxChunk = 8192;
2067  while (nleft > maxChunk)
2068  {
2069  glDrawArrays(GL_POINTS, ndone, maxChunk);
2070  nleft -= maxChunk;
2071  ndone += maxChunk;
2072  }
2073  glDrawArrays(GL_POINTS, ndone, nleft);
2074  }
2075  glPopClientAttrib();
2076  }
2077 
2078  if (changePM)
2079  EndExtendPickRegion();
2080 }
2081 
2082 ////////////////////////////////////////////////////////////////////////////////
2083 /// Render markers as circular or square points.
2084 /// Color is never changed.
2085 
2086 void TGLUtil::RenderPoints(const TAttMarker& marker, const std::vector<Double_t> &points)
2087 {
2088  const Int_t style = marker.GetMarkerStyle();
2089  Float_t size = 5 * marker.GetMarkerSize();
2090 
2091  if (style == 4 || style == 20 || style == 24)
2092  {
2093  glEnable(GL_POINT_SMOOTH);
2094  if (style == 4 || style == 24) {
2095  glEnable(GL_BLEND);
2096  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2097  glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
2098  }
2099  }
2100  else
2101  {
2102  glDisable(GL_POINT_SMOOTH);
2103  if (style == 1) size = 1;
2104  else if (style == 6) size = 2;
2105  else if (style == 7) size = 3;
2106  }
2107 
2108  glPointSize(size);
2109 
2110  glVertexPointer(3, GL_DOUBLE, 0, &points[0]);
2111  glEnableClientState(GL_VERTEX_ARRAY);
2112 
2113  // Circumvent bug in ATI's linux drivers.
2114  Int_t nleft = points.size() / 3;
2115  Int_t ndone = 0;
2116  const Int_t maxChunk = 8192;
2117  while (nleft > maxChunk)
2118  {
2119  glDrawArrays(GL_POINTS, ndone, maxChunk);
2120  nleft -= maxChunk;
2121  ndone += maxChunk;
2122  }
2123 
2124  if (nleft > 0)
2125  glDrawArrays(GL_POINTS, ndone, nleft);
2126 
2127  glDisableClientState(GL_VERTEX_ARRAY);
2128  glPointSize(1.f);
2129 }
2130 
2131 ////////////////////////////////////////////////////////////////////////////////
2132 /// Render markers as crosses.
2133 /// Color is never changed.
2134 
2135 void TGLUtil::RenderCrosses(const TAttMarker& marker,
2136  Float_t* op, Int_t n,
2137  Bool_t sec_selection)
2138 {
2139  if (marker.GetMarkerStyle() == 28)
2140  {
2141  glEnable(GL_BLEND);
2142  glEnable(GL_LINE_SMOOTH);
2143  TGLUtil::LineWidth(2);
2144  }
2145  else
2146  {
2147  glDisable(GL_LINE_SMOOTH);
2148  TGLUtil::LineWidth(1);
2149  }
2150 
2151  // cross dim
2152  const Float_t d = 2*marker.GetMarkerSize();
2153  Float_t* p = op;
2154  if (sec_selection)
2155  {
2156  glPushName(0);
2157  for (Int_t i=0; i<n; ++i, p+=3)
2158  {
2159  glLoadName(i);
2160  glBegin(GL_LINES);
2161  glVertex3f(p[0]-d, p[1], p[2]); glVertex3f(p[0]+d, p[1], p[2]);
2162  glVertex3f(p[0], p[1]-d, p[2]); glVertex3f(p[0], p[1]+d, p[2]);
2163  glVertex3f(p[0], p[1], p[2]-d); glVertex3f(p[0], p[1], p[2]+d);
2164  glEnd();
2165  }
2166  glPopName();
2167  }
2168  else
2169  {
2170  glBegin(GL_LINES);
2171  for (Int_t i=0; i<n; ++i, p+=3)
2172  {
2173  glVertex3f(p[0]-d, p[1], p[2]); glVertex3f(p[0]+d, p[1], p[2]);
2174  glVertex3f(p[0], p[1]-d, p[2]); glVertex3f(p[0], p[1]+d, p[2]);
2175  glVertex3f(p[0], p[1], p[2]-d); glVertex3f(p[0], p[1], p[2]+d);
2176  }
2177  glEnd();
2178  }
2179 
2180  // Anti-flickering -- when crosses get too small they
2181  // appear / disappear randomly.
2182  {
2183  glDisable(GL_POINT_SMOOTH);
2184  TGLUtil::PointSize(1);
2185 
2186  glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
2187  glVertexPointer(3, GL_FLOAT, 0, op);
2188  glEnableClientState(GL_VERTEX_ARRAY);
2189  { // Circumvent bug in ATI's linux drivers.
2190  Int_t nleft = n;
2191  Int_t ndone = 0;
2192  const Int_t maxChunk = 8192;
2193  while (nleft > maxChunk)
2194  {
2195  glDrawArrays(GL_POINTS, ndone, maxChunk);
2196  nleft -= maxChunk;
2197  ndone += maxChunk;
2198  }
2199  glDrawArrays(GL_POINTS, ndone, nleft);
2200  }
2201  glPopClientAttrib();
2202  }
2203 }
2204 
2205 ////////////////////////////////////////////////////////////////////////////////
2206 /// Render markers as crosses.
2207 /// Color is never changed.
2208 
2209 void TGLUtil::RenderCrosses(const TAttMarker& marker, const std::vector<Double_t> &points,
2210  Double_t dX, Double_t dY, Double_t dZ)
2211 {
2212  if (marker.GetMarkerStyle() == 28)
2213  {
2214  glEnable(GL_BLEND);
2215  glEnable(GL_LINE_SMOOTH);
2216  glLineWidth(2.f);
2217  }
2218  else
2219  {
2220  glDisable(GL_LINE_SMOOTH);
2221  glLineWidth(1.f);
2222  }
2223 
2224  typedef std::vector<Double_t>::size_type size_type;
2225 
2226  glBegin(GL_LINES);
2227 
2228  for (size_type i = 0; i < points.size(); i += 3) {
2229  const Double_t *p = &points[i];
2230  glVertex3f(p[0] - dX, p[1], p[2]); glVertex3f(p[0] + dX, p[1], p[2]);
2231  glVertex3f(p[0], p[1] - dY, p[2]); glVertex3f(p[0], p[1] + dY, p[2]);
2232  glVertex3f(p[0], p[1], p[2] - dZ); glVertex3f(p[0], p[1], p[2] + dZ);
2233  }
2234 
2235  glEnd();
2236 
2237  if (marker.GetMarkerStyle() == 28) {
2238  glDisable(GL_LINE_SMOOTH);
2239  glDisable(GL_BLEND);
2240  glLineWidth(1.f);
2241  }
2242 }
2243 
2244 ////////////////////////////////////////////////////////////////////////////////
2245 /// Render poly-line as specified by the p-array.
2246 
2247 void TGLUtil::RenderPolyLine(const TAttLine& aline, Char_t transp,
2248  Float_t* p, Int_t n,
2249  Int_t pick_radius, Bool_t selection)
2250 {
2251  if (n == 0) return;
2252 
2253  BeginAttLine(aline, transp, pick_radius, selection);
2254 
2255  Float_t* tp = p;
2256  glBegin(GL_LINE_STRIP);
2257  for (Int_t i=0; i<n; ++i, tp+=3)
2258  glVertex3fv(tp);
2259  glEnd();
2260 
2261  EndAttLine(pick_radius, selection);
2262 }
2263 
2264 ////////////////////////////////////////////////////////////////////////////////
2265 /// Setup drawing parameters according to passed TAttLine.
2266 
2267 void TGLUtil::BeginAttLine(const TAttLine& aline, Char_t transp,
2268  Int_t pick_radius, Bool_t selection)
2269 {
2270  glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
2271 
2272  glDisable(GL_LIGHTING);
2273  TGLUtil::ColorTransparency(aline.GetLineColor(), transp);
2274  TGLUtil::LineWidth(aline.GetLineWidth());
2275  if (aline.GetLineStyle() > 1)
2276  {
2277  // Int_t fac = 1;
2278  UShort_t pat = 0xffff;
2279  switch (aline.GetLineStyle()) {
2280  case 2: pat = 0x3333; break;
2281  case 3: pat = 0x5555; break;
2282  case 4: pat = 0xf040; break;
2283  case 5: pat = 0xf4f4; break;
2284  case 6: pat = 0xf111; break;
2285  case 7: pat = 0xf0f0; break;
2286  case 8: pat = 0xff11; break;
2287  case 9: pat = 0x3fff; break;
2288  case 10: pat = 0x08ff; /* fac = 2; */ break;
2289  }
2290 
2291  glLineStipple(1, pat);
2292  glEnable(GL_LINE_STIPPLE);
2293  }
2294 
2295  // During selection extend picking region for large line-widths.
2296  if (selection && TGLUtil::LineWidth() > pick_radius)
2297  BeginExtendPickRegion((Float_t) pick_radius / TGLUtil::LineWidth());
2298 }
2299 
2300 ////////////////////////////////////////////////////////////////////////////////
2301 /// Restore previous line drawing state.
2302 
2303 void TGLUtil::EndAttLine(Int_t pick_radius, Bool_t selection)
2304 {
2305  if (selection && TGLUtil::LineWidth() > pick_radius)
2306  EndExtendPickRegion();
2307 
2308  glPopAttrib();
2309 }
2310 
2311 /******************************************************************************/
2312 // Rendering atoms used by TGLViewer / TGScene.
2313 /******************************************************************************/
2314 
2315 ////////////////////////////////////////////////////////////////////////////////
2316 /// Set basic draw colors from 4 component 'rgba'
2317 /// Used by other TGLUtil drawing routines
2318 ///
2319 /// Sets basic (unlit) color - glColor
2320 /// and also GL materials (see OpenGL docs) thus:
2321 ///
2322 /// diffuse : rgba
2323 /// ambient : 0.0 0.0 0.0 1.0
2324 /// specular : 0.6 0.6 0.6 1.0
2325 /// emission : rgba/4.0
2326 /// shininess: 60.0
2327 ///
2328 /// emission is set so objects with no lights (but lighting still enabled)
2329 /// are partially visible
2330 
2331 void TGLUtil::SetDrawColors(const UChar_t rgbai[4])
2332 {
2333 
2334  // Util function to setup GL color for both unlit and lit material
2335  Float_t rgba[4] = {rgbai[0]/255.f, rgbai[1]/255.f, rgbai[2]/255.f, rgbai[3]/255.f};
2336  Float_t ambient[4] = {0.0, 0.0, 0.0, 1.0};
2337  Float_t specular[4] = {0.6, 0.6, 0.6, 1.0};
2338  Float_t emission[4] = {rgba[0]/4.f, rgba[1]/4.f, rgba[2]/4.f, rgba[3]};
2339 
2340  glColor4fv(rgba);
2341  glMaterialfv(GL_FRONT, GL_DIFFUSE, rgba);
2342  glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
2343  glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
2344  glMaterialfv(GL_FRONT, GL_EMISSION, emission);
2345  glMaterialf(GL_FRONT, GL_SHININESS, 60.0);
2346 }
2347 
2348 ////////////////////////////////////////////////////////////////////////////////
2349 /// Draw sphere, centered on vertex 'position', with radius 'radius',
2350 /// color 'rgba'
2351 
2352 void TGLUtil::DrawSphere(const TGLVertex3 & position, Double_t radius,
2353  const UChar_t rgba[4])
2354 {
2355  static TGLQuadric quad;
2356  SetDrawColors(rgba);
2357  glPushMatrix();
2358  glTranslated(position.X(), position.Y(), position.Z());
2359  gluSphere(quad.Get(), radius, fgDrawQuality, fgDrawQuality);
2360  glPopMatrix();
2361 }
2362 
2363 ////////////////////////////////////////////////////////////////////////////////
2364 /// Draw thick line (tube) defined by 'line', with head at end shape
2365 /// 'head' - box/arrow/none, (head) size 'size', color 'rgba'
2366 
2367 void TGLUtil::DrawLine(const TGLLine3 & line, ELineHeadShape head, Double_t size,
2368  const UChar_t rgba[4])
2369 {
2370  DrawLine(line.Start(), line.Vector(), head, size, rgba);
2371 }
2372 
2373 ////////////////////////////////////////////////////////////////////////////////
2374 /// Draw thick line (tube) running from 'start', length 'vector',
2375 /// with head at end of shape 'head' - box/arrow/none,
2376 /// (head) size 'size', color 'rgba'
2377 
2378 void TGLUtil::DrawLine(const TGLVertex3 & start, const TGLVector3 & vector,
2379  ELineHeadShape head, Double_t size, const UChar_t rgba[4])
2380 {
2381  static TGLQuadric quad;
2382 
2383  // Draw 3D line (tube) with optional head shape
2384  SetDrawColors(rgba);
2385  glPushMatrix();
2386  TGLMatrix local(start, vector);
2387  glMultMatrixd(local.CArr());
2388 
2389  Double_t headHeight=0;
2390  if (head == kLineHeadNone) {
2391  headHeight = 0.0;
2392  } else if (head == kLineHeadArrow) {
2393  headHeight = size*2.0;
2394  } else if (head == kLineHeadBox) {
2395  headHeight = size*1.4;
2396  }
2397 
2398  // Line (tube) component
2399  gluCylinder(quad.Get(), 0.25*size, 0.25*size, vector.Mag() - headHeight, fgDrawQuality, 1);
2400  gluQuadricOrientation(quad.Get(), (GLenum)GLU_INSIDE);
2401  gluDisk(quad.Get(), 0.0, 0.25*size, fgDrawQuality, 1);
2402 
2403  glTranslated(0.0, 0.0, vector.Mag() - headHeight); // Shift down local Z to end of line
2404 
2405  if (head == kLineHeadNone) {
2406  // Cap end of line
2407  gluQuadricOrientation(quad.Get(), (GLenum)GLU_OUTSIDE);
2408  gluDisk(quad.Get(), 0.0, size/4.0, fgDrawQuality, 1);
2409  }
2410  else if (head == kLineHeadArrow) {
2411  // Arrow base / end line cap
2412  gluDisk(quad.Get(), 0.0, size, fgDrawQuality, 1);
2413  // Arrow cone
2414  gluQuadricOrientation(quad.Get(), (GLenum)GLU_OUTSIDE);
2415  gluCylinder(quad.Get(), size, 0.0, headHeight, fgDrawQuality, 1);
2416  } else if (head == kLineHeadBox) {
2417  // Box
2418  // TODO: Drawing box should be simpler - maybe make
2419  // a static helper which BB + others use.
2420  // Single face tesselation - ugly lighting
2421  gluQuadricOrientation(quad.Get(), (GLenum)GLU_OUTSIDE);
2422  TGLBoundingBox box(TGLVertex3(-size*.7, -size*.7, 0.0),
2423  TGLVertex3(size*.7, size*.7, headHeight));
2424  box.Draw(kTRUE);
2425  }
2426  glPopMatrix();
2427 }
2428 
2429 ////////////////////////////////////////////////////////////////////////////////
2430 /// Draw ring, centered on 'center', lying on plane defined by 'center' & 'normal'
2431 /// of outer radius 'radius', color 'rgba'
2432 
2433 void TGLUtil::DrawRing(const TGLVertex3 & center, const TGLVector3 & normal,
2434  Double_t radius, const UChar_t rgba[4])
2435 {
2436  static TGLQuadric quad;
2437 
2438  // Draw a ring, round vertex 'center', lying on plane defined by 'normal' vector
2439  // Radius defines the outer radius
2440  TGLUtil::SetDrawColors(rgba);
2441 
2442  Double_t outer = radius;
2443  Double_t width = radius*0.05;
2444  Double_t inner = outer - width;
2445 
2446  // Shift into local system, looking down 'normal' vector, origin at center
2447  glPushMatrix();
2448  TGLMatrix local(center, normal);
2449  glMultMatrixd(local.CArr());
2450 
2451  // Shift half width so rings centered over center vertex
2452  glTranslated(0.0, 0.0, -width/2.0);
2453 
2454  // Inner and outer faces
2455  gluCylinder(quad.Get(), inner, inner, width, fgDrawQuality, 1);
2456  gluCylinder(quad.Get(), outer, outer, width, fgDrawQuality, 1);
2457 
2458  // Top/bottom
2459  gluQuadricOrientation(quad.Get(), (GLenum)GLU_INSIDE);
2460  gluDisk(quad.Get(), inner, outer, fgDrawQuality, 1);
2461  glTranslated(0.0, 0.0, width);
2462  gluQuadricOrientation(quad.Get(), (GLenum)GLU_OUTSIDE);
2463  gluDisk(quad.Get(), inner, outer, fgDrawQuality, 1);
2464 
2465  glPopMatrix();
2466 }
2467 
2468 /**************************************************************************/
2469 
2470 ////////////////////////////////////////////////////////////////////////////////
2471 /// Draw a sphere- marker on world-coordinate 'pos' with pixel
2472 /// radius 'radius'. Color argument is optional.
2473 
2474 void TGLUtil::DrawReferenceMarker(const TGLCamera & camera,
2475  const TGLVertex3 & pos,
2476  Float_t radius,
2477  const UChar_t * rgba)
2478 {
2479  static const UChar_t defColor[4] = { 250, 110, 0, 255 }; // Orange
2480 
2481  radius = camera.ViewportDeltaToWorld(pos, radius, radius).Mag();
2482  DrawSphere(pos, radius, rgba ? rgba : defColor);
2483 
2484 }
2485 
2486 ////////////////////////////////////////////////////////////////////////////////
2487 /// Draw simple xyz-axes for given bounding-box.
2488 
2489 void TGLUtil::DrawSimpleAxes(const TGLCamera & camera,
2490  const TGLBoundingBox & bbox,
2491  Int_t axesType)
2492 {
2493  if (axesType == kAxesNone)
2494  return;
2495 
2496  static const UChar_t axesColors[][4] = {
2497  {128, 0, 0, 255}, // -ive X axis light red
2498  {255, 0, 0, 255}, // +ive X axis deep red
2499  { 0, 128, 0, 255}, // -ive Y axis light green
2500  { 0, 255, 0, 255}, // +ive Y axis deep green
2501  { 0, 0, 128, 255}, // -ive Z axis light blue
2502  { 0, 0, 255, 255} // +ive Z axis deep blue
2503  };
2504 
2505  static const UChar_t xyz[][8] = {
2506  {0x44, 0x44, 0x28, 0x10, 0x10, 0x28, 0x44, 0x44},
2507  {0x10, 0x10, 0x10, 0x10, 0x10, 0x28, 0x44, 0x44},
2508  {0x7c, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x7c}
2509  };
2510 
2511  // Axes draw at fixed screen size - back project to world
2512  TGLVector3 pixelVector = camera.ViewportDeltaToWorld(bbox.Center(), 1, 1);
2513  Double_t pixelSize = pixelVector.Mag();
2514 
2515  // Find x/y/z min/max values
2516  Double_t min[3] = { bbox.XMin(), bbox.YMin(), bbox.ZMin() };
2517  Double_t max[3] = { bbox.XMax(), bbox.YMax(), bbox.ZMax() };
2518 
2519  for (UInt_t i = 0; i < 3; i++) {
2520  TGLVertex3 start;
2521  TGLVector3 vector;
2522 
2523  if (axesType == kAxesOrigin) {
2524  // Through origin axes
2525  start[(i+1)%3] = 0.0;
2526  start[(i+2)%3] = 0.0;
2527  } else {
2528  // Side axes
2529  start[(i+1)%3] = min[(i+1)%3];
2530  start[(i+2)%3] = min[(i+2)%3];
2531  }
2532  vector[(i+1)%3] = 0.0;
2533  vector[(i+2)%3] = 0.0;
2534 
2535  // -ive axis?
2536  if (min[i] < 0.0) {
2537  // Runs from origin?
2538  if (max[i] > 0.0) {
2539  start[i] = 0.0;
2540  vector[i] = min[i];
2541  } else {
2542  start[i] = max[i];
2543  vector[i] = min[i] - max[i];
2544  }
2545  DrawLine(start, vector, kLineHeadNone, pixelSize*2.5, axesColors[i*2]);
2546  }
2547  // +ive axis?
2548  if (max[i] > 0.0) {
2549  // Runs from origin?
2550  if (min[i] < 0.0) {
2551  start[i] = 0.0;
2552  vector[i] = max[i];
2553  } else {
2554  start[i] = min[i];
2555  vector[i] = max[i] - min[i];
2556  }
2557  DrawLine(start, vector, kLineHeadNone, pixelSize*2.5, axesColors[i*2 + 1]);
2558  }
2559  }
2560 
2561  // Draw origin sphere(s)
2562  if (axesType == kAxesOrigin) {
2563  // Single white origin sphere at 0, 0, 0
2564  DrawSphere(TGLVertex3(0.0, 0.0, 0.0), pixelSize*2.0, fgWhite);
2565  } else {
2566  for (UInt_t j = 0; j < 3; j++) {
2567  if (min[j] <= 0.0 && max[j] >= 0.0) {
2568  TGLVertex3 zero;
2569  zero[j] = 0.0;
2570  zero[(j+1)%3] = min[(j+1)%3];
2571  zero[(j+2)%3] = min[(j+2)%3];
2572  DrawSphere(zero, pixelSize*2.0, axesColors[j*2 + 1]);
2573  }
2574  }
2575  }
2576 
2577  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2578 
2579  // Labels
2580  Double_t padPixels = 25.0;
2581 
2582  glDisable(GL_LIGHTING);
2583  for (UInt_t k = 0; k < 3; k++) {
2584  SetDrawColors(axesColors[k*2+1]);
2585  TGLVertex3 minPos, maxPos;
2586  if (axesType == kAxesOrigin) {
2587  minPos[(k+1)%3] = 0.0;
2588  minPos[(k+2)%3] = 0.0;
2589  } else {
2590  minPos[(k+1)%3] = min[(k+1)%3];
2591  minPos[(k+2)%3] = min[(k+2)%3];
2592  }
2593  maxPos = minPos;
2594  minPos[k] = min[k];
2595  maxPos[k] = max[k];
2596 
2597  TGLVector3 axis = maxPos - minPos;
2598  TGLVector3 axisViewport = camera.WorldDeltaToViewport(minPos, axis);
2599 
2600  // Skip drawing if viewport projection of axis very small - labels will overlap
2601  // Occurs with orthographic cameras
2602  if (axisViewport.Mag() < 1) {
2603  continue;
2604  }
2605 
2606  minPos -= camera.ViewportDeltaToWorld(minPos, padPixels*axisViewport.X()/axisViewport.Mag(),
2607  padPixels*axisViewport.Y()/axisViewport.Mag());
2608  axisViewport = camera.WorldDeltaToViewport(maxPos, -axis);
2609  maxPos -= camera.ViewportDeltaToWorld(maxPos, padPixels*axisViewport.X()/axisViewport.Mag(),
2610  padPixels*axisViewport.Y()/axisViewport.Mag());
2611 
2612  DrawNumber(Form("%.0f", min[k]), minPos, kTRUE); // Min value
2613  DrawNumber(Form("%.0f", max[k]), maxPos, kTRUE); // Max value
2614 
2615  // Axis name beside max value
2616  TGLVertex3 namePos = maxPos -
2617  camera.ViewportDeltaToWorld(maxPos, padPixels*axisViewport.X()/axisViewport.Mag(),
2618  padPixels*axisViewport.Y()/axisViewport.Mag());
2619  glRasterPos3dv(namePos.CArr());
2620  glBitmap(8, 8, 0.0, 4.0, 0.0, 0.0, xyz[k]); // Axis Name
2621  }
2622 }
2623 
2624 ////////////////////////////////////////////////////////////////////////////////
2625 /// Draw number in string 'num' via internal 8x8-pixel bitmap on
2626 /// vertex 'pos'. If 'center' is true, the number is centered on 'pos'.
2627 /// Only numbers, '.', '-' and ' ' are supported.
2628 
2629 void TGLUtil::DrawNumber(const TString & num,
2630  const TGLVertex3 & pos,
2631  Bool_t center)
2632 {
2633  static const UChar_t digits[][8] = {
2634  {0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38},//0
2635  {0x10, 0x10, 0x10, 0x10, 0x10, 0x70, 0x10, 0x10},//1
2636  {0x7c, 0x44, 0x20, 0x18, 0x04, 0x04, 0x44, 0x38},//2
2637  {0x38, 0x44, 0x04, 0x04, 0x18, 0x04, 0x44, 0x38},//3
2638  {0x04, 0x04, 0x04, 0x04, 0x7c, 0x44, 0x44, 0x44},//4
2639  {0x7c, 0x44, 0x04, 0x04, 0x7c, 0x40, 0x40, 0x7c},//5
2640  {0x7c, 0x44, 0x44, 0x44, 0x7c, 0x40, 0x40, 0x7c},//6
2641  {0x20, 0x20, 0x20, 0x10, 0x08, 0x04, 0x44, 0x7c},//7
2642  {0x38, 0x44, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38},//8
2643  {0x7c, 0x44, 0x04, 0x04, 0x7c, 0x44, 0x44, 0x7c},//9
2644  {0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},//.
2645  {0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00},//-
2646  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} //space
2647  };
2648 
2649  Double_t xOffset = 0, yOffset = 0;
2650  if (center)
2651  {
2652  xOffset = 3.5 * num.Length();
2653  yOffset = 4.0;
2654  }
2655 
2656  glRasterPos3dv(pos.CArr());
2657  for (Ssiz_t i = 0, e = num.Length(); i < e; ++i) {
2658  if (num[i] == '.') {
2659  glBitmap(8, 8, xOffset, yOffset, 7.0, 0.0, digits[10]);
2660  } else if (num[i] == '-') {
2661  glBitmap(8, 8, xOffset, yOffset, 7.0, 0.0, digits[11]);
2662  } else if (num[i] == ' ') {
2663  glBitmap(8, 8, xOffset, yOffset, 7.0, 0.0, digits[12]);
2664  } else if (num[i] >= '0' && num[i] <= '9') {
2665  glBitmap(8, 8, xOffset, yOffset, 7.0, 0.0, digits[num[i] - '0']);
2666  }
2667  }
2668 }
2669 
2670 
2671 /**************************************************************************/
2672 /**************************************************************************/
2673 
2674 ////////////////////////////////////////////////////////////////////////////////
2675 /// Constructor - change state only if necessary.
2676 
2677 TGLCapabilitySwitch::TGLCapabilitySwitch(Int_t what, Bool_t state) :
2678  fWhat(what)
2679 {
2680  fState = glIsEnabled(fWhat);
2681  fFlip = (fState != state);
2682  if (fFlip)
2683  SetState(state);
2684 }
2685 
2686 ////////////////////////////////////////////////////////////////////////////////
2687 /// Destructor - reset state if changed.
2688 
2689 TGLCapabilitySwitch::~TGLCapabilitySwitch()
2690 {
2691  if (fFlip)
2692  SetState(fState);
2693 }
2694 
2695 ////////////////////////////////////////////////////////////////////////////////
2696 
2697 void TGLCapabilitySwitch::SetState(Bool_t s)
2698 {
2699  if (s)
2700  glEnable(fWhat);
2701  else
2702  glDisable(fWhat);
2703 }
2704 
2705 
2706 ////////////////////////////////////////////////////////////////////////////////
2707 /// Constructor - change state only if necessary.
2708 
2709 TGLCapabilityEnabler::TGLCapabilityEnabler(Int_t what, Bool_t state) :
2710  fWhat(what)
2711 {
2712  fFlip = ! glIsEnabled(fWhat) && state;
2713  if (fFlip)
2714  glEnable(fWhat);
2715 }
2716 
2717 ////////////////////////////////////////////////////////////////////////////////
2718 /// Destructor - reset state if changed.
2719 
2720 TGLCapabilityEnabler::~TGLCapabilityEnabler()
2721 {
2722  if (fFlip)
2723  glDisable(fWhat);
2724 }
2725 
2726 
2727 ////////////////////////////////////////////////////////////////////////////////
2728 
2729 TGLFloatHolder::TGLFloatHolder(Int_t what, Float_t state, void (*foo)(Float_t)) :
2730  fWhat(what), fState(0), fFlip(kFALSE), fFoo(foo)
2731  {
2732  glGetFloatv(fWhat, &fState);
2733  fFlip = (fState != state);
2734  if (fFlip) fFoo(state);
2735  }
2736 
2737 ////////////////////////////////////////////////////////////////////////////////
2738 
2739 TGLFloatHolder::~TGLFloatHolder()
2740  {
2741  if (fFlip) fFoo(fState);
2742  }
2743 
2744 
2745 ////////////////////////////////////////////////////////////////////////////////
2746 /// TGLEnableGuard constructor.
2747 
2748 TGLEnableGuard::TGLEnableGuard(Int_t cap)
2749  : fCap(cap)
2750 {
2751  glEnable(GLenum(fCap));
2752 }
2753 
2754 ////////////////////////////////////////////////////////////////////////////////
2755 /// TGLEnableGuard destructor.
2756 
2757 TGLEnableGuard::~TGLEnableGuard()
2758 {
2759  glDisable(GLenum(fCap));
2760 }
2761 
2762 ////////////////////////////////////////////////////////////////////////////////
2763 /// TGLDisableGuard constructor.
2764 
2765 TGLDisableGuard::TGLDisableGuard(Int_t cap)
2766  : fCap(cap)
2767 {
2768  glDisable(GLenum(fCap));
2769 }
2770 
2771 ////////////////////////////////////////////////////////////////////////////////
2772 /// TGLDisableGuard destructor.
2773 
2774 TGLDisableGuard::~TGLDisableGuard()
2775 {
2776  glEnable(GLenum(fCap));
2777 }
2778 
2779 /** \class TGLSelectionBuffer
2780 \ingroup opengl
2781 */
2782 
2783 ClassImp(TGLSelectionBuffer);
2784 
2785 ////////////////////////////////////////////////////////////////////////////////
2786 /// TGLSelectionBuffer constructor.
2787 
2788 TGLSelectionBuffer::TGLSelectionBuffer()
2789  : fWidth(0), fHeight(0)
2790 {
2791 }
2792 
2793 ////////////////////////////////////////////////////////////////////////////////
2794 /// TGLSelectionBuffer destructor.
2795 
2796 TGLSelectionBuffer::~TGLSelectionBuffer()
2797 {
2798 }
2799 
2800 ////////////////////////////////////////////////////////////////////////////////
2801 /// Read color buffer.
2802 
2803 void TGLSelectionBuffer::ReadColorBuffer(Int_t w, Int_t h)
2804 {
2805  fWidth = w;
2806  fHeight = h;
2807  fBuffer.resize(w * h * 4);
2808  glPixelStorei(GL_PACK_ALIGNMENT, 1);
2809  glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, &fBuffer[0]);
2810 }
2811 
2812 ////////////////////////////////////////////////////////////////////////////////
2813 /// Read color buffer.
2814 
2815 void TGLSelectionBuffer::ReadColorBuffer(Int_t x, Int_t y, Int_t w, Int_t h)
2816 {
2817  fWidth = w;
2818  fHeight = h;
2819  fBuffer.resize(w * h * 4);
2820  glPixelStorei(GL_PACK_ALIGNMENT, 1);
2821  glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, &fBuffer[0]);
2822 }
2823 
2824 ////////////////////////////////////////////////////////////////////////////////
2825 /// Get pixel color.
2826 
2827 const UChar_t *TGLSelectionBuffer::GetPixelColor(Int_t px, Int_t py)const
2828 {
2829  if (px < 0)
2830  px = 0;
2831  if (py < 0)
2832  py = 0;
2833 
2834  if (UInt_t(px * fWidth * 4 + py * 4) > fBuffer.size())
2835  return &fBuffer[0];
2836 
2837  return &fBuffer[px * fWidth * 4 + py * 4];
2838 }
2839 
2840 namespace Rgl {
2841 
2842 const Float_t gRedEmission[] = {1.f, 0.f, 0.f, 1.f};
2843 const Float_t gGreenEmission[] = {0.f, 1.f, 0.f, 1.f};
2844 const Float_t gBlueEmission[] = {0.f, 0.f, 1.f, 1.f};
2845 const Float_t gOrangeEmission[] = {1.f, 0.4f, 0.f, 1.f};
2846 const Float_t gWhiteEmission[] = {1.f, 1.f, 1.f, 1.f};
2847 const Float_t gGrayEmission[] = {0.3f,0.3f, 0.3f,1.f};
2848 const Float_t gNullEmission[] = {0.f, 0.f, 0.f, 1.f};
2849 
2850 namespace {
2851  struct RGB_t {
2852  Int_t fRGB[3];
2853  };
2854 
2855  RGB_t gColorTriplets[] = {{{255, 0, 0}},
2856  {{0, 255, 0}},
2857  {{0, 0, 255}},
2858  {{255, 255, 0}},
2859  {{255, 0, 255}},
2860  {{0, 255, 255}},
2861  {{255, 255, 255}}};
2862 
2863  Bool_t operator < (const RGB_t &lhs, const RGB_t &rhs)
2864  {
2865  if (lhs.fRGB[0] < rhs.fRGB[0])
2866  return kTRUE;
2867  else if (lhs.fRGB[0] > rhs.fRGB[0])
2868  return kFALSE;
2869  else if (lhs.fRGB[1] < rhs.fRGB[1])
2870  return kTRUE;
2871  else if (lhs.fRGB[1] > rhs.fRGB[1])
2872  return kFALSE;
2873  else if (lhs.fRGB[2] < rhs.fRGB[2])
2874  return kTRUE;
2875 
2876  return kFALSE;
2877  }
2878 
2879  typedef std::map<Int_t, RGB_t> ColorLookupTable_t;
2880  typedef ColorLookupTable_t::const_iterator CLTCI_t;
2881 
2882  ColorLookupTable_t gObjectIDToColor;
2883 
2884  typedef std::map<RGB_t, Int_t> ObjectLookupTable_t;
2885  typedef ObjectLookupTable_t::const_iterator OLTCI_t;
2886 
2887  ObjectLookupTable_t gColorToObjectID;
2888 }
2889 ////////////////////////////////////////////////////////////////////////////////
2890 ///Object id encoded as rgb triplet.
2891 
2892 void ObjectIDToColor(Int_t objectID, Bool_t highColor)
2893 {
2894  if (!highColor)
2895  glColor3ub(objectID & 0xff, (objectID & 0xff00) >> 8, (objectID & 0xff0000) >> 16);
2896  else {
2897  if (!gObjectIDToColor.size()) {
2898  //Initialize lookup tables.
2899  for (Int_t i = 0, id = 1; i < Int_t(sizeof gColorTriplets / sizeof(RGB_t)); ++i, ++id)
2900  gObjectIDToColor[id] = gColorTriplets[i];
2901  for (Int_t i = 0, id = 1; i < Int_t(sizeof gColorTriplets / sizeof(RGB_t)); ++i, ++id)
2902  gColorToObjectID[gColorTriplets[i]] = id;
2903  }
2904 
2905  CLTCI_t it = gObjectIDToColor.find(objectID);
2906 
2907  if (it != gObjectIDToColor.end())
2908  glColor3ub(it->second.fRGB[0], it->second.fRGB[1], it->second.fRGB[2]);
2909  else {
2910  Error("ObjectIDToColor", "No color for such object ID: %d", objectID);
2911  glColor3ub(0, 0, 0);
2912  }
2913  }
2914 }
2915 
2916 ////////////////////////////////////////////////////////////////////////////////
2917 
2918 Int_t ColorToObjectID(const UChar_t *pixel, Bool_t highColor)
2919 {
2920  if (!highColor)
2921  return pixel[0] | (pixel[1] << 8) | (pixel[2] << 16);
2922  else {
2923  if (!gObjectIDToColor.size())
2924  return 0;
2925 
2926  RGB_t triplet = {{pixel[0], pixel[1], pixel[2]}};
2927  OLTCI_t it = gColorToObjectID.find(triplet);
2928 
2929  if (it != gColorToObjectID.end())
2930  return it->second;
2931  else
2932  return 0;
2933  }
2934 }
2935 
2936 
2937 ////////////////////////////////////////////////////////////////////////////////
2938 ///Draw quad outline.
2939 
2940 void DrawQuadOutline(const TGLVertex3 &v1, const TGLVertex3 &v2,
2941  const TGLVertex3 &v3, const TGLVertex3 &v4)
2942 {
2943  glBegin(GL_LINE_LOOP);
2944  glVertex3dv(v1.CArr());
2945  glVertex3dv(v2.CArr());
2946  glVertex3dv(v3.CArr());
2947  glVertex3dv(v4.CArr());
2948  glEnd();
2949 }
2950 
2951 ////////////////////////////////////////////////////////////////////////////////
2952 ///Draw quad face.
2953 
2954 void DrawQuadFilled(const TGLVertex3 &v0, const TGLVertex3 &v1, const TGLVertex3 &v2,
2955  const TGLVertex3 &v3, const TGLVector3 &normal)
2956 {
2957  glBegin(GL_POLYGON);
2958  glNormal3dv(normal.CArr());
2959  glVertex3dv(v0.CArr());
2960  glVertex3dv(v1.CArr());
2961  glVertex3dv(v2.CArr());
2962  glVertex3dv(v3.CArr());
2963  glEnd();
2964 }
2965 
2966 ////////////////////////////////////////////////////////////////////////////////
2967 ///Draw quad face.
2968 
2969 void DrawQuadFilled(const Double_t *v0, const Double_t *v1, const Double_t *v2, const Double_t *v3,
2970  const Double_t *normal)
2971 {
2972  glBegin(GL_QUADS);
2973  glNormal3dv(normal);
2974  glVertex3dv(v0);
2975  glVertex3dv(v1);
2976  glVertex3dv(v2);
2977  glVertex3dv(v3);
2978  glEnd();
2979 }
2980 
2981 ////////////////////////////////////////////////////////////////////////////////
2982 ///Draws triangle face, each vertex has its own averaged normal
2983 
2984 void DrawSmoothFace(const TGLVertex3 &v1, const TGLVertex3 &v2, const TGLVertex3 &v3,
2985  const TGLVector3 &norm1, const TGLVector3 &norm2, const TGLVector3 &norm3)
2986 {
2987  glBegin(GL_POLYGON);
2988  glNormal3dv(norm1.CArr());
2989  glVertex3dv(v1.CArr());
2990  glNormal3dv(norm2.CArr());
2991  glVertex3dv(v2.CArr());
2992  glNormal3dv(norm3.CArr());
2993  glVertex3dv(v3.CArr());
2994  glEnd();
2995 }
2996 
2997 const Int_t gBoxFrontQuads[][4] = {{0, 1, 2, 3}, {4, 0, 3, 5}, {4, 5, 6, 7}, {7, 6, 2, 1}};
2998 const Double_t gBoxFrontNormals[][3] = {{-1., 0., 0.}, {0., -1., 0.}, {1., 0., 0.}, {0., 1., 0.}};
2999 const Int_t gBoxFrontPlanes[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}};
3000 
3001 const Int_t gBoxBackQuads[][4] = {{7, 1, 2, 6}, {4, 7, 6, 5}, {0, 4, 5, 3}, {0, 3, 2, 1}};
3002 const Double_t gBoxBackNormals[][3] = {{0., -1., 0.}, {-1., 0., 0.}, {0., 1., 0.}, {1., 0., 0.}};
3003 const Int_t gBoxBackPlanes[][2] = {{0, 1}, {3, 0}, {2, 3}, {1, 2}};
3004 
3005 ////////////////////////////////////////////////////////////////////////////////
3006 ///Draws lego's bar as a 3d box
3007 
3008 void DrawBoxFront(Double_t xMin, Double_t xMax, Double_t yMin, Double_t yMax,
3009  Double_t zMin, Double_t zMax, Int_t fp)
3010 {
3011  if (zMax < zMin)
3012  std::swap(zMax, zMin);
3013 
3014  //Bottom is always drawn.
3015  glBegin(GL_POLYGON);
3016  glNormal3d(0., 0., -1.);
3017  glVertex3d(xMax, yMin, zMin);
3018  glVertex3d(xMin, yMin, zMin);
3019  glVertex3d(xMin, yMax, zMin);
3020  glVertex3d(xMax, yMax, zMin);
3021  glEnd();
3022  //Draw two visible front planes.
3023  const Double_t box[][3] = {{xMin, yMin, zMax}, {xMin, yMax, zMax}, {xMin, yMax, zMin}, {xMin, yMin, zMin},
3024  {xMax, yMin, zMax}, {xMax, yMin, zMin}, {xMax, yMax, zMin}, {xMax, yMax, zMax}};
3025  const Int_t *verts = gBoxFrontQuads[gBoxFrontPlanes[fp][0]];
3026 
3027  glBegin(GL_POLYGON);
3028  glNormal3dv(gBoxFrontNormals[gBoxFrontPlanes[fp][0]]);
3029  glVertex3dv(box[verts[0]]);
3030  glVertex3dv(box[verts[1]]);
3031  glVertex3dv(box[verts[2]]);
3032  glVertex3dv(box[verts[3]]);
3033  glEnd();
3034 
3035  verts = gBoxFrontQuads[gBoxFrontPlanes[fp][1]];
3036 
3037  glBegin(GL_POLYGON);
3038  glNormal3dv(gBoxFrontNormals[gBoxFrontPlanes[fp][1]]);
3039  glVertex3dv(box[verts[0]]);
3040  glVertex3dv(box[verts[1]]);
3041  glVertex3dv(box[verts[2]]);
3042  glVertex3dv(box[verts[3]]);
3043  glEnd();
3044 
3045  //Top is always drawn.
3046  glBegin(GL_POLYGON);
3047  glNormal3d(0., 0., 1.);
3048  glVertex3d(xMax, yMin, zMax);
3049  glVertex3d(xMax, yMax, zMax);
3050  glVertex3d(xMin, yMax, zMax);
3051  glVertex3d(xMin, yMin, zMax);
3052  glEnd();
3053 }
3054 
3055 ////////////////////////////////////////////////////////////////////////////////
3056 ///Draws lego's bar as a 3d box
3057 
3058 void DrawTransparentBox(Double_t xMin, Double_t xMax, Double_t yMin, Double_t yMax,
3059  Double_t zMin, Double_t zMax, Int_t fp)
3060 {
3061  if (zMax < zMin)
3062  std::swap(zMax, zMin);
3063 
3064  //The order is: 1) two back planes, 2) bottom plane, 3) two front planes,
3065  //4) top.
3066 
3067  //Bottom is always drawn.
3068  glBegin(GL_POLYGON);
3069  glNormal3d(0., 0., -1.);
3070  glVertex3d(xMax, yMin, zMin);
3071  glVertex3d(xMin, yMin, zMin);
3072  glVertex3d(xMin, yMax, zMin);
3073  glVertex3d(xMax, yMax, zMin);
3074  glEnd();
3075 
3076  const Double_t box[][3] = {{xMin, yMin, zMax}, {xMin, yMax, zMax}, {xMin, yMax, zMin}, {xMin, yMin, zMin},
3077  {xMax, yMin, zMax}, {xMax, yMin, zMin}, {xMax, yMax, zMin}, {xMax, yMax, zMax}};
3078 
3079  //Draw two back planes.
3080  const Int_t *verts = gBoxBackQuads[gBoxBackPlanes[fp][0]];
3081 
3082  glBegin(GL_POLYGON);
3083  glNormal3dv(gBoxBackNormals[gBoxBackPlanes[fp][0]]);
3084  glVertex3dv(box[verts[0]]);
3085  glVertex3dv(box[verts[1]]);
3086  glVertex3dv(box[verts[2]]);
3087  glVertex3dv(box[verts[3]]);
3088  glEnd();
3089 
3090  verts = gBoxBackQuads[gBoxBackPlanes[fp][1]];
3091 
3092  glBegin(GL_POLYGON);
3093  glNormal3dv(gBoxBackNormals[gBoxBackPlanes[fp][1]]);
3094  glVertex3dv(box[verts[0]]);
3095  glVertex3dv(box[verts[1]]);
3096  glVertex3dv(box[verts[2]]);
3097  glVertex3dv(box[verts[3]]);
3098  glEnd();
3099 
3100  //Draw two visible front planes.
3101  verts = gBoxFrontQuads[gBoxFrontPlanes[fp][0]];
3102 
3103  glBegin(GL_POLYGON);
3104  glNormal3dv(gBoxFrontNormals[gBoxFrontPlanes[fp][0]]);
3105  glVertex3dv(box[verts[0]]);
3106  glVertex3dv(box[verts[1]]);
3107  glVertex3dv(box[verts[2]]);
3108  glVertex3dv(box[verts[3]]);
3109  glEnd();
3110 
3111  verts = gBoxFrontQuads[gBoxFrontPlanes[fp][1]];
3112 
3113  glBegin(GL_POLYGON);
3114  glNormal3dv(gBoxFrontNormals[gBoxFrontPlanes[fp][1]]);
3115  glVertex3dv(box[verts[0]]);
3116  glVertex3dv(box[verts[1]]);
3117  glVertex3dv(box[verts[2]]);
3118  glVertex3dv(box[verts[3]]);
3119  glEnd();
3120 
3121  //Top is always drawn.
3122  glBegin(GL_POLYGON);
3123  glNormal3d(0., 0., 1.);
3124  glVertex3d(xMax, yMin, zMax);
3125  glVertex3d(xMax, yMax, zMax);
3126  glVertex3d(xMin, yMax, zMax);
3127  glVertex3d(xMin, yMin, zMax);
3128  glEnd();
3129 }
3130 
3131 ////////////////////////////////////////////////////////////////////////////////
3132 ///Draws lego's bar as a 3d box
3133 ///LULULULU
3134 
3135 void DrawBoxFrontTextured(Double_t xMin, Double_t xMax, Double_t yMin,
3136  Double_t yMax, Double_t zMin, Double_t zMax,
3137  Double_t texMin, Double_t texMax, Int_t fp)
3138 {
3139  if (zMax < zMin) {
3140  std::swap(zMax, zMin);
3141  std::swap(texMax, texMin);
3142  }
3143 
3144  //Top and bottom are always drawn.
3145  glBegin(GL_POLYGON);
3146  glNormal3d(0., 0., 1.);
3147  glTexCoord1d(texMax);
3148  glVertex3d(xMax, yMin, zMax);
3149  glVertex3d(xMax, yMax, zMax);
3150  glVertex3d(xMin, yMax, zMax);
3151  glVertex3d(xMin, yMin, zMax);
3152  glEnd();
3153 
3154  glBegin(GL_POLYGON);
3155  glTexCoord1d(texMin);
3156  glNormal3d(0., 0., -1.);
3157  glVertex3d(xMax, yMin, zMin);
3158  glVertex3d(xMin, yMin, zMin);
3159  glVertex3d(xMin, yMax, zMin);
3160  glVertex3d(xMax, yMax, zMin);
3161  glEnd();
3162  //Draw two visible front planes.
3163  const Double_t box[][3] = {{xMin, yMin, zMax}, {xMin, yMax, zMax}, {xMin, yMax, zMin}, {xMin, yMin, zMin},
3164  {xMax, yMin, zMax}, {xMax, yMin, zMin}, {xMax, yMax, zMin}, {xMax, yMax, zMax}};
3165 
3166  const Double_t tex[] = {texMax, texMax, texMin, texMin, texMax, texMin, texMin, texMax};
3167  const Int_t *verts = gBoxFrontQuads[gBoxFrontPlanes[fp][0]];
3168 
3169  glBegin(GL_POLYGON);
3170  glNormal3dv(gBoxFrontNormals[gBoxFrontPlanes[fp][0]]);
3171  glTexCoord1d(tex[verts[0]]);
3172  glVertex3dv(box[verts[0]]);
3173  glTexCoord1d(tex[verts[1]]);
3174  glVertex3dv(box[verts[1]]);
3175  glTexCoord1d(tex[verts[2]]);
3176  glVertex3dv(box[verts[2]]);
3177  glTexCoord1d(tex[verts[3]]);
3178  glVertex3dv(box[verts[3]]);
3179  glEnd();
3180 
3181  verts = gBoxFrontQuads[gBoxFrontPlanes[fp][1]];
3182 
3183  glBegin(GL_POLYGON);
3184  glNormal3dv(gBoxFrontNormals[gBoxFrontPlanes[fp][1]]);
3185  glTexCoord1d(tex[verts[0]]);
3186  glVertex3dv(box[verts[0]]);
3187  glTexCoord1d(tex[verts[1]]);
3188  glVertex3dv(box[verts[1]]);
3189  glTexCoord1d(tex[verts[2]]);
3190  glVertex3dv(box[verts[2]]);
3191  glTexCoord1d(tex[verts[3]]);
3192  glVertex3dv(box[verts[3]]);
3193  glEnd();
3194 }
3195 
3196 ////////////////////////////////////////////////////////////////////////////////
3197 
3198 void DrawBoxWithGradientFill(Double_t y1, Double_t y2, Double_t x1, Double_t x2,
3199  const Double_t *rgba1, const Double_t *rgba2)
3200 {
3201  assert(rgba1 != 0 && "DrawBoxWithGradientFill, parameter 'rgba1' is null");
3202  assert(rgba2 != 0 && "DrawBoxWithGradientFill, parameter 'rgba2' is null");
3203 
3204  glBegin(GL_POLYGON);
3205  glColor4dv(rgba1);
3206  glVertex2d(x1, y1);
3207  glVertex2d(x2, y1);
3208  glColor4dv(rgba2);
3209  glVertex2d(x2, y2);
3210  glVertex2d(x1, y2);
3211  glEnd();
3212 }
3213 
3214 ////////////////////////////////////////////////////////////////////////////////
3215 ///TODO: is it possible to use GLdouble to avoid problems with Double_t/GLdouble if they
3216 ///are not the same type?
3217 
3218 void DrawQuadStripWithRadialGradientFill(unsigned nPoints, const Double_t *inner, const Double_t *innerRGBA,
3219  const Double_t *outer, const Double_t *outerRGBA)
3220 {
3221  assert(nPoints != 0 &&
3222  "DrawQuadStripWithRadialGradientFill, invalid number of points");
3223  assert(inner != 0 &&
3224  "DrawQuadStripWithRadialGradientFill, parameter 'inner' is null");
3225  assert(innerRGBA != 0 &&
3226  "DrawQuadStripWithRadialGradientFill, parameter 'innerRGBA' is null");
3227  assert(outer != 0 &&
3228  "DrawQuadStripWithRadialGradientFill, parameter 'outer' is null");
3229  assert(outerRGBA != 0 &&
3230  "DrawQuadStripWithRadialGradientFill, parameter 'outerRGBA' is null");
3231 
3232  glBegin(GL_QUAD_STRIP);
3233  for (UInt_t j = 0; j < nPoints; ++j) {
3234  glColor4dv(innerRGBA);
3235  glVertex2dv(inner + j * 2);
3236  glColor4dv(outerRGBA);
3237  glVertex2dv(outer + j * 2);
3238  }
3239  glEnd();
3240 }
3241 
3242 ////////////////////////////////////////////////////////////////////////////////
3243 ///Cylinder for lego3.
3244 
3245 void DrawCylinder(TGLQuadric *quadric, Double_t xMin, Double_t xMax, Double_t yMin,
3246  Double_t yMax, Double_t zMin, Double_t zMax)
3247 {
3248  GLUquadric *quad = quadric->Get();
3249 
3250  if (quad) {
3251  if (zMin > zMax)
3252  std::swap(zMin, zMax);
3253  const Double_t xCenter = xMin + (xMax - xMin) / 2;
3254  const Double_t yCenter = yMin + (yMax - yMin) / 2;
3255  const Double_t radius = TMath::Min((xMax - xMin) / 2, (yMax - yMin) / 2);
3256 
3257  glPushMatrix();
3258  glTranslated(xCenter, yCenter, zMin);
3259  gluCylinder(quad, radius, radius, zMax - zMin, 40, 1);
3260  glPopMatrix();
3261  glPushMatrix();
3262  glTranslated(xCenter, yCenter, zMax);
3263  gluDisk(quad, 0., radius, 40, 1);
3264  glPopMatrix();
3265  glPushMatrix();
3266  glTranslated(xCenter, yCenter, zMin);
3267  glRotated(180., 0., 1., 0.);
3268  gluDisk(quad, 0., radius, 40, 1);
3269  glPopMatrix();
3270  }
3271 }
3272 
3273 ////////////////////////////////////////////////////////////////////////////////
3274 ///Cylinder for lego3.
3275 
3276 void DrawSphere(TGLQuadric *quadric, Double_t xMin, Double_t xMax, Double_t yMin,
3277  Double_t yMax, Double_t zMin, Double_t zMax)
3278 {
3279  GLUquadric *quad = quadric->Get();
3280 
3281  if (quad) {
3282  const Double_t xCenter = xMin + (xMax - xMin) / 2;
3283  const Double_t yCenter = yMin + (yMax - yMin) / 2;
3284  const Double_t zCenter = zMin + (zMax - zMin) / 2;
3285 
3286  const Double_t radius = TMath::Min((zMax - zMin) / 2,
3287  TMath::Min((xMax - xMin) / 2, (yMax - yMin) / 2));
3288 
3289  glPushMatrix();
3290  glTranslated(xCenter, yCenter, zCenter);
3291  gluSphere(quad, radius, 10, 10);
3292  glPopMatrix();
3293  }
3294 }
3295 
3296 
3297 ////////////////////////////////////////////////////////////////////////////////
3298 
3299 void DrawError(Double_t xMin, Double_t xMax, Double_t yMin,
3300  Double_t yMax, Double_t zMin, Double_t zMax)
3301 {
3302  const Double_t xWid = xMax - xMin;
3303  const Double_t yWid = yMax - yMin;
3304 
3305  glBegin(GL_LINES);
3306  glVertex3d(xMin + xWid / 2, yMin + yWid / 2, zMin);
3307  glVertex3d(xMin + xWid / 2, yMin + yWid / 2, zMax);
3308  glEnd();
3309 
3310  glBegin(GL_LINES);
3311  glVertex3d(xMin + xWid / 2, yMin, zMin);
3312  glVertex3d(xMin + xWid / 2, yMax, zMin);
3313  glEnd();
3314 
3315  glBegin(GL_LINES);
3316  glVertex3d(xMin, yMin + yWid / 2, zMin);
3317  glVertex3d(xMax, yMin + yWid / 2, zMin);
3318  glEnd();
3319 }
3320 
3321 void CylindricalNormal(const Double_t *v, Double_t *normal)
3322 {
3323  const Double_t n = TMath::Sqrt(v[0] * v[0] + v[1] * v[1]);
3324  if (n > 0.) {
3325  normal[0] = v[0] / n;
3326  normal[1] = v[1] / n;
3327  normal[2] = 0.;
3328  } else {
3329  normal[0] = v[0];
3330  normal[1] = v[1];
3331  normal[2] = 0.;
3332  }
3333 }
3334 
3335 void CylindricalNormalInv(const Double_t *v, Double_t *normal)
3336 {
3337  const Double_t n = TMath::Sqrt(v[0] * v[0] + v[1] * v[1]);
3338  if (n > 0.) {
3339  normal[0] = -v[0] / n;
3340  normal[1] = -v[1] / n;
3341  normal[2] = 0.;
3342  } else {
3343  normal[0] = -v[0];
3344  normal[1] = -v[1];
3345  normal[2] = 0.;
3346  }
3347 }
3348 
3349 void DrawTrapezoid(const Double_t ver[][2], Double_t zMin, Double_t zMax, Bool_t color)
3350 {
3351  //In polar coordinates, box became trapezoid.
3352  //Four faces need normal calculations.
3353  if (zMin > zMax)
3354  std::swap(zMin, zMax);
3355  //top
3356  glBegin(GL_POLYGON);
3357  glNormal3d(0., 0., 1.);
3358  glVertex3d(ver[0][0], ver[0][1], zMax);
3359  glVertex3d(ver[1][0], ver[1][1], zMax);
3360  glVertex3d(ver[2][0], ver[2][1], zMax);
3361  glVertex3d(ver[3][0], ver[3][1], zMax);
3362  glEnd();
3363  //bottom
3364  glBegin(GL_POLYGON);
3365  glNormal3d(0., 0., -1.);
3366  glVertex3d(ver[0][0], ver[0][1], zMin);
3367  glVertex3d(ver[3][0], ver[3][1], zMin);
3368  glVertex3d(ver[2][0], ver[2][1], zMin);
3369  glVertex3d(ver[1][0], ver[1][1], zMin);
3370  glEnd();
3371  //
3372 
3373  Double_t trapezoid[][3] = {{ver[0][0], ver[0][1], zMin}, {ver[1][0], ver[1][1], zMin},
3374  {ver[2][0], ver[2][1], zMin}, {ver[3][0], ver[3][1], zMin},
3375  {ver[0][0], ver[0][1], zMax}, {ver[1][0], ver[1][1], zMax},
3376  {ver[2][0], ver[2][1], zMax}, {ver[3][0], ver[3][1], zMax}};
3377  Double_t normal[3] = {0.};
3378  glBegin(GL_POLYGON);
3379  CylindricalNormal(trapezoid[1], normal), glNormal3dv(normal), glVertex3dv(trapezoid[1]);
3380  CylindricalNormal(trapezoid[2], normal), glNormal3dv(normal), glVertex3dv(trapezoid[2]);
3381  CylindricalNormal(trapezoid[6], normal), glNormal3dv(normal), glVertex3dv(trapezoid[6]);
3382  CylindricalNormal(trapezoid[5], normal), glNormal3dv(normal), glVertex3dv(trapezoid[5]);
3383  glEnd();
3384 
3385  glBegin(GL_POLYGON);
3386  CylindricalNormalInv(trapezoid[0], normal), glNormal3dv(normal), glVertex3dv(trapezoid[0]);
3387  CylindricalNormalInv(trapezoid[4], normal), glNormal3dv(normal), glVertex3dv(trapezoid[4]);
3388  CylindricalNormalInv(trapezoid[7], normal), glNormal3dv(normal), glVertex3dv(trapezoid[7]);
3389  CylindricalNormalInv(trapezoid[3], normal), glNormal3dv(normal), glVertex3dv(trapezoid[3]);
3390  glEnd();
3391 
3392  glBegin(GL_POLYGON);
3393  if (color) {
3394  TMath::Normal2Plane(trapezoid[0], trapezoid[1], trapezoid[5], normal);
3395  glNormal3dv(normal);
3396  }
3397  glVertex3dv(trapezoid[0]);
3398  glVertex3dv(trapezoid[1]);
3399  glVertex3dv(trapezoid[5]);
3400  glVertex3dv(trapezoid[4]);
3401  glEnd();
3402 
3403  glBegin(GL_POLYGON);
3404  if (color) {
3405  TMath::Normal2Plane(trapezoid[3], trapezoid[7], trapezoid[6], normal);
3406  glNormal3dv(normal);
3407  }
3408  glVertex3dv(trapezoid[3]);
3409  glVertex3dv(trapezoid[7]);
3410  glVertex3dv(trapezoid[6]);
3411  glVertex3dv(trapezoid[2]);
3412  glEnd();
3413 }
3414 
3415 ////////////////////////////////////////////////////////////////////////////////
3416 ///In polar coordinates, box became trapezoid.
3417 ///Four faces need normal calculations.
3418 
3419 void DrawTrapezoidTextured(const Double_t ver[][2], Double_t zMin, Double_t zMax,
3420  Double_t texMin, Double_t texMax)
3421 {
3422  if (zMin > zMax) {
3423  std::swap(zMin, zMax);
3424  std::swap(texMin, texMax);
3425  }
3426 
3427  //top
3428  glBegin(GL_POLYGON);
3429  glNormal3d(0., 0., 1.);
3430  glTexCoord1d(texMax);
3431  glVertex3d(ver[0][0], ver[0][1], zMax);
3432  glVertex3d(ver[1][0], ver[1][1], zMax);
3433  glVertex3d(ver[2][0], ver[2][1], zMax);
3434  glVertex3d(ver[3][0], ver[3][1], zMax);
3435  glEnd();
3436  //bottom
3437  glBegin(GL_POLYGON);
3438  glNormal3d(0., 0., -1.);
3439  glTexCoord1d(texMin);
3440  glVertex3d(ver[0][0], ver[0][1], zMin);
3441  glVertex3d(ver[3][0], ver[3][1], zMin);
3442  glVertex3d(ver[2][0], ver[2][1], zMin);
3443  glVertex3d(ver[1][0], ver[1][1], zMin);
3444  glEnd();
3445  //
3446 
3447  Double_t trapezoid[][3] = {{ver[0][0], ver[0][1], zMin}, {ver[1][0], ver[1][1], zMin},
3448  {ver[2][0], ver[2][1], zMin}, {ver[3][0], ver[3][1], zMin},
3449  {ver[0][0], ver[0][1], zMax}, {ver[1][0], ver[1][1], zMax},
3450  {ver[2][0], ver[2][1], zMax}, {ver[3][0], ver[3][1], zMax}};
3451  Double_t normal[3] = {0.};
3452  glBegin(GL_POLYGON);
3453  CylindricalNormal(trapezoid[1], normal), glNormal3dv(normal), glTexCoord1d(texMin), glVertex3dv(trapezoid[1]);
3454  CylindricalNormal(trapezoid[2], normal), glNormal3dv(normal), glTexCoord1d(texMin), glVertex3dv(trapezoid[2]);
3455  CylindricalNormal(trapezoid[6], normal), glNormal3dv(normal), glTexCoord1d(texMax), glVertex3dv(trapezoid[6]);
3456  CylindricalNormal(trapezoid[5], normal), glNormal3dv(normal), glTexCoord1d(texMax), glVertex3dv(trapezoid[5]);
3457  glEnd();
3458 
3459  glBegin(GL_POLYGON);
3460  CylindricalNormalInv(trapezoid[0], normal), glNormal3dv(normal), glTexCoord1d(texMin), glVertex3dv(trapezoid[0]);
3461  CylindricalNormalInv(trapezoid[4], normal), glNormal3dv(normal), glTexCoord1d(texMax), glVertex3dv(trapezoid[4]);
3462  CylindricalNormalInv(trapezoid[7], normal), glNormal3dv(normal), glTexCoord1d(texMax), glVertex3dv(trapezoid[7]);
3463  CylindricalNormalInv(trapezoid[3], normal), glNormal3dv(normal), glTexCoord1d(texMin), glVertex3dv(trapezoid[3]);
3464  glEnd();
3465 
3466  glBegin(GL_POLYGON);
3467  TMath::Normal2Plane(trapezoid[0], trapezoid[1], trapezoid[5], normal);
3468  glNormal3dv(normal);
3469  glTexCoord1d(texMin);
3470  glVertex3dv(trapezoid[0]);
3471  glTexCoord1d(texMin);
3472  glVertex3dv(trapezoid[1]);
3473  glTexCoord1d(texMax);
3474  glVertex3dv(trapezoid[5]);
3475  glTexCoord1d(texMax);
3476  glVertex3dv(trapezoid[4]);
3477  glEnd();
3478 
3479  glBegin(GL_POLYGON);
3480  TMath::Normal2Plane(trapezoid[3], trapezoid[7], trapezoid[6], normal);
3481  glNormal3dv(normal);
3482  glTexCoord1d(texMin);
3483  glVertex3dv(trapezoid[3]);
3484  glTexCoord1d(texMax);
3485  glVertex3dv(trapezoid[7]);
3486  glTexCoord1d(texMax);
3487  glVertex3dv(trapezoid[6]);
3488  glTexCoord1d(texMin);
3489  glVertex3dv(trapezoid[2]);
3490  glEnd();
3491 }
3492 
3493 ////////////////////////////////////////////////////////////////////////////////
3494 ///In polar coordinates, box became trapezoid.
3495 
3496 void DrawTrapezoidTextured2(const Double_t ver[][2], Double_t zMin, Double_t zMax,
3497  Double_t texMin, Double_t texMax)
3498 {
3499  if (zMin > zMax)
3500  std::swap(zMin, zMax);
3501 
3502  const Double_t trapezoid[][3] = {{ver[0][0], ver[0][1], zMin}, {ver[1][0], ver[1][1], zMin},
3503  {ver[2][0], ver[2][1], zMin}, {ver[3][0], ver[3][1], zMin},
3504  {ver[0][0], ver[0][1], zMax}, {ver[1][0], ver[1][1], zMax},
3505  {ver[2][0], ver[2][1], zMax}, {ver[3][0], ver[3][1], zMax}};
3506  const Double_t tex[] = {texMin, texMax, texMax, texMin, texMin, texMax, texMax, texMin};
3507  //top
3508  glBegin(GL_POLYGON);
3509  glNormal3d(0., 0., 1.);
3510  glTexCoord1d(tex[4]), glVertex3dv(trapezoid[4]);
3511  glTexCoord1d(tex[5]), glVertex3dv(trapezoid[5]);
3512  glTexCoord1d(tex[6]), glVertex3dv(trapezoid[6]);
3513  glTexCoord1d(tex[7]), glVertex3dv(trapezoid[7]);
3514  glEnd();
3515  //bottom
3516  glBegin(GL_POLYGON);
3517  glNormal3d(0., 0., -1.);
3518  glTexCoord1d(tex[0]), glVertex3dv(trapezoid[0]);
3519  glTexCoord1d(tex[3]), glVertex3dv(trapezoid[3]);
3520  glTexCoord1d(tex[2]), glVertex3dv(trapezoid[2]);
3521  glTexCoord1d(tex[1]), glVertex3dv(trapezoid[1]);
3522  glEnd();
3523  //
3524  glBegin(GL_POLYGON);
3525  Double_t normal[3] = {};
3526  CylindricalNormal(trapezoid[1], normal), glNormal3dv(normal), glTexCoord1d(tex[1]), glVertex3dv(trapezoid[1]);
3527  CylindricalNormal(trapezoid[2], normal), glNormal3dv(normal), glTexCoord1d(tex[2]), glVertex3dv(trapezoid[2]);
3528  CylindricalNormal(trapezoid[6], normal), glNormal3dv(normal), glTexCoord1d(tex[6]), glVertex3dv(trapezoid[6]);
3529  CylindricalNormal(trapezoid[5], normal), glNormal3dv(normal), glTexCoord1d(tex[5]), glVertex3dv(trapezoid[5]);
3530  glEnd();
3531 
3532  glBegin(GL_POLYGON);
3533  CylindricalNormalInv(trapezoid[0], normal), glNormal3dv(normal), glTexCoord1d(tex[0]), glVertex3dv(trapezoid[0]);
3534  CylindricalNormalInv(trapezoid[4], normal), glNormal3dv(normal), glTexCoord1d(tex[4]), glVertex3dv(trapezoid[4]);
3535  CylindricalNormalInv(trapezoid[7], normal), glNormal3dv(normal), glTexCoord1d(tex[7]), glVertex3dv(trapezoid[7]);
3536  CylindricalNormalInv(trapezoid[3], normal), glNormal3dv(normal), glTexCoord1d(tex[3]), glVertex3dv(trapezoid[3]);
3537  glEnd();
3538 
3539  glBegin(GL_POLYGON);
3540  TMath::Normal2Plane(trapezoid[0], trapezoid[1], trapezoid[5], normal);
3541  glNormal3dv(normal);
3542  glTexCoord1d(tex[0]), glVertex3dv(trapezoid[0]);
3543  glTexCoord1d(tex[1]), glVertex3dv(trapezoid[1]);
3544  glTexCoord1d(tex[5]), glVertex3dv(trapezoid[5]);
3545  glTexCoord1d(tex[4]), glVertex3dv(trapezoid[4]);
3546  glEnd();
3547 
3548  glBegin(GL_POLYGON);
3549  TMath::Normal2Plane(trapezoid[3], trapezoid[7], trapezoid[6], normal);
3550  glNormal3dv(normal);
3551  glTexCoord1d(tex[3]), glVertex3dv(trapezoid[3]);
3552  glTexCoord1d(tex[7]), glVertex3dv(trapezoid[7]);
3553  glTexCoord1d(tex[6]), glVertex3dv(trapezoid[6]);
3554  glTexCoord1d(tex[2]), glVertex3dv(trapezoid[2]);
3555  glEnd();
3556 }
3557 
3558 ////////////////////////////////////////////////////////////////////////////////
3559 
3560 void SphericalNormal(const Double_t *v, Double_t *normal)
3561 {
3562  const Double_t n = TMath::Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
3563  if (n > 0.) {
3564  normal[0] = v[0] / n;
3565  normal[1] = v[1] / n;
3566  normal[2] = v[2] / n;
3567  } else {
3568  normal[0] = v[0];
3569  normal[1] = v[1];
3570  normal[2] = v[2];
3571  }
3572 }
3573 
3574 ////////////////////////////////////////////////////////////////////////////////
3575 
3576 void SphericalNormalInv(const Double_t *v, Double_t *normal)
3577 {
3578  const Double_t n = TMath::Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
3579  if (n > 0.) {
3580  normal[0] = -v[0] / n;
3581  normal[1] = -v[1] / n;
3582  normal[2] = -v[2] / n;
3583  } else {
3584  normal[0] = -v[0];
3585  normal[1] = -v[1];
3586  normal[2] = -v[2];
3587  }
3588 }
3589 
3590 ////////////////////////////////////////////////////////////////////////////////
3591 
3592 void DrawTrapezoid(const Double_t ver[][3])
3593 {
3594  Double_t normal[3] = {0.};
3595 
3596  glBegin(GL_POLYGON);
3597  TMath::Normal2Plane(ver[1], ver[2], ver[3], normal);
3598  glNormal3dv(normal);
3599  glVertex3dv(ver[0]);
3600  glVertex3dv(ver[1]);
3601  glVertex3dv(ver[2]);
3602  glVertex3dv(ver[3]);
3603  glEnd();
3604  //bottom
3605  glBegin(GL_POLYGON);
3606  TMath::Normal2Plane(ver[4], ver[7], ver[6], normal);
3607  glNormal3dv(normal);
3608  glVertex3dv(ver[4]);
3609  glVertex3dv(ver[7]);
3610  glVertex3dv(ver[6]);
3611  glVertex3dv(ver[5]);
3612  glEnd();
3613  //
3614 
3615  glBegin(GL_POLYGON);
3616  TMath::Normal2Plane(ver[0], ver[3], ver[7], normal);
3617  glNormal3dv(normal);
3618  glVertex3dv(ver[0]);
3619  glVertex3dv(ver[3]);
3620  glVertex3dv(ver[7]);
3621  glVertex3dv(ver[4]);
3622  glEnd();
3623 
3624  glBegin(GL_POLYGON);
3625  SphericalNormal(ver[3], normal), glNormal3dv(normal), glVertex3dv(ver[3]);
3626  SphericalNormal(ver[2], normal), glNormal3dv(normal), glVertex3dv(ver[2]);
3627  SphericalNormal(ver[6], normal), glNormal3dv(normal), glVertex3dv(ver[6]);
3628  SphericalNormal(ver[7], normal), glNormal3dv(normal), glVertex3dv(ver[7]);
3629  glEnd();
3630 
3631  glBegin(GL_POLYGON);
3632  TMath::Normal2Plane(ver[5], ver[6], ver[2], normal);
3633  glNormal3dv(normal);
3634  glVertex3dv(ver[5]);
3635  glVertex3dv(ver[6]);
3636  glVertex3dv(ver[2]);
3637  glVertex3dv(ver[1]);
3638  glEnd();
3639 
3640  glBegin(GL_POLYGON);
3641  SphericalNormalInv(ver[0], normal), glNormal3dv(normal), glVertex3dv(ver[0]);
3642  SphericalNormalInv(ver[4], normal), glNormal3dv(normal), glVertex3dv(ver[4]);
3643  SphericalNormalInv(ver[5], normal), glNormal3dv(normal), glVertex3dv(ver[5]);
3644  SphericalNormalInv(ver[1], normal), glNormal3dv(normal), glVertex3dv(ver[1]);
3645  glEnd();
3646 }
3647 
3648 ////////////////////////////////////////////////////////////////////////////////
3649 
3650 void DrawTrapezoidTextured(const Double_t ver[][3], Double_t texMin, Double_t texMax)
3651 {
3652  Double_t normal[3] = {};
3653  if (texMin > texMax)
3654  std::swap(texMin, texMax);
3655 
3656  const Double_t tex[] = {texMin, texMin, texMax, texMax, texMin, texMin, texMax, texMax};
3657  glBegin(GL_POLYGON);
3658  TMath::Normal2Plane(ver[0], ver[1], ver[2], normal);
3659  glNormal3dv(normal);
3660  glTexCoord1d(tex[0]), glVertex3dv(ver[0]);
3661  glTexCoord1d(tex[1]), glVertex3dv(ver[1]);
3662  glTexCoord1d(tex[2]), glVertex3dv(ver[2]);
3663  glTexCoord1d(tex[3]), glVertex3dv(ver[3]);
3664  glEnd();
3665  glBegin(GL_POLYGON);
3666  TMath::Normal2Plane(ver[4], ver[7], ver[6], normal);
3667  glNormal3dv(normal);
3668  glTexCoord1d(tex[4]), glVertex3dv(ver[4]);
3669  glTexCoord1d(tex[7]), glVertex3dv(ver[7]);
3670  glTexCoord1d(tex[6]), glVertex3dv(ver[6]);
3671  glTexCoord1d(tex[5]), glVertex3dv(ver[5]);
3672  glEnd();
3673  glBegin(GL_POLYGON);
3674  TMath::Normal2Plane(ver[0], ver[3], ver[7], normal);
3675  glNormal3dv(normal);
3676  glTexCoord1d(tex[0]), glVertex3dv(ver[0]);
3677  glTexCoord1d(tex[3]), glVertex3dv(ver[3]);
3678  glTexCoord1d(tex[7]), glVertex3dv(ver[7]);
3679  glTexCoord1d(tex[4]), glVertex3dv(ver[4]);
3680  glEnd();
3681  glBegin(GL_POLYGON);
3682  SphericalNormal(ver[3], normal), glNormal3dv(normal), glTexCoord1d(tex[3]), glVertex3dv(ver[3]);
3683  SphericalNormal(ver[2], normal), glNormal3dv(normal), glTexCoord1d(tex[2]), glVertex3dv(ver[2]);
3684  SphericalNormal(ver[6], normal), glNormal3dv(normal), glTexCoord1d(tex[6]), glVertex3dv(ver[6]);
3685  SphericalNormal(ver[7], normal), glNormal3dv(normal), glTexCoord1d(tex[7]), glVertex3dv(ver[7]);
3686  glEnd();
3687  glBegin(GL_POLYGON);
3688  TMath::Normal2Plane(ver[5], ver[6], ver[2], normal);
3689  glNormal3dv(normal);
3690  glTexCoord1d(tex[5]), glVertex3dv(ver[5]);
3691  glTexCoord1d(tex[6]), glVertex3dv(ver[6]);
3692  glTexCoord1d(tex[2]), glVertex3dv(ver[2]);
3693  glTexCoord1d(tex[1]), glVertex3dv(ver[1]);
3694  glEnd();
3695  glBegin(GL_POLYGON);
3696  SphericalNormalInv(ver[0], normal), glNormal3dv(normal), glTexCoord1d(tex[0]), glVertex3dv(ver[0]);
3697  SphericalNormalInv(ver[4], normal), glNormal3dv(normal), glTexCoord1d(tex[4]), glVertex3dv(ver[4]);
3698  SphericalNormalInv(ver[5], normal), glNormal3dv(normal), glTexCoord1d(tex[5]), glVertex3dv(ver[5]);
3699  SphericalNormalInv(ver[1], normal), glNormal3dv(normal), glTexCoord1d(tex[1]), glVertex3dv(ver[1]);
3700  glEnd();
3701 }
3702 
3703 
3704 void Draw2DAxis(TAxis *axis, Double_t xMin, Double_t yMin, Double_t xMax, Double_t yMax,
3705  Double_t min, Double_t max, Bool_t log, Bool_t z = kFALSE)
3706 {
3707  //Axes are drawn with help of TGaxis class
3708  std::string option;
3709  option.reserve(20);
3710 
3711  if (xMin > xMax || z) option += "SDH=+";
3712  else option += "SDH=-";
3713 
3714  if (log) option += 'G';
3715 
3716  Int_t nDiv = axis->GetNdivisions();
3717 
3718  if (nDiv < 0) {
3719  option += 'N';
3720  nDiv = -nDiv;
3721  }
3722 
3723  TGaxis axisPainter;
3724  axisPainter.SetLineWidth(1);
3725 
3726  static const Double_t zero = 0.001;
3727 
3728  if (TMath::Abs(xMax - xMin) >= zero || TMath::Abs(yMax - yMin) >= zero) {
3729  axisPainter.ImportAxisAttributes(axis);
3730  axisPainter.SetLabelOffset(axis->GetLabelOffset() + axis->GetTickLength());
3731 
3732  if (log) {
3733  min = TMath::Power(10, min);
3734  max = TMath::Power(10, max);
3735  }
3736  //Option time display is required ?
3737  if (axis->GetTimeDisplay()) {
3738  option += 't';
3739 
3740  if (!strlen(axis->GetTimeFormatOnly()))
3741  axisPainter.SetTimeFormat(axis->ChooseTimeFormat(max - min));
3742  else
3743  axisPainter.SetTimeFormat(axis->GetTimeFormat());
3744  }
3745 
3746  axisPainter.SetOption(option.c_str());
3747  axisPainter.PaintAxis(xMin, yMin, xMax, yMax, min, max, nDiv, option.c_str());
3748  }
3749 }
3750 
3751 const Int_t gFramePoints[][2] = {{3, 1}, {0, 2}, {1, 3}, {2, 0}};
3752 //Each point has two "neighbouring axes" (left and right). Axes types are 1 (ordinata) and 0 (abscissa)
3753 const Int_t gAxisType[][2] = {{1, 0}, {0, 1}, {1, 0}, {0, 1}};
3754 
3755 ////////////////////////////////////////////////////////////////////////////////
3756 ///Using front point, find, where to draw axes and which labels to use for them
3757 ///gVirtualX->SelectWindow(gGLManager->GetVirtualXInd(fGLDevice));
3758 ///gVirtualX->SetDrawMode(TVirtualX::kCopy);//TCanvas by default sets in kInverse
3759 
3760 void DrawAxes(Int_t fp, const Int_t *vp, const TGLVertex3 *box, const TGLPlotCoordinates *coord,
3761  TAxis *xAxis, TAxis *yAxis, TAxis *zAxis)
3762 {
3763  const Int_t left = gFramePoints[fp][0];
3764  const Int_t right = gFramePoints[fp][1];
3765  const Double_t xLeft = gPad->AbsPixeltoX(Int_t(gPad->GetXlowNDC() * gPad->GetWw()
3766  + box[left].X() - vp[0]));
3767  const Double_t yLeft = gPad->AbsPixeltoY(Int_t(vp[3] - box[left].Y()
3768  + (1 - gPad->GetHNDC() - gPad->GetYlowNDC())
3769  * gPad->GetWh() + vp[1]));
3770  const Double_t xMid = gPad->AbsPixeltoX(Int_t(gPad->GetXlowNDC() * gPad->GetWw()
3771  + box[fp].X() - vp[0]));
3772  const Double_t yMid = gPad->AbsPixeltoY(Int_t(vp[3] - box[fp].Y()
3773  + (1 - gPad->GetHNDC() - gPad->GetYlowNDC())
3774  * gPad->GetWh() + vp[1]));
3775  const Double_t xRight = gPad->AbsPixeltoX(Int_t(gPad->GetXlowNDC()
3776  * gPad->GetWw() + box[right].X() - vp[0]));
3777  const Double_t yRight = gPad->AbsPixeltoY(Int_t(vp[3] - box[right].Y()
3778  + (1 - gPad->GetHNDC() - gPad->GetYlowNDC())
3779  * gPad->GetWh() + vp[1]));
3780  const Double_t points[][2] = {{coord->GetXRange().first, coord->GetYRange().first },
3781  {coord->GetXRange().second, coord->GetYRange().first },
3782  {coord->GetXRange().second, coord->GetYRange().second},
3783  {coord->GetXRange().first, coord->GetYRange().second}};
3784  const Int_t leftType = gAxisType[fp][0];
3785  const Int_t rightType = gAxisType[fp][1];
3786  const Double_t leftLabel = points[left][leftType];
3787  const Double_t leftMidLabel = points[fp][leftType];
3788  const Double_t rightMidLabel = points[fp][rightType];
3789  const Double_t rightLabel = points[right][rightType];
3790 
3791  if (xLeft - xMid || yLeft - yMid) {//To suppress error messages from TGaxis
3792  TAxis *axis = leftType ? yAxis : xAxis;
3793  if (leftLabel < leftMidLabel)
3794  Draw2DAxis(axis, xLeft, yLeft, xMid, yMid, leftLabel, leftMidLabel,
3795  leftType ? coord->GetYLog() : coord->GetXLog());
3796  else
3797  Draw2DAxis(axis, xMid, yMid, xLeft, yLeft, leftMidLabel, leftLabel,
3798  leftType ? coord->GetYLog() : coord->GetXLog());
3799  }
3800 
3801  if (xRight - xMid || yRight - yMid) {//To suppress error messages from TGaxis
3802  TAxis *axis = rightType ? yAxis : xAxis;
3803 
3804  if (rightMidLabel < rightLabel)
3805  Draw2DAxis(axis, xMid, yMid, xRight, yRight, rightMidLabel, rightLabel,
3806  rightType ? coord->GetYLog() : coord->GetXLog());
3807  else
3808  Draw2DAxis(axis, xRight, yRight, xMid, yMid, rightLabel, rightMidLabel,
3809  rightType ? coord->GetYLog() : coord->GetXLog());
3810  }
3811 
3812  const Double_t xUp = gPad->AbsPixeltoX(Int_t(gPad->GetXlowNDC() * gPad->GetWw()
3813  + box[left + 4].X() - vp[0]));
3814  const Double_t yUp = gPad->AbsPixeltoY(Int_t(vp[3] - box[left + 4].Y()
3815  + (1 - gPad->GetHNDC() - gPad->GetYlowNDC())
3816  * gPad->GetWh() + vp[1]));
3817  Draw2DAxis(zAxis, xLeft, yLeft, xUp, yUp, coord->GetZRange().first,
3818  coord->GetZRange().second, coord->GetZLog(), kTRUE);
3819 }
3820 
3821 void SetZLevels(TAxis *zAxis, Double_t zMin, Double_t zMax,
3822  Double_t zScale, std::vector<Double_t> &zLevels)
3823 {
3824  Int_t nDiv = zAxis->GetNdivisions() % 100;
3825  Int_t nBins = 0;
3826  Double_t binLow = 0., binHigh = 0., binWidth = 0.;
3827  THLimitsFinder::Optimize(zMin, zMax, nDiv, binLow, binHigh, nBins, binWidth, " ");
3828  zLevels.resize(nBins + 1);
3829 
3830  for (Int_t i = 0; i < nBins + 1; ++i)
3831  zLevels[i] = (binLow + i * binWidth) * zScale;
3832 }
3833 
3834 ////////////////////////////////////////////////////////////////////////////////
3835 ///Draw textured triangle
3836 
3837 void DrawFaceTextured(const TGLVertex3 &v1, const TGLVertex3 &v2, const TGLVertex3 &v3,
3838  Double_t t1, Double_t t2, Double_t t3, const TGLVector3 &norm1,
3839  const TGLVector3 &norm2, const TGLVector3 &norm3)
3840 {
3841  glBegin(GL_POLYGON);
3842  glNormal3dv(norm1.CArr());
3843  glTexCoord1d(t1);
3844  glVertex3dv(v1.CArr());
3845  glNormal3dv(norm2.CArr());
3846  glTexCoord1d(t2);
3847  glVertex3dv(v2.CArr());
3848  glNormal3dv(norm3.CArr());
3849  glTexCoord1d(t3);
3850  glVertex3dv(v3.CArr());
3851  glEnd();
3852 }
3853 
3854 ////////////////////////////////////////////////////////////////////////////////
3855 ///Draw textured triangle on a plane
3856 
3857 void DrawFaceTextured(const TGLVertex3 &v1, const TGLVertex3 &v2, const TGLVertex3 &v3,
3858  Double_t t1, Double_t t2, Double_t t3, Double_t z,
3859  const TGLVector3 &normal)
3860 {
3861  glBegin(GL_POLYGON);
3862  glNormal3dv(normal.CArr());
3863  glTexCoord1d(t1);
3864  glVertex3d(v1.X(), v1.Y(), z);
3865  glTexCoord1d(t2);
3866  glVertex3d(v2.X(), v2.Y(), z);
3867  glTexCoord1d(t3);
3868  glVertex3d(v3.X(), v3.Y(), z);
3869  glEnd();
3870 }
3871 
3872 ////////////////////////////////////////////////////////////////////////////////
3873 ///This function creates color for parametric surface's vertex,
3874 ///using its 'u' value.
3875 ///I've found it in one of Apple's Carbon tutorials , and it's based
3876 ///on Paul Bourke work. Very nice colors!!! :)
3877 
3878 void GetColor(Float_t v, Float_t vmin, Float_t vmax, Int_t type, Float_t *rgba)
3879 {
3880  Float_t dv,vmid;
3881  //Float_t c[] = {1.f, 1.f, 1.f};
3882  Float_t c1[3] = {}, c2[3] = {}, c3[3] = {};
3883  Float_t ratio ;
3884  rgba[3] = 1.f;
3885 
3886  if (v < vmin)
3887  v = vmin;
3888  if (v > vmax)
3889  v = vmax;
3890  dv = vmax - vmin;
3891 
3892  switch (type) {
3893  case 0:
3894  rgba[0] = 1.f;
3895  rgba[1] = 1.f;
3896  rgba[2] = 1.f;
3897  break;
3898  case 1:
3899  if (v < (vmin + 0.25 * dv)) {
3900  rgba[0] = 0;
3901  rgba[1] = 4 * (v - vmin) / dv;
3902  rgba[2] = 1;
3903  } else if (v < (vmin + 0.5 * dv)) {
3904  rgba[0] = 0;
3905  rgba[1] = 1;
3906  rgba[2] = 1 + 4 * (vmin + 0.25 * dv - v) / dv;
3907  } else if (v < (vmin + 0.75 * dv)) {
3908  rgba[0] = 4 * (v - vmin - 0.5 * dv) / dv;
3909  rgba[1] = 1;
3910  rgba[2] = 0;
3911  } else {
3912  rgba[0] = 1;
3913  rgba[1] = 1 + 4 * (vmin + 0.75 * dv - v) / dv;
3914  rgba[2] = 0;
3915  }
3916  break;
3917  case 2:
3918  rgba[0] = (v - vmin) / dv;
3919  rgba[1] = 0;
3920  rgba[2] = (vmax - v) / dv;
3921  break;
3922  case 3:
3923  rgba[0] = (v - vmin) / dv;
3924  rgba[1] = rgba[0];
3925  rgba[2] = rgba[0];
3926  break;
3927  case 4:
3928  if (v < (vmin + dv / 6.0)) {
3929  rgba[0] = 1;
3930  rgba[1] = 6 * (v - vmin) / dv;
3931  rgba[2] = 0;
3932  } else if (v < (vmin + 2.0 * dv / 6.0)) {
3933  rgba[0] = 1 + 6 * (vmin + dv / 6.0 - v) / dv;
3934  rgba[1] = 1;
3935  rgba[2] = 0;
3936  } else if (v < (vmin + 3.0 * dv / 6.0)) {
3937  rgba[0] = 0;
3938  rgba[1] = 1;
3939  rgba[2] = 6 * (v - vmin - 2.0 * dv / 6.0) / dv;
3940  } else if (v < (vmin + 4.0 * dv / 6.0)) {
3941  rgba[0] = 0;
3942  rgba[1] = 1 + 6 * (vmin + 3.0 * dv / 6.0 - v) / dv;
3943  rgba[2] = 1;
3944  } else if (v < (vmin + 5.0 * dv / 6.0)) {
3945  rgba[0] = 6 * (v - vmin - 4.0 * dv / 6.0) / dv;
3946  rgba[1] = 0;
3947  rgba[2] = 1;
3948  } else {
3949  rgba[0] = 1;
3950  rgba[1] = 0;
3951  rgba[2] = 1 + 6 * (vmin + 5.0 * dv / 6.0 - v) / dv;
3952  }
3953  break;
3954  case 5:
3955  rgba[0] = (v - vmin) / (vmax - vmin);
3956  rgba[1] = 1;
3957  rgba[2] = 0;
3958  break;
3959  case 6:
3960  rgba[0] = (v - vmin) / (vmax - vmin);
3961  rgba[1] = (vmax - v) / (vmax - vmin);
3962  rgba[2] = rgba[0];
3963  break;
3964  case 7:
3965  if (v < (vmin + 0.25 * dv)) {
3966  rgba[0] = 0;
3967  rgba[1] = 4 * (v - vmin) / dv;
3968  rgba[2] = 1 - rgba[1];
3969  } else if (v < (vmin + 0.5 * dv)) {
3970  rgba[0] = 4 * (v - vmin - 0.25 * dv) / dv;
3971  rgba[1] = 1 - rgba[0];
3972  rgba[2] = 0;
3973  } else if (v < (vmin + 0.75 * dv)) {
3974  rgba[1] = 4 * (v - vmin - 0.5 * dv) / dv;
3975  rgba[0] = 1 - rgba[1];
3976  rgba[2] = 0;
3977  } else {
3978  rgba[0] = 0;
3979  rgba[2] = 4 * (v - vmin - 0.75 * dv) / dv;
3980  rgba[1] = 1 - rgba[2];
3981  }
3982  break;
3983  case 8:
3984  if (v < (vmin + 0.5 * dv)) {
3985  rgba[0] = 2 * (v - vmin) / dv;
3986  rgba[1] = rgba[0];
3987  rgba[2] = rgba[0];
3988  } else {
3989  rgba[0] = 1 - 2 * (v - vmin - 0.5 * dv) / dv;
3990  rgba[1] = rgba[0];
3991  rgba[2] = rgba[0];
3992  }
3993  break;
3994  case 9:
3995  if (v < (vmin + dv / 3)) {
3996  rgba[2] = 3 * (v - vmin) / dv;
3997  rgba[1] = 0;
3998  rgba[0] = 1 - rgba[2];
3999  } else if (v < (vmin + 2 * dv / 3)) {
4000  rgba[0] = 0;
4001  rgba[1] = 3 * (v - vmin - dv / 3) / dv;
4002  rgba[2] = 1;
4003  } else {
4004  rgba[0] = 3 * (v - vmin - 2 * dv / 3) / dv;
4005  rgba[1] = 1 - rgba[0];
4006  rgba[2] = 1;
4007  }
4008  break;
4009  case 10:
4010  if (v < (vmin + 0.2 * dv)) {
4011  rgba[0] = 0;
4012  rgba[1] = 5 * (v - vmin) / dv;
4013  rgba[2] = 1;
4014  } else if (v < (vmin + 0.4 * dv)) {
4015  rgba[0] = 0;
4016  rgba[1] = 1;
4017  rgba[2] = 1 + 5 * (vmin + 0.2 * dv - v) / dv;
4018  } else if (v < (vmin + 0.6 * dv)) {
4019  rgba[0] = 5 * (v - vmin - 0.4 * dv) / dv;
4020  rgba[1] = 1;
4021  rgba[2] = 0;
4022  } else if (v < (vmin + 0.8 * dv)) {
4023  rgba[0] = 1;
4024  rgba[1] = 1 - 5 * (v - vmin - 0.6 * dv) / dv;
4025  rgba[2] = 0;
4026  } else {
4027  rgba[0] = 1;
4028  rgba[1] = 5 * (v - vmin - 0.8 * dv) / dv;
4029  rgba[2] = 5 * (v - vmin - 0.8 * dv) / dv;
4030  }
4031  break;
4032  case 11:
4033  c1[0] = 200 / 255.0; c1[1] = 60 / 255.0; c1[2] = 0 / 255.0;
4034  c2[0] = 250 / 255.0; c2[1] = 160 / 255.0; c2[2] = 110 / 255.0;
4035  rgba[0] = (c2[0] - c1[0]) * (v - vmin) / dv + c1[0];
4036  rgba[1] = (c2[1] - c1[1]) * (v - vmin) / dv + c1[1];
4037  rgba[2] = (c2[2] - c1[2]) * (v - vmin) / dv + c1[2];
4038  break;
4039  case 12:
4040  c1[0] = 55 / 255.0; c1[1] = 55 / 255.0; c1[2] = 45 / 255.0;
4041  c2[0] = 200 / 255.0; c2[1] = 60 / 255.0; c2[2] = 0 / 255.0;
4042  c3[0] = 250 / 255.0; c3[1] = 160 / 255.0; c3[2] = 110 / 255.0;
4043  ratio = 0.4;
4044  vmid = vmin + ratio * dv;
4045  if (v < vmid) {
4046  rgba[0] = (c2[0] - c1[0]) * (v - vmin) / (ratio*dv) + c1[0];
4047  rgba[1] = (c2[1] - c1[1]) * (v - vmin) / (ratio*dv) + c1[1];
4048  rgba[2] = (c2[2] - c1[2]) * (v - vmin) / (ratio*dv) + c1[2];
4049  } else {
4050  rgba[0] = (c3[0] - c2[0]) * (v - vmid) / ((1-ratio)*dv) + c2[0];
4051  rgba[1] = (c3[1] - c2[1]) * (v - vmid) / ((1-ratio)*dv) + c2[1];
4052  rgba[2] = (c3[2] - c2[2]) * (v - vmid) / ((1-ratio)*dv) + c2[2];
4053  }
4054  break;
4055  case 13:
4056  c1[0] = 0 / 255.0; c1[1] = 255 / 255.0; c1[2] = 0 / 255.0;
4057  c2[0] = 255 / 255.0; c2[1] = 150 / 255.0; c2[2] = 0 / 255.0;
4058  c3[0] = 255 / 255.0; c3[1] = 250 / 255.0; c3[2] = 240 / 255.0;
4059  ratio = 0.3;
4060  vmid = vmin + ratio * dv;
4061  if (v < vmid) {
4062  rgba[0] = (c2[0] - c1[0]) * (v - vmin) / (ratio*dv) + c1[0];
4063  rgba[1] = (c2[1] - c1[1]) * (v - vmin) / (ratio*dv) + c1[1];
4064  rgba[2] = (c2[2] - c1[2]) * (v - vmin) / (ratio*dv) + c1[2];
4065  } else {
4066  rgba[0] = (c3[0] - c2[0]) * (v - vmid) / ((1-ratio)*dv) + c2[0];
4067  rgba[1] = (c3[1] - c2[1]) * (v - vmid) / ((1-ratio)*dv) + c2[1];
4068  rgba[2] = (c3[2] - c2[2]) * (v - vmid) / ((1-ratio)*dv) + c2[2];
4069  }
4070  break;
4071  case 14:
4072  rgba[0] = 1;
4073  rgba[1] = 1 - (v - vmin) / dv;
4074  rgba[2] = 0;
4075  break;
4076  case 15:
4077  if (v < (vmin + 0.25 * dv)) {
4078  rgba[0] = 0;
4079  rgba[1] = 4 * (v - vmin) / dv;
4080  rgba[2] = 1;
4081  } else if (v < (vmin + 0.5 * dv)) {
4082  rgba[0] = 0;
4083  rgba[1] = 1;
4084  rgba[2] = 1 - 4 * (v - vmin - 0.25 * dv) / dv;
4085  } else if (v < (vmin + 0.75 * dv)) {
4086  rgba[0] = 4 * (v - vmin - 0.5 * dv) / dv;
4087  rgba[1] = 1;
4088  rgba[2] = 0;
4089  } else {
4090  rgba[0] = 1;
4091  rgba[1] = 1;
4092  rgba[2] = 4 * (v - vmin - 0.75 * dv) / dv;
4093  }
4094  break;
4095  case 16:
4096  if (v < (vmin + 0.5 * dv)) {
4097  rgba[0] = 0.0;
4098  rgba[1] = 2 * (v - vmin) / dv;
4099  rgba[2] = 1 - 2 * (v - vmin) / dv;
4100  } else {
4101  rgba[0] = 2 * (v - vmin - 0.5 * dv) / dv;
4102  rgba[1] = 1 - 2 * (v - vmin - 0.5 * dv) / dv;
4103  rgba[2] = 0.0;
4104  }
4105  break;
4106  case 17:
4107  if (v < (vmin + 0.5 * dv)) {
4108  rgba[0] = 1.0;
4109  rgba[1] = 1 - 2 * (v - vmin) / dv;
4110  rgba[2] = 2 * (v - vmin) / dv;
4111  } else {
4112  rgba[0] = 1 - 2 * (v - vmin - 0.5 * dv) / dv;
4113  rgba[1] = 2 * (v - vmin - 0.5 * dv) / dv;
4114  rgba[2] = 1.0;
4115  }
4116  break;
4117  case 18:
4118  rgba[0] = 0;
4119  rgba[1] = (v - vmin) / (vmax - vmin);
4120  rgba[2] = 1;
4121  break;
4122  case 19:
4123  rgba[0] = (v - vmin) / (vmax - vmin);
4124  rgba[1] = rgba[0];
4125  rgba[2] = 1;
4126  break;
4127  case 20:
4128  c1[0] = 0 / 255.0; c1[1] = 160 / 255.0; c1[2] = 0 / 255.0;
4129  c2[0] = 180 / 255.0; c2[1] = 220 / 255.0; c2[2] = 0 / 255.0;
4130  c3[0] = 250 / 255.0; c3[1] = 220 / 255.0; c3[2] = 170 / 255.0;
4131  ratio = 0.3;
4132  vmid = vmin + ratio * dv;
4133  if (v < vmid) {
4134  rgba[0] = (c2[0] - c1[0]) * (v - vmin) / (ratio*dv) + c1[0];
4135  rgba[1] = (c2[1] - c1[1]) * (v - vmin) / (ratio*dv) + c1[1];
4136  rgba[2] = (c2[2] - c1[2]) * (v - vmin) / (ratio*dv) + c1[2];
4137  } else {
4138  rgba[0] = (c3[0] - c2[0]) * (v - vmid) / ((1-ratio)*dv) + c2[0];
4139  rgba[1] = (c3[1] - c2[1]) * (v - vmid) / ((1-ratio)*dv) + c2[1];
4140  rgba[2] = (c3[2] - c2[2]) * (v - vmid) / ((1-ratio)*dv) + c2[2];
4141  }
4142  break;
4143  }
4144 }
4145 
4146 }
4147 
4148 ////////////////////////////////////////////////////////////////////////////////
4149 ///Ctor.
4150 
4151 TGLLevelPalette::TGLLevelPalette()
4152  : fContours(0),
4153  fPaletteSize(0),
4154  fTexture(0),
4155  fMaxPaletteSize(0)
4156 {
4157 }
4158 
4159 ////////////////////////////////////////////////////////////////////////////////
4160 ///Try to find colors for palette.
4161 
4162 Bool_t TGLLevelPalette::GeneratePalette(UInt_t paletteSize, const Rgl::Range_t &zRange, Bool_t check)
4163 {
4164  if (!fMaxPaletteSize && check)
4165  glGetIntegerv(GL_MAX_TEXTURE_SIZE, &fMaxPaletteSize);
4166 
4167  if (!(zRange.second - zRange.first))
4168  return kFALSE;
4169 
4170  if (!paletteSize) {
4171  Error("TGLLevelPaletter::GeneratePalette",
4172  "Invalid palette size, must be a positive number");
4173  return kFALSE;
4174  }
4175 
4176  if (check && paletteSize > UInt_t(fMaxPaletteSize)) {
4177  Error("TGLLevelPalette::GeneratePalette",
4178  "Number of contours %d is too big for GL 1D texture, try to reduce it to %d",
4179  paletteSize, fMaxPaletteSize);
4180  return kFALSE;
4181  }
4182 
4183  UInt_t nearestPow2 = 2;
4184  while (nearestPow2 < paletteSize)
4185  nearestPow2 <<= 1;
4186 
4187  fTexels.resize(4 * nearestPow2);
4188  fPaletteSize = paletteSize;
4189 
4190  //Generate texels.
4191  const Int_t nColors = gStyle->GetNumberOfColors();
4192 
4193  //Map color index into index in real palette.
4194 
4195  for (UInt_t i = 0; i < paletteSize; ++i) {
4196  Int_t paletteInd = Int_t(nColors / Double_t(paletteSize) * i);
4197  if (paletteInd > nColors - 1)
4198  paletteInd = nColors - 1;
4199  Int_t colorInd = gStyle->GetColorPalette(paletteInd);
4200 
4201  if (const TColor *c = gROOT->GetColor(colorInd)) {
4202  Float_t rgb[3] = {};
4203  c->GetRGB(rgb[0], rgb[1], rgb[2]);
4204  fTexels[i * 4] = UChar_t(rgb[0] * 255);
4205  fTexels[i * 4 + 1] = UChar_t(rgb[1] * 255);
4206  fTexels[i * 4 + 2] = UChar_t(rgb[2] * 255);
4207  fTexels[i * 4 + 3] = 200;//alpha
4208  }
4209  }
4210 
4211  fZRange = zRange;
4212 
4213  return kTRUE;
4214 }
4215 
4216 ////////////////////////////////////////////////////////////////////////////////
4217 ///Clear :)
4218 
4219 void TGLLevelPalette::SetContours(const std::vector<Double_t> *cont)
4220 {
4221  fContours = cont;
4222 }
4223 
4224 ////////////////////////////////////////////////////////////////////////////////
4225 ///Enable 1D texture
4226 
4227 void TGLLevelPalette::EnableTexture(Int_t mode)const
4228 {
4229  glEnable(GL_TEXTURE_1D);
4230 
4231  glGenTextures(1, &fTexture);
4232 
4233  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
4234  glBindTexture(GL_TEXTURE_1D, fTexture);
4235  glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
4236  glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4237  glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4238  glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, fTexels.size() / 4, 0,
4239  GL_RGBA, GL_UNSIGNED_BYTE, &fTexels[0]);
4240  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GLint(mode));
4241 }
4242 
4243 ////////////////////////////////////////////////////////////////////////////////
4244 ///Disable 1D texture
4245 
4246 void TGLLevelPalette::DisableTexture()const
4247 {
4248  glDeleteTextures(1, &fTexture);
4249  glDisable(GL_TEXTURE_1D);
4250 }
4251 
4252 ////////////////////////////////////////////////////////////////////////////////
4253 ///Get. Palette. Size.
4254 
4255 Int_t TGLLevelPalette::GetPaletteSize()const
4256 {
4257  return Int_t(fPaletteSize);
4258 }
4259 
4260 ////////////////////////////////////////////////////////////////////////////////
4261 ///Get tex coordinate
4262 
4263 Double_t TGLLevelPalette::GetTexCoord(Double_t z)const
4264 {
4265  if (!fContours) {
4266  if (z - fZRange.first < 0)
4267  z = fZRange.first;
4268  else if (fZRange.second < z)
4269  z = fZRange.second;
4270 
4271  return (z - fZRange.first) / (fZRange.second - fZRange.first) * fPaletteSize / (fTexels.size() / 4);
4272  }
4273  /*
4274  //This part is wrong. To be fixed.
4275  std::vector<Double_t>::size_type i = 0, e = fContours->size();
4276 
4277  if (!e)
4278  return 0.;
4279 
4280  for (; i < e - 1; ++i) {
4281  if (z >= (*fContours)[i] && z <= (*fContours)[i + 1])
4282  return i / Double_t(fTexels.size() / 4);
4283  }
4284  */
4285 
4286  return 1.;
4287 }
4288 
4289 ////////////////////////////////////////////////////////////////////////////////
4290 ///Get color.
4291 
4292 const UChar_t *TGLLevelPalette::GetColour(Double_t z)const
4293 {
4294  if (z - fZRange.first < 0)
4295  z = fZRange.first;
4296  else if (fZRange.second < z)
4297  z = fZRange.second;
4298 
4299  UInt_t ind = UInt_t((z - fZRange.first) / (fZRange.second - fZRange.first) * fPaletteSize);
4300  if (ind >= fPaletteSize)
4301  ind = fPaletteSize - 1;
4302 
4303  return &fTexels[ind * 4];
4304 }
4305 
4306 ////////////////////////////////////////////////////////////////////////////////
4307 ///Get color.
4308 
4309 const UChar_t *TGLLevelPalette::GetColour(Int_t ind)const
4310 {
4311  return &fTexels[ind * 4];
4312 }