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