/*===========================================================================*\
* *
* OpenFlipper *
* Copyright (C) 2001-2014 by Computer Graphics Group, RWTH Aachen *
* www.openflipper.org *
* *
*---------------------------------------------------------------------------*
* This file is part of OpenFlipper. *
* *
* OpenFlipper is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of *
* the License, or (at your option) any later version with the *
* following exceptions: *
* *
* If other files instantiate templates or use macros *
* or inline functions from this file, or you compile this file and *
* link it with other files to produce an executable, this file does *
* not by itself cause the resulting executable to be covered by the *
* GNU Lesser General Public License. This exception does not however *
* invalidate any other reasons why the executable file might be *
* covered by the GNU Lesser General Public License. *
* *
* OpenFlipper 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU LesserGeneral Public *
* License along with OpenFlipper. If not, *
* see . *
* *
\*===========================================================================*/
/*===========================================================================*\
* *
* $Revision$ *
* $Author$ *
* $Date$ *
* *
\*===========================================================================*/
//=============================================================================
//
// CLASS MeshNodeT - IMPLEMENTATION
//
//=============================================================================
#define ACG_MESHNODE_C
#include
#include
#include
//== NAMESPACES ===============================================================
namespace ACG {
namespace SceneGraph {
//== INCLUDES =================================================================
#include "MeshNode2T.hh"
template
MeshNodeT::
MeshNodeT(Mesh& _mesh,
BaseNode* _parent,
std::string _name ):
BaseNode(_parent, _name),
mesh_(_mesh),
drawMesh_(0),
enableNormals_(true),
enableColors_(true),
enabled_arrays_(0),
updateVertexPicking_(true),
vertexPickingBaseIndex_(0),
updateEdgePicking_(true),
edgePickingBaseIndex_(0),
updateFacePicking_(true),
facePickingBaseIndex_(0),
updateAnyPicking_(true),
anyPickingBaseIndex_(0),
perFaceTextureIndexAvailable_(false),
perFaceTextureCoordsAvailable_(false),
textureMap_(0),
polyEdgeBuf_(0),
polyEdgeBufSize_(0),
polyEdgeBufTex_(0)
{
/// \todo : Handle vbo not supported
if ( ! checkExtensionSupported("GL_ARB_vertex_buffer_object") ) {
std::cerr << "Error! Vertex buffer objects are not supported! The meshNode will not work without them!" << std::endl;
}
drawMesh_ = new DrawMeshT(mesh_);
}
template
MeshNodeT::
~MeshNodeT()
{
// Delete all allocated buffers
delete drawMesh_;
}
template
DrawModes::DrawMode
MeshNodeT::
availableDrawModes() const {
DrawModes::DrawMode drawModes(DrawModes::NONE);
// We can always render points and a wireframe.
drawModes |= DrawModes::POINTS;
drawModes |= DrawModes::HIDDENLINE;
drawModes |= DrawModes::WIREFRAME;
drawModes |= DrawModes::HALFEDGES;
if (mesh_.has_vertex_normals())
{
drawModes |= DrawModes::POINTS_SHADED;
drawModes |= DrawModes::SOLID_SMOOTH_SHADED;
drawModes |= DrawModes::SOLID_PHONG_SHADED;
}
if (mesh_.has_face_normals())
drawModes |= DrawModes::SOLID_FLAT_SHADED;
if (mesh_.has_halfedge_normals())
drawModes |= DrawModes::SOLID_SMOOTH_SHADED_FEATURES;
if (mesh_.has_vertex_colors())
{
drawModes |= DrawModes::POINTS_COLORED;
drawModes |= DrawModes::SOLID_POINTS_COLORED;
if (mesh_.has_vertex_normals())
drawModes |= DrawModes::SOLID_POINTS_COLORED_SHADED;
}
if(mesh_.has_edge_colors())
{
drawModes |= DrawModes::EDGES_COLORED;
}
if(mesh_.has_halfedge_colors())
{
drawModes |= DrawModes::HALFEDGES_COLORED;
}
if (mesh_.has_face_colors()) {
drawModes |= DrawModes::SOLID_FACES_COLORED;
if( mesh_.has_face_normals() )
drawModes |= DrawModes::SOLID_FACES_COLORED_FLAT_SHADED;
if( mesh().has_vertex_normals() )
drawModes |= DrawModes::SOLID_FACES_COLORED_SMOOTH_SHADED;
}
if ( mesh_.has_vertex_texcoords2D() ) {
drawModes |= DrawModes::SOLID_TEXTURED;
if (mesh_.has_vertex_normals())
drawModes |= DrawModes::SOLID_TEXTURED_SHADED;
}
if ( perFaceTextureCoordsAvailable_ ) {
drawModes |= DrawModes::SOLID_2DTEXTURED_FACE;
if (mesh_.has_face_normals())
drawModes |= DrawModes::SOLID_2DTEXTURED_FACE_SHADED;
}
return drawModes;
}
template
void
MeshNodeT::
boundingBox(Vec3d& _bbMin, Vec3d& _bbMax) {
_bbMin.minimize(bbMin_);
_bbMax.maximize(bbMax_);
}
template
void
MeshNodeT::
draw(GLState& _state, const DrawModes::DrawMode& _drawMode) {
/*
if ( ( _drawMode & DrawModes::SOLID_FLAT_SHADED ) ||
( _drawMode & DrawModes::SOLID_FACES_COLORED_FLAT_SHADED) ||
( _drawMode & DrawModes::SOLID_TEXTURED) ||
( _drawMode & DrawModes::SOLID_2DTEXTURED_FACE))
{
drawMesh_->setFlatShading();
}
else
drawMesh_->setSmoothShading();
if ( (_drawMode & DrawModes::SOLID_FACES_COLORED ||
_drawMode & DrawModes::SOLID_FACES_COLORED_FLAT_SHADED))
{
drawMesh_->usePerFaceColors();
}
else
drawMesh_->usePerVertexColors();
*/
GLenum prev_depth = _state.depthFunc();
glPushAttrib(GL_ENABLE_BIT);
/// get bound texture buffer and target
GLuint lastBuffer = ACG::GLState::getBoundTextureBuffer();
GLenum lastTarget = ACG::GLState::getBoundTextureTarget();
// Unbind to avoid painting textures on non textured primitives
ACG::GLState::bindTexture(lastTarget,0);
if ( (_drawMode & DrawModes::POINTS) || (_drawMode & DrawModes::POINTS_COLORED) || (_drawMode & DrawModes::POINTS_SHADED ) ) {
_state.set_color( _state.specular_color() );
ACG::GLState::shadeModel(GL_FLAT);
if ( _drawMode & DrawModes::POINTS_SHADED ) {
ACG::GLState::enable(GL_LIGHTING);
} else
ACG::GLState::disable(GL_LIGHTING);
// Use Colors in this mode if allowed
if ( enableColors_ && (_drawMode & DrawModes::POINTS_COLORED) )
{
drawMesh_->usePerVertexColors();
// If we have colors and lighting with normals, we have to use colormaterial
if ( enableNormals_ && (_drawMode & DrawModes::POINTS_SHADED ) )
ACG::GLState::enable(GL_COLOR_MATERIAL);
else
ACG::GLState::disable(GL_COLOR_MATERIAL);
}
else
drawMesh_->disableColors();
// Bring the arrays online
// enable_arrays(arrays);
// Draw vertices
draw_vertices();
}
/// \todo We can render also wireframe shaded and with vertex colors
if (_drawMode & DrawModes::WIREFRAME)
{
const Vec4f oldColor = _state.color();
// If the mode is atomic, we use the specular, otherwise we take the overlay color
if (_drawMode.isAtomic() )
_state.set_color( _state.specular_color() );
else
_state.set_color( _state.overlay_color() );
ACG::GLState::disable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_FLAT);
drawMesh_->disableColors();
draw_lines();
_state.set_color(oldColor);
}
if (_drawMode & DrawModes::HIDDENLINE)
{
// enable_arrays(VERTEX_ARRAY);
// First:
// Render all faces in background color to initialize z-buffer
ACG::GLState::disable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_FLAT);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// drawMesh_->SetFlatShading();
drawMesh_->disableColors();
Vec4f clear_color = _state.clear_color();
clear_color[3] = 1.0;
_state.set_color( clear_color );
ACG::GLState::depthRange(0.01, 1.0);
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
// Second
// Render the lines. All lines not on the front will be skipped in z-test
// enable_arrays(VERTEX_ARRAY|LINE_INDEX_ARRAY);
ACG::GLState::depthFunc(GL_LEQUAL);
_state.set_color( _state.specular_color() );
draw_lines();
//restore depth buffer comparison function for the next draw calls inside this function
ACG::GLState::depthFunc(prev_depth);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
if (_drawMode & DrawModes::EDGES_COLORED)
{
enable_arrays( PER_EDGE_VERTEX_ARRAY | PER_EDGE_COLOR_ARRAY );
ACG::GLState::disable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_FLAT);
draw_lines();
}
if (_drawMode & DrawModes::HALFEDGES)
{
_state.set_color( _state.specular_color() );
enable_arrays( PER_HALFEDGE_VERTEX_ARRAY);
ACG::GLState::disable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_FLAT);
draw_halfedges();
}
if (_drawMode & DrawModes::HALFEDGES_COLORED)
{
enable_arrays( PER_HALFEDGE_VERTEX_ARRAY | PER_HALFEDGE_COLOR_ARRAY );
ACG::GLState::disable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_FLAT);
draw_halfedges();
}
if ( ( _drawMode & DrawModes::SOLID_POINTS_COLORED ) && mesh_.has_vertex_colors() )
{
ACG::GLState::disable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_SMOOTH);
ACG::GLState::depthRange(0.01, 1.0);
drawMesh_->usePerVertexColors();
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
}
if ( ( _drawMode & DrawModes::SOLID_POINTS_COLORED_SHADED ) && mesh_.has_vertex_colors() && mesh_.has_vertex_normals() )
{
ACG::GLState::enable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_SMOOTH);
ACG::GLState::depthRange(0.01, 1.0);
if ( enableNormals_ ) {
ACG::GLState::enable(GL_COLOR_MATERIAL);
} else {
ACG::GLState::disable(GL_COLOR_MATERIAL);
}
drawMesh_->usePerVertexColors();
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
}
if ( ( _drawMode & DrawModes::SOLID_FLAT_SHADED ) && mesh_.has_face_normals() && mesh_.n_faces() > 0)
{
ACG::GLState::enable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_FLAT);
ACG::GLState::depthRange(0.01, 1.0);
drawMesh_->setFlatShading();
drawMesh_->disableColors();
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
}
if ( ( _drawMode & DrawModes::SOLID_SMOOTH_SHADED ) && mesh_.has_vertex_normals() )
{
ACG::GLState::enable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_SMOOTH);
ACG::GLState::depthRange(0.01, 1.0);
drawMesh_->usePerVertexNormals();
drawMesh_->setSmoothShading();
drawMesh_->disableColors();
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
}
if ( ( _drawMode & DrawModes::SOLID_PHONG_SHADED ) && mesh_.has_vertex_normals() )
{
///\todo Integrate shader here!
// if ( parent() != 0 ) {
// if ( parent()->className() == "ShaderNode" ) {
//
// ShaderNode* node = dynamic_cast< ShaderNode* > ( parent() );
//
// GLSL::PtrProgram program = node->getShader( DrawModes::SOLID_PHONG_SHADED );
//
// // Enable own Phong shader
// program->use();
// enable_arrays(VERTEX_ARRAY | NORMAL_VERTEX_ARRAY );
ACG::GLState::disable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_SMOOTH);
ACG::GLState::depthRange(0.01, 1.0);
drawMesh_->usePerVertexNormals();
drawMesh_->setSmoothShading();
drawMesh_->disableColors();
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
//disable own Phong shader
// program->disable();
// }
// }
}
if ( ( _drawMode & DrawModes::SOLID_FACES_COLORED ) && mesh_.has_face_colors() && mesh_.n_faces() > 0)
{
Vec4f base_color_backup = _state.base_color();
ACG::GLState::disable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_FLAT);
ACG::GLState::depthRange(0.01, 1.0);
// enable_arrays(PER_FACE_VERTEX_ARRAY | PER_FACE_COLOR_ARRAY);
drawMesh_->usePerFaceColors();
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
_state.set_base_color(base_color_backup);
}
if ( ( _drawMode & DrawModes::SOLID_SMOOTH_SHADED_FEATURES ) && mesh_.has_halfedge_normals() && mesh_.n_faces() > 0)
{
ACG::GLState::enable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_SMOOTH);
ACG::GLState::depthRange(0.01, 1.0);
drawMesh_->disableColors();
drawMesh_->setSmoothShading();
drawMesh_->usePerHalfedgeNormals();
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
}
if ( ( _drawMode & DrawModes::SOLID_FACES_COLORED_FLAT_SHADED ) && mesh_.has_face_colors() && mesh_.has_face_normals() && mesh_.n_faces() > 0 )
{
Vec4f base_color_backup = _state.base_color();
ACG::GLState::enable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_FLAT);
ACG::GLState::depthRange(0.01, 1.0);
// enable_arrays(PER_FACE_VERTEX_ARRAY | PER_FACE_COLOR_ARRAY | PER_FACE_NORMAL_ARRAY );
drawMesh_->setFlatShading();
drawMesh_->usePerFaceColors();
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
_state.set_base_color(base_color_backup);
}
if ( ( _drawMode & DrawModes::SOLID_FACES_COLORED_SMOOTH_SHADED ) && mesh_.has_face_colors() && mesh_.has_vertex_normals() && mesh_.n_faces() > 0)
{
Vec4f base_color_backup = _state.base_color();
ACG::GLState::enable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_SMOOTH);
ACG::GLState::depthRange(0.01, 1.0);
drawMesh_->setSmoothShading();
drawMesh_->usePerVertexNormals();
drawMesh_->usePerFaceColors();
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
_state.set_base_color(base_color_backup);
}
// Rebind the previous texture
ACG::GLState::bindTexture(lastTarget,lastBuffer);
if ( ( _drawMode & DrawModes::SOLID_TEXTURED ) && mesh_.has_vertex_texcoords2D())
{
///\todo enableTexCoords_
// enable_arrays(VERTEX_ARRAY | TEXCOORD_VERTEX_ARRAY );
ACG::GLState::enable(GL_TEXTURE_2D);
ACG::GLState::disable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_FLAT);
ACG::GLState::depthRange(0.01, 1.0);
drawMesh_->disableColors();
drawMesh_->usePerVertexTexcoords();
// texture environment: fragment color = texture sample
GLint prevTexEnvMode = 0;
glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &prevTexEnvMode);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
ACG::GLState::disable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, prevTexEnvMode);
}
if ( ( _drawMode & DrawModes::SOLID_TEXTURED_SHADED ) && mesh_.has_vertex_texcoords2D() && mesh_.has_vertex_normals())
{
// enable_arrays(VERTEX_ARRAY | NORMAL_VERTEX_ARRAY | TEXCOORD_VERTEX_ARRAY);
ACG::GLState::enable(GL_TEXTURE_2D);
ACG::GLState::enable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_SMOOTH);
ACG::GLState::depthRange(0.01, 1.0);
drawMesh_->setSmoothShading();
drawMesh_->disableColors();
drawMesh_->usePerVertexTexcoords();
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
ACG::GLState::disable(GL_TEXTURE_2D);
}
// Textured by using coordinates stored in halfedges ... arrays generated by stripprocessor
if ( (_drawMode & DrawModes::SOLID_2DTEXTURED_FACE) && mesh_.n_faces() > 0 )
{
ACG::GLState::enable(GL_TEXTURE_2D);
// enable_arrays( PER_FACE_VERTEX_ARRAY | PER_FACE_TEXCOORD_ARRAY );
ACG::GLState::disable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_FLAT);
ACG::GLState::depthRange(0.01, 1.0);
drawMesh_->disableColors();
drawMesh_->usePerHalfedgeTexcoords();
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
ACG::GLState::disable(GL_TEXTURE_2D);
}
// Textured by using coordinates stored in halfedges
if ( ( _drawMode & DrawModes::SOLID_2DTEXTURED_FACE_SHADED ) && mesh_.has_face_normals() && mesh_.n_faces() > 0)
{
ACG::GLState::enable(GL_TEXTURE_2D);
// enable_arrays( PER_FACE_VERTEX_ARRAY | PER_FACE_TEXCOORD_ARRAY | PER_FACE_PER_VERTEX_NORMAL_ARRAY );
ACG::GLState::enable(GL_LIGHTING);
ACG::GLState::shadeModel(GL_FLAT);
ACG::GLState::depthRange(0.01, 1.0);
drawMesh_->setFlatShading();
drawMesh_->disableColors();
drawMesh_->usePerHalfedgeTexcoords();
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
ACG::GLState::disable(GL_TEXTURE_2D);
}
enable_arrays(0);
// Unbind all remaining buffers
ACG::GLState::bindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB , 0 );
glPopAttrib();
}
template
void ACG::SceneGraph::MeshNodeT::getRenderObjects( IRenderer* _renderer, GLState& _state, const DrawModes::DrawMode& _drawMode, const Material* _mat )
{
RenderObject ro;
ro.debugName = "MeshNode";
// shader gen setup (lighting, shademode, vertex-colors..)
for (unsigned int i = 0; i < _drawMode.getNumLayers(); ++i)
{
const DrawModes::DrawModeProperties* props = _drawMode.getLayer(i);
// reset renderobject
ro.initFromState(&_state);
ro.priority = 0;
ro.depthRange = Vec2f(0.0f, 1.0f);
ro.depthTest = true; // some previous node disabled depth testing
ro.depthWrite = true;
ro.depthFunc = GL_LESS;
ro.setMaterial(_mat);
ro.shaderDesc.vertexTemplateFile = ""; //QString(props->vertexShader().c_str());
ro.shaderDesc.geometryTemplateFile = ""; //QString(props->geometryShader().c_str());
ro.shaderDesc.fragmentTemplateFile = ""; //QString(props->fragmentShader().c_str());
// ------------------------
// 1. setup drawMesh based on property source
if (props->flatShaded())
drawMesh_->setFlatShading();
else
drawMesh_->setSmoothShading();
ro.shaderDesc.vertexColors = true;
switch (props->colorSource())
{
case DrawModes::COLOR_PER_VERTEX: drawMesh_->usePerVertexColors(); break;
case DrawModes::COLOR_PER_FACE: drawMesh_->usePerFaceColors(); break;
default:
{
drawMesh_->disableColors();
ro.shaderDesc.vertexColors = false;
} break;
}
switch (props->normalSource())
{
case DrawModes::NORMAL_PER_VERTEX: drawMesh_->usePerVertexNormals(); break;
case DrawModes::NORMAL_PER_HALFEDGE: drawMesh_->usePerHalfedgeNormals(); break;
default: break;
}
ro.shaderDesc.addTextureType(GL_TEXTURE_2D,false,0);
switch (props->texcoordSource())
{
case DrawModes::TEXCOORD_PER_VERTEX: drawMesh_->usePerVertexTexcoords(); break;
case DrawModes::TEXCOORD_PER_HALFEDGE: drawMesh_->usePerHalfedgeTexcoords(); break;
default:
{
ro.shaderDesc.clearTextures();
}break;
}
// ------------------------
// 2. prepare renderobject
// enable / disable lighting
ro.shaderDesc.numLights = props->lighting() ? 0 : -1;
// TODO: better handling of attribute sources in shader gen
switch (props->lightStage())
{
case DrawModes::LIGHTSTAGE_SMOOTH:
ro.shaderDesc.shadeMode = SG_SHADE_GOURAUD;
break;
case DrawModes::LIGHTSTAGE_PHONG:
ro.shaderDesc.shadeMode = SG_SHADE_PHONG;
break;
case DrawModes::LIGHTSTAGE_UNLIT:
ro.shaderDesc.shadeMode = SG_SHADE_UNLIT;
break;
}
if (props->flatShaded())
ro.shaderDesc.shadeMode = SG_SHADE_FLAT;
// handle 'special' primitives (wireframe, hiddenline, primitives in sysmem buffers)..
if (props->primitive() == DrawModes::PRIMITIVE_WIREFRAME)
{
ro.shaderDesc.shadeMode = SG_SHADE_UNLIT;
drawMesh_->disableColors();
// use specular color for lines
if (_drawMode.isAtomic() )
ro.emissive = ro.specular;
else
ro.emissive = OpenMesh::color_cast(_state.overlay_color());
// allow wireframe + solid mode
ro.depthFunc = GL_LEQUAL;
// use alpha blending for anti-aliasing in combined wireframe + solid mode
ro.blending = true;
ro.blendSrc = GL_SRC_ALPHA;
ro.blendDest = GL_ONE_MINUS_SRC_ALPHA;
// use geometry shaders to simulate line width
QString geomTemplate = ShaderProgGenerator::getShaderDir();
geomTemplate += "Wireframe/geometry_wire.tpl";
QString fragTemplate = ShaderProgGenerator::getShaderDir();
fragTemplate += "Wireframe/fragment_wire.tpl";
#ifdef GL_ARB_texture_buffer_object
if (!mesh_.is_trimesh())
{
// use modified shader for npoly meshes
// the shader can identify non-face edges with the poly edge buffer
updatePolyEdgeBuf();
if (polyEdgeBufTex_)
{
geomTemplate = ShaderProgGenerator::getShaderDir();
geomTemplate += "Wireframe/geometry_npoly_wire.tpl";
fragTemplate = ShaderProgGenerator::getShaderDir();
fragTemplate += "Wireframe/fragment_npoly_wire.tpl";
RenderObject::Texture roTex;
roTex.id = polyEdgeBufTex_;
roTex.type = GL_TEXTURE_BUFFER;
// bind poly edge buffer to texture stage 2
ro.setUniform("polyEdgeBuffer", 2);
ro.addTexture(roTex, 2, false);
}
}
#endif
ro.shaderDesc.geometryTemplateFile = geomTemplate;
ro.shaderDesc.fragmentTemplateFile = fragTemplate;
ro.setUniform("screenSize", Vec2f((float)_state.viewport_width(), (float)_state.viewport_height()));
ro.setUniform("lineWidth", _state.line_width());
add_face_RenderObjects(_renderer, &ro);
}
if (props->primitive() == DrawModes::PRIMITIVE_HIDDENLINE)
{
ro.shaderDesc.shadeMode = SG_SHADE_UNLIT;
drawMesh_->disableColors();
// use specular color for lines
if (_drawMode.isAtomic() )
ro.emissive = ro.specular;
else
ro.emissive = OpenMesh::color_cast(_state.overlay_color());
// use shaders to simulate line width
QString geomTemplate = ShaderProgGenerator::getShaderDir();
geomTemplate += "Wireframe/geometry_hidden.tpl";
QString fragTemplate = ShaderProgGenerator::getShaderDir();
fragTemplate += "Wireframe/fragment_hidden.tpl";
#ifdef GL_ARB_texture_buffer_object
if (!mesh_.is_trimesh())
{
// use modified shader for npoly meshes
// the shader can identify non-face edges with the poly edge buffer
updatePolyEdgeBuf();
if (polyEdgeBufTex_)
{
geomTemplate = ShaderProgGenerator::getShaderDir();
geomTemplate += "Wireframe/geometry_npoly_hidden.tpl";
fragTemplate = ShaderProgGenerator::getShaderDir();
fragTemplate += "Wireframe/fragment_npoly_hidden.tpl";
RenderObject::Texture roTex;
roTex.id = polyEdgeBufTex_;
roTex.type = GL_TEXTURE_BUFFER;
// bind poly edge buffer to texture stage 2
ro.setUniform("polyEdgeBuffer", 2);
ro.addTexture(roTex, 2, false);
}
}
#endif
ro.shaderDesc.geometryTemplateFile = geomTemplate;
ro.shaderDesc.fragmentTemplateFile = fragTemplate;
ro.setUniform("screenSize", Vec2f((float)_state.viewport_width(), (float)_state.viewport_height()));
ro.setUniform("lineWidth", _state.line_width());
ro.setUniform("bkColor", _state.clear_color());
add_face_RenderObjects(_renderer, &ro);
}
if (props->colored() && props->primitive() == DrawModes::PRIMITIVE_EDGE)
{
ro.shaderDesc.shadeMode = SG_SHADE_UNLIT;
ro.shaderDesc.vertexColors = true;
// note: colored edges are in sysmem, so they are directly bound to the VertexDeclaration
ro.vertexDecl = drawMesh_->getEdgeColoredVertexDeclaration();
ro.glDrawArrays(GL_LINES, 0, int(mesh_.n_edges() * 2));
// use specular color for lines
ro.emissive = ro.specular;
// use shaders to simulate line width
QString geomTemplate = ShaderProgGenerator::getShaderDir();
geomTemplate += "Wireframe/geom_line2quad.tpl";
ro.shaderDesc.geometryTemplateFile = geomTemplate;
ro.setUniform("screenSize", Vec2f((float)_state.viewport_width(), (float)_state.viewport_height()));
ro.setUniform("lineWidth", _state.line_width());
_renderer->addRenderObject(&ro);
// skip other edge primitives for this drawmode layer
continue;
}
if (props->primitive() == DrawModes::PRIMITIVE_HALFEDGE)
{
ro.shaderDesc.shadeMode = SG_SHADE_UNLIT;
// buffers in system memory
if (props->colored())
ro.vertexDecl = drawMesh_->getHalfedgeVertexDeclaration();
else
ro.vertexDecl = drawMesh_->getHalfedgeColoredVertexDeclaration();
// use specular color for lines
ro.emissive = ro.specular;
ro.glDrawArrays(GL_LINES, 0, int(mesh_.n_halfedges() * 2));
// use shaders to simulate line width
QString geomTemplate = ShaderProgGenerator::getShaderDir();
geomTemplate += "Wireframe/geom_line2quad.tpl";
ro.shaderDesc.geometryTemplateFile = geomTemplate;
ro.setUniform("screenSize", Vec2f((float)_state.viewport_width(), (float)_state.viewport_height()));
ro.setUniform("lineWidth", _state.line_width());
_renderer->addRenderObject(&ro);
}
// -----------------------------------------------------
// take care of all the other primitives
ro.depthRange = Vec2f(0.01f, 1.0f);
switch (props->primitive())
{
case DrawModes::PRIMITIVE_POINT:
{
if (ro.shaderDesc.shadeMode == SG_SHADE_UNLIT)
{
// use specular color for points
if (_drawMode.isAtomic() )
ro.emissive = ro.specular;
else
ro.emissive = OpenMesh::color_cast(_state.overlay_color());
}
// use shaders to simulate line width
QString geomTemplate = ShaderProgGenerator::getShaderDir();
geomTemplate += "PointSize/geometry.tpl";
QString fragTemplate = ShaderProgGenerator::getShaderDir();
fragTemplate += "PointSize/fragment.tpl";
ro.shaderDesc.geometryTemplateFile = geomTemplate;
ro.shaderDesc.fragmentTemplateFile = fragTemplate;
ro.setUniform("screenSize", Vec2f((float)_state.viewport_width(), (float)_state.viewport_height()));
ro.setUniform("pointSize", _mat->pointSize());
add_point_RenderObjects(_renderer, &ro);
} break;
case DrawModes::PRIMITIVE_EDGE:
{
// use specular color for lines
ro.emissive = ro.specular;
// use shaders to simulate line width
QString geomTemplate = ShaderProgGenerator::getShaderDir();
geomTemplate += "Wireframe/geom_line2quad.tpl";
ro.shaderDesc.geometryTemplateFile = geomTemplate;
ro.setUniform("screenSize", Vec2f((float)_state.viewport_width(), (float)_state.viewport_height()));
ro.setUniform("lineWidth", _state.line_width());
add_line_RenderObjects(_renderer, &ro);
} break;
case DrawModes::PRIMITIVE_POLYGON: add_face_RenderObjects(_renderer, &ro); break;
default: break;
}
}
}
template
void
MeshNodeT::
add_point_RenderObjects(IRenderer* _renderer, const RenderObject* _baseObj) {
drawMesh_->addPointRenderObjects(_renderer, _baseObj);
}
template
void
MeshNodeT::
draw_vertices() {
drawMesh_->drawVertices();
}
template
void
MeshNodeT::
draw_lines() {
if ((enabled_arrays_ & PER_EDGE_COLOR_ARRAY) && (enabled_arrays_ & PER_EDGE_VERTEX_ARRAY))
{
// colored edges still slow
glDrawArrays(GL_LINES, 0, int(mesh_.n_edges() * 2));
}
else
drawMesh_->drawLines();
}
template
void
MeshNodeT::
add_line_RenderObjects(IRenderer* _renderer, const RenderObject* _baseObj) {
if ((enabled_arrays_ & PER_EDGE_COLOR_ARRAY) && (enabled_arrays_ & PER_EDGE_VERTEX_ARRAY))
{
// colored edges still slow
glDrawArrays(GL_LINES, 0, int(mesh_.n_edges() * 2));
}
else
drawMesh_->addLineRenderObjects(_renderer, _baseObj);
}
template
void
MeshNodeT::
draw_halfedges() {
// If we are rendering per edge per vertex attributes, we need to use a seperated vertex buffer!
if ( enabled_arrays_ & PER_HALFEDGE_VERTEX_ARRAY )
glDrawArrays(GL_LINES, 0, int(mesh_.n_halfedges() * 2));
// Something went wrong here!
else
std::cerr << "Unable to Draw! halfedge array configuration is invalid!!" << std::endl;
}
template
void
MeshNodeT::
draw_faces() {
drawMesh_->draw(textureMap_);
}
template
void
MeshNodeT::
add_face_RenderObjects(IRenderer* _renderer, const RenderObject* _baseObj) {
drawMesh_->addTriRenderObjects(_renderer, _baseObj, textureMap_);
}
template
void
MeshNodeT::
enable_arrays(unsigned int _arrays) {
// Unbind everything to ensure sane settings
ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
ACG::GLState::bindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
//===================================================================
// per Edge Vertex Array
//===================================================================
// Check if we should enable the per face vertex array
if (_arrays & PER_EDGE_VERTEX_ARRAY) {
// Check if its already enabled
if (!(enabled_arrays_ & PER_EDGE_VERTEX_ARRAY)) {
enabled_arrays_ |= PER_EDGE_VERTEX_ARRAY;
// For this version we load the colors directly not from vbo
ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
ACG::GLState::vertexPointer( drawMesh_->perEdgeVertexBuffer() );
ACG::GLState::enableClientState(GL_VERTEX_ARRAY);
}
} else if (enabled_arrays_ & PER_EDGE_VERTEX_ARRAY) {
// Disable Vertex array
enabled_arrays_ &= ~PER_EDGE_VERTEX_ARRAY;
ACG::GLState::disableClientState(GL_VERTEX_ARRAY);
}
//===================================================================
// per Edge Color Array
//===================================================================
// Check if we should enable the per face vertex array
if ( mesh_.has_edge_colors() && ( _arrays & PER_EDGE_COLOR_ARRAY) ) {
// Check if its already enabled
if (!(enabled_arrays_ & PER_EDGE_COLOR_ARRAY)) {
enabled_arrays_ |= PER_EDGE_COLOR_ARRAY;
// For this version we load the colors directly not from vbo
ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
ACG::GLState::colorPointer( drawMesh_->perEdgeColorBuffer() );
ACG::GLState::enableClientState(GL_COLOR_ARRAY);
}
} else if (enabled_arrays_ & PER_EDGE_COLOR_ARRAY) {
// Disable Vertex array
enabled_arrays_ &= ~PER_EDGE_COLOR_ARRAY;
ACG::GLState::disableClientState(GL_COLOR_ARRAY);
}
//===================================================================
// per Halfedge Vertex Array
//===================================================================
// Check if we should enable the per face vertex array
if (_arrays & PER_HALFEDGE_VERTEX_ARRAY) {
// Check if its already enabled
if (!(enabled_arrays_ & PER_HALFEDGE_VERTEX_ARRAY)) {
enabled_arrays_ |= PER_HALFEDGE_VERTEX_ARRAY;
// For this version we load the colors directly not from vbo
ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
ACG::GLState::vertexPointer( drawMesh_->perHalfedgeVertexBuffer() );
ACG::GLState::enableClientState(GL_VERTEX_ARRAY);
}
} else if (enabled_arrays_ & PER_HALFEDGE_VERTEX_ARRAY) {
// Disable Vertex array
enabled_arrays_ &= ~PER_HALFEDGE_VERTEX_ARRAY;
ACG::GLState::disableClientState(GL_VERTEX_ARRAY);
}
//===================================================================
// per Halfedge Color Array
//===================================================================
// Check if we should enable the per face vertex array
if ( mesh_.has_halfedge_colors() && ( _arrays & PER_HALFEDGE_COLOR_ARRAY) ) {
// Check if its already enabled
if (!(enabled_arrays_ & PER_HALFEDGE_COLOR_ARRAY)) {
enabled_arrays_ |= PER_HALFEDGE_COLOR_ARRAY;
// For this version we load the colors directly not from vbo
ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
ACG::GLState::colorPointer( drawMesh_->perHalfedgeColorBuffer() );
ACG::GLState::enableClientState(GL_COLOR_ARRAY);
}
} else if (enabled_arrays_ & PER_HALFEDGE_COLOR_ARRAY) {
// Disable Vertex array
enabled_arrays_ &= ~PER_HALFEDGE_COLOR_ARRAY;
ACG::GLState::disableClientState(GL_COLOR_ARRAY);
}
//===================================================================
// Check for OpenGL Errors
//===================================================================
glCheckErrors();
}
template
void
MeshNodeT::
pick(GLState& _state, PickTarget _target) {
switch (_target)
{
case PICK_VERTEX:
{
pick_vertices(_state);
break;
}
case PICK_FRONT_VERTEX:
{
pick_vertices(_state, true);
break;
}
case PICK_ANYTHING:
{
pick_any(_state);
break;
}
case PICK_FACE:
{
pick_faces(_state);
break;
}
case PICK_EDGE:
{
pick_edges(_state);
break;
}
case PICK_FRONT_EDGE:
{
pick_edges(_state, true);
break;
}
default:
break;
}
}
template
void
MeshNodeT::
pick_vertices(GLState& _state, bool _front)
{
GLenum prev_depth = _state.depthFunc();
typename Mesh::ConstVertexIter v_it(mesh_.vertices_begin()),
v_end(mesh_.vertices_end());
if (!_state.pick_set_maximum (static_cast(mesh_.n_vertices()))) {
omerr() << "MeshNode::pick_vertices: color range too small, " << "picking failed\n";
return;
}
if ( mesh_.n_vertices() == 0 ) {
std::cerr << "pick_vertices: No vertices in Mesh!" << std::endl;
return;
}
if (_front && ( mesh_.n_faces() != 0 ) ) {
Vec4f clear_color = _state.clear_color();
Vec4f base_color = _state.base_color();
clear_color[3] = 1.0;
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glColor(clear_color);
ACG::GLState::depthRange(0.01, 1.0);
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
ACG::GLState::depthFunc(GL_LEQUAL);
glColor(base_color);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
if (_state.color_picking () ) {
if ( updateVertexPicking_ || _state.pick_current_index () != vertexPickingBaseIndex_) {
drawMesh_->updatePickingVertices(_state);
vertexPickingBaseIndex_ = _state.pick_current_index ();
updateVertexPicking_ = false;
}
if (drawMesh_) {
// For this version we load the colors directly not from vbo
ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
ACG::GLState::colorPointer( drawMesh_->pickVertexColorBuffer() );
ACG::GLState::enableClientState(GL_COLOR_ARRAY);
// vertex positions
ACG::GLState::vertexPointer( drawMesh_->pickVertexBuffer() );
ACG::GLState::enableClientState(GL_VERTEX_ARRAY);
// Draw color picking
glDrawArrays(GL_POINTS, 0, int(mesh_.n_vertices()));
// Disable color array
ACG::GLState::disableClientState(GL_COLOR_ARRAY);
// disable vertex array
ACG::GLState::disableClientState(GL_VERTEX_ARRAY);
} else {
std::cerr << "pick_vertices: No vertices in Mesh!" << std::endl;
}
} else {
std::cerr << "No fallback pick_vertices!" << std::endl;
}
ACG::GLState::depthFunc(prev_depth);
}
template
void
MeshNodeT::
pick_edges(GLState& _state, bool _front)
{
GLenum prev_depth = _state.depthFunc();
if (!_state.pick_set_maximum (static_cast(mesh_.n_edges()))) {
omerr() << "MeshNode::pick_edges: color range too small, " << "picking failed\n";
return;
}
if ( mesh_.n_vertices() == 0 ) {
std::cerr << "pick_edges: No vertices in Mesh!" << std::endl;
return;
}
if ( _front && ( mesh_.n_faces() != 0 ) ) {
Vec4f clear_color = _state.clear_color();
Vec4f base_color = _state.base_color();
clear_color[3] = 1.0;
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glColor(clear_color);
ACG::GLState::depthRange(0.01, 1.0);
draw_faces();
ACG::GLState::depthRange(0.0, 1.0);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
ACG::GLState::depthFunc(GL_LEQUAL);
glColor(base_color);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// disable all other arrays
enable_arrays(0);
}
if (_state.color_picking () ) {
if ( updateEdgePicking_ || _state.pick_current_index () != edgePickingBaseIndex_) {
drawMesh_->updatePickingEdges(_state);
edgePickingBaseIndex_ = _state.pick_current_index ();
updateEdgePicking_ = false;
}
if ( mesh_.n_edges() != 0 && drawMesh_) {
// For this version we load the colors directly not from vbo
ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
ACG::GLState::enableClientState(GL_VERTEX_ARRAY);
ACG::GLState::enableClientState(GL_COLOR_ARRAY);
ACG::GLState::vertexPointer(drawMesh_->perEdgeVertexBuffer());
ACG::GLState::colorPointer(drawMesh_->pickEdgeColorBuffer());
glDrawArrays(GL_LINES, 0, int(mesh_.n_edges() * 2));
ACG::GLState::disableClientState(GL_COLOR_ARRAY);
ACG::GLState::disableClientState(GL_VERTEX_ARRAY);
// disable all other arrays
enable_arrays(0);
}
} else {
std::cerr << "No fallback pick_edges!" << std::endl;
}
ACG::GLState::depthFunc(prev_depth);
}
template
void
MeshNodeT::
pick_faces(GLState& _state)
{
typename Mesh::ConstFaceIter f_it(mesh_.faces_sbegin()),
f_end(mesh_.faces_end());
typename Mesh::ConstFaceVertexIter fv_it;
if ( mesh_.n_vertices() == 0 ) {
std::cerr << "pick_faces: No vertices in Mesh!" << std::endl;
return;
}
if ( mesh_.n_faces() > 0 ) {
if (!_state.pick_set_maximum (static_cast(mesh_.n_faces()))) {
omerr() << "MeshNode::pick_faces: color range too small, " << "picking failed\n";
return;
}
} else {
if (!_state.pick_set_maximum (1)) {
omerr() << "Strange pickSetMAximum failed for index 1 in MeshNode\n";
return;
}
}
if (_state.color_picking ()) {
if ( updateFacePicking_ || _state.pick_current_index () != facePickingBaseIndex_) {
drawMesh_->updatePickingFaces(_state);
facePickingBaseIndex_ = _state.pick_current_index ();
updateFacePicking_ = false;
}
if ( mesh_.n_faces() != 0 ) {
// For this version we load the colors directly not from vbo
ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
ACG::GLState::enableClientState(GL_VERTEX_ARRAY);
ACG::GLState::enableClientState(GL_COLOR_ARRAY);
ACG::GLState::vertexPointer(drawMesh_->pickFaceVertexBuffer());
ACG::GLState::colorPointer(drawMesh_->pickFaceColorBuffer());
glDrawArrays(GL_TRIANGLES, 0, int(3 * drawMesh_->getNumTris()));
ACG::GLState::disableClientState(GL_COLOR_ARRAY);
ACG::GLState::disableClientState(GL_VERTEX_ARRAY);
// disable all other arrays
enable_arrays(0);
}
} else
std::cerr << "No fallback pick_faces!" << std::endl;
}
template
void
MeshNodeT::
pick_any(GLState& _state)
{
GLenum prev_depth = _state.depthFunc();
size_t numElements = mesh_.n_faces() + mesh_.n_edges() + mesh_.n_vertices();
if ( mesh_.n_vertices() == 0 ) {
std::cerr << "pick_any: No vertices in Mesh!" << std::endl;
return;
}
// nothing to pick ?
if (numElements == 0) {
std::cerr << "pick_any: Number of elements : 0 " << std::endl;
return;
}
if (!_state.pick_set_maximum (static_cast(numElements)))
{
omerr() << "MeshNode::pick_any: color range too small, " << "picking failed\n";
return;
}
if (_state.color_picking()) {
if ( updateAnyPicking_ || _state.pick_current_index () != anyPickingBaseIndex_) {
drawMesh_->updatePickingAny(_state);
anyPickingBaseIndex_ = _state.pick_current_index ();
updateAnyPicking_ = false;
}
// For this version we load the colors directly, not from vbo
ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
ACG::GLState::disableClientState(GL_NORMAL_ARRAY);
ACG::GLState::disableClientState(GL_TEXTURE_COORD_ARRAY);
ACG::GLState::enableClientState(GL_VERTEX_ARRAY);
ACG::GLState::enableClientState(GL_COLOR_ARRAY);
// If we do not have any faces, we generate an empty list here.
if ( mesh_.n_faces() != 0 && drawMesh_) {
ACG::GLState::vertexPointer(drawMesh_->pickFaceVertexBuffer());
ACG::GLState::colorPointer(drawMesh_->pickAnyFaceColorBuffer());
glDrawArrays(GL_TRIANGLES, 0, int(3 * drawMesh_->getNumTris()));
}
ACG::GLState::depthFunc(GL_LEQUAL);
// If we do not have any edges, we generate an empty list here.
if ( mesh_.n_edges() != 0 && drawMesh_) {
ACG::GLState::vertexPointer(drawMesh_->perEdgeVertexBuffer());
ACG::GLState::colorPointer(drawMesh_->pickAnyEdgeColorBuffer());
glDrawArrays(GL_LINES, 0, int(mesh_.n_edges() * 2));
}
// For this version we load the colors directly not from vbo
ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
ACG::GLState::vertexPointer( drawMesh_->pickVertexBuffer() );
ACG::GLState::colorPointer(drawMesh_->pickAnyVertexColorBuffer());
// Draw color picking
glDrawArrays(GL_POINTS, 0, int(mesh_.n_vertices()));
ACG::GLState::disableClientState(GL_COLOR_ARRAY);
ACG::GLState::disableClientState(GL_VERTEX_ARRAY);
// disable all other arrays
enable_arrays(0);
} else
std::cerr << "No fallback pick_any!" << std::endl;
//restore depth buffer comparison function for the active display list
ACG::GLState::depthFunc(prev_depth);
glCheckErrors();
}
template
void
MeshNodeT::
update_geometry() {
/// \todo check the following statements. If only geometry changed, the normals,vertices have to be updated nothing else!
/*
updateFaceList_ = true;
updateAnyList_ = true;
*/
updateVertexPicking_ = true;
updateEdgePicking_ = true;
updateFacePicking_ = true;
updateAnyPicking_ = true;
// Set per edge arrays to invalid as they have to be regenerated
drawMesh_->invalidatePerEdgeBuffers();
// Set per halfedge arrays to invalid as they have to be regenerated
drawMesh_->invalidatePerHalfedgeBuffers();
drawMesh_->updateGeometry();
// First of all, we update the bounding box:
bbMin_ = Vec3d(FLT_MAX, FLT_MAX, FLT_MAX);
bbMax_ = Vec3d(-FLT_MAX, -FLT_MAX, -FLT_MAX);
typename Mesh::ConstVertexIter v_it(mesh_.vertices_begin()),
v_end(mesh_.vertices_end());
for (; v_it!=v_end; ++v_it)
{
bbMin_.minimize(mesh_.point(*v_it));
bbMax_.maximize(mesh_.point(*v_it));
}
}
template
void
MeshNodeT::
update_topology() {
drawMesh_->invalidatePerEdgeBuffers();
drawMesh_->invalidatePerHalfedgeBuffers();
drawMesh_->updateTopology();
// Unbind the buffer after the work has been done
ACG::GLState::bindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
}
template
void
MeshNodeT::
update_textures() {
drawMesh_->updateTextures();
}
template
void
MeshNodeT::
update_color() {
drawMesh_->invalidatePerEdgeBuffers();
drawMesh_->invalidatePerHalfedgeBuffers();
// TODO: optimize update strategy:
// if only vertex colors have changed, then call UpdateGeometry() (faster)
// for face colors we have to use UpdateFull()
drawMesh_->updateFull();
}
template
void
MeshNodeT::
setIndexPropertyName( std::string _indexPropertyName ) {
drawMesh_->setTextureIndexPropertyName(_indexPropertyName);
perFaceTextureIndexAvailable_ = drawMesh_->perFaceTextureIndexAvailable() != 0;
}
template
const std::string&
MeshNodeT::
indexPropertyName() const {
return drawMesh_->getTextureIndexPropertyName();
}
template
void
MeshNodeT::
setHalfedgeTextcoordPropertyName( std::string _halfedgeTextcoordPropertyName ){
drawMesh_->setPerFaceTextureCoordinatePropertyName(_halfedgeTextcoordPropertyName);
perFaceTextureCoordsAvailable_ = drawMesh_->perFaceTextureCoordinateAvailable() != 0;
}
template
unsigned int
MeshNodeT::getMemoryUsage()
{
unsigned int res = 0;
if (drawMesh_)
res += drawMesh_->getMemoryUsage();
return res;
}
template
DrawMeshT*
MeshNodeT::getDrawMesh()
{
return drawMesh_;
}
template
void MeshNodeT::updatePolyEdgeBuf()
{
#ifdef GL_ARB_texture_buffer_object
MeshCompiler* mc = drawMesh_->getMeshCompiler();
if (mc && !mc->isTriangleMesh())
{
// create/update the poly-edge buffer
if (!polyEdgeBuf_)
glGenBuffers(1, &polyEdgeBuf_);
const int nTris = mc->getNumTriangles();
const int newBufSize = (nTris/2+1);
if (polyEdgeBufSize_ != newBufSize)
{
glBindBuffer(GL_TEXTURE_BUFFER, polyEdgeBuf_);
// The poly-edge buffer is a texture buffer that stores one byte for each triangle, which encodes triangle edge properties.
// An inner edge is an edge that was added during the triangulation of a n-poly,
// whereas outer edges are edges that already exist in the input mesh object.
// This information is used in the wireframe/hiddenline geometry shader to identify edges, which should not be rendered.
// Buffer storage:
// each triangle uses 3 bits to mark edges as visible or hidden
// outer edge -> bit = 1 (visible)
// inner edge -> bit = 0 (hidden)
// each byte can store edges for two triangles and the remaining 2 bits are left unused
polyEdgeBufSize_ = newBufSize;
unsigned char* polyEdgeBufData = new unsigned char[newBufSize];
// set zero
memset(polyEdgeBufData, 0, newBufSize);
// build buffer
for (int i = 0; i < nTris; ++i)
{
int byteidx = i>>1;
int bitidx = (i&1) * 3;
for (int k = 0; k < 3; ++k)
if (mc->isFaceEdge(i, k))
polyEdgeBufData[byteidx] += 1 << (k + bitidx);
}
glBufferData(GL_TEXTURE_BUFFER, polyEdgeBufSize_, polyEdgeBufData, GL_STATIC_DRAW);
delete [] polyEdgeBufData;
polyEdgeBufData = 0;
// create texture object for the texture buffer
if (!polyEdgeBufTex_)
{
glGenTextures(1, &polyEdgeBufTex_);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, polyEdgeBufTex_);
glTexBuffer(GL_TEXTURE_BUFFER, GL_R8UI, polyEdgeBuf_);
glBindTexture(GL_TEXTURE_2D, 0);
}
ACG::glCheckErrors();
}
}
#endif
}
//=============================================================================
} // namespace SceneGraph
} // namespace ACG
//=============================================================================