Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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#include <iostream>
17
18#include "THLimitsFinder.h"
19#include "TVirtualPad.h"
20#include "TVirtualX.h"
21#include "TStyle.h"
22#include "TGaxis.h"
23#include "TColor.h"
24#include "TError.h"
25#include "TAxis.h"
26#include "TMath.h"
27#include "TROOT.h"
28#include "TEnv.h"
29
30#include "TGLBoundingBox.h"
31#include "TGLCamera.h"
32#include "TGLPlotPainter.h"
33#include "TGLIncludes.h"
34#include "TGLQuadric.h"
35#include "TGLUtil.h"
36
37/** \class TGLVertex3
38\ingroup opengl
393 component (x/y/z) vertex class.
40
41This is part of collection of simple utility classes for GL only in
42TGLUtil.h/cxx. These provide const and non-const accessors Arr() &
43CArr() to a GL compatible internal field - so can be used directly
44with OpenGL C API calls - which TVector3 etc cannot (easily).
45They are not intended to be fully featured just provide minimum required.
46*/
47
49
50////////////////////////////////////////////////////////////////////////////////
51/// Construct a default (0.0, 0.0, 0.0) vertex
52
54{
55 Fill(0.0);
56}
57
58////////////////////////////////////////////////////////////////////////////////
59/// Construct a vertex with components (x,y,z)
60
65
66////////////////////////////////////////////////////////////////////////////////
67/// Construct a vertex with components (v[0], v[1], v[2])
68
70{
71 Set(v[0], v[1], v[2]);
72}
73
74////////////////////////////////////////////////////////////////////////////////
75/// Construct a vertex from 'other'
76
81
82////////////////////////////////////////////////////////////////////////////////
83/// Destroy vertex object
84
88
89////////////////////////////////////////////////////////////////////////////////
90/// Offset a vertex by vector 'shift'
91
93{
94 fVals[0] += shift[0];
95 fVals[1] += shift[1];
96 fVals[2] += shift[2];
97}
98
99////////////////////////////////////////////////////////////////////////////////
100/// Offset a vertex by components (xDelta, yDelta, zDelta)
101
103{
104 fVals[0] += xDelta;
105 fVals[1] += yDelta;
106 fVals[2] += zDelta;
107}
108
109////////////////////////////////////////////////////////////////////////////////
110
112{
113 fVals[0] = TMath::Min(fVals[0], other.fVals[0]);
114 fVals[1] = TMath::Min(fVals[1], other.fVals[1]);
115 fVals[2] = TMath::Min(fVals[2], other.fVals[2]);
116}
117
118////////////////////////////////////////////////////////////////////////////////
119
121{
122 fVals[0] = TMath::Max(fVals[0], other.fVals[0]);
123 fVals[1] = TMath::Max(fVals[1], other.fVals[1]);
124 fVals[2] = TMath::Max(fVals[2], other.fVals[2]);
125}
126
127////////////////////////////////////////////////////////////////////////////////
128/// Output vertex component values to std::cout
129
131{
132 std::cout << "(" << fVals[0] << "," << fVals[1] << "," << fVals[2] << ")" << std::endl;
133}
134
135/** \class TGLVector3
136\ingroup opengl
1373 component (x/y/z) vector class.
138
139This is part of collection of utility classes for GL in TGLUtil.h/cxx
140These provide const and non-const accessors Arr() / CArr() to a GL
141compatible internal field - so can be used directly with OpenGL C API
142calls. They are not intended to be fully featured just provide
143minimum required.
144*/
145
147
148////////////////////////////////////////////////////////////////////////////////
149/// Construct a vector with components (x,y,z)
150
155
156////////////////////////////////////////////////////////////////////////////////
157/// Construct a vector with components (src[0], src[1], src[2])
158
160 TGLVertex3(src[0], src[1], src[2])
161{
162}
163
164
165/** \class TGLLine3
166\ingroup opengl
1673D space, fixed length, line class, with direction / length 'vector',
168passing through point 'vertex'. Just wraps a TGLVector3 / TGLVertex3 pair.
169*/
170
172
173////////////////////////////////////////////////////////////////////////////////
174/// Construct 3D line running from 'start' to 'end'
175
176TGLLine3::TGLLine3(const TGLVertex3 & start, const TGLVertex3 & end) :
177 fVertex(start), fVector(end - start)
178{
179}
180
181////////////////////////////////////////////////////////////////////////////////
182/// Construct 3D line running from 'start', magnitude 'vect'
183
185 fVertex(start), fVector(vect)
186{
187}
188
189////////////////////////////////////////////////////////////////////////////////
190/// Set 3D line running from 'start' to 'end'
191
192void TGLLine3::Set(const TGLVertex3 & start, const TGLVertex3 & end)
193{
194 fVertex = start;
195 fVector = end - start;
196}
197
198////////////////////////////////////////////////////////////////////////////////
199/// Set 3D line running from start, magnitude 'vect'
200
201void TGLLine3::Set(const TGLVertex3 & start, const TGLVector3 & vect)
202{
203 fVertex = start;
204 fVector = vect;
205}
206
207////////////////////////////////////////////////////////////////////////////////
208/// Draw line in current basic GL color. Assume we are in the correct reference
209/// frame
210
211void TGLLine3::Draw() const
212{
215 glVertex3dv(End().CArr());
216 glEnd();
217}
218
219/** \class TGLRect
220\ingroup opengl
221Viewport (pixel base) 2D rectangle class.
222*/
223
225
226////////////////////////////////////////////////////////////////////////////////
227/// Construct empty rect object, corner (0,0), width/height 0
228
230 fX(0), fY(0), fWidth(0), fHeight(0)
231{
232}
233
234////////////////////////////////////////////////////////////////////////////////
235/// Construct rect object, corner (x,y), dimensions 'width', 'height'
236
238 fX(x), fY(y), fWidth(width), fHeight(height)
239{
240}
241
242////////////////////////////////////////////////////////////////////////////////
243/// Construct rect object, corner (x,y), dimensions 'width', 'height'
244
246 fX(x), fY(y), fWidth(width), fHeight(height)
247{
248}
249
250
251////////////////////////////////////////////////////////////////////////////////
252/// Destroy rect object
253
257
258////////////////////////////////////////////////////////////////////////////////
259/// Expand the rect to encompass point (x,y)
260
262{
263 Int_t delX = x - fX;
264 Int_t delY = y - fY;
265
266 if (delX > fWidth) {
267 fWidth = delX;
268 }
269 if (delY > fHeight) {
270 fHeight = delY;
271 }
272
273 if (delX < 0) {
274 fX = x;
275 fWidth += -delX;
276 }
277 if (delY < 0) {
278 fY = y;
279 fHeight += -delY;
280 }
281}
282
283////////////////////////////////////////////////////////////////////////////////
284/// Return the diagonal of the rectangle.
285
287{
288 const Double_t w = static_cast<Double_t>(fWidth);
289 const Double_t h = static_cast<Double_t>(fHeight);
290 return TMath::Nint(TMath::Sqrt(w*w + h*h));
291}
292
293////////////////////////////////////////////////////////////////////////////////
294/// Return overlap result (kInside, kOutside, kPartial) of this
295/// rect with 'other'
296
298{
299 using namespace Rgl;
300
301 if ((fX <= other.fX) && (fX + fWidth >= other.fX + other.fWidth) &&
302 (fY <= other.fY) && (fY + fHeight >= other.fY + other.fHeight))
303 {
304 return kInside;
305 }
306 else if ((fX >= other.fX + static_cast<Int_t>(other.fWidth)) ||
307 (fX + static_cast<Int_t>(fWidth) <= other.fX) ||
308 (fY >= other.fY + static_cast<Int_t>(other.fHeight)) ||
309 (fY + static_cast<Int_t>(fHeight) <= other.fY))
310 {
311 return kOutside;
312 }
313 else
314 {
315 return kPartial;
316 }
317}
318
319/** \class TGLPlane
320\ingroup opengl
3213D plane class - of format Ax + By + Cz + D = 0
322
323This is part of collection of simple utility classes for GL only in
324TGLUtil.h/cxx. These provide const and non-const accessors Arr() &
325CArr() to a GL compatible internal field - so can be used directly
326with OpenGL C API calls - which TVector3 etc cannot (easily).
327They are not intended to be fully featured just provide minimum
328required.
329*/
330
332
333////////////////////////////////////////////////////////////////////////////////
334/// Construct a default plane of x + y + z = 0
335
337{
338 Set(1.0, 1.0, 1.0, 0.0);
339}
340
341////////////////////////////////////////////////////////////////////////////////
342/// Construct plane from 'other'
343
345{
346 Set(other);
347}
348
349////////////////////////////////////////////////////////////////////////////////
350/// Construct plane with equation a.x + b.y + c.z + d = 0
351/// with optional normalisation
352
357
358////////////////////////////////////////////////////////////////////////////////
359/// Construct plane with equation eq[0].x + eq[1].y + eq[2].z + eq[3] = 0
360/// with optional normalisation
361
363{
364 Set(eq);
365}
366
367////////////////////////////////////////////////////////////////////////////////
368/// Construct plane passing through 3 supplied points
369/// with optional normalisation
370
372 const TGLVertex3 & p3)
373{
374 Set(p1, p2, p3);
375}
376
377////////////////////////////////////////////////////////////////////////////////
378/// Construct plane with supplied normal vector, passing through point
379/// with optional normalisation
380
382{
383 Set(v, p);
384}
385
386////////////////////////////////////////////////////////////////////////////////
387/// Assignment operator
388
390{
391 Set(src);
392 return *this;
393}
394
395////////////////////////////////////////////////////////////////////////////////
396/// Normalise the plane.
397
399{
400 Double_t mag = sqrt(fVals[0]*fVals[0] + fVals[1]*fVals[1] + fVals[2]*fVals[2]);
401
402 if (mag == 0.0 ) {
403 Error("TGLPlane::Normalise", "trying to normalise plane with zero magnitude normal");
404 return;
405 }
406 mag = 1.0 / mag;
407 fVals[0] *= mag;
408 fVals[1] *= mag;
409 fVals[2] *= mag;
410 fVals[3] *= mag;
411}
412
413////////////////////////////////////////////////////////////////////////////////
414/// Output plane equation to std::out
415
416void TGLPlane::Dump() const
417{
418 std::cout.precision(6);
419 std::cout << "Plane : " << fVals[0] << "x + " << fVals[1] << "y + " << fVals[2] << "z + " << fVals[3] << std::endl;
420}
421
422////////////////////////////////////////////////////////////////////////////////
423/// Assign from other.
424
426{
427 fVals[0] = other.fVals[0];
428 fVals[1] = other.fVals[1];
429 fVals[2] = other.fVals[2];
430 fVals[3] = other.fVals[3];
431}
432
433////////////////////////////////////////////////////////////////////////////////
434/// Set by values.
435
437{
438 fVals[0] = a;
439 fVals[1] = b;
440 fVals[2] = c;
441 fVals[3] = d;
442 Normalise();
443}
444
445////////////////////////////////////////////////////////////////////////////////
446/// Set by array values.
447
449{
450 fVals[0] = eq[0];
451 fVals[1] = eq[1];
452 fVals[2] = eq[2];
453 fVals[3] = eq[3];
454 Normalise();
455}
456
457////////////////////////////////////////////////////////////////////////////////
458/// Set plane from a normal vector and in-plane point pair
459
460void TGLPlane::Set(const TGLVector3 & norm, const TGLVertex3 & point)
461{
462 fVals[0] = norm[0];
463 fVals[1] = norm[1];
464 fVals[2] = norm[2];
465 fVals[3] = -(fVals[0]*point[0] + fVals[1]*point[1] + fVals[2]*point[2]);
466 Normalise();
467}
468
469////////////////////////////////////////////////////////////////////////////////
470/// Set plane by three points.
471
472void TGLPlane::Set(const TGLVertex3 & p1, const TGLVertex3 & p2, const TGLVertex3 & p3)
473{
474 TGLVector3 norm = Cross(p2 - p1, p3 - p1);
475 Set(norm, p2);
476}
477
478////////////////////////////////////////////////////////////////////////////////
479/// Negate the plane.
480
482{
483 fVals[0] = -fVals[0];
484 fVals[1] = -fVals[1];
485 fVals[2] = -fVals[2];
486 fVals[3] = -fVals[3];
487}
488
489////////////////////////////////////////////////////////////////////////////////
490/// Distance from plane to vertex.
491
493{
494 return (fVals[0]*vertex[0] + fVals[1]*vertex[1] + fVals[2]*vertex[2] + fVals[3]);
495}
496
497////////////////////////////////////////////////////////////////////////////////
498/// Return nearest point on plane.
499
501{
502 TGLVector3 o = Norm() * (Dot(Norm(), TGLVector3(point[0], point[1], point[2])) + D() / Dot(Norm(), Norm()));
503 TGLVertex3 v = point - o;
504 return v;
505}
506
507// Some free functions for plane intersections
508
509////////////////////////////////////////////////////////////////////////////////
510/// Find 3D line interestion of this plane with 'other'. Returns a std::pair
511///
512/// first (Bool_t) second (TGLLine3)
513/// kTRUE - planes intersect intersection line between planes
514/// kFALSE - no intersect (parallel) undefined
515
516std::pair<Bool_t, TGLLine3> Intersection(const TGLPlane & p1, const TGLPlane & p2)
517{
518 TGLVector3 lineDir = Cross(p1.Norm(), p2.Norm());
519
520 if (lineDir.Mag() == 0.0) {
521 return std::make_pair(kFALSE, TGLLine3(TGLVertex3(0.0, 0.0, 0.0),
522 TGLVector3(0.0, 0.0, 0.0)));
523 }
524 TGLVertex3 linePoint = Cross((p1.Norm()*p2.D() - p2.Norm()*p1.D()), lineDir) /
526 return std::make_pair(kTRUE, TGLLine3(linePoint, lineDir));
527}
528
529////////////////////////////////////////////////////////////////////////////////
530
531std::pair<Bool_t, TGLVertex3> Intersection(const TGLPlane & p1, const TGLPlane & p2, const TGLPlane & p3)
532{
533 Double_t denom = Dot(p1.Norm(), Cross(p2.Norm(), p3.Norm()));
534 if (denom == 0.0) {
535 return std::make_pair(kFALSE, TGLVertex3(0.0, 0.0, 0.0));
536 }
537 TGLVector3 vect = ((Cross(p2.Norm(),p3.Norm())* -p1.D()) -
538 (Cross(p3.Norm(),p1.Norm())*p2.D()) -
539 (Cross(p1.Norm(),p2.Norm())*p3.D())) / denom;
540 TGLVertex3 interVert(vect.X(), vect.Y(), vect.Z());
541 return std::make_pair(kTRUE, interVert);
542}
543
544////////////////////////////////////////////////////////////////////////////////
545/// Find intersection of 3D space 'line' with this plane. If 'extend' is kTRUE
546/// then line extents can be extended (infinite length) to find intersection.
547/// If 'extend' is kFALSE the fixed extents of line is respected.
548///
549/// The return a std::pair
550///
551/// - first (Bool_t) second (TGLVertex3)
552/// - kTRUE - line/plane intersect intersection vertex on plane
553/// - kFALSE - no line/plane intersect undefined
554///
555/// If intersection is not found (first == kFALSE) & 'extend' was kTRUE (infinite line)
556/// this implies line and plane are parallel. If 'extend' was kFALSE, then
557/// either line parallel or insufficient length.
558
559std::pair<Bool_t, TGLVertex3> Intersection(const TGLPlane & plane, const TGLLine3 & line, Bool_t extend)
560{
561 Double_t denom = -(plane.A()*line.Vector().X() +
562 plane.B()*line.Vector().Y() +
563 plane.C()*line.Vector().Z());
564
565 if (denom == 0.0) {
566 return std::make_pair(kFALSE, TGLVertex3(0.0, 0.0, 0.0));
567 }
568
569 Double_t num = plane.A()*line.Start().X() + plane.B()*line.Start().Y() +
570 plane.C()*line.Start().Z() + plane.D();
571 Double_t factor = num/denom;
572
573 // If not extending (projecting) line is length from start enough to reach plane?
574 if (!extend && (factor < 0.0 || factor > 1.0)) {
575 return std::make_pair(kFALSE, TGLVertex3(0.0, 0.0, 0.0));
576 }
577
578 TGLVector3 toPlane = line.Vector() * factor;
579 return std::make_pair(kTRUE, line.Start() + toPlane);
580}
581
582/** \class TGLMatrix
583\ingroup opengl
58416 component (4x4) transform matrix - column MAJOR as per GL.
585Provides limited support for adjusting the translation, scale and
586rotation components.
587
588This is part of collection of simple utility classes for GL only in
589TGLUtil.h/cxx. These provide const and non-const accessors Arr() &
590CArr() to a GL compatible internal field - so can be used directly
591with OpenGL C API calls - which TVector3 etc cannot (easily).
592They are not intended to be fully featured just provide minimum
593required.
594*/
595
597
598////////////////////////////////////////////////////////////////////////////////
599/// Construct default identity matrix:
600///
601/// 1 0 0 0
602/// 0 1 0 0
603/// 0 0 1 0
604/// 0 0 0 1
605
610
611////////////////////////////////////////////////////////////////////////////////
612/// Construct matrix with translation components x,y,z:
613///
614/// 1 0 0 x
615/// 0 1 0 y
616/// 0 0 1 z
617/// 0 0 0 1
618
624
625////////////////////////////////////////////////////////////////////////////////
626/// Construct matrix with translation components x,y,z:
627///
628/// 1 0 0 translation.X()
629/// 0 1 0 translation.Y()
630/// 0 0 1 translation.Z()
631/// 0 0 0 1
632
638
639////////////////////////////////////////////////////////////////////////////////
640/// Construct matrix which when applied puts local origin at
641/// 'origin' and the local Z axis in direction 'z'. Both
642/// 'origin' and 'zAxisVec' are expressed in the parent frame
643
645{
646 SetIdentity();
647
649 zAxisInt.Normalise();
651
652 if (TMath::Abs(zAxisInt.X()) <= TMath::Abs(zAxisInt.Y()) && TMath::Abs(zAxisInt.X()) <= TMath::Abs(zAxisInt.Z())) {
653 arbAxis.Set(1.0, 0.0, 0.0);
654 } else if (TMath::Abs(zAxisInt.Y()) <= TMath::Abs(zAxisInt.X()) && TMath::Abs(zAxisInt.Y()) <= TMath::Abs(zAxisInt.Z())) {
655 arbAxis.Set(0.0, 1.0, 0.0);
656 } else {
657 arbAxis.Set(0.0, 0.0, 1.0);
658 }
659
661}
662
663////////////////////////////////////////////////////////////////////////////////
664/// Construct matrix which when applied puts local origin at
665/// 'origin' and the local Z axis in direction 'z'. Both
666/// 'origin' and 'zAxisVec' are expressed in the parent frame
667
673
674////////////////////////////////////////////////////////////////////////////////
675/// Construct matrix using the 16 Double_t 'vals' passed,
676/// ordering is maintained - i.e. should be column major
677/// as we are
678
680{
681 Set(vals);
682}
683
684////////////////////////////////////////////////////////////////////////////////
685/// Construct matrix from 'other'
686
688{
689 *this = other;
690}
691
692////////////////////////////////////////////////////////////////////////////////
693/// Destroy matrix object
694
698
699////////////////////////////////////////////////////////////////////////////////
700/// Multiply with matrix rhs on right.
701
703{
704 Double_t B[4];
705 Double_t* C = fVals;
706 for(int r=0; r<4; ++r, ++C)
707 {
708 const Double_t* T = rhs.fVals;
709 for(int c=0; c<4; ++c, T+=4)
710 B[c] = C[0]*T[0] + C[4]*T[1] + C[8]*T[2] + C[12]*T[3];
711 C[0] = B[0]; C[4] = B[1]; C[8] = B[2]; C[12] = B[3];
712 }
713}
714
715////////////////////////////////////////////////////////////////////////////////
716/// Multiply with matrix lhs on left.
717
719{
720 Double_t B[4];
721 Double_t* C = fVals;
722 for (int c=0; c<4; ++c, C+=4)
723 {
724 const Double_t* T = lhs.fVals;
725 for(int r=0; r<4; ++r, ++T)
726 B[r] = T[0]*C[0] + T[4]*C[1] + T[8]*C[2] + T[12]*C[3];
727 C[0] = B[0]; C[1] = B[1]; C[2] = B[2]; C[3] = B[3];
728 }
729}
730
731////////////////////////////////////////////////////////////////////////////////
732/// Set matrix which when applied puts local origin at
733/// 'origin' and the local Z axis in direction 'z'. Both
734/// 'origin' and 'z' are expressed in the parent frame
735
737{
739 zAxisInt.Normalise();
740
742 xAxisInt.Normalise();
744
745 fVals[0] = xAxisInt.X(); fVals[4] = yAxisInt.X(); fVals[8 ] = zAxisInt.X(); fVals[12] = origin.X();
746 fVals[1] = xAxisInt.Y(); fVals[5] = yAxisInt.Y(); fVals[9 ] = zAxisInt.Y(); fVals[13] = origin.Y();
747 fVals[2] = xAxisInt.Z(); fVals[6] = yAxisInt.Z(); fVals[10] = zAxisInt.Z(); fVals[14] = origin.Z();
748 fVals[3] = 0.0; fVals[7] = 0.0; fVals[11] = 0.0; fVals[15] = 1.0;
749}
750
751////////////////////////////////////////////////////////////////////////////////
752/// Set matrix using the 16 Double_t 'vals' passed,
753/// ordering is maintained - i.e. should be column major.
754
755void TGLMatrix::Set(const Double_t vals[16])
756{
757 for (UInt_t i=0; i < 16; i++) {
758 fVals[i] = vals[i];
759 }
760}
761
762////////////////////////////////////////////////////////////////////////////////
763/// Set matrix to identity.
764
766{
767 fVals[0] = 1.0; fVals[4] = 0.0; fVals[8 ] = 0.0; fVals[12] = 0.0;
768 fVals[1] = 0.0; fVals[5] = 1.0; fVals[9 ] = 0.0; fVals[13] = 0.0;
769 fVals[2] = 0.0; fVals[6] = 0.0; fVals[10] = 1.0; fVals[14] = 0.0;
770 fVals[3] = 0.0; fVals[7] = 0.0; fVals[11] = 0.0; fVals[15] = 1.0;
771}
772
773////////////////////////////////////////////////////////////////////////////////
774/// Set matrix translation components x,y,z.
775
780
781////////////////////////////////////////////////////////////////////////////////
782/// Set matrix translation components x,y,z.
783
785{
786 fVals[12] = translation[0];
787 fVals[13] = translation[1];
788 fVals[14] = translation[2];
789}
790
791////////////////////////////////////////////////////////////////////////////////
792/// Return the translation component of matrix.
793
795{
796 return TGLVector3(fVals[12], fVals[13], fVals[14]);
797}
798
799////////////////////////////////////////////////////////////////////////////////
800/// Shift matrix translation components by 'vect' in parent frame.
801
803{
804 fVals[12] += vect[0];
805 fVals[13] += vect[1];
806 fVals[14] += vect[2];
807}
808
809////////////////////////////////////////////////////////////////////////////////
810/// Translate in local frame.
811/// i1, i2 are axes indices: 1 ~ x, 2 ~ y, 3 ~ z.
812
814{
815 const Double_t *C = fVals + 4*--ai;
816 fVals[12] += amount*C[0]; fVals[13] += amount*C[1]; fVals[14] += amount*C[2];
817}
818
819////////////////////////////////////////////////////////////////////////////////
820/// Translate in local frame along all base vectors simultaneously.
821
823{
824 fVals[12] += x*fVals[0] + y*fVals[4] + z*fVals[8];
825 fVals[13] += x*fVals[1] + y*fVals[5] + z*fVals[9];
826 fVals[14] += x*fVals[2] + y*fVals[6] + z*fVals[10];
827}
828
829////////////////////////////////////////////////////////////////////////////////
830/// Set matrix axis scales to 'scale'. Note - this really sets
831/// the overall (total) scaling for each axis - it does NOT
832/// apply compounded scale on top of existing one
833
835{
837
838 // x
839 if (currentScale[0] != 0.0) {
840 fVals[0] *= scale[0]/currentScale[0];
841 fVals[1] *= scale[0]/currentScale[0];
842 fVals[2] *= scale[0]/currentScale[0];
843 } else {
844 Error("TGLMatrix::Scale()", "zero scale div by zero");
845 }
846 // y
847 if (currentScale[1] != 0.0) {
848 fVals[4] *= scale[1]/currentScale[1];
849 fVals[5] *= scale[1]/currentScale[1];
850 fVals[6] *= scale[1]/currentScale[1];
851 } else {
852 Error("TGLMatrix::Scale()", "zero scale div by zero");
853 }
854 // z
855 if (currentScale[2] != 0.0) {
856 fVals[8] *= scale[2]/currentScale[2];
857 fVals[9] *= scale[2]/currentScale[2];
858 fVals[10] *= scale[2]/currentScale[2];
859 } else {
860 Error("TGLMatrix::Scale()", "zero scale div by zero");
861 }
862}
863
864////////////////////////////////////////////////////////////////////////////////
865/// Update matrix so resulting transform has been rotated about 'pivot'
866/// (in parent frame), round vector 'axis', through 'angle' (radians)
867/// Equivalent to glRotate function, but with addition of translation
868/// and compounded on top of existing.
869
871{
872 TGLVector3 nAxis = axis;
873 nAxis.Normalise();
874 Double_t x = nAxis.X();
875 Double_t y = nAxis.Y();
876 Double_t z = nAxis.Z();
879
880 // Calculate local rotation, with pre-translation to local pivot origin
882 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];
883 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];
884 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];
885 rotMat[ 3] = 0.0; rotMat[ 7] = 0.0; rotMat[11] = 0.0; rotMat[15] = 1.0;
887
888 // TODO: Ugly - should use quaternions to avoid compound rounding errors and
889 // triple multiplication
890 *this = rotMat * localToWorld * (*this);
891}
892
893////////////////////////////////////////////////////////////////////////////////
894/// Rotate in local frame. Does optimised version of MultRight.
895/// i1, i2 are axes indices: 1 ~ x, 2 ~ y, 3 ~ z.
896
898{
899 if(i1 == i2) return;
900 const Double_t cos = TMath::Cos(amount), sin = TMath::Sin(amount);
901 Double_t b1, b2;
902 Double_t* c = fVals;
903 --i1 <<= 2; --i2 <<= 2; // column major
904 for(int r=0; r<4; ++r, ++c) {
905 b1 = cos*c[i1] + sin*c[i2];
906 b2 = cos*c[i2] - sin*c[i1];
907 c[i1] = b1; c[i2] = b2;
908 }
909}
910
911////////////////////////////////////////////////////////////////////////////////
912/// Rotate in parent frame. Does optimised version of MultLeft.
913
915{
916 if(i1 == i2) return;
917
918 // Optimized version:
919 const Double_t cos = TMath::Cos(amount), sin = TMath::Sin(amount);
920 Double_t b1, b2;
921 Double_t* C = fVals;
922 --i1; --i2;
923 for(int c=0; c<4; ++c, C+=4) {
924 b1 = cos*C[i1] - sin*C[i2];
925 b2 = cos*C[i2] + sin*C[i1];
926 C[i1] = b1; C[i2] = b2;
927 }
928}
929
930////////////////////////////////////////////////////////////////////////////////
931/// Transform passed 'vertex' by this matrix - converts local frame to parent
932
934{
936 for (UInt_t i = 0; i < 3; i++) {
937 vertex[i] = orig[0] * fVals[0+i] + orig[1] * fVals[4+i] +
938 orig[2] * fVals[8+i] + fVals[12+i];
939 }
940}
941
942////////////////////////////////////////////////////////////////////////////////
943/// Transpose the top left 3x3 matrix component along major diagonal
944/// Supported as currently incompatibility between TGeo and GL matrix
945/// layouts for this 3x3 only. To be resolved.
946
948{
949 // TODO: Move this fix to the TBuffer3D filling side and remove
950 //
951 // 0 4 8 12
952 // 1 5 9 13
953 // 2 6 10 14
954 // 3 7 11 15
955
956 Double_t temp = fVals[4];
957 fVals[4] = fVals[1];
958 fVals[1] = temp;
959 temp = fVals[8];
960 fVals[8] = fVals[2];
961 fVals[2] = temp;
962 temp = fVals[9];
963 fVals[9] = fVals[6];
964 fVals[6] = temp;
965}
966
967////////////////////////////////////////////////////////////////////////////////
968/// Invert the matrix, returns determinant.
969/// Copied from TMatrixFCramerInv.
970
972{
973 Double_t* M = fVals;
974
975 const Double_t det2_12_01 = M[1]*M[6] - M[5]*M[2];
976 const Double_t det2_12_02 = M[1]*M[10] - M[9]*M[2];
977 const Double_t det2_12_03 = M[1]*M[14] - M[13]*M[2];
978 const Double_t det2_12_13 = M[5]*M[14] - M[13]*M[6];
979 const Double_t det2_12_23 = M[9]*M[14] - M[13]*M[10];
980 const Double_t det2_12_12 = M[5]*M[10] - M[9]*M[6];
981 const Double_t det2_13_01 = M[1]*M[7] - M[5]*M[3];
982 const Double_t det2_13_02 = M[1]*M[11] - M[9]*M[3];
983 const Double_t det2_13_03 = M[1]*M[15] - M[13]*M[3];
984 const Double_t det2_13_12 = M[5]*M[11] - M[9]*M[7];
985 const Double_t det2_13_13 = M[5]*M[15] - M[13]*M[7];
986 const Double_t det2_13_23 = M[9]*M[15] - M[13]*M[11];
987 const Double_t det2_23_01 = M[2]*M[7] - M[6]*M[3];
988 const Double_t det2_23_02 = M[2]*M[11] - M[10]*M[3];
989 const Double_t det2_23_03 = M[2]*M[15] - M[14]*M[3];
990 const Double_t det2_23_12 = M[6]*M[11] - M[10]*M[7];
991 const Double_t det2_23_13 = M[6]*M[15] - M[14]*M[7];
992 const Double_t det2_23_23 = M[10]*M[15] - M[14]*M[11];
993
994
995 const Double_t det3_012_012 = M[0]*det2_12_12 - M[4]*det2_12_02 + M[8]*det2_12_01;
996 const Double_t det3_012_013 = M[0]*det2_12_13 - M[4]*det2_12_03 + M[12]*det2_12_01;
997 const Double_t det3_012_023 = M[0]*det2_12_23 - M[8]*det2_12_03 + M[12]*det2_12_02;
998 const Double_t det3_012_123 = M[4]*det2_12_23 - M[8]*det2_12_13 + M[12]*det2_12_12;
999 const Double_t det3_013_012 = M[0]*det2_13_12 - M[4]*det2_13_02 + M[8]*det2_13_01;
1000 const Double_t det3_013_013 = M[0]*det2_13_13 - M[4]*det2_13_03 + M[12]*det2_13_01;
1001 const Double_t det3_013_023 = M[0]*det2_13_23 - M[8]*det2_13_03 + M[12]*det2_13_02;
1002 const Double_t det3_013_123 = M[4]*det2_13_23 - M[8]*det2_13_13 + M[12]*det2_13_12;
1003 const Double_t det3_023_012 = M[0]*det2_23_12 - M[4]*det2_23_02 + M[8]*det2_23_01;
1004 const Double_t det3_023_013 = M[0]*det2_23_13 - M[4]*det2_23_03 + M[12]*det2_23_01;
1005 const Double_t det3_023_023 = M[0]*det2_23_23 - M[8]*det2_23_03 + M[12]*det2_23_02;
1006 const Double_t det3_023_123 = M[4]*det2_23_23 - M[8]*det2_23_13 + M[12]*det2_23_12;
1007 const Double_t det3_123_012 = M[1]*det2_23_12 - M[5]*det2_23_02 + M[9]*det2_23_01;
1008 const Double_t det3_123_013 = M[1]*det2_23_13 - M[5]*det2_23_03 + M[13]*det2_23_01;
1009 const Double_t det3_123_023 = M[1]*det2_23_23 - M[9]*det2_23_03 + M[13]*det2_23_02;
1010 const Double_t det3_123_123 = M[5]*det2_23_23 - M[9]*det2_23_13 + M[13]*det2_23_12;
1011
1012 const Double_t det = M[0]*det3_123_123 - M[4]*det3_123_023 +
1013 M[8]*det3_123_013 - M[12]*det3_123_012;
1014
1015 if(det == 0) {
1016 Warning("TGLMatrix::Invert", "matrix is singular.");
1017 return 0;
1018 }
1019
1020 const Double_t oneOverDet = 1.0/det;
1021 const Double_t mn1OverDet = - oneOverDet;
1022
1023 M[0] = det3_123_123 * oneOverDet;
1024 M[4] = det3_023_123 * mn1OverDet;
1025 M[8] = det3_013_123 * oneOverDet;
1026 M[12] = det3_012_123 * mn1OverDet;
1027
1028 M[1] = det3_123_023 * mn1OverDet;
1029 M[5] = det3_023_023 * oneOverDet;
1030 M[9] = det3_013_023 * mn1OverDet;
1031 M[13] = det3_012_023 * oneOverDet;
1032
1033 M[2] = det3_123_013 * oneOverDet;
1034 M[6] = det3_023_013 * mn1OverDet;
1035 M[10] = det3_013_013 * oneOverDet;
1036 M[14] = det3_012_013 * mn1OverDet;
1037
1038 M[3] = det3_123_012 * mn1OverDet;
1039 M[7] = det3_023_012 * oneOverDet;
1040 M[11] = det3_013_012 * mn1OverDet;
1041 M[15] = det3_012_012 * oneOverDet;
1042
1043 return det;
1044}
1045
1046////////////////////////////////////////////////////////////////////////////////
1047/// Multiply vector.
1048
1050{
1051 const Double_t* M = fVals;
1052 TGLVector3 r;
1053 r.X() = M[0]*v[0] + M[4]*v[1] + M[8]*v[2] + M[12]*w;
1054 r.Y() = M[1]*v[0] + M[5]*v[1] + M[9]*v[2] + M[13]*w;
1055 r.Z() = M[2]*v[0] + M[6]*v[1] + M[10]*v[2] + M[14]*w;
1056 return r;
1057}
1058
1059////////////////////////////////////////////////////////////////////////////////
1060/// Rotate vector. Translation is not applied.
1061
1063{
1064 const Double_t* M = fVals;
1065 TGLVector3 r;
1066 r.X() = M[0]*v[0] + M[4]*v[1] + M[8]*v[2];
1067 r.Y() = M[1]*v[0] + M[5]*v[1] + M[9]*v[2];
1068 r.Z() = M[2]*v[0] + M[6]*v[1] + M[10]*v[2];
1069 return r;
1070}
1071
1072////////////////////////////////////////////////////////////////////////////////
1073/// Multiply vector in-place.
1074
1076{
1077 const Double_t* M = fVals;
1078 Double_t r[3] = { v[0], v[1], v[2] };
1079 v.X() = M[0]*r[0] + M[4]*r[1] + M[8]*r[2] + M[12]*w;
1080 v.Y() = M[1]*r[0] + M[5]*r[1] + M[9]*r[2] + M[13]*w;
1081 v.Z() = M[2]*r[0] + M[6]*r[1] + M[10]*r[2] + M[14]*w;
1082}
1083
1084////////////////////////////////////////////////////////////////////////////////
1085/// Rotate vector in-place. Translation is not applied.
1086
1088{
1089 const Double_t* M = fVals;
1090 Double_t r[3] = { v[0], v[1], v[2] };
1091 v.X() = M[0]*r[0] + M[4]*r[1] + M[8]*r[2];
1092 v.Y() = M[1]*r[0] + M[5]*r[1] + M[9]*r[2];
1093 v.Z() = M[2]*r[0] + M[6]*r[1] + M[10]*r[2];
1094}
1095
1096////////////////////////////////////////////////////////////////////////////////
1097/// Get local axis scaling factors
1098
1100{
1101 TGLVector3 x(fVals[0], fVals[1], fVals[2]);
1102 TGLVector3 y(fVals[4], fVals[5], fVals[6]);
1103 TGLVector3 z(fVals[8], fVals[9], fVals[10]);
1104 return TGLVector3(x.Mag(), y.Mag(), z.Mag());
1105}
1106
1107////////////////////////////////////////////////////////////////////////////////
1108/// Return true if matrix is to be considered a scaling matrix
1109/// for rendering.
1110
1112{
1113 Double_t ss;
1114 ss = fVals[0]*fVals[0] + fVals[1]*fVals[1] + fVals[2]*fVals[2];
1115 if (ss < 0.8 || ss > 1.2) return kTRUE;
1116 ss = fVals[4]*fVals[4] + fVals[5]*fVals[5] + fVals[6]*fVals[6];
1117 if (ss < 0.8 || ss > 1.2) return kTRUE;
1118 ss = fVals[8]*fVals[8] + fVals[9]*fVals[9] + fVals[10]*fVals[10];
1119 if (ss < 0.8 || ss > 1.2) return kTRUE;
1120 return kFALSE;
1121}
1122
1123////////////////////////////////////////////////////////////////////////////////
1124/// Output 16 matrix components to std::cout
1125///
1126/// 0 4 8 12
1127/// 1 5 9 13
1128/// 2 6 10 14
1129/// 3 7 11 15
1130///
1131
1133{
1134 std::cout.precision(6);
1135 for (Int_t x = 0; x < 4; x++) {
1136 std::cout << "[ ";
1137 for (Int_t y = 0; y < 4; y++) {
1138 std::cout << fVals[y*4 + x] << " ";
1139 }
1140 std::cout << "]" << std::endl;
1141 }
1142}
1143
1144
1145/** \class TGLColor
1146\ingroup opengl
1147Class encapsulating color information in preferred GL format - an
1148array of four unsigned bytes.
1149Color index is also cached for easier interfacing with the
1150traditional ROOT graphics.
1151*/
1152
1154
1155////////////////////////////////////////////////////////////////////////////////
1156/// Default constructor. Color is initialized to black.
1157
1159{
1160 fRGBA[0] = fRGBA[1] = fRGBA[2] = 0;
1161 fRGBA[3] = 255;
1162 fIndex = -1;
1163}
1164
1165////////////////////////////////////////////////////////////////////////////////
1166/// Constructor from Int_t values.
1167
1169{
1170 SetColor(r, g, b, a);
1171}
1172
1173////////////////////////////////////////////////////////////////////////////////
1174/// Constructor from Float_t values.
1175
1180
1181////////////////////////////////////////////////////////////////////////////////
1182/// Constructor from color-index and transparency.
1183
1188
1189////////////////////////////////////////////////////////////////////////////////
1190/// copy constructor
1191
1193{
1194 fRGBA[0] = c.fRGBA[0];
1195 fRGBA[1] = c.fRGBA[1];
1196 fRGBA[2] = c.fRGBA[2];
1197 fRGBA[3] = c.fRGBA[3];
1198 fIndex = c.fIndex;
1199}
1200
1201////////////////////////////////////////////////////////////////////////////////
1202/// Assignment operator.
1203
1205{
1206 fRGBA[0] = c.fRGBA[0];
1207 fRGBA[1] = c.fRGBA[1];
1208 fRGBA[2] = c.fRGBA[2];
1209 fRGBA[3] = c.fRGBA[3];
1210 fIndex = c.fIndex;
1211 return *this;
1212}
1213
1214////////////////////////////////////////////////////////////////////////////////
1215/// Returns color-index representing the color.
1216
1218{
1219 if (fIndex == -1)
1220 fIndex = TColor::GetColor(fRGBA[0], fRGBA[1], fRGBA[2]);
1221 return fIndex;
1222}
1223
1224////////////////////////////////////////////////////////////////////////////////
1225/// Returns transparency value.
1226
1228{
1229 return TMath::Nint(100.0*(1.0 - fRGBA[3]/255.0));
1230}
1231
1232////////////////////////////////////////////////////////////////////////////////
1233/// Set color with Int_t values.
1234
1236{
1237 fRGBA[0] = r;
1238 fRGBA[1] = g;
1239 fRGBA[2] = b;
1240 fRGBA[3] = a;
1241 fIndex = -1;
1242}
1243
1244////////////////////////////////////////////////////////////////////////////////
1245/// Set color with Float_t values.
1246
1248{
1249 fRGBA[0] = (UChar_t)(255*r);
1250 fRGBA[1] = (UChar_t)(255*g);
1251 fRGBA[2] = (UChar_t)(255*b);
1252 fRGBA[3] = (UChar_t)(255*a);
1253 fIndex = -1;
1254}
1255
1256////////////////////////////////////////////////////////////////////////////////
1257/// Set color by color-index. Alpha is not changed.
1258/// If color_index is not valid, color is set to magenta.
1259
1261{
1263 if (c)
1264 {
1265 fRGBA[0] = (UChar_t)(255*c->GetRed());
1266 fRGBA[1] = (UChar_t)(255*c->GetGreen());
1267 fRGBA[2] = (UChar_t)(255*c->GetBlue());
1269 }
1270 else
1271 {
1272 // Set to magenta.
1273 fRGBA[0] = 255;
1274 fRGBA[1] = 0;
1275 fRGBA[2] = 255;
1276 fIndex = -1;
1277 }
1278}
1279
1280////////////////////////////////////////////////////////////////////////////////
1281/// Set color by color-index and alpha from the transparency.
1282/// If color_index is not valid, color is set to magenta.
1283
1285{
1286 UChar_t alpha = (255*(100 - transparency))/100;
1287
1289 if (c)
1290 {
1291 fRGBA[0] = (UChar_t)(255*c->GetRed());
1292 fRGBA[1] = (UChar_t)(255*c->GetGreen());
1293 fRGBA[2] = (UChar_t)(255*c->GetBlue());
1294 fRGBA[3] = alpha;
1296 }
1297 else
1298 {
1299 // Set to magenta.
1300 fRGBA[0] = 255;
1301 fRGBA[1] = 0;
1302 fRGBA[2] = 255;
1303 fRGBA[3] = alpha;
1304 fIndex = -1;
1305 return;
1306 }
1307}
1308
1309////////////////////////////////////////////////////////////////////////////////
1310/// Set alpha from the transparency.
1311
1313{
1314 fRGBA[3] = (255*(100 - transparency))/100;
1315}
1316
1317////////////////////////////////////////////////////////////////////////////////
1318/// Return string describing the color.
1319
1321{
1322 return TString::Format("rgba:%02hhx/%02hhx/%02hhx/%02hhx",
1323 fRGBA[0], fRGBA[1], fRGBA[2], fRGBA[3]);
1324}
1325
1326
1327/** \class TGLColorSet
1328\ingroup opengl
1329Class encapsulating a set of colors used throughout standard rendering.
1330*/
1331
1333
1334////////////////////////////////////////////////////////////////////////////////
1335/// Constructor. Sets default for dark background.
1336
1341
1342////////////////////////////////////////////////////////////////////////////////
1343/// Copy constructor
1344
1346{
1349 fOutline = s.fOutline;
1350 fMarkup = s.fMarkup;
1351 for (Int_t i = 0; i < 5; ++i)
1352 fSelection[i] = s.fSelection[i];
1353}
1354
1355////////////////////////////////////////////////////////////////////////////////
1356/// Assignment operator.
1357
1359{
1362 fOutline = s.fOutline;
1363 fMarkup = s.fMarkup;
1364 for (Int_t i = 0; i < 5; ++i)
1365 fSelection[i] = s.fSelection[i];
1366 return *this;
1367}
1368
1369////////////////////////////////////////////////////////////////////////////////
1370/// Set defaults for dark (black) background.
1371
1373{
1374 fBackground .SetColor(0, 0, 0);
1375 fForeground .SetColor(255, 255, 255);
1376 fOutline .SetColor(240, 255, 240);
1377 fMarkup .SetColor(200, 200, 200);
1378
1379 fSelection[0].SetColor( 0, 0, 0);
1380 fSelection[1].SetColor(255, 220, 220);
1381 fSelection[2].SetColor(255, 220, 220);
1382 fSelection[3].SetColor(200, 200, 255);
1383 fSelection[4].SetColor(200, 200, 255);
1384}
1385
1386////////////////////////////////////////////////////////////////////////////////
1387/// Set defaults for light (white) background.
1388
1390{
1391 fBackground .SetColor(255, 255, 255);
1392 fForeground .SetColor(0, 0, 0);
1393 fOutline .SetColor(0, 0, 0);
1394 fMarkup .SetColor(55, 55, 55);
1395
1396 fSelection[0].SetColor(0, 0, 0);
1397 fSelection[1].SetColor(200, 100, 100);
1398 fSelection[2].SetColor(200, 100, 100);
1399 fSelection[3].SetColor(100, 100, 200);
1400 fSelection[4].SetColor(100, 100, 200);
1401}
1402
1403
1404/** \class TGLUtil
1405\ingroup opengl
1406Wrapper class for various misc static functions - error checking, draw helpers etc.
1407*/
1408
1410
1412UInt_t TGLUtil::fgDrawQuality = fgDefaultDrawQuality;
1414
1419
1423
1426
1429
1430const UChar_t TGLUtil::fgRed[4] = { 230, 0, 0, 255 };
1431const UChar_t TGLUtil::fgGreen[4] = { 0, 230, 0, 255 };
1432const UChar_t TGLUtil::fgBlue[4] = { 0, 0, 230, 255 };
1433const UChar_t TGLUtil::fgYellow[4] = { 210, 210, 0, 255 };
1434const UChar_t TGLUtil::fgWhite[4] = { 255, 255, 255, 255 };
1435const UChar_t TGLUtil::fgGrey[4] = { 128, 128, 128, 100 };
1436
1437#ifndef CALLBACK
1438#define CALLBACK
1439#endif
1440
1441extern "C"
1442{
1443#if defined(__APPLE_CC__) && __APPLE_CC__ > 4000 && __APPLE_CC__ < 5450 && !defined(__INTEL_COMPILER)
1444 typedef GLvoid (*tessfuncptr_t)(...);
1445#elif defined(__linux__) || defined(__FreeBSD__) || defined( __OpenBSD__ ) || defined(__sun) || defined (__CYGWIN__) || defined (__APPLE__)
1446 typedef GLvoid (*tessfuncptr_t)();
1447#elif defined (WIN32)
1448 typedef GLvoid (CALLBACK *tessfuncptr_t)();
1449#else
1450 #error "Error - need to define type tessfuncptr_t for this platform/compiler"
1451#endif
1452}
1453
1454namespace
1455{
1456
1457class TGLTesselatorWrap
1458{
1459protected:
1460
1461public:
1462 GLUtesselator *fTess;
1463
1464 TGLTesselatorWrap(tessfuncptr_t vertex_func) : fTess(nullptr)
1465 {
1466 fTess = gluNewTess();
1467 if (!fTess)
1468 throw std::bad_alloc();
1469
1470#if defined(__GNUC__) && __GNUC__ >= 8
1471#pragma GCC diagnostic push
1472#pragma GCC diagnostic ignored "-Wcast-function-type"
1473#endif
1474
1478
1479#if defined(__GNUC__) && __GNUC__ >= 8
1480#pragma GCC diagnostic pop
1481#endif
1482
1483 }
1484
1485 virtual ~TGLTesselatorWrap()
1486 {
1487 if (fTess)
1488 gluDeleteTess(fTess);
1489 }
1490};
1491
1492}
1493
1494////////////////////////////////////////////////////////////////////////////////
1495/// Returns a tesselator for direct drawing when using 3-vertices with
1496/// single precision.
1497
1499{
1500
1501#if defined(__GNUC__) && __GNUC__ >= 8
1502#pragma GCC diagnostic push
1503#pragma GCC diagnostic ignored "-Wcast-function-type"
1504#endif
1505
1506 static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex3fv);
1507
1508#if defined(__GNUC__) && __GNUC__ >= 8
1509#pragma GCC diagnostic pop
1510#endif
1511
1512 return singleton.fTess;
1513}
1514
1515////////////////////////////////////////////////////////////////////////////////
1516/// Returns a tesselator for direct drawing when using 4-vertices with
1517/// single precision.
1518
1520{
1521
1522#if defined(__GNUC__) && __GNUC__ >= 8
1523#pragma GCC diagnostic push
1524#pragma GCC diagnostic ignored "-Wcast-function-type"
1525#endif
1526
1527 static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex4fv);
1528
1529#if defined(__GNUC__) && __GNUC__ >= 8
1530#pragma GCC diagnostic pop
1531#endif
1532
1533 return singleton.fTess;
1534}
1535
1536////////////////////////////////////////////////////////////////////////////////
1537/// Returns a tesselator for direct drawing when using 3-vertices with
1538/// double precision.
1539
1541{
1542
1543#if defined(__GNUC__) && __GNUC__ >= 8
1544#pragma GCC diagnostic push
1545#pragma GCC diagnostic ignored "-Wcast-function-type"
1546#endif
1547
1548 static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex3dv);
1549
1550#if defined(__GNUC__) && __GNUC__ >= 8
1551#pragma GCC diagnostic pop
1552#endif
1553
1554 return singleton.fTess;
1555}
1556
1557////////////////////////////////////////////////////////////////////////////////
1558/// Returns a tesselator for direct drawing when using 4-vertices with
1559/// double precision.
1560
1562{
1563
1564#if defined(__GNUC__) && __GNUC__ >= 8
1565#pragma GCC diagnostic push
1566#pragma GCC diagnostic ignored "-Wcast-function-type"
1567#endif
1568
1569 static TGLTesselatorWrap singleton((tessfuncptr_t) glVertex4dv);
1570
1571#if defined(__GNUC__) && __GNUC__ >= 8
1572#pragma GCC diagnostic pop
1573#endif
1574
1575 return singleton.fTess;
1576}
1577
1578////////////////////////////////////////////////////////////////////////////////
1579/// Initialize globals that require other libraries to be initialized.
1580/// This is called from TGLWidget creation function.
1581
1583{
1584 static Bool_t init_done = kFALSE;
1585 if (init_done) return;
1586 init_done = kTRUE;
1587
1588 fgScreenScalingFactor = gVirtualX->GetOpenGLScalingFactor();
1589
1590 if (strcmp(gEnv->GetValue("OpenGL.PointLineScalingFactor", "native"), "native") == 0)
1591 {
1593 }
1594 else
1595 {
1596 fgPointLineScalingFactor = gEnv->GetValue("OpenGL.PointLineScalingFactor", 1.0);
1597 }
1598
1599 fgPickingRadius = TMath::Nint(gEnv->GetValue("OpenGL.PickingRadius", 3.0) * TMath::Sqrt(fgScreenScalingFactor));
1600}
1601
1602////////////////////////////////////////////////////////////////////////////////
1603///static: get draw quality
1604
1609
1610////////////////////////////////////////////////////////////////////////////////
1611///static: set draw quality
1612
1617
1618////////////////////////////////////////////////////////////////////////////////
1619///static: reset draw quality
1620
1625
1626////////////////////////////////////////////////////////////////////////////////
1627///static: get default draw quality
1628
1633
1634////////////////////////////////////////////////////////////////////////////////
1635///static: set default draw quality
1636
1641
1642////////////////////////////////////////////////////////////////////////////////
1643/// Check current GL error state, outputting details via ROOT
1644/// Error method if one
1645
1647{
1649 const GLubyte *errString;
1650
1651 if ((errCode = glGetError()) != GL_NO_ERROR) {
1653 if (loc) {
1654 Error(loc, "GL Error %s", (const char *)errString);
1655 } else {
1656 Error("TGLUtil::CheckError", "GL Error %s", (const char *)errString);
1657 }
1658 }
1659 return errCode;
1660}
1661
1662/******************************************************************************/
1663// Color wrapping functions
1664/******************************************************************************/
1665
1666////////////////////////////////////////////////////////////////////////////////
1667/// Prevent further color changes.
1668
1670{
1671 return ++fgColorLockCount;
1672}
1673
1674////////////////////////////////////////////////////////////////////////////////
1675/// Allow color changes.
1676
1678{
1679 if (fgColorLockCount)
1681 else
1682 Error("TGLUtil::UnlockColor", "fgColorLockCount already 0.");
1683 return fgColorLockCount;
1684}
1685
1686////////////////////////////////////////////////////////////////////////////////
1687/// Returns true if color lock-count is greater than 0.
1688
1690{
1691 return fgColorLockCount > 0;
1692}
1693
1694////////////////////////////////////////////////////////////////////////////////
1695/// Set color from TGLColor.
1696
1697void TGLUtil::Color(const TGLColor& color)
1698{
1699 if (fgColorLockCount == 0) glColor4ubv(color.CArr());
1700}
1701
1702////////////////////////////////////////////////////////////////////////////////
1703/// Set color from TGLColor and alpha value.
1704
1705void TGLUtil::ColorAlpha(const TGLColor& color, UChar_t alpha)
1706{
1707 if (fgColorLockCount == 0)
1708 {
1709 glColor4ub(color.GetRed(), color.GetGreen(), color.GetBlue(), alpha);
1710 }
1711}
1712
1713////////////////////////////////////////////////////////////////////////////////
1714/// Set color from TGLColor and alpha value.
1715
1716void TGLUtil::ColorAlpha(const TGLColor& color, Float_t alpha)
1717{
1718 if (fgColorLockCount == 0)
1719 {
1720 glColor4ub(color.GetRed(), color.GetGreen(), color.GetBlue(), (UChar_t)(255*alpha));
1721 }
1722}
1723
1724////////////////////////////////////////////////////////////////////////////////
1725/// Set color from color_index and GL-style alpha (default 1).
1726
1728{
1729 if (fgColorLockCount == 0) {
1730 if (color_index < 0)
1731 color_index = 1;
1733 if (c)
1734 glColor4f(c->GetRed(), c->GetGreen(), c->GetBlue(), alpha);
1735 }
1736}
1737
1738////////////////////////////////////////////////////////////////////////////////
1739/// Set color from color_index and ROOT-style transparency (default 0).
1740
1742{
1743 if (fgColorLockCount == 0) {
1744 if (color_index < 0)
1745 color_index = 1;
1747 if (c)
1748 glColor4f(c->GetRed(), c->GetGreen(), c->GetBlue(), 1.0f - 0.01f*transparency);
1749 }
1750}
1751
1752////////////////////////////////////////////////////////////////////////////////
1753/// Wrapper for glColor3ub.
1754
1756{
1757 if (fgColorLockCount == 0) glColor3ub(r, g, b);
1758}
1759
1760////////////////////////////////////////////////////////////////////////////////
1761/// Wrapper for glColor4ub.
1762
1764{
1765 if (fgColorLockCount == 0) glColor4ub(r, g, b, a);
1766}
1767
1768////////////////////////////////////////////////////////////////////////////////
1769/// Wrapper for glColor3ubv.
1770
1772{
1773 if (fgColorLockCount == 0) glColor3ubv(rgb);
1774}
1775
1776////////////////////////////////////////////////////////////////////////////////
1777/// Wrapper for glColor4ubv.
1778
1780{
1782}
1783
1784////////////////////////////////////////////////////////////////////////////////
1785/// Wrapper for glColor3f.
1786
1788{
1789 if (fgColorLockCount == 0) glColor3f(r, g, b);
1790}
1791
1792////////////////////////////////////////////////////////////////////////////////
1793/// Wrapper for glColor4f.
1794
1796{
1797 if (fgColorLockCount == 0) glColor4f(r, g, b, a);
1798}
1799
1800////////////////////////////////////////////////////////////////////////////////
1801/// Wrapper for glColor3fv.
1802
1804{
1805 if (fgColorLockCount == 0) glColor3fv(rgb);
1806}
1807
1808////////////////////////////////////////////////////////////////////////////////
1809/// Wrapper for glColor4fv.
1810
1812{
1813 if (fgColorLockCount == 0) glColor4fv(rgba);
1814}
1815
1816/******************************************************************************/
1817// Coordinate conversion and extra scaling (needed for osx retina)
1818/******************************************************************************/
1819
1820////////////////////////////////////////////////////////////////////////////////
1821/// Convert from point/screen coordinates to GL viewport coordinates.
1822
1824{
1825 if (fgScreenScalingFactor != 1.0)
1826 {
1829 }
1830}
1831
1832////////////////////////////////////////////////////////////////////////////////
1833/// Convert from point/screen coordinates to GL viewport coordinates.
1834
1845
1846////////////////////////////////////////////////////////////////////////////////
1847/// Returns scaling factor between screen points and GL viewport pixels.
1848/// This is what is returned by gVirtualX->GetOpenGLScalingFactor() but is
1849/// cached here to avoid a virtual function call as it is used quite often in
1850/// TGLPhysical shape when drawing the selection highlight.
1851
1856
1857////////////////////////////////////////////////////////////////////////////////
1858/// Return extra scaling factor for points and lines.
1859/// By default this is set to the same value as ScreenScalingFactor to keep
1860/// the same appearance. To override use rootrc entry, e.g.:
1861/// OpenGL.PointLineScalingFactor: 1.0
1862
1867
1868////////////////////////////////////////////////////////////////////////////////
1869/// Returns picking radius.
1870
1875
1876/******************************************************************************/
1877// Control for scaling of point-size and line-width.
1878/******************************************************************************/
1879
1880////////////////////////////////////////////////////////////////////////////////
1881/// Get global point-size scale.
1882
1887
1888////////////////////////////////////////////////////////////////////////////////
1889/// Set global point-size scale.
1890
1895
1896////////////////////////////////////////////////////////////////////////////////
1897/// Returns global line-width scale.
1898
1903
1904////////////////////////////////////////////////////////////////////////////////
1905/// Set global line-width scale.
1906
1911
1912////////////////////////////////////////////////////////////////////////////////
1913/// Set the point-size, taking the global scaling into account.
1914/// Wrapper for glPointSize.
1915
1921
1922////////////////////////////////////////////////////////////////////////////////
1923/// Set the line-width, taking the global scaling into account.
1924/// Wrapper for glLineWidth.
1925
1931
1932////////////////////////////////////////////////////////////////////////////////
1933/// Get the point-size, taking the global scaling into account.
1934
1936{
1937 return fgPointSize;
1938}
1939
1940////////////////////////////////////////////////////////////////////////////////
1941/// Get the line-width, taking the global scaling into account.
1942
1944{
1945 return fgLineWidth;
1946}
1947
1948/******************************************************************************/
1949// Rendering of polymarkers and lines from logical-shapes.
1950/******************************************************************************/
1951
1953{
1954 // Extend pick region for large point-sizes or line-widths.
1955
1957 glPushMatrix();
1958 Float_t pm[16];
1960 for (Int_t i=0; i<=12; i+=4) {
1961 pm[i] *= scale; pm[i+1] *= scale;
1962 }
1965}
1966
1968{
1969 // End extension of the pick region.
1970
1972 glPopMatrix();
1974}
1975
1976////////////////////////////////////////////////////////////////////////////////
1977/// Render polymarkers at points specified by p-array.
1978/// Supports point and cross-like styles.
1979
1981 Float_t* p, Int_t n,
1984{
1985 if (n == 0) return;
1986
1988
1991
1992 Int_t s = marker.GetMarkerStyle();
1993 if (s == 2 || s == 3 || s == 5 || s == 28)
1994 RenderCrosses(marker, p, n, sec_selection);
1995 else
1997
1998 glPopAttrib();
1999}
2000
2001////////////////////////////////////////////////////////////////////////////////
2002/// Render polymarkers at points specified by p-array.
2003/// Supports point and cross-like styles.
2004/// Color is set externally. Lighting is disabled externally.
2005
2006void TGLUtil::RenderPolyMarkers(const TAttMarker &marker, const std::vector<Double_t> &points,
2008{
2009 const Int_t s = marker.GetMarkerStyle();
2010 if (s == 2 || s == 3 || s == 5 || s == 28)
2011 RenderCrosses(marker, points, dX, dY, dZ);
2012 else
2013 RenderPoints(marker, points);
2014}
2015
2016////////////////////////////////////////////////////////////////////////////////
2017/// Render markers as circular or square points.
2018/// Color is never changed.
2019
2021 Float_t* op, Int_t n,
2024{
2025 Int_t style = marker.GetMarkerStyle();
2026 Float_t size = 5*marker.GetMarkerSize();
2027 if (style == 4 || style == 20 || style == 24)
2028 {
2030 if (style == 4 || style == 24) {
2034 }
2035 }
2036 else
2037 {
2039 if (style == 1) size = 1;
2040 else if (style == 6) size = 2;
2041 else if (style == 7) size = 3;
2042 }
2044
2045 // During selection extend picking region for large point-sizes.
2047 if (changePM)
2049
2050 Float_t* p = op;
2051 if (sec_selection)
2052 {
2053 glPushName(0);
2054 for (Int_t i=0; i<n; ++i, p+=3)
2055 {
2056 glLoadName(i);
2058 glVertex3fv(p);
2059 glEnd();
2060 }
2061 glPopName();
2062 }
2063 else
2064 {
2066 glVertexPointer(3, GL_FLOAT, 0, p);
2068 { // Circumvent bug in ATI's linux drivers.
2069 Int_t nleft = n;
2070 Int_t ndone = 0;
2071 const Int_t maxChunk = 8192;
2072 while (nleft > maxChunk)
2073 {
2075 nleft -= maxChunk;
2076 ndone += maxChunk;
2077 }
2079 }
2081 }
2082
2083 if (changePM)
2085}
2086
2087////////////////////////////////////////////////////////////////////////////////
2088/// Render markers as circular or square points.
2089/// Color is never changed.
2090
2091void TGLUtil::RenderPoints(const TAttMarker& marker, const std::vector<Double_t> &points)
2092{
2093 const Int_t style = marker.GetMarkerStyle();
2094 Float_t size = 5 * marker.GetMarkerSize();
2095
2096 if (style == 4 || style == 20 || style == 24)
2097 {
2099 if (style == 4 || style == 24) {
2103 }
2104 }
2105 else
2106 {
2108 if (style == 1) size = 1;
2109 else if (style == 6) size = 2;
2110 else if (style == 7) size = 3;
2111 }
2112
2114
2115 glVertexPointer(3, GL_DOUBLE, 0, &points[0]);
2117
2118 // Circumvent bug in ATI's linux drivers.
2119 Int_t nleft = points.size() / 3;
2120 Int_t ndone = 0;
2121 const Int_t maxChunk = 8192;
2122 while (nleft > maxChunk)
2123 {
2125 nleft -= maxChunk;
2126 ndone += maxChunk;
2127 }
2128
2129 if (nleft > 0)
2131
2133 glPointSize(1.f);
2134}
2135
2136////////////////////////////////////////////////////////////////////////////////
2137/// Render markers as crosses.
2138/// Color is never changed.
2139
2141 Float_t* op, Int_t n,
2143{
2144 if (marker.GetMarkerStyle() == 28)
2145 {
2149 }
2150 else
2151 {
2154 }
2155
2156 // cross dim
2157 const Float_t d = 2*marker.GetMarkerSize();
2158 Float_t* p = op;
2159 if (sec_selection)
2160 {
2161 glPushName(0);
2162 for (Int_t i=0; i<n; ++i, p+=3)
2163 {
2164 glLoadName(i);
2166 glVertex3f(p[0]-d, p[1], p[2]); glVertex3f(p[0]+d, p[1], p[2]);
2167 glVertex3f(p[0], p[1]-d, p[2]); glVertex3f(p[0], p[1]+d, p[2]);
2168 glVertex3f(p[0], p[1], p[2]-d); glVertex3f(p[0], p[1], p[2]+d);
2169 glEnd();
2170 }
2171 glPopName();
2172 }
2173 else
2174 {
2176 for (Int_t i=0; i<n; ++i, p+=3)
2177 {
2178 glVertex3f(p[0]-d, p[1], p[2]); glVertex3f(p[0]+d, p[1], p[2]);
2179 glVertex3f(p[0], p[1]-d, p[2]); glVertex3f(p[0], p[1]+d, p[2]);
2180 glVertex3f(p[0], p[1], p[2]-d); glVertex3f(p[0], p[1], p[2]+d);
2181 }
2182 glEnd();
2183 }
2184
2185 // Anti-flickering -- when crosses get too small they
2186 // appear / disappear randomly.
2187 {
2190
2192 glVertexPointer(3, GL_FLOAT, 0, op);
2194 { // Circumvent bug in ATI's linux drivers.
2195 Int_t nleft = n;
2196 Int_t ndone = 0;
2197 const Int_t maxChunk = 8192;
2198 while (nleft > maxChunk)
2199 {
2201 nleft -= maxChunk;
2202 ndone += maxChunk;
2203 }
2205 }
2207 }
2208}
2209
2210////////////////////////////////////////////////////////////////////////////////
2211/// Render markers as crosses.
2212/// Color is never changed.
2213
2214void TGLUtil::RenderCrosses(const TAttMarker& marker, const std::vector<Double_t> &points,
2216{
2217 if (marker.GetMarkerStyle() == 28)
2218 {
2221 glLineWidth(2.f);
2222 }
2223 else
2224 {
2226 glLineWidth(1.f);
2227 }
2228
2229 typedef std::vector<Double_t>::size_type size_type;
2230
2232
2233 for (size_type i = 0; i < points.size(); i += 3) {
2234 const Double_t *p = &points[i];
2235 glVertex3f(p[0] - dX, p[1], p[2]); glVertex3f(p[0] + dX, p[1], p[2]);
2236 glVertex3f(p[0], p[1] - dY, p[2]); glVertex3f(p[0], p[1] + dY, p[2]);
2237 glVertex3f(p[0], p[1], p[2] - dZ); glVertex3f(p[0], p[1], p[2] + dZ);
2238 }
2239
2240 glEnd();
2241
2242 if (marker.GetMarkerStyle() == 28) {
2245 glLineWidth(1.f);
2246 }
2247}
2248
2249////////////////////////////////////////////////////////////////////////////////
2250/// Render poly-line as specified by the p-array.
2251
2253 Float_t* p, Int_t n,
2255{
2256 if (n == 0) return;
2257
2259
2260 Float_t* tp = p;
2262 for (Int_t i=0; i<n; ++i, tp+=3)
2263 glVertex3fv(tp);
2264 glEnd();
2265
2267}
2268
2269////////////////////////////////////////////////////////////////////////////////
2270/// Setup drawing parameters according to passed TAttLine.
2271
2274{
2276
2278 TGLUtil::ColorTransparency(aline.GetLineColor(), transp);
2279 TGLUtil::LineWidth(aline.GetLineWidth());
2280 if (aline.GetLineStyle() > 1)
2281 {
2282 // Int_t fac = 1;
2283 UShort_t pat = 0xffff;
2284 switch (aline.GetLineStyle()) {
2285 case 2: pat = 0x3333; break;
2286 case 3: pat = 0x5555; break;
2287 case 4: pat = 0xf040; break;
2288 case 5: pat = 0xf4f4; break;
2289 case 6: pat = 0xf111; break;
2290 case 7: pat = 0xf0f0; break;
2291 case 8: pat = 0xff11; break;
2292 case 9: pat = 0x3fff; break;
2293 case 10: pat = 0x08ff; /* fac = 2; */ break;
2294 }
2295
2296 glLineStipple(1, pat);
2298 }
2299
2300 // During selection extend picking region for large line-widths.
2303}
2304
2305////////////////////////////////////////////////////////////////////////////////
2306/// Restore previous line drawing state.
2307
2315
2316/******************************************************************************/
2317// Rendering atoms used by TGLViewer / TGScene.
2318/******************************************************************************/
2319
2320////////////////////////////////////////////////////////////////////////////////
2321/// Set basic draw colors from 4 component 'rgba'
2322/// Used by other TGLUtil drawing routines
2323///
2324/// Sets basic (unlit) color - glColor
2325/// and also GL materials (see OpenGL docs) thus:
2326///
2327/// diffuse : rgba
2328/// ambient : 0.0 0.0 0.0 1.0
2329/// specular : 0.6 0.6 0.6 1.0
2330/// emission : rgba/4.0
2331/// shininess: 60.0
2332///
2333/// emission is set so objects with no lights (but lighting still enabled)
2334/// are partially visible
2335
2337{
2338
2339 // Util function to setup GL color for both unlit and lit material
2340 Float_t rgba[4] = {rgbai[0]/255.f, rgbai[1]/255.f, rgbai[2]/255.f, rgbai[3]/255.f};
2341 Float_t ambient[4] = {0.0, 0.0, 0.0, 1.0};
2342 Float_t specular[4] = {0.6, 0.6, 0.6, 1.0};
2343 Float_t emission[4] = {rgba[0]/4.f, rgba[1]/4.f, rgba[2]/4.f, rgba[3]};
2344
2351}
2352
2353////////////////////////////////////////////////////////////////////////////////
2354/// Draw sphere, centered on vertex 'position', with radius 'radius',
2355/// color 'rgba'
2356
2358 const UChar_t rgba[4])
2359{
2360 static TGLQuadric quad;
2362 glPushMatrix();
2363 glTranslated(position.X(), position.Y(), position.Z());
2365 glPopMatrix();
2366}
2367
2368////////////////////////////////////////////////////////////////////////////////
2369/// Draw thick line (tube) defined by 'line', with head at end shape
2370/// 'head' - box/arrow/none, (head) size 'size', color 'rgba'
2371
2373 const UChar_t rgba[4])
2374{
2375 DrawLine(line.Start(), line.Vector(), head, size, rgba);
2376}
2377
2378////////////////////////////////////////////////////////////////////////////////
2379/// Draw thick line (tube) running from 'start', length 'vector',
2380/// with head at end of shape 'head' - box/arrow/none,
2381/// (head) size 'size', color 'rgba'
2382
2383void TGLUtil::DrawLine(const TGLVertex3 & start, const TGLVector3 & vector,
2384 ELineHeadShape head, Double_t size, const UChar_t rgba[4])
2385{
2386 static TGLQuadric quad;
2387
2388 // Draw 3D line (tube) with optional head shape
2390 glPushMatrix();
2391 TGLMatrix local(start, vector);
2392 glMultMatrixd(local.CArr());
2393
2395 if (head == kLineHeadNone) {
2396 headHeight = 0.0;
2397 } else if (head == kLineHeadArrow) {
2398 headHeight = size*2.0;
2399 } else if (head == kLineHeadBox) {
2400 headHeight = size*1.4;
2401 }
2402
2403 // Line (tube) component
2404 gluCylinder(quad.Get(), 0.25*size, 0.25*size, vector.Mag() - headHeight, fgDrawQuality, 1);
2406 gluDisk(quad.Get(), 0.0, 0.25*size, fgDrawQuality, 1);
2407
2408 glTranslated(0.0, 0.0, vector.Mag() - headHeight); // Shift down local Z to end of line
2409
2410 if (head == kLineHeadNone) {
2411 // Cap end of line
2413 gluDisk(quad.Get(), 0.0, size/4.0, fgDrawQuality, 1);
2414 }
2415 else if (head == kLineHeadArrow) {
2416 // Arrow base / end line cap
2417 gluDisk(quad.Get(), 0.0, size, fgDrawQuality, 1);
2418 // Arrow cone
2420 gluCylinder(quad.Get(), size, 0.0, headHeight, fgDrawQuality, 1);
2421 } else if (head == kLineHeadBox) {
2422 // Box
2423 // TODO: Drawing box should be simpler - maybe make
2424 // a static helper which BB + others use.
2425 // Single face tesselation - ugly lighting
2427 TGLBoundingBox box(TGLVertex3(-size*.7, -size*.7, 0.0),
2428 TGLVertex3(size*.7, size*.7, headHeight));
2429 box.Draw(kTRUE);
2430 }
2431 glPopMatrix();
2432}
2433
2434////////////////////////////////////////////////////////////////////////////////
2435/// Draw ring, centered on 'center', lying on plane defined by 'center' & 'normal'
2436/// of outer radius 'radius', color 'rgba'
2437
2438void TGLUtil::DrawRing(const TGLVertex3 & center, const TGLVector3 & normal,
2439 Double_t radius, const UChar_t rgba[4])
2440{
2441 static TGLQuadric quad;
2442
2443 // Draw a ring, round vertex 'center', lying on plane defined by 'normal' vector
2444 // Radius defines the outer radius
2446
2448 Double_t width = radius*0.05;
2450
2451 // Shift into local system, looking down 'normal' vector, origin at center
2452 glPushMatrix();
2453 TGLMatrix local(center, normal);
2454 glMultMatrixd(local.CArr());
2455
2456 // Shift half width so rings centered over center vertex
2457 glTranslated(0.0, 0.0, -width/2.0);
2458
2459 // Inner and outer faces
2462
2463 // Top/bottom
2465 gluDisk(quad.Get(), inner, outer, fgDrawQuality, 1);
2466 glTranslated(0.0, 0.0, width);
2468 gluDisk(quad.Get(), inner, outer, fgDrawQuality, 1);
2469
2470 glPopMatrix();
2471}
2472
2473/**************************************************************************/
2474
2475////////////////////////////////////////////////////////////////////////////////
2476/// Draw a sphere- marker on world-coordinate 'pos' with pixel
2477/// radius 'radius'. Color argument is optional.
2478
2480 const TGLVertex3 & pos,
2482 const UChar_t * rgba)
2483{
2484 static const UChar_t defColor[4] = { 250, 110, 0, 255 }; // Orange
2485
2486 radius = camera.ViewportDeltaToWorld(pos, radius, radius).Mag();
2487 DrawSphere(pos, radius, rgba ? rgba : defColor);
2488
2489}
2490
2491////////////////////////////////////////////////////////////////////////////////
2492/// Draw simple xyz-axes for given bounding-box.
2493
2495 const TGLBoundingBox & bbox,
2498{
2499 if (axesType == kAxesNone)
2500 return;
2501
2502 static const UChar_t axesColors[][4] = {
2503 {128, 0, 0, 255}, // -ive X axis light red
2504 {255, 0, 0, 255}, // +ive X axis deep red
2505 { 0, 128, 0, 255}, // -ive Y axis light green
2506 { 0, 255, 0, 255}, // +ive Y axis deep green
2507 { 0, 0, 128, 255}, // -ive Z axis light blue
2508 { 0, 0, 255, 255} // +ive Z axis deep blue
2509 };
2510
2511 static const UChar_t xyz[][8] = {
2512 {0x44, 0x44, 0x28, 0x10, 0x10, 0x28, 0x44, 0x44},
2513 {0x10, 0x10, 0x10, 0x10, 0x10, 0x28, 0x44, 0x44},
2514 {0x7c, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x7c}
2515 };
2516
2517 // Axes draw at fixed screen size - back project to world
2518 TGLVector3 pixelVector = camera.ViewportDeltaToWorld(bbox.Center(), 1, 1);
2520
2521 // Find x/y/z min/max values
2522 TGLBoundingBox bb(bbox);
2524 Double_t min[3] = { bb.XMin(), bb.YMin(), bb.ZMin() };
2525 Double_t max[3] = { bb.XMax(), bb.YMax(), bb.ZMax() };
2526
2527 for (UInt_t i = 0; i < 3; i++) {
2528 TGLVertex3 start;
2529 TGLVector3 vector;
2530
2531 if (axesType == kAxesOrigin) {
2532 // Through origin axes
2533 start[(i+1)%3] = 0.0;
2534 start[(i+2)%3] = 0.0;
2535 } else {
2536 // Side axes
2537 start[(i+1)%3] = min[(i+1)%3];
2538 start[(i+2)%3] = min[(i+2)%3];
2539 }
2540 vector[(i+1)%3] = 0.0;
2541 vector[(i+2)%3] = 0.0;
2542
2543 // -ive axis?
2544 if (min[i] < 0.0) {
2545 // Runs from origin?
2546 if (max[i] > 0.0) {
2547 start[i] = 0.0;
2548 vector[i] = min[i];
2549 } else {
2550 start[i] = max[i];
2551 vector[i] = min[i] - max[i];
2552 }
2554 }
2555 // +ive axis?
2556 if (max[i] > 0.0) {
2557 // Runs from origin?
2558 if (min[i] < 0.0) {
2559 start[i] = 0.0;
2560 vector[i] = max[i];
2561 } else {
2562 start[i] = min[i];
2563 vector[i] = max[i] - min[i];
2564 }
2565 DrawLine(start, vector, kLineHeadNone, pixelSize*fgSimpleAxisWidthScale*2.5, axesColors[i*2 + 1]);
2566 }
2567 }
2568
2569 // Draw origin sphere(s)
2570 if (axesType == kAxesOrigin) {
2571 // Single white origin sphere at 0, 0, 0
2572 DrawSphere(TGLVertex3(0.0, 0.0, 0.0), pixelSize*2.0, fgWhite);
2573 } else {
2574 for (UInt_t j = 0; j < 3; j++) {
2575 if (min[j] <= 0.0 && max[j] >= 0.0) {
2577 zero[j] = 0.0;
2578 zero[(j+1)%3] = min[(j+1)%3];
2579 zero[(j+2)%3] = min[(j+2)%3];
2580 DrawSphere(zero, pixelSize*2.0, axesColors[j*2 + 1]);
2581 }
2582 }
2583 }
2584
2586
2587 // Labels
2588 Double_t padPixels = 25.0;
2589
2591 for (UInt_t k = 0; k < 3; k++) {
2592 SetDrawColors(axesColors[k*2+1]);
2594 if (axesType == kAxesOrigin) {
2595 minPos[(k+1)%3] = 0.0;
2596 minPos[(k+2)%3] = 0.0;
2597 } else {
2598 minPos[(k+1)%3] = min[(k+1)%3];
2599 minPos[(k+2)%3] = min[(k+2)%3];
2600 }
2601 maxPos = minPos;
2602 minPos[k] = min[k];
2603 maxPos[k] = max[k];
2604
2605 TGLVector3 axis = maxPos - minPos;
2606 TGLVector3 axisViewport = camera.WorldDeltaToViewport(minPos, axis);
2607
2608 // Skip drawing if viewport projection of axis very small - labels will overlap
2609 // Occurs with orthographic cameras
2610 if (axisViewport.Mag() < 1) {
2611 continue;
2612 }
2613
2614 minPos -= camera.ViewportDeltaToWorld(minPos, padPixels*axisViewport.X()/axisViewport.Mag(),
2616 axisViewport = camera.WorldDeltaToViewport(maxPos, -axis);
2617 maxPos -= camera.ViewportDeltaToWorld(maxPos, padPixels*axisViewport.X()/axisViewport.Mag(),
2619
2620 DrawNumber(Form("%.0f", labelScale * min[k]), minPos, kTRUE); // Min value
2621 DrawNumber(Form("%.0f", labelScale * max[k]), maxPos, kTRUE); // Max value
2622
2623 // Axis name beside max value
2625 camera.ViewportDeltaToWorld(maxPos, padPixels*axisViewport.X()/axisViewport.Mag(),
2627 glRasterPos3dv(namePos.CArr());
2628 glBitmap(8, 8, 0.0, 4.0, 0.0, 0.0, xyz[k]); // Axis Name
2629 }
2630}
2631
2632////////////////////////////////////////////////////////////////////////////////
2633/// Draw number in string 'num' via internal 8x8-pixel bitmap on
2634/// vertex 'pos'. If 'center' is true, the number is centered on 'pos'.
2635/// Only numbers, '.', '-' and ' ' are supported.
2636
2638 const TGLVertex3 & pos,
2639 Bool_t center)
2640{
2641 static const UChar_t digits[][8] = {
2642 {0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38},//0
2643 {0x10, 0x10, 0x10, 0x10, 0x10, 0x70, 0x10, 0x10},//1
2644 {0x7c, 0x44, 0x20, 0x18, 0x04, 0x04, 0x44, 0x38},//2
2645 {0x38, 0x44, 0x04, 0x04, 0x18, 0x04, 0x44, 0x38},//3
2646 {0x04, 0x04, 0x04, 0x04, 0x7c, 0x44, 0x44, 0x44},//4
2647 {0x7c, 0x44, 0x04, 0x04, 0x7c, 0x40, 0x40, 0x7c},//5
2648 {0x7c, 0x44, 0x44, 0x44, 0x7c, 0x40, 0x40, 0x7c},//6
2649 {0x20, 0x20, 0x20, 0x10, 0x08, 0x04, 0x44, 0x7c},//7
2650 {0x38, 0x44, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38},//8
2651 {0x7c, 0x44, 0x04, 0x04, 0x7c, 0x44, 0x44, 0x7c},//9
2652 {0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},//.
2653 {0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00},//-
2654 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} //space
2655 };
2656
2657 Double_t xOffset = 0, yOffset = 0;
2658 if (center)
2659 {
2660 xOffset = 3.5 * num.Length();
2661 yOffset = 4.0;
2662 }
2663
2664 glRasterPos3dv(pos.CArr());
2665 for (Ssiz_t i = 0, e = num.Length(); i < e; ++i) {
2666 if (num[i] == '.') {
2667 glBitmap(8, 8, xOffset, yOffset, 7.0, 0.0, digits[10]);
2668 } else if (num[i] == '-') {
2669 glBitmap(8, 8, xOffset, yOffset, 7.0, 0.0, digits[11]);
2670 } else if (num[i] == ' ') {
2671 glBitmap(8, 8, xOffset, yOffset, 7.0, 0.0, digits[12]);
2672 } else if (num[i] >= '0' && num[i] <= '9') {
2673 glBitmap(8, 8, xOffset, yOffset, 7.0, 0.0, digits[num[i] - '0']);
2674 }
2675 }
2676}
2677
2678
2679/**************************************************************************/
2680/**************************************************************************/
2681
2682////////////////////////////////////////////////////////////////////////////////
2683/// Constructor - change state only if necessary.
2684
2686 fWhat(what)
2687{
2689 fFlip = (fState != state);
2690 if (fFlip)
2691 SetState(state);
2692}
2693
2694////////////////////////////////////////////////////////////////////////////////
2695/// Destructor - reset state if changed.
2696
2702
2703////////////////////////////////////////////////////////////////////////////////
2704
2706{
2707 if (s)
2708 glEnable(fWhat);
2709 else
2711}
2712
2713
2714////////////////////////////////////////////////////////////////////////////////
2715/// Constructor - change state only if necessary.
2716
2718 fWhat(what)
2719{
2720 fFlip = ! glIsEnabled(fWhat) && state;
2721 if (fFlip)
2722 glEnable(fWhat);
2723}
2724
2725////////////////////////////////////////////////////////////////////////////////
2726/// Destructor - reset state if changed.
2727
2733
2734
2735////////////////////////////////////////////////////////////////////////////////
2736
2738 fWhat(what), fState(0), fFlip(kFALSE), fFoo(foo)
2739 {
2741 fFlip = (fState != state);
2742 if (fFlip) fFoo(state);
2743 }
2744
2745////////////////////////////////////////////////////////////////////////////////
2746
2751
2752
2753////////////////////////////////////////////////////////////////////////////////
2754/// TGLEnableGuard constructor.
2755
2761
2762////////////////////////////////////////////////////////////////////////////////
2763/// TGLEnableGuard destructor.
2764
2769
2770////////////////////////////////////////////////////////////////////////////////
2771/// TGLDisableGuard constructor.
2772
2778
2779////////////////////////////////////////////////////////////////////////////////
2780/// TGLDisableGuard destructor.
2781
2786
2787/** \class TGLSelectionBuffer
2788\ingroup opengl
2789*/
2790
2792
2793////////////////////////////////////////////////////////////////////////////////
2794/// TGLSelectionBuffer constructor.
2795
2797 : fWidth(0), fHeight(0)
2798{
2799}
2800
2801////////////////////////////////////////////////////////////////////////////////
2802/// TGLSelectionBuffer destructor.
2803
2807
2808////////////////////////////////////////////////////////////////////////////////
2809/// Read color buffer.
2810
2812{
2813 fWidth = w;
2814 fHeight = h;
2815 fBuffer.resize(w * h * 4);
2818}
2819
2820////////////////////////////////////////////////////////////////////////////////
2821/// Read color buffer.
2822
2824{
2825 fWidth = w;
2826 fHeight = h;
2827 fBuffer.resize(w * h * 4);
2830}
2831
2832////////////////////////////////////////////////////////////////////////////////
2833/// Get pixel color.
2834
2836{
2837 if (px < 0)
2838 px = 0;
2839 if (py < 0)
2840 py = 0;
2841
2842 if (UInt_t(px * fWidth * 4 + py * 4) > fBuffer.size())
2843 return &fBuffer[0];
2844
2845 return &fBuffer[px * fWidth * 4 + py * 4];
2846}
2847
2848namespace Rgl {
2849
2850const Float_t gRedEmission[] = {1.f, 0.f, 0.f, 1.f};
2851const Float_t gGreenEmission[] = {0.f, 1.f, 0.f, 1.f};
2852const Float_t gBlueEmission[] = {0.f, 0.f, 1.f, 1.f};
2853const Float_t gOrangeEmission[] = {1.f, 0.4f, 0.f, 1.f};
2854const Float_t gWhiteEmission[] = {1.f, 1.f, 1.f, 1.f};
2855const Float_t gGrayEmission[] = {0.3f,0.3f, 0.3f,1.f};
2856const Float_t gNullEmission[] = {0.f, 0.f, 0.f, 1.f};
2857
2858namespace {
2859 struct RGB_t {
2860 Int_t fRGB[3];
2861 };
2862
2863 RGB_t gColorTriplets[] = {{{255, 0, 0}},
2864 {{0, 255, 0}},
2865 {{0, 0, 255}},
2866 {{255, 255, 0}},
2867 {{255, 0, 255}},
2868 {{0, 255, 255}},
2869 {{255, 255, 255}}};
2870
2871 Bool_t operator < (const RGB_t &lhs, const RGB_t &rhs)
2872 {
2873 if (lhs.fRGB[0] < rhs.fRGB[0])
2874 return kTRUE;
2875 else if (lhs.fRGB[0] > rhs.fRGB[0])
2876 return kFALSE;
2877 else if (lhs.fRGB[1] < rhs.fRGB[1])
2878 return kTRUE;
2879 else if (lhs.fRGB[1] > rhs.fRGB[1])
2880 return kFALSE;
2881 else if (lhs.fRGB[2] < rhs.fRGB[2])
2882 return kTRUE;
2883
2884 return kFALSE;
2885 }
2886
2887 typedef std::map<Int_t, RGB_t> ColorLookupTable_t;
2889
2891
2892 typedef std::map<RGB_t, Int_t> ObjectLookupTable_t;
2894
2896}
2897////////////////////////////////////////////////////////////////////////////////
2898///Object id encoded as rgb triplet.
2899
2901{
2902 if (!highColor)
2903 glColor3ub(objectID & 0xff, (objectID & 0xff00) >> 8, (objectID & 0xff0000) >> 16);
2904 else {
2905 if (gObjectIDToColor.empty()) {
2906 //Initialize lookup tables.
2907 for (Int_t i = 0, id = 1; i < Int_t(sizeof gColorTriplets / sizeof(RGB_t)); ++i, ++id)
2909 for (Int_t i = 0, id = 1; i < Int_t(sizeof gColorTriplets / sizeof(RGB_t)); ++i, ++id)
2911 }
2912
2914
2915 if (it != gObjectIDToColor.end())
2916 glColor3ub(it->second.fRGB[0], it->second.fRGB[1], it->second.fRGB[2]);
2917 else {
2918 Error("ObjectIDToColor", "No color for such object ID: %d", objectID);
2919 glColor3ub(0, 0, 0);
2920 }
2921 }
2922}
2923
2924////////////////////////////////////////////////////////////////////////////////
2925
2927{
2928 if (!highColor)
2929 return pixel[0] | (pixel[1] << 8) | (pixel[2] << 16);
2930 else {
2931 if (gObjectIDToColor.empty())
2932 return 0;
2933
2934 RGB_t triplet = {{pixel[0], pixel[1], pixel[2]}};
2935 OLTCI_t it = gColorToObjectID.find(triplet);
2936
2937 if (it != gColorToObjectID.end())
2938 return it->second;
2939 else
2940 return 0;
2941 }
2942}
2943
2944
2945////////////////////////////////////////////////////////////////////////////////
2946///Draw quad outline.
2947
2949 const TGLVertex3 &v3, const TGLVertex3 &v4)
2950{
2952 glVertex3dv(v1.CArr());
2953 glVertex3dv(v2.CArr());
2954 glVertex3dv(v3.CArr());
2955 glVertex3dv(v4.CArr());
2956 glEnd();
2957}
2958
2959////////////////////////////////////////////////////////////////////////////////
2960///Draw quad face.
2961
2963 const TGLVertex3 &v3, const TGLVector3 &normal)
2964{
2966 glNormal3dv(normal.CArr());
2967 glVertex3dv(v0.CArr());
2968 glVertex3dv(v1.CArr());
2969 glVertex3dv(v2.CArr());
2970 glVertex3dv(v3.CArr());
2971 glEnd();
2972}
2973
2974////////////////////////////////////////////////////////////////////////////////
2975///Draw quad face.
2976
2977void DrawQuadFilled(const Double_t *v0, const Double_t *v1, const Double_t *v2, const Double_t *v3,
2978 const Double_t *normal)
2979{
2981 glNormal3dv(normal);
2982 glVertex3dv(v0);
2983 glVertex3dv(v1);
2984 glVertex3dv(v2);
2985 glVertex3dv(v3);
2986 glEnd();
2987}
2988
2989////////////////////////////////////////////////////////////////////////////////
2990///Draws triangle face, each vertex has its own averaged normal
2991
2993 const TGLVector3 &norm1, const TGLVector3 &norm2, const TGLVector3 &norm3)
2994{
2996 glNormal3dv(norm1.CArr());
2997 glVertex3dv(v1.CArr());
2998 glNormal3dv(norm2.CArr());
2999 glVertex3dv(v2.CArr());
3000 glNormal3dv(norm3.CArr());
3001 glVertex3dv(v3.CArr());
3002 glEnd();
3003}
3004
3005const Int_t gBoxFrontQuads[][4] = {{0, 1, 2, 3}, {4, 0, 3, 5}, {4, 5, 6, 7}, {7, 6, 2, 1}};
3006const Double_t gBoxFrontNormals[][3] = {{-1., 0., 0.}, {0., -1., 0.}, {1., 0., 0.}, {0., 1., 0.}};
3007const Int_t gBoxFrontPlanes[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}};
3008
3009const Int_t gBoxBackQuads[][4] = {{7, 1, 2, 6}, {4, 7, 6, 5}, {0, 4, 5, 3}, {0, 3, 2, 1}};
3010const Double_t gBoxBackNormals[][3] = {{0., -1., 0.}, {-1., 0., 0.}, {0., 1., 0.}, {1., 0., 0.}};
3011const Int_t gBoxBackPlanes[][2] = {{0, 1}, {3, 0}, {2, 3}, {1, 2}};
3012
3013////////////////////////////////////////////////////////////////////////////////
3014///Draws lego's bar as a 3d box
3015
3018{
3019 if (zMax < zMin)
3020 std::swap(zMax, zMin);
3021
3022 //Bottom is always drawn.
3024 glNormal3d(0., 0., -1.);
3029 glEnd();
3030 //Draw two visible front planes.
3031 const Double_t box[][3] = {{xMin, yMin, zMax}, {xMin, yMax, zMax}, {xMin, yMax, zMin}, {xMin, yMin, zMin},
3032 {xMax, yMin, zMax}, {xMax, yMin, zMin}, {xMax, yMax, zMin}, {xMax, yMax, zMax}};
3033 const Int_t *verts = gBoxFrontQuads[gBoxFrontPlanes[fp][0]];
3034
3037 glVertex3dv(box[verts[0]]);
3038 glVertex3dv(box[verts[1]]);
3039 glVertex3dv(box[verts[2]]);
3040 glVertex3dv(box[verts[3]]);
3041 glEnd();
3042
3044
3047 glVertex3dv(box[verts[0]]);
3048 glVertex3dv(box[verts[1]]);
3049 glVertex3dv(box[verts[2]]);
3050 glVertex3dv(box[verts[3]]);
3051 glEnd();
3052
3053 //Top is always drawn.
3055 glNormal3d(0., 0., 1.);
3060 glEnd();
3061}
3062
3063////////////////////////////////////////////////////////////////////////////////
3064///Draws lego's bar as a 3d box
3065
3068{
3069 if (zMax < zMin)
3070 std::swap(zMax, zMin);
3071
3072 //The order is: 1) two back planes, 2) bottom plane, 3) two front planes,
3073 //4) top.
3074
3075 //Bottom is always drawn.
3077 glNormal3d(0., 0., -1.);
3082 glEnd();
3083
3084 const Double_t box[][3] = {{xMin, yMin, zMax}, {xMin, yMax, zMax}, {xMin, yMax, zMin}, {xMin, yMin, zMin},
3085 {xMax, yMin, zMax}, {xMax, yMin, zMin}, {xMax, yMax, zMin}, {xMax, yMax, zMax}};
3086
3087 //Draw two back planes.
3088 const Int_t *verts = gBoxBackQuads[gBoxBackPlanes[fp][0]];
3089
3092 glVertex3dv(box[verts[0]]);
3093 glVertex3dv(box[verts[1]]);
3094 glVertex3dv(box[verts[2]]);
3095 glVertex3dv(box[verts[3]]);
3096 glEnd();
3097
3099
3102 glVertex3dv(box[verts[0]]);
3103 glVertex3dv(box[verts[1]]);
3104 glVertex3dv(box[verts[2]]);
3105 glVertex3dv(box[verts[3]]);
3106 glEnd();
3107
3108 //Draw two visible front planes.
3110
3113 glVertex3dv(box[verts[0]]);
3114 glVertex3dv(box[verts[1]]);
3115 glVertex3dv(box[verts[2]]);
3116 glVertex3dv(box[verts[3]]);
3117 glEnd();
3118
3120
3123 glVertex3dv(box[verts[0]]);
3124 glVertex3dv(box[verts[1]]);
3125 glVertex3dv(box[verts[2]]);
3126 glVertex3dv(box[verts[3]]);
3127 glEnd();
3128
3129 //Top is always drawn.
3131 glNormal3d(0., 0., 1.);
3136 glEnd();
3137}
3138
3139////////////////////////////////////////////////////////////////////////////////
3140///Draws lego's bar as a 3d box
3141///LULULULU
3142
3146{
3147 if (zMax < zMin) {
3148 std::swap(zMax, zMin);
3149 std::swap(texMax, texMin);
3150 }
3151
3152 //Top and bottom are always drawn.
3154 glNormal3d(0., 0., 1.);
3160 glEnd();
3161
3164 glNormal3d(0., 0., -1.);
3169 glEnd();
3170 //Draw two visible front planes.
3171 const Double_t box[][3] = {{xMin, yMin, zMax}, {xMin, yMax, zMax}, {xMin, yMax, zMin}, {xMin, yMin, zMin},
3172 {xMax, yMin, zMax}, {xMax, yMin, zMin}, {xMax, yMax, zMin}, {xMax, yMax, zMax}};
3173
3175 const Int_t *verts = gBoxFrontQuads[gBoxFrontPlanes[fp][0]];
3176
3179 glTexCoord1d(tex[verts[0]]);
3180 glVertex3dv(box[verts[0]]);
3181 glTexCoord1d(tex[verts[1]]);
3182 glVertex3dv(box[verts[1]]);
3183 glTexCoord1d(tex[verts[2]]);
3184 glVertex3dv(box[verts[2]]);
3185 glTexCoord1d(tex[verts[3]]);
3186 glVertex3dv(box[verts[3]]);
3187 glEnd();
3188
3190
3193 glTexCoord1d(tex[verts[0]]);
3194 glVertex3dv(box[verts[0]]);
3195 glTexCoord1d(tex[verts[1]]);
3196 glVertex3dv(box[verts[1]]);
3197 glTexCoord1d(tex[verts[2]]);
3198 glVertex3dv(box[verts[2]]);
3199 glTexCoord1d(tex[verts[3]]);
3200 glVertex3dv(box[verts[3]]);
3201 glEnd();
3202}
3203
3204////////////////////////////////////////////////////////////////////////////////
3205
3207 const Double_t *rgba1, const Double_t *rgba2)
3208{
3209 assert(rgba1 != nullptr && "DrawBoxWithGradientFill, parameter 'rgba1' is null");
3210 assert(rgba2 != nullptr && "DrawBoxWithGradientFill, parameter 'rgba2' is null");
3211
3214 glVertex2d(x1, y1);
3215 glVertex2d(x2, y1);
3217 glVertex2d(x2, y2);
3218 glVertex2d(x1, y2);
3219 glEnd();
3220}
3221
3222////////////////////////////////////////////////////////////////////////////////
3223///TODO: is it possible to use GLdouble to avoid problems with Double_t/GLdouble if they
3224///are not the same type?
3225
3227 const Double_t *outer, const Double_t *outerRGBA)
3228{
3229 assert(nPoints != 0 &&
3230 "DrawQuadStripWithRadialGradientFill, invalid number of points");
3231 assert(inner != nullptr &&
3232 "DrawQuadStripWithRadialGradientFill, parameter 'inner' is null");
3233 assert(innerRGBA != nullptr &&
3234 "DrawQuadStripWithRadialGradientFill, parameter 'innerRGBA' is null");
3235 assert(outer != nullptr &&
3236 "DrawQuadStripWithRadialGradientFill, parameter 'outer' is null");
3237 assert(outerRGBA != nullptr &&
3238 "DrawQuadStripWithRadialGradientFill, parameter 'outerRGBA' is null");
3239
3241 for (UInt_t j = 0; j < nPoints; ++j) {
3243 glVertex2dv(inner + j * 2);
3245 glVertex2dv(outer + j * 2);
3246 }
3247 glEnd();
3248}
3249
3250////////////////////////////////////////////////////////////////////////////////
3251///Cylinder for lego3.
3252
3255{
3256 GLUquadric *quad = quadric->Get();
3257
3258 if (quad) {
3259 if (zMin > zMax)
3260 std::swap(zMin, zMax);
3261 const Double_t xCenter = xMin + (xMax - xMin) / 2;
3262 const Double_t yCenter = yMin + (yMax - yMin) / 2;
3263 const Double_t radius = TMath::Min((xMax - xMin) / 2, (yMax - yMin) / 2);
3264
3265 glPushMatrix();
3267 gluCylinder(quad, radius, radius, zMax - zMin, 40, 1);
3268 glPopMatrix();
3269 glPushMatrix();
3271 gluDisk(quad, 0., radius, 40, 1);
3272 glPopMatrix();
3273 glPushMatrix();
3275 glRotated(180., 0., 1., 0.);
3276 gluDisk(quad, 0., radius, 40, 1);
3277 glPopMatrix();
3278 }
3279}
3280
3281////////////////////////////////////////////////////////////////////////////////
3282///Cylinder for lego3.
3283
3286{
3287 GLUquadric *quad = quadric->Get();
3288
3289 if (quad) {
3290 const Double_t xCenter = xMin + (xMax - xMin) / 2;
3291 const Double_t yCenter = yMin + (yMax - yMin) / 2;
3292 const Double_t zCenter = zMin + (zMax - zMin) / 2;
3293
3294 const Double_t radius = TMath::Min((zMax - zMin) / 2,
3295 TMath::Min((xMax - xMin) / 2, (yMax - yMin) / 2));
3296
3297 glPushMatrix();
3299 gluSphere(quad, radius, 10, 10);
3300 glPopMatrix();
3301 }
3302}
3303
3304
3305////////////////////////////////////////////////////////////////////////////////
3306
3309{
3310 const Double_t xWid = xMax - xMin;
3311 const Double_t yWid = yMax - yMin;
3312
3314 glVertex3d(xMin + xWid / 2, yMin + yWid / 2, zMin);
3315 glVertex3d(xMin + xWid / 2, yMin + yWid / 2, zMax);
3316 glEnd();
3317
3319 glVertex3d(xMin + xWid / 2, yMin, zMin);
3320 glVertex3d(xMin + xWid / 2, yMax, zMin);
3321 glEnd();
3322
3324 glVertex3d(xMin, yMin + yWid / 2, zMin);
3325 glVertex3d(xMax, yMin + yWid / 2, zMin);
3326 glEnd();
3327}
3328
3330{
3331 const Double_t n = TMath::Sqrt(v[0] * v[0] + v[1] * v[1]);
3332 if (n > 0.) {
3333 normal[0] = v[0] / n;
3334 normal[1] = v[1] / n;
3335 normal[2] = 0.;
3336 } else {
3337 normal[0] = v[0];
3338 normal[1] = v[1];
3339 normal[2] = 0.;
3340 }
3341}
3342
3344{
3345 const Double_t n = TMath::Sqrt(v[0] * v[0] + v[1] * v[1]);
3346 if (n > 0.) {
3347 normal[0] = -v[0] / n;
3348 normal[1] = -v[1] / n;
3349 normal[2] = 0.;
3350 } else {
3351 normal[0] = -v[0];
3352 normal[1] = -v[1];
3353 normal[2] = 0.;
3354 }
3355}
3356
3358{
3359 //In polar coordinates, box became trapezoid.
3360 //Four faces need normal calculations.
3361 if (zMin > zMax)
3362 std::swap(zMin, zMax);
3363 //top
3365 glNormal3d(0., 0., 1.);
3366 glVertex3d(ver[0][0], ver[0][1], zMax);
3367 glVertex3d(ver[1][0], ver[1][1], zMax);
3368 glVertex3d(ver[2][0], ver[2][1], zMax);
3369 glVertex3d(ver[3][0], ver[3][1], zMax);
3370 glEnd();
3371 //bottom
3373 glNormal3d(0., 0., -1.);
3374 glVertex3d(ver[0][0], ver[0][1], zMin);
3375 glVertex3d(ver[3][0], ver[3][1], zMin);
3376 glVertex3d(ver[2][0], ver[2][1], zMin);
3377 glVertex3d(ver[1][0], ver[1][1], zMin);
3378 glEnd();
3379 //
3380
3381 Double_t trapezoid[][3] = {{ver[0][0], ver[0][1], zMin}, {ver[1][0], ver[1][1], zMin},
3382 {ver[2][0], ver[2][1], zMin}, {ver[3][0], ver[3][1], zMin},
3383 {ver[0][0], ver[0][1], zMax}, {ver[1][0], ver[1][1], zMax},
3384 {ver[2][0], ver[2][1], zMax}, {ver[3][0], ver[3][1], zMax}};
3385 Double_t normal[3] = {0.};
3391 glEnd();
3392
3398 glEnd();
3399
3401 if (color) {
3403 glNormal3dv(normal);
3404 }
3409 glEnd();
3410
3412 if (color) {
3414 glNormal3dv(normal);
3415 }
3420 glEnd();
3421}
3422
3423////////////////////////////////////////////////////////////////////////////////
3424///In polar coordinates, box became trapezoid.
3425///Four faces need normal calculations.
3426
3429{
3430 if (zMin > zMax) {
3431 std::swap(zMin, zMax);
3432 std::swap(texMin, texMax);
3433 }
3434
3435 //top
3437 glNormal3d(0., 0., 1.);
3439 glVertex3d(ver[0][0], ver[0][1], zMax);
3440 glVertex3d(ver[1][0], ver[1][1], zMax);
3441 glVertex3d(ver[2][0], ver[2][1], zMax);
3442 glVertex3d(ver[3][0], ver[3][1], zMax);
3443 glEnd();
3444 //bottom
3446 glNormal3d(0., 0., -1.);
3448 glVertex3d(ver[0][0], ver[0][1], zMin);
3449 glVertex3d(ver[3][0], ver[3][1], zMin);
3450 glVertex3d(ver[2][0], ver[2][1], zMin);
3451 glVertex3d(ver[1][0], ver[1][1], zMin);
3452 glEnd();
3453 //
3454
3455 Double_t trapezoid[][3] = {{ver[0][0], ver[0][1], zMin}, {ver[1][0], ver[1][1], zMin},
3456 {ver[2][0], ver[2][1], zMin}, {ver[3][0], ver[3][1], zMin},
3457 {ver[0][0], ver[0][1], zMax}, {ver[1][0], ver[1][1], zMax},
3458 {ver[2][0], ver[2][1], zMax}, {ver[3][0], ver[3][1], zMax}};
3459 Double_t normal[3] = {0.};
3465 glEnd();
3466
3472 glEnd();
3473
3476 glNormal3dv(normal);
3485 glEnd();
3486
3489 glNormal3dv(normal);
3498 glEnd();
3499}
3500
3501////////////////////////////////////////////////////////////////////////////////
3502///In polar coordinates, box became trapezoid.
3503
3506{
3507 if (zMin > zMax)
3508 std::swap(zMin, zMax);
3509
3510 const Double_t trapezoid[][3] = {{ver[0][0], ver[0][1], zMin}, {ver[1][0], ver[1][1], zMin},
3511 {ver[2][0], ver[2][1], zMin}, {ver[3][0], ver[3][1], zMin},
3512 {ver[0][0], ver[0][1], zMax}, {ver[1][0], ver[1][1], zMax},
3513 {ver[2][0], ver[2][1], zMax}, {ver[3][0], ver[3][1], zMax}};
3515 //top
3517 glNormal3d(0., 0., 1.);
3522 glEnd();
3523 //bottom
3525 glNormal3d(0., 0., -1.);
3530 glEnd();
3531 //
3533 Double_t normal[3] = {};
3538 glEnd();
3539
3545 glEnd();
3546
3549 glNormal3dv(normal);
3554 glEnd();
3555
3558 glNormal3dv(normal);
3563 glEnd();
3564}
3565
3566////////////////////////////////////////////////////////////////////////////////
3567
3568void SphericalNormal(const Double_t *v, Double_t *normal)
3569{
3570 const Double_t n = TMath::Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
3571 if (n > 0.) {
3572 normal[0] = v[0] / n;
3573 normal[1] = v[1] / n;
3574 normal[2] = v[2] / n;
3575 } else {
3576 normal[0] = v[0];
3577 normal[1] = v[1];
3578 normal[2] = v[2];
3579 }
3580}
3581
3582////////////////////////////////////////////////////////////////////////////////
3583
3585{
3586 const Double_t n = TMath::Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
3587 if (n > 0.) {
3588 normal[0] = -v[0] / n;
3589 normal[1] = -v[1] / n;
3590 normal[2] = -v[2] / n;
3591 } else {
3592 normal[0] = -v[0];
3593 normal[1] = -v[1];
3594 normal[2] = -v[2];
3595 }
3596}
3597
3598////////////////////////////////////////////////////////////////////////////////
3599
3601{
3602 Double_t normal[3] = {0.};
3603
3605 TMath::Normal2Plane(ver[1], ver[2], ver[3], normal);
3606 glNormal3dv(normal);
3607 glVertex3dv(ver[0]);
3608 glVertex3dv(ver[1]);
3609 glVertex3dv(ver[2]);
3610 glVertex3dv(ver[3]);
3611 glEnd();
3612 //bottom
3614 TMath::Normal2Plane(ver[4], ver[7], ver[6], normal);
3615 glNormal3dv(normal);
3616 glVertex3dv(ver[4]);
3617 glVertex3dv(ver[7]);
3618 glVertex3dv(ver[6]);
3619 glVertex3dv(ver[5]);
3620 glEnd();
3621 //
3622
3624 TMath::Normal2Plane(ver[0], ver[3], ver[7], normal);
3625 glNormal3dv(normal);
3626 glVertex3dv(ver[0]);
3627 glVertex3dv(ver[3]);
3628 glVertex3dv(ver[7]);
3629 glVertex3dv(ver[4]);
3630 glEnd();
3631
3633 SphericalNormal(ver[3], normal), glNormal3dv(normal), glVertex3dv(ver[3]);
3634 SphericalNormal(ver[2], normal), glNormal3dv(normal), glVertex3dv(ver[2]);
3635 SphericalNormal(ver[6], normal), glNormal3dv(normal), glVertex3dv(ver[6]);
3636 SphericalNormal(ver[7], normal), glNormal3dv(normal), glVertex3dv(ver[7]);
3637 glEnd();
3638
3640 TMath::Normal2Plane(ver[5], ver[6], ver[2], normal);
3641 glNormal3dv(normal);
3642 glVertex3dv(ver[5]);
3643 glVertex3dv(ver[6]);
3644 glVertex3dv(ver[2]);
3645 glVertex3dv(ver[1]);
3646 glEnd();
3647
3649 SphericalNormalInv(ver[0], normal), glNormal3dv(normal), glVertex3dv(ver[0]);
3650 SphericalNormalInv(ver[4], normal), glNormal3dv(normal), glVertex3dv(ver[4]);
3651 SphericalNormalInv(ver[5], normal), glNormal3dv(normal), glVertex3dv(ver[5]);
3652 SphericalNormalInv(ver[1], normal), glNormal3dv(normal), glVertex3dv(ver[1]);
3653 glEnd();
3654}
3655
3656////////////////////////////////////////////////////////////////////////////////
3657
3659{
3660 Double_t normal[3] = {};
3661 if (texMin > texMax)
3662 std::swap(texMin, texMax);
3663
3666 TMath::Normal2Plane(ver[0], ver[1], ver[2], normal);
3667 glNormal3dv(normal);
3672 glEnd();
3674 TMath::Normal2Plane(ver[4], ver[7], ver[6], normal);
3675 glNormal3dv(normal);
3680 glEnd();
3682 TMath::Normal2Plane(ver[0], ver[3], ver[7], normal);
3683 glNormal3dv(normal);
3688 glEnd();
3690 SphericalNormal(ver[3], normal), glNormal3dv(normal), glTexCoord1d(tex[3]), glVertex3dv(ver[3]);
3691 SphericalNormal(ver[2], normal), glNormal3dv(normal), glTexCoord1d(tex[2]), glVertex3dv(ver[2]);
3692 SphericalNormal(ver[6], normal), glNormal3dv(normal), glTexCoord1d(tex[6]), glVertex3dv(ver[6]);
3693 SphericalNormal(ver[7], normal), glNormal3dv(normal), glTexCoord1d(tex[7]), glVertex3dv(ver[7]);
3694 glEnd();
3696 TMath::Normal2Plane(ver[5], ver[6], ver[2], normal);
3697 glNormal3dv(normal);
3702 glEnd();
3704 SphericalNormalInv(ver[0], normal), glNormal3dv(normal), glTexCoord1d(tex[0]), glVertex3dv(ver[0]);
3705 SphericalNormalInv(ver[4], normal), glNormal3dv(normal), glTexCoord1d(tex[4]), glVertex3dv(ver[4]);
3706 SphericalNormalInv(ver[5], normal), glNormal3dv(normal), glTexCoord1d(tex[5]), glVertex3dv(ver[5]);
3707 SphericalNormalInv(ver[1], normal), glNormal3dv(normal), glTexCoord1d(tex[1]), glVertex3dv(ver[1]);
3708 glEnd();
3709}
3710
3711
3713 Double_t min, Double_t max, Bool_t log, Bool_t z = kFALSE)
3714{
3715 //Axes are drawn with help of TGaxis class
3716 std::string option;
3717 option.reserve(20);
3718
3719 if (xMin > xMax || z) option += "SDH=+";
3720 else option += "SDH=-";
3721
3722 if (log) option += 'G';
3723
3724 Int_t nDiv = axis->GetNdivisions();
3725
3726 if (nDiv < 0) {
3727 option += 'N';
3728 nDiv = -nDiv;
3729 }
3730
3732 axisPainter.SetLineWidth(1);
3733
3734 static const Double_t zero = 0.001;
3735
3736 if (TMath::Abs(xMax - xMin) >= zero || TMath::Abs(yMax - yMin) >= zero) {
3737 axisPainter.ImportAxisAttributes(axis);
3738 axisPainter.SetLabelOffset(axis->GetLabelOffset() + axis->GetTickLength());
3739
3740 if (log) {
3741 min = TMath::Power(10, min);
3742 max = TMath::Power(10, max);
3743 }
3744 //Option time display is required ?
3745 if (axis->GetTimeDisplay()) {
3746 option += 't';
3747
3748 if (!strlen(axis->GetTimeFormatOnly()))
3749 axisPainter.SetTimeFormat(axis->ChooseTimeFormat(max - min));
3750 else
3751 axisPainter.SetTimeFormat(axis->GetTimeFormat());
3752 }
3753
3754 axisPainter.SetOption(option.c_str());
3755 axisPainter.PaintAxis(xMin, yMin, xMax, yMax, min, max, nDiv, option.c_str());
3756 }
3757}
3758
3759const Int_t gFramePoints[][2] = {{3, 1}, {0, 2}, {1, 3}, {2, 0}};
3760//Each point has two "neighbouring axes" (left and right). Axes types are 1 (ordinata) and 0 (abscissa)
3761const Int_t gAxisType[][2] = {{1, 0}, {0, 1}, {1, 0}, {0, 1}};
3762
3763////////////////////////////////////////////////////////////////////////////////
3764///Using front point, find, where to draw axes and which labels to use for them
3765///gVirtualX->SelectWindow(gGLManager->GetVirtualXInd(fGLDevice));
3766///gVirtualX->SetDrawMode(TVirtualX::kCopy);//TCanvas by default sets in kInverse
3767
3770{
3771 const Int_t left = gFramePoints[fp][0];
3772 const Int_t right = gFramePoints[fp][1];
3773 const Double_t xLeft = gPad->AbsPixeltoX(Int_t(gPad->GetXlowNDC() * gPad->GetWw()
3774 + box[left].X() - vp[0]));
3775 const Double_t yLeft = gPad->AbsPixeltoY(Int_t(vp[3] - box[left].Y()
3776 + (1 - gPad->GetHNDC() - gPad->GetYlowNDC())
3777 * gPad->GetWh() + vp[1]));
3778 const Double_t xMid = gPad->AbsPixeltoX(Int_t(gPad->GetXlowNDC() * gPad->GetWw()
3779 + box[fp].X() - vp[0]));
3780 const Double_t yMid = gPad->AbsPixeltoY(Int_t(vp[3] - box[fp].Y()
3781 + (1 - gPad->GetHNDC() - gPad->GetYlowNDC())
3782 * gPad->GetWh() + vp[1]));
3783 const Double_t xRight = gPad->AbsPixeltoX(Int_t(gPad->GetXlowNDC()
3784 * gPad->GetWw() + box[right].X() - vp[0]));
3785 const Double_t yRight = gPad->AbsPixeltoY(Int_t(vp[3] - box[right].Y()
3786 + (1 - gPad->GetHNDC() - gPad->GetYlowNDC())
3787 * gPad->GetWh() + vp[1]));
3788 const Double_t points[][2] = {{coord->GetXRange().first, coord->GetYRange().first },
3789 {coord->GetXRange().second, coord->GetYRange().first },
3790 {coord->GetXRange().second, coord->GetYRange().second},
3791 {coord->GetXRange().first, coord->GetYRange().second}};
3792 const Int_t leftType = gAxisType[fp][0];
3793 const Int_t rightType = gAxisType[fp][1];
3794 const Double_t leftLabel = points[left][leftType];
3795 const Double_t leftMidLabel = points[fp][leftType];
3797 const Double_t rightLabel = points[right][rightType];
3798
3799 if (xLeft - xMid || yLeft - yMid) {//To suppress error messages from TGaxis
3800 TAxis *axis = leftType ? yAxis : xAxis;
3801 if (leftLabel < leftMidLabel)
3803 leftType ? coord->GetYLog() : coord->GetXLog());
3804 else
3806 leftType ? coord->GetYLog() : coord->GetXLog());
3807 }
3808
3809 if (xRight - xMid || yRight - yMid) {//To suppress error messages from TGaxis
3810 TAxis *axis = rightType ? yAxis : xAxis;
3811
3814 rightType ? coord->GetYLog() : coord->GetXLog());
3815 else
3817 rightType ? coord->GetYLog() : coord->GetXLog());
3818 }
3819
3820 const Double_t xUp = gPad->AbsPixeltoX(Int_t(gPad->GetXlowNDC() * gPad->GetWw()
3821 + box[left + 4].X() - vp[0]));
3822 const Double_t yUp = gPad->AbsPixeltoY(Int_t(vp[3] - box[left + 4].Y()
3823 + (1 - gPad->GetHNDC() - gPad->GetYlowNDC())
3824 * gPad->GetWh() + vp[1]));
3825 Draw2DAxis(zAxis, xLeft, yLeft, xUp, yUp, coord->GetZRange().first,
3826 coord->GetZRange().second, coord->GetZLog(), kTRUE);
3827}
3828
3830 Double_t zScale, std::vector<Double_t> &zLevels)
3831{
3832 Int_t nDiv = zAxis->GetNdivisions() % 100;
3833 Int_t nBins = 0;
3834 Double_t binLow = 0., binHigh = 0., binWidth = 0.;
3835 THLimitsFinder::Optimize(zMin, zMax, nDiv, binLow, binHigh, nBins, binWidth, " ");
3836 zLevels.resize(nBins + 1);
3837
3838 for (Int_t i = 0; i < nBins + 1; ++i)
3839 zLevels[i] = (binLow + i * binWidth) * zScale;
3840}
3841
3842////////////////////////////////////////////////////////////////////////////////
3843///Draw textured triangle
3844
3847 const TGLVector3 &norm2, const TGLVector3 &norm3)
3848{
3850 glNormal3dv(norm1.CArr());
3852 glVertex3dv(v1.CArr());
3853 glNormal3dv(norm2.CArr());
3855 glVertex3dv(v2.CArr());
3856 glNormal3dv(norm3.CArr());
3858 glVertex3dv(v3.CArr());
3859 glEnd();
3860}
3861
3862////////////////////////////////////////////////////////////////////////////////
3863///Draw textured triangle on a plane
3864
3867 const TGLVector3 &normal)
3868{
3870 glNormal3dv(normal.CArr());
3872 glVertex3d(v1.X(), v1.Y(), z);
3874 glVertex3d(v2.X(), v2.Y(), z);
3876 glVertex3d(v3.X(), v3.Y(), z);
3877 glEnd();
3878}
3879
3880////////////////////////////////////////////////////////////////////////////////
3881///This function creates color for parametric surface's vertex,
3882///using its 'u' value.
3883///I've found it in one of Apple's Carbon tutorials , and it's based
3884///on Paul Bourke work. Very nice colors!!! :)
3885
3887{
3888 Float_t dv,vmid;
3889 //Float_t c[] = {1.f, 1.f, 1.f};
3890 Float_t c1[3] = {}, c2[3] = {}, c3[3] = {};
3891 Float_t ratio ;
3892 rgba[3] = 1.f;
3893
3894 if (v < vmin)
3895 v = vmin;
3896 if (v > vmax)
3897 v = vmax;
3898 dv = vmax - vmin;
3899
3900 switch (type) {
3901 case 0:
3902 rgba[0] = 1.f;
3903 rgba[1] = 1.f;
3904 rgba[2] = 1.f;
3905 break;
3906 case 1:
3907 if (v < (vmin + 0.25 * dv)) {
3908 rgba[0] = 0;
3909 rgba[1] = 4 * (v - vmin) / dv;
3910 rgba[2] = 1;
3911 } else if (v < (vmin + 0.5 * dv)) {
3912 rgba[0] = 0;
3913 rgba[1] = 1;
3914 rgba[2] = 1 + 4 * (vmin + 0.25 * dv - v) / dv;
3915 } else if (v < (vmin + 0.75 * dv)) {
3916 rgba[0] = 4 * (v - vmin - 0.5 * dv) / dv;
3917 rgba[1] = 1;
3918 rgba[2] = 0;
3919 } else {
3920 rgba[0] = 1;
3921 rgba[1] = 1 + 4 * (vmin + 0.75 * dv - v) / dv;
3922 rgba[2] = 0;
3923 }
3924 break;
3925 case 2:
3926 rgba[0] = (v - vmin) / dv;
3927 rgba[1] = 0;
3928 rgba[2] = (vmax - v) / dv;
3929 break;
3930 case 3:
3931 rgba[0] = (v - vmin) / dv;
3932 rgba[1] = rgba[0];
3933 rgba[2] = rgba[0];
3934 break;
3935 case 4:
3936 if (v < (vmin + dv / 6.0)) {
3937 rgba[0] = 1;
3938 rgba[1] = 6 * (v - vmin) / dv;
3939 rgba[2] = 0;
3940 } else if (v < (vmin + 2.0 * dv / 6.0)) {
3941 rgba[0] = 1 + 6 * (vmin + dv / 6.0 - v) / dv;
3942 rgba[1] = 1;
3943 rgba[2] = 0;
3944 } else if (v < (vmin + 3.0 * dv / 6.0)) {
3945 rgba[0] = 0;
3946 rgba[1] = 1;
3947 rgba[2] = 6 * (v - vmin - 2.0 * dv / 6.0) / dv;
3948 } else if (v < (vmin + 4.0 * dv / 6.0)) {
3949 rgba[0] = 0;
3950 rgba[1] = 1 + 6 * (vmin + 3.0 * dv / 6.0 - v) / dv;
3951 rgba[2] = 1;
3952 } else if (v < (vmin + 5.0 * dv / 6.0)) {
3953 rgba[0] = 6 * (v - vmin - 4.0 * dv / 6.0) / dv;
3954 rgba[1] = 0;
3955 rgba[2] = 1;
3956 } else {
3957 rgba[0] = 1;
3958 rgba[1] = 0;
3959 rgba[2] = 1 + 6 * (vmin + 5.0 * dv / 6.0 - v) / dv;
3960 }
3961 break;
3962 case 5:
3963 rgba[0] = (v - vmin) / (vmax - vmin);
3964 rgba[1] = 1;
3965 rgba[2] = 0;
3966 break;
3967 case 6:
3968 rgba[0] = (v - vmin) / (vmax - vmin);
3969 rgba[1] = (vmax - v) / (vmax - vmin);
3970 rgba[2] = rgba[0];
3971 break;
3972 case 7:
3973 if (v < (