1045 lines
34 KiB
C++
1045 lines
34 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
|
* *
|
|
* 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 <windows.h>
|
|
# endif
|
|
# ifdef FC_OS_MACOSX
|
|
# include <OpenGL/gl.h>
|
|
# else
|
|
# include <GL/gl.h>
|
|
# endif
|
|
# include <float.h>
|
|
# include <algorithm>
|
|
# include <Inventor/SoPickedPoint.h>
|
|
# include <Inventor/SoPrimitiveVertex.h>
|
|
# include <Inventor/actions/SoCallbackAction.h>
|
|
# include <Inventor/actions/SoGetBoundingBoxAction.h>
|
|
# include <Inventor/actions/SoGetPrimitiveCountAction.h>
|
|
# include <Inventor/actions/SoGLRenderAction.h>
|
|
# include <Inventor/actions/SoPickAction.h>
|
|
# include <Inventor/actions/SoWriteAction.h>
|
|
# include <Inventor/bundles/SoMaterialBundle.h>
|
|
# include <Inventor/bundles/SoTextureCoordinateBundle.h>
|
|
# include <Inventor/elements/SoOverrideElement.h>
|
|
# include <Inventor/elements/SoCoordinateElement.h>
|
|
# include <Inventor/elements/SoGLCoordinateElement.h>
|
|
# include <Inventor/elements/SoGLCacheContextElement.h>
|
|
# include <Inventor/elements/SoLineWidthElement.h>
|
|
# include <Inventor/elements/SoPointSizeElement.h>
|
|
# include <Inventor/errors/SoReadError.h>
|
|
# include <Inventor/details/SoFaceDetail.h>
|
|
# include <Inventor/details/SoLineDetail.h>
|
|
# include <Inventor/misc/SoState.h>
|
|
#endif
|
|
|
|
#include "SoBrepFaceSet.h"
|
|
#include <Gui/SoFCUnifiedSelection.h>
|
|
#include <Gui/SoFCSelectionAction.h>
|
|
|
|
|
|
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<Gui::SoHighlightElementAction*>(action);
|
|
if (!hlaction->isHighlighted()) {
|
|
this->highlightIndex = -1;
|
|
return;
|
|
}
|
|
|
|
const SoDetail* detail = hlaction->getElement();
|
|
if (detail) {
|
|
if (detail->isOfType(SoFaceDetail::getClassTypeId())) {
|
|
int index = static_cast<const SoFaceDetail*>(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<Gui::SoSelectionElementAction*>(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; i<num;i++)
|
|
v[i] = i;
|
|
this->selectionIndex.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<const SoFaceDetail*>(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<const SoGLCoordinateElement*>(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<const SoGLCoordinateElement*>(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<id;i++)
|
|
start+=(int)pindices[i];
|
|
start *= 4;
|
|
|
|
// normals
|
|
if (nbind == PER_VERTEX_INDEXED)
|
|
nindices = &(nindices[start]);
|
|
else if (nbind == PER_VERTEX)
|
|
normals = &(normals[start]);
|
|
else
|
|
nbind = OVERALL;
|
|
|
|
// materials
|
|
mbind = OVERALL;
|
|
doTextures = FALSE;
|
|
|
|
renderShape(static_cast<const SoGLCoordinateElement*>(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<numSelected; i++) {
|
|
int id = selected[i];
|
|
|
|
// coords
|
|
int length = (int)pindices[id]*4;
|
|
int start=0;
|
|
for (int j=0;j<id;j++)
|
|
start+=(int)pindices[j];
|
|
start *= 4;
|
|
|
|
// normals
|
|
const SbVec3f * normals_s = normals;
|
|
const int32_t * nindices_s = nindices;
|
|
if (nbind == PER_VERTEX_INDEXED)
|
|
nindices_s = &(nindices[start]);
|
|
else if (nbind == PER_VERTEX)
|
|
normals_s = &(normals[start]);
|
|
else
|
|
nbind = OVERALL;
|
|
|
|
renderShape(static_cast<const SoGLCoordinateElement*>(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<SoFaceDetail*>(detail);
|
|
int index = face_detail->getFaceIndex();
|
|
int count = 0;
|
|
for (int i=0; i<num; i++) {
|
|
count += indices[i];
|
|
if (index < count) {
|
|
face_detail->setPartIndex(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;
|
|
}
|