]> Creatis software - cpMesh.git/blob - lib/cpm/VTK/OpenGLMeshMapper.cxx
First commit
[cpMesh.git] / lib / cpm / VTK / OpenGLMeshMapper.cxx
1 #include <cpm/VTK/OpenGLMeshMapper.h>
2
3 #include <algorithm>
4 #include <string>
5
6 #include <vtkCommand.h>
7 #include <vtkImageData.h>
8 #include <vtkOpenGLRenderer.h>
9 #include <vtkProperty.h>
10 #include <vtkTimerLog.h>
11 #include <vtkUnsignedCharArray.h>
12
13 #include <vtkOpenGL.h>
14 #include <vtkOpenGLError.h>
15 #define GL_GLEXT_PROTOTYPES
16 #include <GL/glext.h>
17
18 // some definitions for what the polydata has in it
19 #define CPM_VTK_PDM_NORMALS            0x0001
20 #define CPM_VTK_PDM_COLORS             0x0002
21 #define CPM_VTK_PDM_TCOORDS            0x0004
22 #define CPM_VTK_PDM_CELL_COLORS        0x0008
23 #define CPM_VTK_PDM_CELL_NORMALS       0x0010
24 #define CPM_VTK_PDM_POINT_TYPE_FLOAT   0x0020
25 #define CPM_VTK_PDM_POINT_TYPE_DOUBLE  0x0040
26 #define CPM_VTK_PDM_NORMAL_TYPE_FLOAT  0x0080
27 #define CPM_VTK_PDM_NORMAL_TYPE_DOUBLE 0x0100
28 #define CPM_VTK_PDM_TCOORD_TYPE_FLOAT  0x0200
29 #define CPM_VTK_PDM_TCOORD_TYPE_DOUBLE 0x0400
30 #define CPM_VTK_PDM_TCOORD_1D          0x0800
31 #define CPM_VTK_PDM_OPAQUE_COLORS      0x1000
32 #define CPM_VTK_PDM_USE_FIELD_DATA     0x2000
33
34 // -------------------------------------------------------------------------
35 template< class M >
36 typename cpm::VTK::OpenGLMeshMapper< M >::
37 Self* cpm::VTK::OpenGLMeshMapper< M >::
38 New( )
39 {
40   return( new Self( ) );
41 }
42
43 // -------------------------------------------------------------------------
44 template< class M >
45 void cpm::VTK::OpenGLMeshMapper< M >::
46 RenderPiece( vtkRenderer* aren, vtkActor* act )
47 {
48   vtkOpenGLClearErrorMacro( );
49
50   // Is the renderer correctly initialized?
51   if( aren->GetRenderWindow( )->CheckAbortStatus( ) )
52     return;
53
54   // Get input mesh ( and check it )
55   M* in = this->GetInput( );
56   if( !in )
57   {
58     vtkErrorMacro( << "No input!" );
59     return;
60
61   } // fi
62   unsigned long numPts = in->GetNumberOfPoints( );
63   if( numPts == 0 )
64   {
65     vtkDebugMacro( << "No points!" );
66     return;
67
68   } // fi
69
70   // Update input, if needed
71   this->InvokeEvent( vtkCommand::StartEvent, NULL );
72   if( !this->Static )
73     in->Update( );
74   this->InvokeEvent( vtkCommand::EndEvent, NULL );
75
76   // Update some visualization objects
77   if( !this->LookupTable )
78     this->CreateDefaultLookupTable( );
79   aren->GetRenderWindow( )->MakeCurrent( );
80
81   // Check clipping planes
82   int numClipPlanes = this->GetNumberOfClippingPlanes( );
83   if( numClipPlanes > 6 )
84   {
85     vtkErrorMacro( << "OpenGL has a limit of 6 clipping planes" );
86     numClipPlanes = 6;
87
88   } // fi
89
90   // Add all the clipping planes
91   double eq[ 4 ];
92   GLenum clipPlaneId;
93   for( int i = 0; i < numClipPlanes; i++ )
94   {
95     this->GetClippingPlaneInDataCoords( act->GetMatrix( ), i, eq );
96
97     clipPlaneId = static_cast< GLenum >( GL_CLIP_PLANE0 + i );
98     glEnable( clipPlaneId );
99     glClipPlane( clipPlaneId, eq );
100
101   } // rof
102
103   // Configure opacity
104   this->MapScalars( act->GetProperty( )->GetOpacity( ) );
105
106   // Configure textures
107   if( this->ColorTextureMap )
108   {
109     /* TODO
110       if( !this->InternalColorTexture )
111       {
112       this->InternalColorTexture =
113       vtkSmartPointer< vtkOpenGLTexture >::New( );
114       this->InternalColorTexture->RepeatOff( );
115
116       } // fi
117       this->InternalColorTexture->SetInputData( this->ColorTextureMap );
118     */
119
120     // Keep color from interacting with texture.
121     float info[ 4 ] = { float( 1 ), float( 1 ), float( 1 ), float( 1 ) };
122     glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, info );
123
124   } // fi
125
126   int noAbort = 1;
127   bool renderNeeded = !this->ImmediateModeRendering;
128   renderNeeded     &= !this->GetGlobalImmediateModeRendering( );
129
130   // Something has changed in the pipeline?
131   if( 
132     this->GetMTime( ) > this->BuildTime ||
133     in->GetMTime( ) > this->BuildTime ||
134     act->GetProperty( )->GetMTime( ) > this->BuildTime ||
135     aren->GetRenderWindow( ) != this->LastWindow
136     )
137   {
138     // Update visualization objects
139     this->ReleaseGraphicsResources( aren->GetRenderWindow( ) );
140     this->LastWindow = aren->GetRenderWindow( );
141
142     if( renderNeeded )
143     {
144       // Load textures
145       /* TODO
146          if( this->ColorTextureMap )
147          this->InternalColorTexture->Load( aren );
148       */
149
150       // Time the actual drawing
151       this->Timer->StartTimer( );
152       noAbort = this->Draw( aren, act );
153       this->Timer->StopTimer( );
154
155     } // fi
156
157     if( noAbort )
158       this->BuildTime.Modified( );
159   }
160   else
161   {
162     // If nothing changed, just draw the mapped mesh
163     if( renderNeeded )
164     {
165       // Load textures
166       /* TODO
167          if( this->ColorTextureMap )
168          this->InternalColorTexture->Load( aren );
169       */
170
171       // Time the actual drawing
172       this->Timer->StartTimer( );
173       this->Draw( aren, act );
174       this->Timer->StopTimer( );
175
176     } // fi
177
178   } // fi
179
180   // if we are in immediate mode rendering we always
181   // want to draw the primitives here
182   if( !renderNeeded )
183   {
184     // Load textures
185     /* TODO
186        if( this->ColorTextureMap )
187        this->InternalColorTexture->Load( aren );
188     */
189
190     // Time the actual drawing
191     this->Timer->StartTimer( );
192     this->Draw( aren, act );
193     this->Timer->StopTimer( );
194
195   } // fi
196   this->TimeToDraw = this->Timer->GetElapsedTime( );
197
198   // If the timer is not accurate enough, set it to a small
199   // time so that it is not zero
200   if( this->TimeToDraw == double( 0 ) )
201     this->TimeToDraw = double( 1e-3 );
202
203   for( int c = 0; c < numClipPlanes; c++ )
204   {
205     GLenum clipPlaneId = static_cast< GLenum >( GL_CLIP_PLANE0 + c );
206     glDisable( clipPlaneId );
207
208   } // rof
209   vtkOpenGLCheckErrorMacro( "failed after RenderPiece\n" );
210 }
211
212 // -------------------------------------------------------------------------
213 template< class M >
214 void cpm::VTK::OpenGLMeshMapper< M >::
215 ReleaseGraphicsResources( vtkWindow* win )
216 {
217   if( win && win->GetMapped( ) )
218   {
219     win->MakeCurrent( );
220     vtkOpenGLCheckErrorMacro( "failed after ReleaseGraphicsResources" );
221
222   } // fi
223   this->LastWindow = NULL;
224
225   // TAKEN FROM BASIC vtkOpenGLPolyDataMapper:
226   // We may not want to do this here.
227   /* TODO
228      if( this->InternalColorTexture )
229      this->InternalColorTexture->ReleaseGraphicsResources( win );
230   */
231 }
232
233 // -------------------------------------------------------------------------
234 template< class M >
235 int cpm::VTK::OpenGLMeshMapper< M >::
236 Draw( vtkRenderer* aren, vtkActor* act )
237 {
238   vtkOpenGLClearErrorMacro( );
239
240   // First and second initialization check
241   if( this->FirstRendering )
242     this->FirstRendering = !( this->_ConfigureOpenGL( ) );
243   if( this->FirstRendering )
244     return( 0 );
245
246   vtkOpenGLRenderer* ren = static_cast< vtkOpenGLRenderer* >( aren );
247   int rep, interpolation;
248   float tran;
249   vtkProperty* prop;
250   vtkUnsignedCharArray* c = NULL;
251   int tDim;
252   int noAbort = 1;
253   M* input = this->GetInput( );
254   int cellScalars = 0;
255   vtkIdType cellNum = 0;
256   int cellNormals;
257   int resolve = 0, zResolve = 0;
258   double zRes = 0.0;
259
260   // get the property
261   prop = act->GetProperty( );
262
263   // get the transparency
264   tran = prop->GetOpacity( );
265
266   // if the primitives are invisable then get out of here
267   if( tran <= 0.0 )
268     return( noAbort );
269
270   // get the representation ( e.g., surface / wireframe / points )
271   rep = prop->GetRepresentation( );
272
273   // get the shading interpolation
274   interpolation = prop->GetInterpolation( );
275
276   // are they cell or point scalars
277   if( this->Colors )
278   {
279     c = this->Colors;
280     if( 
281       ( 
282         this->ScalarMode == VTK_SCALAR_MODE_USE_CELL_DATA ||
283         this->ScalarMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA ||
284         this->ScalarMode == VTK_SCALAR_MODE_USE_FIELD_DATA ||
285         !input->GetPointData( )
286         ) &&
287       this->ScalarMode != VTK_SCALAR_MODE_USE_POINT_FIELD_DATA
288       )
289       cellScalars = 1;
290
291   } // fi
292
293   cellNormals = 1;
294
295   // if we are doing vertex colors then set lmcolor to adjust
296   // the current materials ambient and diffuse values using
297   // vertex color commands otherwise tell it not to.
298   glDisable( GL_COLOR_MATERIAL );
299   if( c )
300   {
301     GLenum lmcolorMode;
302     if( this->ScalarMaterialMode == VTK_MATERIALMODE_DEFAULT )
303     {
304       if( prop->GetAmbient( ) > prop->GetDiffuse( ) )
305         lmcolorMode = GL_AMBIENT;
306       else
307         lmcolorMode = GL_DIFFUSE;
308     }
309     else if( this->ScalarMaterialMode == VTK_MATERIALMODE_AMBIENT_AND_DIFFUSE )
310       lmcolorMode = GL_AMBIENT_AND_DIFFUSE;
311     else if( this->ScalarMaterialMode == VTK_MATERIALMODE_AMBIENT )
312       lmcolorMode = GL_AMBIENT;
313     else // if( this->ScalarMaterialMode == VTK_MATERIALMODE_DIFFUSE )
314       lmcolorMode = GL_DIFFUSE;
315     glColorMaterial( GL_FRONT_AND_BACK, lmcolorMode );
316     glEnable( GL_COLOR_MATERIAL );
317
318   } // fi
319
320   unsigned long idx = 0;
321   if( c )
322   {
323     idx |= CPM_VTK_PDM_COLORS;
324     if( c->GetName( ) )
325       idx |= CPM_VTK_PDM_OPAQUE_COLORS;
326   } // fi
327   if( cellScalars )
328     idx |= CPM_VTK_PDM_CELL_COLORS;
329   if( cellNormals )
330     idx |= CPM_VTK_PDM_CELL_NORMALS;
331   if( this->ScalarMode == VTK_SCALAR_MODE_USE_FIELD_DATA )
332     idx |= CPM_VTK_PDM_USE_FIELD_DATA;
333
334   // store the types in the index
335   if( typeid( typename M::CoordRepType ) == typeid( float ) )
336     idx |= CPM_VTK_PDM_POINT_TYPE_FLOAT;
337   else if( typeid( typename M::CoordRepType ) == typeid( double ) )
338     idx |= CPM_VTK_PDM_POINT_TYPE_DOUBLE;
339
340   if( typeid( typename M::CoordRepType ) == typeid( float ) )
341     idx |= CPM_VTK_PDM_NORMAL_TYPE_FLOAT;
342   else if( typeid( typename M::CoordRepType ) == typeid( double ) )
343     idx |= CPM_VTK_PDM_NORMAL_TYPE_DOUBLE;
344
345   if( this->GetResolveCoincidentTopology( ) )
346   {
347     resolve = 1;
348     if( this->GetResolveCoincidentTopology( ) == VTK_RESOLVE_SHIFT_ZBUFFER )
349     {
350       zResolve = 1;
351       zRes = this->GetResolveCoincidentTopologyZShift( );
352     }
353     else
354     {
355 #ifdef GL_VERSION_1_1
356       double f, u;
357       glEnable( GL_POLYGON_OFFSET_FILL );
358       this->GetResolveCoincidentTopologyPolygonOffsetParameters( f, u );
359       glPolygonOffset( f, u );
360 #endif
361     } // fi
362
363   } // fi
364
365   // we need to know the total number of cells so that we can
366   // report progress
367   this->TotalCells = input->GetNumberOfCells( );
368
369   // Actual render
370   if( this->VBOSupported )
371   {
372     glBindBuffer( GL_ARRAY_BUFFER, GLuint( this->VBOID1 ) );
373
374     void* ptr = glMapBuffer( GL_ARRAY_BUFFER, GL_READ_WRITE );
375     if( ptr != NULL )
376     {
377       // Copy source points to OpenGL buffer
378       const TPoint* src =
379         input->GetPoints( )->CastToSTLContainer( ).data( );
380       TPoint* dest = reinterpret_cast< TPoint* >( ptr );
381       if( dest != NULL )
382         std::copy( src, src + input->GetNumberOfPoints( ), dest );
383       glUnmapBuffer( GL_ARRAY_BUFFER );
384
385     } // fi
386
387     std::size_t pSize = input->GetNumberOfPoints( ) * sizeof( TPoint );
388
389     // Bind vertices, normals and indices
390     glNormalPointer( this->ElementValueType, 0, ( void* )( pSize ) );
391     glVertexPointer( 3, this->ElementValueType, 0, 0 );
392     glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, GLuint( this->VBOID2 ) );
393
394     // Prepare to render polygons
395     glEnableClientState( GL_NORMAL_ARRAY );
396     glEnableClientState( GL_VERTEX_ARRAY );
397
398     // Iterate over all input cells
399     unsigned int accum = 0;
400     const TCellsContainer* cells = input->GetCells( );
401     TCellIt cIt = cells->Begin( );
402     for( unsigned int nCell = 0; cIt != cells->End( ); nCell++, cIt++ )
403     {
404       const TCell* cell = cIt.Value( );
405       unsigned int nPoints = this->Sizes[ nCell ];
406
407       // Infere rendering mode
408       GLenum mode;
409       switch( prop->GetRepresentation( ) )
410       {
411       case VTK_SURFACE:
412       {
413         switch( nPoints )
414         {
415         case  1: mode = GL_POINTS;    break;
416         case  2: mode = GL_LINES;     break;
417         case  3: mode = GL_TRIANGLES; break;
418         case  4: mode = GL_QUADS;     break;
419         default: mode = GL_POLYGON;   break;
420         } // hctiws
421         // TODO: GL_LINE_STRIP,
422         // TODO: GL_LINE_LOOP,
423         // TODO: GL_TRIANGLE_STRIP,
424         // TODO: GL_TRIANGLE_FAN,
425         // TODO: GL_QUAD_STRIP,
426       }
427       break;
428       case VTK_WIREFRAME: mode = GL_LINE_LOOP; break;
429       case VTK_POINTS: default: mode = GL_POINTS; break;
430       } // hctiws
431
432       // Actual draw all elements
433       if( nPoints < 3 )
434         glDisable( GL_LIGHTING );
435
436       if( nPoints == 2 && zResolve )
437         glDepthRange( zRes, 1. );
438
439       glDrawElements( 
440         mode, nPoints, this->IndexElementType, ( GLuint* )( 0 ) + accum
441         );
442       accum += nPoints;
443
444       if( nPoints < 3 )
445         glEnable( GL_LIGHTING );
446
447     } // rof
448
449     glDisableClientState( GL_VERTEX_ARRAY );
450     glDisableClientState( GL_NORMAL_ARRAY );
451
452     glBindBuffer( GL_ARRAY_BUFFER, 0 );
453     glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
454   }
455   else
456   {
457     std::cout << "Not VBO rendering!!!" << std::endl;
458
459   } // fi
460
461   if( resolve )
462   {
463     if( zResolve )
464       glDepthRange( 0., 1. );
465     else
466     {
467 #ifdef GL_VERSION_1_1
468       glDisable( GL_POLYGON_OFFSET_FILL );
469 #endif
470     } // fi
471
472   } // fi
473   vtkOpenGLCheckErrorMacro( "failed after Draw" );
474   this->UpdateProgress( 1.0 );
475   return( noAbort );
476 }
477
478 // -------------------------------------------------------------------------
479 template< class M >
480 cpm::VTK::OpenGLMeshMapper< M >::
481 OpenGLMeshMapper( )
482   : Superclass( ),
483     TotalCells( 0 ),
484     FirstRendering( true ),
485     VBOID1( 0 ),
486     VBOID2( 0 )
487 {
488   // Infere index element type
489   switch( sizeof( TIndex ) )
490   {
491   case 1 : this->IndexElementType = GL_UNSIGNED_BYTE;  break;
492   case 2 : this->IndexElementType = GL_UNSIGNED_SHORT; break;
493   case 4 : this->IndexElementType = GL_UNSIGNED_INT;   break;
494   default: this->IndexElementType = GL_UNSIGNED_BYTE;  break;
495   } // hctiws
496
497   // Infere point value type
498   if( typeid( TScalar ) == typeid( float ) )
499     this->ElementValueType = GL_FLOAT;
500   else
501     this->ElementValueType = GL_DOUBLE;
502 }
503
504 // -------------------------------------------------------------------------
505 template< class M >
506 cpm::VTK::OpenGLMeshMapper< M >::
507 ~OpenGLMeshMapper( )
508 {
509   if( this->LastWindow )
510     this->ReleaseGraphicsResources( this->LastWindow );
511   if( this->VBOSupported )
512   {
513     GLuint id1 = GLuint( this->VBOID1 );
514     GLuint id2 = GLuint( this->VBOID2 );
515     if( id1 != GLuint( 0 ) ) glDeleteBuffers( 1, &id1 );
516     if( id2 != GLuint( 0 ) ) glDeleteBuffers( 1, &id2 );
517     this->VBOID1 = this->VBOID2 = 0;
518
519   } // fi
520 }
521
522 // -------------------------------------------------------------------------
523 template< class M >
524 bool cpm::VTK::OpenGLMeshMapper< M >::
525 _ConfigureOpenGL( )
526 {
527   M* input = this->GetInput( );
528   if( input == NULL )
529     return( false );
530
531   // Check if VBO ( Vertex Buffer Object ) is supported
532   std::string str = ( const char* )( glGetString( GL_EXTENSIONS ) );
533   this->VBOSupported =
534     ( str.find( "GL_ARB_vertex_buffer_object" ) != std::string::npos );
535
536   if( this->VBOSupported )
537   {
538     // Create points and normals buffers
539     GLuint id1;
540     std::size_t pSize = input->GetNumberOfPoints( ) * sizeof( TPoint );
541     std::size_t nSize =
542       input->GetPointNormalsContainer( ).size( ) * sizeof( TVector );
543     const TPoint* verts =
544       input->GetPoints( )->CastToSTLContainer( ).data( );
545     const TVector* norms = input->GetPointNormalsContainer( ).data( );
546     glGenBuffers( 1, &id1 );
547     glBindBuffer( GL_ARRAY_BUFFER, id1 );
548     glBufferData( GL_ARRAY_BUFFER, pSize + nSize, 0, GL_STREAM_DRAW );
549     glBufferSubData( GL_ARRAY_BUFFER, 0, pSize, verts );
550     glBufferSubData( GL_ARRAY_BUFFER, pSize, nSize, norms );
551     this->VBOID1 = ( unsigned int )( id1 );
552
553     // Create indices buffer
554     const TCellsContainer* cells = input->GetCells( );
555     if( cells == NULL )
556     {
557       itkExceptionMacro(
558         << "This QuadEdgeMesh does not have any cells!"
559         );
560
561     } // fi
562
563     TCellIt cIt;
564     unsigned int cellPointsCount = 0;
565     this->Sizes.clear( );
566     for( cIt = cells->Begin( ); cIt != cells->End( ); cIt++ )
567     {
568       this->Sizes.push_back( cIt.Value( )->GetNumberOfPoints( ) );
569       cellPointsCount += this->Sizes.back( );
570
571     } // rof
572     this->Indices.resize( cellPointsCount );
573     unsigned int indId = 0;
574     for( cIt = cells->Begin( ); cIt != cells->End( ); cIt++ )
575     {
576       const typename M::TQuadEdgeCell* cell =
577         dynamic_cast< const typename M::TQuadEdgeCell* >( cIt.Value( ) );
578       const typename M::TPrimalEdge* edge =
579         cell->GetEntryPrimalEdge( );
580       typename M::TPrimalEdge::ConstIterator iIt = edge->BeginLnext( );
581       for( ; iIt != edge->EndLnext( ); ++iIt )
582         this->Indices[ indId++ ] = ( *iIt )->GetOrigin( );
583
584     } // fi
585
586     // Attach index buffer to VBO
587     std::size_t iSize = std::size_t( this->Indices.size( ) );
588     iSize            *= sizeof( TIndex );
589     const unsigned int* indices = this->Indices.data( );
590     GLuint id2;
591     glGenBuffers( 1, &id2 );
592     glBindBuffer( GL_ARRAY_BUFFER, id2 );
593     glBufferData( GL_ARRAY_BUFFER, iSize, indices, GL_STATIC_DRAW );
594
595     int bSize;
596     glGetBufferParameteriv( GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &bSize );
597     if( iSize != bSize )
598     {
599       glDeleteBuffers( 1, &id2 );
600       id2 = 0;
601       vtkErrorMacro( << "Data size mismatch with input array" );
602
603     } // fi
604     this->VBOID2 = ( unsigned int )( id2 );
605
606   } // fi
607   return( true );
608 }
609
610 // -------------------------------------------------------------------------
611 #include <cpm/DataStructures/QuadEdgeMesh.h>
612 #include <cpm/DataStructures/SimplexMesh.h>
613
614 using namespace cpm::DataStructures;
615 using namespace cpm::VTK;
616
617 template class OpenGLMeshMapper< QuadEdgeMesh< float, 2 > >;
618 template class OpenGLMeshMapper< QuadEdgeMesh< float, 3 > >;
619 template class OpenGLMeshMapper< QuadEdgeMesh< double, 2 > >;
620 template class OpenGLMeshMapper< QuadEdgeMesh< double, 3 > >;
621
622 template class OpenGLMeshMapper< SimplexMesh< float, 2 > >;
623 template class OpenGLMeshMapper< SimplexMesh< float, 3 > >;
624 template class OpenGLMeshMapper< SimplexMesh< double, 2 > >;
625 template class OpenGLMeshMapper< SimplexMesh< double, 3 > >;
626
627 // eof - $RCSfile$