#include #include #include #include #include #include #include #include #include #include #include #define GL_GLEXT_PROTOTYPES #include // some definitions for what the polydata has in it #define CPM_VTK_PDM_NORMALS 0x0001 #define CPM_VTK_PDM_COLORS 0x0002 #define CPM_VTK_PDM_TCOORDS 0x0004 #define CPM_VTK_PDM_CELL_COLORS 0x0008 #define CPM_VTK_PDM_CELL_NORMALS 0x0010 #define CPM_VTK_PDM_POINT_TYPE_FLOAT 0x0020 #define CPM_VTK_PDM_POINT_TYPE_DOUBLE 0x0040 #define CPM_VTK_PDM_NORMAL_TYPE_FLOAT 0x0080 #define CPM_VTK_PDM_NORMAL_TYPE_DOUBLE 0x0100 #define CPM_VTK_PDM_TCOORD_TYPE_FLOAT 0x0200 #define CPM_VTK_PDM_TCOORD_TYPE_DOUBLE 0x0400 #define CPM_VTK_PDM_TCOORD_1D 0x0800 #define CPM_VTK_PDM_OPAQUE_COLORS 0x1000 #define CPM_VTK_PDM_USE_FIELD_DATA 0x2000 // ------------------------------------------------------------------------- template< class M > typename cpm::VTK::OpenGLMeshMapper< M >:: Self* cpm::VTK::OpenGLMeshMapper< M >:: New( ) { return( new Self( ) ); } // ------------------------------------------------------------------------- template< class M > void cpm::VTK::OpenGLMeshMapper< M >:: RenderPiece( vtkRenderer* aren, vtkActor* act ) { vtkOpenGLClearErrorMacro( ); // Is the renderer correctly initialized? if( aren->GetRenderWindow( )->CheckAbortStatus( ) ) return; // Get input mesh ( and check it ) M* in = this->GetInput( ); if( !in ) { vtkErrorMacro( << "No input!" ); return; } // fi unsigned long numPts = in->GetNumberOfPoints( ); if( numPts == 0 ) { vtkDebugMacro( << "No points!" ); return; } // fi // Update input, if needed this->InvokeEvent( vtkCommand::StartEvent, NULL ); if( !this->Static ) in->Update( ); this->InvokeEvent( vtkCommand::EndEvent, NULL ); // Update some visualization objects if( !this->LookupTable ) this->CreateDefaultLookupTable( ); aren->GetRenderWindow( )->MakeCurrent( ); // Check clipping planes int numClipPlanes = this->GetNumberOfClippingPlanes( ); if( numClipPlanes > 6 ) { vtkErrorMacro( << "OpenGL has a limit of 6 clipping planes" ); numClipPlanes = 6; } // fi // Add all the clipping planes double eq[ 4 ]; GLenum clipPlaneId; for( int i = 0; i < numClipPlanes; i++ ) { this->GetClippingPlaneInDataCoords( act->GetMatrix( ), i, eq ); clipPlaneId = static_cast< GLenum >( GL_CLIP_PLANE0 + i ); glEnable( clipPlaneId ); glClipPlane( clipPlaneId, eq ); } // rof // Configure opacity this->MapScalars( act->GetProperty( )->GetOpacity( ) ); // Configure textures if( this->ColorTextureMap ) { /* TODO if( !this->InternalColorTexture ) { this->InternalColorTexture = vtkSmartPointer< vtkOpenGLTexture >::New( ); this->InternalColorTexture->RepeatOff( ); } // fi this->InternalColorTexture->SetInputData( this->ColorTextureMap ); */ // Keep color from interacting with texture. float info[ 4 ] = { float( 1 ), float( 1 ), float( 1 ), float( 1 ) }; glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, info ); } // fi int noAbort = 1; bool renderNeeded = !this->ImmediateModeRendering; renderNeeded &= !this->GetGlobalImmediateModeRendering( ); // Something has changed in the pipeline? if( this->GetMTime( ) > this->BuildTime || in->GetMTime( ) > this->BuildTime || act->GetProperty( )->GetMTime( ) > this->BuildTime || aren->GetRenderWindow( ) != this->LastWindow ) { // Update visualization objects this->ReleaseGraphicsResources( aren->GetRenderWindow( ) ); this->LastWindow = aren->GetRenderWindow( ); if( renderNeeded ) { // Load textures /* TODO if( this->ColorTextureMap ) this->InternalColorTexture->Load( aren ); */ // Time the actual drawing this->Timer->StartTimer( ); noAbort = this->Draw( aren, act ); this->Timer->StopTimer( ); } // fi if( noAbort ) this->BuildTime.Modified( ); } else { // If nothing changed, just draw the mapped mesh if( renderNeeded ) { // Load textures /* TODO if( this->ColorTextureMap ) this->InternalColorTexture->Load( aren ); */ // Time the actual drawing this->Timer->StartTimer( ); this->Draw( aren, act ); this->Timer->StopTimer( ); } // fi } // fi // if we are in immediate mode rendering we always // want to draw the primitives here if( !renderNeeded ) { // Load textures /* TODO if( this->ColorTextureMap ) this->InternalColorTexture->Load( aren ); */ // Time the actual drawing this->Timer->StartTimer( ); this->Draw( aren, act ); this->Timer->StopTimer( ); } // fi this->TimeToDraw = this->Timer->GetElapsedTime( ); // If the timer is not accurate enough, set it to a small // time so that it is not zero if( this->TimeToDraw == double( 0 ) ) this->TimeToDraw = double( 1e-3 ); for( int c = 0; c < numClipPlanes; c++ ) { GLenum clipPlaneId = static_cast< GLenum >( GL_CLIP_PLANE0 + c ); glDisable( clipPlaneId ); } // rof vtkOpenGLCheckErrorMacro( "failed after RenderPiece\n" ); } // ------------------------------------------------------------------------- template< class M > void cpm::VTK::OpenGLMeshMapper< M >:: ReleaseGraphicsResources( vtkWindow* win ) { if( win && win->GetMapped( ) ) { win->MakeCurrent( ); vtkOpenGLCheckErrorMacro( "failed after ReleaseGraphicsResources" ); } // fi this->LastWindow = NULL; // TAKEN FROM BASIC vtkOpenGLPolyDataMapper: // We may not want to do this here. /* TODO if( this->InternalColorTexture ) this->InternalColorTexture->ReleaseGraphicsResources( win ); */ } // ------------------------------------------------------------------------- template< class M > int cpm::VTK::OpenGLMeshMapper< M >:: Draw( vtkRenderer* aren, vtkActor* act ) { vtkOpenGLClearErrorMacro( ); // First and second initialization check if( this->FirstRendering ) this->FirstRendering = !( this->_ConfigureOpenGL( ) ); if( this->FirstRendering ) return( 0 ); vtkOpenGLRenderer* ren = static_cast< vtkOpenGLRenderer* >( aren ); int rep, interpolation; float tran; vtkProperty* prop; vtkUnsignedCharArray* c = NULL; int tDim; int noAbort = 1; M* input = this->GetInput( ); int cellScalars = 0; vtkIdType cellNum = 0; int cellNormals; int resolve = 0, zResolve = 0; double zRes = 0.0; // get the property prop = act->GetProperty( ); // get the transparency tran = prop->GetOpacity( ); // if the primitives are invisable then get out of here if( tran <= 0.0 ) return( noAbort ); // get the representation ( e.g., surface / wireframe / points ) rep = prop->GetRepresentation( ); // get the shading interpolation interpolation = prop->GetInterpolation( ); // are they cell or point scalars if( this->Colors ) { c = this->Colors; if( ( this->ScalarMode == VTK_SCALAR_MODE_USE_CELL_DATA || this->ScalarMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA || this->ScalarMode == VTK_SCALAR_MODE_USE_FIELD_DATA || !input->GetPointData( ) ) && this->ScalarMode != VTK_SCALAR_MODE_USE_POINT_FIELD_DATA ) cellScalars = 1; } // fi cellNormals = 1; // if we are doing vertex colors then set lmcolor to adjust // the current materials ambient and diffuse values using // vertex color commands otherwise tell it not to. glDisable( GL_COLOR_MATERIAL ); if( c ) { GLenum lmcolorMode; if( this->ScalarMaterialMode == VTK_MATERIALMODE_DEFAULT ) { if( prop->GetAmbient( ) > prop->GetDiffuse( ) ) lmcolorMode = GL_AMBIENT; else lmcolorMode = GL_DIFFUSE; } else if( this->ScalarMaterialMode == VTK_MATERIALMODE_AMBIENT_AND_DIFFUSE ) lmcolorMode = GL_AMBIENT_AND_DIFFUSE; else if( this->ScalarMaterialMode == VTK_MATERIALMODE_AMBIENT ) lmcolorMode = GL_AMBIENT; else // if( this->ScalarMaterialMode == VTK_MATERIALMODE_DIFFUSE ) lmcolorMode = GL_DIFFUSE; glColorMaterial( GL_FRONT_AND_BACK, lmcolorMode ); glEnable( GL_COLOR_MATERIAL ); } // fi unsigned long idx = 0; if( c ) { idx |= CPM_VTK_PDM_COLORS; if( c->GetName( ) ) idx |= CPM_VTK_PDM_OPAQUE_COLORS; } // fi if( cellScalars ) idx |= CPM_VTK_PDM_CELL_COLORS; if( cellNormals ) idx |= CPM_VTK_PDM_CELL_NORMALS; if( this->ScalarMode == VTK_SCALAR_MODE_USE_FIELD_DATA ) idx |= CPM_VTK_PDM_USE_FIELD_DATA; // store the types in the index if( typeid( typename M::CoordRepType ) == typeid( float ) ) idx |= CPM_VTK_PDM_POINT_TYPE_FLOAT; else if( typeid( typename M::CoordRepType ) == typeid( double ) ) idx |= CPM_VTK_PDM_POINT_TYPE_DOUBLE; if( typeid( typename M::CoordRepType ) == typeid( float ) ) idx |= CPM_VTK_PDM_NORMAL_TYPE_FLOAT; else if( typeid( typename M::CoordRepType ) == typeid( double ) ) idx |= CPM_VTK_PDM_NORMAL_TYPE_DOUBLE; if( this->GetResolveCoincidentTopology( ) ) { resolve = 1; if( this->GetResolveCoincidentTopology( ) == VTK_RESOLVE_SHIFT_ZBUFFER ) { zResolve = 1; zRes = this->GetResolveCoincidentTopologyZShift( ); } else { #ifdef GL_VERSION_1_1 double f, u; glEnable( GL_POLYGON_OFFSET_FILL ); this->GetResolveCoincidentTopologyPolygonOffsetParameters( f, u ); glPolygonOffset( f, u ); #endif } // fi } // fi // we need to know the total number of cells so that we can // report progress this->TotalCells = input->GetNumberOfCells( ); // Actual render if( this->VBOSupported ) { glBindBuffer( GL_ARRAY_BUFFER, GLuint( this->VBOID1 ) ); void* ptr = glMapBuffer( GL_ARRAY_BUFFER, GL_READ_WRITE ); if( ptr != NULL ) { // Copy source points to OpenGL buffer const TPoint* src = input->GetPoints( )->CastToSTLContainer( ).data( ); TPoint* dest = reinterpret_cast< TPoint* >( ptr ); if( dest != NULL ) std::copy( src, src + input->GetNumberOfPoints( ), dest ); glUnmapBuffer( GL_ARRAY_BUFFER ); } // fi std::size_t pSize = input->GetNumberOfPoints( ) * sizeof( TPoint ); // Bind vertices, normals and indices glNormalPointer( this->ElementValueType, 0, ( void* )( pSize ) ); glVertexPointer( 3, this->ElementValueType, 0, 0 ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, GLuint( this->VBOID2 ) ); // Prepare to render polygons glEnableClientState( GL_NORMAL_ARRAY ); glEnableClientState( GL_VERTEX_ARRAY ); // Iterate over all input cells unsigned int accum = 0; const TCellsContainer* cells = input->GetCells( ); TCellIt cIt = cells->Begin( ); for( unsigned int nCell = 0; cIt != cells->End( ); nCell++, cIt++ ) { const TCell* cell = cIt.Value( ); unsigned int nPoints = this->Sizes[ nCell ]; // Infere rendering mode GLenum mode; switch( prop->GetRepresentation( ) ) { case VTK_SURFACE: { switch( nPoints ) { case 1: mode = GL_POINTS; break; case 2: mode = GL_LINES; break; case 3: mode = GL_TRIANGLES; break; case 4: mode = GL_QUADS; break; default: mode = GL_POLYGON; break; } // hctiws // TODO: GL_LINE_STRIP, // TODO: GL_LINE_LOOP, // TODO: GL_TRIANGLE_STRIP, // TODO: GL_TRIANGLE_FAN, // TODO: GL_QUAD_STRIP, } break; case VTK_WIREFRAME: mode = GL_LINE_LOOP; break; case VTK_POINTS: default: mode = GL_POINTS; break; } // hctiws // Actual draw all elements if( nPoints < 3 ) glDisable( GL_LIGHTING ); if( nPoints == 2 && zResolve ) glDepthRange( zRes, 1. ); glDrawElements( mode, nPoints, this->IndexElementType, ( GLuint* )( 0 ) + accum ); accum += nPoints; if( nPoints < 3 ) glEnable( GL_LIGHTING ); } // rof glDisableClientState( GL_VERTEX_ARRAY ); glDisableClientState( GL_NORMAL_ARRAY ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); } else { std::cout << "Not VBO rendering!!!" << std::endl; } // fi if( resolve ) { if( zResolve ) glDepthRange( 0., 1. ); else { #ifdef GL_VERSION_1_1 glDisable( GL_POLYGON_OFFSET_FILL ); #endif } // fi } // fi vtkOpenGLCheckErrorMacro( "failed after Draw" ); this->UpdateProgress( 1.0 ); return( noAbort ); } // ------------------------------------------------------------------------- template< class M > cpm::VTK::OpenGLMeshMapper< M >:: OpenGLMeshMapper( ) : Superclass( ), TotalCells( 0 ), FirstRendering( true ), VBOID1( 0 ), VBOID2( 0 ) { // Infere index element type switch( sizeof( TIndex ) ) { case 1 : this->IndexElementType = GL_UNSIGNED_BYTE; break; case 2 : this->IndexElementType = GL_UNSIGNED_SHORT; break; case 4 : this->IndexElementType = GL_UNSIGNED_INT; break; default: this->IndexElementType = GL_UNSIGNED_BYTE; break; } // hctiws // Infere point value type if( typeid( TScalar ) == typeid( float ) ) this->ElementValueType = GL_FLOAT; else this->ElementValueType = GL_DOUBLE; } // ------------------------------------------------------------------------- template< class M > cpm::VTK::OpenGLMeshMapper< M >:: ~OpenGLMeshMapper( ) { if( this->LastWindow ) this->ReleaseGraphicsResources( this->LastWindow ); if( this->VBOSupported ) { GLuint id1 = GLuint( this->VBOID1 ); GLuint id2 = GLuint( this->VBOID2 ); if( id1 != GLuint( 0 ) ) glDeleteBuffers( 1, &id1 ); if( id2 != GLuint( 0 ) ) glDeleteBuffers( 1, &id2 ); this->VBOID1 = this->VBOID2 = 0; } // fi } // ------------------------------------------------------------------------- template< class M > bool cpm::VTK::OpenGLMeshMapper< M >:: _ConfigureOpenGL( ) { M* input = this->GetInput( ); if( input == NULL ) return( false ); // Check if VBO ( Vertex Buffer Object ) is supported std::string str = ( const char* )( glGetString( GL_EXTENSIONS ) ); this->VBOSupported = ( str.find( "GL_ARB_vertex_buffer_object" ) != std::string::npos ); if( this->VBOSupported ) { // Create points and normals buffers GLuint id1; std::size_t pSize = input->GetNumberOfPoints( ) * sizeof( TPoint ); std::size_t nSize = input->GetPointNormalsContainer( ).size( ) * sizeof( TVector ); const TPoint* verts = input->GetPoints( )->CastToSTLContainer( ).data( ); const TVector* norms = input->GetPointNormalsContainer( ).data( ); glGenBuffers( 1, &id1 ); glBindBuffer( GL_ARRAY_BUFFER, id1 ); glBufferData( GL_ARRAY_BUFFER, pSize + nSize, 0, GL_STREAM_DRAW ); glBufferSubData( GL_ARRAY_BUFFER, 0, pSize, verts ); glBufferSubData( GL_ARRAY_BUFFER, pSize, nSize, norms ); this->VBOID1 = ( unsigned int )( id1 ); // Create indices buffer const TCellsContainer* cells = input->GetCells( ); if( cells == NULL ) { itkExceptionMacro( << "This QuadEdgeMesh does not have any cells!" ); } // fi TCellIt cIt; unsigned int cellPointsCount = 0; this->Sizes.clear( ); for( cIt = cells->Begin( ); cIt != cells->End( ); cIt++ ) { this->Sizes.push_back( cIt.Value( )->GetNumberOfPoints( ) ); cellPointsCount += this->Sizes.back( ); } // rof this->Indices.resize( cellPointsCount ); unsigned int indId = 0; for( cIt = cells->Begin( ); cIt != cells->End( ); cIt++ ) { const typename M::TQuadEdgeCell* cell = dynamic_cast< const typename M::TQuadEdgeCell* >( cIt.Value( ) ); const typename M::TPrimalEdge* edge = cell->GetEntryPrimalEdge( ); typename M::TPrimalEdge::ConstIterator iIt = edge->BeginLnext( ); for( ; iIt != edge->EndLnext( ); ++iIt ) this->Indices[ indId++ ] = ( *iIt )->GetOrigin( ); } // fi // Attach index buffer to VBO std::size_t iSize = std::size_t( this->Indices.size( ) ); iSize *= sizeof( TIndex ); const unsigned int* indices = this->Indices.data( ); GLuint id2; glGenBuffers( 1, &id2 ); glBindBuffer( GL_ARRAY_BUFFER, id2 ); glBufferData( GL_ARRAY_BUFFER, iSize, indices, GL_STATIC_DRAW ); int bSize; glGetBufferParameteriv( GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &bSize ); if( iSize != bSize ) { glDeleteBuffers( 1, &id2 ); id2 = 0; vtkErrorMacro( << "Data size mismatch with input array" ); } // fi this->VBOID2 = ( unsigned int )( id2 ); } // fi return( true ); } // ------------------------------------------------------------------------- #include #include using namespace cpm::DataStructures; using namespace cpm::VTK; template class OpenGLMeshMapper< QuadEdgeMesh< float, 2 > >; template class OpenGLMeshMapper< QuadEdgeMesh< float, 3 > >; template class OpenGLMeshMapper< QuadEdgeMesh< double, 2 > >; template class OpenGLMeshMapper< QuadEdgeMesh< double, 3 > >; template class OpenGLMeshMapper< SimplexMesh< float, 2 > >; template class OpenGLMeshMapper< SimplexMesh< float, 3 > >; template class OpenGLMeshMapper< SimplexMesh< double, 2 > >; template class OpenGLMeshMapper< SimplexMesh< double, 3 > >; // eof - $RCSfile$