0024413: Visualization - get rid of projection shift from orthographic camera definition
[occt.git] / src / OpenGl / OpenGl_View.cxx
1 // Created on: 2011-09-20
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #ifdef HAVE_CONFIG_H
17   #include <config.h>
18 #endif
19
20 #include <NCollection_Mat4.hxx>
21
22 #include <OpenGl_Context.hxx>
23 #include <OpenGl_Display.hxx>
24 #include <OpenGl_GlCore11.hxx>
25 #include <OpenGl_GraduatedTrihedron.hxx>
26 #include <OpenGl_GraphicDriver.hxx>
27 #include <OpenGl_ShaderManager.hxx>
28 #include <OpenGl_Texture.hxx>
29 #include <OpenGl_Trihedron.hxx>
30 #include <OpenGl_transform_persistence.hxx>
31 #include <OpenGl_View.hxx>
32 #include <OpenGl_Workspace.hxx>
33
34 #include <Graphic3d_TextureEnv.hxx>
35 #include <Graphic3d_Mat4d.hxx>
36
37 IMPLEMENT_STANDARD_HANDLE(OpenGl_View,MMgt_TShared)
38 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_View,MMgt_TShared)
39
40 /*----------------------------------------------------------------------*/
41
42 static const OPENGL_BG_TEXTURE myDefaultBgTexture = { 0, 0, 0, Aspect_FM_CENTERED };
43 static const OPENGL_BG_GRADIENT myDefaultBgGradient = { {{ 0.F, 0.F, 0.F, 1.F }}, {{ 0.F, 0.F, 0.F, 1.F }}, Aspect_GFM_NONE };
44 static const Tmatrix3 myDefaultMatrix = { { 1.F, 0.F, 0.F, 0.F }, { 0.F, 1.F, 0.F, 0.F }, { 0.F, 0.F, 1.F, 0.F }, { 0.F, 0.F, 0.F, 1.F } };
45 static const OPENGL_ZCLIP myDefaultZClip = { { Standard_True, 0.F }, { Standard_True, 1.F } };
46
47 static const OPENGL_FOG myDefaultFog = { Standard_False, 0.F, 1.F, { { 0.F, 0.F, 0.F, 1.F } } };
48 static const TEL_TRANSFORM_PERSISTENCE myDefaultTransPers = { 0, 0.F, 0.F, 0.F };
49 static const GLdouble THE_IDENTITY_MATRIX[4][4] =
50 {
51   {1.0, 0.0, 0.0, 0.0},
52   {0.0, 1.0, 0.0, 0.0},
53   {0.0, 0.0, 1.0, 0.0},
54   {0.0, 0.0, 0.0, 1.0}
55 };
56
57 /*----------------------------------------------------------------------*/
58
59 OpenGl_View::OpenGl_View (const CALL_DEF_VIEWCONTEXT &AContext,
60                           OpenGl_StateCounter*       theCounter)
61 : mySurfaceDetail(Visual3d_TOD_NONE),
62   myBackfacing(0),
63   myBgTexture(myDefaultBgTexture),
64   myBgGradient(myDefaultBgGradient),
65   //shield_indicator = TOn,
66   //shield_colour = { { 0.F, 0.F, 0.F, 1.F } },
67   //border_indicator = TOff,
68   //border_colour = { { 0.F, 0.F, 0.F, 1.F } },
69   //active_status = TOn,
70   myZClip(myDefaultZClip),
71   myCamera(AContext.Camera),
72   myFog(myDefaultFog),
73   myTrihedron(NULL),
74   myGraduatedTrihedron(NULL),
75   myVisualization(AContext.Visualization),
76   myIntShadingMethod(TEL_SM_GOURAUD),
77   myAntiAliasing(Standard_False),
78   myTransPers(&myDefaultTransPers),
79   myIsTransPers(Standard_False),
80   myProjectionState (0),
81   myModelViewState (0),
82   myStateCounter (theCounter),
83   myLastLightSourceState (0, 0)
84 {
85
86   // Shading method
87   switch (AContext.Model)
88   {
89     case 1 : /* VISUAL3D_TOM_INTERP_COLOR */
90     case 3 : /* VISUAL3D_TOM_VERTEX */
91       myIntShadingMethod = TEL_SM_GOURAUD;
92       break;
93     default :
94       myIntShadingMethod = TEL_SM_FLAT;
95       break;
96   }
97
98   myCurrLightSourceState = myStateCounter->Increment();
99
100 #ifdef HAVE_OPENCL
101   myModificationState = 1; // initial state
102 #endif
103 }
104
105 /*----------------------------------------------------------------------*/
106
107 OpenGl_View::~OpenGl_View ()
108 {
109   ReleaseGlResources (NULL); // ensure ReleaseGlResources() was called within valid context
110 }
111
112 void OpenGl_View::ReleaseGlResources (const Handle(OpenGl_Context)& theCtx)
113 {
114   OpenGl_Element::Destroy (theCtx, myTrihedron);
115   OpenGl_Element::Destroy (theCtx, myGraduatedTrihedron);
116
117   if (!myTextureEnv.IsNull())
118   {
119     theCtx->DelayedRelease (myTextureEnv);
120     myTextureEnv.Nullify();
121   }
122   if (myBgTexture.TexId != 0)
123   {
124     glDeleteTextures (1, (GLuint*)&(myBgTexture.TexId));
125     myBgTexture.TexId = 0;
126   }
127 }
128
129 void OpenGl_View::SetTextureEnv (const Handle(OpenGl_Context)&       theCtx,
130                                  const Handle(Graphic3d_TextureEnv)& theTexture)
131 {
132   if (!myTextureEnv.IsNull())
133   {
134     theCtx->DelayedRelease (myTextureEnv);
135     myTextureEnv.Nullify();
136   }
137
138   if (theTexture.IsNull())
139   {
140     return;
141   }
142
143   myTextureEnv = new OpenGl_Texture (theTexture->GetParams());
144   Handle(Image_PixMap) anImage = theTexture->GetImage();
145   if (!anImage.IsNull())
146     myTextureEnv->Init (theCtx, *anImage.operator->(), theTexture->Type());
147
148 #ifdef HAVE_OPENCL
149   myModificationState++;
150 #endif
151 }
152
153 void OpenGl_View::SetSurfaceDetail (const Visual3d_TypeOfSurfaceDetail theMode)
154 {
155   mySurfaceDetail = theMode;
156
157 #ifdef HAVE_OPENCL
158   myModificationState++;
159 #endif
160 }
161
162 // =======================================================================
163 // function : SetBackfacing
164 // purpose  :
165 // =======================================================================
166 void OpenGl_View::SetBackfacing (const Standard_Integer theMode)
167 {
168   myBackfacing = theMode;
169 }
170
171 // =======================================================================
172 // function : SetLights
173 // purpose  :
174 // =======================================================================
175 void OpenGl_View::SetLights (const CALL_DEF_VIEWCONTEXT& theViewCtx)
176 {
177   myLights.Clear();
178   for (Standard_Integer aLightIt = 0; aLightIt < theViewCtx.NbActiveLight; ++aLightIt)
179   {
180     myLights.Append (theViewCtx.ActiveLight[aLightIt]);
181   }
182   myCurrLightSourceState = myStateCounter->Increment();
183 }
184
185 /*----------------------------------------------------------------------*/
186
187 //call_togl_setvisualisation
188 void OpenGl_View::SetVisualisation (const CALL_DEF_VIEWCONTEXT &AContext)
189 {
190   myVisualization = AContext.Visualization;
191   // Shading method
192   switch (AContext.Model)
193   {
194     case 1 : /* VISUAL3D_TOM_INTERP_COLOR */
195     case 3 : /* VISUAL3D_TOM_VERTEX */
196       myIntShadingMethod = TEL_SM_GOURAUD;
197       break;
198     default :
199       myIntShadingMethod = TEL_SM_FLAT;
200       break;
201   }
202 }
203
204 /*----------------------------------------------------------------------*/
205
206 //call_togl_cliplimit
207 void OpenGl_View::SetClipLimit (const Graphic3d_CView& theCView)
208 {
209   myZClip.Back.Limit = theCView.Context.ZClipBackPlane;
210   myZClip.Front.Limit = theCView.Context.ZClipFrontPlane;
211
212   myZClip.Back.IsOn  = (theCView.Context.BackZClipping  != 0);
213   myZClip.Front.IsOn = (theCView.Context.FrontZClipping != 0);
214 }
215
216 /*----------------------------------------------------------------------*/
217
218 void OpenGl_View::SetFog (const Graphic3d_CView& theCView,
219                           const Standard_Boolean theFlag)
220 {
221   if (!theFlag)
222   {
223     myFog.IsOn = Standard_False;
224   }
225   else
226   {
227     myFog.IsOn = Standard_True;
228
229     myFog.Front = theCView.Context.DepthFrontPlane;
230     myFog.Back = theCView.Context.DepthBackPlane;
231
232     myFog.Color.rgb[0] = theCView.DefWindow.Background.r;
233     myFog.Color.rgb[1] = theCView.DefWindow.Background.g;
234     myFog.Color.rgb[2] = theCView.DefWindow.Background.b;
235     myFog.Color.rgb[3] = 1.0f;
236   }
237 }
238
239 /*----------------------------------------------------------------------*/
240
241 void OpenGl_View::TriedronDisplay (const Handle(OpenGl_Context)&       theCtx,
242                                    const Aspect_TypeOfTriedronPosition thePosition,
243                                    const Quantity_NameOfColor          theColor,
244                                    const Standard_Real                 theScale,
245                                    const Standard_Boolean              theAsWireframe)
246 {
247   OpenGl_Element::Destroy (theCtx, myTrihedron);
248   myTrihedron = new OpenGl_Trihedron (thePosition, theColor, theScale, theAsWireframe);
249 }
250
251 /*----------------------------------------------------------------------*/
252
253 void OpenGl_View::TriedronErase (const Handle(OpenGl_Context)& theCtx)
254 {
255   OpenGl_Element::Destroy (theCtx, myTrihedron);
256 }
257
258 /*----------------------------------------------------------------------*/
259
260 void OpenGl_View::GraduatedTrihedronDisplay (const Handle(OpenGl_Context)&        theCtx,
261                                              const Graphic3d_CGraduatedTrihedron& theData)
262 {
263   OpenGl_Element::Destroy (theCtx, myGraduatedTrihedron);
264   myGraduatedTrihedron = new OpenGl_GraduatedTrihedron (theData);
265 }
266
267 /*----------------------------------------------------------------------*/
268
269 void OpenGl_View::GraduatedTrihedronErase (const Handle(OpenGl_Context)& theCtx)
270 {
271   OpenGl_Element::Destroy (theCtx, myGraduatedTrihedron);
272 }
273
274 /*----------------------------------------------------------------------*/
275
276 //transform_persistence_end
277 void OpenGl_View::EndTransformPersistence(const Handle(OpenGl_Context)& theCtx)
278 {
279   if (myIsTransPers)
280   {
281     // restore matrix
282     glMatrixMode (GL_PROJECTION);
283     glPopMatrix();
284     glMatrixMode (GL_MODELVIEW);
285     glPopMatrix();
286     myIsTransPers = Standard_False;
287
288     // Note: the approach of accessing OpenGl matrices is used now since the matrix
289     // manipulation are made with help of OpenGl methods. This might be replaced by
290     // direct computation of matrices by OCC subroutines.
291     Tmatrix3 aResultWorldView;
292     glGetFloatv (GL_MODELVIEW_MATRIX, *aResultWorldView);
293
294     Tmatrix3 aResultProjection;
295     glGetFloatv (GL_PROJECTION_MATRIX, *aResultProjection);
296
297     // Set OCCT state uniform variables
298     theCtx->ShaderManager()->RevertWorldViewStateTo (&aResultWorldView);
299     theCtx->ShaderManager()->RevertProjectionStateTo (&aResultProjection);
300   }
301 }
302
303 /*----------------------------------------------------------------------*/
304
305 //transform_persistence_begin
306 const TEL_TRANSFORM_PERSISTENCE* OpenGl_View::BeginTransformPersistence (const Handle(OpenGl_Context)& theCtx,
307                                                                          const TEL_TRANSFORM_PERSISTENCE* theTransPers)
308 {
309   const TEL_TRANSFORM_PERSISTENCE* aTransPersPrev = myTransPers;
310   myTransPers = theTransPers;
311   if (theTransPers->mode == 0)
312   {
313     EndTransformPersistence (theCtx);
314     return aTransPersPrev;
315   }
316
317   GLint aViewport[4];
318   GLdouble aModelMatrix[4][4];
319   GLdouble aProjMatrix[4][4];
320   glGetIntegerv (GL_VIEWPORT,          aViewport);
321   glGetDoublev  (GL_MODELVIEW_MATRIX,  (GLdouble* )aModelMatrix);
322   glGetDoublev  (GL_PROJECTION_MATRIX, (GLdouble *)aProjMatrix);
323   const GLdouble aViewportW = (GLdouble )aViewport[2];
324   const GLdouble aViewportH = (GLdouble )aViewport[3];
325
326   if (myIsTransPers)
327   {
328     // pop matrix stack - it will be overridden later
329     glMatrixMode (GL_PROJECTION);
330     glPopMatrix();
331     glMatrixMode (GL_MODELVIEW);
332     glPopMatrix();
333   }
334   else
335   {
336     myIsTransPers = Standard_True;
337   }
338
339   // push matrices into stack and reset them
340   glMatrixMode (GL_MODELVIEW);
341   glPushMatrix();
342   glLoadIdentity();
343
344   glMatrixMode (GL_PROJECTION);
345   glPushMatrix();
346   glLoadIdentity();
347
348   // get the window's (fixed) coordinates for theTransPers->point before matrixes modifications
349   GLdouble aWinX = 0.0, aWinY = 0.0, aWinZ = 0.0;
350   if ((theTransPers->mode & TPF_PAN) != TPF_PAN)
351   {
352     gluProject (theTransPers->pointX, theTransPers->pointY, theTransPers->pointZ,
353                 (GLdouble* )aModelMatrix, (GLdouble* )aProjMatrix, aViewport,
354                 &aWinX, &aWinY, &aWinZ);
355   }
356
357   // prevent zooming
358   if ((theTransPers->mode & TPF_ZOOM)
359    || (theTransPers->mode == TPF_TRIEDRON))
360   {
361     // compute fixed-zoom multiplier
362     // actually function works ugly with TelPerspective!
363     const GLdouble aDet2 = 0.002 / (aViewportW > aViewportH ? aProjMatrix[1][1] : aProjMatrix[0][0]);
364     aProjMatrix[0][0] *= aDet2;
365     aProjMatrix[1][1] *= aDet2;
366     aProjMatrix[2][2] *= aDet2;
367   }
368
369   // prevent translation - annulate translate matrix
370   if ((theTransPers->mode & TPF_PAN)
371    || (theTransPers->mode == TPF_TRIEDRON))
372   {
373     aModelMatrix[3][0] = 0.0;
374     aModelMatrix[3][1] = 0.0;
375     aModelMatrix[3][2] = 0.0;
376     aProjMatrix [3][0] = 0.0;
377     aProjMatrix [3][1] = 0.0;
378     aProjMatrix [3][2] = 0.0;
379   }
380
381   // prevent scaling-on-axis
382   if (theTransPers->mode & TPF_ZOOM)
383   {
384     const gp_Pnt anAxialScale = myCamera->AxialScale();
385     const double aScaleX = anAxialScale.X();
386     const double aScaleY = anAxialScale.Y();
387     const double aScaleZ = anAxialScale.Z();
388     for (int i = 0; i < 3; ++i)
389     {
390       aModelMatrix[0][i] /= aScaleX;
391       aModelMatrix[1][i] /= aScaleY;
392       aModelMatrix[2][i] /= aScaleZ;
393     }
394   }
395
396   // prevent rotating - annulate rotate matrix
397   if (theTransPers->mode & TPF_ROTATE)
398   {
399     aModelMatrix[0][0] = 1.0;
400     aModelMatrix[1][1] = 1.0;
401     aModelMatrix[2][2] = 1.0;
402
403     aModelMatrix[1][0] = 0.0;
404     aModelMatrix[2][0] = 0.0;
405     aModelMatrix[0][1] = 0.0;
406     aModelMatrix[2][1] = 0.0;
407     aModelMatrix[0][2] = 0.0;
408     aModelMatrix[1][2] = 0.0;
409   }
410
411   // load computed matrices
412   glMatrixMode (GL_MODELVIEW);
413   glMultMatrixd ((GLdouble* )aModelMatrix);
414
415   glMatrixMode (GL_PROJECTION);
416   glMultMatrixd ((GLdouble* )aProjMatrix);
417
418   if (theTransPers->mode == TPF_TRIEDRON)
419   {
420     // move to the window corner
421     if (theTransPers->pointX != 0.0
422      && theTransPers->pointY != 0.0)
423     {
424       GLdouble aW1, aH1, aW2, aH2, aDummy;
425       glMatrixMode (GL_PROJECTION);
426       gluUnProject ( 0.5 * aViewportW,  0.5 * aViewportH, 0.0,
427                     (GLdouble* )THE_IDENTITY_MATRIX, (GLdouble* )aProjMatrix, aViewport,
428                     &aW1, &aH1, &aDummy);
429       gluUnProject (-0.5 * aViewportW, -0.5 * aViewportH, 0.0,
430                     (GLdouble* )THE_IDENTITY_MATRIX, (GLdouble* )aProjMatrix, aViewport,
431                     &aW2, &aH2, &aDummy);
432       GLdouble aMoveX = 0.5 * (aW1 - aW2 - theTransPers->pointZ);
433       GLdouble aMoveY = 0.5 * (aH1 - aH2 - theTransPers->pointZ);
434       aMoveX = (theTransPers->pointX > 0.0) ? aMoveX : -aMoveX;
435       aMoveY = (theTransPers->pointY > 0.0) ? aMoveY : -aMoveY;
436       glTranslated (aMoveX, aMoveY, 0.0);
437     }
438   }
439   else if ((theTransPers->mode & TPF_PAN) != TPF_PAN)
440   {
441     // move to thePoint using saved win-coordinates ('marker-behaviour')
442     GLdouble aMoveX, aMoveY, aMoveZ;
443     glGetDoublev (GL_MODELVIEW_MATRIX,  (GLdouble* )aModelMatrix);
444     glGetDoublev (GL_PROJECTION_MATRIX, (GLdouble* )aProjMatrix);
445     gluUnProject (aWinX, aWinY, aWinZ,
446                   (GLdouble* )aModelMatrix, (GLdouble* )aProjMatrix, aViewport,
447                   &aMoveX, &aMoveY, &aMoveZ);
448
449     glMatrixMode (GL_MODELVIEW);
450     glTranslated (aMoveX, aMoveY, aMoveZ);
451   }
452
453   // Note: the approach of accessing OpenGl matrices is used now since the matrix
454   // manipulation are made with help of OpenGl methods. This might be replaced by
455   // direct computation of matrices by OCC subroutines.
456   Tmatrix3 aResultWorldView;
457   glGetFloatv (GL_MODELVIEW_MATRIX, *aResultWorldView);
458
459   Tmatrix3 aResultProjection;
460   glGetFloatv (GL_PROJECTION_MATRIX, *aResultProjection);
461
462   // Set OCCT state uniform variables
463   theCtx->ShaderManager()->UpdateWorldViewStateTo (&aResultWorldView);
464   theCtx->ShaderManager()->UpdateProjectionStateTo (&aResultProjection);
465
466   return aTransPersPrev;
467 }
468
469 /*----------------------------------------------------------------------*/
470
471 void OpenGl_View::GetMatrices (TColStd_Array2OfReal&  theMatOrient,
472                                TColStd_Array2OfReal&  theMatMapping) const
473 {
474   const Graphic3d_Mat4d& aProj   = myCamera->ProjectionMatrix();
475   const Graphic3d_Mat4d& aOrient = myCamera->OrientationMatrix();
476
477   for (Standard_Integer aRow = 0; aRow < 4; ++aRow)
478   {
479     for (Standard_Integer aCol = 0; aCol < 4; ++aCol)
480     {
481       theMatOrient  (aRow, aCol) = aOrient.GetValue (aRow, aCol);
482       theMatMapping (aRow, aCol) = aProj  .GetValue (aRow, aCol);
483     }
484   }
485 }
486 /*----------------------------------------------------------------------*/