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