Salome HOME
Fix background troubles.
[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 #ifdef VTK_OPENGL2
310         if (this->OpenGLHelper.IsInitialized())
311         {
312           if (this->VertexArrayObject == 0)
313           {
314             this->OpenGLHelper.vglGenVertexArraysARB (1, &this->VertexArrayObject);
315           }
316
317           this->OpenGLHelper.vglUseProgramObjectARB (this->BackgroundProgram);
318           this->OpenGLHelper.vglBindVertexArrayARB  (this->VertexArrayObject);
319
320           // First 4 components of Vertex is TexCoords now.
321           GLfloat data[7 * 4] = { 0.0f, 1.0f, 0.0f, 1.0f,       -1.0f,  1.0f, 0.0f,
322                                   0.0f, 0.0f, 0.0f, 1.0f,       -1.0f, -1.0f, 0.0f,
323                                   1.0f, 0.0f, 0.0f, 1.0f,        1.0f, -1.0f, 0.0f,
324                                   1.0f, 1.0f, 0.0f, 1.0f,        1.0f,  1.0f, 0.0f };
325
326           GLuint vertexBuffer;
327           this->OpenGLHelper.vglGenBuffersARB (1, &vertexBuffer);
328           this->OpenGLHelper.vglBindBufferARB (GL_ARRAY_BUFFER_ARB, vertexBuffer);
329           this->OpenGLHelper.vglBufferDataARB (GL_ARRAY_BUFFER_ARB, sizeof(data), data, GL_STATIC_DRAW_ARB);
330
331           GLint colorAttrib  = this->OpenGLHelper.vglGetAttribLocationARB (this->BackgroundProgram, "Color");
332           GLint vertexAttrib = this->OpenGLHelper.vglGetAttribLocationARB (this->BackgroundProgram, "Vertex");
333           GLsizei vertexSize = sizeof(GLfloat) * 7;
334
335           this->OpenGLHelper.vglVertexAttribPointerARB (colorAttrib, 4, GL_FLOAT, GL_FALSE, vertexSize, (const GLvoid*)0);
336           this->OpenGLHelper.vglEnableVertexAttribArrayARB (colorAttrib);
337
338           this->OpenGLHelper.vglVertexAttribPointerARB (vertexAttrib, 3, GL_FLOAT, GL_FALSE, vertexSize, (const GLvoid*)(sizeof(GLfloat) * 4));
339           this->OpenGLHelper.vglEnableVertexAttribArrayARB (vertexAttrib);
340
341           this->OpenGLHelper.vglUniform1iARB (this->myLocations.UseTexture, 1);
342           this->OpenGLHelper.vglUniform1iARB (this->myLocations.BackgroundTexture, GL_TEXTURE0);
343
344           glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
345
346           this->OpenGLHelper.vglDisableVertexAttribArrayARB (0);
347           this->OpenGLHelper.vglBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
348           this->OpenGLHelper.vglDeleteBuffersARB (1, &vertexBuffer);
349           this->OpenGLHelper.vglBindVertexArrayARB (0);
350           this->OpenGLHelper.vglUseProgramObjectARB (0);
351         }
352 #else
353         GLfloat texX = 1.F; // texture <s> coordinate
354         GLfloat texY = 1.F; // texture <t> coordinate
355         GLfloat x_offset = 0.5, y_offset = 0.5;
356         GLfloat coeff = 0.5;
357
358         // OCCT issue 0023102: Change the algorithm of rendering the
359         // 3d viewer background using tiled texture
360         // Setting this coefficient to -1.F allows to tile textures relatively
361         // to the top-left corner of the view (value 1.F corresponds to the
362         // initial behaviour - tiling from the bottom-left corner)
363         GLfloat aCoef = -1.F;
364
365         int aPosition = aTexture->GetPosition();
366         int aWidth = aTexture->GetWidth();
367         int aHeight = aTexture->GetHeight();
368         int aViewWidth = this->RenderWindow->GetSize()[0];
369         int aViewHeight = this->RenderWindow->GetSize()[1];                    
370         if( aPosition == VTKViewer_Texture::Centered )
371         {
372           x_offset = ( (GLfloat)aWidth / (GLfloat)aViewWidth ) / 2.;
373           y_offset = ( (GLfloat)aHeight / (GLfloat)aViewHeight ) / 2.;
374         }
375         else if( aPosition == VTKViewer_Texture::Tiled )
376         {
377           texX = (GLfloat)aViewWidth / (GLfloat)aWidth;
378           texY = (GLfloat)aViewHeight / (GLfloat)aHeight;
379         }
380
381         // Note that texture is mapped using GL_REPEAT wrapping mode so integer part
382         // is simply ignored, and negative multiplier is here for convenience only
383         // and does not result e.g. in texture mirroring
384         glBegin( GL_QUADS );
385         glTexCoord2f(  0.F,          0.F ); glVertex2f( -x_offset + coeff, -aCoef * y_offset + coeff );
386         glTexCoord2f( texX,          0.F ); glVertex2f(  x_offset + coeff, -aCoef * y_offset + coeff );
387         glTexCoord2f( texX, aCoef * texY ); glVertex2f(  x_offset + coeff,  aCoef * y_offset + coeff );
388         glTexCoord2f(  0.F, aCoef * texY ); glVertex2f( -x_offset + coeff,  aCoef * y_offset + coeff );
389         glEnd();
390 #endif
391       }
392     }
393
394     // Restore settings.
395     {
396       glEnable( GL_ALPHA_TEST );
397       glEnable( GL_DEPTH_TEST );
398       glEnable( GL_LIGHTING );
399       glEnable( GL_TEXTURE_1D );
400       glEnable( GL_TEXTURE_2D );
401       glEnable( GL_BLEND );
402
403       glShadeModel( oldShadeModel ); // color interpolation
404     }
405
406     glPopMatrix();
407     glMatrixMode( GL_PROJECTION );
408     glPopMatrix();
409     glMatrixMode( GL_MODELVIEW );
410
411     glPopAttrib();
412   }
413 }