Logo ROOT   6.10/09
Reference Guide
TGLFaceSet.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Timur Pocheptsov 03/08/2004
3 // NOTE: This code moved from obsoleted TGLSceneObject.h / .cxx - see these
4 // attic files for previous CVS history
5 
6 /*************************************************************************
7  * Copyright (C) 1995-2006, Rene Brun and Fons Rademakers. *
8  * All rights reserved. *
9  * *
10  * For the licensing terms see $ROOTSYS/LICENSE. *
11  * For the list of contributors see $ROOTSYS/README/CREDITS. *
12  *************************************************************************/
13 
14 #include "TGLFaceSet.h"
15 #include "TGLRnrCtx.h"
16 #include "TGLIncludes.h"
17 
18 #include "TBuffer3D.h"
19 #include "TMath.h"
20 
21 // For debug tracing
22 #include "TClass.h"
23 #include "TError.h"
24 
25 #include <stdexcept>
26 
27 // Clone from TGLUtil -- typedefs needed for portable tesselator function typedef.
28 
29 #ifndef CALLBACK
30 #define CALLBACK
31 #endif
32 
33 extern "C"
34 {
35 #if defined(__APPLE_CC__) && __APPLE_CC__ > 4000 && __APPLE_CC__ < 5450 && !defined(__INTEL_COMPILER)
36  typedef GLvoid (*tessfuncptr_t)(...);
37 #elif defined(__linux__) || defined(__FreeBSD__) || defined( __OpenBSD__ ) || defined(__sun) || defined (__CYGWIN__) || defined (__APPLE__)
38  typedef GLvoid (*tessfuncptr_t)();
39 #elif defined (WIN32)
40  typedef GLvoid (CALLBACK *tessfuncptr_t)();
41 #else
42  #error "Error - need to define type tessfuncptr_t for this platform/compiler"
43 #endif
44 }
45 
46 /** \class TGLFaceSet
47 \ingroup opengl
48 Implements a native ROOT-GL representation of an arbitrary set of polygons.
49 */
50 
52 
54 
55 ////////////////////////////////////////////////////////////////////////////////
56 /// constructor
57 
59  TGLLogicalShape(buffer),
60  fVertices(buffer.fPnts, buffer.fPnts + 3 * buffer.NbPnts()),
61  fNormals(0)
62 {
63  fNbPols = buffer.NbPols();
64 
65  if (fNbPols == 0) return;
66 
67  Int_t *segs = buffer.fSegs;
68  Int_t *pols = buffer.fPols;
69 
70  Int_t descSize = 0;
71 
72  for (UInt_t i = 0, j = 1; i < fNbPols; ++i, ++j)
73  {
74  descSize += pols[j] + 1;
75  j += pols[j] + 1;
76  }
77 
78  fPolyDesc.resize(descSize);
79 
80  for (UInt_t numPol = 0, currInd = 0, j = 1; numPol < fNbPols; ++numPol)
81  {
82  Int_t segmentInd = pols[j] + j;
83  Int_t segmentCol = pols[j];
84  Int_t s1 = pols[segmentInd];
85  segmentInd--;
86  Int_t s2 = pols[segmentInd];
87  segmentInd--;
88  Int_t segEnds[] = {segs[s1 * 3 + 1], segs[s1 * 3 + 2],
89  segs[s2 * 3 + 1], segs[s2 * 3 + 2]};
90  Int_t numPnts[3] = {0};
91 
92  if (segEnds[0] == segEnds[2]) {
93  numPnts[0] = segEnds[1], numPnts[1] = segEnds[0], numPnts[2] = segEnds[3];
94  } else if (segEnds[0] == segEnds[3]) {
95  numPnts[0] = segEnds[1], numPnts[1] = segEnds[0], numPnts[2] = segEnds[2];
96  } else if (segEnds[1] == segEnds[2]) {
97  numPnts[0] = segEnds[0], numPnts[1] = segEnds[1], numPnts[2] = segEnds[3];
98  } else {
99  numPnts[0] = segEnds[0], numPnts[1] = segEnds[1], numPnts[2] = segEnds[2];
100  }
101 
102  fPolyDesc[currInd] = 3;
103  Int_t sizeInd = currInd++;
104  fPolyDesc[currInd++] = numPnts[0];
105  fPolyDesc[currInd++] = numPnts[1];
106  fPolyDesc[currInd++] = numPnts[2];
107  Int_t lastAdded = numPnts[2];
108 
109  Int_t end = j + 1;
110  for (; segmentInd != end; segmentInd--) {
111  segEnds[0] = segs[pols[segmentInd] * 3 + 1];
112  segEnds[1] = segs[pols[segmentInd] * 3 + 2];
113  if (segEnds[0] == lastAdded) {
114  fPolyDesc[currInd++] = segEnds[1];
115  lastAdded = segEnds[1];
116  } else {
117  fPolyDesc[currInd++] = segEnds[0];
118  lastAdded = segEnds[0];
119  }
120  ++fPolyDesc[sizeInd];
121  }
122  j += segmentCol + 2;
123  }
124 
125  if (fgEnforceTriangles) {
127  }
129 }
130 
131 ////////////////////////////////////////////////////////////////////////////////
132 /// Should only be done on an empty faceset object
133 
134 void TGLFaceSet::SetFromMesh(const RootCsg::TBaseMesh *mesh)
135 {
136  assert(fNbPols == 0);
137 
138  UInt_t nv = mesh->NumberOfVertices();
139  fVertices.reserve(3 * nv);
140  UInt_t i;
141 
142  for (i = 0; i < nv; ++i) {
143  const Double_t *v = mesh->GetVertex(i);
144  fVertices.insert(fVertices.end(), v, v + 3);
145  }
146 
147  fNbPols = mesh->NumberOfPolys();
148 
149  UInt_t descSize = 0;
150 
151  for (i = 0; i < fNbPols; ++i) descSize += mesh->SizeOfPoly(i) + 1;
152 
153  fPolyDesc.reserve(descSize);
154 
155  for (UInt_t polyIndex = 0; polyIndex < fNbPols; ++polyIndex) {
156  UInt_t polySize = mesh->SizeOfPoly(polyIndex);
157 
158  fPolyDesc.push_back(polySize);
159 
160  for(i = 0; i < polySize; ++i) fPolyDesc.push_back(mesh->GetVertexIndex(polyIndex, i));
161  }
162 
163  if (fgEnforceTriangles) {
165  }
167 }
168 
169 ////////////////////////////////////////////////////////////////////////////////
170 /// Use GLU tesselator to replace all polygons with N > 3 with triangles.
171 /// After this call polygon descriptions are changed.
172 /// New vertices are not expected -- exception is thrown if this is
173 /// requested by the triangulator. Support for adding of new vertices can be
174 /// provided.
175 
177 {
178  class TriangleCollector
179  {
180  protected:
181  Int_t fNTriangles;
182  Int_t fNVertices;
183  Int_t fV0, fV1;
184  GLenum fType;
185  std::vector<Int_t> fPolyDesc;
186 
187  void add_triangle(Int_t v0, Int_t v1, Int_t v2)
188  {
189  fPolyDesc.push_back(3);
190  fPolyDesc.push_back(v0);
191  fPolyDesc.push_back(v1);
192  fPolyDesc.push_back(v2);
193  ++fNTriangles;
194  }
195 
196  void process_vertex(Int_t vi)
197  {
198  ++fNVertices;
199 
200  if (fV0 == -1) {
201  fV0 = vi;
202  return;
203  }
204  if (fV1 == -1) {
205  fV1 = vi;
206  return;
207  }
208 
209  switch (fType)
210  {
211  case GL_TRIANGLES:
212  {
213  add_triangle(fV0, fV1, vi);
214  fV0 = fV1 = -1;
215  break;
216  }
217  case GL_TRIANGLE_STRIP:
218  {
219  if (fNVertices % 2 == 0)
220  add_triangle(fV1, fV0, vi);
221  else
222  add_triangle(fV0, fV1, vi);
223  fV0 = fV1;
224  fV1 = vi;
225  break;
226  }
227  case GL_TRIANGLE_FAN:
228  {
229  add_triangle(fV0, fV1, vi);
230  fV1 = vi;
231  break;
232  }
233  default:
234  {
235  throw std::runtime_error("TGLFaceSet::EnforceTriangles unexpected type in tess_vertex callback.");
236  }
237  }
238  }
239 
240  public:
241  TriangleCollector(GLUtesselator* ts) :
242  fNTriangles(0), fNVertices(0), fV0(-1), fV1(-1), fType(GL_NONE)
243  {
244  gluTessCallback(ts, (GLenum)GLU_TESS_BEGIN_DATA, (tessfuncptr_t) tess_begin);
245  gluTessCallback(ts, (GLenum)GLU_TESS_VERTEX_DATA, (tessfuncptr_t) tess_vertex);
246  gluTessCallback(ts, (GLenum)GLU_TESS_COMBINE_DATA, (tessfuncptr_t) tess_combine);
247  gluTessCallback(ts, (GLenum)GLU_TESS_END_DATA, (tessfuncptr_t) tess_end);
248  }
249 
250  Int_t GetNTrianlges() { return fNTriangles; }
251  std::vector<Int_t>& RefPolyDesc() { return fPolyDesc; }
252 
253  static void tess_begin(GLenum type, TriangleCollector* tc)
254  {
255  tc->fNVertices = 0;
256  tc->fV0 = tc->fV1 = -1;
257  tc->fType = type;
258  }
259 
260  static void tess_vertex(Int_t* vi, TriangleCollector* tc)
261  {
262  tc->process_vertex(*vi);
263  }
264 
265  static void tess_combine(GLdouble /*coords*/[3], void* /*vertex_data*/[4],
266  GLfloat /*weight*/[4], void** /*outData*/,
267  TriangleCollector* /*tc*/)
268  {
269  throw std::runtime_error("TGLFaceSet::EnforceTriangles tesselator requested vertex combining -- not supported yet.");
270  }
271 
272  static void tess_end(TriangleCollector* tc)
273  {
274  tc->fType = GL_NONE;
275  }
276  };
277 
278  GLUtesselator *tess = gluNewTess();
279  if (!tess) throw std::bad_alloc();
280 
281  TriangleCollector tc(tess);
282 
283  // Loop ...
284  const Double_t *pnts = &fVertices[0];
285  const Int_t *pols = &fPolyDesc[0];
286 
287  for (UInt_t i = 0, j = 0; i < fNbPols; ++i)
288  {
289  Int_t npoints = pols[j++];
290 
291  gluTessBeginPolygon(tess, &tc);
292  gluTessBeginContour(tess);
293 
294  for (Int_t k = 0; k < npoints; ++k, ++j)
295  {
296  gluTessVertex(tess, (Double_t*) pnts + pols[j] * 3, (GLvoid*) &pols[j]);
297  }
298 
299  gluTessEndContour(tess);
300  gluTessEndPolygon(tess);
301  }
302 
303  gluDeleteTess(tess);
304 
305  fPolyDesc.swap(tc.RefPolyDesc());
306  fNbPols = tc.GetNTrianlges();
307 }
308 
309 ////////////////////////////////////////////////////////////////////////////////
310 /// Debug tracing
311 
312 void TGLFaceSet::DirectDraw(TGLRnrCtx & rnrCtx) const
313 {
314  if (gDebug > 4) {
315  Info("TGLFaceSet::DirectDraw", "this %ld (class %s) LOD %d", (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD());
316  }
317 
318  if (fNbPols == 0) return;
319 
320  GLUtesselator *tessObj = TGLUtil::GetDrawTesselator3dv();
321  const Double_t *pnts = &fVertices[0];
322  const Double_t *normals = &fNormals[0];
323  const Int_t *pols = &fPolyDesc[0];
324 
325  for (UInt_t i = 0, j = 0; i < fNbPols; ++i) {
326  Int_t npoints = pols[j++];
327 
328  if (tessObj && npoints > 4) {
329  gluBeginPolygon(tessObj);
330  gluNextContour(tessObj, (GLenum)GLU_UNKNOWN);
331  glNormal3dv(normals + i * 3);
332 
333  for (Int_t k = 0; k < npoints; ++k, ++j) {
334  gluTessVertex(tessObj, (Double_t *)pnts + pols[j] * 3, (Double_t *)pnts + pols[j] * 3);
335  }
336  gluEndPolygon(tessObj);
337  } else {
338  glBegin(GL_POLYGON);
339  glNormal3dv(normals + i * 3);
340 
341  for (Int_t k = 0; k < npoints; ++k, ++j) {
342  glVertex3dv(pnts + pols[j] * 3);
343  }
344  glEnd();
345  }
346  }
347 }
348 
349 ////////////////////////////////////////////////////////////////////////////////
350 /// CheckPoints
351 
353 {
354  const Double_t * p1 = &fVertices[source[0] * 3];
355  const Double_t * p2 = &fVertices[source[1] * 3];
356  const Double_t * p3 = &fVertices[source[2] * 3];
357  Int_t retVal = 1;
358 
359  if (Eq(p1, p2)) {
360  dest[0] = source[0];
361  if (!Eq(p1, p3) ) {
362  dest[1] = source[2];
363  retVal = 2;
364  }
365  } else if (Eq(p1, p3)) {
366  dest[0] = source[0];
367  dest[1] = source[1];
368  retVal = 2;
369  } else {
370  dest[0] = source[0];
371  dest[1] = source[1];
372  retVal = 2;
373  if (!Eq(p2, p3)) {
374  dest[2] = source[2];
375  retVal = 3;
376  }
377  }
378 
379  return retVal;
380 }
381 
382 ////////////////////////////////////////////////////////////////////////////////
383 /// test equality
384 
386 {
387  Double_t dx = TMath::Abs(p1[0] - p2[0]);
388  Double_t dy = TMath::Abs(p1[1] - p2[1]);
389  Double_t dz = TMath::Abs(p1[2] - p2[2]);
390  return dx < 1e-10 && dy < 1e-10 && dz < 1e-10;
391 }
392 
393 ////////////////////////////////////////////////////////////////////////////////
394 /// CalculateNormals
395 
397 {
398  fNormals.resize(3 *fNbPols);
399  if (fNbPols == 0) return;
400  Double_t *pnts = &fVertices[0];
401  for (UInt_t i = 0, j = 0; i < fNbPols; ++i) {
402  Int_t polEnd = fPolyDesc[j] + j + 1;
403  Int_t norm[] = {fPolyDesc[j + 1], fPolyDesc[j + 2], fPolyDesc[j + 3]};
404  j += 4;
405  Int_t check = CheckPoints(norm, norm), ngood = check;
406  if (check == 3) {
407  TMath::Normal2Plane(pnts + norm[0] * 3, pnts + norm[1] * 3,
408  pnts + norm[2] * 3, &fNormals[i * 3]);
409  j = polEnd;
410  continue;
411  }
412  while (j < (UInt_t)polEnd) {
413  norm[ngood++] = fPolyDesc[j++];
414  if (ngood == 3) {
415  ngood = CheckPoints(norm, norm);
416  if (ngood == 3) {
417  TMath::Normal2Plane(pnts + norm[0] * 3, pnts + norm[1] * 3,
418  pnts + norm[2] * 3, &fNormals[i * 3]);
419  j = polEnd;
420  break;
421  }
422  }
423  }
424  }
425 }
426 
427 ////////////////////////////////////////////////////////////////////////////////
428 /// Get current state of static flag EnforceTriangles.
429 
431 {
432  return fgEnforceTriangles;
433 }
434 
435 ////////////////////////////////////////////////////////////////////////////////
436 /// Set state of static flag EnforceTriangles.
437 /// When this is set, all tesselations will be automatically converted into
438 /// triangle-only meshes.
439 /// This is needed to export TGeo shapes and CSG meshes to external
440 /// triangle-mesh libraries that can not handle arbitrary polygons.
441 
443 {
445 }
std::string GetName(const std::string &scope_name)
Definition: Cppyy.cxx:145
The TGLRnrCtx class aggregates data for a given redering context as needed by various parts of the RO...
Definition: TGLRnrCtx.h:40
static double p3(double t, double a, double b, double c, double d)
void SetFromMesh(const RootCsg::TBaseMesh *m)
Should only be done on an empty faceset object.
Definition: TGLFaceSet.cxx:134
Implements a native ROOT-GL representation of an arbitrary set of polygons.
Definition: TGLFaceSet.h:21
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
Short_t Abs(Short_t d)
Definition: TMathBase.h:108
T * Normal2Plane(const T v1[3], const T v2[3], const T v3[3], T normal[3])
Definition: TMath.h:1181
Int_t CheckPoints(const Int_t *source, Int_t *dest) const
CheckPoints.
Definition: TGLFaceSet.cxx:352
static double p2(double t, double a, double b, double c)
void Info(const char *location, const char *msgfmt,...)
std::vector< Int_t > fPolyDesc
Definition: TGLFaceSet.h:26
static void SetEnforceTriangles(Bool_t e)
Set state of static flag EnforceTriangles.
Definition: TGLFaceSet.cxx:442
Short_t ShapeLOD() const
Definition: TGLRnrCtx.h:177
static Bool_t GetEnforceTriangles()
Get current state of static flag EnforceTriangles.
Definition: TGLFaceSet.cxx:430
Int_t * fPols
Definition: TBuffer3D.h:114
SVector< double, 2 > v
Definition: Dict.h:5
unsigned int UInt_t
Definition: RtypesCore.h:42
Generic 3D primitive description class.
Definition: TBuffer3D.h:17
static Bool_t Eq(const Double_t *p1, const Double_t *p2)
test equality
Definition: TGLFaceSet.cxx:385
#define CALLBACK
Definition: TGLFaceSet.cxx:30
static double p1(double t, double a, double b)
UInt_t NbPols() const
Definition: TBuffer3D.h:82
Abstract logical shape - a GL &#39;drawable&#39; - base for all shapes - faceset sphere etc.
const Bool_t kFALSE
Definition: RtypesCore.h:92
PyObject * fType
long Long_t
Definition: RtypesCore.h:50
std::vector< Double_t > fVertices
Definition: TGLFaceSet.h:24
#define ClassImp(name)
Definition: Rtypes.h:336
virtual void DirectDraw(TGLRnrCtx &rnrCtx) const
Debug tracing.
Definition: TGLFaceSet.cxx:312
double Double_t
Definition: RtypesCore.h:55
int type
Definition: TGX11.cxx:120
static Bool_t fgEnforceTriangles
Definition: TGLFaceSet.h:29
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
UInt_t fNbPols
Definition: TGLFaceSet.h:27
void EnforceTriangles()
Use GLU tesselator to replace all polygons with N > 3 with triangles.
Definition: TGLFaceSet.cxx:176
void CalculateNormals()
CalculateNormals.
Definition: TGLFaceSet.cxx:396
Int_t * fSegs
Definition: TBuffer3D.h:113
TGLFaceSet(const TBuffer3D &buffer)
constructor
Definition: TGLFaceSet.cxx:58
#define dest(otri, vertexptr)
Definition: triangle.c:1040
static GLUtesselator * GetDrawTesselator3dv()
Returns a tesselator for direct drawing when using 3-vertices with double precision.
Definition: TGLUtil.cxx:1521
R__EXTERN Int_t gDebug
Definition: Rtypes.h:83
double norm(double *x, double *p)
Definition: unuranDistr.cxx:40
std::vector< Double_t > fNormals
Definition: TGLFaceSet.h:25
segment * segs
Definition: X3DBuffer.c:21