Logo ROOT   6.16/01
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 }
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)((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);
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
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}
SVector< double, 2 > v
Definition: Dict.h:5
PyObject * fType
#define s1(x)
Definition: RSha256.hxx:91
#define e(i)
Definition: RSha256.hxx:103
static double p3(double t, double a, double b, double c, double d)
static double p1(double t, double a, double b)
static double p2(double t, double a, double b, double c)
int Int_t
Definition: RtypesCore.h:41
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
double Double_t
Definition: RtypesCore.h:55
#define ClassImp(name)
Definition: Rtypes.h:363
R__EXTERN Int_t gDebug
Definition: Rtypes.h:90
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:1551
std::string GetName(const std::string &scope_name)
Definition: Cppyy.cxx:146
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:1177
Short_t Abs(Short_t d)
Definition: TMathBase.h:120
#define dest(otri, vertexptr)
Definition: triangle.c:1040