]> git.uio.no Git - u/mrichter/AliRoot.git/blob - EVE/Reve/QuadSet.cxx
From Cvetan: new macro to load ITS clusters.
[u/mrichter/AliRoot.git] / EVE / Reve / QuadSet.cxx
1 // $Header$
2
3 #include "QuadSet.h"
4 #include "RGBAPalette.h"
5 #include "RGTopFrame.h"
6
7 #include <TColor.h>
8
9 #include <TBuffer3D.h>
10 #include <TBuffer3DTypes.h>
11 #include <TGeometry.h>
12 #include <TVirtualPad.h>
13 #include <TVirtualViewer3D.h>
14
15 #include <TROOT.h>
16 #include <TRandom.h>
17
18
19 using namespace Reve;
20
21 /**************************************************************************/
22 // Quad
23 /**************************************************************************/
24 ClassImp(Reve::Quad)
25
26 void Quad::ColorFromIdx(Color_t ci)
27 {
28   TColor* c = gROOT->GetColor(ci);
29   if(c) {
30     UChar_t *x = (UChar_t*) &color;
31     x[0] = (UChar_t)(255*c->GetRed());  x[1] = (UChar_t)(255*c->GetGreen());
32     x[2] = (UChar_t)(255*c->GetBlue()); x[3] = 255;
33   }
34 }
35
36 Quad::Quad(TRandom& rnd, Float_t origin, Float_t size) : color(0)
37 {
38   ColorFromIdx(Int_t(30*rnd.Rndm()));
39   Float_t x = 2*origin*(rnd.Rndm() - 0.5);
40   Float_t y = 2*origin*(rnd.Rndm() - 0.5);
41   Float_t z = 2*origin*(rnd.Rndm() - 0.5);
42   Float_t* p = vertices;
43   for(int i=0; i<4; ++i) {
44     p[0] = x + 2*size*(rnd.Rndm() - 0.5);
45     p[1] = y + 2*size*(rnd.Rndm() - 0.5);
46     p[2] = z + 2*size*(rnd.Rndm() - 0.5);
47     p += 3;
48   }
49 }
50
51 /**************************************************************************/
52 // OldQuadSet
53 /**************************************************************************/
54 ClassImp(Reve::OldQuadSet)
55
56
57 OldQuadSet::OldQuadSet(const Text_t* n, const Text_t* t) :
58   TNamed(n, t),
59   fQuads(),
60   fTrans(false)
61 {}
62
63 void OldQuadSet::Test(Int_t nquads)
64 {
65   TRandom rnd(0);
66   fQuads.resize(nquads);
67   for(Int_t i=0; i<nquads; ++i) {
68     new (&fQuads[i]) Quad(rnd, 10, 2);
69   }
70 }
71
72 void OldQuadSet::Paint(Option_t* )
73 {
74   TBuffer3D buffer(TBuffer3DTypes::kGeneric);
75
76   // Section kCore
77   buffer.fID           = this;
78   buffer.fColor        = 1;
79   buffer.fTransparency = 0;
80   buffer.fLocalFrame   = fTrans; 
81   if (fTrans)
82     memcpy(buffer.fLocalMaster, fMatrix, 16*sizeof(Double_t));
83   buffer.SetSectionsValid(TBuffer3D::kCore);
84    
85   // We fill kCore on first pass and try with viewer
86   Int_t reqSections = gPad->GetViewer3D()->AddObject(buffer);
87   if (reqSections == TBuffer3D::kNone) {
88     // printf("OldQuadSet::Paint viewer was happy with Core buff3d.\n");
89     return;
90   }
91    
92   if (reqSections & TBuffer3D::kRawSizes) {
93     Int_t nbPnts = fQuads.size()*4;
94     Int_t nbSegs = nbPnts;
95     if (!buffer.SetRawSizes(nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, fQuads.size(), fQuads.size()*6)) {
96       return;
97     }
98     buffer.SetSectionsValid(TBuffer3D::kRawSizes); 
99   }
100
101   if ((reqSections & TBuffer3D::kRaw) && buffer.SectionsValid(TBuffer3D::kRawSizes)) {
102     // Points
103     Int_t pidx = 0;
104     for (std::vector<Quad>::iterator i=fQuads.begin(); i!=fQuads.end(); ++i) {
105       for (Int_t k = 0; k < 12; k++ ){
106         buffer.fPnts[pidx] = (*i).vertices[k]; 
107         pidx++;
108       }
109     }
110
111     // Segments
112     Int_t sidx = 0;
113     for (Int_t q = 0; q < (Int_t)fQuads.size(); ++q) {
114       for (Int_t s = 0; s < 4; ++s ) {
115         buffer.fSegs[3*sidx ] = 4; 
116         buffer.fSegs[3*sidx+1] = sidx;
117         if (s == 3)
118           buffer.fSegs[3*sidx+2] = q*4;
119         else
120           buffer.fSegs[3*sidx+2] = sidx + 1;
121         sidx ++;
122       }
123     }
124
125     // Polygons
126     for (Int_t q = 0; q < (Int_t)fQuads.size(); ++q) {
127       buffer.fPols[6*q] = fQuads[q].color;   
128       buffer.fPols[6*q +1] = 4;
129       buffer.fPols[6*q +2] = 4*q + 0;
130       buffer.fPols[6*q +3] = 4*q + 1;
131       buffer.fPols[6*q +4] = 4*q + 2;
132       buffer.fPols[6*q +5] = 4*q + 3;
133     }
134
135     buffer.SetSectionsValid(TBuffer3D::kRaw);
136     buffer.fColor = 5;
137   }
138    
139   gPad->GetViewer3D()->AddObject(buffer);
140 }
141
142 /**************************************************************************/
143
144 void OldQuadSet::ComputeBBox()
145 {
146   if(fQuads.empty()) {
147     BBoxZero();
148     return;
149   }
150   BBoxInit();
151   for(std::vector<Quad>::iterator q=fQuads.begin(); q!=fQuads.end(); ++q) {
152     Float_t* p = q->vertices;
153     for(int i=0; i<4; ++i, p+=3)
154       BBoxCheckPoint(p);
155   }
156
157   // printf("%s BBox is x(%f,%f), y(%f,%f), z(%f,%f)\n", GetName(),
158   //        fBBox[0], fBBox[1], fBBox[2], fBBox[3], fBBox[4], fBBox[5]);
159 }
160
161 /**************************************************************************/
162 /**************************************************************************/
163 /**************************************************************************/
164 /**************************************************************************/
165
166 //__________________________________________________________________________
167 // QuadSet
168 //
169 // Supports various internal formats that result in rendering of a
170 // set of rectangular objects.
171 //
172 // Names of internal structures and their variables use fixed
173 // assignment to x, z, y coordinates; the render types can override
174 // this convention and impose Y as a fixed coordinate.
175 // For quad modes the deltas are expected to be positive.
176 // For line modes negative deltas are ok.
177
178 ClassImp(Reve::QuadSet)
179
180 QuadSet::QuadSet(const Text_t* n, const Text_t* t) :
181   RenderElement(),
182   TNamed(n, t),
183
184   fQuadType(QT_Undef),
185   fDefaultValue(kMinInt),
186   fValueIsColor(kFALSE),
187   fOwnIds      (kFALSE),
188   fPlex(),
189   fLastQuad(0),
190
191   fDefWidth(1), fDefHeight(1), fDefCoord(0),
192
193   fFrame  (0),
194   fPalette(0),
195   fRenderMode(RM_Fill),
196   fDisableLigting(kTRUE),
197   fEmitSignals(kFALSE),
198   fHMTrans()
199 {}
200
201 QuadSet::QuadSet(QuadType_e quadType, Bool_t valIsCol, Int_t chunkSize,
202                  const Text_t* n, const Text_t* t) :
203   RenderElement(),
204   TNamed(n, t),
205
206   fQuadType(quadType),
207   fDefaultValue(valIsCol ? 0 : kMinInt),
208   fValueIsColor(valIsCol),
209   fOwnIds      (kFALSE),
210   fPlex(SizeofAtom(quadType), chunkSize),
211   fLastQuad(0),
212
213   fDefWidth(1), fDefHeight(1), fDefCoord(0),
214
215   fFrame  (0),
216   fPalette(0),
217   fRenderMode(RM_Fill),
218   fDisableLigting(kTRUE),
219   fEmitSignals(kFALSE),
220   fHMTrans()
221 {}
222
223 QuadSet::~QuadSet()
224 {
225   SetFrame(0);
226   SetPalette(0);
227   if (fOwnIds)
228     ReleaseIds();
229 }
230
231 void QuadSet::ReleaseIds()
232 {
233   VoidCPlex::iterator qi(fPlex);
234   while (qi.next()) {
235     QuadBase& q = * (QuadBase*) qi();
236     if (q.fId.GetObject()) {
237       delete q.fId.GetObject();
238       q.fId = 0;
239     }
240   }
241 }
242
243 /**************************************************************************/
244
245 Int_t QuadSet::SizeofAtom(QuadSet::QuadType_e qt)
246 {
247   static const Exc_t eH("QuadSet::SizeofAtom ");
248
249   switch (qt) {
250     case QT_Undef:                return 0;
251     case QT_FreeQuad:             return sizeof(QFreeQuad);
252     case QT_RectangleXY:          return sizeof(QRect);
253     case QT_RectangleXYFixedDim:  return sizeof(QRectFixDim);
254     case QT_RectangleXZFixedY:
255     case QT_RectangleXYFixedZ:    return sizeof(QRectFixC);
256     case QT_RectangleXZFixedDimY:
257     case QT_RectangleXYFixedDimZ: return sizeof(QRectFixDimC);
258     case QT_LineXZFixedY:
259     case QT_LineXYFixedZ:         return sizeof(QLineFixC);
260     case QT_HexagonXY:
261     case QT_HexagonYX:            return sizeof(QHex);
262     default:                      throw(eH + "unexpected atom type.");
263   }
264   return 0;
265 }
266
267 /**************************************************************************/
268
269 void QuadSet::Reset(QuadSet::QuadType_e quadType, Bool_t valIsCol, Int_t chunkSize)
270 {
271   fQuadType     = quadType;
272   fValueIsColor = valIsCol;
273   fDefaultValue = valIsCol ? 0 : kMinInt;
274   if (fOwnIds)
275     ReleaseIds();
276   fPlex.Reset(SizeofAtom(fQuadType), chunkSize);
277 }
278
279 void QuadSet::RefitPlex()
280 {
281   // Instruct underlying memory allocator to regroup itself into a
282   // contiguous memory chunk.
283
284   fPlex.Refit();
285 }
286
287 /**************************************************************************/
288
289 void QuadSet::ScanMinMaxValues(Int_t& min, Int_t& max)
290 {
291   if (fValueIsColor || fPlex.Size() == 0) return;
292   min = kMaxInt;
293   max = kMinInt;
294   for (Int_t c=0; c<fPlex.VecSize(); ++c)
295   {
296     Char_t* a = fPlex.Chunk(c);
297     Int_t   n = fPlex.NAtoms(c);
298     while (n--)
299     {
300       Int_t v = ((QuadBase*)a)->fValue;
301       if (v < min) min = v;
302       if (v > max) max = v;
303       a += fPlex.S();
304     }
305   }
306   if (min == max)
307     --min;
308 }
309
310 /**************************************************************************/
311
312 void QuadSet::SetMainColor(Color_t color)
313 {
314   if (fFrame) {
315     fFrame->SetFrameColor(color);
316     fFrame->UpdateBackPtrItems();
317   }
318   gReve->Redraw3D();
319 }
320
321 void QuadSet::SetFrame(FrameBox* b)
322 {
323   if (fFrame == b) return;
324   if (fFrame) fFrame->DecRefCount(this);
325   fFrame = b;
326   if (fFrame) {
327     fFrame->IncRefCount(this);
328     SetMainColorPtr(fFrame->PtrFrameColor());
329   } else {
330     SetMainColorPtr(0);
331   }
332 }
333
334 void QuadSet::SetPalette(RGBAPalette* p)
335 {
336   if (fPalette == p) return;
337   if (fPalette) fPalette->DecRefCount();
338   fPalette = p;
339   if (fPalette) fPalette->IncRefCount();
340 }
341
342 RGBAPalette* QuadSet::AssertPalette()
343 {
344   if (fPalette == 0) {
345     fPalette = new RGBAPalette;
346     if (!fValueIsColor) {
347       Int_t min, max;
348       ScanMinMaxValues(min, max);
349       fPalette->SetLimits(min, max);
350       fPalette->SetMinMax(min, max);
351     }
352   }
353   return fPalette;
354 }
355
356 /**************************************************************************/
357
358 QuadSet::QuadBase* QuadSet::NewQuad()
359 {
360   fLastQuad = new (fPlex.NewAtom()) QuadBase(fDefaultValue);
361   return fLastQuad;
362 }
363
364 void QuadSet::AddQuad(Float_t* verts)
365 {
366   static const Exc_t eH("QuadSet::AddQuad ");
367
368   if (fQuadType != QT_FreeQuad)
369     throw(eH + "expect free quad-type.");
370
371   QFreeQuad* fq = (QFreeQuad*) NewQuad();
372   memcpy(fq->fVertices, verts, sizeof(fq->fVertices));
373 }
374
375 void QuadSet::AddQuad(Float_t x, Float_t y)
376 {
377   AddQuad(x, y, fDefCoord, fDefWidth, fDefHeight);
378 }
379
380 void QuadSet::AddQuad(Float_t x, Float_t y, Float_t z)
381 {
382   AddQuad(x, y, z, fDefWidth, fDefHeight);
383 }
384
385 void QuadSet::AddQuad(Float_t x, Float_t y, Float_t w, Float_t h)
386 {
387   AddQuad(x, y, fDefCoord, w, h);
388 }
389
390 void QuadSet::AddQuad(Float_t x, Float_t y, Float_t z, Float_t w, Float_t h)
391 {
392   static const Exc_t eH("QuadSet::AddAAQuad ");
393
394   QOrigin& fq = * (QOrigin*) NewQuad();
395   fq.fX = x; fq.fY = y;
396   switch (fQuadType)
397   {
398     case QT_RectangleXY: {
399       QRect& q = (QRect&) fq;
400       q.fZ = z; q.fW = w; q.fH = h;
401       break;
402     }
403     case QT_RectangleXYFixedDim: {
404       QRectFixDim& q =  (QRectFixDim&) fq;
405       q.fZ = z;
406       break;
407     }
408     case QT_RectangleXZFixedY:
409     case QT_RectangleXYFixedZ: {
410       QRectFixC& q = (QRectFixC&) fq;
411       q.fW = w; q.fH = h;
412       break;
413     }
414     case QT_RectangleXZFixedDimY:
415     case QT_RectangleXYFixedDimZ: {
416       break;
417     }
418     default:
419       throw(eH + "expect axis-aligned quad-type.");
420   }
421 }
422
423 void QuadSet::AddLine(Float_t x, Float_t y, Float_t w, Float_t h)
424 {
425   static const Exc_t eH("QuadSet::AddLine ");
426
427   QOrigin& fq = * (QOrigin*) NewQuad();
428   fq.fX = x; fq.fY = y;
429   switch (fQuadType)
430   {
431     case QT_LineXZFixedY:
432     case QT_LineXYFixedZ: {
433       QLineFixC& q = (QLineFixC&) fq;
434       q.fDx = w; q.fDy = h;
435       break;
436     }
437     default:
438       throw(eH + "expect line quad-type.");
439   }
440 }
441
442 void QuadSet::AddHexagon(Float_t x, Float_t y, Float_t z, Float_t r)
443 {
444   static const Exc_t eH("QuadSet::AddHexagon ");
445
446   QOrigin& fq = * (QOrigin*) NewQuad();
447   fq.fX = x; fq.fY = y;
448   switch (fQuadType)
449   {
450     case QT_HexagonXY:
451     case QT_HexagonYX: {
452       QHex& q = (QHex&) fq;
453       q.fZ = z; q.fR = r;
454       break;
455     }
456     default:
457       throw(eH + "expect line quad-type.");
458   }
459 }
460
461 /**************************************************************************/
462
463 void QuadSet::QuadValue(Int_t value)
464 {
465   fLastQuad->fValue = value;
466 }
467
468 void QuadSet::QuadColor(Color_t ci)
469 {
470   ColorFromIdx(ci, (UChar_t*) & fLastQuad->fValue, kTRUE);
471 }
472
473 void QuadSet::QuadColor(UChar_t r, UChar_t g, UChar_t b, UChar_t a)
474 {
475   UChar_t* x = (UChar_t*) & fLastQuad->fValue;
476   x[0] = r; x[1] = g; x[2] = b; x[3] = a;
477 }
478
479 /**************************************************************************/
480
481 void QuadSet::QuadId(TObject* id)
482 {
483   fLastQuad->fId = id;
484 }
485
486 /**************************************************************************/
487
488 void QuadSet::QuadSelected(Int_t idx)
489 {
490   if (fEmitSignals) {
491     CtrlClicked(this, idx);
492   } else {
493     QuadBase* qb = GetQuad(idx);
494     TObject* obj = qb->fId.GetObject();
495     printf("QuadSet::QuadSelected idx=%d, value=%d, obj=0x%lx\n",
496            idx, qb->fValue, (ULong_t)obj);
497     if (obj)
498       obj->Print();
499   }
500 }
501
502 void QuadSet::CtrlClicked(QuadSet* qs, Int_t idx)
503 {
504   Long_t args[2];
505   args[0] = (Long_t) qs;
506   args[1] = (Long_t) idx;
507
508   Emit("CtrlClicked(Reve::Track*, Int_t)", args);
509 }
510
511 /**************************************************************************/
512 /**************************************************************************/
513
514 void QuadSet::ComputeBBox()
515 {
516   // Fill bounding-box information in base-class TAttBBox (virtual method).
517   // If member 'FrameBox* fFrame' is set, frame's corners are used as bbox.
518
519   static const Exc_t eH("QuadSet::ComputeBBox ");
520
521   if (fFrame != 0)
522   {
523     BBoxInit();
524     Int_t    n    = fFrame->GetFrameSize() / 3;
525     Float_t *bbps = fFrame->GetFramePoints();
526     for (int i=0; i<n; ++i, bbps+=3)
527       BBoxCheckPoint(bbps);
528   }
529   else
530   {
531     if(fPlex.Size() == 0) {
532       BBoxZero();
533       return;
534     }
535
536     BBoxInit();
537     if (fQuadType == QT_RectangleXYFixedZ    ||
538         fQuadType == QT_RectangleXYFixedDimZ)
539     {
540       fBBox[4] = fDefCoord;
541       fBBox[5] = fDefCoord;
542     }
543     else if (fQuadType == QT_RectangleXZFixedY    ||
544              fQuadType == QT_RectangleXZFixedDimY)
545     {
546       fBBox[2] = fDefCoord;
547       fBBox[3] = fDefCoord;
548     }
549
550     VoidCPlex::iterator qi(fPlex);
551   
552     switch (fQuadType)
553     {
554
555       case QT_FreeQuad:
556       {
557         while (qi.next()) {
558           const Float_t* p =  ((QFreeQuad*) qi())->fVertices;
559           BBoxCheckPoint(p); p += 3;
560           BBoxCheckPoint(p); p += 3;
561           BBoxCheckPoint(p); p += 3;
562           BBoxCheckPoint(p);
563         }
564         break;
565       }
566
567       case QT_RectangleXY:
568       {
569         while (qi.next()) {
570           QRect& q = * (QRect*) qi();
571           if(q.fX        < fBBox[0]) fBBox[0] = q.fX;
572           if(q.fX + q.fW > fBBox[1]) fBBox[1] = q.fX + q.fW;
573           if(q.fY        < fBBox[2]) fBBox[2] = q.fY;
574           if(q.fY + q.fH > fBBox[3]) fBBox[3] = q.fY + q.fH;
575           if(q.fZ        < fBBox[4]) fBBox[4] = q.fZ;
576           if(q.fZ        > fBBox[5]) fBBox[5] = q.fZ;
577         }
578         break;
579       }
580
581       case QT_RectangleXYFixedDim:
582       {
583         const Float_t& w = fDefWidth;
584         const Float_t& h = fDefHeight;
585         while (qi.next()) {
586           QRectFixDim& q = * (QRectFixDim*) qi();
587           if(q.fX     < fBBox[0]) fBBox[0] = q.fX;
588           if(q.fX + w > fBBox[1]) fBBox[1] = q.fX + w;
589           if(q.fY     < fBBox[2]) fBBox[2] = q.fY;
590           if(q.fY + h > fBBox[3]) fBBox[3] = q.fY + h;
591           if(q.fZ     < fBBox[4]) fBBox[4] = q.fZ;
592           if(q.fZ     > fBBox[5]) fBBox[5] = q.fZ;
593         }
594         break;
595       }
596
597       case QT_RectangleXYFixedZ:
598       {
599         while (qi.next()) {
600           QRectFixC& q = * (QRectFixC*) qi();
601           if(q.fX        < fBBox[0]) fBBox[0] = q.fX;
602           if(q.fX + q.fW > fBBox[1]) fBBox[1] = q.fX + q.fW;
603           if(q.fY        < fBBox[2]) fBBox[2] = q.fY;
604           if(q.fY + q.fH > fBBox[3]) fBBox[3] = q.fY + q.fH;
605         }
606         break;
607       }
608
609       case QT_RectangleXZFixedY:
610       {
611         while (qi.next()) {
612           QRectFixC& q = * (QRectFixC*) qi();
613           if(q.fX        < fBBox[0]) fBBox[0] = q.fX;
614           if(q.fX + q.fW > fBBox[1]) fBBox[1] = q.fX + q.fW;
615           if(q.fY        < fBBox[4]) fBBox[4] = q.fY;
616           if(q.fY + q.fH > fBBox[5]) fBBox[5] = q.fY + q.fH;
617         }
618         break;
619       }
620
621       case QT_RectangleXYFixedDimZ:
622       {
623         const Float_t& w = fDefWidth;
624         const Float_t& h = fDefHeight;
625         while (qi.next()) {
626           QRectFixDimC& q = * (QRectFixDimC*) qi();
627           if(q.fX     < fBBox[0]) fBBox[0] = q.fX;
628           if(q.fX + w > fBBox[1]) fBBox[1] = q.fX + w;
629           if(q.fY     < fBBox[2]) fBBox[2] = q.fY;
630           if(q.fY + h > fBBox[3]) fBBox[3] = q.fY + h;
631         }
632         break;
633       }
634
635       case QT_RectangleXZFixedDimY:
636       {
637         const Float_t& w = fDefWidth;
638         const Float_t& h = fDefHeight;
639         while (qi.next()) {
640           QRectFixDimC& q = * (QRectFixDimC*) qi();
641           if(q.fX     < fBBox[0]) fBBox[0] = q.fX;
642           if(q.fX + w > fBBox[1]) fBBox[1] = q.fX + w;
643           if(q.fY     < fBBox[4]) fBBox[4] = q.fY;
644           if(q.fY + h > fBBox[5]) fBBox[5] = q.fY + h;
645         }
646         break;
647       }
648
649       case QT_LineXYFixedZ:
650       {
651         while (qi.next()) {
652           QLineFixC& q = * (QLineFixC*) qi();
653           BBoxCheckPoint(q.fX,         q.fY,         fDefCoord);
654           BBoxCheckPoint(q.fX + q.fDx, q.fY + q.fDy, fDefCoord);
655         }
656         break;
657       }
658
659       case QT_LineXZFixedY:
660       {
661         while (qi.next()) {
662           QLineFixC& q = * (QLineFixC*) qi();
663           BBoxCheckPoint(q.fX,         fDefCoord, q.fY);
664           BBoxCheckPoint(q.fX + q.fDx, fDefCoord, q.fY + q.fDy);
665         }
666         break;
667       }
668
669       // Ignore 'slight' difference, assume square box for both cases.
670       case QT_HexagonXY:
671       case QT_HexagonYX:
672       {
673         while (qi.next()) {
674           QHex& q = * (QHex*) qi();
675           BBoxCheckPoint(q.fX-q.fR, q.fY-q.fR, q.fZ);
676           BBoxCheckPoint(q.fX+q.fR, q.fY+q.fR, q.fZ);
677         }
678         break;
679       }
680
681       default: {
682         throw(eH + "unsupported quad-type.");
683       }
684
685     } // end switch quad-type
686   } // end if frame ... else ...
687
688 #if ROOT_VERSION_CODE <= ROOT_VERSION(5,14,0)
689   { // Resize bounding box so that it does not have 0 volume.
690     // This should be done in TAttBBox (via method AssertMinExtents(epsilon)).
691     // Or handled more gracefully in TGLViewer.
692     static const Float_t eps = 1e-3;
693     for (Int_t i=0; i<6; i+=2) {
694       if (fBBox[i+1] - fBBox[i] < eps) {
695         Float_t b = 0.5*(fBBox[i] + fBBox[i+1]);
696         fBBox[i]   = b - 0.5*eps;
697         fBBox[i+1] = b + 0.5*eps;
698       }
699     }
700   }
701 #else
702   AssertBBoxExtents(0.001);
703 #endif
704 }
705
706 /**************************************************************************/
707
708 void QuadSet::Paint(Option_t* /*option*/)
709 {
710   static const Exc_t eH("QuadSet::Paint ");
711
712   TBuffer3D buff(TBuffer3DTypes::kGeneric);
713
714   // Section kCore
715   buff.fID           = this;
716   buff.fColor        = 1;
717   buff.fTransparency = 0;
718   fHMTrans.SetBuffer3D(buff);
719   buff.SetSectionsValid(TBuffer3D::kCore);
720
721   Int_t reqSections = gPad->GetViewer3D()->AddObject(buff);
722   if (reqSections != TBuffer3D::kNone)
723     Error(eH, "only direct GL rendering supported.");
724 }
725
726 /**************************************************************************/