Logo ROOT  
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
33extern "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
48Implements 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
134void 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 }
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)((void*)tess_begin));
245 gluTessCallback(ts, (GLenum)GLU_TESS_VERTEX_DATA, (tessfuncptr_t)((void*)tess_vertex));
246 gluTessCallback(ts, (GLenum)GLU_TESS_COMBINE_DATA, (tessfuncptr_t)((void*)tess_combine));
247 gluTessCallback(ts, (GLenum)GLU_TESS_END_DATA, (tessfuncptr_t)((void*)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);
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
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
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);
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}
#define GL_NONE
Definition: GL_glu.h:263
void GLvoid
Definition: GL_glu.h:269
#define GLU_TESS_BEGIN_DATA
Definition: GL_glu.h:217
#define GLU_TESS_COMBINE_DATA
Definition: GL_glu.h:222
GLAPI void GLAPIENTRY gluBeginPolygon(GLUtesselator *tess)
Definition: tess.c:621
float GLfloat
Definition: GL_glu.h:277
GLAPI GLUtesselator *GLAPIENTRY gluNewTess(void)
Definition: tess.c:102
#define GL_TRIANGLE_FAN
Definition: GL_glu.h:289
GLAPI void GLAPIENTRY gluTessEndPolygon(GLUtesselator *tess)
Definition: tess.c:510
#define GLU_TESS_END_DATA
Definition: GL_glu.h:219
double GLdouble
Definition: GL_glu.h:279
#define GLU_UNKNOWN
Definition: GL_glu.h:229
#define GL_TRIANGLES
Definition: GL_glu.h:287
GLAPI void GLAPIENTRY gluTessBeginContour(GLUtesselator *tess)
Definition: tess.c:486
GLAPI void GLAPIENTRY gluNextContour(GLUtesselator *tess, GLenum type)
Definition: tess.c:630
GLAPI void GLAPIENTRY gluTessBeginPolygon(GLUtesselator *tess, GLvoid *data)
Definition: tess.c:472
GLAPI void GLAPIENTRY gluEndPolygon(GLUtesselator *tess)
Definition: tess.c:639
#define GLU_TESS_VERTEX_DATA
Definition: GL_glu.h:218
GLAPI void GLAPIENTRY gluTessCallback(GLUtesselator *tess, GLenum which, _GLUfuncptr CallBackFunc)
Definition: tess.c:286
#define GL_POLYGON
Definition: GL_glu.h:292
#define GL_TRIANGLE_STRIP
Definition: GL_glu.h:288
GLAPI void GLAPIENTRY gluDeleteTess(GLUtesselator *tess)
Definition: tess.c:203
GLAPI void GLAPIENTRY gluTessVertex(GLUtesselator *tess, GLdouble *location, GLvoid *data)
GLAPI void GLAPIENTRY gluTessEndContour(GLUtesselator *tess)
Definition: tess.c:503
#define s1(x)
Definition: RSha256.hxx:91
#define e(i)
Definition: RSha256.hxx:103
const Bool_t kFALSE
Definition: RtypesCore.h:90
long Long_t
Definition: RtypesCore.h:52
bool Bool_t
Definition: RtypesCore.h:61
double Double_t
Definition: RtypesCore.h:57
R__EXTERN Int_t gDebug
Definition: RtypesCore.h:117
#define ClassImp(name)
Definition: Rtypes.h:361
void Info(const char *location, const char *msgfmt,...)
#define CALLBACK
Definition: TGLFaceSet.cxx:30
int type
Definition: TGX11.cxx:120
segment * segs
Definition: X3DBuffer.c:23
Generic 3D primitive description class.
Definition: TBuffer3D.h:18
Int_t * fPols
Definition: TBuffer3D.h:114
UInt_t NbPols() const
Definition: TBuffer3D.h:82
Int_t * fSegs
Definition: TBuffer3D.h:113
Implements a native ROOT-GL representation of an arbitrary set of polygons.
Definition: TGLFaceSet.h:22
void EnforceTriangles()
Use GLU tesselator to replace all polygons with N > 3 with triangles.
Definition: TGLFaceSet.cxx:176
UInt_t fNbPols
Definition: TGLFaceSet.h:27
static void SetEnforceTriangles(Bool_t e)
Set state of static flag EnforceTriangles.
Definition: TGLFaceSet.cxx:442
std::vector< Int_t > fPolyDesc
Definition: TGLFaceSet.h:26
std::vector< Double_t > fNormals
Definition: TGLFaceSet.h:25
Int_t CheckPoints(const Int_t *source, Int_t *dest) const
CheckPoints.
Definition: TGLFaceSet.cxx:352
void SetFromMesh(const RootCsg::TBaseMesh *m)
Should only be done on an empty faceset object.
Definition: TGLFaceSet.cxx:134
virtual void DirectDraw(TGLRnrCtx &rnrCtx) const
Debug tracing.
Definition: TGLFaceSet.cxx:312
TGLFaceSet(const TBuffer3D &buffer)
constructor
Definition: TGLFaceSet.cxx:58
void CalculateNormals()
CalculateNormals.
Definition: TGLFaceSet.cxx:396
std::vector< Double_t > fVertices
Definition: TGLFaceSet.h:24
static Bool_t Eq(const Double_t *p1, const Double_t *p2)
test equality
Definition: TGLFaceSet.cxx:385
static Bool_t fgEnforceTriangles
Definition: TGLFaceSet.h:29
static Bool_t GetEnforceTriangles()
Get current state of static flag EnforceTriangles.
Definition: TGLFaceSet.cxx:430
Abstract logical shape - a GL 'drawable' - base for all shapes - faceset sphere etc.
The TGLRnrCtx class aggregates data for a given redering context as needed by various parts of the RO...
Definition: TGLRnrCtx.h:41
Short_t ShapeLOD() const
Definition: TGLRnrCtx.h:177
static GLUtesselator * GetDrawTesselator3dv()
Returns a tesselator for direct drawing when using 3-vertices with double precision.
Definition: TGLUtil.cxx:1535
T * Normal2Plane(const T v1[3], const T v2[3], const T v3[3], T normal[3])
Calculate a normal vector of a plane.
Definition: TMath.h:1179
Short_t Abs(Short_t d)
Definition: TMathBase.h:120
#define dest(otri, vertexptr)
Definition: triangle.c:1040