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