Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TEveBoxSetGL.cxx
Go to the documentation of this file.
1 // @(#)root/eve:$Id$
2 // Authors: Matevz Tadel & Alja Mrak-Tadel: 2006, 2007
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2007, 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 "TEveBoxSetGL.h"
13 #include "TEveBoxSet.h"
14 
15 #include "TGLIncludes.h"
16 #include "TGLRnrCtx.h"
17 #include "TGLSelectRecord.h"
18 #include "TGLQuadric.h"
19 
20 /** \class TEveBoxSetGL
21 \ingroup TEve
22 A GL rendering class for TEveBoxSet.
23 */
24 
25 ClassImp(TEveBoxSetGL);
26 
27 ////////////////////////////////////////////////////////////////////////////////
28 /// Default constructor.
29 
30 TEveBoxSetGL::TEveBoxSetGL() : TEveDigitSetGL(), fM(0), fBoxDL(0)
31 {
32  fDLCache = kFALSE; // Disable display list, used internally for boxes, cones.
33  fMultiColor = kTRUE;
34 }
35 
36 ////////////////////////////////////////////////////////////////////////////////
37 /// Destructor.
38 
39 TEveBoxSetGL::~TEveBoxSetGL()
40 {
41  DLCachePurge();
42 }
43 
44 ////////////////////////////////////////////////////////////////////////////////
45 /// Return GL primitive used to render the boxes, based on the
46 /// render-mode specified in the model object.
47 
48 Int_t TEveBoxSetGL::PrimitiveType() const
49 {
50  return (fM->fRenderMode != TEveDigitSet::kRM_Line) ? GL_QUADS : GL_LINE_LOOP;
51 }
52 
53 ////////////////////////////////////////////////////////////////////////////////
54 /// Fill array p to represent a box (0,0,0) - (dx,dy,dz).
55 
56 void TEveBoxSetGL::MakeOriginBox(Float_t p[8][3], Float_t dx, Float_t dy, Float_t dz) const
57 {
58  // bottom
59  p[0][0] = 0; p[0][1] = dy; p[0][2] = 0;
60  p[1][0] = dx; p[1][1] = dy; p[1][2] = 0;
61  p[2][0] = dx; p[2][1] = 0; p[2][2] = 0;
62  p[3][0] = 0; p[3][1] = 0; p[3][2] = 0;
63  // top
64  p[4][0] = 0; p[4][1] = dy; p[4][2] = dz;
65  p[5][0] = dx; p[5][1] = dy; p[5][2] = dz;
66  p[6][0] = dx; p[6][1] = 0; p[6][2] = dz;
67  p[7][0] = 0; p[7][1] = 0; p[7][2] = dz;
68 }
69 
70 ////////////////////////////////////////////////////////////////////////////////
71 /// Render a box specified by points in array p with standard
72 /// axis-aligned normals.
73 
74 inline void TEveBoxSetGL::RenderBoxStdNorm(const Float_t p[8][3]) const
75 {
76  // bottom: 0123
77  glNormal3f(0, 0, -1);
78  glVertex3fv(p[0]); glVertex3fv(p[1]);
79  glVertex3fv(p[2]); glVertex3fv(p[3]);
80  // top: 7654
81  glNormal3f(0, 0, 1);
82  glVertex3fv(p[7]); glVertex3fv(p[6]);
83  glVertex3fv(p[5]); glVertex3fv(p[4]);
84  // back: 0451
85  glNormal3f(0, 1, 0);
86  glVertex3fv(p[0]); glVertex3fv(p[4]);
87  glVertex3fv(p[5]); glVertex3fv(p[1]);
88  // front: 3267
89  glNormal3f(0, -1, 0);
90  glVertex3fv(p[3]); glVertex3fv(p[2]);
91  glVertex3fv(p[6]); glVertex3fv(p[7]);
92  // left: 0374
93  glNormal3f(-1, 0, 0);
94  glVertex3fv(p[0]); glVertex3fv(p[3]);
95  glVertex3fv(p[7]); glVertex3fv(p[4]);
96  // right: 1562
97  glNormal3f(1, 0, 0);
98  glVertex3fv(p[1]); glVertex3fv(p[5]);
99  glVertex3fv(p[6]); glVertex3fv(p[2]);
100 }
101 
102 namespace
103 {
104  void subtract_and_normalize(const Float_t a[3], const Float_t b[3],
105  Float_t o[3])
106  {
107  // Calculate a - b and normalize the result.
108  o[0] = a[0] - b[0];
109  o[1] = a[1] - b[1];
110  o[2] = a[2] - b[2];
111  Float_t d = sqrtf(o[0]*o[0] + o[1]*o[1] + o[2]*o[2]);
112  if (d != 0)
113  {
114  d = 1.0f / d;
115  o[0] *= d;
116  o[1] *= d;
117  o[2] *= d;
118  }
119  }
120 }
121 ////////////////////////////////////////////////////////////////////////////////
122 /// Render box, calculate normals on the fly from first three points.
123 
124 void TEveBoxSetGL::RenderBoxAutoNorm(const Float_t p[8][3]) const
125 {
126  Float_t e[6][3], n[3];
127  subtract_and_normalize(p[1], p[0], e[0]);
128  subtract_and_normalize(p[3], p[0], e[1]);
129  subtract_and_normalize(p[4], p[0], e[2]);
130  subtract_and_normalize(p[5], p[6], e[3]);
131  subtract_and_normalize(p[7], p[6], e[4]);
132  subtract_and_normalize(p[2], p[6], e[5]);
133 
134  // bottom: 0123
135  glNormal3fv(TMath::Cross(e[0], e[1], n));
136  glVertex3fv(p[0]); glVertex3fv(p[1]);
137  glVertex3fv(p[2]); glVertex3fv(p[3]);
138  // top: 7654
139  glNormal3fv(TMath::Cross(e[3], e[4], n));
140  glVertex3fv(p[7]); glVertex3fv(p[6]);
141  glVertex3fv(p[5]); glVertex3fv(p[4]);
142  // back: 0451
143  glNormal3fv(TMath::Cross(e[2], e[0], n));
144  glVertex3fv(p[0]); glVertex3fv(p[4]);
145  glVertex3fv(p[5]); glVertex3fv(p[1]);
146  // front: 3267
147  glNormal3fv(TMath::Cross(e[4], e[5], n));
148  glVertex3fv(p[3]); glVertex3fv(p[2]);
149  glVertex3fv(p[6]); glVertex3fv(p[7]);
150  // left: 0374
151  glNormal3fv(TMath::Cross(e[1], e[2], n));
152  glVertex3fv(p[0]); glVertex3fv(p[3]);
153  glVertex3fv(p[7]); glVertex3fv(p[4]);
154  // right: 1562
155  glNormal3fv(TMath::Cross(e[5], e[3], n));
156  glVertex3fv(p[1]); glVertex3fv(p[5]);
157  glVertex3fv(p[6]); glVertex3fv(p[2]);
158 }
159 
160 ////////////////////////////////////////////////////////////////////////////////
161 /// Create a display-list for rendering a single box, based on the
162 /// current box-type.
163 /// Some box-types don't benefit from the display-list rendering and
164 /// so display-list is not created.
165 
166 void TEveBoxSetGL::MakeDisplayList() const
167 {
168  if (fM->fBoxType == TEveBoxSet::kBT_AABox ||
169  fM->fBoxType == TEveBoxSet::kBT_AABoxFixedDim ||
170  fM->fBoxType == TEveBoxSet::kBT_Cone ||
171  fM->fBoxType == TEveBoxSet::kBT_EllipticCone ||
172  fM->fBoxType == TEveBoxSet::kBT_Hex)
173  {
174  if (fBoxDL == 0)
175  fBoxDL = glGenLists(1);
176 
177  glNewList(fBoxDL, GL_COMPILE);
178 
179  if (fM->fBoxType < TEveBoxSet::kBT_Cone)
180  {
181  glBegin(PrimitiveType());
182  Float_t p[8][3];
183  if (fM->fBoxType == TEveBoxSet::kBT_AABox)
184  MakeOriginBox(p, 1.0f, 1.0f, 1.0f);
185  else
186  MakeOriginBox(p, fM->fDefWidth, fM->fDefHeight, fM->fDefDepth);
187  RenderBoxStdNorm(p);
188  glEnd();
189  }
190  else if (fM->fBoxType < TEveBoxSet::kBT_Hex)
191  {
192  static TGLQuadric quad;
193  Int_t nt = 15; // number of corners
194  gluCylinder(quad.Get(), 0, 1, 1, nt, 1);
195 
196  if (fM->fDrawConeCap)
197  {
198  glPushMatrix();
199  glTranslatef(0, 0, 1);
200  gluDisk(quad.Get(), 0, 1, nt, 1);
201  glPopMatrix();
202  }
203  }
204  else // Hexagons
205  {
206  static TGLQuadric quad;
207  Int_t nt = 6; // number of corners
208  gluCylinder(quad.Get(), 1, 1, 1, nt, 1);
209 
210  gluQuadricOrientation(quad.Get(), GLU_INSIDE);
211  gluDisk(quad.Get(), 0, 1, nt, 1);
212  gluQuadricOrientation(quad.Get(), GLU_OUTSIDE);
213 
214  glPushMatrix();
215  glTranslatef(0, 0, 1);
216  gluDisk(quad.Get(), 0, 1, nt, 1);
217  glPopMatrix();
218  }
219 
220  glEndList();
221 
222  TGLUtil::CheckError("TEveBoxSetGL::MakeDisplayList");
223  }
224 }
225 
226 ////////////////////////////////////////////////////////////////////////////////
227 /// Determines if display-list will be used for rendering.
228 /// Virtual from TGLLogicalShape.
229 
230 Bool_t TEveBoxSetGL::ShouldDLCache(const TGLRnrCtx& rnrCtx) const
231 {
232  return TEveDigitSetGL::ShouldDLCache(rnrCtx);
233 }
234 
235 ////////////////////////////////////////////////////////////////////////////////
236 /// Called when display lists have been destroyed externally and the
237 /// internal display-list data needs to be cleare.
238 /// Virtual from TGLLogicalShape.
239 
240 void TEveBoxSetGL::DLCacheDrop()
241 {
242  fBoxDL = 0;
243  TGLObject::DLCacheDrop();
244 }
245 
246 ////////////////////////////////////////////////////////////////////////////////
247 /// Called when display-lists need to be returned to the system.
248 /// Virtual from TGLLogicalShape.
249 
250 void TEveBoxSetGL::DLCachePurge()
251 {
252  if (fBoxDL != 0)
253  {
254  PurgeDLRange(fBoxDL, 1);
255  fBoxDL = 0;
256  }
257  TGLObject::DLCachePurge();
258 }
259 
260 ////////////////////////////////////////////////////////////////////////////////
261 /// Set model object.
262 /// Virtual from TGLObject.
263 
264 Bool_t TEveBoxSetGL::SetModel(TObject* obj, const Option_t* /*opt*/)
265 {
266  fM = SetModelDynCast<TEveBoxSet>(obj);
267  return kTRUE;
268 }
269 
270 namespace
271 {
272  inline void AntiFlick(Float_t x, Float_t y, Float_t z)
273  {
274  // Render anti-flickering point.
275  glBegin(GL_POINTS);
276  glVertex3f(x, y, z);
277  glEnd();
278  }
279 }
280 
281 ////////////////////////////////////////////////////////////////////////////////
282 /// GL rendering for all box-types.
283 
284 void TEveBoxSetGL::RenderBoxes(TGLRnrCtx& rnrCtx) const
285 {
286  static const TEveException eH("TEveBoxSetGL::RenderBoxes ");
287 
288  if (rnrCtx.SecSelection()) glPushName(0);
289 
290  Int_t boxSkip = 0;
291  if (fM->fBoxSkip > 0 && rnrCtx.CombiLOD() < TGLRnrCtx::kLODHigh &&
292  !rnrCtx.SecSelection())
293  {
294  boxSkip = TMath::Nint(TMath::Power(fM->fBoxSkip, 2.0 - 0.02*rnrCtx.CombiLOD()));
295  }
296 
297  TEveChunkManager::iterator bi(fM->fPlex);
298  if (rnrCtx.Highlight() && fHighlightSet)
299  bi.fSelection = fHighlightSet;
300 
301  switch (fM->fBoxType)
302  {
303 
304  case TEveBoxSet::kBT_FreeBox:
305  {
306  GLenum primitiveType = PrimitiveType();
307  while (bi.next())
308  {
309  TEveBoxSet::BFreeBox_t& b = * (TEveBoxSet::BFreeBox_t*) bi();
310  if (SetupColor(b))
311  {
312  if (rnrCtx.SecSelection()) glLoadName(bi.index());
313  glBegin(primitiveType);
314  RenderBoxAutoNorm(b.fVertices);
315  glEnd();
316  if (fM->fAntiFlick)
317  AntiFlick(0.5f*(b.fVertices[0][0] + b.fVertices[6][0]),
318  0.5f*(b.fVertices[0][1] + b.fVertices[6][1]),
319  0.5f*(b.fVertices[0][2] + b.fVertices[6][2]));
320  }
321  if (boxSkip) { Int_t s = boxSkip; while (s--) bi.next(); }
322  }
323  break;
324  } // end case free-box
325 
326  case TEveBoxSet::kBT_AABox:
327  {
328  glEnable(GL_NORMALIZE);
329  while (bi.next())
330  {
331  TEveBoxSet::BAABox_t& b = * (TEveBoxSet::BAABox_t*) bi();
332  if (SetupColor(b))
333  {
334  if (rnrCtx.SecSelection()) glLoadName(bi.index());
335  glPushMatrix();
336  glTranslatef(b.fA, b.fB, b.fC);
337  glScalef (b.fW, b.fH, b.fD);
338  glCallList(fBoxDL);
339  if (fM->fAntiFlick)
340  AntiFlick(0.5f, 0.5f, 0.5f);
341  glPopMatrix();
342  }
343  if (boxSkip) { Int_t s = boxSkip; while (s--) bi.next(); }
344  }
345  break;
346  }
347 
348  case TEveBoxSet::kBT_AABoxFixedDim:
349  {
350  while (bi.next())
351  {
352  TEveBoxSet::BAABoxFixedDim_t& b = * (TEveBoxSet::BAABoxFixedDim_t*) bi();
353  if (SetupColor(b))
354  {
355  if (rnrCtx.SecSelection()) glLoadName(bi.index());
356  glTranslatef(b.fA, b.fB, b.fC);
357  glCallList(fBoxDL);
358  if (fM->fAntiFlick)
359  AntiFlick(0.5f*fM->fDefWidth, 0.5f*fM->fDefHeight, 0.5f*fM->fDefDepth);
360  glTranslatef(-b.fA, -b.fB, -b.fC);
361  }
362  if (boxSkip) { Int_t s = boxSkip; while (s--) bi.next(); }
363  }
364  break;
365  }
366 
367  case TEveBoxSet::kBT_Cone:
368  {
369  using namespace TMath;
370 
371  glEnable(GL_NORMALIZE);
372  Float_t theta=0, phi=0, h=0;
373  while (bi.next())
374  {
375  TEveBoxSet::BCone_t& b = * (TEveBoxSet::BCone_t*) bi();
376  if (SetupColor(b))
377  {
378  if (rnrCtx.SecSelection()) glLoadName(bi.index());
379  h = b.fDir.Mag();
380  phi = ATan2(b.fDir.fY, b.fDir.fX)*RadToDeg();
381  theta = ATan (b.fDir.fZ / Sqrt(b.fDir.fX*b.fDir.fX + b.fDir.fY*b.fDir.fY))*RadToDeg();
382  glPushMatrix();
383  glTranslatef(b.fPos.fX, b.fPos.fY, b.fPos.fZ);
384  glRotatef(phi, 0, 0, 1);
385  glRotatef(90 - theta, 0, 1, 0);
386  glScalef (b.fR, b.fR, h);
387  glCallList(fBoxDL);
388  if (fM->fAntiFlick)
389  AntiFlick(0.0f, 0.0f, 0.5f);
390  glPopMatrix();
391  }
392  if (boxSkip) { Int_t s = boxSkip; while (s--) bi.next(); }
393  }
394  break;
395  }
396 
397  case TEveBoxSet::kBT_EllipticCone:
398  {
399  using namespace TMath;
400 
401  glEnable(GL_NORMALIZE);
402  Float_t theta=0, phi=0, h=0;
403  while (bi.next())
404  {
405  TEveBoxSet::BEllipticCone_t& b = * (TEveBoxSet::BEllipticCone_t*) bi();
406  if (SetupColor(b))
407  {
408  if (rnrCtx.SecSelection()) glLoadName(bi.index());
409  h = b.fDir.Mag();
410  phi = ATan2(b.fDir.fY, b.fDir.fX)*RadToDeg();
411  theta = ATan (b.fDir.fZ / Sqrt(b.fDir.fX*b.fDir.fX + b.fDir.fY*b.fDir.fY))*RadToDeg();
412  glPushMatrix();
413  glTranslatef(b.fPos.fX, b.fPos.fY, b.fPos.fZ);
414  glRotatef(phi, 0, 0, 1);
415  glRotatef(90 - theta, 0, 1, 0);
416  glRotatef(b.fAngle, 0, 0, 1);
417  glScalef (b.fR, b.fR2, h);
418  glCallList(fBoxDL);
419  if (fM->fAntiFlick)
420  AntiFlick(0.0f, 0.0f, 0.5f);
421  glPopMatrix();
422  }
423  if (boxSkip) { Int_t s = boxSkip; while (s--) bi.next(); }
424  }
425  break;
426  }
427 
428  case TEveBoxSet::kBT_Hex:
429  {
430  using namespace TMath;
431 
432  glEnable(GL_NORMALIZE);
433  while (bi.next())
434  {
435  TEveBoxSet::BHex_t& h = * (TEveBoxSet::BHex_t*) bi();
436  if (SetupColor(h))
437  {
438  if (rnrCtx.SecSelection()) glLoadName(bi.index());
439  glPushMatrix();
440  glTranslatef(h.fPos.fX, h.fPos.fY, h.fPos.fZ);
441  glRotatef(h.fAngle, 0, 0, 1);
442  glScalef (h.fR, h.fR, h.fDepth);
443  glCallList(fBoxDL);
444  if (fM->fAntiFlick)
445  AntiFlick(0.0f, 0.0f, 0.5f);
446  glPopMatrix();
447  }
448  if (boxSkip) { Int_t s = boxSkip; while (s--) bi.next(); }
449  }
450  break;
451  }
452 
453  default:
454  {
455  throw eH + "unsupported box-type.";
456  }
457 
458  } // end switch box-type
459 
460  if (rnrCtx.SecSelection()) glPopName();
461 }
462 
463 ////////////////////////////////////////////////////////////////////////////////
464 /// Actual rendering code.
465 /// Virtual from TGLLogicalShape.
466 
467 void TEveBoxSetGL::DirectDraw(TGLRnrCtx& rnrCtx) const
468 {
469  TEveBoxSet& mB = * fM;
470  // printf("TEveBoxSetGL::DirectDraw N boxes %d\n", mB.fPlex.Size());
471 
472  if (mB.fPlex.Size() > 0)
473  {
474  MakeDisplayList();
475 
476  if (! mB.fSingleColor && ! mB.fValueIsColor && mB.fPalette == 0)
477  {
478  mB.AssertPalette();
479  }
480 
481  glPushAttrib(GL_ENABLE_BIT | GL_POLYGON_BIT);
482 
483  if ( ! rnrCtx.IsDrawPassOutlineLine())
484  {
485  if (mB.fRenderMode == TEveDigitSet::kRM_Fill)
486  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
487  else if (mB.fRenderMode == TEveDigitSet::kRM_Line)
488  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
489  }
490 
491  if (mB.fBoxType == TEveBoxSet::kBT_Cone ||
492  mB.fBoxType == TEveBoxSet::kBT_EllipticCone)
493  {
494  glDisable(GL_CULL_FACE);
495  }
496 
497  if (mB.fDisableLighting) glDisable(GL_LIGHTING);
498 
499  RenderBoxes(rnrCtx);
500 
501  glPopAttrib();
502  }
503 
504  DrawFrameIfNeeded(rnrCtx);
505 }
506 
507 ////////////////////////////////////////////////////////////////////////////////
508 /// Interface for direct rendering from classes that include TEveBoxSet
509 /// as a member.
510 
511 void TEveBoxSetGL::Render(TGLRnrCtx& rnrCtx)
512 {
513  DirectDraw(rnrCtx);
514 }