/**************************************************************************\ * * This file is part of the Coin 3D visualization library. * Copyright (C) 1998-2007 by Systems in Motion. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * ("GPL") version 2 as published by the Free Software Foundation. * See the file LICENSE.GPL at the root directory of this source * distribution for additional information about the GNU GPL. * * For using Coin with software that can not be combined with the GNU * GPL, and for taking advantage of the additional benefits of our * support services, please contact Systems in Motion about acquiring * a Coin Professional Edition License. * * See http://www.coin3d.org/ for more information. * * Systems in Motion, Postboks 1283, Pirsenteret, 7462 Trondheim, NORWAY. * http://www.sim.no/ sales@sim.no coin-support@coin3d.org * \**************************************************************************/ /*! \class SoTriangleStripSet SoTriangleStripSet.h Inventor/nodes/SoTriangleStripSet.h \brief The SoTriangleStripSet class is used to render and control non-indexed triangle strips. \ingroup nodes Triangle strips are specified using the numVertices field. Coordinates, normals, materials and texture coordinates are all fetched in order from the current state or from the vertexProperty node if set. (To render triangle strips from vertex indices, use the SoIndexedTriangleStripSet node.) The numVertices field may be used for multiple strips, coordinates will be fetched with a monotonically increasing index from the coordinates on the traversal state stack (i.e. typically from the last SoCoordinate3 node encountered during traversal). For example, if numVertices is set to [3, 4, 5, 3], this node would specify a triangle from coordinates 0, 1 and 2, a triangle strip from coordinates 3, 4, 5 and 6, a triangle strip from coordinates 7, 8, 9, 10 and 11 and finally a triangle from coordinates 12, 13, 14. Or to put it another way: in a tristrip there will always be two vertices more than there are triangles. Realize that you are handling data on the vertex level (not polygon-level), and that the triangles are laid out like this, given 5 vertices: \verbatim 1-----3-----5 \ / \ / \ / \ / 2-----4 \endverbatim The above figure in scene graph file format: \verbatim #Inventor V2.1 ascii Separator { Coordinate3 { point [ -2 1 0, -1 -1 0, 0 1 0, 1 -1 0, 2 1 0 ] } TriangleStripSet { numVertices [ 5 ] } } \endverbatim The scene graph above in a viewer:
Strips are converted into triangles the way OpenGL does it, of course, so for the dirty details, check out the documentation of OpenGL's \c GL_TRIANGLE_STRIP primitive rendering type. Binding PER_PART (per strip), PER_VERTEX, PER_FACE or OVERALL can be set for material, and normals. The default material binding is OVERALL. The default normal binding is PER_VERTEX. FILE FORMAT/DEFAULTS: \code TriangleStripSet { vertexProperty NULL startIndex 0 numVertices -1 } \endcode \sa SoIndexedTriangleStripSet */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*! \var SoMFInt32 SoTriangleStripSet::numVertices Specifies the number of vertices in each triangle strip. The vertices are fetched from the current coordinate node, or from the vertexProperty field if present. */ SO_NODE_SOURCE(SoTriangleStripSet); /*! Constructor. */ SoTriangleStripSet::SoTriangleStripSet() { SO_NODE_INTERNAL_CONSTRUCTOR(SoTriangleStripSet); SO_NODE_ADD_FIELD(numVertices, (-1)); } /*! Destructor. */ SoTriangleStripSet::~SoTriangleStripSet() { } // doc from parent void SoTriangleStripSet::computeBBox(SoAction * action, SbBox3f & box, SbVec3f & center) { int32_t numvertices = 0; for (int i=0; i < this->numVertices.getNum(); i++) numvertices += this->numVertices[i]; inherited::computeCoordBBox(action, numvertices, box, center); } /*! \COININTERNAL */ SoTriangleStripSet::Binding SoTriangleStripSet::findMaterialBinding(SoState * const state) const { SoMaterialBindingElement::Binding matbind = SoMaterialBindingElement::get(state); Binding binding; switch (matbind) { case SoMaterialBindingElement::OVERALL: binding = OVERALL; break; case SoMaterialBindingElement::PER_VERTEX: case SoMaterialBindingElement::PER_VERTEX_INDEXED: binding = PER_VERTEX; break; case SoMaterialBindingElement::PER_PART: case SoMaterialBindingElement::PER_PART_INDEXED: binding = PER_STRIP; break; case SoMaterialBindingElement::PER_FACE: case SoMaterialBindingElement::PER_FACE_INDEXED: binding = PER_FACE; break; default: binding = OVERALL; #if COIN_DEBUG SoDebugError::postWarning("SoTriangleStripSet::findMaterialBinding", "unknown material binding setting"); #endif // COIN_DEBUG break; } return binding; } /*! \COININTERNAL */ SoTriangleStripSet::Binding SoTriangleStripSet::findNormalBinding(SoState * const state) const { SoNormalBindingElement::Binding normbind = SoNormalBindingElement::get(state); Binding binding; switch (normbind) { case SoMaterialBindingElement::OVERALL: binding = OVERALL; break; case SoMaterialBindingElement::PER_VERTEX: case SoMaterialBindingElement::PER_VERTEX_INDEXED: binding = PER_VERTEX; break; case SoMaterialBindingElement::PER_PART: case SoMaterialBindingElement::PER_PART_INDEXED: binding = PER_STRIP; break; case SoMaterialBindingElement::PER_FACE: case SoMaterialBindingElement::PER_FACE_INDEXED: binding = PER_FACE; break; default: binding = PER_VERTEX; #if COIN_DEBUG SoDebugError::postWarning("SoTriangleStripSet::findNormalBinding", "unknown normal binding setting"); #endif // COIN_DEBUG break; } return binding; } typedef void sogl_render_ni_tristripset_func( const SoGLCoordinateElement * coords, const SbVec3f *normals, SoMaterialBundle * mb, const SoTextureCoordinateBundle * tb, int nbind, int mbind, int doTextures, int32_t idx, const int32_t *ptr, const int32_t *end, SbBool needNormals); static sogl_render_ni_tristripset_func *sotristripset_ni_render_funcs[ 32 ]; #define OVERALL 0 #define PER_STRIP 1 #define PER_FACE 2 #define PER_VERTEX 3 #define MBINDING OVERALL #define NBINDING OVERALL #define TEXTURES FALSE static void sogl_nits_m0_n0_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_STRIP #define NBINDING OVERALL #define TEXTURES FALSE static void sogl_nits_m1_n0_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_FACE #define NBINDING OVERALL #define TEXTURES FALSE static void sogl_nits_m2_n0_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_VERTEX #define NBINDING OVERALL #define TEXTURES FALSE static void sogl_nits_m3_n0_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING OVERALL #define NBINDING PER_STRIP #define TEXTURES FALSE static void sogl_nits_m0_n1_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_STRIP #define NBINDING PER_STRIP #define TEXTURES FALSE static void sogl_nits_m1_n1_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_FACE #define NBINDING PER_STRIP #define TEXTURES FALSE static void sogl_nits_m2_n1_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_VERTEX #define NBINDING PER_STRIP #define TEXTURES FALSE static void sogl_nits_m3_n1_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING OVERALL #define NBINDING PER_FACE #define TEXTURES FALSE static void sogl_nits_m0_n2_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_STRIP #define NBINDING PER_FACE #define TEXTURES FALSE static void sogl_nits_m1_n2_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_FACE #define NBINDING PER_FACE #define TEXTURES FALSE static void sogl_nits_m2_n2_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_VERTEX #define NBINDING PER_FACE #define TEXTURES FALSE static void sogl_nits_m3_n2_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING OVERALL #define NBINDING PER_VERTEX #define TEXTURES FALSE static void sogl_nits_m0_n3_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_STRIP #define NBINDING PER_VERTEX #define TEXTURES FALSE static void sogl_nits_m1_n3_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_FACE #define NBINDING PER_VERTEX #define TEXTURES FALSE static void sogl_nits_m2_n3_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_VERTEX #define NBINDING PER_VERTEX #define TEXTURES FALSE static void sogl_nits_m3_n3_t0 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING OVERALL #define NBINDING OVERALL #define TEXTURES TRUE static void sogl_nits_m0_n0_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_STRIP #define NBINDING OVERALL #define TEXTURES TRUE static void sogl_nits_m1_n0_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_FACE #define NBINDING OVERALL #define TEXTURES TRUE static void sogl_nits_m2_n0_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_VERTEX #define NBINDING OVERALL #define TEXTURES TRUE static void sogl_nits_m3_n0_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING OVERALL #define NBINDING PER_STRIP #define TEXTURES TRUE static void sogl_nits_m0_n1_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_STRIP #define NBINDING PER_STRIP #define TEXTURES TRUE static void sogl_nits_m1_n1_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_FACE #define NBINDING PER_STRIP #define TEXTURES TRUE static void sogl_nits_m2_n1_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_VERTEX #define NBINDING PER_STRIP #define TEXTURES TRUE static void sogl_nits_m3_n1_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING OVERALL #define NBINDING PER_FACE #define TEXTURES TRUE static void sogl_nits_m0_n2_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_STRIP #define NBINDING PER_FACE #define TEXTURES TRUE static void sogl_nits_m1_n2_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_FACE #define NBINDING PER_FACE #define TEXTURES TRUE static void sogl_nits_m2_n2_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_VERTEX #define NBINDING PER_FACE #define TEXTURES TRUE static void sogl_nits_m3_n2_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING OVERALL #define NBINDING PER_VERTEX #define TEXTURES TRUE static void sogl_nits_m0_n3_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_STRIP #define NBINDING PER_VERTEX #define TEXTURES TRUE static void sogl_nits_m1_n3_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_FACE #define NBINDING PER_VERTEX #define TEXTURES TRUE static void sogl_nits_m2_n3_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #define MBINDING PER_VERTEX #define NBINDING PER_VERTEX #define TEXTURES TRUE static void sogl_nits_m3_n3_t1 #include "../misc/SoGLnonindexedTristripSetTemplate.icc" #undef MBINDING #undef NBINDING #undef TEXTURES #undef OVERALL #undef PER_STRIP #undef PER_FACE #undef PER_VERTEX // doc from parent void SoTriangleStripSet::initClass(void) { SO_NODE_INTERNAL_INIT_CLASS(SoTriangleStripSet, SO_FROM_INVENTOR_1); sotristripset_ni_render_funcs[ 0] = sogl_nits_m0_n0_t0; sotristripset_ni_render_funcs[ 1] = sogl_nits_m0_n0_t1; sotristripset_ni_render_funcs[ 2] = sogl_nits_m0_n1_t0; sotristripset_ni_render_funcs[ 3] = sogl_nits_m0_n1_t1; sotristripset_ni_render_funcs[ 4] = sogl_nits_m0_n2_t0; sotristripset_ni_render_funcs[ 5] = sogl_nits_m0_n2_t1; sotristripset_ni_render_funcs[ 6] = sogl_nits_m0_n3_t0; sotristripset_ni_render_funcs[ 7] = sogl_nits_m0_n3_t1; sotristripset_ni_render_funcs[ 8] = sogl_nits_m1_n0_t0; sotristripset_ni_render_funcs[ 9] = sogl_nits_m1_n0_t1; sotristripset_ni_render_funcs[10] = sogl_nits_m1_n1_t0; sotristripset_ni_render_funcs[11] = sogl_nits_m1_n1_t1; sotristripset_ni_render_funcs[12] = sogl_nits_m1_n2_t0; sotristripset_ni_render_funcs[13] = sogl_nits_m1_n2_t1; sotristripset_ni_render_funcs[14] = sogl_nits_m1_n3_t0; sotristripset_ni_render_funcs[15] = sogl_nits_m1_n3_t1; sotristripset_ni_render_funcs[16] = sogl_nits_m2_n0_t0; sotristripset_ni_render_funcs[17] = sogl_nits_m2_n0_t1; sotristripset_ni_render_funcs[18] = sogl_nits_m2_n1_t0; sotristripset_ni_render_funcs[19] = sogl_nits_m2_n1_t1; sotristripset_ni_render_funcs[20] = sogl_nits_m2_n2_t0; sotristripset_ni_render_funcs[21] = sogl_nits_m2_n2_t1; sotristripset_ni_render_funcs[22] = sogl_nits_m2_n3_t0; sotristripset_ni_render_funcs[23] = sogl_nits_m2_n3_t1; sotristripset_ni_render_funcs[24] = sogl_nits_m3_n0_t0; sotristripset_ni_render_funcs[25] = sogl_nits_m3_n0_t1; sotristripset_ni_render_funcs[26] = sogl_nits_m3_n1_t0; sotristripset_ni_render_funcs[27] = sogl_nits_m3_n1_t1; sotristripset_ni_render_funcs[28] = sogl_nits_m3_n2_t0; sotristripset_ni_render_funcs[29] = sogl_nits_m3_n2_t1; sotristripset_ni_render_funcs[30] = sogl_nits_m3_n3_t0; sotristripset_ni_render_funcs[31] = sogl_nits_m3_n3_t1; } // doc from parent void SoTriangleStripSet::GLRender(SoGLRenderAction * action) { int32_t idx = this->startIndex.getValue(); int32_t dummyarray[1]; const int32_t * ptr = this->numVertices.getValues(0); const int32_t * end = ptr + this->numVertices.getNum(); if ((end-ptr == 1) && ptr[0] == 0) return; // nothing to render SoState * state = action->getState(); this->fixNumVerticesPointers(state, ptr, end, dummyarray); SbBool didpush = FALSE; if (this->vertexProperty.getValue()) { state->push(); didpush = TRUE; this->vertexProperty.getValue()->GLRender(action); } Binding mbind = this->findMaterialBinding(action->getState()); Binding nbind = this->findNormalBinding(action->getState()); if ((nbind == PER_FACE && mbind != PER_VERTEX) || (mbind == PER_FACE && nbind != PER_VERTEX)) { if (!didpush) { didpush = TRUE; state->push(); } SoLazyElement::setShadeModel(state, TRUE); } if (!this->shouldGLRender(action)) { if (didpush) state->pop(); return; } const SoCoordinateElement * tmp; const SbVec3f * normals; SbBool doTextures; SoTextureCoordinateBundle tb(action, TRUE, FALSE); doTextures = tb.needCoordinates(); SoMaterialBundle mb(action); SbBool needNormals = !mb.isColorOnly() || tb.isFunction(); SoVertexShape::getVertexData(action->getState(), tmp, normals, needNormals); const SoGLCoordinateElement * coords = (SoGLCoordinateElement *)tmp; if (!needNormals) nbind = OVERALL; SoNormalCache * nc = NULL; if (needNormals && normals == NULL) { nc = this->generateAndReadLockNormalCache(state); normals = nc->getNormals(); } mb.sendFirst(); // make sure we have the correct material sotristripset_ni_render_funcs[ (mbind << 3) | (nbind << 1) | doTextures ] ( coords, normals, &mb, &tb, nbind, mbind, doTextures, idx, ptr, end, needNormals); if (nc) { this->readUnlockNormalCache(); } if (didpush) state->pop(); int numv = this->numVertices.getNum(); // send approx number of triangles for autocache handling sogl_autocache_update(state, numv ? (this->numVertices[0]-2)*numv : 0); } // doc from parent SbBool SoTriangleStripSet::generateDefaultNormals(SoState * state, SoNormalCache * nc) { SbBool ccw = TRUE; if (SoShapeHintsElement::getVertexOrdering(state) == SoShapeHintsElement::CLOCKWISE) ccw = FALSE; const SoCoordinateElement * coords = SoCoordinateElement::getInstance(state); assert(coords); SoNormalGenerator * gen = new SoNormalGenerator(ccw, this->numVertices.getNum()*3); int32_t idx = startIndex.getValue(); int32_t dummyarray[1]; const int32_t * ptr = numVertices.getValues(0); const int32_t * end = ptr + numVertices.getNum(); this->fixNumVerticesPointers(state, ptr, end, dummyarray); const int32_t * start = ptr; while (ptr < end) { int num = *ptr++ - 3; assert(num >= 0); SbVec3f striptri[3]; striptri[0] = coords->get3(idx++); striptri[1] = coords->get3(idx++); striptri[2] = coords->get3(idx++); gen->triangle(striptri[0], striptri[1], striptri[2]); SbBool flag = FALSE; while (num--) { if (flag) striptri[1] = striptri[2]; else striptri[0] = striptri[2]; flag = !flag; striptri[2] = coords->get3(idx++); gen->triangle(striptri[0], striptri[1], striptri[2]); } } const ptrdiff_t range = end - start; switch (this->findNormalBinding(state)) { case OVERALL: gen->generateOverall(); break; case PER_STRIP: gen->generatePerStrip(start, (int)range); break; case PER_FACE: gen->generatePerFace(); break; case PER_VERTEX: gen->generate(SoCreaseAngleElement::get(state), start, (int)range); break; } nc->set(gen); return TRUE; } // doc from parent void SoTriangleStripSet::getPrimitiveCount(SoGetPrimitiveCountAction *action) { if (!this->shouldPrimitiveCount(action)) return; int32_t dummyarray[1]; const int32_t * ptr = numVertices.getValues(0); const int32_t * end = ptr + numVertices.getNum(); const ptrdiff_t range = end - ptr; if ((range == 1) && ptr[0] == 0) return; this->fixNumVerticesPointers(action->getState(), ptr, end, dummyarray); if (action->canApproximateCount()) { // this is a wild guess, disable? pederb, 20000131 action->addNumTriangles((int)(range * 8)); } else { int cnt = 0; while (ptr < end) { cnt += *ptr++ - 2; } action->addNumTriangles(cnt); } } // Documented in superclass. SbBool SoTriangleStripSet::generateDefaultNormals(SoState * /* state */, SoNormalBundle * /* nb */) { // Normals are generated in normal cache. return FALSE; } // Documented in superclass. void SoTriangleStripSet::generatePrimitives(SoAction *action) { if (this->numVertices.getNum() == 1 && this->numVertices[0] == 0) return; SoState * state = action->getState(); if (this->vertexProperty.getValue()) { state->push(); this->vertexProperty.getValue()->doAction(action); } const SoCoordinateElement * coords; const SbVec3f * normals; SbBool doTextures; SbBool needNormals = TRUE; SoVertexShape::getVertexData(action->getState(), coords, normals, needNormals); SoTextureCoordinateBundle tb(action, FALSE, FALSE); doTextures = tb.needCoordinates(); Binding mbind = this->findMaterialBinding(action->getState()); Binding nbind = this->findNormalBinding(action->getState()); SoNormalCache * nc = NULL; if (needNormals && normals == NULL) { nc = this->generateAndReadLockNormalCache(state); normals = nc->getNormals(); } int32_t idx = startIndex.getValue(); int32_t dummyarray[1]; const int32_t * ptr = numVertices.getValues(0); const int32_t * end = ptr + numVertices.getNum(); this->fixNumVerticesPointers(action->getState(), ptr, end, dummyarray); int matnr = 0; int texnr = 0; int normnr = 0; int n; SbVec3f dummynormal(0.0f, 0.0f, 1.0f); const SbVec3f * currnormal = &dummynormal; if (normals) currnormal = normals; SoPrimitiveVertex vertex; SoFaceDetail faceDetail; SoPointDetail pointDetail; vertex.setNormal(*currnormal); vertex.setDetail(&pointDetail); while (ptr < end) { n = *ptr++ - 3; if (n < 0) continue; // triangle with < 3 vertices, try next one faceDetail.setFaceIndex(0); this->beginShape(action, TRIANGLE_STRIP, &faceDetail); // first vertex if (nbind != OVERALL) { pointDetail.setNormalIndex(normnr); currnormal = &normals[normnr++]; vertex.setNormal(*currnormal); } if (mbind != OVERALL) { pointDetail.setMaterialIndex(matnr); vertex.setMaterialIndex(matnr++); } if (doTextures) { if (tb.isFunction()) { vertex.setTextureCoords(tb.get(coords->get3(idx), *currnormal)); if (tb.needIndices()) pointDetail.setTextureCoordIndex(texnr++); } else { pointDetail.setTextureCoordIndex(texnr); vertex.setTextureCoords(tb.get(texnr++)); } } pointDetail.setCoordinateIndex(idx); vertex.setPoint(coords->get3(idx++)); this->shapeVertex(&vertex); // second vertex if (nbind == PER_VERTEX) { pointDetail.setNormalIndex(normnr); currnormal = &normals[normnr++]; vertex.setNormal(*currnormal); } if (mbind == PER_VERTEX) { pointDetail.setMaterialIndex(matnr); vertex.setMaterialIndex(matnr++); } if (doTextures) { if (tb.isFunction()) { vertex.setTextureCoords(tb.get(coords->get3(idx), *currnormal)); if (tb.needIndices()) pointDetail.setTextureCoordIndex(texnr++); } else { pointDetail.setTextureCoordIndex(texnr); vertex.setTextureCoords(tb.get(texnr++)); } } pointDetail.setCoordinateIndex(idx); vertex.setPoint(coords->get3(idx++)); this->shapeVertex(&vertex); // third vertex if (nbind == PER_VERTEX) { pointDetail.setNormalIndex(normnr); currnormal = &normals[normnr++]; vertex.setNormal(*currnormal); } if (mbind == PER_VERTEX) { pointDetail.setMaterialIndex(matnr); vertex.setMaterialIndex(matnr++); } if (doTextures) { if (tb.isFunction()) { vertex.setTextureCoords(tb.get(coords->get3(idx), *currnormal)); if (tb.needIndices()) pointDetail.setTextureCoordIndex(texnr++); } else { pointDetail.setTextureCoordIndex(texnr); vertex.setTextureCoords(tb.get(texnr++)); } } pointDetail.setCoordinateIndex(idx); vertex.setPoint(coords->get3(idx++)); this->shapeVertex(&vertex); // loop for vertices 4-n while (n--) { if (nbind >= PER_FACE) { pointDetail.setNormalIndex(normnr); currnormal = &normals[normnr++]; vertex.setNormal(*currnormal); } if (mbind >= PER_FACE) { pointDetail.setMaterialIndex(matnr); vertex.setMaterialIndex(matnr++); } if (doTextures) { if (tb.isFunction()) { vertex.setTextureCoords(tb.get(coords->get3(idx), *currnormal)); if (tb.needIndices()) pointDetail.setTextureCoordIndex(texnr++); } else { pointDetail.setCoordinateIndex(texnr); vertex.setTextureCoords(tb.get(texnr++)); } } pointDetail.setCoordinateIndex(idx); vertex.setPoint(coords->get3(idx++)); this->shapeVertex(&vertex); faceDetail.incFaceIndex(); } this->endShape(); faceDetail.incPartIndex(); } if (nc) { this->readUnlockNormalCache(); } if (this->vertexProperty.getValue()) state->pop(); }