/*************************************************************************** * Copyright (c) 2011 Werner Mayer * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # ifdef FC_OS_WIN32 # include # endif # ifdef FC_OS_MACOSX # include # else # include # endif # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include #endif #include "SoBrepFaceSet.h" #include #include using namespace PartGui; SO_NODE_SOURCE(SoBrepFaceSet); void SoBrepFaceSet::initClass() { SO_NODE_INIT_CLASS(SoBrepFaceSet, SoIndexedFaceSet, "IndexedFaceSet"); } SoBrepFaceSet::SoBrepFaceSet() { SO_NODE_CONSTRUCTOR(SoBrepFaceSet); SO_NODE_ADD_FIELD(partIndex, (-1)); SO_NODE_ADD_FIELD(highlightIndex, (-1)); SO_NODE_ADD_FIELD(selectionIndex, (-1)); selectionIndex.setNum(0); } SoBrepFaceSet::~SoBrepFaceSet() { } void SoBrepFaceSet::doAction(SoAction* action) { if (action->getTypeId() == Gui::SoHighlightElementAction::getClassTypeId()) { Gui::SoHighlightElementAction* hlaction = static_cast(action); if (!hlaction->isHighlighted()) { this->highlightIndex = -1; return; } const SoDetail* detail = hlaction->getElement(); if (detail) { if (detail->isOfType(SoFaceDetail::getClassTypeId())) { int index = static_cast(detail)->getPartIndex(); this->highlightIndex.setValue(index); this->highlightColor = hlaction->getColor(); } else { this->highlightIndex = -1; return; } } } else if (action->getTypeId() == Gui::SoSelectionElementAction::getClassTypeId()) { Gui::SoSelectionElementAction* selaction = static_cast(action); this->selectionColor = selaction->getColor(); if (selaction->getType() == Gui::SoSelectionElementAction::All) { int num = this->partIndex.getNum(); this->selectionIndex.setNum(num); int32_t* v = this->selectionIndex.startEditing(); for (int i=0; iselectionIndex.finishEditing(); return; } else if (selaction->getType() == Gui::SoSelectionElementAction::None) { this->selectionIndex.setNum(0); return; } const SoDetail* detail = selaction->getElement(); if (detail) { if (!detail->isOfType(SoFaceDetail::getClassTypeId())) { return; } int index = static_cast(detail)->getPartIndex(); switch (selaction->getType()) { case Gui::SoSelectionElementAction::Append: { int start = this->selectionIndex.getNum(); this->selectionIndex.set1Value(start, index); } break; case Gui::SoSelectionElementAction::Remove: { int start = this->selectionIndex.find(index); this->selectionIndex.deleteValues(start,1); } break; default: break; } } } inherited::doAction(action); } #ifdef RENDER_GLARRAYS void SoBrepFaceSet::GLRender(SoGLRenderAction *action) { SoState * state = action->getState(); SoMaterialBundle mb(action); Binding mbind = this->findMaterialBinding(state); SoTextureCoordinateBundle tb(action, TRUE, FALSE); SbBool doTextures = tb.needCoordinates(); int32_t hl_idx = this->highlightIndex.getValue(); int32_t num_selected = this->selectionIndex.getNum(); if (this->coordIndex.getNum() < 3) return; if (num_selected > 0) renderSelection(action); if (hl_idx >= 0) renderHighlight(action); // When setting transparency shouldGLRender() handles the rendering and returns false. // Therefore generatePrimitives() needs to be re-implemented to handle the materials // correctly. if (!this->shouldGLRender(action)) return; #ifdef RENDER_GLARRAYS if (!doTextures && index_array.size() && hl_idx < 0 && num_selected <= 0) { if (mbind == 0) { mb.sendFirst(); // only one material -> apply it! renderSimpleArray(); return; } else if (mbind == 1) { renderColoredArray(&mb); return; } } #endif Binding nbind = this->findNormalBinding(state); const SoCoordinateElement * coords; const SbVec3f * normals; const int32_t * cindices; int numindices; const int32_t * nindices; const int32_t * tindices; const int32_t * mindices; const int32_t * pindices; int numparts; SbBool normalCacheUsed; SbBool sendNormals = !mb.isColorOnly() || tb.isFunction(); this->getVertexData(state, coords, normals, cindices, nindices, tindices, mindices, numindices, sendNormals, normalCacheUsed); mb.sendFirst(); // make sure we have the correct material // just in case someone forgot if (!mindices) mindices = cindices; if (!nindices) nindices = cindices; pindices = this->partIndex.getValues(0); numparts = this->partIndex.getNum(); renderShape(static_cast(coords), cindices, numindices, pindices, numparts, normals, nindices, &mb, mindices, &tb, tindices, nbind, mbind, doTextures?1:0); // Disable caching for this node SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE); // Workaround for #0000433 //#if !defined(FC_OS_WIN32) if (hl_idx >= 0) renderHighlight(action); if (num_selected > 0) renderSelection(action); //#endif } //**************************************************************************** // renderSimpleArray: normal and coord from vertex_array; // no texture, color, highlight or selection but highet possible speed; // all vertices written in one go! // void SoBrepFaceSet::renderSimpleArray() { int cnt = index_array.size(); if (cnt == 0) return; glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); #if 0 glInterleavedArrays(GL_N3F_V3F, 0, vertex_array.data()); glDrawElements(GL_TRIANGLES, cnt, GL_UNSIGNED_INT, index_array.data()); #else glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0])); glDrawElements(GL_TRIANGLES, cnt, GL_UNSIGNED_INT, &(index_array[0])); #endif glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); } //**************************************************************************** // renderColoredArray: normal and coord from vertex_array; // no texture, highlight or selection but color / material array. // needs to iterate over parts (i.e. geometry faces) // void SoBrepFaceSet::renderColoredArray(SoMaterialBundle *const materials) { int num_parts = partIndex.getNum(); int cnt = index_array.size(); if (cnt == 0) return; glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); #if 0 glInterleavedArrays(GL_N3F_V3F, 0, vertex_array.data()); const int32_t* ptr = index_array.data(); #else glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0])); const int32_t* ptr = &(index_array[0]); #endif for (int part_id = 0; part_id < num_parts; part_id++) { int tris = partIndex[part_id]; if (tris > 0) { materials->send(part_id, TRUE); glDrawElements(GL_TRIANGLES, 3 * tris, GL_UNSIGNED_INT, ptr); ptr += 3 * tris; } } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); } #else void SoBrepFaceSet::GLRender(SoGLRenderAction *action) { if (this->coordIndex.getNum() < 3) return; if (this->selectionIndex.getNum() > 0) renderSelection(action); if (this->highlightIndex.getValue() >= 0) renderHighlight(action); // When setting transparency shouldGLRender() handles the rendering and returns false. // Therefore generatePrimitives() needs to be re-implemented to handle the materials // correctly. if (!this->shouldGLRender(action)) return; SoState * state = action->getState(); Binding mbind = this->findMaterialBinding(state); Binding nbind = this->findNormalBinding(state); const SoCoordinateElement * coords; const SbVec3f * normals; const int32_t * cindices; int numindices; const int32_t * nindices; const int32_t * tindices; const int32_t * mindices; const int32_t * pindices; int numparts; SbBool doTextures; SbBool normalCacheUsed; SoMaterialBundle mb(action); SoTextureCoordinateBundle tb(action, TRUE, FALSE); doTextures = tb.needCoordinates(); SbBool sendNormals = !mb.isColorOnly() || tb.isFunction(); this->getVertexData(state, coords, normals, cindices, nindices, tindices, mindices, numindices, sendNormals, normalCacheUsed); mb.sendFirst(); // make sure we have the correct material // just in case someone forgot if (!mindices) mindices = cindices; if (!nindices) nindices = cindices; pindices = this->partIndex.getValues(0); numparts = this->partIndex.getNum(); renderShape(static_cast(coords), cindices, numindices, pindices, numparts, normals, nindices, &mb, mindices, &tb, tindices, nbind, mbind, doTextures?1:0); // Disable caching for this node SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE); // Workaround for #0000433 //#if !defined(FC_OS_WIN32) if (this->highlightIndex.getValue() >= 0) renderHighlight(action); if (this->selectionIndex.getNum() > 0) renderSelection(action); //#endif } #endif void SoBrepFaceSet::GLRenderBelowPath(SoGLRenderAction * action) { inherited::GLRenderBelowPath(action); } // this macro actually makes the code below more readable :-) #define DO_VERTEX(idx) \ if (mbind == PER_VERTEX) { \ pointDetail.setMaterialIndex(matnr); \ vertex.setMaterialIndex(matnr++); \ } \ else if (mbind == PER_VERTEX_INDEXED) { \ pointDetail.setMaterialIndex(*mindices); \ vertex.setMaterialIndex(*mindices++); \ } \ if (nbind == PER_VERTEX) { \ pointDetail.setNormalIndex(normnr); \ currnormal = &normals[normnr++]; \ vertex.setNormal(*currnormal); \ } \ else if (nbind == PER_VERTEX_INDEXED) { \ pointDetail.setNormalIndex(*nindices); \ currnormal = &normals[*nindices++]; \ vertex.setNormal(*currnormal); \ } \ if (tb.isFunction()) { \ vertex.setTextureCoords(tb.get(coords->get3(idx), *currnormal)); \ if (tb.needIndices()) pointDetail.setTextureCoordIndex(tindices ? *tindices++ : texidx++); \ } \ else if (tbind != NONE) { \ pointDetail.setTextureCoordIndex(tindices ? *tindices : texidx); \ vertex.setTextureCoords(tb.get(tindices ? *tindices++ : texidx++)); \ } \ vertex.setPoint(coords->get3(idx)); \ pointDetail.setCoordinateIndex(idx); \ this->shapeVertex(&vertex); void SoBrepFaceSet::generatePrimitives(SoAction * action) { //TODO #if 0 inherited::generatePrimitives(action); #else //This is highly experimental!!! if (this->coordIndex.getNum() < 3) return; SoState * state = action->getState(); if (this->vertexProperty.getValue()) { state->push(); this->vertexProperty.getValue()->doAction(action); } Binding mbind = this->findMaterialBinding(state); Binding nbind = this->findNormalBinding(state); const SoCoordinateElement * coords; const SbVec3f * normals; const int32_t * cindices; int numindices; const int32_t * nindices; const int32_t * tindices; const int32_t * mindices; SbBool doTextures; SbBool sendNormals; SbBool normalCacheUsed; sendNormals = TRUE; // always generate normals this->getVertexData(state, coords, normals, cindices, nindices, tindices, mindices, numindices, sendNormals, normalCacheUsed); SoTextureCoordinateBundle tb(action, FALSE, FALSE); doTextures = tb.needCoordinates(); if (!sendNormals) nbind = OVERALL; else if (normalCacheUsed && nbind == PER_VERTEX) { nbind = PER_VERTEX_INDEXED; } else if (normalCacheUsed && nbind == PER_FACE_INDEXED) { nbind = PER_FACE; } if (this->getNodeType() == SoNode::VRML1) { // For VRML1, PER_VERTEX means per vertex in shape, not PER_VERTEX // on the state. if (mbind == PER_VERTEX) { mbind = PER_VERTEX_INDEXED; mindices = cindices; } if (nbind == PER_VERTEX) { nbind = PER_VERTEX_INDEXED; nindices = cindices; } } Binding tbind = NONE; if (doTextures) { if (tb.isFunction() && !tb.needIndices()) { tbind = NONE; tindices = NULL; } // FIXME: just call inherited::areTexCoordsIndexed() instead of // the if-check? 20020110 mortene. else if (SoTextureCoordinateBindingElement::get(state) == SoTextureCoordinateBindingElement::PER_VERTEX) { tbind = PER_VERTEX; tindices = NULL; } else { tbind = PER_VERTEX_INDEXED; if (tindices == NULL) tindices = cindices; } } if (nbind == PER_VERTEX_INDEXED && nindices == NULL) { nindices = cindices; } if (mbind == PER_VERTEX_INDEXED && mindices == NULL) { mindices = cindices; } int texidx = 0; TriangleShape mode = POLYGON; TriangleShape newmode; const int32_t *viptr = cindices; const int32_t *viendptr = viptr + numindices; const int32_t *piptr = this->partIndex.getValues(0); int num_partindices = this->partIndex.getNum(); const int32_t *piendptr = piptr + num_partindices; int32_t v1, v2, v3, v4, v5 = 0, pi; // v5 init unnecessary, but kills a compiler warning. SoPrimitiveVertex vertex; SoPointDetail pointDetail; SoFaceDetail faceDetail; vertex.setDetail(&pointDetail); SbVec3f dummynormal(0,0,1); const SbVec3f *currnormal = &dummynormal; if (normals) currnormal = normals; vertex.setNormal(*currnormal); int matnr = 0; int normnr = 0; int trinr = 0; pi = piptr < piendptr ? *piptr++ : -1; while (pi == 0) { // It may happen that a part has no triangles pi = piptr < piendptr ? *piptr++ : -1; if (mbind == PER_PART) matnr++; else if (mbind == PER_PART_INDEXED) mindices++; } while (viptr + 2 < viendptr) { v1 = *viptr++; v2 = *viptr++; v3 = *viptr++; if (v1 < 0 || v2 < 0 || v3 < 0) { break; } v4 = viptr < viendptr ? *viptr++ : -1; if (v4 < 0) newmode = TRIANGLES; else { v5 = viptr < viendptr ? *viptr++ : -1; if (v5 < 0) newmode = QUADS; else newmode = POLYGON; } if (newmode != mode) { if (mode != POLYGON) this->endShape(); mode = newmode; this->beginShape(action, mode, &faceDetail); } else if (mode == POLYGON) this->beginShape(action, POLYGON, &faceDetail); // vertex 1 can't use DO_VERTEX if (mbind == PER_PART) { if (trinr == 0) { pointDetail.setMaterialIndex(matnr); vertex.setMaterialIndex(matnr++); } } else if (mbind == PER_PART_INDEXED) { if (trinr == 0) { pointDetail.setMaterialIndex(*mindices); vertex.setMaterialIndex(*mindices++); } } else if (mbind == PER_VERTEX || mbind == PER_FACE) { pointDetail.setMaterialIndex(matnr); vertex.setMaterialIndex(matnr++); } else if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) { pointDetail.setMaterialIndex(*mindices); vertex.setMaterialIndex(*mindices++); } if (nbind == PER_VERTEX || nbind == PER_FACE) { pointDetail.setNormalIndex(normnr); currnormal = &normals[normnr++]; vertex.setNormal(*currnormal); } else if (nbind == PER_FACE_INDEXED || nbind == PER_VERTEX_INDEXED) { pointDetail.setNormalIndex(*nindices); currnormal = &normals[*nindices++]; vertex.setNormal(*currnormal); } if (tb.isFunction()) { vertex.setTextureCoords(tb.get(coords->get3(v1), *currnormal)); if (tb.needIndices()) pointDetail.setTextureCoordIndex(tindices ? *tindices++ : texidx++); } else if (tbind != NONE) { pointDetail.setTextureCoordIndex(tindices ? *tindices : texidx); vertex.setTextureCoords(tb.get(tindices ? *tindices++ : texidx++)); } pointDetail.setCoordinateIndex(v1); vertex.setPoint(coords->get3(v1)); this->shapeVertex(&vertex); DO_VERTEX(v2); DO_VERTEX(v3); if (mode != TRIANGLES) { DO_VERTEX(v4); if (mode == POLYGON) { DO_VERTEX(v5); v1 = viptr < viendptr ? *viptr++ : -1; while (v1 >= 0) { DO_VERTEX(v1); v1 = viptr < viendptr ? *viptr++ : -1; } this->endShape(); } } faceDetail.incFaceIndex(); if (mbind == PER_VERTEX_INDEXED) { mindices++; } if (nbind == PER_VERTEX_INDEXED) { nindices++; } if (tindices) tindices++; trinr++; if (pi == trinr) { pi = piptr < piendptr ? *piptr++ : -1; while (pi == 0) { // It may happen that a part has no triangles pi = piptr < piendptr ? *piptr++ : -1; if (mbind == PER_PART) matnr++; else if (mbind == PER_PART_INDEXED) mindices++; } trinr = 0; } } if (mode != POLYGON) this->endShape(); if (normalCacheUsed) { this->readUnlockNormalCache(); } if (this->vertexProperty.getValue()) { state->pop(); } #endif } #undef DO_VERTEX void SoBrepFaceSet::renderHighlight(SoGLRenderAction *action) { SoState * state = action->getState(); state->push(); SoLazyElement::setEmissive(state, &this->highlightColor); SoOverrideElement::setEmissiveColorOverride(state, this, TRUE); #if 0 // disables shading effect // sendNormals will be FALSE SoLazyElement::setDiffuse(state, this,1, &this->highlightColor,&this->colorpacker); SoOverrideElement::setDiffuseColorOverride(state, this, TRUE); SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); #endif Binding mbind = this->findMaterialBinding(state); Binding nbind = this->findNormalBinding(state); const SoCoordinateElement * coords; const SbVec3f * normals; const int32_t * cindices; int numindices; const int32_t * nindices; const int32_t * tindices; const int32_t * mindices; const int32_t * pindices; SbBool doTextures; SbBool normalCacheUsed; SoMaterialBundle mb(action); SoTextureCoordinateBundle tb(action, TRUE, FALSE); doTextures = tb.needCoordinates(); SbBool sendNormals = !mb.isColorOnly() || tb.isFunction(); this->getVertexData(state, coords, normals, cindices, nindices, tindices, mindices, numindices, sendNormals, normalCacheUsed); mb.sendFirst(); // make sure we have the correct material int32_t id = this->highlightIndex.getValue(); // just in case someone forgot if (!mindices) mindices = cindices; if (!nindices) nindices = cindices; pindices = this->partIndex.getValues(0); // coords int length = (int)pindices[id]*4; int start=0; for (int i=0;i(coords), &(cindices[start]), length, &(pindices[id]), 1, normals, nindices, &mb, mindices, &tb, tindices, nbind, mbind, doTextures?1:0); state->pop(); } void SoBrepFaceSet::renderSelection(SoGLRenderAction *action) { int numSelected = this->selectionIndex.getNum(); const int32_t* selected = this->selectionIndex.getValues(0); if (numSelected == 0) return; SoState * state = action->getState(); state->push(); SoLazyElement::setEmissive(state, &this->selectionColor); SoOverrideElement::setEmissiveColorOverride(state, this, TRUE); #if 0 // disables shading effect SoLazyElement::setDiffuse(state, this,1, &this->selectionColor,&this->colorpacker); SoOverrideElement::setDiffuseColorOverride(state, this, TRUE); SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); #endif Binding mbind = this->findMaterialBinding(state); Binding nbind = this->findNormalBinding(state); const SoCoordinateElement * coords; const SbVec3f * normals; const int32_t * cindices; int numindices; const int32_t * nindices; const int32_t * tindices; const int32_t * mindices; const int32_t * pindices; SbBool doTextures; SbBool normalCacheUsed; SoMaterialBundle mb(action); SoTextureCoordinateBundle tb(action, TRUE, FALSE); doTextures = tb.needCoordinates(); SbBool sendNormals = !mb.isColorOnly() || tb.isFunction(); this->getVertexData(state, coords, normals, cindices, nindices, tindices, mindices, numindices, sendNormals, normalCacheUsed); mb.sendFirst(); // make sure we have the correct material // just in case someone forgot if (!mindices) mindices = cindices; if (!nindices) nindices = cindices; pindices = this->partIndex.getValues(0); // materials mbind = OVERALL; doTextures = FALSE; for (int i=0; i(coords), &(cindices[start]), length, &(pindices[id]), 1, normals_s, nindices_s, &mb, mindices, &tb, tindices, nbind, mbind, doTextures?1:0); } state->pop(); } void SoBrepFaceSet::renderShape(const SoGLCoordinateElement * const vertexlist, const int32_t *vertexindices, int num_indices, const int32_t *partindices, int num_partindices, const SbVec3f *normals, const int32_t *normalindices, SoMaterialBundle *const materials, const int32_t *matindices, SoTextureCoordinateBundle * const texcoords, const int32_t *texindices, const int nbind, const int mbind, const int texture) { int texidx = 0; const SbVec3f * coords3d = NULL; coords3d = vertexlist->getArrayPtr3(); const int32_t *viptr = vertexindices; const int32_t *viendptr = viptr + num_indices; const int32_t *piptr = partindices; const int32_t *piendptr = piptr + num_partindices; int32_t v1, v2, v3, v4, pi; SbVec3f dummynormal(0,0,1); int numverts = vertexlist->getNum(); const SbVec3f *currnormal = &dummynormal; if (normals) currnormal = normals; int matnr = 0; int trinr = 0; pi = piptr < piendptr ? *piptr++ : -1; while (pi == 0) { // It may happen that a part has no triangles pi = piptr < piendptr ? *piptr++ : -1; if (mbind == PER_PART) matnr++; else if (mbind == PER_PART_INDEXED) matindices++; } glBegin(GL_TRIANGLES); while (viptr + 2 < viendptr) { v1 = *viptr++; v2 = *viptr++; v3 = *viptr++; // This test is for robustness upon buggy data sets if (v1 < 0 || v2 < 0 || v3 < 0 || v1 >= numverts || v2 >= numverts || v3 >= numverts) { break; } v4 = viptr < viendptr ? *viptr++ : -1; /* vertex 1 *********************************************************/ if (mbind == PER_PART) { if (trinr == 0) materials->send(matnr++, TRUE); } else if (mbind == PER_PART_INDEXED) { if (trinr == 0) materials->send(*matindices++, TRUE); } else if (mbind == PER_VERTEX || mbind == PER_FACE) { materials->send(matnr++, TRUE); } else if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) { materials->send(*matindices++, TRUE); } if (normals) { if (nbind == PER_VERTEX || nbind == PER_FACE) { currnormal = normals++; glNormal3fv((const GLfloat*)currnormal); } else if (nbind == PER_VERTEX_INDEXED || nbind == PER_FACE_INDEXED) { currnormal = &normals[*normalindices++]; glNormal3fv((const GLfloat*)currnormal); } } if (texture) { texcoords->send(texindices ? *texindices++ : texidx++, vertexlist->get3(v1), *currnormal); } glVertex3fv((const GLfloat*) (coords3d + v1)); /* vertex 2 *********************************************************/ if (mbind == PER_VERTEX) materials->send(matnr++, TRUE); else if (mbind == PER_VERTEX_INDEXED) materials->send(*matindices++, TRUE); if (normals) { if (nbind == PER_VERTEX) { currnormal = normals++; glNormal3fv((const GLfloat*)currnormal); } else if (nbind == PER_VERTEX_INDEXED) { currnormal = &normals[*normalindices++]; glNormal3fv((const GLfloat*)currnormal); } } if (texture) { texcoords->send(texindices ? *texindices++ : texidx++, vertexlist->get3(v2), *currnormal); } glVertex3fv((const GLfloat*) (coords3d + v2)); /* vertex 3 *********************************************************/ if (mbind == PER_VERTEX) materials->send(matnr++, TRUE); else if (mbind == PER_VERTEX_INDEXED) materials->send(*matindices++, TRUE); if (normals) { if (nbind == PER_VERTEX) { currnormal = normals++; glNormal3fv((const GLfloat*)currnormal); } else if (nbind == PER_VERTEX_INDEXED) { currnormal = &normals[*normalindices++]; glNormal3fv((const GLfloat*)currnormal); } } if (texture) { texcoords->send(texindices ? *texindices++ : texidx++, vertexlist->get3(v3), *currnormal); } glVertex3fv((const GLfloat*) (coords3d + v3)); if (mbind == PER_VERTEX_INDEXED) matindices++; if (nbind == PER_VERTEX_INDEXED) normalindices++; if (texture && texindices) { texindices++; } trinr++; if (pi == trinr) { pi = piptr < piendptr ? *piptr++ : -1; while (pi == 0) { // It may happen that a part has no triangles pi = piptr < piendptr ? *piptr++ : -1; if (mbind == PER_PART) matnr++; else if (mbind == PER_PART_INDEXED) matindices++; } trinr = 0; } } glEnd(); } SoDetail * SoBrepFaceSet::createTriangleDetail(SoRayPickAction * action, const SoPrimitiveVertex * v1, const SoPrimitiveVertex * v2, const SoPrimitiveVertex * v3, SoPickedPoint * pp) { SoDetail* detail = inherited::createTriangleDetail(action, v1, v2, v3, pp); const int32_t * indices = this->partIndex.getValues(0); int num = this->partIndex.getNum(); if (indices) { SoFaceDetail* face_detail = static_cast(detail); int index = face_detail->getFaceIndex(); int count = 0; for (int i=0; isetPartIndex(i); break; } } } return detail; } SoBrepFaceSet::Binding SoBrepFaceSet::findMaterialBinding(SoState * const state) const { Binding binding = OVERALL; SoMaterialBindingElement::Binding matbind = SoMaterialBindingElement::get(state); switch (matbind) { case SoMaterialBindingElement::OVERALL: binding = OVERALL; break; case SoMaterialBindingElement::PER_VERTEX: binding = PER_VERTEX; break; case SoMaterialBindingElement::PER_VERTEX_INDEXED: binding = PER_VERTEX_INDEXED; break; case SoMaterialBindingElement::PER_PART: binding = PER_PART; break; case SoMaterialBindingElement::PER_FACE: binding = PER_FACE; break; case SoMaterialBindingElement::PER_PART_INDEXED: binding = PER_PART_INDEXED; break; case SoMaterialBindingElement::PER_FACE_INDEXED: binding = PER_FACE_INDEXED; break; default: break; } return binding; } SoBrepFaceSet::Binding SoBrepFaceSet::findNormalBinding(SoState * const state) const { Binding binding = PER_VERTEX_INDEXED; SoNormalBindingElement::Binding normbind = (SoNormalBindingElement::Binding) SoNormalBindingElement::get(state); switch (normbind) { case SoNormalBindingElement::OVERALL: binding = OVERALL; break; case SoNormalBindingElement::PER_VERTEX: binding = PER_VERTEX; break; case SoNormalBindingElement::PER_VERTEX_INDEXED: binding = PER_VERTEX_INDEXED; break; case SoNormalBindingElement::PER_PART: binding = PER_PART; break; case SoNormalBindingElement::PER_FACE: binding = PER_FACE; break; case SoNormalBindingElement::PER_PART_INDEXED: binding = PER_PART_INDEXED; break; case SoNormalBindingElement::PER_FACE_INDEXED: binding = PER_FACE_INDEXED; break; default: break; } return binding; }