| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <FCConfig.h> |
| |
|
| | #ifndef FC_OS_WIN32 |
| | # ifndef GL_GLEXT_PROTOTYPES |
| | # define GL_GLEXT_PROTOTYPES 1 |
| | # endif |
| | #else |
| | # include <windows.h> |
| | #endif |
| |
|
| | #include <algorithm> |
| | #include <limits> |
| | #ifdef FC_OS_MACOSX |
| | # include <OpenGL/gl.h> |
| | # include <OpenGL/glext.h> |
| | # include <OpenGL/glu.h> |
| | #else |
| | # include <GL/gl.h> |
| | # include <GL/glext.h> |
| | # include <GL/glu.h> |
| | #endif |
| | #include <Inventor/actions/SoGLRenderAction.h> |
| | #include <Inventor/actions/SoSearchAction.h> |
| | #include <Inventor/bundles/SoMaterialBundle.h> |
| | #include <Inventor/bundles/SoTextureCoordinateBundle.h> |
| | #include <Inventor/elements/SoCoordinateElement.h> |
| | #include <Inventor/elements/SoGLCacheContextElement.h> |
| | #include <Inventor/elements/SoGLCoordinateElement.h> |
| | #include <Inventor/elements/SoGLLazyElement.h> |
| | #include <Inventor/elements/SoMaterialBindingElement.h> |
| | #include <Inventor/elements/SoNormalBindingElement.h> |
| | #include <Inventor/elements/SoProjectionMatrixElement.h> |
| | #include <Inventor/elements/SoViewingMatrixElement.h> |
| | #include <Inventor/errors/SoDebugError.h> |
| | #include <Inventor/nodes/SoCoordinate3.h> |
| |
|
| | #include <Inventor/C/glue/gl.h> |
| |
|
| | #include <Gui/GLBuffer.h> |
| | #include <Gui/SoFCInteractiveElement.h> |
| | #include <Gui/Selection/SoFCSelectionAction.h> |
| |
|
| | #include "SoFCIndexedFaceSet.h" |
| |
|
| |
|
| | #define RENDER_GL_VAO |
| |
|
| | using namespace MeshGui; |
| |
|
| | #if defined RENDER_GL_VAO |
| |
|
| | class MeshRenderer::Private |
| | { |
| | public: |
| | Gui::OpenGLMultiBuffer vertices; |
| | Gui::OpenGLMultiBuffer indices; |
| | const SbColor* pcolors {nullptr}; |
| | SoMaterialBindingElement::Binding matbinding {SoMaterialBindingElement::OVERALL}; |
| | bool initialized {false}; |
| |
|
| | Private(); |
| | bool canRenderGLArray(SoGLRenderAction*) const; |
| | void generateGLArrays( |
| | SoGLRenderAction* action, |
| | SoMaterialBindingElement::Binding matbind, |
| | std::vector<float>& vertex, |
| | std::vector<int32_t>& index |
| | ); |
| | void renderFacesGLArray(SoGLRenderAction*); |
| | void renderCoordsGLArray(SoGLRenderAction*); |
| | void update(); |
| | bool needUpdate(SoGLRenderAction*); |
| |
|
| | private: |
| | void renderGLArray(SoGLRenderAction*, GLenum); |
| | }; |
| |
|
| | MeshRenderer::Private::Private() |
| | : vertices(GL_ARRAY_BUFFER) |
| | , indices(GL_ELEMENT_ARRAY_BUFFER) |
| | {} |
| |
|
| | bool MeshRenderer::Private::canRenderGLArray(SoGLRenderAction* action) const |
| | { |
| | static bool init = false; |
| | static bool vboAvailable = false; |
| | if (!init) { |
| | vboAvailable = Gui::OpenGLBuffer::isVBOSupported(action->getCacheContext()); |
| | if (!vboAvailable) { |
| | SoDebugError::postInfo("MeshRenderer", "GL_ARB_vertex_buffer_object extension not supported"); |
| | } |
| | init = true; |
| | } |
| |
|
| | return vboAvailable; |
| | } |
| |
|
| | void MeshRenderer::Private::generateGLArrays( |
| | SoGLRenderAction* action, |
| | SoMaterialBindingElement::Binding matbind, |
| | std::vector<float>& vertex, |
| | std::vector<int32_t>& index |
| | ) |
| | { |
| | if (vertex.empty() || index.empty()) { |
| | return; |
| | } |
| |
|
| | |
| | vertices.setCurrentContext(action->getCacheContext()); |
| | indices.setCurrentContext(action->getCacheContext()); |
| |
|
| | initialized = true; |
| | vertices.create(); |
| | indices.create(); |
| |
|
| | vertices.bind(); |
| | vertices.allocate(vertex.data(), vertex.size() * sizeof(float)); |
| | vertices.release(); |
| |
|
| | indices.bind(); |
| | indices.allocate(index.data(), index.size() * sizeof(int32_t)); |
| | indices.release(); |
| | this->matbinding = matbind; |
| | } |
| |
|
| | void MeshRenderer::Private::renderGLArray(SoGLRenderAction* action, GLenum mode) |
| | { |
| | if (!initialized) { |
| | SoDebugError::postWarning("MeshRenderer", "not initialized"); |
| | return; |
| | } |
| |
|
| | vertices.setCurrentContext(action->getCacheContext()); |
| | indices.setCurrentContext(action->getCacheContext()); |
| |
|
| | glEnableClientState(GL_VERTEX_ARRAY); |
| | glEnableClientState(GL_NORMAL_ARRAY); |
| | glEnableClientState(GL_COLOR_ARRAY); |
| |
|
| | vertices.bind(); |
| | indices.bind(); |
| |
|
| | if (matbinding != SoMaterialBindingElement::OVERALL) { |
| | glInterleavedArrays(GL_C4F_N3F_V3F, 0, nullptr); |
| | } |
| | else { |
| | glInterleavedArrays(GL_N3F_V3F, 0, nullptr); |
| | } |
| |
|
| | glDrawElements(mode, indices.size() / sizeof(uint32_t), GL_UNSIGNED_INT, nullptr); |
| |
|
| | vertices.release(); |
| | indices.release(); |
| |
|
| | glDisableClientState(GL_COLOR_ARRAY); |
| | glDisableClientState(GL_NORMAL_ARRAY); |
| | glDisableClientState(GL_VERTEX_ARRAY); |
| | } |
| |
|
| | void MeshRenderer::Private::renderFacesGLArray(SoGLRenderAction* action) |
| | { |
| | renderGLArray(action, GL_TRIANGLES); |
| | } |
| |
|
| | void MeshRenderer::Private::renderCoordsGLArray(SoGLRenderAction* action) |
| | { |
| | renderGLArray(action, GL_POINTS); |
| | } |
| |
|
| | void MeshRenderer::Private::update() |
| | { |
| | vertices.destroy(); |
| | indices.destroy(); |
| | } |
| |
|
| | bool MeshRenderer::Private::needUpdate(SoGLRenderAction* action) |
| | { |
| | return !vertices.isCreated(action->getCacheContext()) |
| | || !indices.isCreated(action->getCacheContext()); |
| | } |
| | #elif defined RENDER_GLARRAYS |
| | class MeshRenderer::Private |
| | { |
| | public: |
| | std::vector<int32_t> index_array; |
| | std::vector<float> vertex_array; |
| | const SbColor* pcolors; |
| | SoMaterialBindingElement::Binding matbinding; |
| |
|
| | Private() |
| | : pcolors(0) |
| | , matbinding(SoMaterialBindingElement::OVERALL) |
| | {} |
| |
|
| | bool canRenderGLArray(SoGLRenderAction*) const; |
| | void generateGLArrays( |
| | SoGLRenderAction* action, |
| | SoMaterialBindingElement::Binding matbind, |
| | std::vector<float>& vertex, |
| | std::vector<int32_t>& index |
| | ); |
| | void renderFacesGLArray(SoGLRenderAction* action); |
| | void renderCoordsGLArray(SoGLRenderAction* action); |
| | void update() |
| | {} |
| | bool needUpdate(SoGLRenderAction*) |
| | { |
| | return false; |
| | } |
| | }; |
| |
|
| | bool MeshRenderer::Private::canRenderGLArray(SoGLRenderAction*) const |
| | { |
| | return true; |
| | } |
| |
|
| | void MeshRenderer::Private::generateGLArrays( |
| | SoGLRenderAction*, |
| | SoMaterialBindingElement::Binding matbind, |
| | std::vector<float>& vertex, |
| | std::vector<int32_t>& index |
| | ) |
| | { |
| | if (vertex.empty() || index.empty()) { |
| | return; |
| | } |
| |
|
| | this->index_array.resize(0); |
| | this->vertex_array.resize(0); |
| |
|
| | this->index_array.swap(index); |
| | this->vertex_array.swap(vertex); |
| | this->matbinding = matbind; |
| | } |
| |
|
| | void MeshRenderer::Private::renderFacesGLArray(SoGLRenderAction* action) |
| | { |
| | (void)action; |
| | int cnt = index_array.size(); |
| |
|
| | glEnableClientState(GL_NORMAL_ARRAY); |
| | glEnableClientState(GL_VERTEX_ARRAY); |
| |
|
| | if (matbinding != SoMaterialBindingElement::OVERALL) { |
| | glInterleavedArrays(GL_C4F_N3F_V3F, 0, &(vertex_array[0])); |
| | } |
| | else { |
| | glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0])); |
| | } |
| | glDrawElements(GL_TRIANGLES, cnt, GL_UNSIGNED_INT, &(index_array[0])); |
| |
|
| | glDisableClientState(GL_VERTEX_ARRAY); |
| | glDisableClientState(GL_NORMAL_ARRAY); |
| | } |
| |
|
| | void MeshRenderer::Private::renderCoordsGLArray(SoGLRenderAction*) |
| | { |
| | int cnt = index_array.size(); |
| |
|
| | glEnableClientState(GL_NORMAL_ARRAY); |
| | glEnableClientState(GL_VERTEX_ARRAY); |
| |
|
| | if (matbinding != SoMaterialBindingElement::OVERALL) { |
| | glInterleavedArrays(GL_C4F_N3F_V3F, 0, &(vertex_array[0])); |
| | } |
| | else { |
| | glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0])); |
| | } |
| | glDrawElements(GL_POINTS, cnt, GL_UNSIGNED_INT, &(index_array[0])); |
| |
|
| | glDisableClientState(GL_VERTEX_ARRAY); |
| | glDisableClientState(GL_NORMAL_ARRAY); |
| | } |
| | #else |
| | class MeshRenderer::Private |
| | { |
| | public: |
| | const SbColor* pcolors; |
| | SoMaterialBindingElement::Binding matbinding; |
| |
|
| | Private() |
| | : pcolors(0) |
| | , matbinding(SoMaterialBindingElement::OVERALL) |
| | {} |
| |
|
| | bool canRenderGLArray(SoGLRenderAction*) const |
| | { |
| | return false; |
| | } |
| | void generateGLArrays( |
| | SoGLRenderAction*, |
| | SoMaterialBindingElement::Binding, |
| | std::vector<float>&, |
| | std::vector<int32_t>& |
| | ) |
| | {} |
| | void renderFacesGLArray(SoGLRenderAction*) |
| | {} |
| | void renderCoordsGLArray(SoGLRenderAction*) |
| | {} |
| | void update() |
| | {} |
| | bool needUpdate(SoGLRenderAction*) |
| | { |
| | return false; |
| | } |
| | }; |
| | #endif |
| |
|
| | MeshRenderer::MeshRenderer() |
| | : p(new Private) |
| | {} |
| |
|
| | MeshRenderer::~MeshRenderer() |
| | { |
| | delete p; |
| | } |
| |
|
| | void MeshRenderer::update() |
| | { |
| | p->update(); |
| | } |
| |
|
| | bool MeshRenderer::needUpdate(SoGLRenderAction* action) |
| | { |
| | return p->needUpdate(action); |
| | } |
| |
|
| | void MeshRenderer::generateGLArrays( |
| | SoGLRenderAction* action, |
| | SoMaterialBindingElement::Binding matbind, |
| | std::vector<float>& vertex, |
| | std::vector<int32_t>& index |
| | ) |
| | { |
| | SoGLLazyElement* gl = SoGLLazyElement::getInstance(action->getState()); |
| | if (gl) { |
| | p->pcolors = gl->getDiffusePointer(); |
| | } |
| | p->generateGLArrays(action, matbind, vertex, index); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | void MeshRenderer::renderCoordsGLArray(SoGLRenderAction* action) |
| | { |
| | p->renderCoordsGLArray(action); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void MeshRenderer::renderFacesGLArray(SoGLRenderAction* action) |
| | { |
| | p->renderFacesGLArray(action); |
| | } |
| |
|
| | bool MeshRenderer::canRenderGLArray(SoGLRenderAction* action) const |
| | { |
| | return p->canRenderGLArray(action); |
| | } |
| |
|
| | bool MeshRenderer::matchMaterial(SoState* state) const |
| | { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | SoMaterialBindingElement::Binding matbind = SoMaterialBindingElement::get(state); |
| | if (p->matbinding != matbind) { |
| | return false; |
| | } |
| | |
| | if (matbind == SoMaterialBindingElement::OVERALL) { |
| | return true; |
| | } |
| | const SbColor* pcolors = nullptr; |
| | SoGLLazyElement* gl = SoGLLazyElement::getInstance(state); |
| | if (gl) { |
| | pcolors = gl->getDiffusePointer(); |
| | } |
| | return p->pcolors == pcolors; |
| | } |
| |
|
| | bool MeshRenderer::shouldRenderDirectly([[maybe_unused]] bool direct) |
| | { |
| | #ifdef RENDER_GL_VAO |
| | return false; |
| | #else |
| | return direct; |
| | #endif |
| | } |
| |
|
| | |
| |
|
| | SO_ENGINE_SOURCE(SoFCMaterialEngine) |
| |
|
| | SoFCMaterialEngine::SoFCMaterialEngine() |
| | { |
| | SO_ENGINE_CONSTRUCTOR(SoFCMaterialEngine); |
| |
|
| | SO_ENGINE_ADD_INPUT(diffuseColor, (SbColor(0.0, 0.0, 0.0))); |
| | SO_ENGINE_ADD_OUTPUT(trigger, SoSFBool); |
| | } |
| |
|
| | SoFCMaterialEngine::~SoFCMaterialEngine() = default; |
| |
|
| | void SoFCMaterialEngine::initClass() |
| | { |
| | SO_ENGINE_INIT_CLASS(SoFCMaterialEngine, SoEngine, "Engine"); |
| | } |
| |
|
| | void SoFCMaterialEngine::inputChanged(SoField*) |
| | { |
| | SO_ENGINE_OUTPUT(trigger, SoSFBool, setValue(true)); |
| | } |
| |
|
| | void SoFCMaterialEngine::evaluate() |
| | { |
| | |
| | } |
| |
|
| | |
| |
|
| | SO_NODE_SOURCE(SoFCIndexedFaceSet) |
| |
|
| | void SoFCIndexedFaceSet::initClass() |
| | { |
| | SO_NODE_INIT_CLASS(SoFCIndexedFaceSet, SoIndexedFaceSet, "IndexedFaceSet"); |
| | } |
| |
|
| | SoFCIndexedFaceSet::SoFCIndexedFaceSet() |
| | : renderTriangleLimit(std::numeric_limits<unsigned>::max()) |
| | { |
| | SO_NODE_CONSTRUCTOR(SoFCIndexedFaceSet); |
| | SO_NODE_ADD_FIELD(updateGLArray, (false)); |
| | updateGLArray.setFieldType(SoField::EVENTOUT_FIELD); |
| | setName(SoFCIndexedFaceSet::getClassTypeId().getName()); |
| | } |
| |
|
| | |
| | |
| | |
| | void SoFCIndexedFaceSet::GLRender(SoGLRenderAction* action) |
| | { |
| | if (this->coordIndex.getNum() < 3) { |
| | return; |
| | } |
| |
|
| | if (!this->shouldGLRender(action)) { |
| | |
| | |
| | |
| | |
| | |
| | SoMaterialBundle mb(action); |
| | mb.sendFirst(); |
| | return; |
| | } |
| |
|
| | #if defined(RENDER_GL_VAO) |
| | SoState* state = action->getState(); |
| |
|
| | |
| | SbBool useVBO = true; |
| | Gui::SoGLVBOActivatedElement::get(state, useVBO); |
| |
|
| | |
| | if (!render.canRenderGLArray(action)) { |
| | useVBO = false; |
| | } |
| |
|
| | |
| | if (useVBO) { |
| | if (updateGLArray.getValue()) { |
| | updateGLArray.setValue(false); |
| | render.update(); |
| | generateGLArrays(action); |
| | } |
| | else if (render.needUpdate(action)) { |
| | generateGLArrays(action); |
| | } |
| |
|
| | if (render.matchMaterial(state)) { |
| | SoMaterialBundle mb(action); |
| | mb.sendFirst(); |
| | render.renderFacesGLArray(action); |
| | } |
| | else { |
| | drawFaces(action); |
| | } |
| | } |
| | else { |
| | drawFaces(action); |
| | } |
| | #else |
| | drawFaces(action); |
| | #endif |
| | } |
| |
|
| | void SoFCIndexedFaceSet::drawFaces(SoGLRenderAction* action) |
| | { |
| | SoState* state = action->getState(); |
| | SbBool mode = Gui::SoFCInteractiveElement::get(state); |
| |
|
| | unsigned int num = this->coordIndex.getNum() / 4; |
| | if (!mode || num <= this->renderTriangleLimit) { |
| | #ifdef RENDER_GLARRAYS |
| | SoMaterialBindingElement::Binding matbind = SoMaterialBindingElement::get(state); |
| |
|
| | SbBool matchCtx = render.canRenderGLArray(action); |
| | if (matbind == SoMaterialBindingElement::OVERALL && matchCtx) { |
| | SoMaterialBundle mb(action); |
| | mb.sendFirst(); |
| | if (updateGLArray.getValue()) { |
| | updateGLArray.setValue(false); |
| | generateGLArrays(action); |
| | } |
| | render.renderFacesGLArray(action); |
| | } |
| | else { |
| | inherited::GLRender(action); |
| | } |
| | #else |
| | inherited::GLRender(action); |
| | #endif |
| | } |
| | else { |
| | #if 0 && defined(RENDER_GLARRAYS) |
| | SoMaterialBundle mb(action); |
| | mb.sendFirst(); |
| | render.renderCoordsGLArray(action); |
| | #else |
| | SoMaterialBindingElement::Binding matbind = SoMaterialBindingElement::get(state); |
| | int32_t binding = (int32_t)(matbind); |
| |
|
| | const SoCoordinateElement* coords = nullptr; |
| | const SbVec3f* normals = nullptr; |
| | const int32_t* cindices = nullptr; |
| | int numindices = 0; |
| | const int32_t* nindices = nullptr; |
| | const int32_t* tindices = nullptr; |
| | const int32_t* mindices = nullptr; |
| | SbBool normalCacheUsed {}; |
| |
|
| | SoMaterialBundle mb(action); |
| |
|
| | SoTextureCoordinateBundle tb(action, true, false); |
| | SbBool sendNormals = !mb.isColorOnly() || tb.isFunction(); |
| |
|
| | this->getVertexData( |
| | state, |
| | coords, |
| | normals, |
| | cindices, |
| | nindices, |
| | tindices, |
| | mindices, |
| | numindices, |
| | sendNormals, |
| | normalCacheUsed |
| | ); |
| |
|
| | mb.sendFirst(); |
| |
|
| | drawCoords( |
| | static_cast<const SoGLCoordinateElement*>(coords), |
| | cindices, |
| | numindices, |
| | normals, |
| | nindices, |
| | &mb, |
| | mindices, |
| | binding, |
| | &tb, |
| | tindices |
| | ); |
| |
|
| | |
| | |
| | |
| | if (normalCacheUsed) { |
| | this->readUnlockNormalCache(); |
| | } |
| |
|
| | |
| | SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE); |
| | #endif |
| | } |
| | } |
| |
|
| | void SoFCIndexedFaceSet::drawCoords( |
| | const SoGLCoordinateElement* const vertexlist, |
| | const int32_t* vertexindices, |
| | int numindices, |
| | const SbVec3f* normals, |
| | const int32_t* normalindices, |
| | SoMaterialBundle* materials, |
| | const int32_t* , |
| | const int32_t binding, |
| | const SoTextureCoordinateBundle* const , |
| | const int32_t* |
| | ) |
| | { |
| | const SbVec3f* coords3d = nullptr; |
| | coords3d = vertexlist->getArrayPtr3(); |
| |
|
| | int mod = numindices / (4 * this->renderTriangleLimit) + 1; |
| | float size = std::min<float>((float)mod, 3.0F); |
| | glPointSize(size); |
| |
|
| | SbBool per_face = false; |
| | SbBool per_vert = false; |
| | switch (binding) { |
| | case SoMaterialBindingElement::PER_FACE: |
| | per_face = true; |
| | break; |
| | case SoMaterialBindingElement::PER_VERTEX: |
| | per_vert = true; |
| | break; |
| | default: |
| | break; |
| | } |
| |
|
| | int ct = 0; |
| | const int32_t* viptr = vertexindices; |
| | int32_t v1 {}, v2 {}, v3 {}; |
| | SbVec3f dummynormal(0, 0, 1); |
| | const SbVec3f* currnormal = &dummynormal; |
| | if (normals) { |
| | currnormal = normals; |
| | } |
| |
|
| | glBegin(GL_POINTS); |
| | for (int index = 0; index < numindices; ct++) { |
| | if (ct % mod == 0) { |
| | if (per_face) { |
| | materials->send(ct, true); |
| | } |
| | v1 = *viptr++; |
| | index++; |
| | if (per_vert) { |
| | materials->send(v1, true); |
| | } |
| | if (normals) { |
| | currnormal = &normals[*normalindices++]; |
| | } |
| | glNormal3fv((const GLfloat*)currnormal); |
| | glVertex3fv((const GLfloat*)(coords3d + v1)); |
| |
|
| | v2 = *viptr++; |
| | index++; |
| | if (per_vert) { |
| | materials->send(v2, true); |
| | } |
| | if (normals) { |
| | currnormal = &normals[*normalindices++]; |
| | } |
| | glNormal3fv((const GLfloat*)currnormal); |
| | glVertex3fv((const GLfloat*)(coords3d + v2)); |
| |
|
| | v3 = *viptr++; |
| | index++; |
| | if (per_vert) { |
| | materials->send(v3, true); |
| | } |
| | if (normals) { |
| | currnormal = &normals[*normalindices++]; |
| | } |
| | glNormal3fv((const GLfloat*)currnormal); |
| | glVertex3fv((const GLfloat*)(coords3d + v3)); |
| | } |
| | else { |
| | viptr++; |
| | index++; |
| | normalindices++; |
| | viptr++; |
| | index++; |
| | normalindices++; |
| | viptr++; |
| | index++; |
| | normalindices++; |
| | } |
| |
|
| | viptr++; |
| | index++; |
| | normalindices++; |
| | } |
| | glEnd(); |
| | } |
| |
|
| | void SoFCIndexedFaceSet::invalidate() |
| | { |
| | updateGLArray.setValue(true); |
| | } |
| |
|
| | void SoFCIndexedFaceSet::generateGLArrays(SoGLRenderAction* action) |
| | { |
| | const SoCoordinateElement* coords = nullptr; |
| | const SbVec3f* normals = nullptr; |
| | const int32_t* cindices = nullptr; |
| | const SbColor* pcolors = nullptr; |
| | const float* transp = nullptr; |
| | int numindices = 0, numcolors = 0, numtransp = 0; |
| | const int32_t* nindices = nullptr; |
| | const int32_t* tindices = nullptr; |
| | const int32_t* mindices = nullptr; |
| | SbBool normalCacheUsed {}; |
| |
|
| | SbBool sendNormals = true; |
| |
|
| | SoState* state = action->getState(); |
| | this->getVertexData( |
| | state, |
| | coords, |
| | normals, |
| | cindices, |
| | nindices, |
| | tindices, |
| | mindices, |
| | numindices, |
| | sendNormals, |
| | normalCacheUsed |
| | ); |
| |
|
| | const SbVec3f* points = coords->getArrayPtr3(); |
| |
|
| | SoMaterialBindingElement::Binding matbind = SoMaterialBindingElement::get(state); |
| | SoGLLazyElement* gl = SoGLLazyElement::getInstance(state); |
| | if (gl) { |
| | pcolors = gl->getDiffusePointer(); |
| | numcolors = gl->getNumDiffuse(); |
| | transp = gl->getTransparencyPointer(); |
| | numtransp = gl->getNumTransparencies(); |
| | (void)numtransp; |
| | } |
| |
|
| | std::vector<float> face_vertices; |
| | std::vector<int32_t> face_indices; |
| |
|
| | std::size_t numTria = numindices / 4; |
| |
|
| | if (!mindices && matbind == SoMaterialBindingElement::PER_VERTEX_INDEXED) { |
| | mindices = cindices; |
| | } |
| |
|
| | SoNormalBindingElement::Binding normbind = SoNormalBindingElement::get(state); |
| | if (normbind == SoNormalBindingElement::PER_VERTEX_INDEXED) { |
| | if (matbind == SoMaterialBindingElement::PER_FACE) { |
| | face_vertices.reserve(3 * numTria * 10); |
| | face_indices.resize(3 * numTria); |
| |
|
| | if (numcolors != static_cast<int>(numTria)) { |
| | SoDebugError::postWarning( |
| | "SoFCIndexedFaceSet::generateGLArrays", |
| | "The number of faces (%d) does not match with the number of colors (%d).", |
| | numTria, |
| | numcolors |
| | ); |
| | } |
| |
|
| | |
| | int32_t vertex = 0; |
| | int index = 0; |
| | float t = transp ? transp[0] : 0; |
| | for (std::size_t i = 0; i < numTria; i++) { |
| | const SbColor& c = pcolors[i]; |
| | for (int j = 0; j < 3; j++) { |
| | face_vertices.push_back(c[0]); |
| | face_vertices.push_back(c[1]); |
| | face_vertices.push_back(c[2]); |
| | face_vertices.push_back(t); |
| |
|
| | const SbVec3f& n = normals[nindices[index]]; |
| | face_vertices.push_back(n[0]); |
| | face_vertices.push_back(n[1]); |
| | face_vertices.push_back(n[2]); |
| |
|
| | const SbVec3f& p = points[cindices[index]]; |
| | face_vertices.push_back(p[0]); |
| | face_vertices.push_back(p[1]); |
| | face_vertices.push_back(p[2]); |
| |
|
| | face_indices[vertex] = vertex; |
| | vertex++; |
| | index++; |
| | } |
| | index++; |
| | } |
| | } |
| | else if (matbind == SoMaterialBindingElement::PER_VERTEX_INDEXED) { |
| | face_vertices.reserve(3 * numTria * 10); |
| | face_indices.resize(3 * numTria); |
| |
|
| | if (numcolors != coords->getNum()) { |
| | SoDebugError::postWarning( |
| | "SoFCIndexedFaceSet::generateGLArrays", |
| | "The number of points (%d) does not match with the number of colors (%d).", |
| | coords->getNum(), |
| | numcolors |
| | ); |
| | } |
| |
|
| | |
| | int32_t vertex = 0; |
| | int index = 0; |
| | float t = transp ? transp[0] : 0; |
| | for (std::size_t i = 0; i < numTria; i++) { |
| | for (int j = 0; j < 3; j++) { |
| | const SbColor& c = pcolors[mindices[index]]; |
| | face_vertices.push_back(c[0]); |
| | face_vertices.push_back(c[1]); |
| | face_vertices.push_back(c[2]); |
| | face_vertices.push_back(t); |
| |
|
| | const SbVec3f& n = normals[nindices[index]]; |
| | face_vertices.push_back(n[0]); |
| | face_vertices.push_back(n[1]); |
| | face_vertices.push_back(n[2]); |
| |
|
| | const SbVec3f& p = points[cindices[index]]; |
| | face_vertices.push_back(p[0]); |
| | face_vertices.push_back(p[1]); |
| | face_vertices.push_back(p[2]); |
| |
|
| | face_indices[vertex] = vertex; |
| | vertex++; |
| | index++; |
| | } |
| | index++; |
| | } |
| | } |
| | else { |
| | |
| | matbind = SoMaterialBindingElement::OVERALL; |
| |
|
| | face_vertices.reserve(3 * numTria * 6); |
| | face_indices.resize(3 * numTria); |
| |
|
| | |
| | int32_t vertex = 0; |
| | int index = 0; |
| | for (std::size_t i = 0; i < numTria; i++) { |
| | for (int j = 0; j < 3; j++) { |
| | const SbVec3f& n = normals[nindices[index]]; |
| | face_vertices.push_back(n[0]); |
| | face_vertices.push_back(n[1]); |
| | face_vertices.push_back(n[2]); |
| |
|
| | const SbVec3f& p = points[cindices[index]]; |
| | face_vertices.push_back(p[0]); |
| | face_vertices.push_back(p[1]); |
| | face_vertices.push_back(p[2]); |
| |
|
| | face_indices[vertex] = vertex; |
| | vertex++; |
| | index++; |
| | } |
| | index++; |
| | } |
| | } |
| | } |
| | else if (normbind == SoNormalBindingElement::PER_VERTEX) { |
| | |
| | matbind = SoMaterialBindingElement::OVERALL; |
| |
|
| | std::size_t numPts = coords->getNum(); |
| | face_vertices.reserve(6 * numPts); |
| | for (std::size_t i = 0; i < numPts; i++) { |
| | const SbVec3f& n = normals[i]; |
| | face_vertices.push_back(n[0]); |
| | face_vertices.push_back(n[1]); |
| | face_vertices.push_back(n[2]); |
| |
|
| | const SbVec3f& p = coords->get3(i); |
| | face_vertices.push_back(p[0]); |
| | face_vertices.push_back(p[1]); |
| | face_vertices.push_back(p[2]); |
| | } |
| |
|
| | face_indices.reserve(3 * numTria); |
| |
|
| | int index = 0; |
| | for (std::size_t i = 0; i < numTria; i++) { |
| | for (int j = 0; j < 3; j++) { |
| | face_indices.push_back(cindices[index]); |
| | index++; |
| | } |
| | index++; |
| | } |
| | } |
| |
|
| | render.generateGLArrays(action, matbind, face_vertices, face_indices); |
| |
|
| | |
| | |
| | |
| | if (normalCacheUsed) { |
| | this->readUnlockNormalCache(); |
| | } |
| | } |
| |
|
| | void SoFCIndexedFaceSet::doAction(SoAction* action) |
| | { |
| | if (action->getTypeId() == Gui::SoGLSelectAction::getClassTypeId()) { |
| | SoNode* node = action->getNodeAppliedTo(); |
| | if (!node) { |
| | return; |
| | } |
| |
|
| | |
| | |
| | SoSearchAction sa; |
| | sa.setInterest(SoSearchAction::FIRST); |
| | sa.setSearchingAll(false); |
| | sa.setType(SoCoordinate3::getClassTypeId(), 1); |
| | sa.apply(node); |
| | SoPath* path = sa.getPath(); |
| | if (!path) { |
| | return; |
| | } |
| |
|
| | |
| | SoNode* coords = path->getNodeFromTail(0); |
| | if (!(coords && coords->getTypeId().isDerivedFrom(SoCoordinate3::getClassTypeId()))) { |
| | return; |
| | } |
| | startSelection(action); |
| | renderSelectionGeometry(static_cast<SoCoordinate3*>(coords)->point.getValues(0)); |
| | stopSelection(action); |
| | } |
| | else if (action->getTypeId() == Gui::SoVisibleFaceAction::getClassTypeId()) { |
| | SoNode* node = action->getNodeAppliedTo(); |
| | if (!node) { |
| | return; |
| | } |
| |
|
| | |
| | |
| | SoSearchAction sa; |
| | sa.setInterest(SoSearchAction::FIRST); |
| | sa.setSearchingAll(false); |
| | sa.setType(SoCoordinate3::getClassTypeId(), 1); |
| | sa.apply(node); |
| | SoPath* path = sa.getPath(); |
| | if (!path) { |
| | return; |
| | } |
| |
|
| | |
| | SoNode* coords = path->getNodeFromTail(0); |
| | if (!(coords && coords->getTypeId().isDerivedFrom(SoCoordinate3::getClassTypeId()))) { |
| | return; |
| | } |
| | startVisibility(action); |
| | renderVisibleFaces(static_cast<SoCoordinate3*>(coords)->point.getValues(0)); |
| | stopVisibility(action); |
| | } |
| |
|
| | inherited::doAction(action); |
| | } |
| |
|
| | void SoFCIndexedFaceSet::startSelection(SoAction* action) |
| | { |
| | Gui::SoGLSelectAction* doaction = static_cast<Gui::SoGLSelectAction*>(action); |
| | const SbViewportRegion& vp = doaction->getViewportRegion(); |
| | int x = vp.getViewportOriginPixels()[0]; |
| | int y = vp.getViewportOriginPixels()[1]; |
| | int w = vp.getViewportSizePixels()[0]; |
| | int h = vp.getViewportSizePixels()[1]; |
| |
|
| | int bufSize = 5 * (this->coordIndex.getNum() / 4); |
| | this->selectBuf = new GLuint[bufSize]; |
| |
|
| | SbMatrix view = SoViewingMatrixElement::get(action->getState()); |
| | SbMatrix proj = SoProjectionMatrixElement::get(action->getState()); |
| |
|
| | glSelectBuffer(bufSize, selectBuf); |
| | glRenderMode(GL_SELECT); |
| |
|
| | glInitNames(); |
| | glPushName(-1); |
| |
|
| | GLint viewport[4]; |
| | glGetIntegerv(GL_VIEWPORT, viewport); |
| | glMatrixMode(GL_PROJECTION); |
| |
|
| | glPushMatrix(); |
| | glLoadIdentity(); |
| |
|
| | if (w > 0 && h > 0) { |
| | glTranslatef( |
| | (viewport[2] - 2 * (x - viewport[0])) / w, |
| | (viewport[3] - 2 * (y - viewport[1])) / h, |
| | 0 |
| | ); |
| | glScalef(viewport[2] / w, viewport[3] / h, 1.0); |
| | } |
| | glMultMatrixf( (float*)proj); |
| | glMatrixMode(GL_MODELVIEW); |
| | glPushMatrix(); |
| | glLoadMatrixf((float*)view); |
| | } |
| |
|
| | void SoFCIndexedFaceSet::stopSelection(SoAction* action) |
| | { |
| | |
| | glPopMatrix(); |
| | glMatrixMode(GL_PROJECTION); |
| | glPopMatrix(); |
| | glMatrixMode(GL_MODELVIEW); |
| | glFlush(); |
| |
|
| | |
| | GLint hits = glRenderMode(GL_RENDER); |
| |
|
| | int bufSize = 5 * (this->coordIndex.getNum() / 4); |
| | std::vector<std::pair<double, unsigned int>> hit; |
| | GLint index = 0; |
| | for (GLint ii = 0; ii < hits && index < bufSize; ii++) { |
| | GLint ct = (GLint)selectBuf[index]; |
| | hit.emplace_back(selectBuf[index + 1] / 4294967295.0, selectBuf[index + 3]); |
| | index = index + ct + 3; |
| | } |
| |
|
| | delete[] selectBuf; |
| | selectBuf = nullptr; |
| | std::sort(hit.begin(), hit.end()); |
| |
|
| | Gui::SoGLSelectAction* doaction = static_cast<Gui::SoGLSelectAction*>(action); |
| | doaction->indices.reserve(hit.size()); |
| | for (GLint ii = 0; ii < hits; ii++) { |
| | doaction->indices.push_back(hit[ii].second); |
| | } |
| | } |
| |
|
| | void SoFCIndexedFaceSet::renderSelectionGeometry(const SbVec3f* coords3d) |
| | { |
| | int numfaces = this->coordIndex.getNum() / 4; |
| | const int32_t* cindices = this->coordIndex.getValues(0); |
| |
|
| | int fcnt = 0; |
| | int32_t v1 {}, v2 {}, v3 {}; |
| | for (int index = 0; index < numfaces; index++, cindices++) { |
| | glLoadName(fcnt); |
| | glBegin(GL_TRIANGLES); |
| | v1 = *cindices++; |
| | glVertex3fv((const GLfloat*)(coords3d + v1)); |
| | v2 = *cindices++; |
| | glVertex3fv((const GLfloat*)(coords3d + v2)); |
| | v3 = *cindices++; |
| | glVertex3fv((const GLfloat*)(coords3d + v3)); |
| | glEnd(); |
| | fcnt++; |
| | } |
| | } |
| |
|
| | void SoFCIndexedFaceSet::startVisibility(SoAction* action) |
| | { |
| | SbMatrix view = SoViewingMatrixElement::get(action->getState()); |
| | SbMatrix proj = SoProjectionMatrixElement::get(action->getState()); |
| |
|
| | glMatrixMode(GL_PROJECTION); |
| | glPushMatrix(); |
| | glLoadIdentity(); |
| | glMultMatrixf((float*)proj); |
| | glMatrixMode(GL_MODELVIEW); |
| | glPushMatrix(); |
| | glLoadMatrixf((float*)view); |
| | } |
| |
|
| | void SoFCIndexedFaceSet::stopVisibility(SoAction* ) |
| | { |
| | |
| | glPopMatrix(); |
| | glMatrixMode(GL_PROJECTION); |
| | glPopMatrix(); |
| | glMatrixMode(GL_MODELVIEW); |
| | glFlush(); |
| | } |
| |
|
| | void SoFCIndexedFaceSet::renderVisibleFaces(const SbVec3f* coords3d) |
| | { |
| | glDisable(GL_BLEND); |
| | glDisable(GL_DITHER); |
| | glDisable(GL_FOG); |
| | glDisable(GL_LIGHTING); |
| | glDisable(GL_TEXTURE_1D); |
| | glDisable(GL_TEXTURE_2D); |
| | glShadeModel(GL_FLAT); |
| |
|
| | uint32_t numfaces = this->coordIndex.getNum() / 4; |
| | const int32_t* cindices = this->coordIndex.getValues(0); |
| |
|
| | int32_t v1 {}, v2 {}, v3 {}; |
| | for (uint32_t index = 0; index < numfaces; index++, cindices++) { |
| | glBegin(GL_TRIANGLES); |
| | float t {}; |
| | SbColor c; |
| | c.setPackedValue(index << 8, t); |
| | glColor3f(c[0], c[1], c[2]); |
| | v1 = *cindices++; |
| | glVertex3fv((const GLfloat*)(coords3d + v1)); |
| | v2 = *cindices++; |
| | glVertex3fv((const GLfloat*)(coords3d + v2)); |
| | v3 = *cindices++; |
| | glVertex3fv((const GLfloat*)(coords3d + v3)); |
| | glEnd(); |
| | } |
| | } |
| |
|