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