00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00022 #include "TClass.h"
00023 #include "TError.h"
00024
00025 #include <stdexcept>
00026
00027
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
00049
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
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
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
00171
00172
00173
00174
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 [3], void* [4],
00264 GLfloat [4], void** ,
00265 TriangleCollector* )
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
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
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
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
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
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
00426
00427 return fgEnforceTriangles;
00428 }
00429
00430
00431 void TGLFaceSet::SetEnforceTriangles(Bool_t e)
00432 {
00433
00434
00435
00436
00437
00438
00439 fgEnforceTriangles = e;
00440 }