Salome HOME
Merge remote-tracking branch 'origin/rnv/vtk_opengl2_backend' into V8_1_BR
[modules/gui.git] / src / VTKViewer / VTKViewer_OpenGLRenderer.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "VTKViewer_OpenGLRenderer.h"
24 #include "VTKViewer_Texture.h"
25
26 #include <vtkCuller.h>
27 #include <vtkLightCollection.h>
28 #include <vtkObjectFactory.h>
29 #include <vtkOpenGLCamera.h>
30 #include <vtkOpenGLLight.h>
31 #include <vtkOpenGLProperty.h>
32 #include <vtkRenderWindow.h>
33 #ifndef VTK_OPENGL2
34 #include <vtkOpenGLExtensionManager.h>
35 #include <vtkgl.h> // vtkgl namespace
36 #endif
37 #include <vtkImageImport.h>
38 #include <vtkPNGWriter.h>
39 #include <vtkOpenGLTexture.h>
40 #include <vtkTimerLog.h>
41 #include <vtkOpenGL.h>
42 #include <vtkObjectFactory.h>
43
44 vtkStandardNewMacro(VTKViewer_OpenGLRenderer);
45
46 VTKViewer_OpenGLRenderer::VTKViewer_OpenGLRenderer()
47 {
48   this->GradientType = HorizontalGradient;
49
50 #ifdef VTK_OPENGL2
51   this->BackgroundProgram        = 0;
52   this->BackgroundVertexShader   = 0;
53   this->BackgroundFragmentShader = 0;
54   this->VertexArrayObject        = 0;
55
56   this->OpenGLHelper.Init();
57 #endif
58 }
59
60 VTKViewer_OpenGLRenderer::~VTKViewer_OpenGLRenderer()
61 {
62 }
63
64 void VTKViewer_OpenGLRenderer::SetGradientType( const int theGradientType )
65 {
66   this->GradientType = theGradientType;
67 }
68
69 void VTKViewer_OpenGLRenderer::Clear(void)
70 {
71 #ifdef VTK_OPENGL2
72   if (this->OpenGLHelper.IsInitialized())
73   {
74     if (this->BackgroundProgram == 0)
75     {
76       std::string filePath = std::string( getenv( "GUI_ROOT_DIR") ) + "/share/salome/resources/gui/Background";
77       if (!this->OpenGLHelper.CreateShaderProgram (filePath,
78                                                    this->BackgroundProgram,
79                                                    this->BackgroundVertexShader,
80                                                    this->BackgroundFragmentShader))
81       {
82         return;
83       }
84       // Get uniform locations.
85       this->OpenGLHelper.vglUseProgramObjectARB (this->BackgroundProgram);
86
87       this->myLocations.UseTexture        = this->OpenGLHelper.vglGetUniformLocationARB (this->BackgroundProgram, "uUseTexture");
88       this->myLocations.BackgroundTexture = this->OpenGLHelper.vglGetUniformLocationARB (this->BackgroundProgram, "uBackgroundTexture");
89
90       this->OpenGLHelper.vglUseProgramObjectARB (0);
91     }
92   }
93 #endif
94
95   GLbitfield clear_mask = 0;
96
97   if( !this->Transparent() )
98   {
99     glClearColor( static_cast<GLclampf>(this->Background[0]),
100                   static_cast<GLclampf>(this->Background[1]),
101                   static_cast<GLclampf>(this->Background[2]),
102                   static_cast<GLclampf>(0.0));
103     clear_mask |= GL_COLOR_BUFFER_BIT;
104   }
105
106   if( !this->GetPreserveDepthBuffer() )
107   {
108     glClearDepth(static_cast<GLclampf>(1.0));
109     clear_mask |= GL_DEPTH_BUFFER_BIT;
110   }
111
112   vtkDebugMacro(<< "glClear\n");
113   glClear(clear_mask);
114
115   // If gradient background is turned on, draw it now.
116   if( !this->Transparent() &&
117       ( this->GradientBackground || this->TexturedBackground ) )
118   {
119     double aTileViewport[4];
120     this->GetRenderWindow()->GetTileViewport( aTileViewport );
121     glPushAttrib( GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_TEXTURE_BIT );
122     glDisable( GL_ALPHA_TEST );
123     glDisable( GL_DEPTH_TEST );
124     glDisable( GL_LIGHTING );
125     glDisable( GL_TEXTURE_1D );
126     glDisable( GL_TEXTURE_2D );
127     glDisable( GL_BLEND );
128
129     GLint oldShadeModel;
130     glGetIntegerv(GL_SHADE_MODEL, &oldShadeModel);
131     glShadeModel( GL_SMOOTH ); // color interpolation
132
133     glMatrixMode( GL_PROJECTION );
134     glPushMatrix();
135     glLoadIdentity();
136     glMatrixMode( GL_MODELVIEW );
137     glPushMatrix();
138     glLoadIdentity();
139
140     glOrtho( aTileViewport[0], aTileViewport[2], aTileViewport[1], aTileViewport[3], -1.0, 1.0 );
141
142     if( this->GradientBackground )
143     {
144       double* corner1 = 0;
145       double* corner2 = 0;
146       double* corner3 = 0;
147       double* corner4 = 0;
148       double dcorner1[3];
149       double dcorner2[3];
150
151       switch( this->GradientType )
152       {
153         case HorizontalGradient:
154           corner1 = this->Background;
155           corner2 = this->Background2;
156           corner3 = this->Background2;
157           corner4 = this->Background;
158           break;
159         case VerticalGradient:
160           corner1 = this->Background2;
161           corner2 = this->Background2;
162           corner3 = this->Background;
163           corner4 = this->Background;
164           break;
165         case FirstDiagonalGradient:
166           corner2 = this->Background2;
167           corner4 = this->Background;
168           dcorner1[0] = dcorner2[0] = 0.5F * ( corner2[0] + corner4[0] );
169           dcorner1[1] = dcorner2[1] = 0.5F * ( corner2[1] + corner4[1] );
170           dcorner1[2] = dcorner2[2] = 0.5F * ( corner2[2] + corner4[2] );
171           corner1 = dcorner1;
172           corner3 = dcorner2;
173           break;
174         case SecondDiagonalGradient:
175           corner1 = this->Background2;  
176           corner3 = this->Background;
177           dcorner1[0] = dcorner2[0] = 0.5F * ( corner1[0] + corner3[0] );
178           dcorner1[1] = dcorner2[1] = 0.5F * ( corner1[1] + corner3[1] );
179           dcorner1[2] = dcorner2[2] = 0.5F * ( corner1[2] + corner3[2] );
180           corner2 = dcorner1;
181           corner4 = dcorner2;
182           break;
183         case FirstCornerGradient:
184           corner1 = this->Background2;
185           corner2 = this->Background2;
186           corner3 = this->Background2;
187           corner4 = this->Background;
188           break;
189         case SecondCornerGradient:
190           corner1 = this->Background2;
191           corner2 = this->Background2;
192           corner3 = this->Background;
193           corner4 = this->Background2;
194           break;
195         case ThirdCornerGradient:
196           corner1 = this->Background2;
197           corner2 = this->Background;
198           corner3 = this->Background2;
199           corner4 = this->Background2;
200           break;
201         case FourthCornerGradient:
202           corner1 = this->Background;
203           corner2 = this->Background2;
204           corner3 = this->Background2;
205           corner4 = this->Background2;
206           break;
207         default: // just in case
208           corner1 = this->Background;
209           corner2 = this->Background;
210           corner3 = this->Background;
211           corner4 = this->Background;
212           break;
213       }
214
215 #ifdef VTK_OPENGL2
216   if (this->OpenGLHelper.IsInitialized())
217   {
218     if (this->VertexArrayObject == 0)
219     {
220       this->OpenGLHelper.vglGenVertexArraysARB (1, &this->VertexArrayObject);
221     }
222
223     this->OpenGLHelper.vglUseProgramObjectARB (this->BackgroundProgram);
224     this->OpenGLHelper.vglBindVertexArrayARB  (this->VertexArrayObject);
225
226     GLfloat data[7 * 4];
227     if( this->GradientType != FirstCornerGradient && this->GradientType != ThirdCornerGradient )
228     {
229       const float tmpData[] = { (float)corner1[0], (float)corner1[1], (float)corner1[2], 1.0f,       -1.0f,  1.0f, 0.0f,
230                                 (float)corner2[0], (float)corner2[1], (float)corner2[2], 1.0f,       -1.0f, -1.0f, 0.0f,
231                                 (float)corner3[0], (float)corner3[1], (float)corner3[2], 1.0f,        1.0f, -1.0f, 0.0f,
232                                 (float)corner4[0], (float)corner4[1], (float)corner4[2], 1.0f,        1.0f,  1.0f, 0.0f };
233       memcpy (data, tmpData, sizeof(float) * 7 * 4);
234     }
235     else //if( this->GradientType == FirstCornerGradient || this->GradientType == ThirdCornerGradient )
236     {
237       const float tmpData[] = { (float)corner2[0], (float)corner2[1], (float)corner2[2], 1.0f,       -1.0f, -1.0f, 0.0f,
238                                 (float)corner3[0], (float)corner3[1], (float)corner3[2], 1.0f,       -1.0f,  1.0f, 0.0f,
239                                 (float)corner4[0], (float)corner4[1], (float)corner4[2], 1.0f,        1.0f,  1.0f, 0.0f,
240                                 (float)corner1[0], (float)corner1[1], (float)corner1[2], 1.0f,        1.0f, -1.0f, 0.0f };
241       memcpy (data, tmpData, sizeof(float) * 7 * 4);
242     }
243
244     GLuint vertexBuffer;
245     this->OpenGLHelper.vglGenBuffersARB (1, &vertexBuffer);
246     this->OpenGLHelper.vglBindBufferARB (GL_ARRAY_BUFFER_ARB, vertexBuffer);
247     this->OpenGLHelper.vglBufferDataARB (GL_ARRAY_BUFFER_ARB, sizeof(data), data, GL_STATIC_DRAW_ARB);
248
249     GLint colorAttrib  = this->OpenGLHelper.vglGetAttribLocationARB (this->BackgroundProgram, "Color");
250     GLint vertexAttrib = this->OpenGLHelper.vglGetAttribLocationARB (this->BackgroundProgram, "Vertex");
251     GLsizei vertexSize = sizeof(GLfloat) * 7;
252
253     this->OpenGLHelper.vglVertexAttribPointerARB (colorAttrib, 4, GL_FLOAT, GL_FALSE, vertexSize, (const GLvoid*)0);
254     this->OpenGLHelper.vglEnableVertexAttribArrayARB (colorAttrib);
255
256     this->OpenGLHelper.vglVertexAttribPointerARB (vertexAttrib, 3, GL_FLOAT, GL_FALSE, vertexSize, (const GLvoid*)(sizeof(GLfloat) * 4));
257     this->OpenGLHelper.vglEnableVertexAttribArrayARB (vertexAttrib);
258
259     this->OpenGLHelper.vglUniform1iARB (this->myLocations.UseTexture, 0);
260
261     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
262
263     this->OpenGLHelper.vglDisableVertexAttribArrayARB (0);
264     this->OpenGLHelper.vglBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
265     this->OpenGLHelper.vglDeleteBuffersARB (1, &vertexBuffer);
266     this->OpenGLHelper.vglBindVertexArrayARB (0);
267     this->OpenGLHelper.vglUseProgramObjectARB (0);
268   }
269 #else
270
271       glBegin( GL_TRIANGLE_FAN );
272       if( this->GradientType != FirstCornerGradient && this->GradientType != ThirdCornerGradient )
273       {
274         glColor3f( corner1[0], corner1[1], corner1[2] ); glVertex2f( 0.F, 0.F );
275         glColor3f( corner2[0], corner2[1], corner2[2] ); glVertex2f( 1.F, 0.F );
276         glColor3f( corner3[0], corner3[1], corner3[2] ); glVertex2f( 1.F, 1.F );
277         glColor3f( corner4[0], corner4[1], corner4[2] ); glVertex2f( 0.F, 1.F );
278       }
279       else //if( this->GradientType == FirstCornerGradient || this->GradientType == ThirdCornerGradient )
280       {
281         glColor3f( corner2[0], corner2[1], corner2[2] ); glVertex2f( 1.F, 0.F );
282         glColor3f( corner3[0], corner3[1], corner3[2] ); glVertex2f( 1.F, 1.F );
283         glColor3f( corner4[0], corner4[1], corner4[2] ); glVertex2f( 0.F, 1.F );
284         glColor3f( corner1[0], corner1[1], corner1[2] ); glVertex2f( 0.F, 0.F );
285       }
286       glEnd();
287 #endif
288     }
289
290     if( this->TexturedBackground && this->BackgroundTexture )
291     {
292       if( VTKViewer_Texture* aTexture = VTKViewer_Texture::SafeDownCast( this->BackgroundTexture ) )
293       {
294         glEnable( GL_TEXTURE_2D );
295
296         aTexture->Render( this );
297
298         // NOTE: By default the mode is GL_MODULATE. Since the user
299         // cannot set the mode, the default is set to replace.
300         glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
301         glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
302         glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
303
304         // NOTE: vtkTexture Render enables the alpha test
305         // so that no buffer is affected if alpha of incoming fragment is
306         // below the threshold. Here we have to enable it so that it won't
307         // rejects the fragments of the quad as the alpha is set to 0 on it.
308         glDisable( GL_ALPHA_TEST );
309
310         GLfloat texX = 1.F; // texture <s> coordinate
311         GLfloat texY = 1.F; // texture <t> coordinate
312
313         int aPosition = aTexture->GetPosition();
314         int aWidth = aTexture->GetWidth();
315         int aHeight = aTexture->GetHeight();
316         int aViewWidth = this->RenderWindow->GetSize()[0];
317         int aViewHeight = this->RenderWindow->GetSize()[1];
318
319         if( aPosition == VTKViewer_Texture::Tiled )
320         {
321           texX = (GLfloat)aViewWidth / (GLfloat)aWidth;
322           texY = (GLfloat)aViewHeight / (GLfloat)aHeight;
323         }
324 #ifdef VTK_OPENGL2
325         if (this->OpenGLHelper.IsInitialized())
326         {
327           if (this->VertexArrayObject == 0)
328           {
329             this->OpenGLHelper.vglGenVertexArraysARB (1, &this->VertexArrayObject);
330           }
331
332           this->OpenGLHelper.vglUseProgramObjectARB (this->BackgroundProgram);
333           this->OpenGLHelper.vglBindVertexArrayARB  (this->VertexArrayObject);
334
335           GLfloat dx = (aPosition == VTKViewer_Texture::Centered) ? (( (GLfloat)aWidth / (GLfloat)aViewWidth )) : 1.0f;
336           GLfloat dy = (aPosition == VTKViewer_Texture::Centered) ? (( (GLfloat)aHeight / (GLfloat)aViewHeight )) : 1.0f;
337
338
339           // First 4 components of Vertex is TexCoords now.
340           GLfloat data[7 * 4] = { 0.0f, texY, 0.0f, 1.0f,       -dx,  dy, 0.0f,
341                                   0.0f, 0.0f, 0.0f, 1.0f,       -dx, -dy, 0.0f,
342                                   texX, 0.0f, 0.0f, 1.0f,        dx, -dy, 0.0f,
343                                   texX, texY, 0.0f, 1.0f,        dx,  dy, 0.0f };
344
345           GLuint vertexBuffer;
346           this->OpenGLHelper.vglGenBuffersARB (1, &vertexBuffer);
347           this->OpenGLHelper.vglBindBufferARB (GL_ARRAY_BUFFER_ARB, vertexBuffer);
348           this->OpenGLHelper.vglBufferDataARB (GL_ARRAY_BUFFER_ARB, sizeof(data), data, GL_STATIC_DRAW_ARB);
349
350           GLint colorAttrib  = this->OpenGLHelper.vglGetAttribLocationARB (this->BackgroundProgram, "Color");
351           GLint vertexAttrib = this->OpenGLHelper.vglGetAttribLocationARB (this->BackgroundProgram, "Vertex");
352           GLsizei vertexSize = sizeof(GLfloat) * 7;
353
354           this->OpenGLHelper.vglVertexAttribPointerARB (colorAttrib, 4, GL_FLOAT, GL_FALSE, vertexSize, (const GLvoid*)0);
355           this->OpenGLHelper.vglEnableVertexAttribArrayARB (colorAttrib);
356
357           this->OpenGLHelper.vglVertexAttribPointerARB (vertexAttrib, 3, GL_FLOAT, GL_FALSE, vertexSize, (const GLvoid*)(sizeof(GLfloat) * 4));
358           this->OpenGLHelper.vglEnableVertexAttribArrayARB (vertexAttrib);
359
360           this->OpenGLHelper.vglUniform1iARB (this->myLocations.UseTexture, 1);
361           this->OpenGLHelper.vglUniform1iARB (this->myLocations.BackgroundTexture, GL_TEXTURE0);
362
363           glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
364
365           this->OpenGLHelper.vglDisableVertexAttribArrayARB (0);
366           this->OpenGLHelper.vglBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
367           this->OpenGLHelper.vglDeleteBuffersARB (1, &vertexBuffer);
368           this->OpenGLHelper.vglBindVertexArrayARB (0);
369           this->OpenGLHelper.vglUseProgramObjectARB (0);
370         }
371 #else
372         GLfloat x_offset = 0.5f, y_offset = 0.5f;
373         GLfloat coeff = 0.5f;
374         if( aPosition == VTKViewer_Texture::Centered )
375         {
376           x_offset = ( (GLfloat)aWidth / (GLfloat)aViewWidth ) / 2.;
377           y_offset = ( (GLfloat)aHeight / (GLfloat)aViewHeight ) / 2.;
378         }
379
380         // OCCT issue 0023102: Change the algorithm of rendering the
381         // 3d viewer background using tiled texture
382         // Setting this coefficient to -1.F allows to tile textures relatively
383         // to the top-left corner of the view (value 1.F corresponds to the
384         // initial behaviour - tiling from the bottom-left corner)
385         GLfloat aCoef = -1.F;
386
387         // Note that texture is mapped using GL_REPEAT wrapping mode so integer part
388         // is simply ignored, and negative multiplier is here for convenience only
389         // and does not result e.g. in texture mirroring
390         glBegin( GL_QUADS );
391         glTexCoord2f(  0.F,          0.F ); glVertex2f( -x_offset + coeff, -aCoef * y_offset + coeff );
392         glTexCoord2f( texX,          0.F ); glVertex2f(  x_offset + coeff, -aCoef * y_offset + coeff );
393         glTexCoord2f( texX, aCoef * texY ); glVertex2f(  x_offset + coeff,  aCoef * y_offset + coeff );
394         glTexCoord2f(  0.F, aCoef * texY ); glVertex2f( -x_offset + coeff,  aCoef * y_offset + coeff );
395         glEnd();
396 #endif
397       }
398     }
399
400     // Restore settings.
401     {
402       glEnable( GL_ALPHA_TEST );
403       glEnable( GL_DEPTH_TEST );
404       glEnable( GL_LIGHTING );
405       glEnable( GL_TEXTURE_1D );
406       glEnable( GL_TEXTURE_2D );
407       glEnable( GL_BLEND );
408
409       glShadeModel( oldShadeModel ); // color interpolation
410     }
411
412     glPopMatrix();
413     glMatrixMode( GL_PROJECTION );
414     glPopMatrix();
415     glMatrixMode( GL_MODELVIEW );
416
417     glPopAttrib();
418   }
419 }