TGLFaceSet.cxx

Go to the documentation of this file.
00001 // @(#)root/gl:$Id: TGLFaceSet.cxx 37192 2010-12-02 15:54:26Z matevz $
00002 // Author:  Timur Pocheptsov  03/08/2004
00003 // NOTE: This code moved from obsoleted TGLSceneObject.h / .cxx - see these
00004 // attic files for previous CVS history
00005 
00006 /*************************************************************************
00007  * Copyright (C) 1995-2006, Rene Brun and Fons Rademakers.               *
00008  * All rights reserved.                                                  *
00009  *                                                                       *
00010  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00011  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00012  *************************************************************************/
00013 
00014 #include "TGLFaceSet.h"
00015 #include "TGLRnrCtx.h"
00016 #include "TGLIncludes.h"
00017 
00018 #include "TBuffer3D.h"
00019 #include "TMath.h"
00020 
00021 // For debug tracing
00022 #include "TClass.h"
00023 #include "TError.h"
00024 
00025 #include <stdexcept>
00026 
00027 // Clone from TGLUtil -- typedefs needed for portable tesselator function typedef.
00028 
00029 #ifndef CALLBACK
00030 #define CALLBACK
00031 #endif
00032 
00033 extern "C"
00034 {
00035 #if defined(__APPLE_CC__) && __APPLE_CC__ > 4000 && __APPLE_CC__ < 5450 && !defined(__INTEL_COMPILER)
00036     typedef GLvoid (*tessfuncptr_t)(...);
00037 #elif defined(__mips) || defined(__linux__) || defined(__FreeBSD__) || defined( __OpenBSD__ ) || defined(__sun) || defined (__CYGWIN__) || defined (__APPLE__)
00038     typedef GLvoid (*tessfuncptr_t)();
00039 #elif defined (WIN32)
00040     typedef GLvoid (CALLBACK *tessfuncptr_t)();
00041 #else
00042     #error "Error - need to define type tessfuncptr_t for this platform/compiler"
00043 #endif
00044 }
00045 
00046 //______________________________________________________________________________
00047 //
00048 // Implementss a native ROOT-GL representation of an arbitrary set of
00049 // polygons.
00050 
00051 ClassImp(TGLFaceSet);
00052 
00053 Bool_t TGLFaceSet::fgEnforceTriangles = kFALSE;
00054 
00055 //______________________________________________________________________________
00056 TGLFaceSet::TGLFaceSet(const TBuffer3D & buffer) :
00057    TGLLogicalShape(buffer),
00058    fVertices(buffer.fPnts, buffer.fPnts + 3 * buffer.NbPnts()),
00059    fNormals(0)
00060 {
00061    // constructor
00062    fNbPols = buffer.NbPols();
00063 
00064    if (fNbPols == 0) return;
00065 
00066    Int_t *segs = buffer.fSegs;
00067    Int_t *pols = buffer.fPols;
00068 
00069    Int_t descSize = 0;
00070 
00071    for (UInt_t i = 0, j = 1; i < fNbPols; ++i, ++j)
00072    {
00073       descSize += pols[j] + 1;
00074       j += pols[j] + 1;
00075    }
00076 
00077    fPolyDesc.resize(descSize);
00078 
00079    for (UInt_t numPol = 0, currInd = 0, j = 1; numPol < fNbPols; ++numPol)
00080    {
00081       Int_t segmentInd = pols[j] + j;
00082       Int_t segmentCol = pols[j];
00083       Int_t s1 = pols[segmentInd];
00084       segmentInd--;
00085       Int_t s2 = pols[segmentInd];
00086       segmentInd--;
00087       Int_t segEnds[] = {segs[s1 * 3 + 1], segs[s1 * 3 + 2],
00088                          segs[s2 * 3 + 1], segs[s2 * 3 + 2]};
00089       Int_t numPnts[3] = {0};
00090 
00091       if (segEnds[0] == segEnds[2]) {
00092          numPnts[0] = segEnds[1], numPnts[1] = segEnds[0], numPnts[2] = segEnds[3];
00093       } else if (segEnds[0] == segEnds[3]) {
00094          numPnts[0] = segEnds[1], numPnts[1] = segEnds[0], numPnts[2] = segEnds[2];
00095       } else if (segEnds[1] == segEnds[2]) {
00096          numPnts[0] = segEnds[0], numPnts[1] = segEnds[1], numPnts[2] = segEnds[3];
00097       } else {
00098          numPnts[0] = segEnds[0], numPnts[1] = segEnds[1], numPnts[2] = segEnds[2];
00099       }
00100 
00101       fPolyDesc[currInd] = 3;
00102       Int_t sizeInd = currInd++;
00103       fPolyDesc[currInd++] = numPnts[0];
00104       fPolyDesc[currInd++] = numPnts[1];
00105       fPolyDesc[currInd++] = numPnts[2];
00106       Int_t lastAdded = numPnts[2];
00107 
00108       Int_t end = j + 1;
00109       for (; segmentInd != end; segmentInd--) {
00110          segEnds[0] = segs[pols[segmentInd] * 3 + 1];
00111          segEnds[1] = segs[pols[segmentInd] * 3 + 2];
00112          if (segEnds[0] == lastAdded) {
00113             fPolyDesc[currInd++] = segEnds[1];
00114             lastAdded = segEnds[1];
00115          } else {
00116             fPolyDesc[currInd++] = segEnds[0];
00117             lastAdded = segEnds[0];
00118          }
00119          ++fPolyDesc[sizeInd];
00120       }
00121       j += segmentCol + 2;
00122    }
00123 
00124    if (fgEnforceTriangles) {
00125       EnforceTriangles();
00126    }
00127    CalculateNormals();
00128 }
00129 
00130 //______________________________________________________________________________
00131 void TGLFaceSet::SetFromMesh(const RootCsg::TBaseMesh *mesh)
00132 {
00133    // Should only be done on an empty faceset object
00134    assert(fNbPols == 0);
00135 
00136    UInt_t nv = mesh->NumberOfVertices();
00137    fVertices.reserve(3 * nv);
00138    UInt_t i;
00139 
00140    for (i = 0; i < nv; ++i) {
00141       const Double_t *v = mesh->GetVertex(i);
00142       fVertices.insert(fVertices.end(), v, v + 3);
00143    }
00144 
00145    fNbPols = mesh->NumberOfPolys();
00146 
00147    UInt_t descSize = 0;
00148 
00149    for (i = 0; i < fNbPols; ++i) descSize += mesh->SizeOfPoly(i) + 1;
00150 
00151    fPolyDesc.reserve(descSize);
00152 
00153    for (UInt_t polyIndex = 0; polyIndex < fNbPols; ++polyIndex) {
00154       UInt_t polySize = mesh->SizeOfPoly(polyIndex);
00155 
00156       fPolyDesc.push_back(polySize);
00157 
00158       for(i = 0; i < polySize; ++i) fPolyDesc.push_back(mesh->GetVertexIndex(polyIndex, i));
00159    }
00160 
00161    if (fgEnforceTriangles) {
00162       EnforceTriangles();
00163    }
00164    CalculateNormals();
00165 }
00166 
00167 //______________________________________________________________________________
00168 void TGLFaceSet::EnforceTriangles()
00169 {
00170    // Use GLU tesselator to replace all polygons with N > 3 with triangles.
00171    // After this call polygon descriptions are changed.
00172    // New vertices are not expected -- exception is thrown if this is
00173    // requested by the triangulator. Support for adding of new vertices can be
00174    // provided.
00175 
00176    class TriangleCollector
00177    {
00178    protected:
00179       Int_t              fNTriangles;
00180       Int_t              fNVertices;
00181       Int_t              fV0, fV1;
00182       GLenum             fType;
00183       std::vector<Int_t> fPolyDesc;
00184 
00185       void add_triangle(Int_t v0, Int_t v1, Int_t v2)
00186       {
00187          fPolyDesc.push_back(3);
00188          fPolyDesc.push_back(v0);
00189          fPolyDesc.push_back(v1);
00190          fPolyDesc.push_back(v2);
00191          ++fNTriangles;
00192       }
00193 
00194       void process_vertex(Int_t vi)
00195       {
00196          ++fNVertices;
00197 
00198          if (fV0 == -1) {
00199             fV0 = vi;
00200             return;
00201          }
00202          if (fV1 == -1) {
00203             fV1 = vi;
00204             return;
00205          }
00206 
00207          switch (fType)
00208          {
00209             case GL_TRIANGLES:
00210             {
00211                add_triangle(fV0, fV1, vi);
00212                fV0 = fV1 = -1;
00213                break;
00214             }
00215             case GL_TRIANGLE_STRIP:
00216             {
00217                if (fNVertices % 2 == 0)
00218                   add_triangle(fV1, fV0, vi);
00219                else
00220                   add_triangle(fV0, fV1, vi);
00221                fV0 = fV1;
00222                fV1 = vi;
00223                break;
00224             }
00225             case GL_TRIANGLE_FAN:
00226             {
00227                add_triangle(fV0, fV1, vi);
00228                fV1 = vi;
00229                break;
00230             }
00231             default:
00232             {
00233                throw std::runtime_error("TGLFaceSet::EnforceTriangles unexpected type in tess_vertex callback.");
00234             }
00235          }
00236       }
00237 
00238    public:
00239       TriangleCollector(GLUtesselator* ts) :
00240          fNTriangles(0), fNVertices(0), fV0(-1), fV1(-1), fType(GL_NONE)
00241       {
00242          gluTessCallback(ts, (GLenum)GLU_TESS_BEGIN_DATA,   (tessfuncptr_t) tess_begin);
00243          gluTessCallback(ts, (GLenum)GLU_TESS_VERTEX_DATA,  (tessfuncptr_t) tess_vertex);
00244          gluTessCallback(ts, (GLenum)GLU_TESS_COMBINE_DATA, (tessfuncptr_t) tess_combine);
00245          gluTessCallback(ts, (GLenum)GLU_TESS_END_DATA,     (tessfuncptr_t) tess_end);
00246       }
00247 
00248       Int_t               GetNTrianlges() { return fNTriangles; }
00249       std::vector<Int_t>& RefPolyDesc()   { return fPolyDesc; }
00250 
00251       static void tess_begin(GLenum type, TriangleCollector* tc)
00252       {
00253          tc->fNVertices = 0;
00254          tc->fV0 = tc->fV1 = -1;
00255          tc->fType = type;
00256       }
00257 
00258       static void tess_vertex(Int_t* vi, TriangleCollector* tc)
00259       {
00260          tc->process_vertex(*vi);
00261       }
00262 
00263       static void tess_combine(GLdouble /*coords*/[3], void* /*vertex_data*/[4], 
00264                                GLfloat  /*weight*/[4], void** /*outData*/, 
00265                                TriangleCollector* /*tc*/)
00266       {
00267          throw std::runtime_error("TGLFaceSet::EnforceTriangles tesselator requested vertex combining -- not supported yet.");
00268       }
00269 
00270       static void tess_end(TriangleCollector* tc)
00271       {
00272          tc->fType = GL_NONE;
00273       }
00274    };
00275 
00276    GLUtesselator *tess = gluNewTess();
00277    if (!tess) throw std::bad_alloc();
00278 
00279    TriangleCollector tc(tess);
00280 
00281    // Loop ...
00282    const Double_t *pnts = &fVertices[0];
00283    const Int_t    *pols = &fPolyDesc[0];
00284 
00285    for (UInt_t i = 0, j = 0; i < fNbPols; ++i)
00286    {
00287       Int_t npoints = pols[j++];
00288 
00289       gluTessBeginPolygon(tess, &tc);
00290       gluTessBeginContour(tess);
00291 
00292       for (Int_t k = 0; k < npoints; ++k, ++j)
00293       {
00294          gluTessVertex(tess, (Double_t*) pnts + pols[j] * 3, (GLvoid*) &pols[j]);
00295       }
00296 
00297       gluTessEndContour(tess);
00298       gluTessEndPolygon(tess);
00299    }
00300 
00301    gluDeleteTess(tess);
00302 
00303    fPolyDesc.swap(tc.RefPolyDesc());
00304    fNbPols = tc.GetNTrianlges();
00305 }
00306 
00307 //______________________________________________________________________________
00308 void TGLFaceSet::DirectDraw(TGLRnrCtx & rnrCtx) const
00309 {
00310    // Debug tracing
00311    if (gDebug > 4) {
00312       Info("TGLFaceSet::DirectDraw", "this %ld (class %s) LOD %d", (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD());
00313    }
00314 
00315    if (fNbPols == 0) return;
00316 
00317    GLUtesselator  *tessObj = TGLUtil::GetDrawTesselator3dv();
00318    const Double_t *pnts = &fVertices[0];
00319    const Double_t *normals = &fNormals[0];
00320    const Int_t *pols = &fPolyDesc[0];
00321 
00322    for (UInt_t i = 0, j = 0; i < fNbPols; ++i) {
00323       Int_t npoints = pols[j++];
00324 
00325       if (tessObj && npoints > 4) {
00326          gluBeginPolygon(tessObj);
00327          gluNextContour(tessObj, (GLenum)GLU_UNKNOWN);
00328          glNormal3dv(normals + i * 3);
00329 
00330          for (Int_t k = 0; k < npoints; ++k, ++j) {
00331             gluTessVertex(tessObj, (Double_t *)pnts + pols[j] * 3, (Double_t *)pnts + pols[j] * 3);
00332          }
00333          gluEndPolygon(tessObj);
00334       } else {
00335          glBegin(GL_POLYGON);
00336          glNormal3dv(normals + i * 3);
00337 
00338          for (Int_t k = 0; k < npoints; ++k, ++j) {
00339             glVertex3dv(pnts + pols[j] * 3);
00340          }
00341          glEnd();
00342       }
00343    }
00344 }
00345 
00346 //______________________________________________________________________________
00347 Int_t TGLFaceSet::CheckPoints(const Int_t *source, Int_t *dest) const
00348 {
00349    // CheckPoints
00350    const Double_t * p1 = &fVertices[source[0] * 3];
00351    const Double_t * p2 = &fVertices[source[1] * 3];
00352    const Double_t * p3 = &fVertices[source[2] * 3];
00353    Int_t retVal = 1;
00354 
00355    if (Eq(p1, p2)) {
00356       dest[0] = source[0];
00357       if (!Eq(p1, p3) ) {
00358          dest[1] = source[2];
00359          retVal = 2;
00360       }
00361    } else if (Eq(p1, p3)) {
00362       dest[0] = source[0];
00363       dest[1] = source[1];
00364       retVal = 2;
00365    } else {
00366       dest[0] = source[0];
00367       dest[1] = source[1];
00368       retVal = 2;
00369       if (!Eq(p2, p3)) {
00370          dest[2] = source[2];
00371          retVal = 3;
00372       }
00373    }
00374 
00375    return retVal;
00376 }
00377 
00378 //______________________________________________________________________________
00379 Bool_t TGLFaceSet::Eq(const Double_t *p1, const Double_t *p2)
00380 {
00381    // test equality
00382    Double_t dx = TMath::Abs(p1[0] - p2[0]);
00383    Double_t dy = TMath::Abs(p1[1] - p2[1]);
00384    Double_t dz = TMath::Abs(p1[2] - p2[2]);
00385    return dx < 1e-10 && dy < 1e-10 && dz < 1e-10;
00386 }
00387 
00388 //______________________________________________________________________________
00389 void TGLFaceSet::CalculateNormals()
00390 {
00391    // CalculateNormals
00392 
00393    fNormals.resize(3 *fNbPols);
00394    if (fNbPols == 0) return;
00395    Double_t *pnts = &fVertices[0];
00396    for (UInt_t i = 0, j = 0; i < fNbPols; ++i) {
00397       Int_t polEnd = fPolyDesc[j] + j + 1;
00398       Int_t norm[] = {fPolyDesc[j + 1], fPolyDesc[j + 2], fPolyDesc[j + 3]};
00399       j += 4;
00400       Int_t check = CheckPoints(norm, norm), ngood = check;
00401       if (check == 3) {
00402          TMath::Normal2Plane(pnts + norm[0] * 3, pnts + norm[1] * 3,
00403                              pnts + norm[2] * 3, &fNormals[i * 3]);
00404          j = polEnd;
00405          continue;
00406       }
00407       while (j < (UInt_t)polEnd) {
00408          norm[ngood++] = fPolyDesc[j++];
00409          if (ngood == 3) {
00410             ngood = CheckPoints(norm, norm);
00411             if (ngood == 3) {
00412                TMath::Normal2Plane(pnts + norm[0] * 3, pnts + norm[1] * 3,
00413                                    pnts + norm[2] * 3, &fNormals[i * 3]);
00414                j = polEnd;
00415                break;
00416             }
00417          }
00418       }
00419    }
00420 }
00421 
00422 //______________________________________________________________________________
00423 Bool_t TGLFaceSet::GetEnforceTriangles()
00424 {
00425    // Get current state of static flag EnforceTriangles.
00426 
00427    return fgEnforceTriangles;
00428 }
00429 
00430 //______________________________________________________________________________
00431 void TGLFaceSet::SetEnforceTriangles(Bool_t e)
00432 {
00433    // Set state of static flag EnforceTriangles.
00434    // When this is set, all tesselations will be automatically converted into
00435    // triangle-only meshes.
00436    // This is needed to export TGeo shapes and CSG meshes to external
00437    // triangle-mesh libraries that can not handle arbitrary polygons.
00438 
00439    fgEnforceTriangles = e;
00440 }

Generated on Tue Jul 5 14:18:06 2011 for ROOT_528-00b_version by  doxygen 1.5.1