/*===========================================================================*\
* *
* OpenFlipper *
* Copyright (C) 2001-2009 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
//== NAMESPACES ===============================================================
namespace ACG {
namespace SceneGraph {
//== INCLUDES =================================================================
#include "MeshNode2T.hh"
template
MeshNodeT::
MeshNodeT(Mesh& _mesh,
BaseNode* _parent,
std::string _name ):
BaseNode(_parent, _name),
mesh_(_mesh),
stripProcessor_(_mesh),
vertexBuffer_(0),
vertexBufferInitialized_(false),
enableNormals_(true),
normalVertexBuffer_(0),
normalVertexBufferInitialized_(false),
enableColors_(true),
colorVertexbuffer_(0),
colorVertexBufferInitialized_(false),
enableTexCoords_(true),
lineIndexBuffer_(0),
lineIndexBufferInitialized_(false),
enabled_arrays_(0),
updateVertexPickingList_(true),
vertexPickingBaseIndex_(0),
vertexPickingList_(0),
updateEdgePickingList_(true),
edgePickingBaseIndex_(0),
edgePickingList_(0),
updateFacePickingList_(true),
facePickingBaseIndex_(0),
facePickingList_(0),
updateAnyPickingList_(true),
anyPickingBaseIndex_(0),
anyPickingList_(0),
perFaceTextureIndexAvailable_(false),
perFaceTextureCoordsAvailable_(false),
textureMap_(0)
{
/// \todo : Handle vbo not supported
if ( ! GLEW_ARB_vertex_buffer_object ) {
std::cerr << "Error! Vertex buffer objects are not supported! The meshNode will not work without them!" << std::endl;
}
vertexPickingList_ = glGenLists(1);
edgePickingList_ = glGenLists(1);
facePickingList_ = glGenLists(1);
anyPickingList_ = glGenLists(3);
}
template
MeshNodeT::
~MeshNodeT()
{
// Delete all allocated buffers
if (vertexBuffer_)
glDeleteBuffersARB(1, &vertexBuffer_);
if (normalVertexBuffer_)
glDeleteBuffersARB(1, &normalVertexBuffer_);
if (colorVertexbuffer_)
glDeleteBuffersARB(1, &colorVertexbuffer_);
if (lineIndexBuffer_)
glDeleteBuffersARB(1, &lineIndexBuffer_);
if (vertexPickingList_)
glDeleteLists (vertexPickingList_, 1);
if (edgePickingList_)
glDeleteLists (edgePickingList_, 1);
if (facePickingList_)
glDeleteLists (facePickingList_, 1);
if (anyPickingList_)
glDeleteLists (anyPickingList_, 3);
}
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;
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_vertex_colors())
{
drawModes |= DrawModes::POINTS_COLORED;
drawModes |= DrawModes::SOLID_POINTS_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_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, DrawModes::DrawMode _drawMode) {
// Update strips if necessary
stripProcessor_.stripify();
/// \todo Whats this? Why is this set here
glDepthFunc(depthFunc());
unsigned int arrays = VERTEX_ARRAY;
glPushAttrib(GL_ENABLE_BIT);
if ( (_drawMode & DrawModes::POINTS) || (_drawMode & DrawModes::POINTS_COLORED) || (_drawMode & DrawModes::POINTS_SHADED ) ) {
glShadeModel(GL_FLAT);
if ( _drawMode & DrawModes::POINTS_SHADED ) {
glEnable(GL_LIGHTING);
} else
glDisable(GL_LIGHTING);
// Use Colors in this mode if allowed
if ( enableColors_ && (_drawMode & DrawModes::POINTS_COLORED) )
arrays |= COLOR_VERTEX_ARRAY;
// Use Normals in this mode if allowed
if ( enableNormals_ && (_drawMode & DrawModes::POINTS_SHADED ) ) {
arrays |= NORMAL_VERTEX_ARRAY;
// If we have colors and lighting with normals, we have to use colormaterial
if ( (arrays & COLOR_VERTEX_ARRAY) )
glEnable(GL_COLOR_MATERIAL);
else
glDisable(GL_COLOR_MATERIAL);
}
// 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)
{
enable_arrays( VERTEX_ARRAY | LINE_INDEX_ARRAY );
glDisable(GL_LIGHTING);
glShadeModel(GL_FLAT);
draw_lines();
}
if (_drawMode & DrawModes::HIDDENLINE)
{
enable_arrays(VERTEX_ARRAY);
// First:
// Render all faces in background color to initialize z-buffer
Vec4f clear_color = _state.clear_color();
Vec4f base_color = _state.base_color();
clear_color[3] = 1.0;
glDisable(GL_LIGHTING);
glShadeModel(GL_FLAT);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
_state.set_base_color(clear_color);
glDepthRange(0.01, 1.0);
draw_faces(PER_VERTEX);
glDepthRange(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);
glDepthFunc(GL_LEQUAL);
_state.set_base_color(base_color);
draw_lines();
glDepthFunc(depthFunc());
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
if ( ( _drawMode & DrawModes::SOLID_POINTS_COLORED ) && mesh_.has_vertex_colors() )
{
glDisable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
glDepthRange(0.01, 1.0);
enable_arrays( VERTEX_ARRAY | COLOR_VERTEX_ARRAY );
draw_faces(PER_VERTEX);
glDepthRange(0.0, 1.0);
}
if ( ( _drawMode & DrawModes::SOLID_FLAT_SHADED ) && mesh_.has_face_normals())
{
glEnable(GL_LIGHTING);
glShadeModel(GL_FLAT);
glDepthRange(0.01, 1.0);
enable_arrays(PER_FACE_VERTEX_ARRAY | PER_FACE_NORMAL_ARRAY);
draw_faces(PER_FACE);
glDepthRange(0.0, 1.0);
}
if ( ( _drawMode & DrawModes::SOLID_SMOOTH_SHADED ) && mesh_.has_vertex_normals() )
{
enable_arrays( VERTEX_ARRAY | NORMAL_VERTEX_ARRAY );
glEnable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
glDepthRange(0.01, 1.0);
draw_faces(PER_VERTEX);
glDepthRange(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 );
glEnable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
glDepthRange(0.01, 1.0);
draw_faces(PER_VERTEX);
glDepthRange(0.0, 1.0);
//disable own Phong shader
// program->disable();
// }
// }
}
if ( ( _drawMode & DrawModes::SOLID_FACES_COLORED )&& mesh_.has_face_colors())
{
Vec4f base_color_backup = _state.base_color();
glDisable(GL_LIGHTING);
glShadeModel(GL_FLAT);
glDepthRange(0.01, 1.0);
enable_arrays(PER_FACE_VERTEX_ARRAY | PER_FACE_COLOR_ARRAY);
draw_faces(PER_FACE);
glDepthRange(0.0, 1.0);
_state.set_base_color(base_color_backup);
}
if ( ( _drawMode & DrawModes::SOLID_FACES_COLORED_FLAT_SHADED ) && mesh_.has_face_colors() && mesh_.has_face_normals())
{
Vec4f base_color_backup = _state.base_color();
glEnable(GL_LIGHTING);
glShadeModel(GL_FLAT);
glDepthRange(0.01, 1.0);
enable_arrays(PER_FACE_VERTEX_ARRAY | PER_FACE_COLOR_ARRAY | PER_FACE_NORMAL_ARRAY );
draw_faces(PER_FACE);
glDepthRange(0.0, 1.0);
_state.set_base_color(base_color_backup);
}
if ( ( _drawMode & DrawModes::SOLID_TEXTURED ) && mesh_.has_vertex_texcoords2D())
{
///\todo enableTexCoords_
enable_arrays(VERTEX_ARRAY | TEXCOORD_VERTEX_ARRAY );
glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glShadeModel(GL_FLAT);
glDepthRange(0.01, 1.0);
draw_faces(PER_VERTEX);
glDepthRange(0.0, 1.0);
glDisable(GL_TEXTURE_2D);
}
if ( ( _drawMode & DrawModes::SOLID_TEXTURED_SHADED ) && mesh_.has_vertex_texcoords2D() && mesh_.has_vertex_normals())
{
enable_arrays(VERTEX_ARRAY | NORMAL_VERTEX_ARRAY | TEXCOORD_VERTEX_ARRAY);
glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
glDepthRange(0.01, 1.0);
draw_faces(PER_VERTEX);
glDepthRange(0.0, 1.0);
glDisable(GL_TEXTURE_2D);
}
// Textured by using coordinates stored in halfedges ... arrays generated by stripprocessor
if ( _drawMode & DrawModes::SOLID_2DTEXTURED_FACE )
{
glEnable(GL_TEXTURE_2D);
enable_arrays( PER_FACE_VERTEX_ARRAY | PER_FACE_TEXCOORD_ARRAY );
glDisable(GL_LIGHTING);
glShadeModel(GL_FLAT);
glDepthRange(0.01, 1.0);
draw_faces(PER_FACE);
glDepthRange(0.0, 1.0);
glDisable(GL_TEXTURE_2D);
}
// Textured by using coordinates stored in halfedges
if ( ( _drawMode & DrawModes::SOLID_2DTEXTURED_FACE_SHADED ) && mesh_.has_face_normals())
{
glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
enable_arrays( PER_FACE_VERTEX_ARRAY | PER_FACE_TEXCOORD_ARRAY | PER_FACE_NORMAL_ARRAY );
glShadeModel(GL_FLAT);
glDepthRange(0.01, 1.0);
draw_faces(PER_FACE);
glDepthRange(0.0, 1.0);
glDisable(GL_TEXTURE_2D);
}
enable_arrays(0);
// Unbind all remaining buffers
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB , 0 );
/// \todo Whats this? Why is this set here and why isnt it set to the one before entering the function?
glDepthFunc(GL_LESS);
glPopAttrib();
}
template
void
MeshNodeT::
draw_vertices() {
if ( !vertexBufferInitialized_ || ( mesh_.n_verices() == 0 ))
return;
glDrawArrays(GL_POINTS, 0, mesh_.n_vertices());
}
template
void
MeshNodeT::
draw_lines() {
if ( enabled_arrays_ & LINE_INDEX_ARRAY )
// Check if array is set up correctly
if ( lineIndexBufferInitialized_ )
glDrawElements(GL_LINES, mesh_.n_edges() * 2, GL_UNSIGNED_INT, 0 );
else
return;
// If we are rendering per edge per vertex attributes, we need to use a seperated vertex buffer!
else if ( enabled_arrays_ & PER_EDGE_VERTEX_ARRAY )
glDrawArrays(GL_LINES, 0, mesh_.n_edges() * 2);
// Something went wrong here!
else
std::cerr << "Unable to Draw! array configuration is invalid!!" << std::endl;
}
template
void
MeshNodeT::
draw_faces(FaceMode _mode) {
// If we have all properties per Vertex, we can render with index array from triangle strips!
if (_mode == PER_VERTEX) {
typename StripProcessorT::StripsIterator strip_it = stripProcessor_.begin();
typename StripProcessorT::StripsIterator strip_last = stripProcessor_.end();
for (; strip_it!=strip_last; ++strip_it) {
glDrawElements(GL_TRIANGLE_STRIP,
strip_it->indexArray.size(),
GL_UNSIGNED_INT,
&(strip_it->indexArray)[0] );
}
} else if ( _mode == PER_FACE ) {
if ( stripProcessor_.perFaceTextureIndexAvailable() && (textureMap_ != 0) ) {
int lastTexture = -1;
int texture = 0;
for ( uint i = 0 ; i < stripProcessor_.textureRenderData()->size() ; ++i ) {
int texture = (*stripProcessor_.textureRenderData())[i].textureId;
if ( texture != lastTexture) {
if ( textureMap_->find(texture) == textureMap_->end() ) {
std::cerr << "Illegal texture index ... trying to access " << texture << std::endl;
lastTexture = -1;
continue;
}
glBindTexture( GL_TEXTURE_2D, (*textureMap_)[texture] );
lastTexture = texture;
}
// We need per face attributes so we have to use seperate vertices per face
glDrawArrays(GL_TRIANGLES, (*stripProcessor_.textureRenderData())[i].startOffset , (*stripProcessor_.textureRenderData())[i].faceCount * 3 );
}
} else {
// We need per face attributes so we have to use seperate vertices per face
glDrawArrays(GL_TRIANGLES, 0, stripProcessor_.perFaceVertexBufferSize() );
}
}
}
template
void
MeshNodeT::
enable_arrays(unsigned int _arrays) {
// Unbind everything to ensure sane settings
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
//===================================================================
// Vertex Array
//===================================================================
// Check if we should enable the vertex array
if ( (_arrays & VERTEX_ARRAY ) && vertexBufferInitialized_ ) {
// Check if its already enabled
if (!(enabled_arrays_ & VERTEX_ARRAY)) {
// Enable the vertex buffer
enabled_arrays_ |= VERTEX_ARRAY;
// Bind the Vertex buffer
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffer_);
// As we ensure that buffers are converted to float before using them, use Float here
glVertexPointer(3, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
}
} else if (enabled_arrays_ & VERTEX_ARRAY) {
// Disable the Vertex array
enabled_arrays_ &= ~VERTEX_ARRAY;
glDisableClientState(GL_VERTEX_ARRAY);
}
//===================================================================
// Normal Array
//===================================================================
// Check if we should enable the normal array
if ( mesh_.has_vertex_normals() && ( _arrays & NORMAL_VERTEX_ARRAY ) && normalVertexBufferInitialized_ ) {
// Check if its already enabled
if (!(enabled_arrays_ & NORMAL_VERTEX_ARRAY)) {
enabled_arrays_ |= NORMAL_VERTEX_ARRAY;
glBindBufferARB(GL_ARRAY_BUFFER_ARB, normalVertexBuffer_);
// As we ensure that buffers are converted to float before using them, use Float here
glNormalPointer(GL_FLOAT, 0 , 0);
glEnableClientState(GL_NORMAL_ARRAY);
}
} else if (enabled_arrays_ & NORMAL_VERTEX_ARRAY) {
// Disable Normal array
enabled_arrays_ &= ~NORMAL_VERTEX_ARRAY;
glDisableClientState(GL_NORMAL_ARRAY);
}
//===================================================================
// per Vertex Color Array
//===================================================================
/// \todo This is different to normal and vertex buffer since it uses openmesh colors directly! Check for different color representations in OpenMesh!
// Check if we should enable the color array
if ( mesh_.has_vertex_colors() && ( _arrays & COLOR_VERTEX_ARRAY )) {
// Check if its already enabled
if (!(enabled_arrays_ & COLOR_VERTEX_ARRAY)) {
enabled_arrays_ |= COLOR_VERTEX_ARRAY;
glBindBufferARB(GL_ARRAY_BUFFER_ARB, colorVertexbuffer_);
// Explicitly give the pointer as we uploaded the data ourself!
glColorPointer(4, GL_FLOAT , 0 , 0);
glEnableClientState(GL_COLOR_ARRAY);
}
} else if (enabled_arrays_ & COLOR_VERTEX_ARRAY) {
// Disable Color array
enabled_arrays_ &= ~COLOR_VERTEX_ARRAY;
glDisableClientState(GL_COLOR_ARRAY);
}
//===================================================================
// per Vertex Texture coordinate Array
//===================================================================
// Check if we should enable the color array
if ( mesh_.has_vertex_texcoords2D() && ( _arrays & TEXCOORD_VERTEX_ARRAY )) {
// Check if its already enabled
if (!(enabled_arrays_ & TEXCOORD_VERTEX_ARRAY)) {
enabled_arrays_ |= TEXCOORD_VERTEX_ARRAY;
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
// Explicitly give the pointer as we uploaded the data ourself!
glTexCoordPointer(2, GL_FLOAT , 0 , mesh_.texcoords2D() );
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
} else if (enabled_arrays_ & TEXCOORD_VERTEX_ARRAY) {
// Disable TexCoord array
enabled_arrays_ &= ~TEXCOORD_VERTEX_ARRAY;
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
//===================================================================
// 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
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glVertexPointer( stripProcessor_.perEdgeVertexBuffer() );
glEnableClientState(GL_VERTEX_ARRAY);
}
} else if (enabled_arrays_ & PER_EDGE_VERTEX_ARRAY) {
// Disable Vertex array
enabled_arrays_ &= ~PER_EDGE_VERTEX_ARRAY;
glDisableClientState(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
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glColorPointer( stripProcessor_.perEdgeColorBuffer() );
glEnableClientState(GL_COLOR_ARRAY);
}
} else if (enabled_arrays_ & PER_EDGE_COLOR_ARRAY) {
// Disable Vertex array
enabled_arrays_ &= ~PER_EDGE_COLOR_ARRAY;
glDisableClientState(GL_COLOR_ARRAY);
}
//===================================================================
// per Face Vertex Array
//===================================================================
// Check if we should enable the per face vertex array
if (_arrays & PER_FACE_VERTEX_ARRAY) {
// Check if its already enabled
if (!(enabled_arrays_ & PER_FACE_VERTEX_ARRAY)) {
enabled_arrays_ |= PER_FACE_VERTEX_ARRAY;
// For this version we load the colors directly not from vbo
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glVertexPointer( stripProcessor_.perFaceVertexBuffer() );
glEnableClientState(GL_VERTEX_ARRAY);
}
} else if (enabled_arrays_ & PER_FACE_VERTEX_ARRAY) {
// Disable Vertex array
enabled_arrays_ &= ~PER_FACE_VERTEX_ARRAY;
glDisableClientState(GL_VERTEX_ARRAY);
}
//===================================================================
// per Face Normal Array
//===================================================================
// Check if we should enable the per face normal array
if (mesh_.has_face_normals() && (_arrays & PER_FACE_NORMAL_ARRAY) ) {
// Check if its already enabled
if (!(enabled_arrays_ & PER_FACE_NORMAL_ARRAY)) {
enabled_arrays_ |= PER_FACE_NORMAL_ARRAY;
// For this version we load the colors directly not from vbo
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glNormalPointer( stripProcessor_.perFaceNormalBuffer() );
glEnableClientState(GL_NORMAL_ARRAY);
}
} else if (enabled_arrays_ & PER_FACE_NORMAL_ARRAY) {
// Disable Normal array
enabled_arrays_ &= ~PER_FACE_NORMAL_ARRAY;
glDisableClientState(GL_NORMAL_ARRAY);
}
//===================================================================
// per Face Color Array
//===================================================================
// Check if we should enable the per face color array
if (mesh_.has_face_colors() && (_arrays & PER_FACE_COLOR_ARRAY) ) {
// Check if its already enabled
if (!(enabled_arrays_ & PER_FACE_COLOR_ARRAY)) {
enabled_arrays_ |= PER_FACE_COLOR_ARRAY;
// For this version we load the colors directly not from vbo
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glColorPointer( stripProcessor_.perFaceColorBuffer() );
glEnableClientState(GL_COLOR_ARRAY);
}
} else if (enabled_arrays_ & PER_FACE_COLOR_ARRAY) {
// Disable Normal array
enabled_arrays_ &= ~PER_FACE_COLOR_ARRAY;
glDisableClientState(GL_COLOR_ARRAY);
}
//===================================================================
// per Face TexCoord Array
//===================================================================
// Check if we should enable the per face color array
if ( stripProcessor_.perFaceTextureCoordinateAvailable() && (_arrays & PER_FACE_TEXCOORD_ARRAY ) ) {
// Check if its already enabled
if (!(enabled_arrays_ & PER_FACE_TEXCOORD_ARRAY)) {
enabled_arrays_ |= PER_FACE_TEXCOORD_ARRAY;
// For this version we load the colors directly not from vbo
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glTexCoordPointer( stripProcessor_.perFacePerVertexTextureCoordBuffer() );
glEnableClientState(GL_TEXTURE_COORD_ARRAY );
}
} else if (enabled_arrays_ & PER_FACE_TEXCOORD_ARRAY) {
// Disable Texture Coordinate array
enabled_arrays_ &= ~PER_FACE_TEXCOORD_ARRAY;
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
//===================================================================
// Line Index Array
//===================================================================
// Check if we should enable the color array
if (_arrays & LINE_INDEX_ARRAY) {
// Check if its already enabled
if (!(enabled_arrays_ & LINE_INDEX_ARRAY)) {
enabled_arrays_ |= LINE_INDEX_ARRAY;
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, lineIndexBuffer_);
}
} else if (enabled_arrays_ & LINE_INDEX_ARRAY) {
// Disable Color array
enabled_arrays_ &= ~LINE_INDEX_ARRAY;
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
}
if ( _arrays == 0 )
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
//===================================================================
// 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)
{
typename Mesh::ConstVertexIter v_it(mesh_.vertices_begin()),
v_end(mesh_.vertices_end());
if (!_state.pick_set_maximum (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 ) ) {
enable_arrays(VERTEX_ARRAY);
Vec4f clear_color = _state.clear_color();
Vec4f base_color = _state.base_color();
clear_color[3] = 1.0;
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
_state.set_base_color(clear_color);
glDepthRange(0.01, 1.0);
draw_faces(PER_VERTEX);
glDepthRange(0.0, 1.0);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDepthFunc(GL_LEQUAL);
_state.set_base_color(base_color);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
enable_arrays(0);
}
if (vertexPickingList_ && !updateVertexPickingList_ && _state.pick_current_index () == vertexPickingBaseIndex_) {
glCallList (vertexPickingList_);
if (_front)
glDepthFunc(depthFunc());
return;
}
if (vertexPickingList_) {
glNewList (vertexPickingList_, GL_COMPILE);
updateVertexPickingList_ = false;
vertexPickingBaseIndex_ = _state.pick_current_index ();
}
if (_state.color_picking ()) {
stripProcessor_.updatePickingVertices(_state);
enable_arrays(VERTEX_ARRAY);
// For this version we load the colors directly not from vbo
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glColorPointer( stripProcessor_.pickVertexColorBuffer() );
glEnableClientState(GL_COLOR_ARRAY);
// Draw color picking
glDrawArrays(GL_POINTS, 0, mesh_.n_vertices());
// Disable color array
glDisableClientState(GL_COLOR_ARRAY);
// disable all other arrays
enable_arrays(0);
} else
std::cerr << "Fallback not available pick_vertices!" << std::endl;
if (vertexPickingList_) {
glEndList ();
glCallList (vertexPickingList_);
}
if (_front)
glDepthFunc(depthFunc());
}
template
void
MeshNodeT::
pick_edges(GLState& _state, bool _front)
{
if (!_state.pick_set_maximum (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 ) ) {
enable_arrays(VERTEX_ARRAY);
Vec4f clear_color = _state.clear_color();
Vec4f base_color = _state.base_color();
clear_color[3] = 1.0;
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
_state.set_base_color(clear_color);
glDepthRange(0.01, 1.0);
draw_faces(PER_VERTEX);
glDepthRange(0.0, 1.0);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDepthFunc(GL_LEQUAL);
_state.set_base_color(base_color);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// disable all other arrays
enable_arrays(0);
}
if (edgePickingList_ && !updateEdgePickingList_ && _state.pick_current_index () == edgePickingBaseIndex_) {
glCallList (edgePickingList_);
if (_front)
glDepthFunc(depthFunc());
return;
}
if (edgePickingList_) {
glNewList (edgePickingList_, GL_COMPILE);
updateEdgePickingList_ = false;
edgePickingBaseIndex_ = _state.pick_current_index ();
}
if (_state.color_picking () ) {
if ( mesh_.n_edges() != 0 ) {
stripProcessor_.updatePickingEdges(_state);
// For this version we load the colors directly not from vbo
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer (stripProcessor_.perEdgeVertexBuffer());
glColorPointer(stripProcessor_.pickEdgeColorBuffer());
glDrawArrays(GL_LINES, 0, mesh_.n_edges() * 2);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
// disable all other arrays
enable_arrays(0);
} else {
std::cerr << "pick_edges: No edges in Mesh!" << std::endl;
}
} else {
std::cerr << "No fallback pick_edges!" << std::endl;
}
if (edgePickingList_) {
glEndList ();
glCallList (edgePickingList_);
}
if (_front)
glDepthFunc(depthFunc());
}
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 (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 (facePickingList_ && !updateFacePickingList_ && _state.pick_current_index () == facePickingBaseIndex_) {
glCallList (facePickingList_);
return;
}
if (facePickingList_) {
glNewList (facePickingList_, GL_COMPILE);
updateFacePickingList_ = false;
facePickingBaseIndex_ = _state.pick_current_index();
}
if (_state.color_picking ()) {
if ( mesh_.n_faces() != 0 ) {
stripProcessor_.updatePickingFaces(_state);
// For this version we load the colors directly not from vbo
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer( stripProcessor_.perFaceVertexBuffer() );
glColorPointer( stripProcessor_.pickFaceColorBuffer() );
glDrawArrays(GL_TRIANGLES, 0, stripProcessor_.perFaceVertexBufferSize() );
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
// disable all other arrays
enable_arrays(0);
} else {
std::cerr << "pick_faces: No faces in Mesh! " << std::endl;
}
} else
std::cerr << "No fallback pick_faces!" << std::endl;
if (facePickingList_) {
glEndList ();
glCallList (facePickingList_);
}
}
template
void
MeshNodeT::
pick_any(GLState& _state)
{
unsigned int 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 (numElements))
{
omerr() << "MeshNode::pick_any: color range too small, " << "picking failed\n";
return;
}
if (anyPickingList_ && !updateAnyPickingList_ && _state.pick_current_index () == anyPickingBaseIndex_)
{
glCallList (anyPickingList_);
glCallList (anyPickingList_+1);
glCallList (anyPickingList_+2);
return;
}
if (anyPickingList_) {
glNewList (anyPickingList_, GL_COMPILE);
updateAnyPickingList_ = false;
anyPickingBaseIndex_ = _state.pick_current_index ();
}
if (_state.color_picking() ) {
stripProcessor_.updatePickingAny(_state);
// For this version we load the colors directly not from vbo
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
// If we do not have any faces, we generate an empty list here.
if ( mesh_.n_faces() != 0) {
glVertexPointer( stripProcessor_.perFaceVertexBuffer() );
glColorPointer( stripProcessor_.pickFaceColorBuffer() );
glDrawArrays(GL_TRIANGLES, 0, stripProcessor_.perFaceVertexBufferSize() );
}
if (anyPickingList_)
{
glEndList ();
glNewList (anyPickingList_+1, GL_COMPILE);
}
glDepthFunc(GL_LEQUAL);
// If we do not have any edges, we generate an empty list here.
if ( mesh_.n_edges() != 0) {
glVertexPointer (stripProcessor_.perEdgeVertexBuffer());
glColorPointer(stripProcessor_.pickEdgeColorBuffer());
glDrawArrays(GL_LINES, 0, mesh_.n_edges() * 2);
}
if (anyPickingList_)
{
glEndList ();
glNewList (anyPickingList_+2, GL_COMPILE);
}
enable_arrays(VERTEX_ARRAY);
// For this version we load the colors directly not from vbo
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glColorPointer( stripProcessor_.pickVertexColorBuffer() );
glEnableClientState(GL_COLOR_ARRAY);
// Draw color picking
glDrawArrays(GL_POINTS, 0, mesh_.n_vertices());
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDepthFunc(depthFunc());
// disable all other arrays
enable_arrays(0);
}
if (anyPickingList_)
{
glEndList ();
glCallList (anyPickingList_);
glCallList (anyPickingList_+1);
glCallList (anyPickingList_+2);
}
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;
*/
updateVertexPickingList_ = true;
updateEdgePickingList_ = true;
updateFacePickingList_ = true;
updateAnyPickingList_ = true;
// Set per face arrays to invalid as they have to be regenerated
stripProcessor_.invalidatePerFaceBuffers();
// Set per edge arrays to invalid as they have to be regenerated
stripProcessor_.invalidatePerEdgeBuffers();
// 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));
}
//===================================================================
// Generate a vertex buffer on the GPU
//===================================================================
// Allocate it if required
if (!vertexBuffer_) glGenBuffersARB(1, (GLuint*) &vertexBuffer_);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffer_);
vertexBufferInitialized_ = false;
//Check if using floats otherwise convert to internal float array
if ( sizeof(PointScalar) == 4 ) {
glBufferDataARB(GL_ARRAY_BUFFER_ARB,
3 * mesh_.n_vertices() * sizeof(PointScalar),
mesh_.points(),
GL_STATIC_DRAW_ARB);
vertexBufferInitialized_ = true;
} else {
vertices_.clear();
typename Mesh::ConstVertexIter v_it(mesh_.vertices_begin()),
v_end(mesh_.vertices_end());
for ( ; v_it != v_end ; ++v_it )
vertices_.push_back( ACG::Vec3f(mesh_.point(v_it)) );
if ( !vertices_.empty() ) {
glBufferDataARB(GL_ARRAY_BUFFER_ARB,
3 * mesh_.n_vertices() * sizeof(float),
&vertices_[0],
GL_STATIC_DRAW_ARB);
vertexBufferInitialized_ = true;
}
}
// ==========================================================================
// Generate normal buffer
// ==========================================================================
// Allocate it if required
if (!normalVertexBuffer_) glGenBuffersARB(1, (GLuint*) &normalVertexBuffer_);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, normalVertexBuffer_);
normalVertexBufferInitialized_ = false;
// Check if using floats otherwise convert to internal float array
if ( sizeof(NormalScalar) == 4) {
glBufferDataARB(GL_ARRAY_BUFFER_ARB,
3 * mesh_.n_vertices() * sizeof(NormalScalar),
mesh_.vertex_normals(),
GL_STATIC_DRAW_ARB);
normalVertexBufferInitialized_ = true;
} else {
// Clear local conversion array
normals_.clear();
// Preallocate memory for efficiency
normals_.reserve( mesh_.n_vertices() );
// Convert data to the desired format
typename Mesh::ConstVertexIter v_end(mesh_.vertices_end());
for ( typename Mesh::ConstVertexIter v_it(mesh_.vertices_begin()) ; v_it != v_end ; ++v_it )
normals_.push_back( ACG::Vec3f(mesh_.normal(v_it)) );
if ( !normals_.empty() ) {
// Upload to graphics card
glBufferDataARB(GL_ARRAY_BUFFER_ARB,
3 * mesh_.n_vertices() * sizeof(float),
&normals_[0],
GL_STATIC_DRAW_ARB);
normalVertexBufferInitialized_ = true;
// As we uploaded the data to the graphics card, we can clear it in the main memory
normals_.clear();
std::vector< ACG::Vec3f >().swap(normals_);
}
}
// ==========================================================================
// unbind all buffers
// ==========================================================================
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
template
void
MeshNodeT::
update_topology() {
// ==========================================================================
// Clear the strips and regenerate them!
// ==========================================================================
// Mark strips as invalid to force an update
stripProcessor_.invalidateStrips();
// Set per face arrays to invalid as they have to be regenerated
stripProcessor_.invalidatePerFaceBuffers();
// Set per edge arrays to invalid as they have to be regenerated
stripProcessor_.invalidatePerEdgeBuffers();
// std::cerr << "Created " << stripProcessor_.nStrips() << " strips\n" << std::endl;
// ==========================================================================
// Generate a buffer for rendering all lines
// ==========================================================================
lineIndices_.clear();
typename Mesh::ConstEdgeIter e_it(mesh_.edges_begin()),
e_end(mesh_.edges_end());
for ( ; e_it != e_end ; ++e_it ) {
lineIndices_.push_back( mesh_.from_vertex_handle(mesh_.halfedge_handle(e_it,0)).idx() );
lineIndices_.push_back( mesh_.to_vertex_handle(mesh_.halfedge_handle(e_it,0)).idx() );
}
// Allocate it if required
if (!lineIndexBuffer_) glGenBuffersARB(1, (GLuint*) &lineIndexBuffer_);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, lineIndexBuffer_);
lineIndexBufferInitialized_ = false;
if ( !lineIndices_.empty() ) {
// Copy the buffer to the graphics card
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
mesh_.n_edges() * sizeof(unsigned int) * 2,
&lineIndices_[0],
GL_STATIC_DRAW_ARB);
std::vector< unsigned int >().swap(lineIndices_);
lineIndexBufferInitialized_ = true;
}
// Unbind the buffer after the work has been done
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
}
template
void
MeshNodeT::
update_color() {
// ==========================================================================
// Generate color buffer
// ==========================================================================
// Allocate it if required
if (!colorVertexbuffer_) glGenBuffersARB(1, (GLuint*) &colorVertexbuffer_);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, colorVertexbuffer_);
colorVertexBufferInitialized_ = false;
// Colors consist of 4 scalars (RGBA) with type float -> direct upload!
if ( sizeof(ColorScalar) == 4 && mesh_.vertex_colors()->dim() == 4 ) {
glBufferDataARB(GL_ARRAY_BUFFER_ARB,
4 * mesh_.n_vertices() * sizeof(ColorScalar),
mesh_.vertex_colors(),
GL_STATIC_DRAW_ARB);
colorVertexBufferInitialized_ = true;
} else {
// Format mismatch -> conversion
// Clear the local color conversion array
colors_.clear();
// Preallocate memory for efficiency
colors_.reserve( mesh_.n_vertices() );
// Convert data to the desired format
typename Mesh::ConstVertexIter v_end(mesh_.vertices_end());
for ( typename Mesh::ConstVertexIter v_it(mesh_.vertices_begin()) ; v_it != v_end ; ++v_it )
colors_.push_back( OpenMesh::color_cast(mesh_.color(v_it)) );
if ( !colors_.empty() ) {
// Upload to graphics card
glBufferDataARB(GL_ARRAY_BUFFER_ARB,
4 * mesh_.n_vertices() * sizeof(float),
&colors_[0],
GL_STATIC_DRAW_ARB);
colorVertexBufferInitialized_ = true;
// As we uploaded the data to the graphics card, we can clear it in the main memory
colors_.clear();
std::vector< ACG::Vec4f >().swap(colors_);
}
}
// ==========================================================================
// unbind all buffers
// ==========================================================================
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
template
void
MeshNodeT::
setIndexPropertyName( std::string _indexPropertyName ) {
stripProcessor_.setIndexPropertyName(_indexPropertyName);
perFaceTextureIndexAvailable_ = stripProcessor_.perFaceTextureIndexAvailable();
};
template
void
MeshNodeT::
setHalfedgeTextcoordPropertyName( std::string _halfedgeTextcoordPropertyName ){
stripProcessor_.setPerFaceTextureCoordinatePropertyName(_halfedgeTextcoordPropertyName);
perFaceTextureCoordsAvailable_ = stripProcessor_.perFaceTextureCoordinateAvailable();
};
//=============================================================================
} // namespace SceneGraph
} // namespace ACG
//=============================================================================